* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_MODULE_JS_MODULE_MANAGER_H
#define ECMASCRIPT_MODULE_JS_MODULE_MANAGER_H
#include "ecmascript/js_tagged_value-inl.h"
#include "ecmascript/jspandafile/js_pandafile.h"
#include "ecmascript/module/js_module_source_text.h"
#include "ecmascript/module/module_tools.h"
#include "ecmascript/napi/jsnapi_helper.h"
#include "ecmascript/tagged_dictionary.h"
#include "ecmascript/module/module_manager_map.h"
namespace panda::ecmascript {
enum class ModuleExecuteMode {
ExecuteZipMode,
ExecuteBufferMode
};
class ModuleManager {
public:
explicit ModuleManager(EcmaVM *vm);
~ModuleManager()
{
resolvedModules_.Clear();
resolvedSendableModules_.Clear();
classLiteralConstPoolMap_.clear();
}
JSHandle<SourceTextModule> GetImportedModule(const CString &referencing);
JSHandle<SourceTextModule> PUBLIC_API HostGetImportedModule(const CString &referencing);
JSTaggedValue HostGetImportedModule(void *src);
bool IsLocalModuleLoaded(const CString& referencing);
bool IsSharedModuleLoaded(const CString &referencing);
bool IsModuleLoaded(const CString &referencing);
bool IsEvaluatedModule(const CString &referencing);
bool IsInstantiatedModule(const CString &referencing);
bool IsLocalModuleInstantiated(const CString &referencing);
bool NeedExecuteModule(const CString &referencing);
JSHandle<JSTaggedValue> LoadNativeModule(JSThread *thread, const CString &key);
JSHandle<JSTaggedValue> ExecuteNativeModuleMayThrowError(JSThread *thread, const CString &recordName);
JSHandle<JSTaggedValue> ExecuteNativeModule(JSThread *thread, const CString &recordName);
JSHandle<JSTaggedValue> ExecuteJsonModule(JSThread *thread, const CString &recordName,
const CString &filename, const JSPandaFile *jsPandaFile);
JSHandle<JSTaggedValue> ExecuteCjsModule(JSThread *thread, const CString &recordName,
const JSPandaFile *jsPandaFile);
JSHandle<JSTaggedValue> GenerateSendableFuncModule(const JSHandle<JSTaggedValue> &module);
JSHandle<JSTaggedValue> TryGetImportedModule(const CString& referencing);
JSHandle<JSTaggedValue> TryGetSendableModule(const CString& referencing);
void Iterate(RootVisitor &v);
ModuleExecuteMode GetExecuteMode() const
{
return isExecuteBuffer_.load(std::memory_order_acquire);
}
inline void SetExecuteMode(ModuleExecuteMode mode)
{
isExecuteBuffer_.store(mode, std::memory_order_release);
}
static CString PUBLIC_API GetRecordName(const JSThread *thread, JSTaggedValue module);
static int GetExportObjectIndex(EcmaVM *vm, JSHandle<SourceTextModule> ecmaModule, const CString &key);
uint32_t NextModuleAsyncEvaluatingOrdinal()
{
uint32_t ordinal = nextModuleAsyncEvaluatingOrdinal_++;
return ordinal;
}
inline void AddResolveImportedModule(const CString &recordName, JSTaggedValue module)
{
resolvedModules_.Emplace(recordName, module);
}
inline void UpdateResolveImportedModule(const CString &recordName, JSTaggedValue module)
{
resolvedModules_.Insert(recordName, module);
}
inline void AddSendableModuleToCache(const CString &recordName, JSTaggedValue module)
{
resolvedSendableModules_.Emplace(recordName, module);
}
void NativeObjDestroy()
{
#if ENABLE_LATEST_OPTIMIZATION
resolvedModules_.ForEach([](const CString& key, GCRoot& root) {
ASSERT(!key.empty());
SourceTextModule::Cast(root.Read())->DestroyModuleCNativeFields();
});
resolvedSendableModules_.ForEach([](const CString& key, GCRoot& root) {
ASSERT(!key.empty());
SourceTextModule::Cast(root.Read())->DestroyModuleCNativeFields();
});
#else
resolvedModules_.ForEach([](auto it) {
CString key = it->first;
ASSERT(!key.empty());
GCRoot &root = it->second;
SourceTextModule::Cast(root.Read())->DestroyModuleCNativeFields();
});
resolvedSendableModules_.ForEach([](auto it) {
CString key = it->first;
ASSERT(!key.empty());
GCRoot &root = it->second;
SourceTextModule::Cast(root.Read())->DestroyModuleCNativeFields();
});
#endif
}
inline uint32_t GetResolvedModulesSize() const
{
return resolvedModules_.Size();
}
inline void AddNormalSerializeModule(JSThread *thread, JSHandle<TaggedArray> serializerArray, uint32_t idx)
{
#if ENABLE_LATEST_OPTIMIZATION
resolvedModules_.ForEachValue(
[thread, &idx, serializerArray](GCRoot& root) { serializerArray->Set(thread, idx++, root.Read()); });
#else
resolvedModules_.ForEach(
[thread, &idx, serializerArray](auto it) { serializerArray->Set(thread, idx++, it->second.Read()); });
#endif
}
inline bool IsVMBundlePack()
{
return vm_->IsBundlePack();
}
static JSTaggedValue CreateModuleManagerNativePointer(JSThread *thread);
void SyncModuleExecuteMode(JSThread *thread);
static bool CheckModuleValueOutterResolved(JSThread *thread, int32_t index, JSFunction *jsFunc);
static JSTaggedValue GetExternalModuleVarFastPathForJIT(JSThread *thread, int32_t index, JSFunction *jsFunc);
void ClearResolvedModules()
{
resolvedModules_.Clear();
}
void SetClassLiteralConstPoolMap(const CString &recordName, JSHandle<ConstantPool> constpool, uint32_t literalId);
void ResetConstPoolLiterals(const CString &recordName);
CUnorderedSet<CString, CStringHash>& GetModuleImportSet()
{
return moduleImportSet_;
}
std::string_view GetModuleImportStackData() const
{
return moduleImportData_;
}
std::string GetImportStackDataForJSCrash(size_t maxSize) const
{
return ModuleTools::TruncateImportStackForJSCrash(moduleImportData_, maxSize);
}
std::string GetImportStackDataForCPPCrash(const CString &moduleName, size_t maxSize) const
{
return ModuleTools::TruncateImportStackForCPPCrash(moduleName, moduleImportData_, maxSize);
}
std::string GetModuleImportStackContent(size_t headLength) const
{
return moduleImportData_.substr(headLength);
}
void SetModuleImportStackContent(const std::string &content, std::string_view head)
{
moduleImportData_ = std::string(head) + content;
}
void InsertModuleImportStackEntry(const std::string &entry, size_t headLength)
{
moduleImportData_.insert(headLength, entry);
}
private:
NO_COPY_SEMANTIC(ModuleManager);
NO_MOVE_SEMANTIC(ModuleManager);
void RemoveModuleFromCache(const CString &recordName);
void RemoveModuleNameFromList(const CString &recordName);
static constexpr uint32_t DEFAULT_DICTIONARY_CAPACITY = 4;
uint32_t nextModuleAsyncEvaluatingOrdinal_{SourceTextModule::FIRST_ASYNC_EVALUATING_ORDINAL};
EcmaVM *vm_ {nullptr};
#if ENABLE_LATEST_OPTIMIZATION
ModuleManagerMap<CString, CStringHash> resolvedModules_;
ModuleManagerMap<CString, CStringHash> resolvedSendableModules_;
#else
ModuleManagerMap<CString> resolvedModules_;
ModuleManagerMap<CString> resolvedSendableModules_;
#endif
std::atomic<ModuleExecuteMode> isExecuteBuffer_ {ModuleExecuteMode::ExecuteZipMode};
std::string moduleImportData_ {"\nModuleImportStack:"};
CUnorderedSet<CString, CStringHash> moduleImportSet_;
CUnorderedMap<CString, CUnorderedMap<uint32_t, std::vector<uint32_t>>> classLiteralConstPoolMap_;
friend class EcmaVM;
friend class PatchLoader;
friend class ModuleDeregister;
friend class SharedModuleManager;
friend class ModuleImportStackScope;
};
}
#endif