mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-06 23:54:03 +00:00
support top-level await for module
支持ECMA2022规范模块顶层await Issue: #I8LMRX Signed-off-by: lichenshuai <lichenshuai@huawei.com> Change-Id: Id09ac6f6bc6df9d4790d33f998b2b87586650658
This commit is contained in:
parent
b3ce5f1410
commit
b21f1eae7c
@ -2343,6 +2343,18 @@ void Builtins::InitializeForPromiseFuncClass(const JSHandle<GlobalEnv> &env)
|
||||
promiseExecutorFuncClass->SetExtensible(true);
|
||||
env->SetPromiseExecutorFunctionClass(thread_, promiseExecutorFuncClass);
|
||||
|
||||
JSHandle<JSHClass> asyncModuleFulfilledFuncClass = factory_->NewEcmaHClass(
|
||||
JSAsyncModuleFulfilledFunction::SIZE, JSType::JS_ASYNC_MODULE_FULFILLED_FUNCTION, env->GetFunctionPrototype());
|
||||
asyncModuleFulfilledFuncClass->SetCallable(true);
|
||||
asyncModuleFulfilledFuncClass->SetExtensible(true);
|
||||
env->SetAsyncModuleFulfilledFunctionClass(thread_, asyncModuleFulfilledFuncClass);
|
||||
|
||||
JSHandle<JSHClass> asyncModuleRejectedFuncClass = factory_->NewEcmaHClass(
|
||||
JSAsyncModuleRejectedFunction::SIZE, JSType::JS_ASYNC_MODULE_REJECTED_FUNCTION, env->GetFunctionPrototype());
|
||||
asyncModuleRejectedFuncClass->SetCallable(true);
|
||||
asyncModuleRejectedFuncClass->SetExtensible(true);
|
||||
env->SetAsyncModuleRejectedFunctionClass(thread_, asyncModuleRejectedFuncClass);
|
||||
|
||||
JSHandle<JSHClass> promiseAllResolveElementFunctionClass =
|
||||
factory_->NewEcmaHClass(JSPromiseAllResolveElementFunction::SIZE,
|
||||
JSType::JS_PROMISE_ALL_RESOLVE_ELEMENT_FUNCTION, env->GetFunctionPrototype());
|
||||
|
@ -43,6 +43,8 @@ enum class MethodIndex : uint8_t {
|
||||
BUILTINS_ASYNC_GENERATOR_NEXT_FULFILLED_FUNCTION,
|
||||
BUILTINS_ASYNC_GENERATOR_NEXT_REJECTED_FUNCTION,
|
||||
BUILTINS_ASYNC_FROM_SYNC_ITERATOR_FUNCTION,
|
||||
BUILTINS_ASYNC_MODULE_FULFILLED_FUNCTION,
|
||||
BUILTINS_ASYNC_MODULE_REJECTED_FUNCTION,
|
||||
METHOD_END
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
|
@ -394,6 +394,10 @@ CString *HeapSnapshot::GenerateNodeName(TaggedObject *entry)
|
||||
return GetString("PromiseReactionsFunction");
|
||||
case JSType::JS_PROMISE_EXECUTOR_FUNCTION:
|
||||
return GetString("PromiseExecutorFunction");
|
||||
case JSType::JS_ASYNC_MODULE_FULFILLED_FUNCTION:
|
||||
return GetString("AsyncModuleFulfilledFunction");
|
||||
case JSType::JS_ASYNC_MODULE_REJECTED_FUNCTION:
|
||||
return GetString("AsyncModuleRejectedFunction");
|
||||
case JSType::JS_ASYNC_FROM_SYNC_ITER_UNWARP_FUNCTION:
|
||||
return GetString("AsyncFromSyncIterUnwarpFunction");
|
||||
case JSType::JS_PROMISE_ALL_RESOLVE_ELEMENT_FUNCTION:
|
||||
|
@ -289,6 +289,10 @@ CString JSHClass::DumpJSType(JSType type)
|
||||
return "PromiseReactionsFunction";
|
||||
case JSType::JS_PROMISE_EXECUTOR_FUNCTION:
|
||||
return "PromiseExecutorFunction";
|
||||
case JSType::JS_ASYNC_MODULE_FULFILLED_FUNCTION:
|
||||
return "AsyncModuleFulfilledFunction";
|
||||
case JSType::JS_ASYNC_MODULE_REJECTED_FUNCTION:
|
||||
return "AsyncModuleRejectedFunction";
|
||||
case JSType::JS_PROMISE_ALL_RESOLVE_ELEMENT_FUNCTION:
|
||||
return "PromiseAllResolveElementFunction";
|
||||
case JSType::JS_PROMISE_ANY_REJECT_ELEMENT_FUNCTION:
|
||||
@ -822,6 +826,12 @@ static void DumpObject(TaggedObject *obj, std::ostream &os)
|
||||
case JSType::JS_PROMISE_EXECUTOR_FUNCTION:
|
||||
JSPromiseExecutorFunction::Cast(obj)->Dump(os);
|
||||
break;
|
||||
case JSType::JS_ASYNC_MODULE_FULFILLED_FUNCTION:
|
||||
JSAsyncModuleFulfilledFunction::Cast(obj)->Dump(os);
|
||||
break;
|
||||
case JSType::JS_ASYNC_MODULE_REJECTED_FUNCTION:
|
||||
JSAsyncModuleRejectedFunction::Cast(obj)->Dump(os);
|
||||
break;
|
||||
case JSType::ASYNC_GENERATOR_REQUEST:
|
||||
AsyncGeneratorRequest::Cast(obj)->Dump(os);
|
||||
break;
|
||||
@ -2715,6 +2725,20 @@ void JSPromiseExecutorFunction::Dump(std::ostream &os) const
|
||||
JSObject::Dump(os);
|
||||
}
|
||||
|
||||
void JSAsyncModuleFulfilledFunction::Dump(std::ostream &os) const
|
||||
{
|
||||
os << " - module: ";
|
||||
GetModule().Dump(os);
|
||||
JSObject::Dump(os);
|
||||
}
|
||||
|
||||
void JSAsyncModuleRejectedFunction::Dump(std::ostream &os) const
|
||||
{
|
||||
os << " - module: ";
|
||||
GetModule().Dump(os);
|
||||
JSObject::Dump(os);
|
||||
}
|
||||
|
||||
void JSPromiseAllResolveElementFunction::Dump(std::ostream &os) const
|
||||
{
|
||||
os << " - index: ";
|
||||
@ -3556,6 +3580,24 @@ void SourceTextModule::Dump(std::ostream &os) const
|
||||
os << " - NameDictionary: ";
|
||||
GetNameDictionary().Dump(os);
|
||||
os << "\n";
|
||||
os << " - CycleRoot: ";
|
||||
GetCycleRoot().Dump(os);
|
||||
os << "\n";
|
||||
os << " - TopLevelCapability: ";
|
||||
GetTopLevelCapability().Dump(os);
|
||||
os << "\n";
|
||||
os << " - AsyncParentModules: ";
|
||||
GetAsyncParentModules().Dump(os);
|
||||
os << "\n";
|
||||
os << " - HasTLA: ";
|
||||
os << GetHasTLA();
|
||||
os << "\n";
|
||||
os << " - AsyncEvaluatingOrdinal: ";
|
||||
os << GetAsyncEvaluatingOrdinal();
|
||||
os << "\n";
|
||||
os << " - PendingAsyncDependencies: ";
|
||||
os << GetPendingAsyncDependencies();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void ImportEntry::Dump(std::ostream &os) const
|
||||
@ -3926,6 +3968,12 @@ static void DumpObject(TaggedObject *obj, std::vector<Reference> &vec, bool isVm
|
||||
case JSType::JS_PROMISE_EXECUTOR_FUNCTION:
|
||||
JSPromiseExecutorFunction::Cast(obj)->DumpForSnapshot(vec);
|
||||
return;
|
||||
case JSType::JS_ASYNC_MODULE_FULFILLED_FUNCTION:
|
||||
JSAsyncModuleFulfilledFunction::Cast(obj)->DumpForSnapshot(vec);
|
||||
return;
|
||||
case JSType::JS_ASYNC_MODULE_REJECTED_FUNCTION:
|
||||
JSAsyncModuleRejectedFunction::Cast(obj)->DumpForSnapshot(vec);
|
||||
return;
|
||||
case JSType::ASYNC_GENERATOR_REQUEST:
|
||||
AsyncGeneratorRequest::Cast(obj)->DumpForSnapshot(vec);
|
||||
return;
|
||||
@ -5081,6 +5129,18 @@ void JSPromiseExecutorFunction::DumpForSnapshot(std::vector<Reference> &vec) con
|
||||
JSObject::DumpForSnapshot(vec);
|
||||
}
|
||||
|
||||
void JSAsyncModuleFulfilledFunction::DumpForSnapshot(std::vector<Reference> &vec) const
|
||||
{
|
||||
vec.emplace_back(CString("module"), GetModule());
|
||||
JSObject::DumpForSnapshot(vec);
|
||||
}
|
||||
|
||||
void JSAsyncModuleRejectedFunction::DumpForSnapshot(std::vector<Reference> &vec) const
|
||||
{
|
||||
vec.emplace_back(CString("module"), GetModule());
|
||||
JSObject::DumpForSnapshot(vec);
|
||||
}
|
||||
|
||||
void JSPromiseAllResolveElementFunction::DumpForSnapshot(std::vector<Reference> &vec) const
|
||||
{
|
||||
vec.emplace_back(CString("index"), GetIndex());
|
||||
@ -5501,6 +5561,12 @@ void SourceTextModule::DumpForSnapshot(std::vector<Reference> &vec) const
|
||||
vec.emplace_back(CString("DFSIndex"), JSTaggedValue(GetDFSIndex()));
|
||||
vec.emplace_back(CString("DFSAncestorIndex"), JSTaggedValue(GetDFSAncestorIndex()));
|
||||
vec.emplace_back(CString("NameDictionary"), GetNameDictionary());
|
||||
vec.emplace_back(CString("CycleRoot"), GetCycleRoot());
|
||||
vec.emplace_back(CString("TopLevelCapability"), GetTopLevelCapability());
|
||||
vec.emplace_back(CString("AsyncParentModules"), GetAsyncParentModules());
|
||||
vec.emplace_back(CString("HasTLA"), JSTaggedValue(GetHasTLA()));
|
||||
vec.emplace_back(CString("AsyncEvaluatingOrdinal"), JSTaggedValue(GetAsyncEvaluatingOrdinal()));
|
||||
vec.emplace_back(CString("PendingAsyncDependencies"), JSTaggedValue(GetPendingAsyncDependencies()));
|
||||
}
|
||||
|
||||
void ImportEntry::DumpForSnapshot(std::vector<Reference> &vec) const
|
||||
|
@ -298,11 +298,13 @@ Expected<JSTaggedValue, bool> EcmaContext::CommonInvokeEcmaEntrypoint(const JSPa
|
||||
EcmaRuntimeCallInfo *info =
|
||||
EcmaInterpreter::NewRuntimeCallInfo(thread_, JSHandle<JSTaggedValue>(func), global, undefined, 0);
|
||||
EcmaRuntimeStatScope runtimeStatScope(vm_);
|
||||
EcmaInterpreter::Execute(info);
|
||||
result = EcmaInterpreter::Execute(info);
|
||||
}
|
||||
}
|
||||
if (!thread_->HasPendingException()) {
|
||||
job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue());
|
||||
if (!jsPandaFile->IsModule(recordInfo)) {
|
||||
job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -584,7 +584,9 @@ void *EcmaVM::InternalMethodTable[] = {
|
||||
reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::throwerFunction),
|
||||
reinterpret_cast<void *>(JSAsyncGeneratorObject::ProcessorFulfilledFunc),
|
||||
reinterpret_cast<void *>(JSAsyncGeneratorObject::ProcessorRejectedFunc),
|
||||
reinterpret_cast<void *>(JSAsyncFromSyncIterator::AsyncFromSyncIterUnwarpFunction)
|
||||
reinterpret_cast<void *>(JSAsyncFromSyncIterator::AsyncFromSyncIterUnwarpFunction),
|
||||
reinterpret_cast<void *>(SourceTextModule::AsyncModuleFulfilledFunc),
|
||||
reinterpret_cast<void *>(SourceTextModule::AsyncModuleRejectedFunc)
|
||||
};
|
||||
|
||||
void EcmaVM::GenerateInternalNativeMethods()
|
||||
|
@ -76,6 +76,7 @@ template<typename T>
|
||||
class JSHandle;
|
||||
class JSArrayBuffer;
|
||||
class JSFunction;
|
||||
class SourceTextModule;
|
||||
class Program;
|
||||
class TSManager;
|
||||
class AOTFileManager;
|
||||
|
@ -163,6 +163,8 @@
|
||||
V(JSTaggedValue, AsyncAwaitStatusFunctionClass, ASYNC_AWAIT_STATUS_FUNCTION_CLASS) \
|
||||
V(JSTaggedValue, PromiseReactionFunctionClass, PROMISE_REACTION_FUNCTION_CLASS) \
|
||||
V(JSTaggedValue, PromiseExecutorFunctionClass, PROMISE_EXECUTOR_FUNCTION_CLASS) \
|
||||
V(JSTaggedValue, AsyncModuleFulfilledFunctionClass, ASYNC_MODULE_FULFILLED_FUNCTION_CLASS) \
|
||||
V(JSTaggedValue, AsyncModuleRejectedFunctionClass, ASYNC_MODULE_REJECTED_FUNCTION_CLASS) \
|
||||
V(JSTaggedValue, GeneratorFunctionClass, GENERATOR_FUNCTION_CLASS) \
|
||||
V(JSTaggedValue, AsyncGeneratorFunctionClass, ASYNC_GENERATOR_FUNCTION_CLASS) \
|
||||
V(JSTaggedValue, PromiseAllResolveElementFunctionClass, PROMISE_ALL_RESOLVE_ELEMENT_FUNC_CLASS) \
|
||||
|
@ -321,6 +321,30 @@ public:
|
||||
DECL_DUMP()
|
||||
};
|
||||
|
||||
class JSAsyncModuleFulfilledFunction : public JSFunction {
|
||||
public:
|
||||
CAST_CHECK(JSAsyncModuleFulfilledFunction, IsJSAsyncModuleFulfilledFunction);
|
||||
|
||||
static constexpr size_t MODULE_OFFSET = JSFunction::SIZE;
|
||||
ACCESSORS(Module, MODULE_OFFSET, SIZE);
|
||||
|
||||
DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, MODULE_OFFSET, SIZE)
|
||||
|
||||
DECL_DUMP()
|
||||
};
|
||||
|
||||
class JSAsyncModuleRejectedFunction : public JSFunction {
|
||||
public:
|
||||
CAST_CHECK(JSAsyncModuleRejectedFunction, IsJSAsyncModuleRejectedFunction);
|
||||
|
||||
static constexpr size_t MODULE_OFFSET = JSFunction::SIZE;
|
||||
ACCESSORS(Module, MODULE_OFFSET, SIZE);
|
||||
|
||||
DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, MODULE_OFFSET, SIZE)
|
||||
|
||||
DECL_DUMP()
|
||||
};
|
||||
|
||||
class JSPromiseAllResolveElementFunction : public JSFunction {
|
||||
public:
|
||||
CAST_CHECK(JSPromiseAllResolveElementFunction, IsJSPromiseAllResolveElementFunction);
|
||||
|
@ -81,6 +81,8 @@ struct Reference;
|
||||
JS_PROXY_REVOC_FUNCTION, /* /////////////////////////////////////////////////////////////////-PADDING */ \
|
||||
JS_PROMISE_REACTIONS_FUNCTION, /* /////////////////////////////////////////////////////////////////-PADDING */ \
|
||||
JS_PROMISE_EXECUTOR_FUNCTION, /* /////////////////////////////////////////////////////////////////-PADDING */ \
|
||||
JS_ASYNC_MODULE_FULFILLED_FUNCTION, /* ////////////////////////////////////////////////////////////-PADDING */ \
|
||||
JS_ASYNC_MODULE_REJECTED_FUNCTION, /* /////////////////////////////////////////////////////////////-PADDING */ \
|
||||
JS_ASYNC_FROM_SYNC_ITER_UNWARP_FUNCTION, /* //////////////////////////////////////////////////////-PADDING */ \
|
||||
JS_PROMISE_ALL_RESOLVE_ELEMENT_FUNCTION, /* //////////////////////////////////////////////////////-PADDING */ \
|
||||
JS_ASYNC_GENERATOR_RESUME_NEXT_RETURN_PROCESSOR_RST_FTN, /* ///////////////////////////////////////-PADDING */ \
|
||||
@ -757,6 +759,16 @@ public:
|
||||
return GetObjectType() == JSType::JS_PROMISE_EXECUTOR_FUNCTION;
|
||||
}
|
||||
|
||||
inline bool IsJSAsyncModuleFulfilledFunction() const
|
||||
{
|
||||
return GetObjectType() == JSType::JS_ASYNC_MODULE_FULFILLED_FUNCTION;
|
||||
}
|
||||
|
||||
inline bool IsJSAsyncModuleRejectedFunction() const
|
||||
{
|
||||
return GetObjectType() == JSType::JS_ASYNC_MODULE_REJECTED_FUNCTION;
|
||||
}
|
||||
|
||||
inline bool IsJSAsyncFromSyncIterUnwarpFunction() const
|
||||
{
|
||||
return GetObjectType() == JSType::JS_ASYNC_FROM_SYNC_ITER_UNWARP_FUNCTION;
|
||||
|
@ -622,6 +622,16 @@ inline bool JSTaggedValue::IsJSPromiseExecutorFunction() const
|
||||
return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSPromiseExecutorFunction();
|
||||
}
|
||||
|
||||
inline bool JSTaggedValue::IsJSAsyncModuleFulfilledFunction() const
|
||||
{
|
||||
return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSAsyncModuleFulfilledFunction();
|
||||
}
|
||||
|
||||
inline bool JSTaggedValue::IsJSAsyncModuleRejectedFunction() const
|
||||
{
|
||||
return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSAsyncModuleRejectedFunction();
|
||||
}
|
||||
|
||||
inline bool JSTaggedValue::IsJSAsyncFromSyncIterUnwarpFunction() const
|
||||
{
|
||||
return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSAsyncFromSyncIterUnwarpFunction();
|
||||
|
@ -544,6 +544,8 @@ public:
|
||||
bool IsProgram() const;
|
||||
bool IsJSPromiseReactionFunction() const;
|
||||
bool IsJSPromiseExecutorFunction() const;
|
||||
bool IsJSAsyncModuleFulfilledFunction() const;
|
||||
bool IsJSAsyncModuleRejectedFunction() const;
|
||||
bool IsJSAsyncFromSyncIterUnwarpFunction() const;
|
||||
bool IsJSPromiseAllResolveElementFunction() const;
|
||||
bool IsJSAsyncGeneratorResNextRetProRstFtn() const;
|
||||
|
@ -156,6 +156,9 @@ void JSPandaFile::InitializeUnMergedPF()
|
||||
info.classId = index;
|
||||
info.isCjs = true;
|
||||
}
|
||||
if (!info.hasTopLevelAwait && std::strcmp(HASTLA_CLASS, desc) == 0) {
|
||||
info.hasTopLevelAwait = true;
|
||||
}
|
||||
}
|
||||
jsRecordInfo_.insert({JSPandaFile::ENTRY_FUNCTION_NAME, info});
|
||||
methodLiterals_ =
|
||||
@ -190,6 +193,8 @@ void JSPandaFile::InitializeMergedPF()
|
||||
info.jsonStringId = fieldAccessor.GetValue<uint32_t>().value();
|
||||
} else if (std::strcmp(MODULE_RECORD_IDX, fieldName) == 0) {
|
||||
info.moduleRecordIdx = fieldAccessor.GetValue<int32_t>().value();
|
||||
} else if (std::strcmp(HAS_TOP_LEVEL_AWAIT, fieldName) == 0) {
|
||||
info.hasTopLevelAwait = fieldAccessor.GetValue<bool>().value();
|
||||
} else if (std::strcmp(TYPE_FLAG, fieldName) == 0) {
|
||||
info.hasTSTypes = fieldAccessor.GetValue<uint8_t>().value() != 0;
|
||||
} else if (std::strcmp(TYPE_SUMMARY_OFFSET, fieldName) == 0) {
|
||||
|
@ -37,6 +37,7 @@ public:
|
||||
int jsonStringId {-1};
|
||||
CUnorderedSet<const EcmaVM *> vmListOfParsedConstPool;
|
||||
int moduleRecordIdx {-1};
|
||||
bool hasTopLevelAwait {false};
|
||||
CUnorderedMap<uint32_t, uint64_t> constpoolMap;
|
||||
bool hasTSTypes {false};
|
||||
uint32_t typeSummaryOffset {0};
|
||||
@ -65,12 +66,14 @@ public:
|
||||
|
||||
static constexpr char MODULE_CLASS[] = "L_ESModuleRecord;";
|
||||
static constexpr char COMMONJS_CLASS[] = "L_CommonJsRecord;";
|
||||
static constexpr char HASTLA_CLASS[] = "L_HasTopLevelAwait;";
|
||||
static constexpr char TYPE_FLAG[] = "typeFlag";
|
||||
static constexpr char TYPE_SUMMARY_OFFSET[] = "typeSummaryOffset";
|
||||
|
||||
static constexpr char IS_COMMON_JS[] = "isCommonjs";
|
||||
static constexpr char IS_JSON_CONTENT[] = "jsonFileContent";
|
||||
static constexpr char MODULE_RECORD_IDX[] = "moduleRecordIdx";
|
||||
static constexpr char HAS_TOP_LEVEL_AWAIT[] = "hasTopLevelAwait";
|
||||
static constexpr char PACKAGE_NAME[] = "pkgName@";
|
||||
static constexpr char MERGE_ABC_NAME[] = "modules.abc";
|
||||
static constexpr char NPM_PATH_SEGMENT[] = "node_modules";
|
||||
@ -201,6 +204,18 @@ public:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int GetHasTopLevelAwait(const CString &recordName = ENTRY_FUNCTION_NAME) const
|
||||
{
|
||||
if (IsBundlePack()) {
|
||||
return jsRecordInfo_.begin()->second.hasTopLevelAwait;
|
||||
}
|
||||
auto info = jsRecordInfo_.find(recordName);
|
||||
if (info != jsRecordInfo_.end()) {
|
||||
return info->second.hasTopLevelAwait;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Span<const uint32_t> GetClasses() const
|
||||
{
|
||||
return pf_->GetClasses();
|
||||
|
@ -87,7 +87,6 @@ HWTEST_F_L0(JSPandaFileExecutorTest, Execute)
|
||||
Expected<JSTaggedValue, bool> result =
|
||||
JSPandaFileExecutor::Execute(thread, pf.get(), JSPandaFile::ENTRY_MAIN_FUNCTION);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(result.Value(), JSTaggedValue::Hole());
|
||||
|
||||
pfManager->RemoveJSPandaFileVm(instance, pf.get());
|
||||
}
|
||||
@ -123,7 +122,6 @@ HWTEST_F_L0(JSPandaFileExecutorTest, ExecuteFromFile)
|
||||
Expected<JSTaggedValue, bool> result =
|
||||
JSPandaFileExecutor::ExecuteFromFile(thread, CString(fileName), JSPandaFile::ENTRY_MAIN_FUNCTION);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(result.Value(), JSTaggedValue::Hole());
|
||||
|
||||
pfManager->RemoveJSPandaFileVm(instance, pf.get());
|
||||
std::shared_ptr<JSPandaFile> foundPf = pfManager->FindJSPandaFile(fileName);
|
||||
@ -161,7 +159,6 @@ HWTEST_F_L0(JSPandaFileExecutorTest, ExecuteFromBuffer)
|
||||
Expected<JSTaggedValue, bool> result = JSPandaFileExecutor::ExecuteFromBuffer(
|
||||
thread, (void *)data, sizeof(data), JSPandaFile::ENTRY_MAIN_FUNCTION, CString(fileName));
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(result.Value(), JSTaggedValue::Hole());
|
||||
|
||||
pfManager->RemoveJSPandaFileVm(instance, pf.get());
|
||||
std::shared_ptr<JSPandaFile> foundPf = pfManager->FindJSPandaFile(fileName);
|
||||
|
@ -183,6 +183,16 @@ public:
|
||||
jsPromiseExecutorFunction->VisitRangeSlot<visitType>(visitor);
|
||||
break;
|
||||
}
|
||||
case JSType::JS_ASYNC_MODULE_FULFILLED_FUNCTION: {
|
||||
auto jsAsyncModuleFulfilledFunction = JSAsyncModuleFulfilledFunction::Cast(object);
|
||||
jsAsyncModuleFulfilledFunction->VisitRangeSlot<visitType>(visitor);
|
||||
break;
|
||||
}
|
||||
case JSType::JS_ASYNC_MODULE_REJECTED_FUNCTION: {
|
||||
auto jsAsyncModuleRejectedFunction = JSAsyncModuleRejectedFunction::Cast(object);
|
||||
jsAsyncModuleRejectedFunction->VisitRangeSlot<visitType>(visitor);
|
||||
break;
|
||||
}
|
||||
case JSType::JS_ASYNC_FROM_SYNC_ITER_UNWARP_FUNCTION: {
|
||||
auto jsAsyncFromSyncIterUnwarpFunction = JSAsyncFromSyncIterUnwarpFunction::Cast(object);
|
||||
jsAsyncFromSyncIterUnwarpFunction->VisitRangeSlot<visitType>(visitor);
|
||||
|
@ -90,6 +90,12 @@ public:
|
||||
static CString GetRecordName(JSTaggedValue module);
|
||||
static int GetExportObjectIndex(EcmaVM *vm, JSHandle<SourceTextModule> ecmaModule, const std::string &key);
|
||||
|
||||
uint32_t NextModuleAsyncEvaluatingOrdinal()
|
||||
{
|
||||
uint32_t ordinal = nextModuleAsyncEvaluatingOrdinal_++;
|
||||
return ordinal;
|
||||
}
|
||||
|
||||
private:
|
||||
NO_COPY_SEMANTIC(ModuleManager);
|
||||
NO_MOVE_SEMANTIC(ModuleManager);
|
||||
@ -120,6 +126,8 @@ private:
|
||||
|
||||
static constexpr uint32_t DEAULT_DICTIONART_CAPACITY = 4;
|
||||
|
||||
uint32_t nextModuleAsyncEvaluatingOrdinal_{SourceTextModule::FIRST_ASYNC_EVALUATING_ORDINAL};
|
||||
|
||||
EcmaVM *vm_ {nullptr};
|
||||
JSTaggedValue resolvedModules_ {JSTaggedValue::Hole()};
|
||||
JSTaggedValue cachedEmptyModule_ {JSTaggedValue::Hole()};
|
||||
|
@ -27,7 +27,7 @@ int32_t ModuleRecord::Instantiate(JSThread *thread, const JSHandle<JSTaggedValue
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
int32_t ModuleRecord::Evaluate(JSThread *thread, const JSHandle<JSTaggedValue> &module)
|
||||
JSTaggedValue ModuleRecord::Evaluate(JSThread *thread, const JSHandle<JSTaggedValue> &module)
|
||||
{
|
||||
if (module->IsSourceTextModule()) {
|
||||
JSHandle<SourceTextModule> moduleRecord = JSHandle<SourceTextModule>::Cast(module);
|
||||
|
@ -27,7 +27,7 @@ public:
|
||||
// 15.2.1.16.4 Instantiate()
|
||||
static int Instantiate(JSThread *thread, const JSHandle<JSTaggedValue> &module);
|
||||
// 15.2.1.16.5 Evaluate()
|
||||
static int Evaluate(JSThread *thread, const JSHandle<JSTaggedValue> &module);
|
||||
static JSTaggedValue Evaluate(JSThread *thread, const JSHandle<JSTaggedValue> &module);
|
||||
|
||||
static JSTaggedValue GetNamespace(JSTaggedValue module);
|
||||
static void SetNamespace(JSThread *thread, JSTaggedValue module, JSTaggedValue value);
|
||||
|
@ -16,10 +16,14 @@
|
||||
#include "ecmascript/module/js_module_source_text.h"
|
||||
|
||||
#include "ecmascript/global_env.h"
|
||||
#include "ecmascript/base/builtins_base.h"
|
||||
#include "ecmascript/base/path_helper.h"
|
||||
#include "ecmascript/base/string_helper.h"
|
||||
#include "ecmascript/builtins/builtins_promise.h"
|
||||
#include "ecmascript/jobs/micro_job_queue.h"
|
||||
#include "ecmascript/jspandafile/js_pandafile_executor.h"
|
||||
#include "ecmascript/jspandafile/js_pandafile_manager.h"
|
||||
#include "ecmascript/js_promise.h"
|
||||
#include "ecmascript/linked_hash_table.h"
|
||||
#include "ecmascript/module/js_module_deregister.h"
|
||||
#include "ecmascript/module/js_module_manager.h"
|
||||
@ -486,8 +490,10 @@ int SourceTextModule::Instantiate(JSThread *thread, const JSHandle<JSTaggedValue
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX);
|
||||
JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleHdl);
|
||||
// 1. Let module be this Source Text Module Record.
|
||||
// 2. Assert: module.[[Status]] is not "instantiating" or "evaluating".
|
||||
ASSERT(module->GetStatus() != ModuleStatus::INSTANTIATING && module->GetStatus() != ModuleStatus::EVALUATING);
|
||||
// 2. Assert: module.[[Status]] is one of UNLINKED, LINKED, EVALUATING-ASYNC, or EVALUATED.
|
||||
ModuleStatus status = module->GetStatus();
|
||||
ASSERT(status == ModuleStatus::UNINSTANTIATED || status == ModuleStatus::INSTANTIATED ||
|
||||
status == ModuleStatus::EVALUATING_ASYNC || status == ModuleStatus::EVALUATED);
|
||||
// 3. Let stack be a new empty List.
|
||||
CVector<JSHandle<SourceTextModule>> stack;
|
||||
// 4. Let result be InnerModuleInstantiation(module, stack, 0).
|
||||
@ -497,8 +503,10 @@ int SourceTextModule::Instantiate(JSThread *thread, const JSHandle<JSTaggedValue
|
||||
if (thread->HasPendingException()) {
|
||||
return HandleInstantiateException(module, stack, result);
|
||||
}
|
||||
// 6. Assert: module.[[Status]] is "instantiated" or "evaluated".
|
||||
ASSERT(module->GetStatus() == ModuleStatus::INSTANTIATED || module->GetStatus() == ModuleStatus::EVALUATED);
|
||||
// 6. Assert: module.[[Status]] is one of LINKED, EVALUATING-ASYNC, or EVALUATED.
|
||||
status = module->GetStatus();
|
||||
ASSERT(status == ModuleStatus::INSTANTIATED || status == ModuleStatus::EVALUATING_ASYNC ||
|
||||
status == ModuleStatus::EVALUATED);
|
||||
// 7. Assert: stack is empty.
|
||||
ASSERT(stack.empty());
|
||||
// 8. Return undefined.
|
||||
@ -519,8 +527,10 @@ int SourceTextModule::InstantiateForConcurrent(JSThread *thread, const JSHandle<
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX);
|
||||
JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleHdl);
|
||||
// 1. Let module be this Source Text Module Record.
|
||||
// 2. Assert: module.[[Status]] is not "instantiating" or "evaluating".
|
||||
ASSERT(module->GetStatus() != ModuleStatus::INSTANTIATING && module->GetStatus() != ModuleStatus::EVALUATING);
|
||||
// 2. Assert: module.[[Status]] is one of UNLINKED, LINKED, EVALUATING-ASYNC, or EVALUATED.
|
||||
ModuleStatus status = module->GetStatus();
|
||||
ASSERT(status == ModuleStatus::UNINSTANTIATED || status == ModuleStatus::INSTANTIATED ||
|
||||
status == ModuleStatus::EVALUATING_ASYNC || status == ModuleStatus::EVALUATED);
|
||||
// 3. Let stack be a new empty List.
|
||||
CVector<JSHandle<SourceTextModule>> stack;
|
||||
// 4. Let result be InnerModuleInstantiation(module, stack, 0).
|
||||
@ -530,8 +540,10 @@ int SourceTextModule::InstantiateForConcurrent(JSThread *thread, const JSHandle<
|
||||
if (thread->HasPendingException()) {
|
||||
return HandleInstantiateException(module, stack, result);
|
||||
}
|
||||
// 6. Assert: module.[[Status]] is "instantiated" or "evaluated".
|
||||
ASSERT(module->GetStatus() == ModuleStatus::INSTANTIATED || module->GetStatus() == ModuleStatus::EVALUATED);
|
||||
// 6. Assert: module.[[Status]] is one of LINKED, EVALUATING-ASYNC, or EVALUATED.
|
||||
status = module->GetStatus();
|
||||
ASSERT(status == ModuleStatus::INSTANTIATED || status == ModuleStatus::EVALUATING_ASYNC ||
|
||||
status == ModuleStatus::EVALUATED);
|
||||
// 7. Assert: stack is empty.
|
||||
ASSERT(stack.empty());
|
||||
// 8. Return undefined.
|
||||
@ -595,10 +607,12 @@ std::optional<int> SourceTextModule::HandleInnerModuleInstantiation(JSThread *th
|
||||
index = SourceTextModule::InnerModuleInstantiation(thread,
|
||||
requiredModuleRecord, stack, index, excuteFromJob);
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
|
||||
// c. Assert: requiredModule.[[Status]] is either "instantiating", "instantiated", or "evaluated".
|
||||
// c. Assert: requiredModule.[[Status]] is one of LINKING, LINKED, EVALUATING-ASYNC, or EVALUATED.
|
||||
ModuleStatus requiredModuleStatus = requiredModule->GetStatus();
|
||||
ASSERT((requiredModuleStatus == ModuleStatus::INSTANTIATING ||
|
||||
requiredModuleStatus == ModuleStatus::INSTANTIATED || requiredModuleStatus == ModuleStatus::EVALUATED));
|
||||
ASSERT(requiredModuleStatus == ModuleStatus::INSTANTIATING ||
|
||||
requiredModuleStatus == ModuleStatus::INSTANTIATED ||
|
||||
requiredModuleStatus == ModuleStatus::EVALUATING_ASYNC ||
|
||||
requiredModuleStatus == ModuleStatus::EVALUATED);
|
||||
// d. Assert: requiredModule.[[Status]] is "instantiating" if and only if requiredModule is in stack.
|
||||
// e. If requiredModule.[[Status]] is "instantiating", then
|
||||
if (requiredModuleStatus == ModuleStatus::INSTANTIATING) {
|
||||
@ -625,10 +639,11 @@ int SourceTextModule::InnerModuleInstantiation(JSThread *thread, const JSHandle<
|
||||
return index;
|
||||
}
|
||||
JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
|
||||
// 2. If module.[[Status]] is "instantiating", "instantiated", or "evaluated", then Return index.
|
||||
// 2. If module.[[Status]] is one of LINKING, LINKED, EVALUATING-ASYNC, or EVALUATED, then Return index.
|
||||
ModuleStatus status = module->GetStatus();
|
||||
if (status == ModuleStatus::INSTANTIATING ||
|
||||
status == ModuleStatus::INSTANTIATED ||
|
||||
status == ModuleStatus::EVALUATING_ASYNC ||
|
||||
status == ModuleStatus::EVALUATED) {
|
||||
return index;
|
||||
}
|
||||
@ -682,10 +697,11 @@ int SourceTextModule::ModuleInstantiation(JSThread *thread, const JSHandle<Modul
|
||||
return index;
|
||||
}
|
||||
JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
|
||||
// 2. If module.[[Status]] is "instantiating", "instantiated", or "evaluated", then Return index.
|
||||
// 2. If module.[[Status]] is one of LINKING, LINKED, EVALUATING-ASYNC, or EVALUATED, then Return index.
|
||||
ModuleStatus status = module->GetStatus();
|
||||
if (status == ModuleStatus::INSTANTIATING ||
|
||||
status == ModuleStatus::INSTANTIATED ||
|
||||
status == ModuleStatus::EVALUATING_ASYNC ||
|
||||
status == ModuleStatus::EVALUATED) {
|
||||
return index;
|
||||
}
|
||||
@ -907,13 +923,8 @@ JSHandle<JSTaggedValue> SourceTextModule::GetModuleNamespace(JSThread *thread,
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
// 1. Assert: module is an instance of a concrete subclass of Module Record.
|
||||
// 2. Assert: module.[[Status]] is not "uninstantiated".
|
||||
ModuleStatus status = module->GetStatus();
|
||||
ASSERT(status != ModuleStatus::UNINSTANTIATED);
|
||||
// 3. Assert: If module.[[Status]] is "evaluated", module.[[EvaluationError]] is undefined.
|
||||
if (status == ModuleStatus::EVALUATED) {
|
||||
ASSERT(module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX);
|
||||
}
|
||||
// 4. Let namespace be module.[[Namespace]].
|
||||
ASSERT(module->GetStatus() != ModuleStatus::UNINSTANTIATED);
|
||||
// 3. Let namespace be module.[[Namespace]].
|
||||
JSMutableHandle<JSTaggedValue> moduleNamespace(thread, module->GetNamespace().GetWeakRawValue());
|
||||
// If namespace is undefined, then
|
||||
if (moduleNamespace->IsUndefined()) {
|
||||
@ -945,20 +956,12 @@ JSHandle<JSTaggedValue> SourceTextModule::GetModuleNamespace(JSThread *thread,
|
||||
return moduleNamespace;
|
||||
}
|
||||
|
||||
int SourceTextModule::Evaluate(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
const void *buffer, size_t size, bool excuteFromJob)
|
||||
void SourceTextModule::HandleEvaluateResult(JSThread *thread, JSHandle<SourceTextModule> &module,
|
||||
JSHandle<PromiseCapability> &capability, const CVector<JSHandle<SourceTextModule>> &stack, int result)
|
||||
{
|
||||
ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SourceTextModule::Evaluate");
|
||||
// 1. Let module be this Source Text Module Record.
|
||||
// 2. Assert: module.[[Status]] is "instantiated" or "evaluated".
|
||||
[[maybe_unused]] ModuleStatus status = module->GetStatus();
|
||||
ASSERT((status == ModuleStatus::INSTANTIATED || status == ModuleStatus::EVALUATED));
|
||||
// 3. Let stack be a new empty List.
|
||||
CVector<JSHandle<SourceTextModule>> stack;
|
||||
// 4. Let result be InnerModuleEvaluation(module, stack, 0)
|
||||
JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module);
|
||||
int result = SourceTextModule::InnerModuleEvaluation(thread, moduleRecord, stack, 0, buffer, size, excuteFromJob);
|
||||
// 5. If result is an abrupt completion, then
|
||||
ModuleStatus status;
|
||||
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
|
||||
// 9. If result is an abrupt completion, then
|
||||
if (thread->HasPendingException()) {
|
||||
// a. For each module m in stack, do
|
||||
for (auto mm : stack) {
|
||||
@ -972,16 +975,68 @@ int SourceTextModule::Evaluate(JSThread *thread, const JSHandle<SourceTextModule
|
||||
// b. Assert: module.[[Status]] is "evaluated" and module.[[EvaluationError]] is result.
|
||||
status = module->GetStatus();
|
||||
ASSERT(status == ModuleStatus::EVALUATED && module->GetEvaluationError() == result);
|
||||
// c. return result
|
||||
return result;
|
||||
//d. Perform ! Call(capability.[[Reject]], undefined, « result.[[Value]] »).
|
||||
JSHandle<JSTaggedValue> reject(thread, capability->GetReject());
|
||||
JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
|
||||
EcmaRuntimeCallInfo *info =
|
||||
EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefined, undefined, 1);
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
info->SetCallArg(JSTaggedValue(result));
|
||||
[[maybe_unused]] JSTaggedValue res = JSFunction::Call(info);
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
// 10. Else,
|
||||
} else {
|
||||
// a. Assert: module.[[Status]] is either EVALUATING-ASYNC or EVALUATED.
|
||||
status = module->GetStatus();
|
||||
ASSERT(status == ModuleStatus::EVALUATING_ASYNC || status == ModuleStatus::EVALUATED);
|
||||
// b. Assert: module.[[EvaluationError]] is EMPTY.
|
||||
ASSERT(module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX);
|
||||
// c. If module.[[AsyncEvaluation]] is false, then
|
||||
// i. Assert: module.[[Status]] is EVALUATED.
|
||||
// ii. Perform ! Call(capability.[[Resolve]], undefined, « undefined »).
|
||||
if (!module->IsAsyncEvaluating()) {
|
||||
ASSERT(status == ModuleStatus::EVALUATED);
|
||||
}
|
||||
// d. Assert: stack is empty.
|
||||
ASSERT(stack.empty());
|
||||
}
|
||||
// 6. Assert: module.[[Status]] is "evaluated" and module.[[EvaluationError]] is undefined.
|
||||
status = module->GetStatus();
|
||||
ASSERT(status == ModuleStatus::EVALUATED && module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX);
|
||||
// 7. Assert: stack is empty.
|
||||
ASSERT(stack.empty());
|
||||
// 8. Return undefined.
|
||||
return SourceTextModule::UNDEFINED_INDEX;
|
||||
}
|
||||
|
||||
JSTaggedValue SourceTextModule::Evaluate(JSThread *thread, const JSHandle<SourceTextModule> &moduleHdl,
|
||||
const void *buffer, size_t size, bool excuteFromJob)
|
||||
{
|
||||
ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SourceTextModule::Evaluate");
|
||||
// 1. Let module be this Source Text Module Record.
|
||||
// 2. Assert: module.[[Status]] is one of LINKED, EVALUATING-ASYNC, or EVALUATED.
|
||||
JSMutableHandle<SourceTextModule> module(thread, moduleHdl);
|
||||
ModuleStatus status = module->GetStatus();
|
||||
ASSERT((status == ModuleStatus::INSTANTIATED || status == ModuleStatus::EVALUATING_ASYNC ||
|
||||
status == ModuleStatus::EVALUATED));
|
||||
// 3. If module.[[Status]] is either EVALUATING-ASYNC or EVALUATED, set module to module.[[CycleRoot]].
|
||||
if (status == ModuleStatus::EVALUATING_ASYNC || status == ModuleStatus::EVALUATED) {
|
||||
module.Update(module->GetCycleRoot());
|
||||
}
|
||||
// 4. If module.[[TopLevelCapability]] is not EMPTY, then
|
||||
// a. Return module.[[TopLevelCapability]].[[Promise]].
|
||||
// 5. Let stack be a new empty List.
|
||||
CVector<JSHandle<SourceTextModule>> stack;
|
||||
// 6. Let capability be ! NewPromiseCapability(%Promise%).
|
||||
auto vm = thread->GetEcmaVM();
|
||||
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
|
||||
JSHandle<PromiseCapability> capability =
|
||||
JSPromise::NewPromiseCapability(thread, JSHandle<JSTaggedValue>::Cast(env->GetPromiseFunction()));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
// 7. Set module.[[TopLevelCapability]] to capability.
|
||||
module->SetTopLevelCapability(thread, capability);
|
||||
// 8. Let result be Completion(InnerModuleEvaluation(module, stack, 0)).
|
||||
JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module);
|
||||
int result = SourceTextModule::InnerModuleEvaluation(thread, moduleRecord, stack, 0, buffer, size, excuteFromJob);
|
||||
HandleEvaluateResult(thread, module, capability, stack, result);
|
||||
if (!thread->HasPendingException()) {
|
||||
job::MicroJobQueue::ExecutePendingJob(thread, thread->GetCurrentEcmaContext()->GetMicroJobQueue());
|
||||
}
|
||||
// Return capability.[[Promise]].
|
||||
return capability->GetPromise();
|
||||
}
|
||||
|
||||
int SourceTextModule::EvaluateForConcurrent(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
@ -991,51 +1046,47 @@ int SourceTextModule::EvaluateForConcurrent(JSThread *thread, const JSHandle<Sou
|
||||
// 2. Assert: module.[[Status]] is "instantiated" or "evaluated".
|
||||
[[maybe_unused]] ModuleStatus status = module->GetStatus();
|
||||
ASSERT((status == ModuleStatus::INSTANTIATED || status == ModuleStatus::EVALUATED));
|
||||
// 3. Let stack be a new empty List.
|
||||
CVector<JSHandle<SourceTextModule>> stack;
|
||||
// 4. Let result be InnerModuleEvaluation(module, stack, 0)
|
||||
JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module);
|
||||
int result = SourceTextModule::ModuleEvaluation(thread, moduleRecord, stack, 0, method);
|
||||
int result = SourceTextModule::ModuleEvaluation(thread, moduleRecord, 0, method);
|
||||
// 5. If result is an abrupt completion, then
|
||||
if (thread->HasPendingException()) {
|
||||
// a. For each module m in stack, do
|
||||
for (auto mm : stack) {
|
||||
// i. Assert: m.[[Status]] is "evaluating".
|
||||
ASSERT(mm->GetStatus() == ModuleStatus::EVALUATING);
|
||||
// ii. Set m.[[Status]] to "evaluated".
|
||||
mm->SetStatus(ModuleStatus::EVALUATED);
|
||||
// iii. Set m.[[EvaluationError]] to result.
|
||||
mm->SetEvaluationError(result);
|
||||
}
|
||||
// b. Assert: module.[[EvaluationError]] is result.
|
||||
ASSERT(module->GetEvaluationError() == result);
|
||||
// c. return result
|
||||
return result;
|
||||
} else {
|
||||
job::MicroJobQueue::ExecutePendingJob(thread, thread->GetCurrentEcmaContext()->GetMicroJobQueue());
|
||||
return SourceTextModule::UNDEFINED_INDEX;
|
||||
}
|
||||
// 6. Assert: module.[[EvaluationError]] is undefined.
|
||||
ASSERT(module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX);
|
||||
// 7. Assert: stack is empty.
|
||||
ASSERT(stack.empty());
|
||||
// 8. Return undefined.
|
||||
return SourceTextModule::UNDEFINED_INDEX;
|
||||
}
|
||||
|
||||
int SourceTextModule::InnerModuleEvaluation(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord,
|
||||
CVector<JSHandle<SourceTextModule>> &stack, int index,
|
||||
const void *buffer, size_t size, bool excuteFromJob)
|
||||
{
|
||||
// 1. If module is not a Source Text Module Record, then
|
||||
// 1.If module is not a Cyclic Module Record, then
|
||||
if (!moduleRecord.GetTaggedValue().IsSourceTextModule()) {
|
||||
// a. Perform ? module.Instantiate().
|
||||
ModuleRecord::Instantiate(thread, JSHandle<JSTaggedValue>::Cast(moduleRecord));
|
||||
// a. Let promise be ! module.Evaluate().
|
||||
JSTaggedValue promise = ModuleRecord::Evaluate(thread, JSHandle<JSTaggedValue>::Cast(moduleRecord));
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
|
||||
// b. Return index.
|
||||
// b. Assert: promise.[[PromiseState]] is not PENDING.
|
||||
PromiseState state = JSPromise::Cast(promise.GetTaggedObject())->GetPromiseState();
|
||||
ASSERT(state != PromiseState::PENDING);
|
||||
// c. If promise.[[PromiseState]] is REJECTED, then
|
||||
// i. Return ThrowCompletion(promise.[[PromiseResult]]).
|
||||
if (state == PromiseState::REJECTED) {
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
JSTaggedValue promiseResult = JSPromise::Cast(promise.GetTaggedObject())->GetPromiseResult();
|
||||
JSHandle<JSObject> error =
|
||||
factory->GetJSError(base::ErrorType::ERROR, nullptr);
|
||||
THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error.GetTaggedValue(), promiseResult.GetInt());
|
||||
}
|
||||
// d. Return index.
|
||||
return index;
|
||||
}
|
||||
|
||||
JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
|
||||
// 2.If module.[[Status]] is "evaluated", then
|
||||
// 2. If module.[[Status]] is either EVALUATING-ASYNC or EVALUATED, then
|
||||
ModuleStatus status = module->GetStatus();
|
||||
if (status == ModuleStatus::EVALUATED) {
|
||||
if (status == ModuleStatus::EVALUATING_ASYNC || status == ModuleStatus::EVALUATED) {
|
||||
// a. If module.[[EvaluationError]] is undefined, return index
|
||||
if (module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX) {
|
||||
return index;
|
||||
@ -1055,11 +1106,13 @@ int SourceTextModule::InnerModuleEvaluation(JSThread *thread, const JSHandle<Mod
|
||||
module->SetDFSIndex(index);
|
||||
// 7. Set module.[[DFSAncestorIndex]] to index.
|
||||
module->SetDFSAncestorIndex(index);
|
||||
// 8. Set index to index + 1.
|
||||
// 8. Set module.[[PendingAsyncDependencies]] to 0.
|
||||
module->SetPendingAsyncDependencies(0);
|
||||
// 9. Set index to index + 1.
|
||||
index++;
|
||||
// 9. Append module to stack.
|
||||
// 10. Append module to stack.
|
||||
stack.emplace_back(module);
|
||||
// 10. For each String required that is an element of module.[[RequestedModules]], do
|
||||
// 11. For each String required that is an element of module.[[RequestedModules]], do
|
||||
if (!module->GetRequestedModules().IsUndefined()) {
|
||||
JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules());
|
||||
size_t requestedModulesLen = requestedModules->GetLength();
|
||||
@ -1092,25 +1145,48 @@ int SourceTextModule::InnerModuleEvaluation(JSThread *thread, const JSHandle<Mod
|
||||
requiredModule->SetStatus(ModuleStatus::EVALUATED);
|
||||
continue;
|
||||
}
|
||||
// c. Set index to ? InnerModuleEvaluation(requiredModule, stack, index).
|
||||
// b. Set index to ? InnerModuleEvaluation(requiredModule, stack, index).
|
||||
JSHandle<ModuleRecord> requiredModuleRecord = JSHandle<ModuleRecord>::Cast(requiredModule);
|
||||
index = SourceTextModule::InnerModuleEvaluation(thread, requiredModuleRecord, stack, index);
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
|
||||
// d. Assert: requiredModule.[[Status]] is either "evaluating" or "evaluated".
|
||||
// c. If requiredModule is a Cyclic Module Record, then
|
||||
// i. Assert: requiredModule.[[Status]] is one of EVALUATING, EVALUATING-ASYNC, or EVALUATED.
|
||||
ModuleStatus requiredModuleStatus = requiredModule->GetStatus();
|
||||
ASSERT((requiredModuleStatus == ModuleStatus::EVALUATING ||
|
||||
requiredModuleStatus == ModuleStatus::EVALUATED));
|
||||
// e. Assert: requiredModule.[[Status]] is "evaluating" if and only if requiredModule is in stack.
|
||||
ASSERT(requiredModuleStatus == ModuleStatus::EVALUATING ||
|
||||
requiredModuleStatus == ModuleStatus::EVALUATING_ASYNC ||
|
||||
requiredModuleStatus == ModuleStatus::EVALUATED);
|
||||
// ii. Assert: requiredModule.[[Status]] is EVALUATING if and only if stack contains requiredModule.
|
||||
if (requiredModuleStatus == ModuleStatus::EVALUATING) {
|
||||
ASSERT(std::find(stack.begin(), stack.end(), requiredModule) != stack.end());
|
||||
}
|
||||
// f. If requiredModule.[[Status]] is "evaluating", then
|
||||
if (std::find(stack.begin(), stack.end(), requiredModule) != stack.end()) {
|
||||
ASSERT(requiredModuleStatus == ModuleStatus::EVALUATING);
|
||||
}
|
||||
// iii. If requiredModule.[[Status]] is EVALUATING, then
|
||||
if (requiredModuleStatus == ModuleStatus::EVALUATING) {
|
||||
// i. Assert: requiredModule is a Source Text Module Record.
|
||||
// ii. Set module.[[DFSAncestorIndex]] to min(
|
||||
// module.[[DFSAncestorIndex]], requiredModule.[[DFSAncestorIndex]]).
|
||||
// 1. Set module.[[DFSAncestorIndex]] to min(module.[[DFSAncestorIndex]],
|
||||
// requiredModule.[[DFSAncestorIndex]]).
|
||||
int dfsAncIdx = std::min(module->GetDFSAncestorIndex(), requiredModule->GetDFSAncestorIndex());
|
||||
module->SetDFSAncestorIndex(dfsAncIdx);
|
||||
// iv. Else,
|
||||
} else {
|
||||
// 1. Set requiredModule to requiredModule.[[CycleRoot]].
|
||||
requiredModule.Update(requiredModule->GetCycleRoot());
|
||||
// 2. Assert: requiredModule.[[Status]] is either EVALUATING-ASYNC or EVALUATED.
|
||||
requiredModuleStatus = requiredModule->GetStatus();
|
||||
ASSERT(requiredModuleStatus == ModuleStatus::EVALUATING_ASYNC ||
|
||||
requiredModuleStatus == ModuleStatus::EVALUATED);
|
||||
// 3. If requiredModule.[[EvaluationError]] is not EMPTY, return ? requiredModule.[[EvaluationError]].
|
||||
if (requiredModule->GetEvaluationError() != SourceTextModule::UNDEFINED_INDEX) {
|
||||
return requiredModule->GetEvaluationError();
|
||||
}
|
||||
}
|
||||
// v. If requiredModule.[[AsyncEvaluation]] is true, then
|
||||
// 1. Set module.[[PendingAsyncDependencies]] to module.[[PendingAsyncDependencies]] + 1.
|
||||
// 2. Append module to requiredModule.[[AsyncParentModules]].
|
||||
if (requiredModule->IsAsyncEvaluating()) {
|
||||
module->SetPendingAsyncDependencies(module->GetPendingAsyncDependencies() + 1);
|
||||
AddAsyncParentModule(thread, requiredModule, module);
|
||||
}
|
||||
// if requiredModule is CommonJS Module, instantiate here (after CommonJS execution).
|
||||
if (moduleType == ModuleTypes::CJS_MODULE) {
|
||||
@ -1118,16 +1194,31 @@ int SourceTextModule::InnerModuleEvaluation(JSThread *thread, const JSHandle<Mod
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 11. Perform ? ModuleExecution(module).
|
||||
SourceTextModule::ModuleExecution(thread, module, buffer, size, excuteFromJob);
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
|
||||
// 12. Assert: module occurs exactly once in stack.
|
||||
// 13. Assert: module.[[DFSAncestorIndex]] is less than or equal to module.[[DFSIndex]].
|
||||
int pendingAsyncDependencies = module->GetPendingAsyncDependencies();
|
||||
bool hasTLA = module->GetHasTLA();
|
||||
auto moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
|
||||
// 12. If module.[[PendingAsyncDependencies]] > 0 or module.[[HasTLA]] is true, then
|
||||
if (pendingAsyncDependencies > 0 || hasTLA) {
|
||||
// a. Assert: module.[[AsyncEvaluation]] is false and was never previously set to true.
|
||||
ASSERT(module->GetAsyncEvaluatingOrdinal() == NOT_ASYNC_EVALUATED);
|
||||
// b. Set module.[[AsyncEvaluation]] to true.
|
||||
module->SetAsyncEvaluatingOrdinal(moduleManager->NextModuleAsyncEvaluatingOrdinal());
|
||||
// d. If module.[[PendingAsyncDependencies]] = 0, perform ExecuteAsyncModule(module).
|
||||
if (pendingAsyncDependencies == 0) {
|
||||
SourceTextModule::ExecuteAsyncModule(thread, module, buffer, size, excuteFromJob);
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
|
||||
}
|
||||
} else {
|
||||
// 13. Else, Perform ? module.ExecuteModule().
|
||||
SourceTextModule::ModuleExecution(thread, module, buffer, size, excuteFromJob);
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
|
||||
}
|
||||
// 14. Assert: module occurs exactly once in stack.
|
||||
// 15. Assert: module.[[DFSAncestorIndex]] ≤ module.[[DFSIndex]].
|
||||
int dfsAncIdx = module->GetDFSAncestorIndex();
|
||||
int dfsIdx = module->GetDFSIndex();
|
||||
ASSERT(dfsAncIdx <= dfsIdx);
|
||||
// 14. If module.[[DFSAncestorIndex]] equals module.[[DFSIndex]], then
|
||||
// 16. If module.[[DFSAncestorIndex]] = module.[[DFSIndex]], then
|
||||
if (dfsAncIdx == dfsIdx) {
|
||||
// a. Let done be false.
|
||||
bool done = false;
|
||||
@ -1137,20 +1228,62 @@ int SourceTextModule::InnerModuleEvaluation(JSThread *thread, const JSHandle<Mod
|
||||
JSHandle<SourceTextModule> requiredModule = stack.back();
|
||||
// ii. Remove the last element of stack.
|
||||
stack.pop_back();
|
||||
// iii. Set requiredModule.[[Status]] to "evaluated".
|
||||
requiredModule->SetStatus(ModuleStatus::EVALUATED);
|
||||
// iv. If requiredModule and module are the same Module Record, set done to true.
|
||||
// iii. Assert: requiredModule is a Cyclic Module Record.
|
||||
// iv. If requiredModule.[[AsyncEvaluation]] is false, set requiredModule.[[Status]] to EVALUATED.
|
||||
// v. Otherwise, set requiredModule.[[Status]] to EVALUATING-ASYNC.
|
||||
if (!requiredModule->IsAsyncEvaluating()) {
|
||||
requiredModule->SetStatus(ModuleStatus::EVALUATED);
|
||||
} else {
|
||||
requiredModule->SetStatus(ModuleStatus::EVALUATING_ASYNC);
|
||||
}
|
||||
// vi. If requiredModule and module are the same Module Record, set done to true.
|
||||
if (JSTaggedValue::SameValue(module.GetTaggedValue(), requiredModule.GetTaggedValue())) {
|
||||
done = true;
|
||||
}
|
||||
// vii. Set requiredModule.[[CycleRoot]] to module.
|
||||
requiredModule->SetCycleRoot(thread, module);
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
void SourceTextModule::HandleConcurrentEvaluateResult(JSThread *thread, JSHandle<SourceTextModule> &module,
|
||||
const CVector<JSHandle<SourceTextModule>> &stack, int result)
|
||||
{
|
||||
ModuleStatus status;
|
||||
// 9. If result is an abrupt completion, then
|
||||
if (thread->HasPendingException()) {
|
||||
// a. For each module m in stack, do
|
||||
for (auto mm : stack) {
|
||||
// i. Assert: m.[[Status]] is "evaluating".
|
||||
ASSERT(mm->GetStatus() == ModuleStatus::EVALUATING);
|
||||
// ii. Set m.[[Status]] to "evaluated".
|
||||
mm->SetStatus(ModuleStatus::EVALUATED);
|
||||
// iii. Set m.[[EvaluationError]] to result.
|
||||
mm->SetEvaluationError(result);
|
||||
}
|
||||
// b. Assert: module.[[Status]] is "evaluated" and module.[[EvaluationError]] is result.
|
||||
status = module->GetStatus();
|
||||
ASSERT(status == ModuleStatus::EVALUATED && module->GetEvaluationError() == result);
|
||||
// 10. Else,
|
||||
} else {
|
||||
// a. Assert: module.[[Status]] is either EVALUATING-ASYNC or EVALUATED.
|
||||
status = module->GetStatus();
|
||||
ASSERT(status == ModuleStatus::EVALUATING_ASYNC || status == ModuleStatus::EVALUATED);
|
||||
// b. Assert: module.[[EvaluationError]] is EMPTY.
|
||||
ASSERT(module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX);
|
||||
// c. If module.[[AsyncEvaluation]] is false, then
|
||||
// i. Assert: module.[[Status]] is EVALUATED.
|
||||
if (!module->IsAsyncEvaluating()) {
|
||||
ASSERT(status == ModuleStatus::EVALUATED);
|
||||
}
|
||||
// d. Assert: stack is empty.
|
||||
ASSERT(stack.empty());
|
||||
}
|
||||
}
|
||||
|
||||
int SourceTextModule::ModuleEvaluation(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord,
|
||||
CVector<JSHandle<SourceTextModule>> &stack, int index,
|
||||
const JSHandle<Method> &method)
|
||||
int index, const JSHandle<Method> &method)
|
||||
{
|
||||
JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
|
||||
if (!module->GetRequestedModules().IsUndefined()) {
|
||||
@ -1184,7 +1317,10 @@ int SourceTextModule::ModuleEvaluation(JSThread *thread, const JSHandle<ModuleRe
|
||||
continue;
|
||||
}
|
||||
JSHandle<ModuleRecord> requiredModuleRecord = JSHandle<ModuleRecord>::Cast(requiredModule);
|
||||
index = SourceTextModule::InnerModuleEvaluation(thread, requiredModuleRecord, stack, index);
|
||||
CVector<JSHandle<SourceTextModule>> stack;
|
||||
int result = SourceTextModule::InnerModuleEvaluation(thread, requiredModuleRecord, stack, 0);
|
||||
index += result;
|
||||
HandleConcurrentEvaluateResult(thread, requiredModule, stack, result);
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index);
|
||||
[[maybe_unused]] ModuleStatus requiredModuleStatus = requiredModule->GetStatus();
|
||||
ASSERT(requiredModuleStatus == ModuleStatus::EVALUATED);
|
||||
@ -1196,8 +1332,8 @@ int SourceTextModule::ModuleEvaluation(JSThread *thread, const JSHandle<ModuleRe
|
||||
return index;
|
||||
}
|
||||
|
||||
void SourceTextModule::ModuleExecution(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
const void *buffer, size_t size, bool excuteFromJob)
|
||||
Expected<JSTaggedValue, bool> SourceTextModule::ModuleExecution(JSThread *thread,
|
||||
const JSHandle<SourceTextModule> &module, const void *buffer, size_t size, bool excuteFromJob)
|
||||
{
|
||||
JSTaggedValue moduleFileName = module->GetEcmaModuleFilename();
|
||||
ASSERT(moduleFileName.IsString());
|
||||
@ -1224,9 +1360,9 @@ void SourceTextModule::ModuleExecution(JSThread *thread, const JSHandle<SourceTe
|
||||
if (jsPandaFile == nullptr) {
|
||||
CString msg = "Load file with filename '" + moduleFilenameStr + "' failed, recordName '" +
|
||||
entryPoint.c_str() + "'";
|
||||
THROW_ERROR(thread, ErrorType::REFERENCE_ERROR, msg.c_str());
|
||||
THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
|
||||
}
|
||||
JSPandaFileExecutor::Execute(thread, jsPandaFile.get(), entryPoint, excuteFromJob);
|
||||
return JSPandaFileExecutor::Execute(thread, jsPandaFile.get(), entryPoint, excuteFromJob);
|
||||
}
|
||||
|
||||
void SourceTextModule::AddImportEntry(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
@ -1694,4 +1830,304 @@ bool SourceTextModule::IsDynamicModule(LoadingTypes types)
|
||||
{
|
||||
return types == LoadingTypes::DYNAMITC_MODULE;
|
||||
}
|
||||
|
||||
bool SourceTextModule::IsAsyncEvaluating()
|
||||
{
|
||||
return GetAsyncEvaluatingOrdinal() >= FIRST_ASYNC_EVALUATING_ORDINAL;
|
||||
}
|
||||
|
||||
void SourceTextModule::AddAsyncParentModule(JSThread *thread, JSHandle<SourceTextModule> &module,
|
||||
JSHandle<SourceTextModule> &parent)
|
||||
{
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
JSTaggedValue asyncParentModules = module->GetAsyncParentModules();
|
||||
if (asyncParentModules.IsUndefined()) {
|
||||
JSHandle<TaggedArray> array = factory->NewTaggedArray(1);
|
||||
array->Set(thread, 0, parent.GetTaggedValue());
|
||||
module->SetAsyncParentModules(thread, array);
|
||||
} else {
|
||||
JSHandle<TaggedArray> array(thread, asyncParentModules);
|
||||
array = TaggedArray::SetCapacity(thread, array, array->GetLength() + 1);
|
||||
array->Set(thread, array->GetLength() - 1, parent.GetTaggedValue());
|
||||
module->SetAsyncParentModules(thread, array);
|
||||
}
|
||||
}
|
||||
|
||||
void SourceTextModule::ExecuteAsyncModule(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
const void *buffer, size_t size, bool excuteFromJob)
|
||||
{
|
||||
// 1. Assert: module.[[Status]] is either EVALUATING or EVALUATING-ASYNC.
|
||||
ASSERT(module->GetStatus() == ModuleStatus::EVALUATING || module->GetStatus() == ModuleStatus::EVALUATING_ASYNC);
|
||||
// 2. Assert: module.[[HasTLA]] is true.
|
||||
ASSERT(module->GetHasTLA());
|
||||
JSTaggedValue moduleFileName = module->GetEcmaModuleFilename();
|
||||
ASSERT(moduleFileName.IsString());
|
||||
CString moduleFilenameStr = ConvertToString(EcmaString::Cast(moduleFileName.GetTaggedObject()));
|
||||
|
||||
std::string entryPoint;
|
||||
JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();
|
||||
if (moduleRecordName.IsUndefined()) {
|
||||
entryPoint = JSPandaFile::ENTRY_FUNCTION_NAME;
|
||||
} else {
|
||||
ASSERT(moduleRecordName.IsString());
|
||||
entryPoint = ConvertToString(moduleRecordName);
|
||||
}
|
||||
|
||||
std::shared_ptr<JSPandaFile> jsPandaFile;
|
||||
if (buffer != nullptr) {
|
||||
jsPandaFile =
|
||||
JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, moduleFilenameStr, entryPoint, buffer, size);
|
||||
} else {
|
||||
jsPandaFile =
|
||||
JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, moduleFilenameStr, entryPoint);
|
||||
}
|
||||
|
||||
if (jsPandaFile == nullptr) {
|
||||
CString msg = "Load file with filename '" + moduleFilenameStr + "' failed, recordName '" +
|
||||
entryPoint.c_str() + "'";
|
||||
THROW_ERROR(thread, ErrorType::REFERENCE_ERROR, msg.c_str());
|
||||
}
|
||||
Expected<JSTaggedValue, bool> result =
|
||||
JSPandaFileExecutor::Execute(thread, jsPandaFile.get(), entryPoint, excuteFromJob);
|
||||
ASSERT(result.Value().IsJSPromise());
|
||||
// 3. Let capability be ! NewPromiseCapability(%Promise%).
|
||||
// 4. Let fulfilledClosure be a new Abstract Closure with no parameters that captures module and performs
|
||||
// the following steps when called:
|
||||
// a. Perform AsyncModuleExecutionFulfilled(module).
|
||||
// b. Return undefined.
|
||||
// 5. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 0, "", « »).
|
||||
// 6. Let rejectedClosure be a new Abstract Closure with parameters (error) that captures module and performs
|
||||
// the following steps when called:
|
||||
// a. Perform AsyncModuleExecutionRejected(module, error).
|
||||
// b. Return undefined.
|
||||
// 7. Let onRejected be CreateBuiltinFunction(rejectedClosure, 0, "", « »).
|
||||
// 8. Perform PerformPromiseThen(capability.[[Promise]], onFulfilled, onRejected).
|
||||
JSHandle<JSPromise> promise(thread, result.Value());
|
||||
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<JSAsyncModuleFulfilledFunction> onFulfilled =
|
||||
factory->CreateJSAsyncModuleFulfilledFunction();
|
||||
onFulfilled->SetModule(thread, module);
|
||||
|
||||
JSHandle<JSAsyncModuleRejectedFunction> onRejected =
|
||||
factory->CreateJSAsyncModuleRejectedFunction();
|
||||
onRejected->SetModule(thread, module);
|
||||
JSHandle<PromiseCapability> tcap =
|
||||
JSPromise::NewPromiseCapability(thread, JSHandle<JSTaggedValue>::Cast(env->GetPromiseFunction()));
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
builtins::BuiltinsPromise::PerformPromiseThen(
|
||||
thread, promise, JSHandle<JSTaggedValue>::Cast(onFulfilled),
|
||||
JSHandle<JSTaggedValue>::Cast(onRejected), tcap);
|
||||
}
|
||||
|
||||
void SourceTextModule::GatherAvailableAncestors(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
AsyncParentCompletionSet &execList)
|
||||
{
|
||||
auto globalConstants = thread->GlobalConstants();
|
||||
JSTaggedValue asyncParentModulesValue = module->GetAsyncParentModules();
|
||||
if (asyncParentModulesValue.IsUndefined()) {
|
||||
return;
|
||||
}
|
||||
JSMutableHandle<SourceTextModule> cycleRoot(thread, globalConstants->GetUndefined());
|
||||
JSHandle<TaggedArray> asyncParentModules(thread, asyncParentModulesValue);
|
||||
size_t asyncParentModulesLen = asyncParentModules->GetLength();
|
||||
// 1. For each Cyclic Module Record m of module.[[AsyncParentModules]], do
|
||||
for (size_t idx = 0; idx < asyncParentModulesLen; idx++) {
|
||||
JSHandle<SourceTextModule> parentModule(thread, asyncParentModules->Get(idx));
|
||||
// a. If execList does not contain m and m.[[CycleRoot]].[[EvaluationError]] is EMPTY, then
|
||||
cycleRoot.Update(parentModule->GetCycleRoot());
|
||||
if (execList.find(parentModule) == execList.end() &&
|
||||
cycleRoot->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX) {
|
||||
// i. Assert: m.[[Status]] is EVALUATING-ASYNC.
|
||||
ASSERT(parentModule->GetStatus() == ModuleStatus::EVALUATING_ASYNC);
|
||||
// ii. Assert: m.[[EvaluationError]] is EMPTY.
|
||||
ASSERT(parentModule->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX);
|
||||
// iii. Assert: m.[[AsyncEvaluation]] is true.
|
||||
ASSERT(parentModule->IsAsyncEvaluating());
|
||||
// iv. Assert: m.[[PendingAsyncDependencies]] > 0.
|
||||
ASSERT(parentModule->GetPendingAsyncDependencies() > 0);
|
||||
// v. Set m.[[PendingAsyncDependencies]] to m.[[PendingAsyncDependencies]] - 1.
|
||||
parentModule->SetPendingAsyncDependencies(parentModule->GetPendingAsyncDependencies() - 1);
|
||||
// vi. If m.[[PendingAsyncDependencies]] = 0, then
|
||||
// 1. Append m to execList.
|
||||
// 2. If m.[[HasTLA]] is false, perform GatherAvailableAncestors(m, execList).
|
||||
if (parentModule->GetPendingAsyncDependencies() == 0) {
|
||||
execList.insert(parentModule);
|
||||
if (!parentModule->GetHasTLA()) {
|
||||
GatherAvailableAncestors(thread, parentModule, execList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SourceTextModule::AsyncModuleExecutionFulfilled(JSThread *thread, const JSHandle<SourceTextModule> &module)
|
||||
{
|
||||
// 1. If module.[[Status]] is EVALUATED, then
|
||||
// a. Assert: module.[[EvaluationError]] is not EMPTY.
|
||||
// b. Return UNUSED.
|
||||
if (module->GetStatus() == ModuleStatus::EVALUATED) {
|
||||
ASSERT(module->GetEvaluationError() != SourceTextModule::UNDEFINED_INDEX);
|
||||
return;
|
||||
}
|
||||
// 2. Assert: module.[[Status]] is EVALUATING-ASYNC.
|
||||
ASSERT(module->GetStatus() == ModuleStatus::EVALUATING_ASYNC);
|
||||
// 3. Assert: module.[[AsyncEvaluation]] is true.
|
||||
ASSERT(module->IsAsyncEvaluating());
|
||||
// 4. Assert: module.[[EvaluationError]] is EMPTY.
|
||||
ASSERT(module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX);
|
||||
// 5. Set module.[[AsyncEvaluation]] to false.
|
||||
module->SetAsyncEvaluatingOrdinal(ASYNC_EVALUATE_DID_FINISH);
|
||||
// 6. Set module.[[Status]] to EVALUATED.
|
||||
module->SetStatus(ModuleStatus::EVALUATED);
|
||||
// 7. If module.[[TopLevelCapability]] is not EMPTY, then
|
||||
// a. Assert: module.[[CycleRoot]] is module.
|
||||
// b. Perform ! Call(module.[[TopLevelCapability]].[[Resolve]], undefined, « undefined »).
|
||||
auto globalConstants = thread->GlobalConstants();
|
||||
JSTaggedValue topLevelCapabilityValue = module->GetTopLevelCapability();
|
||||
if (!topLevelCapabilityValue.IsUndefined()) {
|
||||
ASSERT(JSTaggedValue::SameValue(module->GetCycleRoot(), module.GetTaggedValue()));
|
||||
JSHandle<PromiseCapability> topLevelCapability(thread, topLevelCapabilityValue);
|
||||
JSHandle<JSTaggedValue> resolve(thread, topLevelCapability->GetResolve());
|
||||
JSHandle<JSTaggedValue> undefined = globalConstants->GetHandledUndefined();
|
||||
EcmaRuntimeCallInfo *info =
|
||||
EcmaInterpreter::NewRuntimeCallInfo(thread, resolve, undefined, undefined, 1);
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
info->SetCallArg(JSTaggedValue::Undefined());
|
||||
[[maybe_unused]] JSTaggedValue res = JSFunction::Call(info);
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
}
|
||||
// 8. Let execList be a new empty List.
|
||||
AsyncParentCompletionSet execList;
|
||||
// 9. Perform GatherAvailableAncestors(module, execList).
|
||||
// 10. Let sortedExecList be a List whose elements are the elements of execList,
|
||||
// in the order in which they had their [[AsyncEvaluation]] fields set to true in InnerModuleEvaluation.
|
||||
GatherAvailableAncestors(thread, module, execList);
|
||||
// 11. Assert: All elements of sortedExecList have their [[AsyncEvaluation]] field set to true,
|
||||
// [[PendingAsyncDependencies]] field set to 0, and [[EvaluationError]] field set to EMPTY.
|
||||
// 12. For each Cyclic Module Record m of sortedExecList, do
|
||||
for (JSHandle<SourceTextModule> m : execList) {
|
||||
// a. If m.[[Status]] is EVALUATED, then
|
||||
// i. Assert: m.[[EvaluationError]] is not EMPTY.
|
||||
if (m->GetStatus() == ModuleStatus::EVALUATED) {
|
||||
ASSERT(m->GetEvaluationError() != UNDEFINED_INDEX);
|
||||
// b. Else if m.[[HasTLA]] is true, then
|
||||
// i. Perform ExecuteAsyncModule(m).
|
||||
} else if (m->GetHasTLA()) {
|
||||
ExecuteAsyncModule(thread, m);
|
||||
// c. Else,
|
||||
} else {
|
||||
// i. Let result be m.ExecuteModule().
|
||||
Expected<JSTaggedValue, bool> result = SourceTextModule::ModuleExecution(thread, m);
|
||||
// ii. If result is an abrupt completion, then
|
||||
// 1. Perform AsyncModuleExecutionRejected(m, result.[[Value]]).
|
||||
if (thread->HasPendingException() || !result || result.Value().IsException()) {
|
||||
AsyncModuleExecutionRejected(thread, m, JSTaggedValue::Exception());
|
||||
// iii. Else,
|
||||
} else {
|
||||
// 1. Set m.[[Status]] to EVALUATED.
|
||||
m->SetStatus(ModuleStatus::EVALUATED);
|
||||
// 2. If m.[[TopLevelCapability]] is not EMPTY, then
|
||||
// a. Assert: m.[[CycleRoot]] is m.
|
||||
// b. Perform ! Call(m.[[TopLevelCapability]].[[Resolve]], undefined, « undefined »).
|
||||
JSTaggedValue capabilityValue = m->GetTopLevelCapability();
|
||||
if (!capabilityValue.IsUndefined()) {
|
||||
ASSERT(JSTaggedValue::SameValue(m->GetCycleRoot(), m.GetTaggedValue()));
|
||||
JSHandle<PromiseCapability> topLevelCapability(thread, capabilityValue);
|
||||
JSHandle<JSTaggedValue> resolve(thread, topLevelCapability->GetResolve());
|
||||
JSHandle<JSTaggedValue> undefined = globalConstants->GetHandledUndefined();
|
||||
EcmaRuntimeCallInfo *info =
|
||||
EcmaInterpreter::NewRuntimeCallInfo(thread, resolve, undefined, undefined, 1);
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
info->SetCallArg(JSTaggedValue::Undefined());
|
||||
[[maybe_unused]] JSTaggedValue res = JSFunction::Call(info);
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SourceTextModule::AsyncModuleExecutionRejected(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
JSTaggedValue error)
|
||||
{
|
||||
// 1. If module.[[Status]] is EVALUATED, then
|
||||
// a. Assert: module.[[EvaluationError]] is not EMPTY.
|
||||
// b. Return UNUSED.
|
||||
if (module->GetStatus() == ModuleStatus::EVALUATED) {
|
||||
ASSERT(module->GetEvaluationError() != SourceTextModule::UNDEFINED_INDEX);
|
||||
return;
|
||||
}
|
||||
// 2. Assert: module.[[Status]] is EVALUATING-ASYNC.
|
||||
ASSERT(module->GetStatus() == ModuleStatus::EVALUATING_ASYNC);
|
||||
// 3. Assert: module.[[AsyncEvaluation]] is true.
|
||||
ASSERT(module->IsAsyncEvaluating());
|
||||
// 4. Assert: module.[[EvaluationError]] is EMPTY.
|
||||
ASSERT(module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX);
|
||||
// 5. Set module.[[EvaluationError]] to ThrowCompletion(error).
|
||||
module->SetEvaluationError(MODULE_ERROR);
|
||||
// 6. Set module.[[Status]] to EVALUATED.
|
||||
module->SetStatus(ModuleStatus::EVALUATED);
|
||||
// 7. For each Cyclic Module Record m of module.[[AsyncParentModules]], do
|
||||
// a. Perform AsyncModuleExecutionRejected(m, error).
|
||||
auto globalConstants = thread->GlobalConstants();
|
||||
JSTaggedValue asyncParentModulesValue = module->GetAsyncParentModules();
|
||||
if (!asyncParentModulesValue.IsUndefined()) {
|
||||
JSMutableHandle<SourceTextModule> parentModule(thread, globalConstants->GetUndefined());
|
||||
JSHandle<TaggedArray> asyncParentModules(thread, asyncParentModulesValue);
|
||||
size_t asyncParentModulesLen = asyncParentModules->GetLength();
|
||||
for (size_t idx = 0; idx < asyncParentModulesLen; idx++) {
|
||||
parentModule.Update(asyncParentModules->Get(idx));
|
||||
AsyncModuleExecutionRejected(thread, parentModule, error);
|
||||
}
|
||||
}
|
||||
|
||||
// 8. If module.[[TopLevelCapability]] is not EMPTY, then
|
||||
// a. Assert: module.[[CycleRoot]] is module.
|
||||
// b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]], undefined, « error »).
|
||||
JSTaggedValue topLevelCapabilityValue = module->GetTopLevelCapability();
|
||||
if (!topLevelCapabilityValue.IsUndefined()) {
|
||||
JSHandle<JSTaggedValue> exceptionHandle(thread, error);
|
||||
// if caught exceptionHandle type is JSError
|
||||
if (exceptionHandle->IsJSError()) {
|
||||
thread->GetCurrentEcmaContext()->HandleUncaughtException(error);
|
||||
}
|
||||
ASSERT(JSTaggedValue::SameValue(module->GetCycleRoot(), module.GetTaggedValue()));
|
||||
JSHandle<PromiseCapability> topLevelCapability(thread, topLevelCapabilityValue);
|
||||
JSHandle<JSTaggedValue> reject(thread, topLevelCapability->GetReject());
|
||||
JSHandle<JSTaggedValue> undefined = globalConstants->GetHandledUndefined();
|
||||
EcmaRuntimeCallInfo *info =
|
||||
EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefined, undefined, 1);
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
info->SetCallArg(error);
|
||||
[[maybe_unused]] JSTaggedValue res = JSFunction::Call(info);
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
}
|
||||
}
|
||||
|
||||
JSTaggedValue SourceTextModule::AsyncModuleFulfilledFunc(EcmaRuntimeCallInfo *argv)
|
||||
{
|
||||
ASSERT(argv);
|
||||
JSThread *thread = argv->GetThread();
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
JSHandle<JSAsyncModuleFulfilledFunction> fulfilledFunc =
|
||||
JSHandle<JSAsyncModuleFulfilledFunction>::Cast(base::BuiltinsBase::GetConstructor(argv));
|
||||
JSHandle<SourceTextModule> module(thread, fulfilledFunc->GetModule());
|
||||
AsyncModuleExecutionFulfilled(thread, module);
|
||||
return JSTaggedValue::Undefined();
|
||||
}
|
||||
|
||||
JSTaggedValue SourceTextModule::AsyncModuleRejectedFunc(EcmaRuntimeCallInfo *argv)
|
||||
{
|
||||
// 1. Let F be the active function object.
|
||||
ASSERT(argv);
|
||||
JSThread *thread = argv->GetThread();
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
JSHandle<JSAsyncModuleRejectedFunction> rejectedFunc =
|
||||
JSHandle<JSAsyncModuleRejectedFunction>::Cast(base::BuiltinsBase::GetConstructor(argv));
|
||||
JSHandle<SourceTextModule> module(thread, rejectedFunc->GetModule());
|
||||
[[maybe_unused]] JSHandle<JSTaggedValue> value = base::BuiltinsBase::GetCallArg(argv, 0);
|
||||
AsyncModuleExecutionRejected(thread, module, value.GetTaggedValue());
|
||||
return JSTaggedValue::Undefined();
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
|
@ -23,7 +23,14 @@
|
||||
#include "ecmascript/tagged_array.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
enum class ModuleStatus : uint8_t { UNINSTANTIATED = 0x01, INSTANTIATING, INSTANTIATED, EVALUATING, EVALUATED };
|
||||
enum class ModuleStatus : uint8_t {
|
||||
UNINSTANTIATED = 0x01,
|
||||
INSTANTIATING,
|
||||
INSTANTIATED,
|
||||
EVALUATING,
|
||||
EVALUATING_ASYNC,
|
||||
EVALUATED
|
||||
};
|
||||
|
||||
enum class ModuleTypes : uint8_t {
|
||||
ECMA_MODULE = 0x01,
|
||||
@ -45,9 +52,21 @@ enum class LoadingTypes : uint8_t {
|
||||
class SourceTextModule final : public ModuleRecord {
|
||||
public:
|
||||
static constexpr int UNDEFINED_INDEX = -1;
|
||||
static constexpr int MODULE_ERROR = 1;
|
||||
static constexpr size_t DEFAULT_DICTIONART_CAPACITY = 2;
|
||||
static constexpr size_t DEFAULT_ARRAY_CAPACITY = 2;
|
||||
static constexpr uint8_t DEREGISTER_MODULE_TAG = 1;
|
||||
static constexpr uint32_t FIRST_ASYNC_EVALUATING_ORDINAL = 2;
|
||||
static constexpr uint32_t NOT_ASYNC_EVALUATED = 0;
|
||||
static constexpr uint32_t ASYNC_EVALUATE_DID_FINISH = 1;
|
||||
struct AsyncEvaluatingOrdinalCompare {
|
||||
bool operator()(const JSHandle<SourceTextModule> &lhs, const JSHandle<SourceTextModule> &rhs) const
|
||||
{
|
||||
return lhs->GetAsyncEvaluatingOrdinal() < rhs->GetAsyncEvaluatingOrdinal();
|
||||
}
|
||||
};
|
||||
using AsyncParentCompletionSet =
|
||||
CSet<JSHandle<SourceTextModule>, AsyncEvaluatingOrdinalCompare>;
|
||||
|
||||
CAST_CHECK(SourceTextModule, IsSourceTextModule);
|
||||
|
||||
@ -85,9 +104,28 @@ public:
|
||||
size_t size = 0, bool excuteFromJob = false);
|
||||
|
||||
// 15.2.1.16.5.2 ModuleExecution ( module )
|
||||
static void ModuleExecution(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
const void *buffer = nullptr, size_t size = 0, bool excuteFromJob = false);
|
||||
static Expected<JSTaggedValue, bool> ModuleExecution(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
const void *buffer = nullptr, size_t size = 0, bool excuteFromJob = false);
|
||||
|
||||
// 16.2.1.5.3.2 ExecuteAsyncModule ( module )
|
||||
static void ExecuteAsyncModule(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
const void *buffer = nullptr, size_t size = 0, bool excuteFromJob = false);
|
||||
|
||||
// 16.2.1.5.3.3 GatherAvailableAncestors ( module, execList )
|
||||
static void GatherAvailableAncestors(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
AsyncParentCompletionSet &execList);
|
||||
|
||||
// 16.2.1.5.3.4 AsyncModuleExecutionFulfilled ( module )
|
||||
static void AsyncModuleExecutionFulfilled(JSThread *thread, const JSHandle<SourceTextModule> &module);
|
||||
|
||||
// 16.2.1.5.3.5 AsyncModuleExecutionRejected ( module, error )
|
||||
static void AsyncModuleExecutionRejected(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
JSTaggedValue error);
|
||||
|
||||
static JSTaggedValue AsyncModuleFulfilledFunc(EcmaRuntimeCallInfo *argv);
|
||||
static JSTaggedValue AsyncModuleRejectedFunc(EcmaRuntimeCallInfo *argv);
|
||||
static void AddAsyncParentModule(JSThread *thread, JSHandle<SourceTextModule> &module,
|
||||
JSHandle<SourceTextModule> &parent);
|
||||
// 15.2.1.18 Runtime Semantics: GetModuleNamespace ( module )
|
||||
static JSHandle<JSTaggedValue> GetModuleNamespace(JSThread *thread, const JSHandle<SourceTextModule> &module);
|
||||
|
||||
@ -124,10 +162,15 @@ public:
|
||||
ACCESSORS(LocalExportEntries, LOCAL_EXPORT_ENTTRIES_OFFSET, INDIRECT_EXPORT_ENTTRIES_OFFSET);
|
||||
ACCESSORS(IndirectExportEntries, INDIRECT_EXPORT_ENTTRIES_OFFSET, START_EXPORT_ENTTRIES_OFFSET);
|
||||
ACCESSORS(StarExportEntries, START_EXPORT_ENTTRIES_OFFSET, NAME_DICTIONARY_OFFSET);
|
||||
ACCESSORS(NameDictionary, NAME_DICTIONARY_OFFSET, EVALUATION_ERROR_OFFSET);
|
||||
ACCESSORS(NameDictionary, NAME_DICTIONARY_OFFSET, CYCLE_ROOT_OFFSET);
|
||||
ACCESSORS(CycleRoot, CYCLE_ROOT_OFFSET, TOP_LEVEL_CAPABILITY_OFFSET);
|
||||
ACCESSORS(TopLevelCapability, TOP_LEVEL_CAPABILITY_OFFSET, ASYNC_PARENT_MODULES_OFFSET);
|
||||
ACCESSORS(AsyncParentModules, ASYNC_PARENT_MODULES_OFFSET, EVALUATION_ERROR_OFFSET);
|
||||
ACCESSORS_PRIMITIVE_FIELD(EvaluationError, int32_t, EVALUATION_ERROR_OFFSET, DFS_ANCESTOR_INDEX_OFFSET);
|
||||
ACCESSORS_PRIMITIVE_FIELD(DFSAncestorIndex, int32_t, DFS_ANCESTOR_INDEX_OFFSET, DFS_INDEX_OFFSET);
|
||||
ACCESSORS_PRIMITIVE_FIELD(DFSIndex, int32_t, DFS_INDEX_OFFSET, BIT_FIELD_OFFSET);
|
||||
ACCESSORS_PRIMITIVE_FIELD(DFSIndex, int32_t, DFS_INDEX_OFFSET, ASYNC_EVALUATION_OFFSET);
|
||||
ACCESSORS_PRIMITIVE_FIELD(AsyncEvaluatingOrdinal, uint32_t, ASYNC_EVALUATION_OFFSET, PENDING_DEPENDENCIES_OFFSET);
|
||||
ACCESSORS_PRIMITIVE_FIELD(PendingAsyncDependencies, int32_t, PENDING_DEPENDENCIES_OFFSET, BIT_FIELD_OFFSET);
|
||||
ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET)
|
||||
|
||||
DEFINE_ALIGN_SIZE(LAST_OFFSET);
|
||||
@ -136,21 +179,23 @@ public:
|
||||
static constexpr size_t STATUS_BITS = 3;
|
||||
static constexpr size_t MODULE_TYPE_BITS = 4;
|
||||
static constexpr size_t IS_NEW_BC_VERSION_BITS = 1;
|
||||
static constexpr size_t HASTLA_BITS = 1;
|
||||
static constexpr size_t LOADING_TYPE_BITS = 3;
|
||||
static constexpr uint16_t REGISTER_COUNTS = 16;
|
||||
|
||||
FIRST_BIT_FIELD(BitField, Status, ModuleStatus, STATUS_BITS)
|
||||
NEXT_BIT_FIELD(BitField, Types, ModuleTypes, MODULE_TYPE_BITS, Status)
|
||||
NEXT_BIT_FIELD(BitField, IsNewBcVersion, bool, IS_NEW_BC_VERSION_BITS, Types)
|
||||
NEXT_BIT_FIELD(BitField, LoadingTypes, LoadingTypes, LOADING_TYPE_BITS, IsNewBcVersion)
|
||||
NEXT_BIT_FIELD(BitField, HasTLA, bool, HASTLA_BITS, IsNewBcVersion)
|
||||
NEXT_BIT_FIELD(BitField, LoadingTypes, LoadingTypes, LOADING_TYPE_BITS, HasTLA)
|
||||
NEXT_BIT_FIELD(BitField, RegisterCounts, uint16_t, REGISTER_COUNTS, LoadingTypes)
|
||||
|
||||
DECL_DUMP()
|
||||
DECL_VISIT_OBJECT(SOURCE_TEXT_MODULE_OFFSET, EVALUATION_ERROR_OFFSET)
|
||||
|
||||
// 15.2.1.16.5 Evaluate()
|
||||
static int Evaluate(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
const void *buffer = nullptr, size_t size = 0, bool excuteFromJob = false);
|
||||
static JSTaggedValue Evaluate(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
const void *buffer = nullptr, size_t size = 0, bool excuteFromJob = false);
|
||||
|
||||
// 15.2.1.16.4 Instantiate()
|
||||
static int Instantiate(JSThread *thread, const JSHandle<JSTaggedValue> &moduleHdl,
|
||||
@ -186,8 +231,7 @@ public:
|
||||
static int EvaluateForConcurrent(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
const JSHandle<Method> &method);
|
||||
static int ModuleEvaluation(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord,
|
||||
CVector<JSHandle<SourceTextModule>> &stack, int index,
|
||||
const JSHandle<Method> &method);
|
||||
int index, const JSHandle<Method> &method);
|
||||
|
||||
private:
|
||||
static void SetExportName(JSThread *thread,
|
||||
@ -228,6 +272,12 @@ private:
|
||||
int &index, bool excuteFromJob);
|
||||
static int HandleInstantiateException(JSHandle<SourceTextModule> &module,
|
||||
const CVector<JSHandle<SourceTextModule>> &stack, int result);
|
||||
static void HandleEvaluateResult(JSThread *thread, JSHandle<SourceTextModule> &module,
|
||||
JSHandle<PromiseCapability> &capability,
|
||||
const CVector<JSHandle<SourceTextModule>> &stack, int result);
|
||||
static void HandleConcurrentEvaluateResult(JSThread *thread, JSHandle<SourceTextModule> &module,
|
||||
const CVector<JSHandle<SourceTextModule>> &stack, int result);
|
||||
bool IsAsyncEvaluating();
|
||||
};
|
||||
|
||||
class ResolvedBinding final : public Record {
|
||||
|
@ -48,6 +48,9 @@ JSHandle<JSTaggedValue> ModuleDataExtractor::ParseModule(JSThread *thread, const
|
||||
JSHandle<SourceTextModule> moduleRecord = factory->NewSourceTextModule();
|
||||
ModuleDataExtractor::ExtractModuleDatas(thread, jsPandaFile, moduleId, moduleRecord);
|
||||
|
||||
bool hasTLA = jsPandaFile->GetHasTopLevelAwait(descriptor);
|
||||
moduleRecord->SetHasTLA(hasTLA);
|
||||
|
||||
JSHandle<EcmaString> ecmaModuleFilename = factory->NewFromUtf8(moduleFilename);
|
||||
moduleRecord->SetEcmaModuleFilename(thread, ecmaModuleFilename);
|
||||
|
||||
|
@ -279,10 +279,10 @@ HWTEST_F_L0(EcmaModuleTest, Instantiate_Evaluate_GetNamespace_SetNamespace)
|
||||
JSHandle<SourceTextModule> module = moduleManager->HostGetImportedModule("module_test_module_test_C");
|
||||
module->SetStatus(ModuleStatus::UNINSTANTIATED);
|
||||
ModuleRecord::Instantiate(thread, JSHandle<JSTaggedValue>(module));
|
||||
int res = ModuleRecord::Evaluate(thread, JSHandle<JSTaggedValue>(module));
|
||||
JSTaggedValue res = ModuleRecord::Evaluate(thread, JSHandle<JSTaggedValue>(module));
|
||||
ModuleRecord::GetNamespace(module.GetTaggedValue());
|
||||
ModuleRecord::SetNamespace(thread, module.GetTaggedValue(), JSTaggedValue::Undefined());
|
||||
EXPECT_TRUE(res == SourceTextModule::UNDEFINED_INDEX);
|
||||
EXPECT_TRUE(res.IsJSPromise());
|
||||
}
|
||||
|
||||
HWTEST_F_L0(EcmaModuleTest, ConcatFileNameWithMerge1)
|
||||
|
@ -1294,6 +1294,14 @@ void ObjectFactory::InitializeJSObject(const JSHandle<JSObject> &obj, const JSHa
|
||||
JSFunction::InitializeJSFunction(thread_, JSHandle<JSFunction>(obj));
|
||||
JSPromiseExecutorFunction::Cast(*obj)->SetCapability(thread_, JSTaggedValue::Undefined());
|
||||
break;
|
||||
case JSType::JS_ASYNC_MODULE_FULFILLED_FUNCTION:
|
||||
JSFunction::InitializeJSFunction(thread_, JSHandle<JSFunction>(obj));
|
||||
JSAsyncModuleFulfilledFunction::Cast(*obj)->SetModule(thread_, JSTaggedValue::Undefined());
|
||||
break;
|
||||
case JSType::JS_ASYNC_MODULE_REJECTED_FUNCTION:
|
||||
JSFunction::InitializeJSFunction(thread_, JSHandle<JSFunction>(obj));
|
||||
JSAsyncModuleRejectedFunction::Cast(*obj)->SetModule(thread_, JSTaggedValue::Undefined());
|
||||
break;
|
||||
case JSType::JS_ASYNC_GENERATOR_RESUME_NEXT_RETURN_PROCESSOR_RST_FTN:
|
||||
JSFunction::InitializeJSFunction(thread_, JSHandle<JSFunction>(obj));
|
||||
JSAsyncGeneratorResNextRetProRstFtn::Cast(*obj)->SetAsyncGeneratorObject(thread_,
|
||||
@ -2982,6 +2990,36 @@ JSHandle<JSPromiseExecutorFunction> ObjectFactory::CreateJSPromiseExecutorFuncti
|
||||
return executorFunction;
|
||||
}
|
||||
|
||||
JSHandle<JSAsyncModuleFulfilledFunction> ObjectFactory::CreateJSAsyncModuleFulfilledFunction()
|
||||
{
|
||||
JSHandle<GlobalEnv> env = vm_->GetGlobalEnv();
|
||||
JSHandle<JSHClass> hclass = JSHandle<JSHClass>::Cast(env->GetAsyncModuleFulfilledFunctionClass());
|
||||
JSHandle<JSAsyncModuleFulfilledFunction> fulfilledFunction =
|
||||
JSHandle<JSAsyncModuleFulfilledFunction>::Cast(NewJSObject(hclass));
|
||||
fulfilledFunction->SetModule(thread_, JSTaggedValue::Undefined());
|
||||
JSHandle<JSFunction> function = JSHandle<JSFunction>::Cast(fulfilledFunction);
|
||||
JSFunction::InitializeJSFunction(thread_, function);
|
||||
fulfilledFunction->SetMethod(
|
||||
thread_, vm_->GetMethodByIndex(MethodIndex::BUILTINS_ASYNC_MODULE_FULFILLED_FUNCTION));
|
||||
JSFunction::SetFunctionLength(thread_, function, JSTaggedValue(FunctionLength::ONE));
|
||||
return fulfilledFunction;
|
||||
}
|
||||
|
||||
JSHandle<JSAsyncModuleRejectedFunction> ObjectFactory::CreateJSAsyncModuleRejectedFunction()
|
||||
{
|
||||
JSHandle<GlobalEnv> env = vm_->GetGlobalEnv();
|
||||
JSHandle<JSHClass> hclass = JSHandle<JSHClass>::Cast(env->GetAsyncModuleRejectedFunctionClass());
|
||||
JSHandle<JSAsyncModuleRejectedFunction> rejectedFunction =
|
||||
JSHandle<JSAsyncModuleRejectedFunction>::Cast(NewJSObject(hclass));
|
||||
rejectedFunction->SetModule(thread_, JSTaggedValue::Undefined());
|
||||
JSHandle<JSFunction> function = JSHandle<JSFunction>::Cast(rejectedFunction);
|
||||
JSFunction::InitializeJSFunction(thread_, function);
|
||||
rejectedFunction->SetMethod(
|
||||
thread_, vm_->GetMethodByIndex(MethodIndex::BUILTINS_ASYNC_MODULE_REJECTED_FUNCTION));
|
||||
JSFunction::SetFunctionLength(thread_, function, JSTaggedValue(FunctionLength::ONE));
|
||||
return rejectedFunction;
|
||||
}
|
||||
|
||||
JSHandle<JSPromiseAllResolveElementFunction> ObjectFactory::NewJSPromiseAllResolveElementFunction()
|
||||
{
|
||||
JSHandle<GlobalEnv> env = vm_->GetGlobalEnv();
|
||||
@ -4066,6 +4104,12 @@ JSHandle<SourceTextModule> ObjectFactory::NewSourceTextModule()
|
||||
obj->SetIndirectExportEntries(thread_, undefinedValue);
|
||||
obj->SetStarExportEntries(thread_, undefinedValue);
|
||||
obj->SetNameDictionary(thread_, undefinedValue);
|
||||
obj->SetCycleRoot(thread_, undefinedValue);
|
||||
obj->SetTopLevelCapability(thread_, undefinedValue);
|
||||
obj->SetAsyncParentModules(thread_, undefinedValue);
|
||||
obj->SetHasTLA(false);
|
||||
obj->SetAsyncEvaluatingOrdinal(SourceTextModule::NOT_ASYNC_EVALUATED);
|
||||
obj->SetPendingAsyncDependencies(SourceTextModule::UNDEFINED_INDEX);
|
||||
obj->SetDFSIndex(SourceTextModule::UNDEFINED_INDEX);
|
||||
obj->SetDFSAncestorIndex(SourceTextModule::UNDEFINED_INDEX);
|
||||
obj->SetEvaluationError(SourceTextModule::UNDEFINED_INDEX);
|
||||
|
@ -71,6 +71,8 @@ class JSDataView;
|
||||
class JSPromise;
|
||||
class JSPromiseReactionsFunction;
|
||||
class JSPromiseExecutorFunction;
|
||||
class JSAsyncModuleFulfilledFunction;
|
||||
class JSAsyncModuleRejectedFunction;
|
||||
class JSPromiseAllResolveElementFunction;
|
||||
class JSAsyncGeneratorResNextRetProRstFtn;
|
||||
class JSPromiseAnyRejectElementFunction;
|
||||
@ -422,6 +424,10 @@ public:
|
||||
|
||||
JSHandle<JSPromiseExecutorFunction> CreateJSPromiseExecutorFunction();
|
||||
|
||||
JSHandle<JSAsyncModuleFulfilledFunction> CreateJSAsyncModuleFulfilledFunction();
|
||||
|
||||
JSHandle<JSAsyncModuleRejectedFunction> CreateJSAsyncModuleRejectedFunction();
|
||||
|
||||
JSHandle<JSPromiseAllResolveElementFunction> NewJSPromiseAllResolveElementFunction();
|
||||
|
||||
JSHandle<JSPromiseAnyRejectElementFunction> NewJSPromiseAnyRejectElementFunction();
|
||||
|
@ -487,6 +487,22 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump)
|
||||
DUMP_FOR_HANDLE(promiseExeFunc);
|
||||
break;
|
||||
}
|
||||
case JSType::JS_ASYNC_MODULE_FULFILLED_FUNCTION: {
|
||||
CHECK_DUMP_FIELDS(JSFunction::SIZE, JSAsyncModuleFulfilledFunction::SIZE, 1U);
|
||||
JSHandle<JSHClass> moduleFulfilledClass =
|
||||
JSHandle<JSHClass>::Cast(globalEnv->GetAsyncModuleFulfilledFunctionClass());
|
||||
JSHandle<JSObject> moduleFulfilledFunc = factory->NewJSObjectWithInit(moduleFulfilledClass);
|
||||
DUMP_FOR_HANDLE(moduleFulfilledFunc);
|
||||
break;
|
||||
}
|
||||
case JSType::JS_ASYNC_MODULE_REJECTED_FUNCTION: {
|
||||
CHECK_DUMP_FIELDS(JSFunction::SIZE, JSAsyncModuleRejectedFunction::SIZE, 1U);
|
||||
JSHandle<JSHClass> moduleRejectedClass =
|
||||
JSHandle<JSHClass>::Cast(globalEnv->GetAsyncModuleRejectedFunctionClass());
|
||||
JSHandle<JSObject> moduleRejectedFunc = factory->NewJSObjectWithInit(moduleRejectedClass);
|
||||
DUMP_FOR_HANDLE(moduleRejectedFunc);
|
||||
break;
|
||||
}
|
||||
case JSType::JS_PROMISE_ALL_RESOLVE_ELEMENT_FUNCTION: {
|
||||
CHECK_DUMP_FIELDS(JSFunction::SIZE, JSPromiseAllResolveElementFunction::SIZE, 5U);
|
||||
JSHandle<JSHClass> promiseAllClass =
|
||||
@ -1289,7 +1305,7 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump)
|
||||
break;
|
||||
}
|
||||
case JSType::SOURCE_TEXT_MODULE_RECORD: {
|
||||
CHECK_DUMP_FIELDS(ModuleRecord::SIZE, SourceTextModule::SIZE, 12U);
|
||||
CHECK_DUMP_FIELDS(ModuleRecord::SIZE, SourceTextModule::SIZE, 16U);
|
||||
JSHandle<SourceTextModule> moduleSourceRecord = factory->NewSourceTextModule();
|
||||
DUMP_FOR_HANDLE(moduleSourceRecord);
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user