diff --git a/BUILD.gn b/BUILD.gn index 164c600f..83f9c21d 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -319,7 +319,6 @@ ecma_source = [ "ecmascript/builtins/builtins_typedarray.cpp", "ecmascript/builtins/builtins_weak_map.cpp", "ecmascript/builtins/builtins_weak_set.cpp", - "ecmascript/class_linker/panda_file_translator.cpp", "ecmascript/containers/containers_arraylist.cpp", "ecmascript/containers/containers_private.cpp", "ecmascript/containers/containers_queue.cpp", @@ -329,10 +328,8 @@ ecma_source = [ "ecmascript/dfx/vmstat/runtime_stat.cpp", "ecmascript/dfx/vm_thread_control.cpp", "ecmascript/dump.cpp", - "ecmascript/ecma_class_linker_extension.cpp", "ecmascript/ecma_exceptions.cpp", "ecmascript/ecma_language_context.cpp", - "ecmascript/ecma_module.cpp", "ecmascript/ecma_string.cpp", "ecmascript/ecma_string_table.cpp", "ecmascript/ecma_vm.cpp", @@ -356,6 +353,14 @@ ecma_source = [ "ecmascript/jspandafile/js_pandafile_manager.cpp", "ecmascript/js_api_queue.cpp", "ecmascript/js_api_queue_iterator.cpp", + "ecmascript/jspandafile/class_info_extractor.cpp", + "ecmascript/jspandafile/ecma_class_linker_extension.cpp", + "ecmascript/jspandafile/literal_data_extractor.cpp", + "ecmascript/jspandafile/module_data_extractor.cpp", + "ecmascript/jspandafile/accessor/module_data_accessor.cpp", + "ecmascript/jspandafile/panda_file_translator.cpp", + "ecmascript/jspandafile/js_pandafile_executor.cpp", + "ecmascript/jspandafile/scope_info_extractor.cpp", "ecmascript/js_api_tree_map.cpp", "ecmascript/js_api_tree_map_iterator.cpp", "ecmascript/js_api_tree_set.cpp", @@ -392,7 +397,6 @@ ecma_source = [ "ecmascript/js_typed_array.cpp", "ecmascript/js_weak_container.cpp", "ecmascript/linked_hash_table.cpp", - "ecmascript/literal_data_extractor.cpp", "ecmascript/message_string.cpp", "ecmascript/mem/c_string.cpp", "ecmascript/mem/chunk.cpp", @@ -415,6 +419,10 @@ ecma_source = [ "ecmascript/mem/space.cpp", "ecmascript/mem/sparse_space.cpp", "ecmascript/mem/verification.cpp", + "ecmascript/module/js_module_manager.cpp", + "ecmascript/module/js_module_namespace.cpp", + "ecmascript/module/js_module_record.cpp", + "ecmascript/module/js_module_source_text.cpp", "ecmascript/napi/jsnapi.cpp", "ecmascript/object_factory.cpp", "ecmascript/object_operator.cpp", @@ -429,14 +437,12 @@ ecma_source = [ "ecmascript/regexp/regexp_parser_cache.cpp", "ecmascript/runtime_api.cpp", "ecmascript/runtime_trampolines.cpp", - "ecmascript/scope_info_extractor.cpp", "ecmascript/stub_module.cpp", "ecmascript/tagged_dictionary.cpp", "ecmascript/tagged_tree.cpp", "ecmascript/template_string.cpp", "ecmascript/weak_vector.cpp", "ecmascript/compiler/llvm/llvm_stackmap_parser.cpp", - "ecmascript/class_info_extractor.cpp", "ecmascript/ts_types/ts_type.cpp", "ecmascript/ts_types/ts_type_table.cpp", "ecmascript/ts_types/ts_loader.cpp", diff --git a/ecmascript/builtins.cpp b/ecmascript/builtins.cpp index dacad5ce..9feb4989 100644 --- a/ecmascript/builtins.cpp +++ b/ecmascript/builtins.cpp @@ -95,6 +95,7 @@ #include "ecmascript/js_typed_array.h" #include "ecmascript/js_weak_container.h" #include "ecmascript/mem/mem.h" +#include "ecmascript/module/js_module_namespace.h" #include "ecmascript/napi/include/jsnapi.h" #include "ecmascript/object_factory.h" #include "ohos/init_data.h" @@ -331,6 +332,7 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread) InitializeRelativeTimeFormat(env); InitializeCollator(env); InitializePluralRules(env); + InitializeModuleNamespace(env, objFuncDynclass); JSHandle generatorFuncClass = factory_->CreateFunctionClass(FunctionKind::GENERATOR_FUNCTION, JSFunction::SIZE, JSType::JS_GENERATOR_FUNCTION, @@ -2834,4 +2836,19 @@ JSHandle Builtins::InitializeArkPrivate(const JSHandle &env SetConstant(arkPrivate, "PlainArray", JSTaggedValue(static_cast(containers::ContainerTag::PlainArray))); return arkPrivate; } + +void Builtins::InitializeModuleNamespace(const JSHandle &env, + const JSHandle &objFuncDynclass) const +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + // ModuleNamespace.prototype + JSHandle moduleNamespacePrototype = factory_->NewJSObject(objFuncDynclass); + JSHandle moduleNamespacePrototypeValue(moduleNamespacePrototype); + + // ModuleNamespace.prototype_or_dynclass + JSHandle moduleNamespaceDynclass = + factory_->NewEcmaDynClass(ModuleNamespace::SIZE, JSType::JS_MODULE_NAMESPACE, moduleNamespacePrototypeValue); + moduleNamespaceDynclass->SetPrototype(thread_, JSTaggedValue::Null()); + env->SetModuleNamespaceClass(thread_, moduleNamespaceDynclass.GetTaggedValue()); +} } // namespace panda::ecmascript diff --git a/ecmascript/builtins.h b/ecmascript/builtins.h index 65913f48..01f421e5 100644 --- a/ecmascript/builtins.h +++ b/ecmascript/builtins.h @@ -171,6 +171,8 @@ private: void InitializePromiseJob(const JSHandle &env); + void InitializeModuleNamespace(const JSHandle &env, const JSHandle &objFuncDynclass) const; + void SetFunction(const JSHandle &env, const JSHandle &obj, const char *key, EcmaEntrypoint func, int length) const; diff --git a/ecmascript/compiler/bytecode_circuit_builder.cpp b/ecmascript/compiler/bytecode_circuit_builder.cpp index 6e185b86..36a9f89b 100644 --- a/ecmascript/compiler/bytecode_circuit_builder.cpp +++ b/ecmascript/compiler/bytecode_circuit_builder.cpp @@ -1296,7 +1296,7 @@ BytecodeInfo BytecodeCircuitBuilder::GetBytecodeInfo(uint8_t *pc) info.offset = BytecodeOffset::FOUR; break; } - case EcmaOpcode::IMPORTMODULE_PREF_ID32: { + case EcmaOpcode::GETMODULENAMESPACE_PREF_ID32: { info.accOut = true; info.offset = BytecodeOffset::SIX; break; @@ -1312,9 +1312,7 @@ BytecodeInfo BytecodeCircuitBuilder::GetBytecodeInfo(uint8_t *pc) info.offset = BytecodeOffset::THREE; break; } - case EcmaOpcode::LDMODVARBYNAME_PREF_ID32_V8: { - uint32_t v0 = READ_INST_8_5(); - info.vregIn.emplace_back(v0); + case EcmaOpcode::LDMODULEVAR_PREF_ID32_IMM8: { info.accOut = true; info.offset = BytecodeOffset::SEVEN; break; diff --git a/ecmascript/compiler/fast_stub_define.h b/ecmascript/compiler/fast_stub_define.h index 0345e927..f2c12e3c 100644 --- a/ecmascript/compiler/fast_stub_define.h +++ b/ecmascript/compiler/fast_stub_define.h @@ -103,9 +103,9 @@ namespace panda::ecmascript::kungfu { V(LoadICByName, 5) \ V(StoreICByName, 6) \ V(UpdateHotnessCounter, 2) \ - V(ImportModule, 2) \ + V(GetModuleNamespace, 2) \ V(StModuleVar, 3) \ - V(LdModvarByName, 3) \ + V(LdModuleVar, 3) \ V(ThrowDyn, 2) \ V(GetPropIterator, 2) \ V(AsyncFunctionEnter, 1) \ diff --git a/ecmascript/compiler/interpreter_stub.cpp b/ecmascript/compiler/interpreter_stub.cpp index cd4742d7..b045f772 100644 --- a/ecmascript/compiler/interpreter_stub.cpp +++ b/ecmascript/compiler/interpreter_stub.cpp @@ -2197,9 +2197,6 @@ DECLARE_ASM_HANDLER(HandleCloseIteratorPrefV8) DECLARE_ASM_HANDLER(HandleCopyModulePrefV8) { - GateRef v0 = ReadInst8_1(pc); - GateRef srcModule = GetVregValue(sp, ZExtInt8ToPtr(v0)); - CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(CopyModule)), { srcModule }); DISPATCH(PREF_V8); } @@ -4444,13 +4441,13 @@ DECLARE_ASM_HANDLER(ExceptionHandler) } } -DECLARE_ASM_HANDLER(HandleImportModulePrefId32) +DECLARE_ASM_HANDLER(HandleGetModuleNamespacePrefId32) { DEFVARIABLE(varAcc, VariableType::JS_ANY(), acc); GateRef stringId = ReadInst32_1(pc); GateRef prop = GetObjectFromConstPool(constpool, stringId); - GateRef moduleRef = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(ImportModule)), { prop }); + GateRef moduleRef = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(GetModuleNamespace)), { prop }); varAcc = moduleRef; DISPATCH_WITH_ACC(PREF_ID32); } @@ -4465,18 +4462,18 @@ DECLARE_ASM_HANDLER(HandleStModuleVarPrefId32) DISPATCH(PREF_ID32); } -DECLARE_ASM_HANDLER(HandleLdModVarByNamePrefId32V8) +DECLARE_ASM_HANDLER(HandleLdModuleVarPrefId32Imm8) { DEFVARIABLE(varAcc, VariableType::JS_ANY(), acc); GateRef stringId = ReadInst32_1(pc); - GateRef v0 = ReadInst8_5(pc); - GateRef itemName = GetObjectFromConstPool(constpool, stringId); - GateRef moduleObj = GetVregValue(sp, ZExtInt8ToPtr(v0)); - GateRef moduleVar = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(LdModvarByName)), - { moduleObj, itemName }); + GateRef flag = ReadInst8_5(pc); + GateRef key = GetObjectFromConstPool(constpool, stringId); + GateRef innerFlag = ChangeInt64ToTagged(SExtInt1ToInt64(Int32NotEqual(ZExtInt8ToInt32(flag), GetInt32Constant(0)))); + GateRef moduleVar = CallRuntimeTrampoline(glue, GetInt64Constant(FAST_STUB_ID(LdModuleVar)), + { key, innerFlag }); varAcc = moduleVar; - DISPATCH_WITH_ACC(PREF_ID32_V8); + DISPATCH_WITH_ACC(PREF_ID32_IMM8); } DECLARE_ASM_HANDLER(HandleTryLdGlobalByNamePrefId32) diff --git a/ecmascript/compiler/interpreter_stub_define.h b/ecmascript/compiler/interpreter_stub_define.h index b0a31ca0..1637862b 100644 --- a/ecmascript/compiler/interpreter_stub_define.h +++ b/ecmascript/compiler/interpreter_stub_define.h @@ -143,7 +143,7 @@ namespace panda::ecmascript::kungfu { T(HandleStLexVarDynPrefImm8Imm8V8, 7) \ T(HandleStLexVarDynPrefImm16Imm16V8, 7) \ T(HandleDefineClassWithBufferPrefId16Imm16Imm16V8V8, 7) \ - T(HandleImportModulePrefId32, 7) \ + T(HandleGetModuleNamespacePrefId32, 7) \ T(HandleStModuleVarPrefId32, 7) \ T(HandleTryLdGlobalByNamePrefId32, 7) \ T(HandleTryStGlobalByNamePrefId32, 7) \ @@ -154,7 +154,7 @@ namespace panda::ecmascript::kungfu { T(HandleStOwnByNamePrefId32V8, 7) \ T(HandleLdSuperByNamePrefId32V8, 7) \ T(HandleStSuperByNamePrefId32V8, 7) \ - T(HandleLdModVarByNamePrefId32V8, 7) \ + T(HandleLdModuleVarPrefId32Imm8, 7) \ T(HandleCreateRegExpWithLiteralPrefId32Imm8, 7) \ T(HandleIsTruePref, 7) \ T(HandleIsFalsePref, 7) \ diff --git a/ecmascript/compiler/stub_descriptor.cpp b/ecmascript/compiler/stub_descriptor.cpp index 6cd63132..ed24089e 100644 --- a/ecmascript/compiler/stub_descriptor.cpp +++ b/ecmascript/compiler/stub_descriptor.cpp @@ -1621,12 +1621,12 @@ CALL_STUB_INIT_DESCRIPTOR(UpdateHotnessCounter) descriptor->SetStubKind(StubDescriptor::CallStubKind::RUNTIME_STUB); } -CALL_STUB_INIT_DESCRIPTOR(ImportModule) +CALL_STUB_INIT_DESCRIPTOR(GetModuleNamespace) { // 2 : 2 input parameters - StubDescriptor importModule("ImportModule", 0, 2, + StubDescriptor getModuleNamespace("GetModuleNamespace", 0, 2, ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY()); - *descriptor = importModule; + *descriptor = getModuleNamespace; std::array params = { // 2 : 2 input parameters VariableType::POINTER(), VariableType::JS_ANY(), @@ -1650,16 +1650,16 @@ CALL_STUB_INIT_DESCRIPTOR(StModuleVar) descriptor->SetStubKind(StubDescriptor::CallStubKind::RUNTIME_STUB); } -CALL_STUB_INIT_DESCRIPTOR(LdModvarByName) +CALL_STUB_INIT_DESCRIPTOR(LdModuleVar) { // 3 : 3 input parameters - StubDescriptor ldModvarByName("LdModvarByName", 0, 3, + StubDescriptor ldModuleVar("LdModuleVar", 0, 3, ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY()); - *descriptor = ldModvarByName; + *descriptor = ldModuleVar; std::array params = { // 3 : 3 input parameters VariableType::POINTER(), VariableType::JS_ANY(), - VariableType::JS_ANY(), + VariableType::INT16(), }; descriptor->SetParameters(params.data()); descriptor->SetStubKind(StubDescriptor::CallStubKind::RUNTIME_STUB); diff --git a/ecmascript/dfx/hprof/heap_snapshot.cpp b/ecmascript/dfx/hprof/heap_snapshot.cpp index 6c700b76..495bfd2f 100644 --- a/ecmascript/dfx/hprof/heap_snapshot.cpp +++ b/ecmascript/dfx/hprof/heap_snapshot.cpp @@ -320,8 +320,6 @@ CString *HeapSnapShot::GenerateNodeName(JSThread *thread, TaggedObject *entry) return GetString("PendingJob"); case JSType::COMPLETION_RECORD: return GetString("CompletionRecord"); - case JSType::ECMA_MODULE: - return GetString("EcmaModule"); case JSType::JS_API_ARRAY_LIST: return GetString("ArrayList"); case JSType::JS_API_ARRAYLIST_ITERATOR: @@ -338,6 +336,16 @@ CString *HeapSnapShot::GenerateNodeName(JSThread *thread, TaggedObject *entry) return GetString("Queue"); case JSType::JS_API_QUEUE_ITERATOR: return GetString("QueueIterator"); + case JSType::SOURCE_TEXT_MODULE_RECORD: + return GetString("SourceTextModule"); + case JSType::IMPORTENTRY_RECORD: + return GetString("ImportEntry"); + case JSType::EXPORTENTRY_RECORD: + return GetString("ExportEntry"); + case JSType::RESOLVEDBINDING_RECORD: + return GetString("ResolvedBinding"); + case JSType::JS_MODULE_NAMESPACE: + return GetString("ModuleNamespace"); default: break; } diff --git a/ecmascript/dfx/hprof/tests/hprof_test.cpp b/ecmascript/dfx/hprof/tests/hprof_test.cpp index 75ed3fce..ee635026 100644 --- a/ecmascript/dfx/hprof/tests/hprof_test.cpp +++ b/ecmascript/dfx/hprof/tests/hprof_test.cpp @@ -17,8 +17,6 @@ #include #include "ecmascript/accessor_data.h" -#include "ecmascript/class_linker/program_object-inl.h" -#include "ecmascript/ecma_module.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_dictionary-inl.h" #include "ecmascript/global_env.h" @@ -32,6 +30,7 @@ #include "ecmascript/ic/proto_change_details.h" #include "ecmascript/jobs/micro_job_queue.h" #include "ecmascript/jobs/pending_job.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/js_arguments.h" #include "ecmascript/js_array.h" #include "ecmascript/js_array_iterator.h" diff --git a/ecmascript/dump.cpp b/ecmascript/dump.cpp index b2a5ed8a..d289f440 100644 --- a/ecmascript/dump.cpp +++ b/ecmascript/dump.cpp @@ -19,9 +19,6 @@ #include #include "ecmascript/accessor_data.h" -#include "ecmascript/class_info_extractor.h" -#include "ecmascript/class_linker/program_object-inl.h" -#include "ecmascript/ecma_module.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_dictionary-inl.h" #include "ecmascript/global_env.h" @@ -33,6 +30,8 @@ #include "ecmascript/jobs/pending_job.h" #include "ecmascript/js_api_queue.h" #include "ecmascript/js_api_queue_iterator.h" +#include "ecmascript/jspandafile/class_info_extractor.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/js_api_tree_map.h" #include "ecmascript/js_api_tree_map_iterator.h" #include "ecmascript/js_api_tree_set.h" @@ -78,6 +77,8 @@ #include "ecmascript/mem/assert_scope-inl.h" #include "ecmascript/mem/c_containers.h" #include "ecmascript/mem/machine_code.h" +#include "ecmascript/module/js_module_namespace.h" +#include "ecmascript/module/js_module_source_text.h" #include "ecmascript/tagged_array.h" #include "ecmascript/tagged_dictionary.h" #include "ecmascript/tagged_tree-inl.h" @@ -256,8 +257,6 @@ CString JSHClass::DumpJSType(JSType type) return "program"; case JSType::MACHINE_CODE_OBJECT: return "MachineCode"; - case JSType::ECMA_MODULE: - return "EcmaModule"; case JSType::CLASS_INFO_EXTRACTOR: return "ClassInfoExtractor"; case JSType::JS_API_ARRAY_LIST: @@ -623,9 +622,6 @@ static void DumpObject(JSThread *thread, TaggedObject *obj, std::ostream &os) case JSType::MACHINE_CODE_OBJECT: MachineCode::Cast(obj)->Dump(thread, os); break; - case JSType::ECMA_MODULE: - EcmaModule::Cast(obj)->Dump(thread, os); - break; case JSType::CLASS_INFO_EXTRACTOR: ClassInfoExtractor::Cast(obj)->Dump(thread, os); break; @@ -677,6 +673,21 @@ static void DumpObject(JSThread *thread, TaggedObject *obj, std::ostream &os) case JSType::JS_API_QUEUE_ITERATOR: JSAPIQueueIterator::Cast(obj)->Dump(thread, os); break; + case JSType::SOURCE_TEXT_MODULE_RECORD: + SourceTextModule::Cast(obj)->Dump(thread, os); + break; + case JSType::IMPORTENTRY_RECORD: + ImportEntry::Cast(obj)->Dump(thread, os); + break; + case JSType::EXPORTENTRY_RECORD: + ExportEntry::Cast(obj)->Dump(thread, os); + break; + case JSType::RESOLVEDBINDING_RECORD: + ResolvedBinding::Cast(obj)->Dump(thread, os); + break; + case JSType::JS_MODULE_NAMESPACE: + ModuleNamespace::Cast(obj)->Dump(thread, os); + break; default: UNREACHABLE(); break; @@ -1024,6 +1035,9 @@ void JSFunction::Dump(JSThread *thread, std::ostream &os) const os << " - ProfileTypeInfo: "; GetProfileTypeInfo().D(); os << "\n"; + os << " - Module: "; + GetModule().D(); + os << "\n"; JSObject::Dump(thread, os); } @@ -2112,13 +2126,6 @@ void MachineCode::Dump(JSThread *thread, std::ostream &os) const os << "\n"; } -void EcmaModule::Dump(JSThread *thread, std::ostream &os) const -{ - os << " - NameDictionary: "; - GetNameDictionary().D(); - os << "\n"; -} - void ClassInfoExtractor::Dump(JSThread *thread, std::ostream &os) const { os << " - PrototypeHClass: "; @@ -2443,6 +2450,99 @@ void TSArrayType::Dump(JSThread *thread, std::ostream &os) const os << parameterTypeRef; os << "\n"; } + +void SourceTextModule::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - Environment: "; + GetEnvironment().D(); + os << "\n"; + os << " - Namespace: "; + GetNamespace().D(); + os << "\n"; + os << " - EcmaModuleFilename: "; + GetEcmaModuleFilename().D(); + os << "\n"; + os << " - RequestedModules: "; + GetRequestedModules().D(); + os << "\n"; + os << " - ImportEntries: "; + GetImportEntries().D(); + os << "\n"; + os << " - LocalExportEntries: "; + GetLocalExportEntries().D(); + os << "\n"; + os << " - IndirectExportEntries: "; + GetIndirectExportEntries().D(); + os << "\n"; + os << " - StarExportEntries: "; + GetStarExportEntries().D(); + os << "\n"; + os << " - Status: "; + os << static_cast(GetStatus()); + os << "\n"; + os << " - EvaluationError: "; + os << GetEvaluationError(); + os << "\n"; + os << " - DFSIndex: "; + os << GetDFSIndex(); + os << "\n"; + os << " - DFSAncestorIndex: "; + os << GetDFSAncestorIndex(); + os << "\n"; + os << " - NameDictionary: "; + GetNameDictionary().D(); + os << "\n"; +} + +void ImportEntry::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - ModuleRequest: "; + GetModuleRequest().D(); + os << "\n"; + os << " - ImportName: "; + GetImportName().D(); + os << "\n"; + os << " - LocalName: "; + GetLocalName().D(); + os << "\n"; +} + +void ExportEntry::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - ExportName: "; + GetExportName().D(); + os << "\n"; + os << " - ModuleRequest: "; + GetModuleRequest().D(); + os << "\n"; + os << " - ImportName: "; + GetImportName().D(); + os << "\n"; + os << " - LocalName: "; + GetLocalName().D(); + os << "\n"; +} + +void ResolvedBinding::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - Module: "; + GetModule().D(); + os << "\n"; + os << " - BindingName: "; + GetBindingName().D(); + os << "\n"; +} + +void ModuleNamespace::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - Module: "; + GetModule().D(); + os << "\n"; + os << " - Exports: "; + GetExports().D(); + os << "\n"; +} + // ######################################################################################## // Dump for Snapshot // ######################################################################################## @@ -2652,9 +2752,6 @@ static void DumpObject(JSThread *thread, TaggedObject *obj, case JSType::JS_GENERATOR_CONTEXT: GeneratorContext::Cast(obj)->DumpForSnapshot(thread, vec); return; - case JSType::ECMA_MODULE: - EcmaModule::Cast(obj)->DumpForSnapshot(thread, vec); - return; case JSType::JS_API_ARRAY_LIST: JSAPIArrayList::Cast(obj)->DumpForSnapshot(thread, vec); return; @@ -2679,6 +2776,21 @@ static void DumpObject(JSThread *thread, TaggedObject *obj, case JSType::JS_API_QUEUE_ITERATOR: JSAPIQueueIterator::Cast(obj)->DumpForSnapshot(thread, vec); return; + case JSType::SOURCE_TEXT_MODULE_RECORD: + SourceTextModule::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::IMPORTENTRY_RECORD: + ImportEntry::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::EXPORTENTRY_RECORD: + ExportEntry::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::RESOLVEDBINDING_RECORD: + ResolvedBinding::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::JS_MODULE_NAMESPACE: + ModuleNamespace::Cast(obj)->DumpForSnapshot(thread, vec); + return; default: break; } @@ -3602,11 +3714,6 @@ void MachineCode::DumpForSnapshot(JSThread *thread, std::vector> &vec) const -{ - vec.push_back(std::make_pair(CString("NameDictionary"), GetNameDictionary())); -} - void ClassInfoExtractor::DumpForSnapshot(JSThread *thread, std::vector> &vec) const { vec.push_back(std::make_pair(CString("PrototypeHClass"), GetPrototypeHClass())); @@ -3663,4 +3770,48 @@ void TSArrayType::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("Environment"), GetEnvironment())); + vec.push_back(std::make_pair(CString("Namespace"), GetNamespace())); + vec.push_back(std::make_pair(CString("EcmaModuleFilename"), GetEcmaModuleFilename())); + vec.push_back(std::make_pair(CString("RequestedModules"), GetRequestedModules())); + vec.push_back(std::make_pair(CString("ImportEntries"), GetImportEntries())); + vec.push_back(std::make_pair(CString("LocalExportEntries"), GetLocalExportEntries())); + vec.push_back(std::make_pair(CString("IndirectExportEntries"), GetIndirectExportEntries())); + vec.push_back(std::make_pair(CString("StarExportEntries"), GetStarExportEntries())); + vec.push_back(std::make_pair(CString("Status"), JSTaggedValue(static_cast(GetStatus())))); + vec.push_back(std::make_pair(CString("EvaluationError"), JSTaggedValue(GetEvaluationError()))); + vec.push_back(std::make_pair(CString("DFSIndex"), JSTaggedValue(GetDFSIndex()))); + vec.push_back(std::make_pair(CString("DFSAncestorIndex"), JSTaggedValue(GetDFSAncestorIndex()))); + vec.push_back(std::make_pair(CString("NameDictionary"), GetNameDictionary())); +} + +void ImportEntry::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("ModuleRequest"), GetModuleRequest())); + vec.push_back(std::make_pair(CString("ImportName"), GetImportName())); + vec.push_back(std::make_pair(CString("LocalName"), GetLocalName())); +} + +void ExportEntry::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("ExportName"), GetExportName())); + vec.push_back(std::make_pair(CString("ModuleRequest"), GetModuleRequest())); + vec.push_back(std::make_pair(CString("ImportName"), GetImportName())); + vec.push_back(std::make_pair(CString("LocalName"), GetLocalName())); +} + +void ResolvedBinding::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("Module"), GetModule())); + vec.push_back(std::make_pair(CString("BindingName"), GetBindingName())); +} + +void ModuleNamespace::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("Module"), GetModule())); + vec.push_back(std::make_pair(CString("Exports"), GetExports())); +} } // namespace panda::ecmascript diff --git a/ecmascript/ecma_isa.yaml b/ecmascript/ecma_isa.yaml index 006c317a..d2c09911 100644 --- a/ecmascript/ecma_isa.yaml +++ b/ecmascript/ecma_isa.yaml @@ -489,7 +489,7 @@ groups: prefix: ecma format: [pref_op_id_16_imm1_16_imm2_16_v1_8_v2_8] properties: [method_id] - - sig: ecma.importmodule string_id + - sig: ecma.getmodulenamespace string_id acc: out:top prefix: ecma format: [pref_op_id_32] @@ -544,10 +544,10 @@ groups: prefix: ecma format: [pref_op_id_32_v_8] properties: [string_id] - - sig: ecma.ldmodvarbyname string_id, v:in:top + - sig: ecma.ldmodulevar string_id, imm acc: out:top prefix: ecma - format: [pref_op_id_32_v_8] + format: [pref_op_id_32_imm_8] properties: [string_id] - sig: ecma.createregexpwithliteral string_id, imm acc: out:top diff --git a/ecmascript/ecma_language_context.cpp b/ecmascript/ecma_language_context.cpp index bade8e7f..694e61eb 100644 --- a/ecmascript/ecma_language_context.cpp +++ b/ecmascript/ecma_language_context.cpp @@ -15,9 +15,9 @@ #include "ecmascript/ecma_language_context.h" -#include "ecmascript/ecma_class_linker_extension.h" #include "ecmascript/ecma_exceptions.h" #include "ecmascript/interpreter/frame_handler.h" +#include "ecmascript/jspandafile/ecma_class_linker_extension.h" #include "ecmascript/js_method.h" #include "ecmascript/js_object.h" #include "ecmascript/js_tagged_value.h" diff --git a/ecmascript/ecma_macros.h b/ecmascript/ecma_macros.h index 2077da41..c2862f91 100644 --- a/ecmascript/ecma_macros.h +++ b/ecmascript/ecma_macros.h @@ -325,10 +325,10 @@ } while (false) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define THROW_RANGE_ERROR(thread, message) \ +#define THROW_ERROR(thread, type, message) \ do { \ ObjectFactory *factory = (thread)->GetEcmaVM()->GetFactory(); \ - JSHandle error = factory->GetJSError(ErrorType::RANGE_ERROR, message); \ + JSHandle error = factory->GetJSError(type, message); \ THROW_NEW_ERROR_AND_RETURN(thread, error.GetTaggedValue()); \ } while (false) @@ -340,6 +340,7 @@ THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error.GetTaggedValue(), exception); \ } while (false) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define THROW_SYNTAX_ERROR_AND_RETURN(thread, message, exception) \ do { \ ObjectFactory *factory = (thread)->GetEcmaVM()->GetFactory(); \ @@ -347,6 +348,14 @@ THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error.GetTaggedValue(), exception); \ } while (false) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define THROW_REFERENCE_ERROR_AND_RETURN(thread, message, value) \ + do { \ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); \ + JSHandle error = factory->GetJSError(ErrorType::REFERENCE_ERROR, message); \ + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error.GetTaggedValue(), value); \ + } while (false) + // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define RETURN_REJECT_PROMISE_IF_ABRUPT(thread, value, capability) \ do { \ diff --git a/ecmascript/ecma_module.cpp b/ecmascript/ecma_module.cpp deleted file mode 100644 index 6cc03148..00000000 --- a/ecmascript/ecma_module.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/* - * 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. - */ - -#include "ecmascript/ecma_module.h" -#include "ecmascript/ecma_vm.h" -#include "ecmascript/global_env.h" -#include "ecmascript/js_thread.h" -#include "ecmascript/object_factory.h" -#include "ecmascript/tagged_array.h" -#include "ecmascript/tagged_dictionary.h" - -namespace panda::ecmascript { -JSHandle EcmaModule::GetItem(const JSThread *thread, JSHandle itemName) -{ - JSHandle moduleItems(thread, NameDictionary::Cast(GetNameDictionary().GetTaggedObject())); - int entry = moduleItems->FindEntry(itemName.GetTaggedValue()); - if (entry != -1) { - return JSHandle(thread, moduleItems->GetValue(entry)); - } - - return JSHandle(thread, JSTaggedValue::Undefined()); -} - -void EcmaModule::AddItem(const JSThread *thread, JSHandle module, JSHandle itemName, - JSHandle itemValue) -{ - JSMutableHandle data(thread, module->GetNameDictionary()); - if (data->IsUndefined()) { - data.Update(NameDictionary::Create(thread, DEAULT_DICTIONART_CAPACITY)); - } - JSHandle dataDict = JSHandle::Cast(data); - JSHandle newDict = - NameDictionary::Put(thread, dataDict, itemName, itemValue, PropertyAttributes::Default()); - module->SetNameDictionary(thread, newDict); -} - -void EcmaModule::RemoveItem(const JSThread *thread, JSHandle module, JSHandle itemName) -{ - JSHandle data(thread, module->GetNameDictionary()); - if (data->IsUndefined()) { - return; - } - JSHandle moduleItems(data); - int entry = moduleItems->FindEntry(itemName.GetTaggedValue()); - if (entry != -1) { - JSHandle newDict = NameDictionary::Remove(thread, moduleItems, entry); - module->SetNameDictionary(thread, newDict); - } -} - -void EcmaModule::CopyModuleInternal(const JSThread *thread, JSHandle dstModule, - JSHandle srcModule) -{ - JSHandle moduleItems(thread, - NameDictionary::Cast(srcModule->GetNameDictionary().GetTaggedObject())); - uint32_t numAllKeys = moduleItems->EntriesCount(); - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - JSHandle allKeys = factory->NewTaggedArray(numAllKeys); - moduleItems->GetAllKeys(thread, 0, allKeys.GetObject()); - - JSMutableHandle itemName(thread, JSTaggedValue::Undefined()); - JSMutableHandle itemValue(thread, JSTaggedValue::Undefined()); - unsigned int capcity = allKeys->GetLength(); - for (unsigned int i = 0; i < capcity; i++) { - int entry = moduleItems->FindEntry(allKeys->Get(i)); - if (entry != -1) { - itemName.Update(allKeys->Get(i)); - itemValue.Update(moduleItems->GetValue(entry)); - EcmaModule::AddItem(thread, dstModule, itemName, itemValue); - } - } -} - -void EcmaModule::DebugPrint(const JSThread *thread, const CString &caller) -{ - JSHandle moduleItems(thread, NameDictionary::Cast(GetNameDictionary().GetTaggedObject())); - uint32_t numAllKeys = moduleItems->EntriesCount(); - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - JSHandle allKeys = factory->NewTaggedArray(numAllKeys); - moduleItems->GetAllKeys(thread, 0, allKeys.GetObject()); - - unsigned int capcity = allKeys->GetLength(); - for (unsigned int i = 0; i < capcity; i++) { - int entry = moduleItems->FindEntry(allKeys->Get(i)); - if (entry != -1) { - std::cout << "[" << caller << "]" << std::endl - << "--itemName: " << ConvertToString(EcmaString::Cast(allKeys->Get(i).GetTaggedObject())) - << std::endl - << "--itemValue(ObjRef): 0x" << std::hex << moduleItems->GetValue(entry).GetRawData() - << std::endl; - } - } -} - -ModuleManager::ModuleManager(EcmaVM *vm) : vm_(vm) -{ - ecmaModules_ = NameDictionary::Create(vm_->GetJSThread(), DEAULT_DICTIONART_CAPACITY).GetTaggedValue(); -} - -// class ModuleManager -void ModuleManager::AddModule(JSHandle moduleName, JSHandle module) -{ - JSThread *thread = vm_->GetJSThread(); - [[maybe_unused]] EcmaHandleScope scope(thread); - JSHandle dict(thread, ecmaModules_); - ecmaModules_ = - NameDictionary::Put(thread, dict, moduleName, module, PropertyAttributes::Default()).GetTaggedValue(); -} - -void ModuleManager::RemoveModule(JSHandle moduleName) -{ - JSThread *thread = vm_->GetJSThread(); - [[maybe_unused]] EcmaHandleScope scope(thread); - JSHandle moduleItems(thread, ecmaModules_); - int entry = moduleItems->FindEntry(moduleName.GetTaggedValue()); - if (entry != -1) { - ecmaModules_ = NameDictionary::Remove(thread, moduleItems, entry).GetTaggedValue(); - } -} - -JSHandle ModuleManager::GetModule(const JSThread *thread, - [[maybe_unused]] JSHandle moduleName) -{ - int entry = NameDictionary::Cast(ecmaModules_.GetTaggedObject())->FindEntry(moduleName.GetTaggedValue()); - if (entry != -1) { - return JSHandle(thread, NameDictionary::Cast(ecmaModules_.GetTaggedObject())->GetValue(entry)); - } - return thread->GlobalConstants()->GetHandledUndefined(); -} - -CString ModuleManager::GenerateAmiPath(const CString ¤tPathFile, const CString &relativeFile) -{ - if (relativeFile.find("./") != 0 && relativeFile.find("../") != 0) { // not start with "./" or "../" - return relativeFile; // not relative - } - - auto slashPos = currentPathFile.find_last_of('/'); - if (slashPos == CString::npos) { - return relativeFile; // no need to process - } - - auto dotPos = relativeFile.find_last_of("."); - if (dotPos == CString::npos) { - dotPos = 0; - } - - CString fullPath; - fullPath.append(currentPathFile.substr(0, slashPos + 1)); // 1: with "/" - fullPath.append(relativeFile.substr(0, dotPos)); - fullPath.append(".abc"); // ".js" -> ".abc" - return fullPath; -} - -const CString &ModuleManager::GetCurrentExportModuleName() -{ - return moduleNames_.back(); -} - -void ModuleManager::SetCurrentExportModuleName(const std::string_view &moduleFile) -{ - moduleNames_.emplace_back(CString(moduleFile)); // xx/xx/x.abc -} - -void ModuleManager::RestoreCurrentExportModuleName() -{ - auto s = moduleNames_.size(); - if (s > 0) { - moduleNames_.resize(s - 1); - return; - } - UNREACHABLE(); -} - -const CString &ModuleManager::GetPrevExportModuleName() -{ - static const int MINIMUM_COUNT = 2; - auto count = moduleNames_.size(); - ASSERT(count >= MINIMUM_COUNT); - return moduleNames_[count - MINIMUM_COUNT]; -} - -void ModuleManager::AddModuleItem(const JSThread *thread, JSHandle itemName, - JSHandle value) -{ - CString name_str = GetCurrentExportModuleName(); - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - - JSHandle moduleName = factory->NewFromString(name_str); - - JSHandle module = GetModule(thread, JSHandle::Cast(moduleName)); - if (module->IsUndefined()) { - JSHandle emptyModule = factory->NewEmptyEcmaModule(); - EcmaModule::AddItem(thread, emptyModule, itemName, value); - - AddModule(JSHandle::Cast(moduleName), JSHandle::Cast(emptyModule)); - } else { - EcmaModule::AddItem(thread, JSHandle(module), itemName, value); - } -} - -JSHandle ModuleManager::GetModuleItem(const JSThread *thread, JSHandle module, - JSHandle itemName) -{ - return EcmaModule::Cast(module->GetTaggedObject())->GetItem(thread, itemName); // Assume the module is exist -} - -void ModuleManager::CopyModule(const JSThread *thread, JSHandle src) -{ - ASSERT(src->IsHeapObject()); - JSHandle srcModule = JSHandle::Cast(src); - CString name_str = GetCurrentExportModuleName(); // Assume the srcModule exist when dstModule Execute - - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - JSHandle moduleName = factory->NewFromString(name_str); - - JSHandle dstModule = GetModule(thread, JSHandle::Cast(moduleName)); - - if (dstModule->IsUndefined()) { - JSHandle emptyModule = factory->NewEmptyEcmaModule(); - EcmaModule::CopyModuleInternal(thread, emptyModule, srcModule); - - AddModule(JSHandle::Cast(moduleName), JSHandle::Cast(emptyModule)); - } else { - EcmaModule::CopyModuleInternal(thread, JSHandle(dstModule), srcModule); - } -} - -void ModuleManager::DebugPrint([[maybe_unused]] const JSThread *thread, [[maybe_unused]] const CString &caller) -{ - std::cout << "ModuleStack:"; - for_each(moduleNames_.cbegin(), - moduleNames_.cend(), - [](const CString& s)->void { - std::cout << s << " "; - }); - std::cout << "\n"; -} -} // namespace panda::ecmascript diff --git a/ecmascript/ecma_module.h b/ecmascript/ecma_module.h deleted file mode 100644 index 37c9564e..00000000 --- a/ecmascript/ecma_module.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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_ECMA_MODULE_H -#define ECMASCRIPT_ECMA_MODULE_H - -#include "ecmascript/js_object.h" -#include "ecmascript/js_tagged_value-inl.h" -#include "ecmascript/mem/c_string.h" - -namespace panda::ecmascript { -class EcmaVm; - -// Forward declaration -class EcmaModule : public ECMAObject { -public: - static EcmaModule *Cast(ObjectHeader *object) - { - return static_cast(object); - } - - JSHandle GetItem(const JSThread *thread, JSHandle itemName); - - static void AddItem(const JSThread *thread, JSHandle module, JSHandle itemName, - JSHandle itemValue); - - static void RemoveItem(const JSThread *thread, JSHandle module, JSHandle itemName); - - void DebugPrint(const JSThread *thread, const CString &caller); - - static constexpr uint32_t DEAULT_DICTIONART_CAPACITY = 4; - - static constexpr size_t NAME_DICTIONARY_OFFSET = ECMAObject::SIZE; - ACCESSORS(NameDictionary, NAME_DICTIONARY_OFFSET, SIZE) - - DECL_VISIT_OBJECT_FOR_JS_OBJECT(ECMAObject, NAME_DICTIONARY_OFFSET, SIZE) - DECL_DUMP() - -protected: - static void CopyModuleInternal(const JSThread *thread, JSHandle dstModule, - JSHandle srcModule); - - friend class ModuleManager; -}; - -class ModuleManager { -public: - explicit ModuleManager(EcmaVM *vm); - ~ModuleManager() = default; - - void AddModule(JSHandle moduleName, JSHandle module); - - void RemoveModule(JSHandle moduleName); - - JSHandle GetModule(const JSThread *thread, JSHandle moduleName); - - CString GenerateAmiPath(const CString ¤tPathFile, const CString &relativeFile); - - const CString &GetCurrentExportModuleName(); - - const CString &GetPrevExportModuleName(); - - void SetCurrentExportModuleName(const std::string_view &moduleFile); - - void RestoreCurrentExportModuleName(); - - void AddModuleItem(const JSThread *thread, JSHandle itemName, JSHandle value); - - JSHandle GetModuleItem(const JSThread *thread, JSHandle module, - JSHandle itemName); - - void CopyModule(const JSThread *thread, JSHandle src); - - void DebugPrint(const JSThread *thread, const CString &caller); - - void Iterate(const RootVisitor &v) - { - v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(&ecmaModules_))); - } - -private: - static constexpr uint32_t DEAULT_DICTIONART_CAPACITY = 4; - - NO_COPY_SEMANTIC(ModuleManager); - NO_MOVE_SEMANTIC(ModuleManager); - - EcmaVM *vm_{nullptr}; - JSTaggedValue ecmaModules_ {JSTaggedValue::Hole()}; - std::vector moduleNames_ {DEAULT_DICTIONART_CAPACITY}; - - friend class EcmaVM; -}; -} // namespace panda::ecmascript - -#endif diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp index 62bbebcc..8e183da1 100644 --- a/ecmascript/ecma_vm.cpp +++ b/ecmascript/ecma_vm.cpp @@ -18,13 +18,10 @@ #include "ecmascript/base/string_helper.h" #include "ecmascript/builtins.h" #include "ecmascript/builtins/builtins_regexp.h" -#include "ecmascript/class_linker/panda_file_translator.h" -#include "ecmascript/class_linker/program_object-inl.h" #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h" #endif #include "ecmascript/dfx/vmstat/runtime_stat.h" -#include "ecmascript/ecma_module.h" #include "ecmascript/ecma_string_table.h" #include "ecmascript/global_dictionary.h" #include "ecmascript/global_env.h" @@ -34,6 +31,9 @@ #include "ecmascript/jobs/micro_job_queue.h" #include "ecmascript/jspandafile/js_pandafile.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" +#include "ecmascript/jspandafile/module_data_extractor.h" +#include "ecmascript/jspandafile/panda_file_translator.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/js_arraybuffer.h" #include "ecmascript/js_for_in_iterator.h" #include "ecmascript/js_invoker.h" @@ -41,6 +41,7 @@ #include "ecmascript/js_thread.h" #include "ecmascript/mem/concurrent_marker.h" #include "ecmascript/mem/heap.h" +#include "ecmascript/module/js_module_manager.h" #include "ecmascript/object_factory.h" #include "ecmascript/platform/platform.h" #include "ecmascript/regexp/regexp_parser_cache.h" @@ -72,7 +73,6 @@ namespace panda::ecmascript { // NOLINTNEXTLINE(fuchsia-statically-constructed-objects) -static const std::string_view ENTRY_POINTER = "_GLOBAL::func_main_0"; JSRuntimeOptions JSRuntimeOptions::temporary_options; // NOLINT(fuchsia-statically-constructed-objects) /* static */ @@ -336,17 +336,6 @@ EcmaVM::~EcmaVM() } } -bool EcmaVM::ExecuteFromPf(const std::string &filename, std::string_view entryPoint, - const std::vector &args, bool isModule) -{ - const JSPandaFile *jsPandaFile = GetJSPandaFileManager()->LoadJSPandaFile(filename); - if (jsPandaFile == nullptr) { - return false; - } - - return Execute(jsPandaFile, entryPoint, args); -} - bool EcmaVM::CollectInfoOfPandaFile(const std::string &filename, std::vector *infoList) { const JSPandaFile *jsPandaFile = GetJSPandaFileManager()->LoadAotInfoFromPf(filename, infoList); @@ -361,44 +350,12 @@ bool EcmaVM::CollectInfoOfPandaFile(const std::string &filename, std::vector &args, const std::string &filename) -{ - const JSPandaFile *jsPandaFile = GetJSPandaFileManager()->LoadJSPandaFile(filename, buffer, size); - if (jsPandaFile == nullptr) { - return false; - } - // Get ClassName and MethodName - size_t pos = entryPoint.find_last_of("::"); - if (pos == std::string_view::npos) { - LOG_ECMA(ERROR) << "EntryPoint:" << entryPoint << " is illegal"; - return false; - } - CString methodName(entryPoint.substr(pos + 1)); - InvokeEcmaEntrypoint(jsPandaFile, methodName, args); - return true; -} - tooling::ecmascript::PtJSExtractor *EcmaVM::GetDebugInfoExtractor(const panda_file::File *file) { tooling::ecmascript::PtJSExtractor *res = GetJSPandaFileManager()->GetOrCreatePtJSExtractor(file); return res; } -bool EcmaVM::Execute(const JSPandaFile *jsPandaFile, std::string_view entryPoint, const std::vector &args) -{ - // Get ClassName and MethodName - size_t pos = entryPoint.find_last_of("::"); - if (pos == std::string_view::npos) { - LOG_ECMA(ERROR) << "EntryPoint:" << entryPoint << " is illegal"; - return false; - } - CString methodName(entryPoint.substr(pos + 1)); - // For Ark application startup - InvokeEcmaEntrypoint(jsPandaFile, methodName, args); - return true; -} - JSHandle EcmaVM::GetGlobalEnv() const { return JSHandle(reinterpret_cast(&globalEnv_)); @@ -471,6 +428,12 @@ Expected EcmaVM::InvokeEcmaEntrypoint(const JSPandaFile *js params->MakeArgList(*jsargs); JSRuntimeOptions options = this->GetJSOptions(); JSHandle global = GlobalEnv::Cast(globalEnv_.GetTaggedObject())->GetJSGlobalObject(); + + if (jsPandaFile->IsModule()) { + global = JSHandle(thread_, JSTaggedValue::Undefined()); + JSHandle module = moduleManager_->HostGetImportedModule(jsPandaFile->GetJSPandaFileDesc()); + func->SetModule(thread_, module); + } if (options.IsEnableCpuProfiler()) { #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) CpuProfiler *profiler = CpuProfiler::GetInstance(); @@ -677,44 +640,6 @@ void EcmaVM::SetMicroJobQueue(job::MicroJobQueue *queue) microJobQueue_ = JSTaggedValue(queue); } -JSHandle EcmaVM::GetModuleByName(JSHandle moduleName) -{ - // only used in testcase, pandaFileWithProgram_ only one item. this interface will delete - const JSPandaFile *currentJSPandaFile = nullptr; - GetJSPandaFileManager()->EnumerateJSPandaFiles([¤tJSPandaFile](const JSPandaFile *jsPandaFile) { - currentJSPandaFile = jsPandaFile; - return false; - }); - ASSERT(currentJSPandaFile != nullptr); - CString currentPathFile = currentJSPandaFile->GetJSPandaFileDesc(); - CString relativeFile = ConvertToString(EcmaString::Cast(moduleName->GetTaggedObject())); - - // generate full path - CString abcPath = moduleManager_->GenerateAmiPath(currentPathFile, relativeFile); - - // Uniform module name - JSHandle abcModuleName = factory_->NewFromString(abcPath); - - JSHandle module = moduleManager_->GetModule(thread_, JSHandle::Cast(abcModuleName)); - if (module->IsUndefined()) { - std::string file = base::StringHelper::ToStdString(abcModuleName.GetObject()); - std::vector argv; - ExecuteModule(file, ENTRY_POINTER, argv); - module = moduleManager_->GetModule(thread_, JSHandle::Cast(abcModuleName)); - } - return module; -} - -void EcmaVM::ExecuteModule(const std::string &moduleFile, std::string_view entryPoint, - const std::vector &args) -{ - moduleManager_->SetCurrentExportModuleName(moduleFile); - // Update Current Module - EcmaVM::ExecuteFromPf(moduleFile, entryPoint, args, true); - // Restore Current Module - moduleManager_->RestoreCurrentExportModuleName(); -} - void EcmaVM::ClearNativeMethodsData() { for (auto iter : nativeMethods_) { diff --git a/ecmascript/ecma_vm.h b/ecmascript/ecma_vm.h index 73169f87..0c53e2b5 100644 --- a/ecmascript/ecma_vm.h +++ b/ecmascript/ecma_vm.h @@ -69,10 +69,9 @@ class JSHandle; class JSArrayBuffer; class JSFunction; class Program; -class ModuleManager; -class EcmaModule; class TSLoader; struct BytecodeTranslationInfo; +class ModuleManager; using HostPromiseRejectionTracker = void (*)(const EcmaVM* vm, const JSHandle promise, const JSHandle reason, @@ -101,12 +100,6 @@ public: ~EcmaVM() override; - bool ExecuteFromPf(const std::string &filename, std::string_view entryPoint, - const std::vector &args, bool isModule = false); - - bool ExecuteFromBuffer(const void *buffer, size_t size, std::string_view entryPoint, - const std::vector &args, const std::string &filename = ""); - bool PUBLIC_API CollectInfoOfPandaFile(const std::string &filename, std::vector *infoList); @@ -335,11 +328,6 @@ public: void ProcessNativeDelete(const WeakRootVisitor &v0); void ProcessReferences(const WeakRootVisitor &v0); - JSHandle GetModuleByName(JSHandle moduleName); - - void ExecuteModule(const std::string &moduleFile, std::string_view entryPoint, - const std::vector &args); - ModuleManager *GetModuleManager() const { return moduleManager_; @@ -423,8 +411,6 @@ private: void SetMicroJobQueue(job::MicroJobQueue *queue); - bool Execute(const JSPandaFile *jsPandaFile, std::string_view entryPoint, const std::vector &args); - Expected InvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile, const CString &methodName, const std::vector &args); @@ -493,6 +479,7 @@ private: friend class ObjectFactory; friend class ValueSerializer; friend class panda::JSNApi; + friend class JSPandaFileExecutor; }; } // namespace ecmascript } // namespace panda diff --git a/ecmascript/global_env.cpp b/ecmascript/global_env.cpp index cf6b5ef8..76219632 100644 --- a/ecmascript/global_env.cpp +++ b/ecmascript/global_env.cpp @@ -14,12 +14,11 @@ */ #include "ecmascript/global_env.h" -#include "ecma_module.h" #include "ecmascript/builtins/builtins_promise_handler.h" -#include "ecmascript/class_linker/program_object-inl.h" #include "ecmascript/ic/ic_handler.h" #include "ecmascript/ic/proto_change_details.h" #include "ecmascript/jobs/micro_job_queue.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/js_generator_object.h" #include "ecmascript/js_handle.h" #include "ecmascript/js_promise.h" diff --git a/ecmascript/global_env.h b/ecmascript/global_env.h index 8ac1a2b7..aff6fd24 100644 --- a/ecmascript/global_env.h +++ b/ecmascript/global_env.h @@ -137,7 +137,8 @@ class JSThread; V(JSTaggedValue, JSIntlBoundFunctionClass, JS_INTL_BOUND_FUNCTION_CLASS) \ V(JSTaggedValue, NumberFormatLocales, NUMBER_FORMAT_LOCALES_INDEX) \ V(JSTaggedValue, DateTimeFormatLocales, DATE_TIMEFORMAT_LOCALES_INDEX) \ - V(JSTaggedValue, GlobalRecord, GLOBAL_RECORD) + V(JSTaggedValue, GlobalRecord, GLOBAL_RECORD) \ + V(JSTaggedValue, ModuleNamespaceClass, MODULENAMESPACE_CLASS) class GlobalEnv : public TaggedObject { public: diff --git a/ecmascript/global_env_constants.cpp b/ecmascript/global_env_constants.cpp index 17d8e50c..67f74505 100644 --- a/ecmascript/global_env_constants.cpp +++ b/ecmascript/global_env_constants.cpp @@ -18,9 +18,6 @@ #include "ecmascript/accessor_data.h" #include "ecmascript/builtins.h" #include "ecmascript/builtins/builtins_global.h" -#include "ecmascript/class_info_extractor.h" -#include "ecmascript/class_linker/program_object.h" -#include "ecmascript/ecma_module.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/free_object.h" #include "ecmascript/global_env.h" @@ -30,6 +27,8 @@ #include "ecmascript/ic/proto_change_details.h" #include "ecmascript/jobs/micro_job_queue.h" #include "ecmascript/jobs/pending_job.h" +#include "ecmascript/jspandafile/class_info_extractor.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/js_arguments.h" #include "ecmascript/js_array.h" #include "ecmascript/js_array_iterator.h" @@ -50,6 +49,7 @@ #include "ecmascript/js_symbol.h" #include "ecmascript/js_tagged_value.h" #include "ecmascript/js_thread.h" +#include "ecmascript/module/js_module_source_text.h" #include "ecmascript/object_factory.h" #include "ecmascript/ts_types/ts_type.h" @@ -112,8 +112,18 @@ void GlobalEnvConstants::InitRootsClass([[maybe_unused]] JSThread *thread, JSHCl factory->NewEcmaDynClass(dynClassClass, PropertyBox::SIZE, JSType::PROPERTY_BOX)); SetConstant(ConstantIndex::PROGRAM_CLASS_INDEX, factory->NewEcmaDynClass(dynClassClass, Program::SIZE, JSType::PROGRAM)); - SetConstant(ConstantIndex::ECMA_MODULE_CLASS_INDEX, - factory->NewEcmaDynClass(dynClassClass, EcmaModule::SIZE, JSType::ECMA_MODULE)); + SetConstant( + ConstantIndex::IMPORT_ENTRY_CLASS_INDEX, + factory->NewEcmaDynClass(dynClassClass, ImportEntry::SIZE, JSType::IMPORTENTRY_RECORD)); + SetConstant( + ConstantIndex::EXPORT_ENTRY_CLASS_INDEX, + factory->NewEcmaDynClass(dynClassClass, ExportEntry::SIZE, JSType::EXPORTENTRY_RECORD)); + SetConstant( + ConstantIndex::SOURCE_TEXT_MODULE_CLASS_INDEX, + factory->NewEcmaDynClass(dynClassClass, SourceTextModule::SIZE, JSType::SOURCE_TEXT_MODULE_RECORD)); + SetConstant( + ConstantIndex::RESOLVED_BINDING_CLASS_INDEX, + factory->NewEcmaDynClass(dynClassClass, ResolvedBinding::SIZE, JSType::RESOLVEDBINDING_RECORD)); JSHClass *jsProxyCallableClass = *factory->NewEcmaDynClass(dynClassClass, JSProxy::SIZE, JSType::JS_PROXY); @@ -385,6 +395,9 @@ void GlobalEnvConstants::InitGlobalConstant(JSThread *thread) SetConstant(ConstantIndex::UNICODE_INDEX, factory->NewFromCanBeCompressString("unicode")); SetConstant(ConstantIndex::ZERO_INDEX, factory->NewFromCanBeCompressString("0")); SetConstant(ConstantIndex::VALUES_INDEX, factory->NewFromCanBeCompressString("values")); + SetConstant(ConstantIndex::AMBIGUOUS_INDEX, factory->NewFromCanBeCompressString("ambiguous")); + SetConstant(ConstantIndex::MODULE_INDEX, factory->NewFromCanBeCompressString("module")); + SetConstant(ConstantIndex::STAR_INDEX, factory->NewFromCanBeCompressString("*")); auto accessor = factory->NewInternalAccessor(reinterpret_cast(JSFunction::PrototypeSetter), reinterpret_cast(JSFunction::PrototypeGetter)); diff --git a/ecmascript/global_env_constants.h b/ecmascript/global_env_constants.h index 45005e28..61841162 100644 --- a/ecmascript/global_env_constants.h +++ b/ecmascript/global_env_constants.h @@ -60,7 +60,6 @@ class JSThread; V(JSTaggedValue, TransitionHandlerClass, TRANSITION_HANDLER_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, PropertyBoxClass, PROPERTY_BOX_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, ProgramClass, PROGRAM_CLASS_INDEX, ecma_roots_class) \ - V(JSTaggedValue, EcmaModuleClass, ECMA_MODULE_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, JSProxyCallableClass, JS_PROXY_CALLABLE_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, JSProxyConstructClass, JS_PROXY_CONSTRUCT_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, JSRealmClass, JS_REALM_CLASS_INDEX, ecma_roots_class) \ @@ -74,7 +73,12 @@ class JSThread; V(JSTaggedValue, TSClassInstanceTypeClass, TS_CLASS_INSTANCE_TYPE_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, TSImportTypeClass, TS_IMPORT_TYPE_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, TSFunctionTypeClass, TS_FUNCTION_TYPE_CLASS_INDEX, ecma_roots_class) \ - V(JSTaggedValue, TSArrayTypeClass, TS_ARRAY_TYPE_CLASS_INDEX, ecma_roots_class) + V(JSTaggedValue, TSArrayTypeClass, TS_ARRAY_TYPE_CLASS_INDEX, ecma_roots_class) \ + V(JSTaggedValue, ImportEntryClass, IMPORT_ENTRY_CLASS_INDEX, ecma_roots_class) \ + V(JSTaggedValue, ExportEntryClass, EXPORT_ENTRY_CLASS_INDEX, ecma_roots_class) \ + V(JSTaggedValue, SourceTextModuleClass, SOURCE_TEXT_MODULE_CLASS_INDEX, ecma_roots_class) \ + V(JSTaggedValue, ResolvedBindingClass, RESOLVED_BINDING_CLASS_INDEX, ecma_roots_class) + // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define GLOBAL_ENV_CONSTANT_SPECIAL(V) \ V(JSTaggedValue, Undefined, UNDEFINED_INDEX, ecma_roots_special) \ @@ -302,7 +306,11 @@ class JSThread; V(JSTaggedValue, IndexString, INDEX_INDEX, index) \ V(JSTaggedValue, InputString, INPUT_INDEX, input) \ V(JSTaggedValue, UnicodeString, UNICODE_INDEX, unicode) \ - V(JSTaggedValue, ZeroString, ZERO_INDEX, zero) + V(JSTaggedValue, ZeroString, ZERO_INDEX, zero) \ + /* for module. */ \ + V(JSTaggedValue, AmbiguousString, AMBIGUOUS_INDEX, ambiguous) \ + V(JSTaggedValue, ModuleString, MODULE_INDEX, module) \ + V(JSTaggedValue, StarString, STAR_INDEX, star) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define GLOBAL_ENV_CONSTANT_ACCESSOR(V) \ diff --git a/ecmascript/interpreter/frame_handler.cpp b/ecmascript/interpreter/frame_handler.cpp index 75586d54..671cd4d2 100644 --- a/ecmascript/interpreter/frame_handler.cpp +++ b/ecmascript/interpreter/frame_handler.cpp @@ -16,9 +16,9 @@ #include "ecmascript/interpreter/frame_handler.h" -#include "ecmascript/class_linker/program_object.h" #include "ecmascript/compiler/llvm/llvm_stackmap_parser.h" #include "ecmascript/mem/heap.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/js_function.h" #include "ecmascript/js_thread.h" diff --git a/ecmascript/interpreter/interpreter-inl.h b/ecmascript/interpreter/interpreter-inl.h index 578c3004..1973e20b 100644 --- a/ecmascript/interpreter/interpreter-inl.h +++ b/ecmascript/interpreter/interpreter-inl.h @@ -16,11 +16,9 @@ #ifndef ECMASCRIPT_INTERPRETER_INTERPRETER_INL_H #define ECMASCRIPT_INTERPRETER_INTERPRETER_INL_H -#include "ecmascript/class_linker/program_object-inl.h" #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h" #endif -#include "ecmascript/class_linker/program_object-inl.h" #include "ecmascript/ecma_string.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" @@ -30,10 +28,12 @@ #include "ecmascript/interpreter/interpreter_assembly.h" #include "ecmascript/interpreter/frame_handler.h" #include "ecmascript/interpreter/slow_runtime_stub.h" +#include "ecmascript/jspandafile/literal_data_extractor.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/js_generator_object.h" #include "ecmascript/js_tagged_value.h" -#include "ecmascript/literal_data_extractor.h" #include "ecmascript/mem/concurrent_marker.h" +#include "ecmascript/module/js_module_manager.h" #include "ecmascript/runtime_call_id.h" #include "ecmascript/template_string.h" #include "include/runtime_notification.h" @@ -1932,6 +1932,9 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); JSTaggedValue envHandle = GET_VREG_VALUE(v0); result->SetLexicalEnv(thread, envHandle); + + JSFunction *currentFunc = JSFunction::Cast((GET_FRAME(sp)->function).GetTaggedObject()); + result->SetModule(thread, currentFunc->GetModule()); SET_ACC(JSTaggedValue(result)) DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); @@ -1962,6 +1965,9 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool JSTaggedValue env = GET_VREG_VALUE(v0); result->SetLexicalEnv(thread, env); result->SetHomeObject(thread, homeObject); + + JSFunction *currentFunc = JSFunction::Cast((GET_FRAME(sp)->function).GetTaggedObject()); + result->SetModule(thread, currentFunc->GetModule()); SET_ACC(JSTaggedValue(result)); DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); @@ -1989,6 +1995,9 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); JSTaggedValue taggedCurEnv = GET_VREG_VALUE(v0); result->SetLexicalEnv(thread, taggedCurEnv); + + JSFunction *currentFunc = JSFunction::Cast((GET_FRAME(sp)->function).GetTaggedObject()); + result->SetModule(thread, currentFunc->GetModule()); SET_ACC(JSTaggedValue(result)); DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); @@ -2568,55 +2577,48 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool SET_ACC(res); DISPATCH(BytecodeInstruction::Format::PREF_IMM16); } - HANDLE_OPCODE(HANDLE_IMPORTMODULE_PREF_ID32) { + HANDLE_OPCODE(HANDLE_GETMODULENAMESPACE_PREF_ID32) { uint32_t stringId = READ_INST_32_1(); - auto prop = constpool->GetObjectFromCache(stringId); + auto localName = constpool->GetObjectFromCache(stringId); - LOG_INST() << "intrinsics::importmodule " - << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(prop.GetTaggedObject())); + LOG_INST() << "intrinsics::getmodulenamespace " + << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(localName.GetTaggedObject())); - JSTaggedValue moduleRef = SlowRuntimeStub::ImportModule(thread, prop); - SET_ACC(moduleRef); + JSTaggedValue moduleNamespace = SlowRuntimeStub::GetModuleNamespace(thread, localName); + INTERPRETER_RETURN_IF_ABRUPT(moduleNamespace); + SET_ACC(moduleNamespace); DISPATCH(BytecodeInstruction::Format::PREF_ID32); } HANDLE_OPCODE(HANDLE_STMODULEVAR_PREF_ID32) { uint32_t stringId = READ_INST_32_1(); - auto prop = constpool->GetObjectFromCache(stringId); + auto key = constpool->GetObjectFromCache(stringId); LOG_INST() << "intrinsics::stmodulevar " - << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(prop.GetTaggedObject())); + << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(key.GetTaggedObject())); JSTaggedValue value = GET_ACC(); SAVE_ACC(); - SlowRuntimeStub::StModuleVar(thread, prop, value); + SlowRuntimeStub::StModuleVar(thread, key, value); RESTORE_ACC(); DISPATCH(BytecodeInstruction::Format::PREF_ID32); } HANDLE_OPCODE(HANDLE_COPYMODULE_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - JSTaggedValue srcModule = GET_VREG_VALUE(v0); - - LOG_INST() << "intrinsics::copymodule "; - - SAVE_ACC(); - SlowRuntimeStub::CopyModule(thread, srcModule); - RESTORE_ACC(); DISPATCH(BytecodeInstruction::Format::PREF_V8); } - HANDLE_OPCODE(HANDLE_LDMODVARBYNAME_PREF_ID32_V8) { + HANDLE_OPCODE(HANDLE_LDMODULEVAR_PREF_ID32_IMM8) { uint32_t stringId = READ_INST_32_1(); - uint32_t v0 = READ_INST_8_5(); + uint8_t innerFlag = READ_INST_8_5(); - JSTaggedValue itemName = constpool->GetObjectFromCache(stringId); - JSTaggedValue moduleObj = GET_VREG_VALUE(v0); - LOG_INST() << "intrinsics::ldmodvarbyname " + JSTaggedValue key = constpool->GetObjectFromCache(stringId); + LOG_INST() << "intrinsics::ldmodulevar " << "string_id:" << stringId << ", " - << "itemName: " << ConvertToString(EcmaString::Cast(itemName.GetTaggedObject())); + << "key: " << ConvertToString(EcmaString::Cast(key.GetTaggedObject())); - JSTaggedValue moduleVar = SlowRuntimeStub::LdModvarByName(thread, moduleObj, itemName); + JSTaggedValue moduleVar = SlowRuntimeStub::LdModuleVar(thread, key, innerFlag != 0); + INTERPRETER_RETURN_IF_ABRUPT(moduleVar); SET_ACC(moduleVar); - DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_IMM8); } HANDLE_OPCODE(HANDLE_CREATEREGEXPWITHLITERAL_PREF_ID32_IMM8) { uint32_t stringId = READ_INST_32_1(); @@ -2767,6 +2769,9 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); JSTaggedValue env = GET_VREG_VALUE(v0); result->SetLexicalEnv(thread, env); + + JSFunction *currentFunc = JSFunction::Cast((GET_FRAME(sp)->function).GetTaggedObject()); + result->SetModule(thread, currentFunc->GetModule()); SET_ACC(JSTaggedValue(result)) DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); } @@ -2791,6 +2796,9 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); JSTaggedValue env = GET_VREG_VALUE(v0); result->SetLexicalEnv(thread, env); + + JSFunction *currentFunc = JSFunction::Cast((GET_FRAME(sp)->function).GetTaggedObject()); + result->SetModule(thread, currentFunc->GetModule()); SET_ACC(JSTaggedValue(result)) DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); } @@ -3579,6 +3587,9 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool lexenv = GET_VREG_VALUE(v0); // slow runtime may gc cls->SetLexicalEnv(thread, lexenv); + JSFunction *currentFunc = JSFunction::Cast((GET_FRAME(sp)->function).GetTaggedObject()); + cls->SetModule(thread, currentFunc->GetModule()); + SlowRuntimeStub::SetClassConstructorLength(thread, res, JSTaggedValue(length)); SET_ACC(res); @@ -4001,7 +4012,7 @@ std::string GetEcmaOpcodeStr(EcmaOpcode opcode) {STLEXVARDYN_PREF_IMM16_IMM16_V8, "STLEXVARDYN"}, {NEWLEXENVWITHNAMEDYN_PREF_IMM16_IMM16, "NEWLEXENVWITHNAMEDYN"}, {DEFINECLASSWITHBUFFER_PREF_ID16_IMM16_IMM16_V8_V8, "DEFINECLASSWITHBUFFER"}, - {IMPORTMODULE_PREF_ID32, "IMPORTMODULE"}, + {GETMODULENAMESPACE_PREF_ID32, "GETMODULENAMESPACE"}, {STMODULEVAR_PREF_ID32, "STMODULEVAR"}, {TRYLDGLOBALBYNAME_PREF_ID32, "TRYLDGLOBALBYNAME"}, {TRYSTGLOBALBYNAME_PREF_ID32, "TRYSTGLOBALBYNAME"}, @@ -4012,7 +4023,7 @@ std::string GetEcmaOpcodeStr(EcmaOpcode opcode) {STOWNBYNAME_PREF_ID32_V8, "STOWNBYNAME"}, {LDSUPERBYNAME_PREF_ID32_V8, "LDSUPERBYNAME"}, {STSUPERBYNAME_PREF_ID32_V8, "STSUPERBYNAME"}, - {LDMODVARBYNAME_PREF_ID32_V8, "LDMODVARBYNAME"}, + {LDMODULEVAR_PREF_ID32_IMM8, "LDMODULEVAR"}, {CREATEREGEXPWITHLITERAL_PREF_ID32_IMM8, "CREATEREGEXPWITHLITERAL"}, {ISTRUE_PREF, "ISTRUE"}, {ISFALSE_PREF, "ISFALSE"}, diff --git a/ecmascript/interpreter/interpreter.h b/ecmascript/interpreter/interpreter.h index 20640b88..7c74f47e 100755 --- a/ecmascript/interpreter/interpreter.h +++ b/ecmascript/interpreter/interpreter.h @@ -185,7 +185,7 @@ enum EcmaOpcode { STLEXVARDYN_PREF_IMM8_IMM8_V8, STLEXVARDYN_PREF_IMM16_IMM16_V8, DEFINECLASSWITHBUFFER_PREF_ID16_IMM16_IMM16_V8_V8, - IMPORTMODULE_PREF_ID32, + GETMODULENAMESPACE_PREF_ID32, STMODULEVAR_PREF_ID32, TRYLDGLOBALBYNAME_PREF_ID32, TRYSTGLOBALBYNAME_PREF_ID32, @@ -196,7 +196,7 @@ enum EcmaOpcode { STOWNBYNAME_PREF_ID32_V8, LDSUPERBYNAME_PREF_ID32_V8, STSUPERBYNAME_PREF_ID32_V8, - LDMODVARBYNAME_PREF_ID32_V8, + LDMODULEVAR_PREF_ID32_IMM8, CREATEREGEXPWITHLITERAL_PREF_ID32_IMM8, ISTRUE_PREF, ISFALSE_PREF, diff --git a/ecmascript/interpreter/interpreter_assembly.cpp b/ecmascript/interpreter/interpreter_assembly.cpp index f49f5924..af3ea74c 100644 --- a/ecmascript/interpreter/interpreter_assembly.cpp +++ b/ecmascript/interpreter/interpreter_assembly.cpp @@ -15,7 +15,6 @@ #include "ecmascript/interpreter/interpreter_assembly.h" -#include "ecmascript/class_linker/program_object-inl.h" #include "ecmascript/dfx/vmstat/runtime_stat.h" #include "ecmascript/ecma_string.h" #include "ecmascript/ecma_vm.h" @@ -24,9 +23,10 @@ #include "ecmascript/interpreter/fast_runtime_stub-inl.h" #include "ecmascript/interpreter/frame_handler.h" #include "ecmascript/interpreter/slow_runtime_stub.h" +#include "ecmascript/jspandafile/literal_data_extractor.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/js_generator_object.h" #include "ecmascript/js_tagged_value.h" -#include "ecmascript/literal_data_extractor.h" #include "ecmascript/mem/concurrent_marker.h" #include "ecmascript/runtime_call_id.h" #include "ecmascript/template_string.h" @@ -1791,6 +1791,9 @@ void InterpreterAssembly::HandleDefineFuncDynPrefId16Imm16V8( result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); JSTaggedValue envHandle = GET_VREG_VALUE(v0); result->SetLexicalEnv(thread, envHandle); + + JSFunction *currentFunc = JSFunction::Cast((GET_FRAME(sp)->function).GetTaggedObject()); + result->SetModule(thread, currentFunc->GetModule()); SET_ACC(JSTaggedValue(result)) DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); @@ -1825,6 +1828,9 @@ void InterpreterAssembly::HandleDefineNCFuncDynPrefId16Imm16V8( JSTaggedValue env = GET_VREG_VALUE(v0); result->SetLexicalEnv(thread, env); result->SetHomeObject(thread, homeObject); + + JSFunction *currentFunc = JSFunction::Cast((GET_FRAME(sp)->function).GetTaggedObject()); + result->SetModule(thread, currentFunc->GetModule()); SET_ACC(JSTaggedValue(result)); DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); @@ -1856,6 +1862,9 @@ void InterpreterAssembly::HandleDefineMethodPrefId16Imm16V8( result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); JSTaggedValue taggedCurEnv = GET_VREG_VALUE(v0); result->SetLexicalEnv(thread, taggedCurEnv); + + JSFunction *currentFunc = JSFunction::Cast((GET_FRAME(sp)->function).GetTaggedObject()); + result->SetModule(thread, currentFunc->GetModule()); SET_ACC(JSTaggedValue(result)); DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); @@ -2394,18 +2403,19 @@ void InterpreterAssembly::HandleCreateArrayWithBufferPrefImm16( DISPATCH(BytecodeInstruction::Format::PREF_IMM16); } -void InterpreterAssembly::HandleImportModulePrefId32( +void InterpreterAssembly::HandleGetModuleNamespacePrefId32( JSThread *thread, const uint8_t *pc, JSTaggedType *sp, JSTaggedValue constpool, JSTaggedValue profileTypeInfo, JSTaggedValue acc, int32_t hotnessCounter) { uint32_t stringId = READ_INST_32_1(); - auto prop = ConstantPool::Cast(constpool.GetTaggedObject())->GetObjectFromCache(stringId); + auto localName = ConstantPool::Cast(constpool.GetTaggedObject())->GetObjectFromCache(stringId); - LOG_INST() << "intrinsics::importmodule " - << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(prop.GetTaggedObject())); + LOG_INST() << "intrinsics::getmodulenamespace " + << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(localName.GetTaggedObject())); - JSTaggedValue moduleRef = SlowRuntimeStub::ImportModule(thread, prop); - SET_ACC(moduleRef); + JSTaggedValue moduleNamespace = SlowRuntimeStub::GetModuleNamespace(thread, localName); + INTERPRETER_RETURN_IF_ABRUPT(moduleNamespace); + SET_ACC(moduleNamespace); DISPATCH(BytecodeInstruction::Format::PREF_ID32); } @@ -2414,14 +2424,15 @@ void InterpreterAssembly::HandleStModuleVarPrefId32( JSTaggedValue acc, int32_t hotnessCounter) { uint32_t stringId = READ_INST_32_1(); - auto prop = ConstantPool::Cast(constpool.GetTaggedObject())->GetObjectFromCache(stringId); + auto key = ConstantPool::Cast(constpool.GetTaggedObject())->GetObjectFromCache(stringId); LOG_INST() << "intrinsics::stmodulevar " - << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(prop.GetTaggedObject())); + << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(key.GetTaggedObject())); + JSTaggedValue value = GET_ACC(); SAVE_ACC(); - SlowRuntimeStub::StModuleVar(thread, prop, value); + SlowRuntimeStub::StModuleVar(thread, key, value); RESTORE_ACC(); DISPATCH(BytecodeInstruction::Format::PREF_ID32); } @@ -2430,32 +2441,25 @@ void InterpreterAssembly::HandleCopyModulePrefV8( JSThread *thread, const uint8_t *pc, JSTaggedType *sp, JSTaggedValue constpool, JSTaggedValue profileTypeInfo, JSTaggedValue acc, int32_t hotnessCounter) { - uint16_t v0 = READ_INST_8_1(); - JSTaggedValue srcModule = GET_VREG_VALUE(v0); - - LOG_INST() << "intrinsics::copymodule "; - - SAVE_ACC(); - SlowRuntimeStub::CopyModule(thread, srcModule); - RESTORE_ACC(); DISPATCH(BytecodeInstruction::Format::PREF_V8); } -void InterpreterAssembly::HandleLdModVarByNamePrefId32V8( +void InterpreterAssembly::HandleLdModuleVarPrefId32Imm8( JSThread *thread, const uint8_t *pc, JSTaggedType *sp, JSTaggedValue constpool, JSTaggedValue profileTypeInfo, JSTaggedValue acc, int32_t hotnessCounter) { uint32_t stringId = READ_INST_32_1(); - uint32_t v0 = READ_INST_8_5(); - JSTaggedValue itemName = ConstantPool::Cast(constpool.GetTaggedObject())->GetObjectFromCache(stringId); - JSTaggedValue moduleObj = GET_VREG_VALUE(v0); - LOG_INST() << "intrinsics::ldmodvarbyname " - << "string_id:" << stringId << ", " - << "itemName: " << ConvertToString(EcmaString::Cast(itemName.GetTaggedObject())); + uint8_t innerFlag = READ_INST_8_5(); - JSTaggedValue moduleVar = SlowRuntimeStub::LdModvarByName(thread, moduleObj, itemName); + JSTaggedValue key = ConstantPool::Cast(constpool.GetTaggedObject())->GetObjectFromCache(stringId); + LOG_INST() << "intrinsics::ldmodulevar " + << "string_id:" << stringId << ", " + << "key: " << ConvertToString(EcmaString::Cast(key.GetTaggedObject())); + + JSTaggedValue moduleVar = SlowRuntimeStub::LdModuleVar(thread, key, innerFlag != 0); + INTERPRETER_RETURN_IF_ABRUPT(moduleVar); SET_ACC(moduleVar); - DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_IMM8); } void InterpreterAssembly::HandleCreateRegExpWithLiteralPrefId32Imm8( @@ -2631,6 +2635,9 @@ void InterpreterAssembly::HandleDefineGeneratorFuncPrefId16Imm16V8( result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); JSTaggedValue env = GET_VREG_VALUE(v0); result->SetLexicalEnv(thread, env); + + JSFunction *currentFunc = JSFunction::Cast((GET_FRAME(sp)->function).GetTaggedObject()); + result->SetModule(thread, currentFunc->GetModule()); SET_ACC(JSTaggedValue(result)) DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); } @@ -2659,6 +2666,9 @@ void InterpreterAssembly::HandleDefineAsyncFuncPrefId16Imm16V8( result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); JSTaggedValue env = GET_VREG_VALUE(v0); result->SetLexicalEnv(thread, env); + + JSFunction *currentFunc = JSFunction::Cast((GET_FRAME(sp)->function).GetTaggedObject()); + result->SetModule(thread, currentFunc->GetModule()); SET_ACC(JSTaggedValue(result)) DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); } @@ -3469,6 +3479,9 @@ void InterpreterAssembly::HandleDefineClassWithBufferPrefId16Imm16Imm16V8V8( lexenv = GET_VREG_VALUE(v0); // slow runtime may gc cls->SetLexicalEnv(thread, lexenv); + JSFunction *currentFunc = JSFunction::Cast((GET_FRAME(sp)->function).GetTaggedObject()); + cls->SetModule(thread, currentFunc->GetModule()); + SlowRuntimeStub::SetClassConstructorLength(thread, res, JSTaggedValue(length)); SET_ACC(res); diff --git a/ecmascript/interpreter/interpreter_assembly.h b/ecmascript/interpreter/interpreter_assembly.h index db36afc6..b896ecc9 100644 --- a/ecmascript/interpreter/interpreter_assembly.h +++ b/ecmascript/interpreter/interpreter_assembly.h @@ -351,7 +351,7 @@ public: static void HandleCreateArrayWithBufferPrefImm16( JSThread *thread, const uint8_t *pc, JSTaggedType *sp, JSTaggedValue constpool, JSTaggedValue profileTypeInfo, JSTaggedValue acc, int32_t hotnessCounter); - static void HandleImportModulePrefId32( + static void HandleGetModuleNamespacePrefId32( JSThread *thread, const uint8_t *pc, JSTaggedType *sp, JSTaggedValue constpool, JSTaggedValue profileTypeInfo, JSTaggedValue acc, int32_t hotnessCounter); static void HandleStModuleVarPrefId32( @@ -360,7 +360,7 @@ public: static void HandleCopyModulePrefV8( JSThread *thread, const uint8_t *pc, JSTaggedType *sp, JSTaggedValue constpool, JSTaggedValue profileTypeInfo, JSTaggedValue acc, int32_t hotnessCounter); - static void HandleLdModVarByNamePrefId32V8( + static void HandleLdModuleVarPrefId32Imm8( JSThread *thread, const uint8_t *pc, JSTaggedType *sp, JSTaggedValue constpool, JSTaggedValue profileTypeInfo, JSTaggedValue acc, int32_t hotnessCounter); static void HandleCreateRegExpWithLiteralPrefId32Imm8( @@ -623,7 +623,7 @@ static std::array asmDisp InterpreterAssembly::HandleStLexVarDynPrefImm8Imm8V8, InterpreterAssembly::HandleStLexVarDynPrefImm16Imm16V8, InterpreterAssembly::HandleDefineClassWithBufferPrefId16Imm16Imm16V8V8, - InterpreterAssembly::HandleImportModulePrefId32, + InterpreterAssembly::HandleGetModuleNamespacePrefId32, InterpreterAssembly::HandleStModuleVarPrefId32, InterpreterAssembly::HandleTryLdGlobalByNamePrefId32, InterpreterAssembly::HandleTryStGlobalByNamePrefId32, @@ -634,7 +634,7 @@ static std::array asmDisp InterpreterAssembly::HandleStOwnByNamePrefId32V8, InterpreterAssembly::HandleLdSuperByNamePrefId32V8, InterpreterAssembly::HandleStSuperByNamePrefId32V8, - InterpreterAssembly::HandleLdModVarByNamePrefId32V8, + InterpreterAssembly::HandleLdModuleVarPrefId32Imm8, InterpreterAssembly::HandleCreateRegExpWithLiteralPrefId32Imm8, InterpreterAssembly::HandleIsTruePref, InterpreterAssembly::HandleIsFalsePref, diff --git a/ecmascript/interpreter/slow_runtime_stub.cpp b/ecmascript/interpreter/slow_runtime_stub.cpp index d640bfdb..68938951 100644 --- a/ecmascript/interpreter/slow_runtime_stub.cpp +++ b/ecmascript/interpreter/slow_runtime_stub.cpp @@ -17,14 +17,14 @@ #include "ecmascript/base/number_helper.h" #include "ecmascript/builtins/builtins_regexp.h" -#include "ecmascript/class_linker/program_object-inl.h" -#include "ecmascript/ecma_module.h" #include "ecmascript/global_dictionary-inl.h" #include "ecmascript/ic/profile_type_info.h" #include "ecmascript/internal_call_params.h" #include "ecmascript/interpreter/fast_runtime_stub-inl.h" #include "ecmascript/interpreter/frame_handler.h" #include "ecmascript/interpreter/slow_runtime_helper.h" +#include "ecmascript/jspandafile/program_object-inl.h" +#include "ecmascript/jspandafile/scope_info_extractor.h" #include "ecmascript/js_arguments.h" #include "ecmascript/js_array.h" #include "ecmascript/js_array_iterator.h" @@ -39,7 +39,7 @@ #include "ecmascript/js_proxy.h" #include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/js_thread.h" -#include "ecmascript/scope_info_extractor.h" +#include "ecmascript/module/js_module_manager.h" #include "ecmascript/tagged_dictionary.h" #include "ecmascript/runtime_call_id.h" #include "ecmascript/template_string.h" @@ -979,44 +979,26 @@ JSTaggedValue SlowRuntimeStub::CloseIterator(JSThread *thread, JSTaggedValue ite return result.GetTaggedValue(); } -JSTaggedValue SlowRuntimeStub::ImportModule([[maybe_unused]] JSThread *thread, - [[maybe_unused]] JSTaggedValue moduleName) -{ - INTERPRETER_TRACE(thread, ImportModule); - [[maybe_unused]] EcmaHandleScope scope(thread); - JSHandle name(thread, moduleName); - JSHandle module = thread->GetEcmaVM()->GetModuleByName(name); - return module.GetTaggedValue(); // return moduleRef -} - -void SlowRuntimeStub::StModuleVar([[maybe_unused]] JSThread *thread, [[maybe_unused]] JSTaggedValue exportName, - [[maybe_unused]] JSTaggedValue exportObj) +void SlowRuntimeStub::StModuleVar([[maybe_unused]] JSThread *thread, [[maybe_unused]] JSTaggedValue key, + [[maybe_unused]] JSTaggedValue value) { INTERPRETER_TRACE(thread, StModuleVar); [[maybe_unused]] EcmaHandleScope scope(thread); - JSHandle name(thread, exportName); - JSHandle value(thread, exportObj); - thread->GetEcmaVM()->GetModuleManager()->AddModuleItem(thread, name, value); + thread->GetEcmaVM()->GetModuleManager()->StoreModuleValue(key, value); } -void SlowRuntimeStub::CopyModule(JSThread *thread, JSTaggedValue srcModule) +JSTaggedValue SlowRuntimeStub::LdModuleVar([[maybe_unused]] JSThread *thread, + [[maybe_unused]] JSTaggedValue key, + [[maybe_unused]] bool inner) { - INTERPRETER_TRACE(thread, CopyModule); + INTERPRETER_TRACE(thread, LdModuleVar); [[maybe_unused]] EcmaHandleScope scope(thread); - JSHandle srcModuleObj(thread, srcModule); - thread->GetEcmaVM()->GetModuleManager()->CopyModule(thread, srcModuleObj); -} + if (inner) { + JSTaggedValue moduleValue = thread->GetEcmaVM()->GetModuleManager()->GetModuleValueInner(key); + return moduleValue; + } -JSTaggedValue SlowRuntimeStub::LdModvarByName([[maybe_unused]] JSThread *thread, - [[maybe_unused]] JSTaggedValue moduleObj, - [[maybe_unused]] JSTaggedValue itemName) -{ - INTERPRETER_TRACE(thread, LdModvarByName); - [[maybe_unused]] EcmaHandleScope scope(thread); - JSHandle module(thread, moduleObj); - JSHandle item(thread, itemName); - JSHandle moduleVar = thread->GetEcmaVM()->GetModuleManager()->GetModuleItem(thread, module, item); - return moduleVar.GetTaggedValue(); + return thread->GetEcmaVM()->GetModuleManager()->GetModuleValueOutter(key); } JSTaggedValue SlowRuntimeStub::CreateRegExpWithLiteral(JSThread *thread, JSTaggedValue pattern, uint8_t flags) @@ -1809,6 +1791,10 @@ JSTaggedValue SlowRuntimeStub::ResolveClass(JSThread *thread, JSTaggedValue ctor JSHandle lexicalEnv(thread, lexenv); JSHandle constpoolHandle(thread, constpool); + InterpretedFrameHandler frameHandler(thread); + JSTaggedValue currentFunc = frameHandler.GetFunction(); + JSHandle ecmaModule(thread, JSFunction::Cast(currentFunc.GetTaggedObject())->GetModule()); + SetClassInheritanceRelationship(thread, ctor, base); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -1820,6 +1806,7 @@ JSTaggedValue SlowRuntimeStub::ResolveClass(JSThread *thread, JSTaggedValue ctor if (LIKELY(value.IsJSFunction())) { JSFunction::Cast(value.GetTaggedObject())->SetLexicalEnv(thread, lexicalEnv.GetTaggedValue()); JSFunction::Cast(value.GetTaggedObject())->SetConstantPool(thread, constpoolHandle.GetTaggedValue()); + JSFunction::Cast(value.GetTaggedObject())->SetModule(thread, ecmaModule); } } @@ -1939,4 +1926,9 @@ JSTaggedValue SlowRuntimeStub::SetClassConstructorLength(JSThread *thread, JSTag } return JSTaggedValue::Undefined(); } + +JSTaggedValue SlowRuntimeStub::GetModuleNamespace(JSThread *thread, JSTaggedValue localName) +{ + return thread->GetEcmaVM()->GetModuleManager()->GetModuleNamespace(localName); +} } // namespace panda::ecmascript diff --git a/ecmascript/interpreter/slow_runtime_stub.h b/ecmascript/interpreter/slow_runtime_stub.h index 03bf31a5..68dc3f2d 100644 --- a/ecmascript/interpreter/slow_runtime_stub.h +++ b/ecmascript/interpreter/slow_runtime_stub.h @@ -16,7 +16,7 @@ #ifndef ECMASCRIPT_INTERPRETER_SLOW_RUNTIME_STUB_H #define ECMASCRIPT_INTERPRETER_SLOW_RUNTIME_STUB_H -#include "ecmascript/class_linker/program_object.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/js_tagged_value.h" #include "ecmascript/js_thread.h" @@ -104,10 +104,8 @@ public: static JSTaggedValue GetIterator(JSThread *thread, JSTaggedValue obj); static JSTaggedValue IterNext(JSThread *thread, JSTaggedValue iter); static JSTaggedValue CloseIterator(JSThread *thread, JSTaggedValue iter); - static JSTaggedValue ImportModule(JSThread *thread, JSTaggedValue moduleName); - static void StModuleVar(JSThread *thread, JSTaggedValue exportName, JSTaggedValue exportObj); - static void CopyModule(JSThread *thread, JSTaggedValue srcModule); - static JSTaggedValue LdModvarByName(JSThread *thread, JSTaggedValue moduleObj, JSTaggedValue itemName); + static void StModuleVar(JSThread *thread, JSTaggedValue key, JSTaggedValue value); + static JSTaggedValue LdModuleVar(JSThread *thread, JSTaggedValue key, bool inner); static JSTaggedValue CreateRegExpWithLiteral(JSThread *thread, JSTaggedValue pattern, uint8_t flags); static JSTaggedValue GetIteratorNext(JSThread *thread, JSTaggedValue obj, JSTaggedValue method); @@ -153,6 +151,7 @@ public: static JSTaggedValue CloneClassFromTemplate(JSThread *thread, JSTaggedValue ctor, JSTaggedValue base, JSTaggedValue lexenv, ConstantPool *constpool); static JSTaggedValue SetClassConstructorLength(JSThread *thread, JSTaggedValue ctor, JSTaggedValue length); + static JSTaggedValue GetModuleNamespace(JSThread *thread, JSTaggedValue localName); /* -------------- Common API End, Don't change those interface!!! ----------------- */ private: diff --git a/ecmascript/interpreter/templates/debugger_instruction_dispatch.inl b/ecmascript/interpreter/templates/debugger_instruction_dispatch.inl index 118ea7cb..3a61e01d 100644 --- a/ecmascript/interpreter/templates/debugger_instruction_dispatch.inl +++ b/ecmascript/interpreter/templates/debugger_instruction_dispatch.inl @@ -126,7 +126,7 @@ &&DEBUG_HANDLE_STLEXVARDYN_PREF_IMM8_IMM8_V8, &&DEBUG_HANDLE_STLEXVARDYN_PREF_IMM16_IMM16_V8, &&DEBUG_HANDLE_DEFINECLASSWITHBUFFER_PREF_ID16_IMM16_IMM16_V8_V8, - &&DEBUG_HANDLE_IMPORTMODULE_PREF_ID32, + &&DEBUG_HANDLE_GETMODULENAMESPACE_PREF_ID32, &&DEBUG_HANDLE_STMODULEVAR_PREF_ID32, &&DEBUG_HANDLE_TRYLDGLOBALBYNAME_PREF_ID32, &&DEBUG_HANDLE_TRYSTGLOBALBYNAME_PREF_ID32, @@ -137,7 +137,7 @@ &&DEBUG_HANDLE_STOWNBYNAME_PREF_ID32_V8, &&DEBUG_HANDLE_LDSUPERBYNAME_PREF_ID32_V8, &&DEBUG_HANDLE_STSUPERBYNAME_PREF_ID32_V8, - &&DEBUG_HANDLE_LDMODVARBYNAME_PREF_ID32_V8, + &&DEBUG_HANDLE_LDMODULEVAR_PREF_ID32_IMM8, &&DEBUG_HANDLE_CREATEREGEXPWITHLITERAL_PREF_ID32_IMM8, &&DEBUG_HANDLE_ISTRUE_PREF, &&DEBUG_HANDLE_ISFALSE_PREF, diff --git a/ecmascript/interpreter/templates/debugger_instruction_handler.inl b/ecmascript/interpreter/templates/debugger_instruction_handler.inl index cdc69b6d..8c01bba1 100644 --- a/ecmascript/interpreter/templates/debugger_instruction_handler.inl +++ b/ecmascript/interpreter/templates/debugger_instruction_handler.inl @@ -583,10 +583,10 @@ NOTIFY_DEBUGGER_EVENT(); REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::DEFINECLASSWITHBUFFER_PREF_ID16_IMM16_IMM16_V8_V8); } - HANDLE_OPCODE(DEBUG_HANDLE_IMPORTMODULE_PREF_ID32) + HANDLE_OPCODE(DEBUG_HANDLE_GETMODULENAMESPACE_PREF_ID32) { NOTIFY_DEBUGGER_EVENT(); - REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::IMPORTMODULE_PREF_ID32); + REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::GETMODULENAMESPACE_PREF_ID32); } HANDLE_OPCODE(DEBUG_HANDLE_STMODULEVAR_PREF_ID32) { @@ -638,10 +638,10 @@ NOTIFY_DEBUGGER_EVENT(); REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::STSUPERBYNAME_PREF_ID32_V8); } - HANDLE_OPCODE(DEBUG_HANDLE_LDMODVARBYNAME_PREF_ID32_V8) + HANDLE_OPCODE(DEBUG_HANDLE_LDMODULEVAR_PREF_ID32_IMM8) { NOTIFY_DEBUGGER_EVENT(); - REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::LDMODVARBYNAME_PREF_ID32_V8); + REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::LDMODULEVAR_PREF_ID32_IMM8); } HANDLE_OPCODE(DEBUG_HANDLE_CREATEREGEXPWITHLITERAL_PREF_ID32_IMM8) { diff --git a/ecmascript/interpreter/templates/instruction_dispatch.inl b/ecmascript/interpreter/templates/instruction_dispatch.inl index acf8a829..d03e9915 100644 --- a/ecmascript/interpreter/templates/instruction_dispatch.inl +++ b/ecmascript/interpreter/templates/instruction_dispatch.inl @@ -126,7 +126,7 @@ &&HANDLE_STLEXVARDYN_PREF_IMM8_IMM8_V8, &&HANDLE_STLEXVARDYN_PREF_IMM16_IMM16_V8, &&HANDLE_DEFINECLASSWITHBUFFER_PREF_ID16_IMM16_IMM16_V8_V8, - &&HANDLE_IMPORTMODULE_PREF_ID32, + &&HANDLE_GETMODULENAMESPACE_PREF_ID32, &&HANDLE_STMODULEVAR_PREF_ID32, &&HANDLE_TRYLDGLOBALBYNAME_PREF_ID32, &&HANDLE_TRYSTGLOBALBYNAME_PREF_ID32, @@ -137,7 +137,7 @@ &&HANDLE_STOWNBYNAME_PREF_ID32_V8, &&HANDLE_LDSUPERBYNAME_PREF_ID32_V8, &&HANDLE_STSUPERBYNAME_PREF_ID32_V8, - &&HANDLE_LDMODVARBYNAME_PREF_ID32_V8, + &&HANDLE_LDMODULEVAR_PREF_ID32_IMM8, &&HANDLE_CREATEREGEXPWITHLITERAL_PREF_ID32_IMM8, &&HANDLE_ISTRUE_PREF, &&HANDLE_ISFALSE_PREF, diff --git a/ecmascript/js_api_arraylist.cpp b/ecmascript/js_api_arraylist.cpp index f87aa11d..8362ee64 100644 --- a/ecmascript/js_api_arraylist.cpp +++ b/ecmascript/js_api_arraylist.cpp @@ -39,7 +39,7 @@ void JSAPIArrayList::Insert(JSThread *thread, const JSHandle &ar { int length = static_cast(arrayList->GetLength().GetArrayLength()); if (index < 0 || index >= length) { - THROW_RANGE_ERROR(thread, "ArrayList: set out-of-bounds"); + THROW_ERROR(thread, ErrorType::RANGE_ERROR, "ArrayList: set out-of-bounds"); } JSHandle elements = GrowCapacity(thread, arrayList, length + 1); diff --git a/ecmascript/js_array.cpp b/ecmascript/js_array.cpp index 977e8da0..60e3402c 100644 --- a/ecmascript/js_array.cpp +++ b/ecmascript/js_array.cpp @@ -15,6 +15,7 @@ #include "ecmascript/js_array.h" #include "ecmascript/accessor_data.h" +#include "ecmascript/base/array_helper.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" #include "ecmascript/internal_call_params.h" @@ -376,4 +377,93 @@ bool JSArray::FastSetPropertyByValue(JSThread *thread, const JSHandle &obj, const JSHandle &fn) +{ + if (!fn->IsUndefined() && !fn->IsCallable()) { + THROW_TYPE_ERROR(thread, "Callable is false"); + } + + // 2. Let len be ToLength(Get(obj, "length")). + double len = base::ArrayHelper::GetArrayLength(thread, JSHandle(obj)); + // 3. ReturnIfAbrupt(len). + RETURN_IF_ABRUPT_COMPLETION(thread); + + JSMutableHandle presentValue(thread, JSTaggedValue::Undefined()); + JSMutableHandle middleValue(thread, JSTaggedValue::Undefined()); + JSMutableHandle previousValue(thread, JSTaggedValue::Undefined()); + for (int i = 1; i < len; i++) { + int beginIndex = 0; + int endIndex = i; + presentValue.Update(FastRuntimeStub::FastGetPropertyByIndex(thread, obj.GetTaggedValue(), i)); + RETURN_IF_ABRUPT_COMPLETION(thread); + while (beginIndex < endIndex) { + int middleIndex = (beginIndex + endIndex) / 2; // 2 : half + middleValue.Update( + FastRuntimeStub::FastGetPropertyByIndex(thread, obj.GetTaggedValue(), middleIndex)); + RETURN_IF_ABRUPT_COMPLETION(thread); + int32_t compareResult = base::ArrayHelper::SortCompare(thread, fn, middleValue, presentValue); + RETURN_IF_ABRUPT_COMPLETION(thread); + if (compareResult > 0) { + endIndex = middleIndex; + } else { + beginIndex = middleIndex + 1; + } + } + + if (endIndex >= 0 && endIndex < i) { + for (int j = i; j > endIndex; j--) { + previousValue.Update( + FastRuntimeStub::FastGetPropertyByIndex(thread, obj.GetTaggedValue(), j - 1)); + RETURN_IF_ABRUPT_COMPLETION(thread); + FastRuntimeStub::FastSetPropertyByIndex(thread, obj.GetTaggedValue(), j, + previousValue.GetTaggedValue()); + RETURN_IF_ABRUPT_COMPLETION(thread); + } + FastRuntimeStub::FastSetPropertyByIndex(thread, obj.GetTaggedValue(), endIndex, + presentValue.GetTaggedValue()); + RETURN_IF_ABRUPT_COMPLETION(thread); + } + } +} + +bool JSArray::IncludeInSortedValue(JSThread *thread, const JSHandle &obj, + const JSHandle &value) +{ + ASSERT(obj->IsJSArray()); + JSHandle arrayObj = JSHandle::Cast(obj); + int32_t length = arrayObj->GetArrayLength(); + if (length == 0) { + return false; + } + int32_t left = 0; + int32_t right = length - 1; + while (left <= right) { + int32_t middle = (left + right) / 2; + JSHandle vv = JSArray::FastGetPropertyByValue(thread, obj, middle); + ComparisonResult res = JSTaggedValue::Compare(thread, vv, value); + if (res == ComparisonResult::EQUAL) { + return true; + } else if (res == ComparisonResult::LESS) { + left = middle + 1; + } else { + right = middle - 1; + } + } + return false; +} + +JSHandle JSArray::ToTaggedArray(JSThread *thread, const JSHandle &obj) +{ + ASSERT(obj->IsJSArray()); + JSHandle arrayObj = JSHandle::Cast(obj); + int32_t length = arrayObj->GetArrayLength(); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle taggedArray = factory->NewTaggedArray(length); + for (int32_t idx = 0; idx < length; idx++) { + JSHandle vv = JSArray::FastGetPropertyByValue(thread, obj, idx); + taggedArray->Set(thread, idx, vv); + } + return taggedArray; +} } // namespace panda::ecmascript diff --git a/ecmascript/js_array.h b/ecmascript/js_array.h index 16e60f26..723b393d 100644 --- a/ecmascript/js_array.h +++ b/ecmascript/js_array.h @@ -87,6 +87,11 @@ public: static bool FastSetPropertyByValue(JSThread *thread, const JSHandle &obj, const JSHandle &key, const JSHandle &value); + static void Sort(JSThread *thread, const JSHandle &obj, const JSHandle &fn); + static bool IncludeInSortedValue(JSThread *thread, const JSHandle &obj, + const JSHandle &value); + static JSHandle ToTaggedArray(JSThread *thread, const JSHandle &obj); + private: static void SetCapacity(JSThread *thread, const JSHandle &array, uint32_t oldLen, uint32_t newLen); }; diff --git a/ecmascript/js_function.cpp b/ecmascript/js_function.cpp index 3273746e..b19e5a2c 100644 --- a/ecmascript/js_function.cpp +++ b/ecmascript/js_function.cpp @@ -16,12 +16,12 @@ #include "js_function.h" #include "ecmascript/base/error_type.h" -#include "ecmascript/class_info_extractor.h" #include "ecmascript/ecma_macros.h" #include "ecmascript/ecma_runtime_call_info.h" #include "ecmascript/global_env.h" #include "ecmascript/internal_call_params.h" #include "ecmascript/interpreter/interpreter-inl.h" +#include "ecmascript/jspandafile/class_info_extractor.h" #include "ecmascript/js_handle.h" #include "ecmascript/js_promise.h" #include "ecmascript/js_proxy.h" @@ -46,6 +46,7 @@ void JSFunction::InitializeJSFunction(JSThread *thread, const JSHandleSetProtoOrDynClass(thread, JSTaggedValue::Hole(), SKIP_BARRIER); func->SetHomeObject(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); func->SetLexicalEnv(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); + func->SetModule(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); func->SetConstantPool(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); func->SetProfileTypeInfo(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); func->SetFunctionExtraInfo(thread, JSTaggedValue::Undefined()); diff --git a/ecmascript/js_function.h b/ecmascript/js_function.h index 0ce1dc95..ad92900f 100644 --- a/ecmascript/js_function.h +++ b/ecmascript/js_function.h @@ -225,7 +225,8 @@ public: ACCESSORS(HomeObject, HOME_OBJECT_OFFSET, FUNCTION_EXTRA_INFO_OFFSET) ACCESSORS(FunctionExtraInfo, FUNCTION_EXTRA_INFO_OFFSET, CONSTANT_POOL_OFFSET) ACCESSORS(ConstantPool, CONSTANT_POOL_OFFSET, PROFILE_TYPE_INFO_OFFSET) - ACCESSORS(ProfileTypeInfo, PROFILE_TYPE_INFO_OFFSET, BIT_FIELD_OFFSET) + ACCESSORS(ProfileTypeInfo, PROFILE_TYPE_INFO_OFFSET, ECMA_MODULE_OFFSET) + ACCESSORS(Module, ECMA_MODULE_OFFSET, BIT_FIELD_OFFSET) ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET) DEFINE_ALIGN_SIZE(LAST_OFFSET); diff --git a/ecmascript/js_hclass.h b/ecmascript/js_hclass.h index d719b4c5..a8bbc5f0 100644 --- a/ecmascript/js_hclass.h +++ b/ecmascript/js_hclass.h @@ -132,6 +132,7 @@ class ProtoChangeDetails; JS_FLOAT32_ARRAY, /* ////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_FLOAT64_ARRAY, /* JS_TYPED_ARRAY_END ///////////////////////////////////////////////////////////// */ \ JS_PRIMITIVE_REF, /* number\boolean\string. SPECIAL indexed objects end, DON'T CHANGE HERE ////////-PADDING */ \ + JS_MODULE_NAMESPACE, /* ///////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_GLOBAL_OBJECT, /* JS_OBJECT_END/////////////////////////////////////////////////////////////////-PADDING */ \ JS_PROXY, /* ECMA_OBJECT_END ////////////////////////////////////////////////////////////////////////////// */ \ \ @@ -163,9 +164,13 @@ class ProtoChangeDetails; PROMISE_ITERATOR_RECORD, /* ////////////////////////////////////////////////////////////////////-PADDING */ \ MICRO_JOB_QUEUE, /* /////////////////////////////////////////////////////////////////////////////-PADDING */ \ PENDING_JOB, /* /////////////////////////////////////////////////////////////////////////////-PADDING */ \ + MODULE_RECORD, /* //////////////////////////////////////////////////////////////////////////////-PADDING */ \ + SOURCE_TEXT_MODULE_RECORD, /* //////////////////////////////////////////////////////////////////-PADDING */ \ + IMPORTENTRY_RECORD, /* /////////////////////////////////////////////////////////////////////////-PADDING */ \ + EXPORTENTRY_RECORD, /* /////////////////////////////////////////////////////////////////////////-PADDING */ \ + RESOLVEDBINDING_RECORD, /* /////////////////////////////////////////////////////////////////////-PADDING */ \ COMPLETION_RECORD, /* JS_RECORD_END /////////////////////////////////////////////////////////////////////// */ \ MACHINE_CODE_OBJECT, \ - ECMA_MODULE, /* ///////////////////////////////////////////////////////////////////////////////////-PADDING */ \ CLASS_INFO_EXTRACTOR, /* //////////////////////////////////////////////////////////////////////////-PADDING */ \ TS_ARRAY_TYPE, /* ////////////////////////////////////////////////////////////////////////////////-PADDING */ \ TS_UNION_TYPE, /* ////////////////////////////////////////////////////////////////////////////////-PADDING */ \ @@ -196,7 +201,11 @@ class ProtoChangeDetails; JS_RECORD_END = COMPLETION_RECORD, /* ///////////////////////////////////////////////////////-PADDING */ \ \ JS_TYPED_ARRAY_BEGIN = JS_TYPED_ARRAY, /* /////////////////////////////////////////////////////////-PADDING */ \ - JS_TYPED_ARRAY_END = JS_FLOAT64_ARRAY /* /////////////////////////////////////////////////////////-PADDING */ + JS_TYPED_ARRAY_END = JS_FLOAT64_ARRAY, /* /////////////////////////////////////////////////////////-PADDING */ \ + \ + MODULE_RECORD_BEGIN = MODULE_RECORD, /* ///////////////////////////////////////////////////////////-PADDING */ \ + MODULE_RECORD_END = SOURCE_TEXT_MODULE_RECORD /* //////////////////////////////////////////////////-PADDING */ + enum class JSType : uint8_t { JSTYPE_DECL, @@ -732,11 +741,6 @@ public: return GetObjectType() == JSType::PROGRAM; } - inline bool IsEcmaModule() const - { - return GetObjectType() == JSType::ECMA_MODULE; - } - inline bool IsClassInfoExtractor() const { return GetObjectType() == JSType::CLASS_INFO_EXTRACTOR; @@ -951,6 +955,37 @@ public: return GetObjectType() == JSType::TS_ARRAY_TYPE; } + inline bool IsModuleRecord() const + { + JSType jsType = GetObjectType(); + return jsType >= JSType::MODULE_RECORD_BEGIN && jsType <= JSType::MODULE_RECORD_END; + } + + inline bool IsSourceTextModule() const + { + return GetObjectType() == JSType::SOURCE_TEXT_MODULE_RECORD; + } + + inline bool IsImportEntry() const + { + return GetObjectType() == JSType::IMPORTENTRY_RECORD; + } + + inline bool IsExportEntry() const + { + return GetObjectType() == JSType::EXPORTENTRY_RECORD; + } + + inline bool IsResolvedBinding() const + { + return GetObjectType() == JSType::RESOLVEDBINDING_RECORD; + } + + inline bool IsModuleNamespace() const + { + return GetObjectType() == JSType::JS_MODULE_NAMESPACE; + } + inline void SetElementRepresentation(Representation representation) { uint32_t bits = GetBitField(); diff --git a/ecmascript/js_number_format.cpp b/ecmascript/js_number_format.cpp index b89a2567..cf05e6da 100644 --- a/ecmascript/js_number_format.cpp +++ b/ecmascript/js_number_format.cpp @@ -469,11 +469,11 @@ void JSNumberFormat::InitializeNumberFormat(JSThread *thread, const JSHandleIsUndefined()) { JSHandle numberingSystemEcmaString = JSHandle::Cast(numberingSystemTaggedValue); if (numberingSystemEcmaString->IsUtf16()) { - THROW_RANGE_ERROR(thread, "invalid numberingSystem"); + THROW_ERROR(thread, ErrorType::RANGE_ERROR, "invalid numberingSystem"); } numberingSystemStr = JSLocale::ConvertToStdString(numberingSystemEcmaString); if (!JSLocale::IsNormativeNumberingSystem(numberingSystemStr)) { - THROW_RANGE_ERROR(thread, "invalid numberingSystem"); + THROW_ERROR(thread, ErrorType::RANGE_ERROR, "invalid numberingSystem"); } } diff --git a/ecmascript/js_object.cpp b/ecmascript/js_object.cpp index e7841db3..63b37fda 100644 --- a/ecmascript/js_object.cpp +++ b/ecmascript/js_object.cpp @@ -1279,7 +1279,7 @@ JSHandle JSObject::EnumerableOwnNames(JSThread *thread, const JSHan JSHandle tagObj(obj); uint32_t copyLength = 0; // fast mode - if (tagObj->IsJSObject() && !tagObj->IsTypedArray()) { + if (tagObj->IsJSObject() && !tagObj->IsTypedArray() && !tagObj->IsModuleNamespace()) { uint32_t numOfKeys = obj->GetNumberOfKeys(); uint32_t numOfElements = obj->GetNumberOfElements(); JSHandle elementArray; diff --git a/ecmascript/js_relative_time_format.cpp b/ecmascript/js_relative_time_format.cpp index d8d3c9fc..1b15d51c 100644 --- a/ecmascript/js_relative_time_format.cpp +++ b/ecmascript/js_relative_time_format.cpp @@ -470,7 +470,7 @@ void JSRelativeTimeFormat::ResolvedOptions(JSThread *thread, const JSHandleGetIcuRTFFormatter() != nullptr) { [[maybe_unused]] icu::RelativeDateTimeFormatter *formatter = relativeTimeFormat->GetIcuRTFFormatter(); } else { - THROW_RANGE_ERROR(thread, "rtf is not initialized"); + THROW_ERROR(thread, ErrorType::RANGE_ERROR, "rtf is not initialized"); } auto globalConst = thread->GlobalConstants(); @@ -503,7 +503,7 @@ void JSRelativeTimeFormat::ResolvedOptions(JSThread *thread, const JSHandleGetHandledAutoString(); } else { - THROW_RANGE_ERROR(thread, "numeric is exception"); + THROW_ERROR(thread, ErrorType::RANGE_ERROR, "numeric is exception"); } PropertyDescriptor numericDesc(thread, numericValue, true, true, true); JSObject::DefineOwnProperty(thread, options, property, numericDesc); diff --git a/ecmascript/js_tagged_value-inl.h b/ecmascript/js_tagged_value-inl.h index 3ddb0477..a8c7793a 100644 --- a/ecmascript/js_tagged_value-inl.h +++ b/ecmascript/js_tagged_value-inl.h @@ -33,6 +33,7 @@ #include "ecmascript/js_thread.h" #include "ecmascript/mem/c_containers.h" #include "ecmascript/mem/tagged_object-inl.h" +#include "ecmascript/module/js_module_namespace.h" #include "ecmascript/object_factory.h" namespace panda::ecmascript { @@ -237,6 +238,9 @@ inline bool JSTaggedValue::IsExtensible(JSThread *thread) const if (UNLIKELY(IsJSProxy())) { return JSProxy::IsExtensible(thread, JSHandle(thread, *this)); } + if (UNLIKELY(IsModuleNamespace())) { + return ModuleNamespace::IsExtensible(); + } return IsHeapObject() && GetTaggedObject()->GetClass()->IsExtensible(); } @@ -920,6 +924,36 @@ inline bool JSTaggedValue::IsTSArrayType() const return IsHeapObject() && GetTaggedObject()->GetClass()->IsTSArrayType(); } +inline bool JSTaggedValue::IsModuleRecord() const +{ + return IsHeapObject() && GetTaggedObject()->GetClass()->IsModuleRecord(); +} + +inline bool JSTaggedValue::IsSourceTextModule() const +{ + return IsHeapObject() && GetTaggedObject()->GetClass()->IsSourceTextModule(); +} + +inline bool JSTaggedValue::IsImportEntry() const +{ + return IsHeapObject() && GetTaggedObject()->GetClass()->IsImportEntry(); +} + +inline bool JSTaggedValue::IsExportEntry() const +{ + return IsHeapObject() && GetTaggedObject()->GetClass()->IsExportEntry(); +} + +inline bool JSTaggedValue::IsResolvedBinding() const +{ + return IsHeapObject() && GetTaggedObject()->GetClass()->IsResolvedBinding(); +} + +inline bool JSTaggedValue::IsModuleNamespace() const +{ + return IsHeapObject() && GetTaggedObject()->GetClass()->IsModuleNamespace(); +} + inline double JSTaggedValue::ExtractNumber() const { ASSERT(IsNumber()); diff --git a/ecmascript/js_tagged_value.cpp b/ecmascript/js_tagged_value.cpp index 3520e6b1..a8ed424a 100644 --- a/ecmascript/js_tagged_value.cpp +++ b/ecmascript/js_tagged_value.cpp @@ -27,6 +27,7 @@ #include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/js_thread.h" #include "ecmascript/js_typed_array.h" +#include "ecmascript/module/js_module_namespace.h" #include "ecmascript/tagged_array.h" #include "js_object-inl.h" #include "object_factory.h" @@ -426,6 +427,9 @@ OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandleIsTypedArray()) { return JSTypedArray::GetProperty(thread, obj, JSTypedArray::ToPropKey(thread, key)); } + if (obj->IsModuleNamespace()) { + return ModuleNamespace::GetProperty(thread, obj, key); + } return JSObject::GetProperty(thread, obj, key); } @@ -484,6 +488,8 @@ bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle success = JSProxy::SetProperty(thread, JSHandle(obj), key, value, mayThrow); } else if (obj->IsTypedArray()) { success = JSTypedArray::SetProperty(thread, obj, JSTypedArray::ToPropKey(thread, key), value, mayThrow); + } else if (obj->IsModuleNamespace()) { + success = ModuleNamespace::SetProperty(thread, mayThrow); } else { success = JSObject::SetProperty(thread, obj, key, value, mayThrow); } @@ -510,6 +516,8 @@ bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle JSHandle keyHandle(thread, JSTaggedValue(key)); success = JSTypedArray::SetProperty( thread, obj, JSHandle(JSTaggedValue::ToString(thread, keyHandle)), value, mayThrow); + } else if (obj->IsModuleNamespace()) { + success = ModuleNamespace::SetProperty(thread, mayThrow); } else { success = JSObject::SetProperty(thread, obj, key, value, mayThrow); } @@ -537,6 +545,8 @@ bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle } else if (obj->IsTypedArray()) { success = JSTypedArray::SetProperty(thread, obj, JSTypedArray::ToPropKey(thread, key), value, receiver, mayThrow); + } else if (obj->IsModuleNamespace()) { + success = ModuleNamespace::SetProperty(thread, mayThrow); } else { success = JSObject::SetProperty(thread, obj, key, value, receiver, mayThrow); } @@ -554,6 +564,10 @@ bool JSTaggedValue::DeleteProperty(JSThread *thread, const JSHandle(obj), key); } + if (obj->IsModuleNamespace()) { + return ModuleNamespace::DeleteProperty(thread, obj, key); + } + if (obj->IsSpecialContainer()) { THROW_TYPE_ERROR_AND_RETURN(thread, "Can not delete property in Container Object", false); } @@ -615,6 +629,10 @@ bool JSTaggedValue::DefineOwnProperty(JSThread *thread, const JSHandleIsModuleNamespace()) { + return ModuleNamespace::DefineOwnProperty(thread, obj, key, desc); + } + if (obj->IsSpecialContainer()) { THROW_TYPE_ERROR_AND_RETURN(thread, "Can not defineProperty on Container Object", false); } @@ -631,6 +649,9 @@ bool JSTaggedValue::GetOwnProperty(JSThread *thread, const JSHandleIsTypedArray()) { return JSTypedArray::GetOwnProperty(thread, obj, JSTypedArray::ToPropKey(thread, key), desc); } + if (obj->IsModuleNamespace()) { + return ModuleNamespace::GetOwnProperty(thread, obj, key, desc); + } if (obj->IsSpecialContainer()) { return GetContainerProperty(thread, obj, key, desc); } @@ -643,6 +664,9 @@ bool JSTaggedValue::SetPrototype(JSThread *thread, const JSHandle if (obj->IsJSProxy()) { return JSProxy::SetPrototype(thread, JSHandle(obj), proto); } + if (obj->IsModuleNamespace()) { + return ModuleNamespace::SetPrototype(thread, obj, proto); + } if (obj->IsSpecialContainer()) { THROW_TYPE_ERROR_AND_RETURN(thread, "Can not set Prototype on Container Object", false); } @@ -655,6 +679,9 @@ bool JSTaggedValue::PreventExtensions(JSThread *thread, const JSHandleIsJSProxy()) { return JSProxy::PreventExtensions(thread, JSHandle(obj)); } + if (obj->IsModuleNamespace()) { + return ModuleNamespace::PreventExtensions(); + } return JSObject::PreventExtensions(thread, JSHandle(obj)); } @@ -669,6 +696,9 @@ JSHandle JSTaggedValue::GetOwnPropertyKeys(JSThread *thread, const if (obj->IsSpecialContainer()) { return GetOwnContainerPropertyKeys(thread, obj); } + if (obj->IsModuleNamespace()) { + return ModuleNamespace::OwnPropertyKeys(thread, obj); + } return JSObject::GetOwnPropertyKeys(thread, JSHandle(obj)); } @@ -682,6 +712,9 @@ bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle if (obj->IsTypedArray()) { return JSTypedArray::HasProperty(thread, obj, JSTypedArray::ToPropKey(thread, key)); } + if (obj->IsModuleNamespace()) { + return ModuleNamespace::HasProperty(thread, obj, key); + } if (obj->IsSpecialContainer()) { return HasContainerProperty(thread, obj, key); } diff --git a/ecmascript/js_tagged_value.h b/ecmascript/js_tagged_value.h index 5b3cf4df..6d19540e 100644 --- a/ecmascript/js_tagged_value.h +++ b/ecmascript/js_tagged_value.h @@ -346,6 +346,12 @@ public: bool IsTSFunctionType() const; bool IsTSArrayType() const; + bool IsModuleRecord() const; + bool IsSourceTextModule() const; + bool IsImportEntry() const; + bool IsExportEntry() const; + bool IsResolvedBinding() const; + bool IsModuleNamespace() const; static bool IsSameTypeOrHClass(JSTaggedValue x, JSTaggedValue y); static ComparisonResult Compare(JSThread *thread, const JSHandle &x, diff --git a/ecmascript/jspandafile/accessor/module_data_accessor-inl.h b/ecmascript/jspandafile/accessor/module_data_accessor-inl.h new file mode 100644 index 00000000..cd640658 --- /dev/null +++ b/ecmascript/jspandafile/accessor/module_data_accessor-inl.h @@ -0,0 +1,69 @@ +/* + * 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_JSPANDAFILE_ACCESSOR_MODULE_DATA_ACCESSOR_INL_H +#define ECMASCRIPT_JSPANDAFILE_ACCESSOR_MODULE_DATA_ACCESSOR_INL_H + +#include "ecmascript/jspandafile/accessor/module_data_accessor.h" + +#include +#include "libpandafile/file_items.h" +#include "libpandafile/helpers.h" +#include "libpandabase/utils/utf.h" + +namespace panda::ecmascript::jspandafile { +template +inline void ModuleDataAccessor::EnumerateModuleRecord(const Callback &cb) +{ + auto sp = entryDataSp_; + + auto regularImportNum = panda_file::helpers::Read(&sp); + for (size_t idx = 0; idx < regularImportNum; idx++) { + auto localNameOffset = static_cast(panda_file::helpers::Read(&sp)); + auto importNameOffset = static_cast(panda_file::helpers::Read(&sp)); + auto moduleRequestIdx = static_cast(panda_file::helpers::Read(&sp)); + cb(ModuleTag::REGULAR_IMPORT, 0, moduleRequestIdx, importNameOffset, localNameOffset); + } + + auto namespaceImportNum = panda_file::helpers::Read(&sp); + for (size_t idx = 0; idx < namespaceImportNum; idx++) { + auto localNameOffset = static_cast(panda_file::helpers::Read(&sp)); + auto moduleRequestIdx = static_cast(panda_file::helpers::Read(&sp)); + cb(ModuleTag::NAMESPACE_IMPORT, 0, moduleRequestIdx, 0, localNameOffset); + } + + auto localExportNum = panda_file::helpers::Read(&sp); + for (size_t idx = 0; idx < localExportNum; idx++) { + auto localNameOffset = static_cast(panda_file::helpers::Read(&sp)); + auto exportNameOffset = static_cast(panda_file::helpers::Read(&sp)); + cb(ModuleTag::LOCAL_EXPORT, exportNameOffset, 0, 0, localNameOffset); + } + + auto indirectExportNum = panda_file::helpers::Read(&sp); + for (size_t idx = 0; idx < indirectExportNum; idx++) { + auto exportNameOffset = static_cast(panda_file::helpers::Read(&sp)); + auto importNameOffset = static_cast(panda_file::helpers::Read(&sp)); + auto moduleRequestIdx = static_cast(panda_file::helpers::Read(&sp)); + cb(ModuleTag::INDIRECT_EXPORT, exportNameOffset, moduleRequestIdx, importNameOffset, 0); + } + + auto starExportNum = panda_file::helpers::Read(&sp); + for (size_t idx = 0; idx < starExportNum; idx++) { + auto moduleRequestIdx = static_cast(panda_file::helpers::Read(&sp)); + cb(ModuleTag::STAR_EXPORT, 0, moduleRequestIdx, 0, 0); + } +} +} // namespace panda::ecmascript::jspandafile +#endif // ECMASCRIPT_JSPANDAFILE_ACCESSOR_MODULE_DATA_ACCESSOR_INL_H diff --git a/ecmascript/jspandafile/accessor/module_data_accessor.cpp b/ecmascript/jspandafile/accessor/module_data_accessor.cpp new file mode 100644 index 00000000..0e7f6b58 --- /dev/null +++ b/ecmascript/jspandafile/accessor/module_data_accessor.cpp @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#include "ecmascript/jspandafile/accessor/module_data_accessor.h" +#include "libpandafile/file_items.h" +#include "libpandafile/helpers.h" + +namespace panda::ecmascript::jspandafile { +ModuleDataAccessor::ModuleDataAccessor(const panda_file::File &pandaFile, panda_file::File::EntityId moduleDataId) + : pandaFile_(pandaFile), moduleDataId_(moduleDataId) +{ + auto sp = pandaFile_.GetSpanFromId(moduleDataId); + + auto moduleSp = sp.SubSpan(panda_file::ID_SIZE); // skip literalnum + + numModuleRequests_ = panda_file::helpers::Read(&moduleSp); + + for (size_t idx = 0; idx < numModuleRequests_; idx++) { + auto value = static_cast(panda_file::helpers::Read(&moduleSp)); + moduleRequests_.emplace_back(value); + } + + entryDataSp_ = moduleSp; +} +} // namespace panda::ecmascript::jspandafile diff --git a/ecmascript/jspandafile/accessor/module_data_accessor.h b/ecmascript/jspandafile/accessor/module_data_accessor.h new file mode 100644 index 00000000..44113fbf --- /dev/null +++ b/ecmascript/jspandafile/accessor/module_data_accessor.h @@ -0,0 +1,71 @@ +/* + * 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_JSPANDAFILE_ACCESSOR_MODULE_DATA_ACCESSOR_H +#define ECMASCRIPT_JSPANDAFILE_ACCESSOR_MODULE_DATA_ACCESSOR_H + +#include "libpandafile/field_data_accessor.h" +#include "libpandafile/file.h" +#include "libpandabase/utils/span.h" + +namespace panda::ecmascript::jspandafile { +using StringData = panda_file::File::StringData; + +enum class ModuleTag : uint8_t { + REGULAR_IMPORT = 0x00, + NAMESPACE_IMPORT = 0x01, + LOCAL_EXPORT = 0x02, + INDIRECT_EXPORT = 0x03, + STAR_EXPORT = 0x04, +}; + +class ModuleDataAccessor { +public: + ModuleDataAccessor(const panda_file::File &panda_file, panda_file::File::EntityId module_data_id); + ~ModuleDataAccessor() = default; + DEFAULT_MOVE_CTOR(ModuleDataAccessor) + DEFAULT_COPY_CTOR(ModuleDataAccessor) + NO_MOVE_OPERATOR(ModuleDataAccessor); + NO_COPY_OPERATOR(ModuleDataAccessor); + + template + void EnumerateModuleRecord(const Callback &cb); + + const panda_file::File &GetPandaFile() const + { + return pandaFile_; + } + + panda_file::File::EntityId GetModuleDataId() const + { + return moduleDataId_; + } + + const std::vector& getRequestModules() const + { + return moduleRequests_; + } + + using ModuleValue = std::variant; + +private: + const panda_file::File &pandaFile_; + panda_file::File::EntityId moduleDataId_; + uint32_t numModuleRequests_; + std::vector moduleRequests_; + Span entryDataSp_ {nullptr, nullptr}; +}; +} // namespace panda::ecmascript::jspandafile +#endif // ECMASCRIPT_JSPANDAFILE_ACCESSOR_MODULE_DATA_ACCESSOR_H diff --git a/ecmascript/class_info_extractor.cpp b/ecmascript/jspandafile/class_info_extractor.cpp similarity index 99% rename from ecmascript/class_info_extractor.cpp rename to ecmascript/jspandafile/class_info_extractor.cpp index febd3d2c..42b0eb9a 100644 --- a/ecmascript/class_info_extractor.cpp +++ b/ecmascript/jspandafile/class_info_extractor.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "ecmascript/class_info_extractor.h" +#include "ecmascript/jspandafile/class_info_extractor.h" #include "ecmascript/global_env.h" #include "ecmascript/js_function.h" diff --git a/ecmascript/class_info_extractor.h b/ecmascript/jspandafile/class_info_extractor.h similarity index 95% rename from ecmascript/class_info_extractor.h rename to ecmascript/jspandafile/class_info_extractor.h index 745954d0..ef3d4332 100644 --- a/ecmascript/class_info_extractor.h +++ b/ecmascript/jspandafile/class_info_extractor.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ECMASCRIPT_CLASS_INFO_EXTRACTOR_H -#define ECMASCRIPT_CLASS_INFO_EXTRACTOR_H +#ifndef ECMASCRIPT_JSPANDAFILE_CLASS_INFO_EXTRACTOR_H +#define ECMASCRIPT_JSPANDAFILE_CLASS_INFO_EXTRACTOR_H -#include "js_tagged_value-inl.h" +#include "ecmascript/js_tagged_value-inl.h" namespace panda::ecmascript { // ClassInfoExtractor will analyze and extract the contents from class literal to keys, properties and elements(both @@ -97,4 +97,4 @@ private: JSHandle &elements, const JSHandle &constantpool); }; } // namespace panda::ecmascript -#endif // ECMASCRIPT_CLASS_INFO_EXTRACTOR_H +#endif // ECMASCRIPT_JSPANDAFILE_CLASS_INFO_EXTRACTOR_H diff --git a/ecmascript/ecma_class_linker_extension.cpp b/ecmascript/jspandafile/ecma_class_linker_extension.cpp similarity index 98% rename from ecmascript/ecma_class_linker_extension.cpp rename to ecmascript/jspandafile/ecma_class_linker_extension.cpp index 24711c50..6c6ea5e8 100644 --- a/ecmascript/ecma_class_linker_extension.cpp +++ b/ecmascript/jspandafile/ecma_class_linker_extension.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "ecmascript/ecma_class_linker_extension.h" +#include "ecmascript/jspandafile/ecma_class_linker_extension.h" #include "ecmascript/ecma_string.h" #include "include/class_linker-inl.h" #include "include/coretypes/class.h" diff --git a/ecmascript/ecma_class_linker_extension.h b/ecmascript/jspandafile/ecma_class_linker_extension.h similarity index 94% rename from ecmascript/ecma_class_linker_extension.h rename to ecmascript/jspandafile/ecma_class_linker_extension.h index d9b6a68d..4837988f 100644 --- a/ecmascript/ecma_class_linker_extension.h +++ b/ecmascript/jspandafile/ecma_class_linker_extension.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ECMASCRIPT_ECMA_CLASS_LINKER_EXTENSION_H -#define ECMASCRIPT_ECMA_CLASS_LINKER_EXTENSION_H +#ifndef ECMASCRIPT_JSPANDAFILE_ECMA_CLASS_LINKER_EXTENSION_H +#define ECMASCRIPT_JSPANDAFILE_ECMA_CLASS_LINKER_EXTENSION_H #include "libpandafile/file_items.h" #include "include/class_linker.h" @@ -106,4 +106,4 @@ private: } // namespace ecmascript } // namespace panda -#endif // ECMASCRIPT_ECMA_CLASS_LINKER_EXTENSION_H +#endif // ECMASCRIPT_JSPANDAFILE_ECMA_CLASS_LINKER_EXTENSION_H diff --git a/ecmascript/jspandafile/js_pandafile.cpp b/ecmascript/jspandafile/js_pandafile.cpp index ebd6cf14..cf4e23ea 100644 --- a/ecmascript/jspandafile/js_pandafile.cpp +++ b/ecmascript/jspandafile/js_pandafile.cpp @@ -15,12 +15,12 @@ #include "ecmascript/jspandafile/js_pandafile.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" -#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/jspandafile/program_object-inl.h" namespace panda::ecmascript { JSPandaFile::JSPandaFile(const panda_file::File *pf, const CString &descriptor) : pf_(pf), desc_(descriptor) { - InitMethods(); + Initialize(); } JSPandaFile::~JSPandaFile() @@ -58,7 +58,7 @@ uint32_t JSPandaFile::GetOrInsertConstantPool(ConstPoolType type, uint32_t offse return index; } -void JSPandaFile::InitMethods() +void JSPandaFile::Initialize() { Span classIndexes = pf_->GetClasses(); for (const uint32_t index : classIndexes) { @@ -68,6 +68,10 @@ void JSPandaFile::InitMethods() } panda_file::ClassDataAccessor cda(*pf_, classId); numMethods_ += cda.GetMethodsNumber(); + const char *desc = utf::Mutf8AsCString(cda.GetDescriptor()); + if (!isModule_ && std::strcmp(MODULE_CLASS, desc) == 0) { + isModule_ = true; + } } methods_ = static_cast(JSPandaFileManager::AllocateBuffer(sizeof(JSMethod) * numMethods_)); } @@ -83,4 +87,9 @@ const JSMethod *JSPandaFile::FindMethods(uint32_t offset) const return nullptr; } + +bool JSPandaFile::IsModule() const +{ + return isModule_; +} } // namespace panda::ecmascript diff --git a/ecmascript/jspandafile/js_pandafile.h b/ecmascript/jspandafile/js_pandafile.h index 51b4c8ba..114bdb30 100644 --- a/ecmascript/jspandafile/js_pandafile.h +++ b/ecmascript/jspandafile/js_pandafile.h @@ -17,8 +17,8 @@ #define ECMASCRIPT_JSPANDAFILE_JS_PANDAFILE_H #include "ecmascript/mem/c_containers.h" -#include "ecmascript/class_linker/panda_file_translator.h" #include "ecmascript/jspandafile/constpool_value.h" +#include "ecmascript/jspandafile/panda_file_translator.h" #include "ecmascript/tooling/pt_js_extractor.h" #include "libpandafile/file.h" #include "libpandabase/utils/logger.h" @@ -30,6 +30,8 @@ class File; namespace ecmascript { #define ENTRY_FUNCTION_NAME "func_main_0" +#define MODULE_CLASS "L_ESModuleRecord;" +#define ENTRY_MAIN_FUNCTION "_GLOBAL::func_main_0" class JSPandaFile { public: @@ -87,8 +89,10 @@ public: return pf_->GetClasses(); } + bool IsModule() const; + private: - void InitMethods(); + void Initialize(); uint32_t constpoolIndex_ {0}; std::unordered_map constpoolMap_; @@ -98,6 +102,7 @@ private: const panda_file::File *pf_ {nullptr}; std::unique_ptr ptJSExtractor_; CString desc_; + bool isModule_ {false}; }; } // namespace ecmascript } // namespace panda diff --git a/ecmascript/jspandafile/js_pandafile_executor.cpp b/ecmascript/jspandafile/js_pandafile_executor.cpp new file mode 100644 index 00000000..5a7034bb --- /dev/null +++ b/ecmascript/jspandafile/js_pandafile_executor.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2022 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. + */ + +#include "ecmascript/jspandafile/js_pandafile_executor.h" +#include "ecmascript/ecma_vm.h" +#include "ecmascript/internal_call_params.h" +#include "ecmascript/js_invoker.h" +#include "ecmascript/jspandafile/js_pandafile_manager.h" +#include "ecmascript/jspandafile/program_object-inl.h" +#include "ecmascript/module/js_module_manager.h" + +namespace panda::ecmascript { +bool JSPandaFileExecutor::ExecuteFromFile(JSThread *thread, const std::string &filename, std::string_view entryPoint, + const std::vector &args) +{ + const JSPandaFile *jsPandaFile = EcmaVM::GetJSPandaFileManager()->LoadJSPandaFile(filename); + if (jsPandaFile == nullptr) { + return false; + } + + bool isModule = jsPandaFile->IsModule(); + if (isModule) { + [[maybe_unused]] EcmaHandleScope scope(thread); + EcmaVM *vm = thread->GetEcmaVM(); + ModuleManager *moduleManager = vm->GetModuleManager(); + JSHandle moduleRecord = moduleManager->HostResolveImportedModule(filename); + SourceTextModule::Instantiate(thread, moduleRecord); + if (thread->HasPendingException()) { + auto exception = thread->GetException(); + vm->HandleUncaughtException(exception.GetTaggedObject()); + return false; + } + SourceTextModule::Evaluate(thread, moduleRecord); + return true; + } + return JSPandaFileExecutor::Execute(thread, jsPandaFile, entryPoint, args); +} + +bool JSPandaFileExecutor::ExecuteFromBuffer(JSThread *thread, const void *buffer, size_t size, + std::string_view entryPoint, const std::vector &args, + const std::string &filename) +{ + const JSPandaFile *jsPandaFile = EcmaVM::GetJSPandaFileManager()->LoadJSPandaFile(filename, buffer, size); + if (jsPandaFile == nullptr) { + return false; + } + bool isModule = jsPandaFile->IsModule(); + if (isModule) { + ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager(); + moduleManager->AddResolveImportedModule(jsPandaFile, filename); + } + return JSPandaFileExecutor::Execute(thread, jsPandaFile, entryPoint, args); +} + +bool JSPandaFileExecutor::Execute(JSThread *thread, const JSPandaFile *jsPandaFile, std::string_view entryPoint, + const std::vector &args) +{ + // Get ClassName and MethodName + size_t pos = entryPoint.find_last_of("::"); + if (pos == std::string_view::npos) { + LOG_ECMA(ERROR) << "EntryPoint:" << entryPoint << " is illegal"; + return false; + } + CString methodName(entryPoint.substr(pos + 1)); + // For Ark application startup + EcmaVM *vm = thread->GetEcmaVM(); + vm->InvokeEcmaEntrypoint(jsPandaFile, methodName, args); + return true; +} +} // namespace panda::ecmascript diff --git a/ecmascript/jspandafile/js_pandafile_executor.h b/ecmascript/jspandafile/js_pandafile_executor.h new file mode 100644 index 00000000..6c8706f8 --- /dev/null +++ b/ecmascript/jspandafile/js_pandafile_executor.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022 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_JSPANDAFILE_JS_PANDAFILE_EXECUTOR_H +#define ECMASCRIPT_JSPANDAFILE_JS_PANDAFILE_EXECUTOR_H + +#include "ecmascript/mem/c_containers.h" +#include "ecmascript/js_tagged_value.h" +#include "ecmascript/js_thread.h" +#include "ecmascript/jspandafile/js_pandafile.h" +#include "ecmascript/module/js_module_source_text.h" + +namespace panda::ecmascript { +class JSPandaFileExecutor { +public: + static bool ExecuteFromFile(JSThread *thread, const std::string &filename, std::string_view entryPoint, + const std::vector &args); + static bool ExecuteFromBuffer(JSThread *thread, const void *buffer, size_t size, std::string_view entryPoint, + const std::vector &args, const std::string &filename = ""); +private: + static bool Execute(JSThread *thread, const JSPandaFile *jsPandaFile, std::string_view entryPoint, + const std::vector &args); + +friend class SourceTextModule; +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_JSPANDAFILE_JS_PANDAFILE_EXECUTOR_H diff --git a/ecmascript/jspandafile/js_pandafile_manager.cpp b/ecmascript/jspandafile/js_pandafile_manager.cpp index 86573717..eddd60a7 100644 --- a/ecmascript/jspandafile/js_pandafile_manager.cpp +++ b/ecmascript/jspandafile/js_pandafile_manager.cpp @@ -14,7 +14,7 @@ */ #include "ecmascript/jspandafile/js_pandafile_manager.h" -#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/jspandafile/program_object-inl.h" namespace panda::ecmascript { static const size_t MALLOC_SIZE_LIMIT = 2147483648; // Max internal memory used by the VM declared in options diff --git a/ecmascript/jspandafile/js_pandafile_manager.h b/ecmascript/jspandafile/js_pandafile_manager.h index d44695bc..6909c0d4 100644 --- a/ecmascript/jspandafile/js_pandafile_manager.h +++ b/ecmascript/jspandafile/js_pandafile_manager.h @@ -17,8 +17,8 @@ #define ECMASCRIPT_JSPANDAFILE_JS_PANDAFILE_MANAGER_H #include "ecmascript/mem/c_containers.h" -#include "ecmascript/class_linker/panda_file_translator.h" #include "ecmascript/jspandafile/js_pandafile.h" +#include "ecmascript/jspandafile/panda_file_translator.h" #include "ecmascript/tooling/pt_js_extractor.h" #include "libpandafile/file.h" #include "libpandabase/utils/logger.h" diff --git a/ecmascript/literal_data_extractor.cpp b/ecmascript/jspandafile/literal_data_extractor.cpp similarity index 99% rename from ecmascript/literal_data_extractor.cpp rename to ecmascript/jspandafile/literal_data_extractor.cpp index 31ef3729..1d075999 100644 --- a/ecmascript/literal_data_extractor.cpp +++ b/ecmascript/jspandafile/literal_data_extractor.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "literal_data_extractor.h" +#include "ecmascript/jspandafile/literal_data_extractor.h" #include "ecmascript/base/string_helper.h" #include "ecmascript/ecma_string.h" diff --git a/ecmascript/literal_data_extractor.h b/ecmascript/jspandafile/literal_data_extractor.h similarity index 87% rename from ecmascript/literal_data_extractor.h rename to ecmascript/jspandafile/literal_data_extractor.h index 84b66e14..0dff8144 100644 --- a/ecmascript/literal_data_extractor.h +++ b/ecmascript/jspandafile/literal_data_extractor.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ECMASCRIPT_LITERAL_DATA_EXTRACTOR_H -#define ECMASCRIPT_LITERAL_DATA_EXTRACTOR_H +#ifndef ECMASCRIPT_JSPANDAFILE_LITERAL_DATA_EXTRACTOR_H +#define ECMASCRIPT_JSPANDAFILE_LITERAL_DATA_EXTRACTOR_H -#include "ecmascript/class_linker/panda_file_translator.h" +#include "ecmascript/jspandafile/panda_file_translator.h" #include "ecmascript/js_tagged_value-inl.h" namespace panda::ecmascript { @@ -39,4 +39,4 @@ public: PandaFileTranslator *pft = nullptr); }; } // namespace panda::ecmascript -#endif // ECMASCRIPT_LITERAL_DATA_EXTRACTOR_H +#endif // ECMASCRIPT_JSPANDAFILE_LITERAL_DATA_EXTRACTOR_H diff --git a/ecmascript/jspandafile/module_data_extractor.cpp b/ecmascript/jspandafile/module_data_extractor.cpp new file mode 100644 index 00000000..9d6f2dac --- /dev/null +++ b/ecmascript/jspandafile/module_data_extractor.cpp @@ -0,0 +1,174 @@ +/* + * 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. + */ + +#include "ecmascript/jspandafile/module_data_extractor.h" +#include "ecmascript/jspandafile/accessor/module_data_accessor-inl.h" +#include "ecmascript/base/string_helper.h" +#include "ecmascript/ecma_string.h" +#include "ecmascript/global_env.h" +#include "ecmascript/jspandafile/js_pandafile_manager.h" +#include "ecmascript/tagged_array-inl.h" +#include "libpandafile/literal_data_accessor-inl.h" + +namespace panda::ecmascript { +using ModuleTag = jspandafile::ModuleTag; +using StringData = panda_file::StringData; + +JSHandle ModuleDataExtractor::ParseModule(JSThread *thread, const JSPandaFile *jsPandaFile, + const std::string &descriptor) +{ + const panda_file::File *pf = jsPandaFile->GetPandaFile(); + Span classIndexes = pf->GetClasses(); + int moduleIdx = -1; + for (const uint32_t index : classIndexes) { + panda_file::File::EntityId classId(index); + if (pf->IsExternal(classId)) { + continue; + } + panda_file::ClassDataAccessor cda(*pf, classId); + const char *desc = utf::Mutf8AsCString(cda.GetDescriptor()); + if (std::strcmp(MODULE_CLASS, desc) == 0) { // module class + cda.EnumerateFields([&](panda_file::FieldDataAccessor &field_accessor) -> void { + panda_file::File::EntityId field_name_id = field_accessor.GetNameId(); + StringData sd = pf->GetStringData(field_name_id); + if (std::strcmp(reinterpret_cast(sd.data), descriptor.c_str())) { + moduleIdx = field_accessor.GetValue().value(); + return; + } + }); + } + } + ASSERT(moduleIdx != -1); + panda_file::File::EntityId literalArraysId = pf->GetLiteralArraysId(); + panda_file::LiteralDataAccessor lda(*pf, literalArraysId); + panda_file::File::EntityId moduleId = lda.GetLiteralArrayId(moduleIdx); + + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle moduleRecord = factory->NewSourceTextModule(); + ModuleDataExtractor::ExtractModuleDatas(thread, jsPandaFile, moduleId, moduleRecord); + + JSHandle ecmaModuleFilename = factory->NewFromStdString(descriptor); + moduleRecord->SetEcmaModuleFilename(thread, ecmaModuleFilename); + + moduleRecord->SetStatus(ModuleStatus::UNINSTANTIATED); + return JSHandle::Cast(moduleRecord); +} + +void ModuleDataExtractor::ExtractModuleDatas(JSThread *thread, const JSPandaFile *jsPandaFile, + panda_file::File::EntityId moduleId, + JSHandle &moduleRecord) +{ + const panda_file::File *pf = jsPandaFile->GetPandaFile(); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + jspandafile::ModuleDataAccessor mda(*pf, moduleId); + const std::vector &requestModules = mda.getRequestModules(); + JSHandle requestModuleArray = factory->NewTaggedArray(requestModules.size()); + for (size_t idx = 0; idx < requestModules.size(); idx++) { + StringData sd = pf->GetStringData(panda_file::File::EntityId(requestModules[idx])); + JSTaggedValue value(factory->GetRawStringFromStringTable(sd.data, sd.utf16_length, sd.is_ascii)); + requestModuleArray->Set(thread, idx, value); + } + moduleRecord->SetRequestedModules(thread, requestModuleArray); + + mda.EnumerateModuleRecord([factory, thread, pf, requestModuleArray, moduleRecord] + (const ModuleTag &tag, uint32_t exportNameOffset, + uint32_t moduleRequestIdx, uint32_t importNameOffset, uint32_t localNameOffset) { + size_t requestArraySize = requestModuleArray->GetLength(); + ASSERT((requestArraySize == 0 || moduleRequestIdx < requestArraySize)); + JSHandle defaultValue = thread->GlobalConstants()->GetHandledUndefined(); + switch (tag) { + case ModuleTag::REGULAR_IMPORT: { + StringData sd = pf->GetStringData(panda_file::File::EntityId(localNameOffset)); + JSHandle localName(thread, + factory->GetRawStringFromStringTable(sd.data, sd.utf16_length, sd.is_ascii)); + + sd = pf->GetStringData(panda_file::File::EntityId(importNameOffset)); + JSHandle importName(thread, + factory->GetRawStringFromStringTable(sd.data, sd.utf16_length, sd.is_ascii)); + + JSHandle moduleRequest = thread->GlobalConstants()->GetHandledUndefined(); + if (requestArraySize != 0) { + moduleRequest = JSHandle(thread, requestModuleArray->Get(moduleRequestIdx)); + } + JSHandle importEntry = factory->NewImportEntry(moduleRequest, importName, localName); + SourceTextModule::AddImportEntry(thread, moduleRecord, importEntry); + break; + } + case ModuleTag::NAMESPACE_IMPORT: { + StringData sd = pf->GetStringData(panda_file::File::EntityId(localNameOffset)); + JSHandle localName(thread, + factory->GetRawStringFromStringTable(sd.data, sd.utf16_length, sd.is_ascii)); + + JSHandle moduleRequest = thread->GlobalConstants()->GetHandledUndefined(); + if (requestArraySize != 0) { + moduleRequest = JSHandle(thread, requestModuleArray->Get(moduleRequestIdx)); + } + JSHandle importName = thread->GlobalConstants()->GetHandledStarString(); + JSHandle importEntry = factory->NewImportEntry(moduleRequest, importName, localName); + SourceTextModule::AddImportEntry(thread, moduleRecord, importEntry); + break; + } + case ModuleTag::LOCAL_EXPORT: { + StringData sd = pf->GetStringData(panda_file::File::EntityId(localNameOffset)); + JSHandle localName(thread, + factory->GetRawStringFromStringTable(sd.data, sd.utf16_length, sd.is_ascii)); + + sd = pf->GetStringData(panda_file::File::EntityId(exportNameOffset)); + JSHandle exportName(thread, + factory->GetRawStringFromStringTable(sd.data, sd.utf16_length, sd.is_ascii)); + + JSHandle exportEntry = + factory->NewExportEntry(exportName, defaultValue, defaultValue, localName); + SourceTextModule::AddLocalExportEntry(thread, moduleRecord, exportEntry); + break; + } + case ModuleTag::INDIRECT_EXPORT: { + StringData sd = pf->GetStringData(panda_file::File::EntityId(exportNameOffset)); + JSHandle exportName(thread, + factory->GetRawStringFromStringTable(sd.data, sd.utf16_length, sd.is_ascii)); + + sd = pf->GetStringData(panda_file::File::EntityId(importNameOffset)); + JSHandle importName(thread, + factory->GetRawStringFromStringTable(sd.data, sd.utf16_length, sd.is_ascii)); + + JSHandle moduleRequest = thread->GlobalConstants()->GetHandledUndefined(); + if (requestArraySize != 0) { + moduleRequest = JSHandle(thread, requestModuleArray->Get(moduleRequestIdx)); + } + + JSHandle exportEntry = + factory->NewExportEntry(exportName, moduleRequest, importName, defaultValue); + SourceTextModule::AddIndirectExportEntry(thread, moduleRecord, exportEntry); + break; + } + case ModuleTag::STAR_EXPORT: { + JSHandle moduleRequest = thread->GlobalConstants()->GetHandledUndefined(); + if (requestArraySize != 0) { + moduleRequest = JSHandle(thread, requestModuleArray->Get(moduleRequestIdx)); + } + + JSHandle exportEntry = + factory->NewExportEntry(defaultValue, moduleRequest, defaultValue, defaultValue); + SourceTextModule::AddStarExportEntry(thread, moduleRecord, exportEntry); + break; + } + default: { + UNREACHABLE(); + break; + } + } + }); +} +} // namespace panda::ecmascript diff --git a/ecmascript/jspandafile/module_data_extractor.h b/ecmascript/jspandafile/module_data_extractor.h new file mode 100644 index 00000000..11bea007 --- /dev/null +++ b/ecmascript/jspandafile/module_data_extractor.h @@ -0,0 +1,41 @@ +/* + * 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_JSPANDAFILE_MODULE_DATA_EXTRACTOR_H +#define ECMASCRIPT_JSPANDAFILE_MODULE_DATA_EXTRACTOR_H + +#include "ecmascript/js_tagged_value-inl.h" +#include "ecmascript/module/js_module_source_text.h" +#include "ecmascript/jspandafile/js_pandafile.h" + +namespace panda::ecmascript { +using EntityId = panda_file::File::EntityId; + +class ModuleDataExtractor { +public: + explicit ModuleDataExtractor() = default; + virtual ~ModuleDataExtractor() = default; + + DEFAULT_NOEXCEPT_MOVE_SEMANTIC(ModuleDataExtractor); + DEFAULT_COPY_SEMANTIC(ModuleDataExtractor); + + static void ExtractModuleDatas(JSThread *thread, const JSPandaFile *jsPandaFile, + panda_file::File::EntityId moduleId, + JSHandle &moduleRecord); + static JSHandle ParseModule(JSThread *thread, const JSPandaFile *jsPandaFile, + const std::string &descriptor); +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_JSPANDAFILE_MODULE_DATA_EXTRACTOR_H diff --git a/ecmascript/class_linker/panda_file_translator.cpp b/ecmascript/jspandafile/panda_file_translator.cpp similarity index 99% rename from ecmascript/class_linker/panda_file_translator.cpp rename to ecmascript/jspandafile/panda_file_translator.cpp index a78b9044..dc9cf8fd 100644 --- a/ecmascript/class_linker/panda_file_translator.cpp +++ b/ecmascript/jspandafile/panda_file_translator.cpp @@ -19,15 +19,15 @@ #include #include -#include "ecmascript/class_info_extractor.h" -#include "ecmascript/class_linker/program_object-inl.h" #include "ecmascript/global_env.h" #include "ecmascript/interpreter/interpreter.h" +#include "ecmascript/jspandafile/class_info_extractor.h" +#include "ecmascript/jspandafile/literal_data_extractor.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/js_array.h" #include "ecmascript/js_function.h" #include "ecmascript/js_thread.h" -#include "ecmascript/literal_data_extractor.h" #include "ecmascript/object_factory.h" #include "ecmascript/tagged_array.h" #include "ecmascript/ts_types/ts_type_table.h" @@ -351,9 +351,9 @@ void PandaFileTranslator::UpdateICOffset(JSMethod *method, uint8_t *pc) case EcmaOpcode::STSUPERBYVALUE_PREF_V8_V8: case EcmaOpcode::LDSUPERBYNAME_PREF_ID32_V8: case EcmaOpcode::STSUPERBYNAME_PREF_ID32_V8: - case EcmaOpcode::LDMODVARBYNAME_PREF_ID32_V8: + case EcmaOpcode::LDMODULEVAR_PREF_ID32_IMM8: case EcmaOpcode::STMODULEVAR_PREF_ID32: - method->UpdateSlotSize(2); + method->UpdateSlotSize(2); // 2: occupy two ic slot break; default: return; diff --git a/ecmascript/class_linker/panda_file_translator.h b/ecmascript/jspandafile/panda_file_translator.h similarity index 94% rename from ecmascript/class_linker/panda_file_translator.h rename to ecmascript/jspandafile/panda_file_translator.h index ab874b82..872ae9c1 100644 --- a/ecmascript/class_linker/panda_file_translator.h +++ b/ecmascript/jspandafile/panda_file_translator.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ECMASCRIPT_CLASS_LINKER_PANDA_FILE_TRANSLATOR_H -#define ECMASCRIPT_CLASS_LINKER_PANDA_FILE_TRANSLATOR_H +#ifndef ECMASCRIPT_JSPANDAFILE_PANDA_FILE_TRANSLATOR_H +#define ECMASCRIPT_JSPANDAFILE_PANDA_FILE_TRANSLATOR_H #include "ecmascript/ecma_vm.h" #include "ecmascript/js_function.h" @@ -66,4 +66,4 @@ private: const JSPandaFile *jsPandaFile_; }; } // namespace panda::ecmascript -#endif // ECMASCRIPT_CLASS_LINKER_PANDA_FILE_TRANSLATOR_H +#endif // ECMASCRIPT_JSPANDAFILE_PANDA_FILE_TRANSLATOR_H diff --git a/ecmascript/class_linker/program_object-inl.h b/ecmascript/jspandafile/program_object-inl.h similarity index 84% rename from ecmascript/class_linker/program_object-inl.h rename to ecmascript/jspandafile/program_object-inl.h index 80a7eada..ed5d0bd8 100644 --- a/ecmascript/class_linker/program_object-inl.h +++ b/ecmascript/jspandafile/program_object-inl.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ECMASCRIPT_CLASS_LINKER_PROGRAM_INL_H -#define ECMASCRIPT_CLASS_LINKER_PROGRAM_INL_H +#ifndef ECMASCRIPT_JSPANDAFILE_PROGRAM_OBJECT_INL_H +#define ECMASCRIPT_JSPANDAFILE_PROGRAM_OBJECT_INL_H #include "program_object.h" #include "ecmascript/mem/native_area_allocator.h" @@ -27,4 +27,4 @@ JSTaggedValue ConstantPool::GetObjectFromCache(uint32_t index) const } } // namespace ecmascript } // namespace panda -#endif // ECMASCRIPT_CLASS_LINKER_PROGRAM_INL_H \ No newline at end of file +#endif // ECMASCRIPT_JSPANDAFILE_PROGRAM_OBJECT_INL_H \ No newline at end of file diff --git a/ecmascript/class_linker/program_object.h b/ecmascript/jspandafile/program_object.h similarity index 90% rename from ecmascript/class_linker/program_object.h rename to ecmascript/jspandafile/program_object.h index cdfe17ff..a2d078d9 100644 --- a/ecmascript/class_linker/program_object.h +++ b/ecmascript/jspandafile/program_object.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ECMASCRIPT_CLASS_LINKER_PROGRAM_H -#define ECMASCRIPT_CLASS_LINKER_PROGRAM_H +#ifndef ECMASCRIPT_JSPANDAFILE_PROGRAM_OBJECT_H +#define ECMASCRIPT_JSPANDAFILE_PROGRAM_OBJECT_H #include "ecmascript/ecma_macros.h" #include "ecmascript/js_tagged_value-inl.h" @@ -48,4 +48,4 @@ public: }; } // namespace ecmascript } // namespace panda -#endif // ECMASCRIPT_CLASS_LINKER_PROGRAM_H +#endif // ECMASCRIPT_JSPANDAFILE_PROGRAM_OBJECT_H diff --git a/ecmascript/scope_info_extractor.cpp b/ecmascript/jspandafile/scope_info_extractor.cpp similarity index 94% rename from ecmascript/scope_info_extractor.cpp rename to ecmascript/jspandafile/scope_info_extractor.cpp index 05291569..81480f3a 100644 --- a/ecmascript/scope_info_extractor.cpp +++ b/ecmascript/jspandafile/scope_info_extractor.cpp @@ -13,9 +13,9 @@ * limitations under the License. */ -#include "ecmascript/scope_info_extractor.h" +#include "ecmascript/jspandafile/scope_info_extractor.h" #include "ecmascript/interpreter/frame_handler.h" -#include "ecmascript/literal_data_extractor.h" +#include "ecmascript/jspandafile/literal_data_extractor.h" #include "ecmascript/tagged_array-inl.h" namespace panda::ecmascript { diff --git a/ecmascript/scope_info_extractor.h b/ecmascript/jspandafile/scope_info_extractor.h similarity index 86% rename from ecmascript/scope_info_extractor.h rename to ecmascript/jspandafile/scope_info_extractor.h index 88e1a92f..ed7daa12 100644 --- a/ecmascript/scope_info_extractor.h +++ b/ecmascript/jspandafile/scope_info_extractor.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ECMASCRIPT_SCOPE_INFO_EXTRACTOR_H -#define ECMASCRIPT_SCOPE_INFO_EXTRACTOR_H +#ifndef ECMASCRIPT_JSPANDAFILE_SCOPE_INFO_EXTRACTOR_H +#define ECMASCRIPT_JSPANDAFILE_SCOPE_INFO_EXTRACTOR_H #include "ecmascript/js_tagged_value-inl.h" @@ -31,4 +31,4 @@ public: }; } // namespace panda::ecmascript -#endif // ECMASCRIPT_SCOPE_INFO_EXTRACTOR_H +#endif // ECMASCRIPT_JSPANDAFILE_SCOPE_INFO_EXTRACTOR_H diff --git a/ecmascript/mem/object_xray-inl.h b/ecmascript/mem/object_xray-inl.h index 2d6874c6..78d6258f 100644 --- a/ecmascript/mem/object_xray-inl.h +++ b/ecmascript/mem/object_xray-inl.h @@ -17,9 +17,6 @@ #define ECMASCRIPT_MEM_HEAP_ROOTS_INL_H #include -#include "ecmascript/class_info_extractor.h" -#include "ecmascript/class_linker/program_object.h" -#include "ecmascript/ecma_module.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" #include "ecmascript/ic/ic_handler.h" @@ -28,6 +25,8 @@ #include "ecmascript/jobs/pending_job.h" #include "ecmascript/js_api_queue.h" #include "ecmascript/js_api_queue_iterator.h" +#include "ecmascript/jspandafile/class_info_extractor.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/js_api_tree_map.h" #include "ecmascript/js_api_tree_map_iterator.h" #include "ecmascript/js_api_tree_set.h" @@ -69,6 +68,8 @@ #include "ecmascript/mem/mem.h" #include "ecmascript/ts_types/ts_type.h" #include "ecmascript/ts_types/ts_type_table.h" +#include "ecmascript/module/js_module_source_text.h" +#include "ecmascript/module/js_module_namespace.h" namespace panda::ecmascript { void ObjectXRay::VisitVMRoots(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) const @@ -265,9 +266,6 @@ void ObjectXRay::VisitObjectBody(TaggedObject *object, JSHClass *klass, const Ec case JSType::COMPLETION_RECORD: CompletionRecord::Cast(object)->VisitRangeSlot(visitor); break; - case JSType::ECMA_MODULE: - EcmaModule::Cast(object)->VisitRangeSlot(visitor); - break; case JSType::PROGRAM: Program::Cast(object)->VisitRangeSlot(visitor); break; @@ -350,6 +348,21 @@ void ObjectXRay::VisitObjectBody(TaggedObject *object, JSHClass *klass, const Ec case JSType::JS_API_TREESET_ITERATOR: JSAPITreeSetIterator::Cast(object)->VisitRangeSlot(visitor); break; + case JSType::SOURCE_TEXT_MODULE_RECORD: + SourceTextModule::Cast(object)->VisitRangeSlot(visitor); + break; + case JSType::IMPORTENTRY_RECORD: + ImportEntry::Cast(object)->VisitRangeSlot(visitor); + break; + case JSType::EXPORTENTRY_RECORD: + ExportEntry::Cast(object)->VisitRangeSlot(visitor); + break; + case JSType::RESOLVEDBINDING_RECORD: + ResolvedBinding::Cast(object)->VisitRangeSlot(visitor); + break; + case JSType::JS_MODULE_NAMESPACE: + ModuleNamespace::Cast(object)->VisitRangeSlot(visitor); + break; default: UNREACHABLE(); } diff --git a/ecmascript/module/js_module_manager.cpp b/ecmascript/module/js_module_manager.cpp new file mode 100644 index 00000000..6b73ee42 --- /dev/null +++ b/ecmascript/module/js_module_manager.cpp @@ -0,0 +1,155 @@ +/* + * 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. + */ + +#include "ecmascript/module/js_module_manager.h" + +#include "ecmascript/global_env.h" +#include "ecmascript/interpreter/frame_handler.h" +#include "ecmascript/jspandafile/module_data_extractor.h" +#include "ecmascript/jspandafile/js_pandafile.h" +#include "ecmascript/jspandafile/js_pandafile_manager.h" +#include "ecmascript/js_array.h" +#include "ecmascript/linked_hash_table.h" +#include "ecmascript/module/js_module_source_text.h" +#include "ecmascript/tagged_dictionary.h" + +namespace panda::ecmascript { +ModuleManager::ModuleManager(EcmaVM *vm) : vm_(vm) +{ + resolvedModules_ = NameDictionary::Create(vm_->GetJSThread(), DEAULT_DICTIONART_CAPACITY).GetTaggedValue(); +} + +JSTaggedValue ModuleManager::GetCurrentModule() +{ + InterpretedFrameHandler frameHandler(vm_->GetJSThread()); + JSTaggedValue currentFunc = frameHandler.GetFunction(); + return JSFunction::Cast(currentFunc.GetTaggedObject())->GetModule(); +} + +JSTaggedValue ModuleManager::GetModuleValueInner(JSTaggedValue key) +{ + JSTaggedValue currentModule = GetCurrentModule(); + if (currentModule.IsUndefined()) { + LOG_ECMA(FATAL) << "GetModuleValueInner currentModule failed"; + } + return SourceTextModule::Cast(currentModule.GetHeapObject())->GetModuleValue(vm_->GetJSThread(), key, false); +} + +JSTaggedValue ModuleManager::GetModuleValueOutter(JSTaggedValue key) +{ + JSThread *thread = vm_->GetJSThread(); + JSTaggedValue currentModule = GetCurrentModule(); + if (currentModule.IsUndefined()) { + LOG_ECMA(FATAL) << "GetModuleValueOutter currentModule failed"; + } + JSTaggedValue moduleEnvironment = SourceTextModule::Cast(currentModule.GetHeapObject())->GetEnvironment(); + ASSERT(!moduleEnvironment.IsUndefined()); + JSTaggedValue resolvedBinding = LinkedHashMap::Cast(moduleEnvironment.GetTaggedObject())->Get(key); + if (resolvedBinding.IsUndefined()) { + return thread->GlobalConstants()->GetUndefined(); + } + ASSERT(resolvedBinding.IsResolvedBinding()); + ResolvedBinding *binding = ResolvedBinding::Cast(resolvedBinding.GetTaggedObject()); + JSTaggedValue resolvedModule = binding->GetModule(); + ASSERT(resolvedModule.IsSourceTextModule()); + return SourceTextModule::Cast(resolvedModule.GetHeapObject())->GetModuleValue(thread, binding->GetBindingName(), + false); +} + +void ModuleManager::StoreModuleValue(JSTaggedValue key, JSTaggedValue value) +{ + JSThread *thread = vm_->GetJSThread(); + JSHandle currentModule(thread, GetCurrentModule()); + if (currentModule.GetTaggedValue().IsUndefined()) { + LOG_ECMA(FATAL) << "StoreModuleValue currentModule failed"; + } + JSHandle keyHandle(thread, key); + JSHandle valueHandle(thread, value); + currentModule->StoreModuleValue(thread, keyHandle, valueHandle); +} + +JSHandle ModuleManager::HostGetImportedModule(const CString &referencingModule) +{ + ObjectFactory *factory = vm_->GetFactory(); + JSHandle referencingHandle = + JSHandle::Cast(factory->NewFromString(referencingModule)); + int entry = + NameDictionary::Cast(resolvedModules_.GetTaggedObject())->FindEntry(referencingHandle.GetTaggedValue()); + LOG_IF(entry == -1, FATAL, ECMASCRIPT) << "cannot get module: " << referencingModule; + + return JSHandle(vm_->GetJSThread(), + NameDictionary::Cast(resolvedModules_.GetTaggedObject())->GetValue(entry)); +} + +JSHandle ModuleManager::HostResolveImportedModule(const std::string &referencingModule) +{ + JSThread *thread = vm_->GetJSThread(); + ObjectFactory *factory = vm_->GetFactory(); + JSHandle referencingHandle = + JSHandle::Cast(factory->NewFromStdString(referencingModule)); + int entry = + NameDictionary::Cast(resolvedModules_.GetTaggedObject())->FindEntry(referencingHandle.GetTaggedValue()); + if (entry != -1) { + return JSHandle( + thread, NameDictionary::Cast(resolvedModules_.GetTaggedObject())->GetValue(entry)); + } + + const JSPandaFile *jsPandaFile = EcmaVM::GetJSPandaFileManager()->LoadJSPandaFile(referencingModule); + if (jsPandaFile == nullptr) { + LOG_ECMA(ERROR) << "open jsPandaFile " << referencingModule << " error"; + UNREACHABLE(); + } + JSHandle moduleRecord = ModuleDataExtractor::ParseModule(thread, jsPandaFile, referencingModule); + JSHandle dict(thread, resolvedModules_); + resolvedModules_ = + NameDictionary::Put(thread, dict, referencingHandle, moduleRecord, PropertyAttributes::Default()) + .GetTaggedValue(); + return JSHandle::Cast(moduleRecord); +} + +void ModuleManager::AddResolveImportedModule(const JSPandaFile *jsPandaFile, const std::string &referencingModule) +{ + JSThread *thread = vm_->GetJSThread(); + ObjectFactory *factory = vm_->GetFactory(); + JSHandle moduleRecord = ModuleDataExtractor::ParseModule(thread, jsPandaFile, referencingModule); + JSHandle referencingHandle = + JSHandle::Cast(factory->NewFromStdString(referencingModule)); + JSHandle dict(thread, resolvedModules_); + resolvedModules_ = + NameDictionary::Put(thread, dict, referencingHandle, moduleRecord, PropertyAttributes::Default()) + .GetTaggedValue(); +} + +JSTaggedValue ModuleManager::GetModuleNamespace(JSTaggedValue localName) +{ + JSTaggedValue currentModule = GetCurrentModule(); + if (currentModule.IsUndefined()) { + LOG_ECMA(FATAL) << "GetModuleNamespace currentModule failed"; + } + JSTaggedValue moduleEnvironment = SourceTextModule::Cast(currentModule.GetHeapObject())->GetEnvironment(); + ASSERT(!moduleEnvironment.IsUndefined()); + JSTaggedValue moduleNamespace = LinkedHashMap::Cast(moduleEnvironment.GetTaggedObject())->Get(localName); + if (moduleNamespace.IsUndefined()) { + return vm_->GetJSThread()->GlobalConstants()->GetUndefined(); + } + ASSERT(moduleNamespace.IsModuleNamespace()); + return moduleNamespace; +} + +void ModuleManager::Iterate(const RootVisitor &v) +{ + v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(&resolvedModules_))); +} +} // namespace panda::ecmascript \ No newline at end of file diff --git a/ecmascript/module/js_module_manager.h b/ecmascript/module/js_module_manager.h new file mode 100644 index 00000000..0cdc6b08 --- /dev/null +++ b/ecmascript/module/js_module_manager.h @@ -0,0 +1,51 @@ +/* + * 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" + +namespace panda::ecmascript { +class ModuleManager { +public: + explicit ModuleManager(EcmaVM *vm); + ~ModuleManager() = default; + + JSTaggedValue GetModuleValueInner(JSTaggedValue key); + JSTaggedValue GetModuleValueOutter(JSTaggedValue key); + void StoreModuleValue(JSTaggedValue key, JSTaggedValue value); + JSHandle HostGetImportedModule(const CString &referencingModule); + JSHandle HostResolveImportedModule(const std::string &referencingModule); + JSTaggedValue GetModuleNamespace(JSTaggedValue localName); + void AddResolveImportedModule(const JSPandaFile *jsPandaFile, const std::string &referencingModule); + void Iterate(const RootVisitor &v); + +private: + NO_COPY_SEMANTIC(ModuleManager); + NO_MOVE_SEMANTIC(ModuleManager); + + JSTaggedValue GetCurrentModule(); + + static constexpr uint32_t DEAULT_DICTIONART_CAPACITY = 4; + + EcmaVM *vm_ {nullptr}; + JSTaggedValue resolvedModules_ {JSTaggedValue::Hole()}; + + friend class EcmaVM; +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_MODULE_JS_MODULE_MANAGER_H \ No newline at end of file diff --git a/ecmascript/module/js_module_namespace.cpp b/ecmascript/module/js_module_namespace.cpp new file mode 100644 index 00000000..8fee8c4b --- /dev/null +++ b/ecmascript/module/js_module_namespace.cpp @@ -0,0 +1,246 @@ +/* + * 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. + */ + +#include "ecmascript/module/js_module_namespace.h" + +#include "ecmascript/global_env.h" +#include "ecmascript/js_array.h" +#include "ecmascript/module/js_module_record.h" +#include "ecmascript/module/js_module_source_text.h" +#include "ecmascript/base/string_helper.h" + +namespace panda::ecmascript { +JSHandle ModuleNamespace::ModuleNamespaceCreate(JSThread *thread, + const JSHandle &module, + const JSHandle &exports) +{ + auto globalConst = thread->GlobalConstants(); + // 1. Assert: module is a Module Record. + ASSERT(module->IsModuleRecord()); + // 2. Assert: module.[[Namespace]] is undefined. + JSHandle moduleRecord = JSHandle::Cast(module); + ASSERT(ModuleRecord::GetNamespace(moduleRecord.GetTaggedValue()).IsUndefined()); + // 3. Assert: exports is a List of String values. + // 4. Let M be a newly created object. + // 5. Set M's essential internal methods to the definitions specified in 9.4.6. + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle mNp = factory->NewModuleNamespace(); + // 6. Set M.[[Module]] to module. + mNp->SetModule(thread, module); + // 7. Let sortedExports be a new List containing the same values as the list exports where the values + // are ordered as if an Array of the same values had been sorted using + // Array.prototype.sort using undefined as comparefn. + JSHandle exportsArray = JSArray::CreateArrayFromList(thread, exports); + JSHandle sortedExports = JSHandle::Cast(exportsArray); + JSHandle fn = globalConst->GetHandledUndefined(); + JSArray::Sort(thread, sortedExports, fn); + // 8. Set M.[[Exports]] to sortedExports. + mNp->SetExports(thread, sortedExports); + // 9. Create own properties of M corresponding to the definitions in 26.3. + + JSHandle toStringTag = thread->GetEcmaVM()->GetGlobalEnv()->GetToStringTagSymbol(); + JSHandle moduleString = globalConst->GetHandledModuleString(); + PropertyDescriptor des(thread, moduleString, false, false, false); + JSHandle mNpObj = JSHandle::Cast(mNp); + JSObject::DefineOwnProperty(thread, mNpObj, toStringTag, des); + // 10. Set module.[[Namespace]] to M. + ModuleRecord::SetNamespace(thread, moduleRecord.GetTaggedValue(), mNp.GetTaggedValue()); + return mNp; +} + +OperationResult ModuleNamespace::GetProperty(JSThread *thread, const JSHandle &obj, + const JSHandle &key) +{ + // 1. Assert: IsPropertyKey(P) is true. + ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key"); + // 2. If Type(P) is Symbol, then + // a. Return ? OrdinaryGet(O, P, Receiver). + if (key->IsSymbol()) { + return JSObject::GetProperty(thread, obj, key); + } + JSHandle moduleNamespace = JSHandle::Cast(obj); + // 3. Let exports be O.[[Exports]]. + JSHandle exports(thread, moduleNamespace->GetExports()); + // 4. If P is not an element of exports, return undefined. + if (exports->IsUndefined()) { + return OperationResult(thread, thread->GlobalConstants()->GetUndefined(), PropertyMetaData(false)); + } + if (!JSArray::IncludeInSortedValue(thread, exports, key)) { + return OperationResult(thread, thread->GlobalConstants()->GetUndefined(), PropertyMetaData(false)); + } + // 5. Let m be O.[[Module]]. + JSHandle mm(thread, moduleNamespace->GetModule()); + // 6. Let binding be ! m.ResolveExport(P, « »). + CVector, JSHandle>> resolveSet; + JSHandle binding = SourceTextModule::ResolveExport(thread, mm, key, resolveSet); + // 7. Assert: binding is a ResolvedBinding Record. + ASSERT(binding->IsResolvedBinding()); + // 8. Let targetModule be binding.[[Module]]. + JSHandle resolvedBind = JSHandle::Cast(binding); + JSTaggedValue targetModule = resolvedBind->GetModule(); + // 9. Assert: targetModule is not undefined. + ASSERT(!targetModule.IsUndefined()); + JSTaggedValue result = SourceTextModule::Cast(targetModule.GetHeapObject())-> + GetModuleValue(thread, resolvedBind->GetBindingName(), true); + return OperationResult(thread, result, PropertyMetaData(true)); +} + +JSHandle ModuleNamespace::OwnPropertyKeys(JSThread *thread, const JSHandle &obj) +{ + ASSERT(obj->IsModuleNamespace()); + // 1. Let exports be a copy of O.[[Exports]]. + JSHandle moduleNamespace = JSHandle::Cast(obj); + JSHandle exports(thread, moduleNamespace->GetExports()); + JSHandle exportsArray = JSArray::ToTaggedArray(thread, exports); + if (!moduleNamespace->ValidateKeysAvailable(thread, exportsArray)) { + return exportsArray; + } + + // 2. Let symbolKeys be ! OrdinaryOwnPropertyKeys(O). + JSHandle symbolKeys = JSObject::GetOwnPropertyKeys(thread, JSHandle(obj)); + // 3. Append all the entries of symbolKeys to the end of exports. + JSHandle result = TaggedArray::Append(thread, exportsArray, symbolKeys); + // 4. Return exports. + return result; +} + +bool ModuleNamespace::IsExtensible() +{ + return false; +} + +bool ModuleNamespace::PreventExtensions() +{ + return true; +} + +bool ModuleNamespace::DefineOwnProperty(JSThread *thread, const JSHandle &obj, + const JSHandle &key, PropertyDescriptor desc) +{ + return false; +} + +bool ModuleNamespace::HasProperty(JSThread *thread, const JSHandle &obj, + const JSHandle &key) +{ + ASSERT(obj->IsModuleNamespace()); + // 1. If Type(P) is Symbol, return OrdinaryHasProperty(O, P). + if (key->IsSymbol()) { + return JSObject::HasProperty(thread, JSHandle(obj), key); + } + // 2. Let exports be O.[[Exports]]. + JSHandle moduleNamespace = JSHandle::Cast(obj); + JSHandle exports(thread, moduleNamespace->GetExports()); + // 3. If P is an element of exports, return true. + if (exports->IsUndefined()) { + return false; + } + if (JSArray::IncludeInSortedValue(thread, exports, key)) { + return true; + } + // 4. Return false. + return false; +} + +bool ModuleNamespace::SetPrototype(JSThread *thread, [[maybe_unused]]const JSHandle &obj, + const JSHandle &proto) +{ + ASSERT(obj->IsModuleNamespace()); + // 1. Assert: Either Type(V) is Object or Type(V) is Null. + ASSERT(proto->IsECMAObject() || proto->IsNull()); + return proto->IsNull(); +} + +bool ModuleNamespace::GetOwnProperty(JSThread *thread, const JSHandle &obj, + const JSHandle &key, PropertyDescriptor &desc) +{ + // 1. If Type(P) is Symbol, return OrdinaryGetOwnProperty(O, P). + if (key->IsSymbol()) { + return JSObject::GetOwnProperty(thread, JSHandle(obj), key, desc); + } + // 2. Let exports be O.[[Exports]]. + JSHandle moduleNamespace = JSHandle::Cast(obj); + JSHandle exports(thread, moduleNamespace->GetExports()); + // 3. If P is not an element of exports, return undefined. + if (exports->IsUndefined()) { + return false; + } + if (!JSArray::IncludeInSortedValue(thread, exports, key)) { + return false; + } + // 4. Let value be ? O.[[Get]](P, O). + JSHandle value = ModuleNamespace::GetProperty(thread, obj, key).GetValue(); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); + // 5. Return PropertyDescriptor { + // [[Value]]: value, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: false }. + desc.SetValue(value); + desc.SetEnumerable(true); + desc.SetWritable(true); + desc.SetConfigurable(false); + return true; +} + +bool ModuleNamespace::SetProperty(JSThread *thread, bool mayThrow) +{ + if (mayThrow) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot assign to read only property of Object Module", false); + } + return false; +} + +bool ModuleNamespace::DeleteProperty(JSThread *thread, const JSHandle &obj, + const JSHandle &key) +{ + ASSERT(obj->IsModuleNamespace()); + // 1. Assert: IsPropertyKey(P) is true. + ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key"); + // 2. If Type(P) is Symbol, then + // Return ? OrdinaryDelete(O, P). + if (key->IsSymbol()) { + return JSObject::DeleteProperty(thread, JSHandle(obj), key); + } + // 3. Let exports be O.[[Exports]]. + JSHandle moduleNamespace = JSHandle::Cast(obj); + JSHandle exports(thread, moduleNamespace->GetExports()); + // 4. If P is an element of exports, return false. + if (exports->IsUndefined()) { + return true; + } + if (JSArray::IncludeInSortedValue(thread, exports, key)) { + return false; + } + return true; +} + +bool ModuleNamespace::ValidateKeysAvailable(JSThread *thread, const JSHandle &exports) +{ + JSHandle moduleNamespace(thread, this); + JSHandle mm(thread, moduleNamespace->GetModule()); + int32_t exportsLength = exports->GetLength(); + for (int32_t idx = 0; idx < exportsLength; idx++) { + JSHandle key(thread, exports->Get(idx)); + CVector, JSHandle>> resolveSet; + JSHandle binding = SourceTextModule::ResolveExport(thread, mm, key, resolveSet); + ASSERT(binding->IsResolvedBinding()); + JSTaggedValue targetModule = JSHandle::Cast(binding)->GetModule(); + ASSERT(!targetModule.IsUndefined()); + JSTaggedValue dictionary = SourceTextModule::Cast(targetModule.GetHeapObject())->GetNameDictionary(); + if (dictionary.IsUndefined()) { + THROW_REFERENCE_ERROR_AND_RETURN(thread, "module environment is undefined", false); + } + } + return true; +} +} // namespace panda::ecmascript \ No newline at end of file diff --git a/ecmascript/module/js_module_namespace.h b/ecmascript/module/js_module_namespace.h new file mode 100644 index 00000000..0cabdb3d --- /dev/null +++ b/ecmascript/module/js_module_namespace.h @@ -0,0 +1,66 @@ +/* + * 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_NAMESPACE_H +#define ECMASCRIPT_MODULE_JS_MODULE_NAMESPACE_H + +#include "ecmascript/js_object.h" +#include "ecmascript/js_tagged_value.h" + +namespace panda::ecmascript { +class ModuleNamespace final : public JSObject { +public: + CAST_CHECK(ModuleNamespace, IsModuleNamespace); + + // 9.4.6.11ModuleNamespaceCreate ( module, exports ) + static JSHandle ModuleNamespaceCreate(JSThread *thread, const JSHandle &module, + const JSHandle &exports); + // 9.4.6.1[[SetPrototypeOf]] + static bool SetPrototype(JSThread *thread, const JSHandle &obj, + const JSHandle &proto); + // 9.4.6.2[[IsExtensible]] + static bool IsExtensible(); + // 9.4.6.3[[PreventExtensions]] + static bool PreventExtensions(); + // 9.4.6.4[[GetOwnProperty]] + static bool GetOwnProperty(JSThread *thread, const JSHandle &obj, const JSHandle &key, + PropertyDescriptor &desc); + // 9.4.6.5[[DefineOwnProperty]] ( P, Desc ) + static bool DefineOwnProperty(JSThread *thread, const JSHandle &obj, + const JSHandle &key, PropertyDescriptor desc); + // 9.4.6.6[[HasProperty]] + static bool HasProperty(JSThread *thread, const JSHandle &obj, const JSHandle &key); + // 9.4.6.7[[Get]] ( P, Receiver ) + static OperationResult GetProperty(JSThread *thread, const JSHandle &obj, + const JSHandle &key); + // 9.4.6.8[[Set]] ( P, V, Receiver ) + static bool SetProperty(JSThread *thread, bool mayThrow); + // 9.4.6.9[[Delete]] ( P ) + static bool DeleteProperty(JSThread *thread, const JSHandle &obj, + const JSHandle &key); + // 9.4.6.10[[OwnPropertyKeys]] + static JSHandle OwnPropertyKeys(JSThread *thread, const JSHandle &proxy); + + bool ValidateKeysAvailable(JSThread *thread, const JSHandle &exports); + + static constexpr size_t MODULE_OFFSET = JSObject::SIZE; + ACCESSORS(Module, MODULE_OFFSET, EXPORTS_OFFSET) + ACCESSORS(Exports, EXPORTS_OFFSET, SIZE) + + DECL_DUMP() + DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, MODULE_OFFSET, SIZE) +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_MODULE_JS_MODULE_NAMESPACE_H diff --git a/ecmascript/module/js_module_record.cpp b/ecmascript/module/js_module_record.cpp new file mode 100644 index 00000000..38910f05 --- /dev/null +++ b/ecmascript/module/js_module_record.cpp @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#include "ecmascript/module/js_module_record.h" +#include "ecmascript/module/js_module_source_text.h" + +namespace panda::ecmascript { +int32_t ModuleRecord::Instantiate(JSThread *thread, const JSHandle &module) +{ + if (module->IsSourceTextModule()) { + JSHandle moduleRecord = JSHandle::Cast(module); + return SourceTextModule::Instantiate(thread, moduleRecord); + } + UNREACHABLE(); +} + +int32_t ModuleRecord::Evaluate(JSThread *thread, const JSHandle &module) +{ + if (module->IsSourceTextModule()) { + JSHandle moduleRecord = JSHandle::Cast(module); + return SourceTextModule::Evaluate(thread, moduleRecord); + } + UNREACHABLE(); +} + +JSTaggedValue ModuleRecord::GetNamespace(JSTaggedValue module) +{ + if (module.IsSourceTextModule()) { + return SourceTextModule::Cast(module.GetHeapObject())->GetNamespace(); + } + UNREACHABLE(); +} + +void ModuleRecord::SetNamespace(JSThread *thread, JSTaggedValue module, JSTaggedValue value) +{ + if (module.IsSourceTextModule()) { + SourceTextModule::Cast(module.GetHeapObject())->SetNamespace(thread, value); + } else { + UNREACHABLE(); + } +} +} // namespace panda::ecmascript \ No newline at end of file diff --git a/ecmascript/module/js_module_record.h b/ecmascript/module/js_module_record.h new file mode 100644 index 00000000..0033d079 --- /dev/null +++ b/ecmascript/module/js_module_record.h @@ -0,0 +1,36 @@ +/* + * 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_RECORD_H +#define ECMASCRIPT_MODULE_JS_MODULE_RECORD_H + +#include "ecmascript/js_tagged_value-inl.h" +#include "ecmascript/record.h" + +namespace panda::ecmascript { +class ModuleRecord : public Record { +public: + CAST_CHECK(ModuleRecord, IsModuleRecord); + + // 15.2.1.16.4 Instantiate() + static int Instantiate(JSThread *thread, const JSHandle &module); + // 15.2.1.16.5 Evaluate() + static int Evaluate(JSThread *thread, const JSHandle &module); + + static JSTaggedValue GetNamespace(JSTaggedValue module); + static void SetNamespace(JSThread *thread, JSTaggedValue module, JSTaggedValue value); +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_MODULE_JS_MODULE_RECORD_H diff --git a/ecmascript/module/js_module_source_text.cpp b/ecmascript/module/js_module_source_text.cpp new file mode 100644 index 00000000..4fac66b5 --- /dev/null +++ b/ecmascript/module/js_module_source_text.cpp @@ -0,0 +1,869 @@ +/* + * 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. + */ + +#include "ecmascript/module/js_module_source_text.h" + +#include "ecmascript/global_env.h" +#include "ecmascript/base/string_helper.h" +#include "ecmascript/jspandafile/js_pandafile_executor.h" +#include "ecmascript/jspandafile/js_pandafile_manager.h" +#include "ecmascript/jspandafile/module_data_extractor.h" +#include "ecmascript/linked_hash_table.h" +#include "ecmascript/module/js_module_manager.h" +#include "ecmascript/module/js_module_namespace.h" +#include "ecmascript/tagged_dictionary.h" + +namespace panda::ecmascript { +CVector SourceTextModule::GetExportedNames(JSThread *thread, const JSHandle &module, + const JSHandle &exportStarSet) +{ + CVector exportedNames; + // 1. Let module be this Source Text Module Record. + // 2. If exportStarSet contains module, then + if (exportStarSet->GetIdx(module.GetTaggedValue()) != TaggedArray::MAX_ARRAY_INDEX) { + // a. Assert: We've reached the starting point of an import * circularity. + // b. Return a new empty List. + return exportedNames; + } + // 3. Append module to exportStarSet. + size_t len = exportStarSet->GetLength(); + JSHandle newExportStarSet = TaggedArray::SetCapacity(thread, exportStarSet, len + 1); + newExportStarSet->Set(thread, len, module.GetTaggedValue()); + + // 5. For each ExportEntry Record e in module.[[LocalExportEntries]], do + JSTaggedValue entryValue = module->GetLocalExportEntries(); + auto globalConstants = thread->GlobalConstants(); + if (!entryValue.IsUndefined()) { + JSHandle localExportEntries(thread, entryValue); + size_t localExportEntriesLen = localExportEntries->GetLength(); + JSMutableHandle ee(thread, globalConstants->GetUndefined()); + for (size_t idx = 0; idx < localExportEntriesLen; idx++) { + ee.Update(localExportEntries->Get(idx)); + // a. Assert: module provides the direct binding for this export. + // b. Append e.[[ExportName]] to exportedNames. + std::string exportName = + base::StringHelper::ToStdString(EcmaString::Cast(ee->GetExportName().GetHeapObject())); + exportedNames.emplace_back(exportName); + } + } + + // 6. For each ExportEntry Record e in module.[[IndirectExportEntries]], do + entryValue = module->GetIndirectExportEntries(); + if (!entryValue.IsUndefined()) { + JSHandle indirectExportEntries(thread, entryValue); + size_t indirectExportEntriesLen = indirectExportEntries->GetLength(); + JSMutableHandle ee(thread, globalConstants->GetUndefined()); + for (size_t idx = 0; idx < indirectExportEntriesLen; idx++) { + ee.Update(indirectExportEntries->Get(idx)); + // a. Assert: module imports a specific binding for this export. + // b. Append e.[[ExportName]] to exportedNames. + std::string exportName = + base::StringHelper::ToStdString(EcmaString::Cast(ee->GetExportName().GetHeapObject())); + exportedNames.emplace_back(exportName); + } + } + + // 7. For each ExportEntry Record e in module.[[StarExportEntries]], do + entryValue = module->GetStarExportEntries(); + if (!entryValue.IsUndefined()) { + JSHandle starExportEntries(thread, entryValue); + size_t starExportEntriesLen = starExportEntries->GetLength(); + JSMutableHandle ee(thread, globalConstants->GetUndefined()); + JSMutableHandle moduleRequest(thread, globalConstants->GetUndefined()); + for (size_t idx = 0; idx < starExportEntriesLen; idx++) { + ee.Update(starExportEntries->Get(idx)); + // a. Let requestedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]). + moduleRequest.Update(ee->GetModuleRequest()); + JSHandle requestedModule = + SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, exportedNames); + // b. Let starNames be ? requestedModule.GetExportedNames(exportStarSet). + CVector starNames = + SourceTextModule::GetExportedNames(thread, requestedModule, newExportStarSet); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, exportedNames); + // c. For each element n of starNames, do + for (std::string &nn : starNames) { + // i. If SameValue(n, "default") is false, then + if (nn != "default" && + std::find(exportedNames.begin(), exportedNames.end(), nn) == exportedNames.end()) { + // 1. If n is not an element of exportedNames, then + // a. Append n to exportedNames. + exportedNames.emplace_back(nn); + } + } + } + } + return exportedNames; +} + +JSHandle SourceTextModule::HostResolveImportedModule(JSThread *thread, + const JSHandle &module, + const JSHandle &moduleRequest) +{ + std::string moduleFilename = base::StringHelper::ToStdString(EcmaString::Cast(moduleRequest->GetHeapObject())); + ASSERT(module->GetEcmaModuleFilename().IsHeapObject()); + std::string baseFilename = + base::StringHelper::ToStdString(EcmaString::Cast(module->GetEcmaModuleFilename().GetHeapObject())); + int suffixEnd = moduleFilename.find_last_of('.'); + if (suffixEnd == -1) { + RETURN_HANDLE_IF_ABRUPT_COMPLETION(SourceTextModule, thread); + } + std::string moduleFullname; + if (moduleFilename[0] == '/') { // absoluteFilePath + moduleFullname = moduleFilename.substr(0, suffixEnd) + ".abc"; + } else { + int pos = baseFilename.find_last_of('/'); + if (pos == -1) { + RETURN_HANDLE_IF_ABRUPT_COMPLETION(SourceTextModule, thread); + } + moduleFullname = baseFilename.substr(0, pos + 1) + moduleFilename.substr(0, suffixEnd) + ".abc"; + } + return thread->GetEcmaVM()->GetModuleManager()->HostResolveImportedModule(moduleFullname); +} + +JSHandle SourceTextModule::ResolveExport(JSThread *thread, const JSHandle &module, + const JSHandle &exportName, + CVector, JSHandle>> &resolveSet) +{ + // 1. Let module be this Source Text Module Record. + // 2. For each Record { [[Module]], [[ExportName]] } r in resolveSet, do + auto globalConstants = thread->GlobalConstants(); + for (auto rr : resolveSet) { + // a. If module and r.[[Module]] are the same Module Record and + // SameValue(exportName, r.[[ExportName]]) is true, then + if (JSTaggedValue::SameValue(rr.first.GetTaggedValue(), module.GetTaggedValue()) && + JSTaggedValue::SameValue(rr.second, exportName)) { + // i. Assert: This is a circular import request. + // ii. Return null. + return globalConstants->GetHandledNull(); + } + } + // 3. Append the Record { [[Module]]: module, [[ExportName]]: exportName } to resolveSet. + resolveSet.emplace_back(std::make_pair(module, exportName)); + // 4. For each ExportEntry Record e in module.[[LocalExportEntries]], do + JSTaggedValue localExportEntriesTv = module->GetLocalExportEntries(); + if (!localExportEntriesTv.IsUndefined()) { + JSHandle localExportEntries(thread, localExportEntriesTv); + size_t localExportEntriesLen = localExportEntries->GetLength(); + JSMutableHandle ee(thread, globalConstants->GetUndefined()); + JSMutableHandle localName(thread, globalConstants->GetUndefined()); + for (size_t idx = 0; idx < localExportEntriesLen; idx++) { + ee.Update(localExportEntries->Get(idx)); + // a. If SameValue(exportName, e.[[ExportName]]) is true, then + if (JSTaggedValue::SameValue(ee->GetExportName(), exportName.GetTaggedValue())) { + // i. Assert: module provides the direct binding for this export. + // ii. Return ResolvedBinding Record { [[Module]]: module, [[BindingName]]: e.[[LocalName]] }. + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + localName.Update(ee->GetLocalName()); + return JSHandle::Cast(factory->NewResolvedBindingRecord(module, localName)); + } + } + } + // 5. For each ExportEntry Record e in module.[[IndirectExportEntries]], do + JSTaggedValue indirectExportEntriesTv = module->GetIndirectExportEntries(); + if (!indirectExportEntriesTv.IsUndefined()) { + JSHandle indirectExportEntries(thread, indirectExportEntriesTv); + size_t indirectExportEntriesLen = indirectExportEntries->GetLength(); + JSMutableHandle ee(thread, globalConstants->GetUndefined()); + JSMutableHandle moduleRequest(thread, globalConstants->GetUndefined()); + JSMutableHandle importName(thread, globalConstants->GetUndefined()); + for (size_t idx = 0; idx < indirectExportEntriesLen; idx++) { + ee.Update(indirectExportEntries->Get(idx)); + // a. If SameValue(exportName, e.[[ExportName]]) is true, then + if (JSTaggedValue::SameValue(exportName.GetTaggedValue(), ee->GetExportName())) { + // i. Assert: module imports a specific binding for this export. + // ii. Let importedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]). + moduleRequest.Update(ee->GetModuleRequest()); + JSHandle requestedModule = + SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest); + RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); + // iii. Return importedModule.ResolveExport(e.[[ImportName]], resolveSet). + importName.Update(ee->GetImportName()); + return SourceTextModule::ResolveExport(thread, requestedModule, importName, resolveSet); + } + } + } + + // 6. If SameValue(exportName, "default") is true, then + JSHandle defaultString = globalConstants->GetHandledDefaultString(); + if (JSTaggedValue::SameValue(exportName, defaultString)) { + // a. Assert: A default export was not explicitly defined by this module. + // b. Return null. + // c. NOTE: A default export cannot be provided by an export *. + return globalConstants->GetHandledNull(); + } + // 7. Let starResolution be null. + JSMutableHandle starResolution(thread, globalConstants->GetNull()); + // 8. For each ExportEntry Record e in module.[[StarExportEntries]], do + JSTaggedValue starExportEntriesTv = module->GetStarExportEntries(); + if (starExportEntriesTv.IsUndefined()) { + return starResolution; + } + JSHandle starExportEntries(thread, starExportEntriesTv); + size_t starExportEntriesLen = starExportEntries->GetLength(); + JSMutableHandle ee(thread, globalConstants->GetUndefined()); + JSMutableHandle moduleRequest(thread, globalConstants->GetUndefined()); + for (size_t idx = 0; idx < starExportEntriesLen; idx++) { + ee.Update(starExportEntries->Get(idx)); + // a. Let importedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]). + moduleRequest.Update(ee->GetModuleRequest()); + JSHandle importedModule = + SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest); + RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); + // b. Let resolution be ? importedModule.ResolveExport(exportName, resolveSet). + JSHandle resolution = + SourceTextModule::ResolveExport(thread, importedModule, exportName, resolveSet); + RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); + // c. If resolution is "ambiguous", return "ambiguous". + if (resolution->IsString()) { // if resolution is string, resolution must be "ambiguous" + return globalConstants->GetHandledAmbiguousString(); + } + // d. If resolution is not null, then + if (resolution->IsNull()) { + continue; + } + // i. Assert: resolution is a ResolvedBinding Record. + ASSERT(resolution->IsResolvedBinding()); + // ii. If starResolution is null, set starResolution to resolution. + if (starResolution->IsNull()) { + starResolution.Update(resolution.GetTaggedValue()); + } else { + // 1. Assert: There is more than one * import that includes the requested name. + // 2. If resolution.[[Module]] and starResolution.[[Module]] are not the same Module Record or + // SameValue( + // resolution.[[BindingName]], starResolution.[[BindingName]]) is false, return "ambiguous". + JSHandle resolutionBd = JSHandle::Cast(resolution); + JSHandle starResolutionBd = JSHandle::Cast(starResolution); + if ((!JSTaggedValue::SameValue(resolutionBd->GetModule(), starResolutionBd->GetModule())) || + (!JSTaggedValue::SameValue( + resolutionBd->GetBindingName(), starResolutionBd->GetBindingName()))) { + return globalConstants->GetHandledAmbiguousString(); + } + } + } + + // 9. Return starResolution. + return starResolution; +} + +int SourceTextModule::Instantiate(JSThread *thread, const JSHandle &module) +{ + // 1. Let module be this Source Text Module Record. + // 2. Assert: module.[[Status]] is not "instantiating" or "evaluating". + ModuleStatus status = module->GetStatus(); + ASSERT(status != ModuleStatus::INSTANTIATING && status != ModuleStatus::EVALUATING); + // 3. Let stack be a new empty List. + CVector> stack; + // 4. Let result be InnerModuleInstantiation(module, stack, 0). + JSHandle moduleRecord = JSHandle::Cast(module); + int result = SourceTextModule::InnerModuleInstantiation(thread, moduleRecord, stack, 0); + // 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 "instantiating". + [[maybe_unused]] ModuleStatus mmStatus = mm->GetStatus(); + ASSERT(mmStatus == ModuleStatus::INSTANTIATING); + // ii. Set m.[[Status]] to "uninstantiated". + mm->SetStatus(ModuleStatus::UNINSTANTIATED); + // iii. Set m.[[Environment]] to undefined. + // iv. Set m.[[DFSIndex]] to undefined. + mm->SetDFSIndex(SourceTextModule::UNDEFINED_INDEX); + // v. Set m.[[DFSAncestorIndex]] to undefined. + mm->SetDFSAncestorIndex(SourceTextModule::UNDEFINED_INDEX); + } + // b. Assert: module.[[Status]] is "uninstantiated". + status = module->GetStatus(); + ASSERT(status == ModuleStatus::UNINSTANTIATED); + // c. return result + return result; + } + // 6. Assert: module.[[Status]] is "instantiated" or "evaluated". + status = module->GetStatus(); + ASSERT(status == ModuleStatus::INSTANTIATED || status == ModuleStatus::EVALUATED); + // 7. Assert: stack is empty. + ASSERT(stack.empty()); + // 8. Return undefined. + return SourceTextModule::UNDEFINED_INDEX; +} + +int SourceTextModule::InnerModuleInstantiation(JSThread *thread, const JSHandle &moduleRecord, + CVector> &stack, int index) +{ + // 1. If module is not a Source Text Module Record, then + if (!moduleRecord.GetTaggedValue().IsSourceTextModule()) { + // a. Perform ? module.Instantiate(). + ModuleRecord::Instantiate(thread, JSHandle::Cast(moduleRecord)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index); + // b. Return index. + return index; + } + JSHandle module = JSHandle::Cast(moduleRecord); + // 2. If module.[[Status]] is "instantiating", "instantiated", or "evaluated", then Return index. + ModuleStatus status = module->GetStatus(); + if (status == ModuleStatus::INSTANTIATING || + status == ModuleStatus::INSTANTIATED || + status == ModuleStatus::EVALUATED) { + return index; + } + // 3. Assert: module.[[Status]] is "uninstantiated". + ASSERT(status == ModuleStatus::UNINSTANTIATED); + // 4. Set module.[[Status]] to "instantiating". + module->SetStatus(ModuleStatus::INSTANTIATING); + // 5. Set module.[[DFSIndex]] to index. + module->SetDFSIndex(index); + // 6. Set module.[[DFSAncestorIndex]] to index. + module->SetDFSAncestorIndex(index); + // 7. Set index to index + 1. + index++; + // 8. Append module to stack. + stack.emplace_back(module); + // 9. For each String required that is an element of module.[[RequestedModules]], do + JSHandle requestedModules(thread, module->GetRequestedModules()); + size_t requestedModulesLen = requestedModules->GetLength(); + JSMutableHandle required(thread, thread->GlobalConstants()->GetUndefined()); + for (size_t idx = 0; idx < requestedModulesLen; idx++) { + required.Update(requestedModules->Get(idx)); + // a. Let requiredModule be ? HostResolveImportedModule(module, required). + JSHandle requiredModule = + SourceTextModule::HostResolveImportedModule(thread, module, required); + // b. Set index to ? InnerModuleInstantiation(requiredModule, stack, index). + JSHandle requiredModuleRecord = JSHandle::Cast(requiredModule); + index = SourceTextModule::InnerModuleInstantiation(thread, requiredModuleRecord, stack, index); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index); + // c. Assert: requiredModule.[[Status]] is either "instantiating", "instantiated", or "evaluated". + ModuleStatus requiredModuleStatus = requiredModule->GetStatus(); + ASSERT((requiredModuleStatus == ModuleStatus::INSTANTIATING || + requiredModuleStatus == ModuleStatus::INSTANTIATED || 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) { + // d. Assert: requiredModule.[[Status]] is "instantiating" if and only if requiredModule is in stack. + ASSERT(std::find(stack.begin(), stack.end(), requiredModule) != stack.end()); + // i. Assert: requiredModule is a Source Text Module Record. + // ii. Set module.[[DFSAncestorIndex]] to min( + // module.[[DFSAncestorIndex]], requiredModule.[[DFSAncestorIndex]]). + int dfsAncIdx = std::min(module->GetDFSAncestorIndex(), requiredModule->GetDFSAncestorIndex()); + module->SetDFSAncestorIndex(dfsAncIdx); + } + } + // 10. Perform ? ModuleDeclarationEnvironmentSetup(module). + SourceTextModule::ModuleDeclarationEnvironmentSetup(thread, module); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index); + // 11. Assert: module occurs exactly once in stack. + // 12. Assert: module.[[DFSAncestorIndex]] is less than or equal to module.[[DFSIndex]]. + int dfsAncIdx = module->GetDFSAncestorIndex(); + int dfsIdx = module->GetDFSIndex(); + ASSERT(dfsAncIdx <= dfsIdx); + // 13. If module.[[DFSAncestorIndex]] equals module.[[DFSIndex]], then + if (dfsAncIdx == dfsIdx) { + // a. Let done be false. + bool done = false; + // b. Repeat, while done is false, + while (!done) { + // i. Let requiredModule be the last element in stack. + JSHandle requiredModule = stack.back(); + // ii. Remove the last element of stack. + stack.pop_back(); + // iii. Set requiredModule.[[Status]] to "instantiated". + requiredModule->SetStatus(ModuleStatus::INSTANTIATED); + // iv. If requiredModule and module are the same Module Record, set done to true. + if (JSTaggedValue::SameValue(module.GetTaggedValue(), requiredModule.GetTaggedValue())) { + done = true; + } + } + } + return index; +} + +void SourceTextModule::ModuleDeclarationEnvironmentSetup(JSThread *thread, + const JSHandle &module) +{ + auto globalConstants = thread->GlobalConstants(); + // 1. For each ExportEntry Record e in module.[[IndirectExportEntries]], do + JSTaggedValue indirectExportEntriesTv = module->GetIndirectExportEntries(); + if (!indirectExportEntriesTv.IsUndefined()) { + JSHandle indirectExportEntries(thread, indirectExportEntriesTv); + size_t indirectExportEntriesLen = indirectExportEntries->GetLength(); + JSMutableHandle ee(thread, globalConstants->GetUndefined()); + JSMutableHandle exportName(thread, globalConstants->GetUndefined()); + for (size_t idx = 0; idx < indirectExportEntriesLen; idx++) { + ee.Update(indirectExportEntries->Get(idx)); + // a. Let resolution be ? module.ResolveExport(e.[[ExportName]], « »). + exportName.Update(ee->GetExportName()); + CVector, JSHandle>> resolveSet; + JSHandle resolution = + SourceTextModule::ResolveExport(thread, module, exportName, resolveSet); + // b. If resolution is null or "ambiguous", throw a SyntaxError exception. + if (resolution->IsNull() || resolution->IsString()) { + THROW_ERROR(thread, ErrorType::SYNTAX_ERROR, ""); + } + // c. Assert: resolution is a ResolvedBinding Record. + ASSERT(resolution->IsResolvedBinding()); + } + } + + // 2. Assert: All named exports from module are resolvable. + // 3. Let realm be module.[[Realm]]. + // 4. Assert: realm is not undefined. + // 5. Let env be NewModuleEnvironment(realm.[[GlobalEnv]]). + JSHandle map = LinkedHashMap::Create(thread); + // 6. Set module.[[Environment]] to env. + module->SetEnvironment(thread, map); + // 7. Let envRec be env's EnvironmentRecord. + JSMutableHandle envRec(thread, module->GetEnvironment()); + ASSERT(!envRec->IsUndefined()); + // 8. For each ImportEntry Record in in module.[[ImportEntries]], do + JSTaggedValue importEntriesTv = module->GetImportEntries(); + if (importEntriesTv.IsUndefined()) { + module->SetEnvironment(thread, envRec); + return; + } + JSHandle importEntries(thread, importEntriesTv); + size_t importEntriesLen = importEntries->GetLength(); + JSMutableHandle in(thread, globalConstants->GetUndefined()); + JSMutableHandle moduleRequest(thread, globalConstants->GetUndefined()); + JSMutableHandle importName(thread, globalConstants->GetUndefined()); + JSMutableHandle localName(thread, globalConstants->GetUndefined()); + for (size_t idx = 0; idx < importEntriesLen; idx++) { + in.Update(importEntries->Get(idx)); + // a. Let importedModule be ! HostResolveImportedModule(module, in.[[ModuleRequest]]). + moduleRequest.Update(in->GetModuleRequest()); + JSHandle importedModule = + SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest); + // c. If in.[[ImportName]] is "*", then + importName.Update(in->GetImportName()); + JSHandle starString = globalConstants->GetHandledStarString(); + if (JSTaggedValue::SameValue(importName, starString)) { + // i. Let namespace be ? GetModuleNamespace(importedModule). + JSHandle moduleNamespace = SourceTextModule::GetModuleNamespace(thread, importedModule); + // ii. Perform ! envRec.CreateImmutableBinding(in.[[LocalName]], true). + // iii. Call envRec.InitializeBinding(in.[[LocalName]], namespace). + JSHandle mapHandle = JSHandle::Cast(envRec); + localName.Update(in->GetLocalName()); + JSHandle newMap = LinkedHashMap::Set(thread, mapHandle, localName, moduleNamespace); + envRec.Update(newMap); + } else { + // i. Let resolution be ? importedModule.ResolveExport(in.[[ImportName]], « »). + CVector, JSHandle>> resolveSet; + JSHandle resolution = + SourceTextModule::ResolveExport(thread, importedModule, importName, resolveSet); + // ii. If resolution is null or "ambiguous", throw a SyntaxError exception. + if (resolution->IsNull() || resolution->IsString()) { + THROW_ERROR(thread, ErrorType::SYNTAX_ERROR, ""); + } + // iii. Call envRec.CreateImportBinding( + // in.[[LocalName]], resolution.[[Module]], resolution.[[BindingName]]). + JSHandle mapHandle = JSHandle::Cast(envRec); + localName.Update(in->GetLocalName()); + JSHandle newMap = LinkedHashMap::Set(thread, mapHandle, localName, resolution); + envRec.Update(newMap); + } + } + module->SetEnvironment(thread, envRec); +} + +JSHandle SourceTextModule::GetModuleNamespace(JSThread *thread, + const JSHandle &module) +{ + 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]]. + JSMutableHandle moduleNamespace(thread, module->GetNamespace()); + // If namespace is undefined, then + if (moduleNamespace->IsUndefined()) { + // a. Let exportedNames be ? module.GetExportedNames(« »). + JSHandle exportStarSet = factory->EmptyArray(); + CVector exportedNames = SourceTextModule::GetExportedNames(thread, module, exportStarSet); + // b. Let unambiguousNames be a new empty List. + JSHandle unambiguousNames = factory->NewTaggedArray(exportedNames.size()); + // c. For each name that is an element of exportedNames, do + size_t idx = 0; + for (std::string &name : exportedNames) { + // i. Let resolution be ? module.ResolveExport(name, « »). + CVector, JSHandle>> resolveSet; + JSHandle nameHandle = JSHandle::Cast(factory->NewFromStdString(name)); + JSHandle resolution = + SourceTextModule::ResolveExport(thread, module, nameHandle, resolveSet); + // ii. If resolution is a ResolvedBinding Record, append name to unambiguousNames. + if (resolution->IsResolvedBinding()) { + unambiguousNames->Set(thread, idx, nameHandle); + idx++; + } + } + JSHandle fixUnambiguousNames = TaggedArray::SetCapacity(thread, unambiguousNames, idx); + JSHandle moduleTagged = JSHandle::Cast(module); + JSHandle np = + ModuleNamespace::ModuleNamespaceCreate(thread, moduleTagged, fixUnambiguousNames); + moduleNamespace.Update(np.GetTaggedValue()); + } + return moduleNamespace; +} + +int SourceTextModule::Evaluate(JSThread *thread, const JSHandle &module) +{ + // 1. Let module be this Source Text Module Record. + // 2. Assert: module.[[Status]] is "instantiated" or "evaluated". + ModuleStatus status = module->GetStatus(); + ASSERT((status == ModuleStatus::INSTANTIATED || status == ModuleStatus::EVALUATED)); + // 3. Let stack be a new empty List. + CVector> stack; + // 4. Let result be InnerModuleEvaluation(module, stack, 0) + JSHandle moduleRecord = JSHandle::Cast(module); + int result = SourceTextModule::InnerModuleEvaluation(thread, moduleRecord, stack, 0); + // 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". + [[maybe_unused]] ModuleStatus mmStatus = mm->GetStatus(); + ASSERT(mmStatus == 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); + // c. return result + return result; + } + // 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; +} + +int SourceTextModule::InnerModuleEvaluation(JSThread *thread, const JSHandle &moduleRecord, + CVector> &stack, int index) +{ + // 1. If module is not a Source Text Module Record, then + if (!moduleRecord.GetTaggedValue().IsSourceTextModule()) { + // a. Perform ? module.Instantiate(). + ModuleRecord::Instantiate(thread, JSHandle::Cast(moduleRecord)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, index); + // b. Return index. + return index; + } + JSHandle module = JSHandle::Cast(moduleRecord); + // 2.If module.[[Status]] is "evaluated", then + ModuleStatus status = module->GetStatus(); + if (status == ModuleStatus::EVALUATED) { + // a. If module.[[EvaluationError]] is undefined, return index. + if (module->GetEvaluationError() == SourceTextModule::UNDEFINED_INDEX) { + return index; + } + // Otherwise return module.[[EvaluationError]]. + return module->GetEvaluationError(); + } + // 3. If module.[[Status]] is "evaluating", return index. + if (status == ModuleStatus::EVALUATING) { + return index; + } + // 4. Assert: module.[[Status]] is "instantiated". + ASSERT(status == ModuleStatus::INSTANTIATED); + // 5. Set module.[[Status]] to "evaluating". + module->SetStatus(ModuleStatus::EVALUATING); + // 6. Set module.[[DFSIndex]] to index. + module->SetDFSIndex(index); + // 7. Set module.[[DFSAncestorIndex]] to index. + module->SetDFSAncestorIndex(index); + // 8. Set index to index + 1. + index++; + // 9. Append module to stack. + stack.emplace_back(module); + // 10. For each String required that is an element of module.[[RequestedModules]], do + JSHandle requestedModules(thread, module->GetRequestedModules()); + size_t requestedModulesLen = requestedModules->GetLength(); + JSMutableHandle required(thread, thread->GlobalConstants()->GetUndefined()); + for (size_t idx = 0; idx < requestedModulesLen; idx++) { + required.Update(requestedModules->Get(idx)); + // a. Let requiredModule be ! HostResolveImportedModule(module, required). + JSHandle requiredModule = + SourceTextModule::HostResolveImportedModule(thread, module, required); + // c. Set index to ? InnerModuleEvaluation(requiredModule, stack, index). + JSHandle requiredModuleRecord = JSHandle::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". + 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. + if (requiredModuleStatus == ModuleStatus::EVALUATING) { + ASSERT(std::find(stack.begin(), stack.end(), requiredModule) != stack.end()); + } + // f. 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]]). + int dfsAncIdx = std::min(module->GetDFSAncestorIndex(), requiredModule->GetDFSAncestorIndex()); + module->SetDFSAncestorIndex(dfsAncIdx); + } + } + // 11. Perform ? ModuleExecution(module). + SourceTextModule::ModuleExecution(thread, module); + 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 dfsAncIdx = module->GetDFSAncestorIndex(); + int dfsIdx = module->GetDFSIndex(); + ASSERT(dfsAncIdx <= dfsIdx); + // 14. If module.[[DFSAncestorIndex]] equals module.[[DFSIndex]], then + if (dfsAncIdx == dfsIdx) { + // a. Let done be false. + bool done = false; + // b. Repeat, while done is false, + while (!done) { + // i. Let requiredModule be the last element in stack. + JSHandle 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. + if (JSTaggedValue::SameValue(module.GetTaggedValue(), requiredModule.GetTaggedValue())) { + done = true; + } + } + } + return index; +} + +void SourceTextModule::ModuleExecution(JSThread *thread, const JSHandle &module) +{ + JSTaggedValue moduleFileName = module->GetEcmaModuleFilename(); + ASSERT(moduleFileName.IsString()); + std::string moduleFilenameStr = base::StringHelper::ToStdString(EcmaString::Cast(moduleFileName.GetHeapObject())); + const JSPandaFile *jsPandaFile = EcmaVM::GetJSPandaFileManager()->LoadJSPandaFile(moduleFilenameStr); + if (jsPandaFile == nullptr) { + LOG_ECMA(ERROR) << "open jsPandaFile " << moduleFilenameStr << " error"; + UNREACHABLE(); + } + std::vector argv; + JSPandaFileExecutor::Execute(thread, jsPandaFile, ENTRY_MAIN_FUNCTION, argv); +} + +void SourceTextModule::AddImportEntry(JSThread *thread, const JSHandle &module, + const JSHandle &importEntry) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSTaggedValue importEntries = module->GetImportEntries(); + if (importEntries.IsUndefined()) { + JSHandle array = factory->NewTaggedArray(1); + array->Set(thread, 0, importEntry.GetTaggedValue()); + module->SetImportEntries(thread, array); + } else { + JSHandle entries(thread, importEntries); + size_t len = entries->GetLength(); + JSHandle newEntries = TaggedArray::SetCapacity(thread, entries, len + 1); + newEntries->Set(thread, len, importEntry.GetTaggedValue()); + module->SetImportEntries(thread, newEntries); + } +} + +void SourceTextModule::AddLocalExportEntry(JSThread *thread, const JSHandle &module, + const JSHandle &exportEntry) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSTaggedValue localExportEntries = module->GetLocalExportEntries(); + if (localExportEntries.IsUndefined()) { + JSHandle array = factory->NewTaggedArray(1); + array->Set(thread, 0, exportEntry.GetTaggedValue()); + module->SetLocalExportEntries(thread, array); + } else { + JSHandle entries(thread, localExportEntries); + size_t len = entries->GetLength(); + JSHandle newEntries = TaggedArray::SetCapacity(thread, entries, len + 1); + newEntries->Set(thread, len, exportEntry.GetTaggedValue()); + module->SetLocalExportEntries(thread, newEntries); + } +} + +void SourceTextModule::AddIndirectExportEntry(JSThread *thread, const JSHandle &module, + const JSHandle &exportEntry) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSTaggedValue indirectExportEntries = module->GetIndirectExportEntries(); + if (indirectExportEntries.IsUndefined()) { + JSHandle array = factory->NewTaggedArray(1); + array->Set(thread, 0, exportEntry.GetTaggedValue()); + module->SetIndirectExportEntries(thread, array); + } else { + JSHandle entries(thread, indirectExportEntries); + size_t len = entries->GetLength(); + JSHandle newEntries = TaggedArray::SetCapacity(thread, entries, len + 1); + newEntries->Set(thread, len, exportEntry.GetTaggedValue()); + module->SetIndirectExportEntries(thread, newEntries); + } +} + +void SourceTextModule::AddStarExportEntry(JSThread *thread, const JSHandle &module, + const JSHandle &exportEntry) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSTaggedValue starExportEntries = module->GetStarExportEntries(); + if (starExportEntries.IsUndefined()) { + JSHandle array = factory->NewTaggedArray(1); + array->Set(thread, 0, exportEntry.GetTaggedValue()); + module->SetStarExportEntries(thread, array); + } else { + JSHandle entries(thread, starExportEntries); + size_t len = entries->GetLength(); + JSHandle newEntries = TaggedArray::SetCapacity(thread, entries, len + 1); + newEntries->Set(thread, len, exportEntry.GetTaggedValue()); + module->SetStarExportEntries(thread, newEntries); + } +} + +JSTaggedValue SourceTextModule::GetModuleValue(JSThread *thread, JSTaggedValue key, bool isThrow) +{ + JSTaggedValue dictionary = GetNameDictionary(); + if (dictionary.IsUndefined()) { + if (isThrow) { + THROW_REFERENCE_ERROR_AND_RETURN(thread, "module environment is undefined", JSTaggedValue::Exception()); + } + return JSTaggedValue::Hole(); + } + + NameDictionary *dict = NameDictionary::Cast(dictionary.GetTaggedObject()); + int entry = dict->FindEntry(key); + if (entry != -1) { + return dict->GetValue(entry); + } + + JSTaggedValue importEntriesTv = GetImportEntries(); + if (!importEntriesTv.IsUndefined()) { + TaggedArray *importEntries = TaggedArray::Cast(importEntriesTv.GetTaggedObject()); + size_t importEntriesLen = importEntries->GetLength(); + for (size_t idx = 0; idx < importEntriesLen; idx++) { + ImportEntry *ee = ImportEntry::Cast(importEntries->Get(idx).GetTaggedObject()); + if (!JSTaggedValue::SameValue(ee->GetLocalName(), key)) { + continue; + } + JSTaggedValue importName = ee->GetImportName(); + entry = dict->FindEntry(importName); + if (entry != -1) { + return dict->GetValue(entry); + } + } + } + + JSTaggedValue exportEntriesTv = GetLocalExportEntries(); + if (!exportEntriesTv.IsUndefined()) { + TaggedArray *exportEntries = TaggedArray::Cast(exportEntriesTv.GetTaggedObject()); + size_t exportEntriesLen = exportEntries->GetLength(); + for (size_t idx = 0; idx < exportEntriesLen; idx++) { + ExportEntry *ee = ExportEntry::Cast(exportEntries->Get(idx).GetTaggedObject()); + if (!JSTaggedValue::SameValue(ee->GetLocalName(), key)) { + continue; + } + JSTaggedValue exportName = ee->GetExportName(); + entry = dict->FindEntry(exportName); + if (entry != -1) { + return dict->GetValue(entry); + } + } + } + + return JSTaggedValue::Hole(); +} + +void SourceTextModule::StoreModuleValue(JSThread *thread, const JSHandle &key, + const JSHandle &value) +{ + JSHandle module(thread, this); + JSMutableHandle data(thread, module->GetNameDictionary()); + if (data->IsUndefined()) { + data.Update(NameDictionary::Create(thread, DEAULT_DICTIONART_CAPACITY)); + } + + JSMutableHandle dataDict(data); + JSTaggedValue localExportEntriesTv = module->GetLocalExportEntries(); + auto globalConstants = thread->GlobalConstants(); + if (!localExportEntriesTv.IsUndefined()) { + JSHandle localExportEntries(thread, localExportEntriesTv); + size_t localExportEntriesLen = localExportEntries->GetLength(); + JSMutableHandle ee(thread, globalConstants->GetUndefined()); + JSMutableHandle exportName(thread, globalConstants->GetUndefined()); + for (size_t idx = 0; idx < localExportEntriesLen; idx++) { + ee.Update(localExportEntries->Get(idx)); + if (JSTaggedValue::SameValue(ee->GetLocalName(), key.GetTaggedValue())) { + exportName.Update(ee->GetExportName()); + dataDict.Update(NameDictionary::Put(thread, dataDict, exportName, value, + PropertyAttributes::Default())); + } + } + } + JSTaggedValue indirectExportEntriesTv = module->GetIndirectExportEntries(); + if (!indirectExportEntriesTv.IsUndefined()) { + JSHandle indirectExportEntries(thread, indirectExportEntriesTv); + size_t indirectExportEntriesLen = indirectExportEntries->GetLength(); + JSMutableHandle ee(thread, globalConstants->GetUndefined()); + JSMutableHandle exportName(thread, globalConstants->GetUndefined()); + for (size_t idx = 0; idx < indirectExportEntriesLen; idx++) { + ee.Update(indirectExportEntries->Get(idx)); + if (JSTaggedValue::SameValue(ee->GetImportName(), key.GetTaggedValue())) { + exportName.Update(ee->GetExportName()); + dataDict.Update(NameDictionary::Put(thread, dataDict, exportName, value, + PropertyAttributes::Default())); + } + } + } + module->SetNameDictionary(thread, dataDict); +} + +JSTaggedValue SourceTextModule::FindExportName(JSThread *thread, const JSHandle &localName) +{ + JSHandle module(thread, this); + JSTaggedValue localExportEntriesTv = module->GetLocalExportEntries(); + auto globalConstants = thread->GlobalConstants(); + if (!localExportEntriesTv.IsUndefined()) { + JSHandle localExportEntries(thread, localExportEntriesTv); + size_t localExportEntriesLen = localExportEntries->GetLength(); + JSMutableHandle ee(thread, globalConstants->GetUndefined()); + for (size_t idx = 0; idx < localExportEntriesLen; idx++) { + ee.Update(localExportEntries->Get(idx)); + if (JSTaggedValue::SameValue(ee->GetLocalName(), localName.GetTaggedValue())) { + return ee->GetExportName(); + } + } + } + JSTaggedValue indirectExportEntriesTv = module->GetIndirectExportEntries(); + if (!indirectExportEntriesTv.IsUndefined()) { + JSHandle indirectExportEntries(thread, indirectExportEntriesTv); + size_t indirectExportEntriesLen = indirectExportEntries->GetLength(); + JSMutableHandle ee(thread, globalConstants->GetUndefined()); + for (size_t idx = 0; idx < indirectExportEntriesLen; idx++) { + ee.Update(indirectExportEntries->Get(idx)); + if (JSTaggedValue::SameValue(ee->GetLocalName(), localName.GetTaggedValue())) { + return ee->GetExportName(); + } + } + } + return globalConstants->GetUndefined(); +} +} // namespace panda::ecmascript \ No newline at end of file diff --git a/ecmascript/module/js_module_source_text.h b/ecmascript/module/js_module_source_text.h new file mode 100644 index 00000000..3baac893 --- /dev/null +++ b/ecmascript/module/js_module_source_text.h @@ -0,0 +1,149 @@ +/* + * 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_SOURCE_TEXT_H +#define ECMASCRIPT_MODULE_JS_MODULE_SOURCE_TEXT_H + +#include "ecmascript/base/string_helper.h" +#include "ecmascript/mem/c_containers.h" +#include "ecmascript/module/js_module_record.h" +#include "ecmascript/tagged_array.h" + +namespace panda::ecmascript { +enum class ModuleStatus : uint8_t { UNINSTANTIATED = 0x01, INSTANTIATING, INSTANTIATED, EVALUATING, EVALUATED }; + +class ImportEntry final : public Record { +public: + CAST_CHECK(ImportEntry, IsImportEntry); + + static constexpr size_t IMPORT_ENTRY_OFFSET = Record::SIZE; + ACCESSORS(ModuleRequest, IMPORT_ENTRY_OFFSET, MODULE_REQUEST_OFFSET); + ACCESSORS(ImportName, MODULE_REQUEST_OFFSET, IMPORT_NAME_OFFSET); + ACCESSORS(LocalName, IMPORT_NAME_OFFSET, SIZE); + + DECL_DUMP() + DECL_VISIT_OBJECT(IMPORT_ENTRY_OFFSET, SIZE) +}; + +class ExportEntry final : public Record { +public: + CAST_CHECK(ExportEntry, IsExportEntry); + + static constexpr size_t EXPORT_ENTRY_OFFSET = Record::SIZE; + ACCESSORS(ExportName, EXPORT_ENTRY_OFFSET, EXPORT_NAME_OFFSET); + ACCESSORS(ModuleRequest, EXPORT_NAME_OFFSET, MODULE_REQUEST_OFFSET); + ACCESSORS(ImportName, MODULE_REQUEST_OFFSET, IMPORT_NAME_OFFSET); + ACCESSORS(LocalName, IMPORT_NAME_OFFSET, SIZE); + + DECL_DUMP() + DECL_VISIT_OBJECT(EXPORT_ENTRY_OFFSET, SIZE) +}; + +class SourceTextModule final : public ModuleRecord { +public: + static constexpr int UNDEFINED_INDEX = -1; + + CAST_CHECK(SourceTextModule, IsSourceTextModule); + + // 15.2.1.17 Runtime Semantics: HostResolveImportedModule ( referencingModule, specifier ) + static JSHandle HostResolveImportedModule(JSThread *thread, + const JSHandle &module, + const JSHandle &moduleRequest); + + // 15.2.1.16.2 GetExportedNames(exportStarSet) + static CVector GetExportedNames(JSThread *thread, const JSHandle &module, + const JSHandle &exportStarSet); + + // 15.2.1.16.3 ResolveExport(exportName, resolveSet) + static JSHandle ResolveExport(JSThread *thread, const JSHandle &module, + const JSHandle &exportName, + CVector, JSHandle>> &resolveSet); + + // 15.2.1.16.4.1 InnerModuleInstantiation ( module, stack, index ) + static int InnerModuleInstantiation(JSThread *thread, const JSHandle &moduleRecord, + CVector> &stack, int index); + + // 15.2.1.16.4.2 ModuleDeclarationEnvironmentSetup ( module ) + static void ModuleDeclarationEnvironmentSetup(JSThread *thread, const JSHandle &module); + + // 15.2.1.16.5.1 InnerModuleEvaluation ( module, stack, index ) + static int InnerModuleEvaluation(JSThread *thread, const JSHandle &moduleRecord, + CVector> &stack, int index); + + // 15.2.1.16.5.2 ModuleExecution ( module ) + static void ModuleExecution(JSThread *thread, const JSHandle &module); + + // 15.2.1.18 Runtime Semantics: GetModuleNamespace ( module ) + static JSHandle GetModuleNamespace(JSThread *thread, const JSHandle &module); + + static void AddImportEntry(JSThread *thread, const JSHandle &module, + const JSHandle &importEntry); + static void AddLocalExportEntry(JSThread *thread, const JSHandle &module, + const JSHandle &exportEntry); + static void AddIndirectExportEntry(JSThread *thread, const JSHandle &module, + const JSHandle &exportEntry); + static void AddStarExportEntry(JSThread *thread, const JSHandle &module, + const JSHandle &exportEntry); + + static constexpr size_t SOURCE_TEXT_MODULE_OFFSET = ModuleRecord::SIZE; + ACCESSORS(Environment, SOURCE_TEXT_MODULE_OFFSET, NAMESPACE_OFFSET); + ACCESSORS(Namespace, NAMESPACE_OFFSET, ECMA_MODULE_FILENAME); + ACCESSORS(EcmaModuleFilename, ECMA_MODULE_FILENAME, REQUESTED_MODULES_OFFSET); + ACCESSORS(RequestedModules, REQUESTED_MODULES_OFFSET, IMPORT_ENTRIES_OFFSET); + ACCESSORS(ImportEntries, IMPORT_ENTRIES_OFFSET, LOCAL_EXPORT_ENTTRIES_OFFSET); + 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_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_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET) + + DEFINE_ALIGN_SIZE(LAST_OFFSET); + + // define BitField + static constexpr size_t STATUS_BITS = 3; + FIRST_BIT_FIELD(BitField, Status, ModuleStatus, STATUS_BITS) + + 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 &module); + + // 15.2.1.16.4 Instantiate() + static int Instantiate(JSThread *thread, const JSHandle &module); + + JSTaggedValue GetModuleValue(JSThread *thread, JSTaggedValue key, bool isThrow); + JSTaggedValue FindExportName(JSThread *thread, const JSHandle &localName); + void StoreModuleValue(JSThread *thread, const JSHandle &key, const JSHandle &value); + + static constexpr size_t DEAULT_DICTIONART_CAPACITY = 4; +}; + +class ResolvedBinding final : public Record { +public: + CAST_CHECK(ResolvedBinding, IsResolvedBinding); + + static constexpr size_t RESOLVED_BINDING_OFFSET = Record::SIZE; + ACCESSORS(Module, RESOLVED_BINDING_OFFSET, MODULE_OFFSET); + ACCESSORS(BindingName, MODULE_OFFSET, SIZE); + + DECL_DUMP() + DECL_VISIT_OBJECT(RESOLVED_BINDING_OFFSET, SIZE) +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_MODULE_JS_MODULE_SOURCE_TEXT_H diff --git a/ecmascript/napi/dfx_jsnapi.cpp b/ecmascript/napi/dfx_jsnapi.cpp index 4fb8f650..871ec74b 100644 --- a/ecmascript/napi/dfx_jsnapi.cpp +++ b/ecmascript/napi/dfx_jsnapi.cpp @@ -16,7 +16,7 @@ #include "ecmascript/napi/include/dfx_jsnapi.h" #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h" #include "ecmascript/dfx/hprof/heap_profiler.h" -#include "ecmascript/ecma_module.h" +#include "ecmascript/base/error_helper.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/mem/c_string.h" #include "ecmascript/mem/heap-inl.h" diff --git a/ecmascript/napi/include/jsnapi.h b/ecmascript/napi/include/jsnapi.h index af5c76e9..20b8b29d 100755 --- a/ecmascript/napi/include/jsnapi.h +++ b/ecmascript/napi/include/jsnapi.h @@ -878,7 +878,7 @@ public: static bool Execute(EcmaVM *vm, const uint8_t *data, int32_t size, const std::string &entry, const std::string &filename = ""); static bool ExecuteModuleFromBuffer(EcmaVM *vm, const void *data, int32_t size, const std::string &file); - static Local GetExportObject(EcmaVM *vm, const std::string &file, const std::string &itemName); + static Local GetExportObject(EcmaVM *vm, const std::string &file, const std::string &key); // ObjectRef Operation static Local GetGlobalObject(const EcmaVM *vm); diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index 685825dc..a8e4d7e1 100755 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -28,13 +28,13 @@ #endif #include "ecmascript/ecma_global_storage-inl.h" #include "ecmascript/ecma_language_context.h" -#include "ecmascript/ecma_module.h" #include "ecmascript/ecma_string.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" #include "ecmascript/internal_call_params.h" #include "ecmascript/interpreter/fast_runtime_stub-inl.h" #include "ecmascript/jobs/micro_job_queue.h" +#include "ecmascript/jspandafile/js_pandafile_executor.h" #include "ecmascript/js_array.h" #include "ecmascript/js_arraybuffer.h" #include "ecmascript/js_dataview.h" @@ -50,6 +50,8 @@ #include "ecmascript/js_thread.h" #include "ecmascript/js_typed_array.h" #include "ecmascript/mem/region.h" +#include "ecmascript/module/js_module_manager.h" +#include "ecmascript/module/js_module_source_text.h" #include "ecmascript/object_factory.h" #include "ecmascript/tagged_array.h" #include "generated/base_options.h" @@ -282,7 +284,8 @@ bool JSNApi::Execute(EcmaVM *vm, const std::string &fileName, const std::string { std::vector argv; LOG_ECMA(DEBUG) << "start to execute ark file" << fileName; - if (!vm->ExecuteFromPf(fileName, entry, argv)) { + JSThread *thread = vm->GetAssociatedJSThread(); + if (!ecmascript::JSPandaFileExecutor::ExecuteFromFile(thread, fileName, entry, argv)) { LOG_ECMA(ERROR) << "Cannot execute ark file '" << fileName << "' with entry '" << entry << "'" << std::endl; return false; @@ -294,7 +297,8 @@ bool JSNApi::Execute(EcmaVM *vm, const uint8_t *data, int32_t size, const std::string &entry, const std::string &filename) { std::vector argv; - if (!vm->ExecuteFromBuffer(data, size, entry, argv, filename)) { + JSThread *thread = vm->GetAssociatedJSThread(); + if (!ecmascript::JSPandaFileExecutor::ExecuteFromBuffer(thread, data, size, entry, argv, filename)) { LOG_ECMA(ERROR) << "Cannot execute ark buffer file '" << filename << "' with entry '" << entry << "'" << std::endl; return false; @@ -468,29 +472,25 @@ void* PromiseRejectInfo::GetData() const bool JSNApi::ExecuteModuleFromBuffer(EcmaVM *vm, const void *data, int32_t size, const std::string &file) { - auto moduleManager = vm->GetModuleManager(); - moduleManager->SetCurrentExportModuleName(file); - // Update Current Module std::vector argv; - if (!vm->ExecuteFromBuffer(data, size, ENTRY_POINTER, argv)) { + JSThread *thread = vm->GetAssociatedJSThread(); + if (!ecmascript::JSPandaFileExecutor::ExecuteFromBuffer(thread, data, size, ENTRY_POINTER, argv, file)) { std::cerr << "Cannot execute panda file from memory" << std::endl; - moduleManager->RestoreCurrentExportModuleName(); return false; } - - // Restore Current Module - moduleManager->RestoreCurrentExportModuleName(); return true; } -Local JSNApi::GetExportObject(EcmaVM *vm, const std::string &file, const std::string &itemName) +Local JSNApi::GetExportObject(EcmaVM *vm, const std::string &file, const std::string &key) { - auto moduleManager = vm->GetModuleManager(); + ecmascript::ModuleManager *moduleManager = vm->GetModuleManager(); + JSThread *thread = vm->GetJSThread(); + JSHandle ecmaModule = moduleManager->HostResolveImportedModule(file); + ObjectFactory *factory = vm->GetFactory(); - JSHandle moduleName(factory->NewFromStdStringUnCheck(file, true)); - JSHandle moduleObj = moduleManager->GetModule(vm->GetJSThread(), moduleName); - JSHandle itemString(factory->NewFromStdString(itemName)); - JSHandle exportObj = moduleManager->GetModuleItem(vm->GetJSThread(), moduleObj, itemString); + JSHandle keyHandle = factory->NewFromStdStringUnCheck(key, true); + + JSHandle exportObj(thread, ecmaModule->GetModuleValue(thread, keyHandle.GetTaggedValue(), false)); return JSNApiHelper::ToLocal(exportObj); } diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index 1216ff11..151da094 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -20,10 +20,7 @@ #include "ecmascript/builtins.h" #include "ecmascript/builtins/builtins_errors.h" #include "ecmascript/builtins/builtins_global.h" -#include "ecmascript/class_info_extractor.h" -#include "ecmascript/class_linker/program_object.h" #include "ecmascript/ecma_macros.h" -#include "ecmascript/ecma_module.h" #include "ecmascript/free_object.h" #include "ecmascript/global_env.h" #include "ecmascript/global_env_constants-inl.h" @@ -38,6 +35,8 @@ #include "ecmascript/jobs/pending_job.h" #include "ecmascript/js_api_queue.h" #include "ecmascript/js_api_queue_iterator.h" +#include "ecmascript/jspandafile/class_info_extractor.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/js_api_tree_map.h" #include "ecmascript/js_api_tree_map_iterator.h" #include "ecmascript/js_api_tree_set.h" @@ -76,6 +75,8 @@ #include "ecmascript/linked_hash_table-inl.h" #include "ecmascript/mem/heap-inl.h" #include "ecmascript/mem/space.h" +#include "ecmascript/module/js_module_namespace.h" +#include "ecmascript/module/js_module_source_text.h" #include "ecmascript/record.h" #include "ecmascript/symbol_table-inl.h" #include "ecmascript/tagged_tree-inl.h" @@ -1676,14 +1677,17 @@ JSHandle ObjectFactory::NewProgram() return p; } -JSHandle ObjectFactory::NewEmptyEcmaModule() +JSHandle ObjectFactory::NewModuleNamespace() { NewObjectHook(); - TaggedObject *header = heap_->AllocateYoungOrHugeObject( - JSHClass::Cast(thread_->GlobalConstants()->GetEcmaModuleClass().GetTaggedObject())); - JSHandle module(thread_, header); - module->SetNameDictionary(thread_, JSTaggedValue::Undefined()); - return module; + JSHandle env = vm_->GetGlobalEnv(); + JSHandle dynclass = JSHandle::Cast(env->GetModuleNamespaceClass()); + JSHandle obj = NewJSObject(dynclass); + + JSHandle moduleNamespace = JSHandle::Cast(obj); + moduleNamespace->SetModule(thread_, JSTaggedValue::Undefined()); + moduleNamespace->SetExports(thread_, JSTaggedValue::Undefined()); + return moduleNamespace; } JSHandle ObjectFactory::GetEmptyString() const @@ -2419,4 +2423,88 @@ JSHandle ObjectFactory::NewJSAPITreeSetIterator(const JSHa iter->SetEntries(thread_, entries); return iter; } + +JSHandle ObjectFactory::NewImportEntry() +{ + JSHandle defautValue = thread_->GlobalConstants()->GetHandledUndefined(); + return NewImportEntry(defautValue, defautValue, defautValue); +} + +JSHandle ObjectFactory::NewImportEntry(const JSHandle &moduleRequest, + const JSHandle &importName, + const JSHandle &localName) +{ + NewObjectHook(); + TaggedObject *header = heap_->AllocateYoungOrHugeObject( + JSHClass::Cast(thread_->GlobalConstants()->GetImportEntryClass().GetTaggedObject())); + JSHandle obj(thread_, header); + obj->SetModuleRequest(thread_, moduleRequest); + obj->SetImportName(thread_, importName); + obj->SetLocalName(thread_, localName); + return obj; +} + +JSHandle ObjectFactory::NewExportEntry() +{ + JSHandle defautValue = thread_->GlobalConstants()->GetHandledUndefined(); + return NewExportEntry(defautValue, defautValue, defautValue, defautValue); +} + +JSHandle ObjectFactory::NewExportEntry(const JSHandle &exportName, + const JSHandle &moduleRequest, + const JSHandle &importName, + const JSHandle &localName) +{ + NewObjectHook(); + TaggedObject *header = heap_->AllocateYoungOrHugeObject( + JSHClass::Cast(thread_->GlobalConstants()->GetExportEntryClass().GetTaggedObject())); + JSHandle obj(thread_, header); + obj->SetExportName(thread_, exportName); + obj->SetModuleRequest(thread_, moduleRequest); + obj->SetImportName(thread_, importName); + obj->SetLocalName(thread_, localName); + return obj; +} + +JSHandle ObjectFactory::NewSourceTextModule() +{ + NewObjectHook(); + TaggedObject *header = heap_->AllocateYoungOrHugeObject( + JSHClass::Cast(thread_->GlobalConstants()->GetSourceTextModuleClass().GetTaggedObject())); + JSHandle obj(thread_, header); + JSTaggedValue undefinedValue = thread_->GlobalConstants()->GetUndefined(); + obj->SetEnvironment(thread_, undefinedValue); + obj->SetNamespace(thread_, undefinedValue); + obj->SetRequestedModules(thread_, undefinedValue); + obj->SetImportEntries(thread_, undefinedValue); + obj->SetLocalExportEntries(thread_, undefinedValue); + obj->SetIndirectExportEntries(thread_, undefinedValue); + obj->SetStarExportEntries(thread_, undefinedValue); + obj->SetNameDictionary(thread_, undefinedValue); + obj->SetDFSIndex(SourceTextModule::UNDEFINED_INDEX); + obj->SetDFSAncestorIndex(SourceTextModule::UNDEFINED_INDEX); + obj->SetEvaluationError(SourceTextModule::UNDEFINED_INDEX); + obj->SetStatus(ModuleStatus::UNINSTANTIATED); + return obj; +} + +JSHandle ObjectFactory::NewResolvedBindingRecord() +{ + JSTaggedValue undefinedValue = thread_->GlobalConstants()->GetUndefined(); + JSHandle ecmaModule(thread_, undefinedValue); + JSHandle bindingName(thread_, undefinedValue); + return NewResolvedBindingRecord(ecmaModule, bindingName); +} + +JSHandle ObjectFactory::NewResolvedBindingRecord(const JSHandle &module, + const JSHandle &bindingName) +{ + NewObjectHook(); + TaggedObject *header = heap_->AllocateYoungOrHugeObject( + JSHClass::Cast(thread_->GlobalConstants()->GetResolvedBindingClass().GetTaggedObject())); + JSHandle obj(thread_, header); + obj->SetModule(thread_, module); + obj->SetBindingName(thread_, bindingName); + return obj; +} } // namespace panda::ecmascript diff --git a/ecmascript/object_factory.h b/ecmascript/object_factory.h index cb1ca2d2..1db8fe1a 100644 --- a/ecmascript/object_factory.h +++ b/ecmascript/object_factory.h @@ -77,7 +77,6 @@ class EcmaVM; class Heap; class ConstantPool; class Program; -class EcmaModule; class LayoutInfo; class JSIntlBoundFunction; class FreeObject; @@ -103,6 +102,11 @@ class JSAPITreeSet; class JSAPITreeMap; class JSAPITreeSetIterator; class JSAPITreeMapIterator; +class ModuleNamespace; +class ImportEntry; +class ExportEntry; +class SourceTextModule; +class ResolvedBinding; namespace job { class MicroJobQueue; @@ -133,7 +137,6 @@ public: JSHandle NewProfileTypeInfo(uint32_t length); JSHandle NewConstantPool(uint32_t capacity); JSHandle NewProgram(); - JSHandle NewEmptyEcmaModule(); JSHandle GetJSError(const ErrorType &errorType, const char *data = nullptr); @@ -395,6 +398,21 @@ public: JSHandle NewJSAPIArrayListIterator(const JSHandle &arrayList); JSHandle NewJSAPITreeMapIterator(const JSHandle &map, IterationKind kind); JSHandle NewJSAPITreeSetIterator(const JSHandle &set, IterationKind kind); + // --------------------------------------module-------------------------------------------- + JSHandle NewModuleNamespace(); + JSHandle NewImportEntry(); + JSHandle NewImportEntry(const JSHandle &moduleRequest, + const JSHandle &importName, + const JSHandle &localName); + JSHandle NewExportEntry(); + JSHandle NewExportEntry(const JSHandle &exportName, + const JSHandle &moduleRequest, + const JSHandle &importName, + const JSHandle &localName); + JSHandle NewSourceTextModule(); + JSHandle NewResolvedBindingRecord(); + JSHandle NewResolvedBindingRecord(const JSHandle &module, + const JSHandle &bindingName); private: friend class GlobalEnv; @@ -467,6 +485,7 @@ private: friend class RuntimeTrampolines; friend class ClassInfoExtractor; friend class TSObjectType; + friend class ModuleDataExtractor; }; class ClassLinkerFactory { diff --git a/ecmascript/runtime_call_id.h b/ecmascript/runtime_call_id.h index 80bf807c..32743319 100644 --- a/ecmascript/runtime_call_id.h +++ b/ecmascript/runtime_call_id.h @@ -179,10 +179,10 @@ namespace panda::ecmascript { V(CreateObjectWithBuffer) \ V(CreateObjectHavingMethod) \ V(SetObjectWithProto) \ - V(ImportModule) \ + V(getmodulenamespace) \ V(StModuleVar) \ V(CopyModule) \ - V(LdModvarByName) \ + V(LdModvarVar) \ V(CreateRegExpWithLiteral) \ V(CreateArrayWithBuffer) \ V(GetNextPropName) \ diff --git a/ecmascript/runtime_trampolines.cpp b/ecmascript/runtime_trampolines.cpp index 917cd7ad..4e8cea70 100644 --- a/ecmascript/runtime_trampolines.cpp +++ b/ecmascript/runtime_trampolines.cpp @@ -517,9 +517,6 @@ DEF_RUNTIME_TRAMPOLINES(CloseIterator) DEF_RUNTIME_TRAMPOLINES(CopyModule) { - RUNTIME_TRAMPOLINES_HEADER(CopyModule); - CONVERT_ARG_TAGGED_CHECKED(srcModule, 0); - SlowRuntimeStub::CopyModule(thread, srcModule); return JSTaggedValue::Hole().GetRawData(); } @@ -999,28 +996,29 @@ DEF_RUNTIME_TRAMPOLINES(UpFrame) return JSTaggedValue(static_cast(0)).GetRawData(); } -DEF_RUNTIME_TRAMPOLINES(ImportModule) +DEF_RUNTIME_TRAMPOLINES(GetModuleNamespace) { - RUNTIME_TRAMPOLINES_HEADER(ImportModule); - CONVERT_ARG_TAGGED_CHECKED(moduleName, 0); - return SlowRuntimeStub::ImportModule(thread, moduleName).GetRawData(); + RUNTIME_TRAMPOLINES_HEADER(GetModuleNamespace); + CONVERT_ARG_TAGGED_CHECKED(localName, 0); + return SlowRuntimeStub::GetModuleNamespace(thread, localName).GetRawData(); } DEF_RUNTIME_TRAMPOLINES(StModuleVar) { RUNTIME_TRAMPOLINES_HEADER(StModuleVar); - CONVERT_ARG_TAGGED_CHECKED(exportName, 0); - CONVERT_ARG_TAGGED_CHECKED(exportObj, 1); - SlowRuntimeStub::StModuleVar(thread, exportName, exportObj); + CONVERT_ARG_TAGGED_CHECKED(key, 0); + CONVERT_ARG_TAGGED_CHECKED(value, 1); + SlowRuntimeStub::StModuleVar(thread, key, value); return JSTaggedValue::Hole().GetRawData(); } -DEF_RUNTIME_TRAMPOLINES(LdModvarByName) +DEF_RUNTIME_TRAMPOLINES(LdModuleVar) { - RUNTIME_TRAMPOLINES_HEADER(LdModvarByName); - CONVERT_ARG_TAGGED_CHECKED(moduleObj, 0); - CONVERT_ARG_TAGGED_CHECKED(itemName, 1); - return SlowRuntimeStub::LdModvarByName(thread, moduleObj, itemName).GetRawData(); + RUNTIME_TRAMPOLINES_HEADER(LdModuleVar); + CONVERT_ARG_TAGGED_CHECKED(key, 0); + CONVERT_ARG_TAGGED_CHECKED(taggedFlag, 1); + bool innerFlag = taggedFlag.GetInt() != 0; + return SlowRuntimeStub::LdModuleVar(thread, JSTaggedValue(key), innerFlag).GetRawData(); } DEF_RUNTIME_TRAMPOLINES(GetPropIterator) diff --git a/ecmascript/snapshot/mem/snapshot.cpp b/ecmascript/snapshot/mem/snapshot.cpp index 1590c555..69da6f79 100644 --- a/ecmascript/snapshot/mem/snapshot.cpp +++ b/ecmascript/snapshot/mem/snapshot.cpp @@ -20,10 +20,10 @@ #include #include -#include "ecmascript/class_linker/program_object.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" #include "ecmascript/jobs/micro_job_queue.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/js_hclass.h" #include "ecmascript/js_thread.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" diff --git a/ecmascript/snapshot/mem/snapshot_serialize.cpp b/ecmascript/snapshot/mem/snapshot_serialize.cpp index 376efccb..de223111 100644 --- a/ecmascript/snapshot/mem/snapshot_serialize.cpp +++ b/ecmascript/snapshot/mem/snapshot_serialize.cpp @@ -52,11 +52,11 @@ #include "ecmascript/builtins/builtins_typedarray.h" #include "ecmascript/builtins/builtins_weak_map.h" #include "ecmascript/builtins/builtins_weak_set.h" -#include "ecmascript/class_linker/program_object.h" #include "ecmascript/containers/containers_arraylist.h" #include "ecmascript/containers/containers_queue.h" #include "ecmascript/containers/containers_treemap.h" #include "ecmascript/containers/containers_treeset.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/global_env.h" #include "ecmascript/js_api_queue_iterator.h" #include "ecmascript/js_api_tree_map_iterator.h" diff --git a/ecmascript/tests/dump_test.cpp b/ecmascript/tests/dump_test.cpp index 87f62735..8bc99213 100644 --- a/ecmascript/tests/dump_test.cpp +++ b/ecmascript/tests/dump_test.cpp @@ -14,14 +14,11 @@ */ #include "ecmascript/accessor_data.h" -#include "ecmascript/class_info_extractor.h" -#include "ecmascript/class_linker/program_object-inl.h" #include "ecmascript/dfx/hprof/heap_profiler.h" #include "ecmascript/dfx/hprof/heap_profiler_interface.h" #include "ecmascript/dfx/hprof/heap_snapshot.h" #include "ecmascript/dfx/hprof/heap_snapshot_json_serializer.h" #include "ecmascript/dfx/hprof/string_hashmap.h" -#include "ecmascript/ecma_module.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_dictionary-inl.h" #include "ecmascript/global_env.h" @@ -32,6 +29,8 @@ #include "ecmascript/jobs/pending_job.h" #include "ecmascript/js_api_queue.h" #include "ecmascript/js_api_queue_iterator.h" +#include "ecmascript/jspandafile/class_info_extractor.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/js_api_tree_map.h" #include "ecmascript/js_api_tree_map_iterator.h" #include "ecmascript/js_api_tree_set.h" @@ -78,6 +77,7 @@ #include "ecmascript/mem/assert_scope-inl.h" #include "ecmascript/mem/c_containers.h" #include "ecmascript/mem/machine_code.h" +#include "ecmascript/module/js_module_source_text.h" #include "ecmascript/object_factory.h" #include "ecmascript/tagged_array.h" #include "ecmascript/tagged_dictionary.h" @@ -252,7 +252,7 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump) break; } case JSType::JS_FUNCTION: { - CHECK_DUMP_FILEDS(JSFunctionBase::SIZE, JSFunction::SIZE, 7) + CHECK_DUMP_FILEDS(JSFunctionBase::SIZE, JSFunction::SIZE, 8) JSHandle jsFunc = globalEnv->GetFunctionFunction(); DUMP_FOR_HANDLE(jsFunc) break; @@ -650,12 +650,6 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump) DUMP_FOR_HANDLE(machineCode) break; } - case JSType::ECMA_MODULE: { - CHECK_DUMP_FILEDS(ECMAObject::SIZE, EcmaModule::SIZE, 1) - JSHandle ecmaModule = factory->NewEmptyEcmaModule(); - DUMP_FOR_HANDLE(ecmaModule) - break; - } case JSType::CLASS_INFO_EXTRACTOR: { #ifdef PANDA_TARGET_64 CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), ClassInfoExtractor::SIZE, 10) @@ -778,6 +772,40 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump) DUMP_FOR_HANDLE(jsTreeSetIter) break; } + case JSType::MODULE_RECORD: { + CHECK_DUMP_FILEDS(Record::SIZE, ModuleRecord::SIZE, 0); + break; + } + case JSType::SOURCE_TEXT_MODULE_RECORD: { + CHECK_DUMP_FILEDS(ModuleRecord::SIZE, SourceTextModule::SIZE, 11); + JSHandle moduleSourceRecord = factory->NewSourceTextModule(); + DUMP_FOR_HANDLE(moduleSourceRecord); + break; + } + case JSType::IMPORTENTRY_RECORD: { + CHECK_DUMP_FILEDS(Record::SIZE, ImportEntry::SIZE, 3); + JSHandle importEntry = factory->NewImportEntry(); + DUMP_FOR_HANDLE(importEntry); + break; + } + case JSType::EXPORTENTRY_RECORD: { + CHECK_DUMP_FILEDS(Record::SIZE, ExportEntry::SIZE, 4); + JSHandle exportEntry = factory->NewExportEntry(); + DUMP_FOR_HANDLE(exportEntry); + break; + } + case JSType::RESOLVEDBINDING_RECORD: { + CHECK_DUMP_FILEDS(Record::SIZE, ResolvedBinding::SIZE, 2); + JSHandle resolvedBinding = factory->NewResolvedBindingRecord(); + DUMP_FOR_HANDLE(resolvedBinding); + break; + } + case JSType::JS_MODULE_NAMESPACE: { + CHECK_DUMP_FILEDS(JSObject::SIZE, ModuleNamespace::SIZE, 2); + JSHandle moduleNamespace = factory->NewModuleNamespace(); + DUMP_FOR_HANDLE(moduleNamespace); + break; + } default: LOG_ECMA_MEM(ERROR) << "JSType " << static_cast(type) << " cannot be dumped."; UNREACHABLE(); diff --git a/ecmascript/tests/ecma_module_test.cpp b/ecmascript/tests/ecma_module_test.cpp index 88ff36a4..e227fc00 100644 --- a/ecmascript/tests/ecma_module_test.cpp +++ b/ecmascript/tests/ecma_module_test.cpp @@ -13,7 +13,6 @@ * limitations under the License. */ -#include "ecmascript/ecma_module.h" #include "ecmascript/global_env.h" #include "ecmascript/js_locale.h" #include "ecmascript/tagged_dictionary.h" @@ -47,421 +46,4 @@ public: ecmascript::EcmaHandleScope *scope {nullptr}; JSThread *thread {nullptr}; }; - -EcmaModule *EcmaModuleCreate(JSThread *thread) -{ - ObjectFactory *objectFactory = thread->GetEcmaVM()->GetFactory(); - JSHandle handleEcmaModule = objectFactory->NewEmptyEcmaModule(); - return *handleEcmaModule; -} - -/* - * Feature: EcmaModule - * Function: AddItem - * SubFunction: GetItem - * FunctionPoints: Add Item To EcmaModule - * CaseDescription: Add an item for a EcmaModule that has called "SetNameDictionary" function in the HWTEST_F_L0, and - * check its value through 'GetItem' function. - */ -HWTEST_F_L0(EcmaModuleTest, AddItem_001) -{ - int numOfElementsDict = 4; - CString cStrItemName = "key1"; - int intItemValue = 1; - JSHandle handleEcmaModule(thread, EcmaModuleCreate(thread)); - JSHandle handleNameDict(NameDictionary::Create(thread, numOfElementsDict)); - JSHandle handleTagValItemName( - thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(cStrItemName)); - JSHandle handleTagValItemValue(thread, JSTaggedValue(intItemValue)); - - handleEcmaModule->SetNameDictionary(thread, handleNameDict); // Call SetNameDictionary in HWTEST_F_L0 - EcmaModule::AddItem(thread, handleEcmaModule, handleTagValItemName, handleTagValItemValue); - EXPECT_EQ(handleEcmaModule->GetItem(thread, handleTagValItemName)->GetNumber(), intItemValue); -} - -/* - * Feature: EcmaModule - * Function: AddItem - * SubFunction: GetItem - * FunctionPoints: Add Item To EcmaModule - * CaseDescription: Add an item for a EcmaModule that has not called "SetNameDictionary" function in the HWTEST_F_L0, - * and check its value through 'GetItem' function. - */ -HWTEST_F_L0(EcmaModuleTest, AddItem_002) -{ - CString cStrItemName = "cStrItemName"; - int intItemValue = 1; - JSHandle handleEcmaModule(thread, EcmaModuleCreate(thread)); - JSHandle handleTagValItemName( - thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(cStrItemName)); - JSHandle handleTagValItemValue(thread, JSTaggedValue(intItemValue)); - - // This EcmaModule calls 'SetNameDictionary' function through 'AddItem' function of "ecma_module.cpp". - EcmaModule::AddItem(thread, handleEcmaModule, handleTagValItemName, handleTagValItemValue); - EXPECT_EQ(handleEcmaModule->GetItem(thread, handleTagValItemName)->GetNumber(), intItemValue); -} - -/* - * Feature: EcmaModule - * Function: RemoveItem - * SubFunction: AddItem/GetItem - * FunctionPoints: Remove Item From EcmaModule - * CaseDescription: Add an item for an empty EcmaModule through 'AddItem' function, then remove the item from the - * EcmaModule through 'RemoveItem' function, finally check whether the item obtained from the - * EcmaModule through 'GetItem' function is undefined. - */ -HWTEST_F_L0(EcmaModuleTest, RemoveItem) -{ - ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory(); - - CString cStrItemName = "cStrItemName"; - int intItemValue = 1; - JSHandle handleEcmaModule(thread, EcmaModuleCreate(thread)); - JSHandle handleTagValItemName(objFactory->NewFromCanBeCompressString(cStrItemName)); - JSHandle handleTagValItemValue(thread, JSTaggedValue(intItemValue)); - - EcmaModule::AddItem(thread, handleEcmaModule, handleTagValItemName, handleTagValItemValue); - EcmaModule::RemoveItem(thread, handleEcmaModule, handleTagValItemName); - EXPECT_TRUE(handleEcmaModule->GetItem(thread, handleTagValItemName)->IsUndefined()); -} - -/* - * Feature: EcmaModule - * Function: SetNameDictionary - * SubFunction: NameDictionary::Put/GetNameDictionary - * FunctionPoints: Set NameDictionary For EcmaModule - * CaseDescription: Create a source key, a source value, a source NameDictionary and a target EcmaModule, change the - * NameDictionary through 'NameDictionary::Put' function, set the changed source NameDictionary as - * this target EcmaModule's NameDictionary through 'SetNameDictionary' function, check whether the - * result returned through 'GetNameDictionary' function from the target EcmaModule are within - * expectations. - */ -HWTEST_F_L0(EcmaModuleTest, SetNameDictionary) -{ - ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory(); - - int numOfElementsDict = 4; - JSHandle handleNameDict(NameDictionary::Create(thread, numOfElementsDict)); - JSHandle handleObjFunc = thread->GetEcmaVM()->GetGlobalEnv()->GetObjectFunction(); - CString keyArray1 = "hello1"; - JSHandle stringKey1 = objFactory->NewFromCanBeCompressString(keyArray1); - JSHandle key1(stringKey1); - JSHandle value1(objFactory - ->NewJSObjectByConstructor(JSHandle(handleObjFunc), handleObjFunc)); - JSHandle handleNameDictionaryFrom( - NameDictionary::Put(thread, handleNameDict, key1, value1, PropertyAttributes::Default())); - JSHandle handleEcmaModule(thread, EcmaModuleCreate(thread)); - - handleEcmaModule->SetNameDictionary(thread, handleNameDictionaryFrom); - JSHandle handleNameDictionaryTo(thread, - NameDictionary::Cast(handleEcmaModule->GetNameDictionary().GetTaggedObject())); - EXPECT_EQ(handleNameDictionaryTo->EntriesCount(), 1); - int entry1 = handleNameDictionaryTo->FindEntry(key1.GetTaggedValue()); - EXPECT_TRUE(key1.GetTaggedValue() == handleNameDictionaryTo->GetKey(entry1)); - EXPECT_TRUE(value1.GetTaggedValue() == handleNameDictionaryTo->GetValue(entry1)); -} - -/* - * Feature: ModuleManager - * Function: AddModule - * SubFunction: AddItem/GetModule/GetItem - * FunctionPoints: Add EcmaModule To ModuleManager - * CaseDescription: Create 2 source EcmaModules that both add an item, create a ModuleManager that add the 2 source - * EcmaModule, check whether the items of EcmaModules obtained from the ModuleManager through - * 'GetModule' function and 'GetItem' function are within expectations. - */ -HWTEST_F_L0(EcmaModuleTest, ModuleManager_AddModule) -{ - ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory(); - ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager(); - - int numOfElementsDict1 = 4; - int numOfElementsDict2 = 4; - CString cStrItemName1 = "cStrItemName1"; - CString cStrItemName2 = "cStrItemName2"; - int intItemValue1 = 1; - int intItemValue2 = 2; - JSHandle handleNameDict1(NameDictionary::Create(thread, numOfElementsDict1)); - JSHandle handleNameDict2(NameDictionary::Create(thread, numOfElementsDict2)); - JSHandle handleItemName1( - thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(cStrItemName1)); - JSHandle handleItemName2( - thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(cStrItemName2)); - JSHandle handleItemValue1(thread, JSTaggedValue(intItemValue1)); - JSHandle handleItemValue2(thread, JSTaggedValue(intItemValue2)); - JSHandle handleEcmaModuleAddFrom1(thread, EcmaModuleCreate(thread)); - JSHandle handleEcmaModuleAddFrom2(thread, EcmaModuleCreate(thread)); - handleEcmaModuleAddFrom1->SetNameDictionary(thread, handleNameDict1); - handleEcmaModuleAddFrom2->SetNameDictionary(thread, handleNameDict2); - - EcmaModule::AddItem(thread, handleEcmaModuleAddFrom1, handleItemName1, handleItemValue1); - JSHandle handleTagValEcmaModuleAddFrom1(thread, handleEcmaModuleAddFrom1.GetTaggedValue()); - std::string stdStrNameEcmaModuleAdd1 = "NameEcmaModule1"; - JSHandle handleTagValNameEcmaModuleAdd1(objFactory->NewFromStdString(stdStrNameEcmaModuleAdd1)); - EcmaModule::AddItem(thread, handleEcmaModuleAddFrom2, handleItemName2, handleItemValue2); - JSHandle handleTagValEcmaModuleAddFrom2(thread, handleEcmaModuleAddFrom2.GetTaggedValue()); - std::string stdStrNameEcmaModuleAdd2 = "NameEcmaModule2"; - JSHandle handleTagValNameEcmaModuleAdd2(objFactory->NewFromStdString(stdStrNameEcmaModuleAdd2)); - - moduleManager->AddModule(handleTagValNameEcmaModuleAdd1, handleTagValEcmaModuleAddFrom1); - moduleManager->AddModule(handleTagValNameEcmaModuleAdd2, handleTagValEcmaModuleAddFrom2); - JSHandle handleTagValEcmaModuleGet1 = moduleManager->GetModule(thread, - handleTagValNameEcmaModuleAdd1); - JSHandle handleTagValEcmaModuleGet2 = moduleManager->GetModule(thread, - handleTagValNameEcmaModuleAdd2); - EXPECT_EQ(JSHandle::Cast(handleTagValEcmaModuleGet1)->GetItem(thread, handleItemName1)->GetNumber(), - intItemValue1); - EXPECT_EQ(JSHandle::Cast(handleTagValEcmaModuleGet2)->GetItem(thread, handleItemName2)->GetNumber(), - intItemValue2); -} - -/* - * Feature: ModuleManager - * Function: RemoveModule - * SubFunction: AddItem/GetModule/AddModule/GetItem - * FunctionPoints: Remove EcmaModule From ModuleManager - * CaseDescription: Create two source EcmaModules that add different items, create a ModuleManager that add the two - * source EcmaModules, check whether the properties of the EcmaModules obtained from the ModuleManager - * through 'GetModule' function are within expectations while removing EcmaModules from the - * ModuleManager through 'RemoveModule' function one by one. - */ -HWTEST_F_L0(EcmaModuleTest, ModuleManager_RemoveModule) -{ - ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory(); - ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager(); - - std::string stdStrNameEcmaModuleAdd1 = "NameEcmaModule1"; - std::string stdStrNameEcmaModuleAdd2 = "NameEcmaModule2"; - int intItemValue1 = 1; - int intItemValue2 = 2; - int numOfElementsDict1 = 4; - int numOfElementsDict2 = 4; - JSHandle handleTagValNameEcmaModuleAdd1(objFactory->NewFromStdString(stdStrNameEcmaModuleAdd1)); - JSHandle handleTagValNameEcmaModuleAdd2(objFactory->NewFromStdString(stdStrNameEcmaModuleAdd2)); - JSHandle handleTagValItemName1(objFactory->NewFromCanBeCompressString("name1")); - JSHandle handleTagValItemName2(objFactory->NewFromCanBeCompressString("name2")); - JSHandle handleTagValItemValue1(thread, JSTaggedValue(intItemValue1)); - JSHandle handleTagValItemValue2(thread, JSTaggedValue(intItemValue2)); - JSHandle handleEcmaModuleAddFrom1(thread, EcmaModuleCreate(thread)); - JSHandle handleEcmaModuleAddFrom2(thread, EcmaModuleCreate(thread)); - JSHandle handleNameDict1(NameDictionary::Create(thread, numOfElementsDict1)); - JSHandle handleNameDict2(NameDictionary::Create(thread, numOfElementsDict2)); - handleEcmaModuleAddFrom1->SetNameDictionary(thread, handleNameDict1); - handleEcmaModuleAddFrom2->SetNameDictionary(thread, handleNameDict2); - EcmaModule::AddItem(thread, handleEcmaModuleAddFrom1, handleTagValItemName1, handleTagValItemValue1); - EcmaModule::AddItem(thread, handleEcmaModuleAddFrom2, handleTagValItemName2, handleTagValItemValue2); - JSHandle handleTaggedValueEcmaModuleAddFrom1(thread, handleEcmaModuleAddFrom1.GetTaggedValue()); - JSHandle handleTaggedValueEcmaModuleAddFrom2(thread, handleEcmaModuleAddFrom2.GetTaggedValue()); - - moduleManager->AddModule(handleTagValNameEcmaModuleAdd1, handleTaggedValueEcmaModuleAddFrom1); - moduleManager->AddModule(handleTagValNameEcmaModuleAdd2, handleTaggedValueEcmaModuleAddFrom2); - EXPECT_EQ(JSHandle::Cast(moduleManager->GetModule(thread, handleTagValNameEcmaModuleAdd1)) - ->GetItem(thread, handleTagValItemName1)->GetNumber(), intItemValue1); - EXPECT_EQ(JSHandle::Cast(moduleManager->GetModule(thread, handleTagValNameEcmaModuleAdd2)) - ->GetItem(thread, handleTagValItemName2)->GetNumber(), intItemValue2); - - moduleManager->RemoveModule(handleTagValNameEcmaModuleAdd1); - EXPECT_TRUE(moduleManager->GetModule(thread, handleTagValNameEcmaModuleAdd1)->IsUndefined()); - EXPECT_EQ(JSHandle::Cast(moduleManager->GetModule(thread, handleTagValNameEcmaModuleAdd2)) - ->GetItem(thread, handleTagValItemName2)->GetNumber(), intItemValue2); - - moduleManager->RemoveModule(handleTagValNameEcmaModuleAdd2); - EXPECT_TRUE(moduleManager->GetModule(thread, handleTagValNameEcmaModuleAdd1)->IsUndefined()); - EXPECT_TRUE(moduleManager->GetModule(thread, handleTagValNameEcmaModuleAdd2)->IsUndefined()); -} - -/* - * Feature: ModuleManager - * Function: SetCurrentExportModuleName - * SubFunction: GetCurrentExportModuleName - * FunctionPoints: Get Current ExportModuleName Of ModuleManager - * CaseDescription: Create a ModuleManager, check whether the ExportModuleName obtained from the ModuleManager through - * 'GetCurrentExportModuleName' function is within expectations while changing the Current - * ExportModuleName of the ModuleManager through 'SetCurrentExportModuleName' function. - */ -HWTEST_F_L0(EcmaModuleTest, ModuleManager_SetCurrentExportModuleName) -{ - ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager(); - - std::string_view strViewNameEcmaModule1 = "NameEcmaModule1"; - std::string_view strViewNameEcmaModule2 = "NameEcmaModule2"; - moduleManager->SetCurrentExportModuleName(strViewNameEcmaModule1); - EXPECT_STREQ(moduleManager->GetCurrentExportModuleName().c_str(), CString(strViewNameEcmaModule1).c_str()); - moduleManager->SetCurrentExportModuleName(strViewNameEcmaModule2); - EXPECT_STREQ(moduleManager->GetCurrentExportModuleName().c_str(), CString(strViewNameEcmaModule2).c_str()); -} - -/* - * Feature: ModuleManager - * Function: GetPrevExportModuleName - * SubFunction: SetCurrentExportModuleName - * FunctionPoints: Get Previous ExportModuleName Of ModuleManager - * CaseDescription: Create a ModuleManager, check whether the previous ExportModuleName obtained from the ModuleManager - * through 'GetPrevExportModuleName' function is within expectations while changing the Current - * ExportModuleName of the ModuleManager through 'SetCurrentExportModuleName' function. - */ -HWTEST_F_L0(EcmaModuleTest, ModuleManager_GetPrevExportModuleName) -{ - ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager(); - - std::string_view strViewNameEcmaModule1 = "NameEcmaModule1"; - std::string_view strViewNameEcmaModule2 = "NameEcmaModule2"; - std::string_view strViewNameEcmaModule3 = "NameEcmaModule3"; - moduleManager->SetCurrentExportModuleName(strViewNameEcmaModule1); - moduleManager->SetCurrentExportModuleName(strViewNameEcmaModule2); - EXPECT_STREQ(moduleManager->GetPrevExportModuleName().c_str(), CString(strViewNameEcmaModule1).c_str()); - moduleManager->SetCurrentExportModuleName(strViewNameEcmaModule3); - EXPECT_STREQ(moduleManager->GetPrevExportModuleName().c_str(), CString(strViewNameEcmaModule2).c_str()); -} - -/* - * Feature: ModuleManager - * Function: RestoreCurrentExportModuleName - * SubFunction: SetCurrentExportModuleName/GetCurrentExportModuleName - * FunctionPoints: Restore Current ExportModuleName Of ModuleManager - * CaseDescription: Create a ModuleManager, check whether the current ExportModuleName obtained from the ModuleManager - * through 'GetCurrentExportModuleName' function is within expectations while changing the Current - * ExportModuleName of the ModuleManager through 'SetCurrentExportModuleName' function and - * 'RestoreCurrentExportModuleName' function. - */ -HWTEST_F_L0(EcmaModuleTest, ModuleManager_RestoreCurrentExportModuleName) -{ - ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager(); - - std::string_view strViewNameEcmaModule1 = "NameEcmaModule1"; - std::string_view strViewNameEcmaModule2 = "NameEcmaModule2"; - std::string_view strViewNameEcmaModule3 = "NameEcmaModule3"; - moduleManager->SetCurrentExportModuleName(strViewNameEcmaModule1); - moduleManager->SetCurrentExportModuleName(strViewNameEcmaModule2); - moduleManager->SetCurrentExportModuleName(strViewNameEcmaModule3); - EXPECT_STREQ(moduleManager->GetCurrentExportModuleName().c_str(), CString(strViewNameEcmaModule3).c_str()); - moduleManager->RestoreCurrentExportModuleName(); - EXPECT_STREQ(moduleManager->GetCurrentExportModuleName().c_str(), CString(strViewNameEcmaModule2).c_str()); - moduleManager->RestoreCurrentExportModuleName(); - EXPECT_STREQ(moduleManager->GetCurrentExportModuleName().c_str(), CString(strViewNameEcmaModule1).c_str()); -} - -/* - * Feature: ModuleManager - * Function: AddModuleItem - * SubFunction: SetCurrentExportModuleName/GetModule/GetModuleItem - * FunctionPoints: Add ModuleItem For Current EcmaModule Of ModuleManager - * CaseDescription: Create a ModuleManager, set the current EcmaModule for the ModuleManager through - * 'SetCurrentExportModuleName' function, add source ModuleItems for the current EcmaModule Of the - * ModuleManager, check whether the ModuleItems obtained through 'GetModuleItem' function from the - * ModuleManager are within expectations. - */ -HWTEST_F_L0(EcmaModuleTest, ModuleManager_AddModuleItem) -{ - ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory(); - ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager(); - - int intItemValue11 = 11; - int intItemValue12 = 12; - int intItemValue21 = 21; - int intItemValue22 = 22; - JSHandle handleTagValItemName11(objFactory->NewFromCanBeCompressString("cStrItemName11")); - JSHandle handleTagValItemName12(objFactory->NewFromCanBeCompressString("cStrItemName12")); - JSHandle handleTagValItemName21(objFactory->NewFromCanBeCompressString("cStrItemName21")); - JSHandle handleTagValItemName22(objFactory->NewFromCanBeCompressString("cStrItemName22")); - JSHandle handleTagValItemValue11(thread, JSTaggedValue(intItemValue11)); - JSHandle handleTagValItemValue12(thread, JSTaggedValue(intItemValue12)); - JSHandle handleTagValItemValue21(thread, JSTaggedValue(intItemValue21)); - JSHandle handleTagValItemValue22(thread, JSTaggedValue(intItemValue22)); - JSHandle handleEcmaStrNameEcmaModule1 = objFactory->NewFromString("cStrNameEcmaModule1"); - JSHandle handleEcmaStrNameEcmaModule2 = objFactory->NewFromString("cStrNameEcmaModule2"); - std::string stdStrModuleFileName1 = JSLocale::ConvertToStdString(handleEcmaStrNameEcmaModule1); - std::string stdStrModuleFileName2 = JSLocale::ConvertToStdString(handleEcmaStrNameEcmaModule2); - JSHandle handleTagValEcmaModuleName1(handleEcmaStrNameEcmaModule1); - JSHandle handleTagValEcmaModuleName2(handleEcmaStrNameEcmaModule2); - - // Test when the module is created through 'NewEmptyEcmaModule' function called at HWTEST_F_L0. - JSHandle handleEcmaModule1(thread, EcmaModuleCreate(thread)); - JSHandle handleTagValEcmaModule1(thread, handleEcmaModule1.GetTaggedValue()); - moduleManager->AddModule(handleTagValEcmaModuleName1, handleTagValEcmaModule1); - moduleManager->SetCurrentExportModuleName(stdStrModuleFileName1); - moduleManager->AddModuleItem(thread, handleTagValItemName11, handleTagValItemValue11); - moduleManager->AddModuleItem(thread, handleTagValItemName12, handleTagValItemValue12); - - EXPECT_EQ(moduleManager->GetModuleItem(thread, handleTagValEcmaModule1, handleTagValItemName11)->GetNumber(), - intItemValue11); - EXPECT_EQ(moduleManager->GetModuleItem(thread, handleTagValEcmaModule1, handleTagValItemName12)->GetNumber(), - intItemValue12); - - // Test when the module is created through 'NewEmptyEcmaModule' function called at "ecma_module.cpp". - moduleManager->SetCurrentExportModuleName(stdStrModuleFileName2); - moduleManager->AddModuleItem(thread, handleTagValItemName21, handleTagValItemValue21); - moduleManager->AddModuleItem(thread, handleTagValItemName22, handleTagValItemValue22); - - JSHandle handleTagValEcmaModule2 = moduleManager->GetModule(thread, handleTagValEcmaModuleName2); - EXPECT_EQ(moduleManager->GetModuleItem(thread, handleTagValEcmaModule1, handleTagValItemName11)->GetNumber(), - intItemValue11); - EXPECT_EQ(moduleManager->GetModuleItem(thread, handleTagValEcmaModule1, handleTagValItemName12)->GetNumber(), - intItemValue12); - EXPECT_EQ(moduleManager->GetModuleItem(thread, handleTagValEcmaModule2, handleTagValItemName21)->GetNumber(), - intItemValue21); - EXPECT_EQ(moduleManager->GetModuleItem(thread, handleTagValEcmaModule2, handleTagValItemName22)->GetNumber(), - intItemValue22); -} - -/* - * Feature: ModuleManager - * Function: CopyModule - * SubFunction: AddItem/SetCurrentExportModuleName/GetModule/GetModuleItem - * FunctionPoints: Copy EcmaModule To ModuleManager - * CaseDescription: Create two source EcmaModules and one target ModuleManager, prepare the two source EcmaModules - * through 'AddItem' function, check whether the the ModuleItems obtained through 'GetModuleItem' from - * the target ModuleManager are within expectations while changing the target ModuleManager through - * 'SetCurrentExportModuleName' function and 'CopyModule' function. - */ -HWTEST_F_L0(EcmaModuleTest, ModuleManager_CopyModule) -{ - ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory(); - ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager(); - - int intItemValue11 = 11; - int intItemValue12 = 12; - int intItemValue21 = 21; - int intItemValue22 = 22; - std::string_view fileNameEcmaModuleCopyTo1 = "fileNameEcmaModuleCopyTo1"; - std::string_view fileNameEcmaModuleCopyTo2 = "fileNameEcmaModuleCopyTo2"; - JSHandle handleTagValItemName11(objFactory->NewFromCanBeCompressString("ItemName11")); - JSHandle handleTagValItemName12(objFactory->NewFromCanBeCompressString("ItemName12")); - JSHandle handleTagValItemName21(objFactory->NewFromCanBeCompressString("ItemName21")); - JSHandle handleTagValItemName22(objFactory->NewFromCanBeCompressString("ItemName22")); - JSHandle handleTagValItemValue11(thread, JSTaggedValue(intItemValue11)); - JSHandle handleTagValItemValue12(thread, JSTaggedValue(intItemValue12)); - JSHandle handleTagValItemValue21(thread, JSTaggedValue(intItemValue21)); - JSHandle handleTagValItemValue22(thread, JSTaggedValue(intItemValue22)); - JSHandle handleEcmaModuleCopyFrom1(thread, EcmaModuleCreate(thread)); - JSHandle handleEcmaModuleCopyFrom2(thread, EcmaModuleCreate(thread)); - JSHandle handleTagValEcmaModuleCopyFrom1(thread, handleEcmaModuleCopyFrom1.GetTaggedValue()); - JSHandle handleTagValEcmaModuleCopyFrom2(thread, handleEcmaModuleCopyFrom2.GetTaggedValue()); - EcmaModule::AddItem(thread, handleEcmaModuleCopyFrom1, handleTagValItemName11, handleTagValItemValue11); - EcmaModule::AddItem(thread, handleEcmaModuleCopyFrom1, handleTagValItemName12, handleTagValItemValue12); - EcmaModule::AddItem(thread, handleEcmaModuleCopyFrom2, handleTagValItemName21, handleTagValItemValue21); - EcmaModule::AddItem(thread, handleEcmaModuleCopyFrom2, handleTagValItemName22, handleTagValItemValue22); - - moduleManager->SetCurrentExportModuleName(fileNameEcmaModuleCopyTo1); - moduleManager->CopyModule(thread, handleTagValEcmaModuleCopyFrom1); - JSHandle handleTagValEcmaModuleCopyTo1 = moduleManager->GetModule(thread, - JSHandle::Cast(objFactory->NewFromString(CString(fileNameEcmaModuleCopyTo1)))); - EXPECT_EQ(intItemValue11, - moduleManager->GetModuleItem(thread, handleTagValEcmaModuleCopyTo1, handleTagValItemName11)->GetNumber()); - EXPECT_EQ(intItemValue12, - moduleManager->GetModuleItem(thread, handleTagValEcmaModuleCopyTo1, handleTagValItemName12)->GetNumber()); - - moduleManager->SetCurrentExportModuleName(fileNameEcmaModuleCopyTo2); - moduleManager->CopyModule(thread, handleTagValEcmaModuleCopyFrom2); - JSHandle handleTagValEcmaModuleCopyTo2 = moduleManager->GetModule(thread, - JSHandle::Cast(objFactory->NewFromString(CString(fileNameEcmaModuleCopyTo2)))); - EXPECT_EQ(intItemValue11, - moduleManager->GetModuleItem(thread, handleTagValEcmaModuleCopyTo1, handleTagValItemName11)->GetNumber()); - EXPECT_EQ(intItemValue12, - moduleManager->GetModuleItem(thread, handleTagValEcmaModuleCopyTo1, handleTagValItemName12)->GetNumber()); - EXPECT_EQ(intItemValue21, - moduleManager->GetModuleItem(thread, handleTagValEcmaModuleCopyTo2, handleTagValItemName21)->GetNumber()); - EXPECT_EQ(intItemValue22, - moduleManager->GetModuleItem(thread, handleTagValEcmaModuleCopyTo2, handleTagValItemName22)->GetNumber()); -} } // namespace panda::ecmascript diff --git a/ecmascript/tooling/interface/debugger_api.cpp b/ecmascript/tooling/interface/debugger_api.cpp index c4c2285f..d13bef58 100644 --- a/ecmascript/tooling/interface/debugger_api.cpp +++ b/ecmascript/tooling/interface/debugger_api.cpp @@ -16,8 +16,8 @@ #include "ecmascript/tooling/interface/debugger_api.h" #include "ecmascript/base/number_helper.h" -#include "ecmascript/class_linker/program_object-inl.h" #include "ecmascript/interpreter/frame_handler.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/js_handle.h" #include "ecmascript/js_method.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" diff --git a/ecmascript/tooling/interface/debugger_api.h b/ecmascript/tooling/interface/debugger_api.h index 05e0900a..612dc93b 100644 --- a/ecmascript/tooling/interface/debugger_api.h +++ b/ecmascript/tooling/interface/debugger_api.h @@ -19,9 +19,9 @@ #include #include "ecmascript/common.h" +#include "ecmascript/jspandafile/scope_info_extractor.h" #include "ecmascript/mem/c_string.h" #include "ecmascript/napi/include/jsnapi.h" -#include "ecmascript/scope_info_extractor.h" #include "ecmascript/lexical_env.h" #include "mem/rendezvous.h" diff --git a/ecmascript/trampoline/asm_defines.h b/ecmascript/trampoline/asm_defines.h index e444ff82..4cd444e6 100644 --- a/ecmascript/trampoline/asm_defines.h +++ b/ecmascript/trampoline/asm_defines.h @@ -17,13 +17,13 @@ #define ECMASCRIPT_ASM_DEFINES_H #ifdef PANDA_TARGET_64 -#define ASM_GLUE_CURRENT_FRAME_OFFSET 2136 -#define ASM_GLUE_RUNTIME_FUNCTIONS_OFFSET 4200 +#define ASM_GLUE_CURRENT_FRAME_OFFSET 2184 +#define ASM_GLUE_RUNTIME_FUNCTIONS_OFFSET 4248 #endif #ifdef PANDA_TARGET_32 -#define ASM_GLUE_CURRENT_FRAME_OFFSET 2136 -#define ASM_GLUE_RUNTIME_FUNCTIONS_OFFSET 3176 +#define ASM_GLUE_CURRENT_FRAME_OFFSET 2184 +#define ASM_GLUE_RUNTIME_FUNCTIONS_OFFSET 3224 #endif #define OPTIMIZE_FRAME_TYPE 0 diff --git a/ecmascript/ts_types/ts_type_table.cpp b/ecmascript/ts_types/ts_type_table.cpp index 941a7ba7..33b44a4f 100644 --- a/ecmascript/ts_types/ts_type_table.cpp +++ b/ecmascript/ts_types/ts_type_table.cpp @@ -12,9 +12,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "ecmascript/class_linker/program_object.h" #include "ecmascript/js_handle.h" -#include "ecmascript/literal_data_extractor.h" +#include "ecmascript/jspandafile/literal_data_extractor.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/object_factory.h" #include "ecmascript/ts_types/ts_loader.h" #include "ecmascript/ts_types/ts_obj_layout_info-inl.h"