diff --git a/BUILD.gn b/BUILD.gn index 014319828c50df80c7383857031cf9751f7a77cb..4d24b422ba61963da33f9067e4f9810327753ac8 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -603,6 +603,7 @@ ecma_source = [ "ecmascript/builtins/builtins_weak_map.cpp", "ecmascript/builtins/builtins_weak_ref.cpp", "ecmascript/builtins/builtins_weak_set.cpp", + "ecmascript/builtins/shared_builtins.cpp", "ecmascript/byte_array.cpp", "ecmascript/ohos/code_decrypt.cpp", "ecmascript/ohos/enable_aot_list_helper.cpp", @@ -779,6 +780,10 @@ ecma_source = [ "ecmascript/mem/parallel_marker.cpp", "ecmascript/mem/partial_gc.cpp", "ecmascript/mem/regexp_cached_chunk.cpp", + "ecmascript/mem/shared_heap/shared_concurrent_sweeper.cpp", + "ecmascript/mem/shared_heap/shared_gc.cpp", + "ecmascript/mem/shared_heap/shared_gc_marker.cpp", + "ecmascript/mem/shared_heap/shared_space.cpp", "ecmascript/mem/stw_young_gc.cpp", "ecmascript/mem/space.cpp", "ecmascript/mem/sparse_space.cpp", @@ -792,9 +797,12 @@ ecma_source = [ "ecmascript/module/js_module_record.cpp", "ecmascript/module/js_module_source_text.cpp", "ecmascript/module/js_module_deregister.cpp", + "ecmascript/module/js_shared_module.cpp", + "ecmascript/module/js_shared_module_manager.cpp", "ecmascript/module/module_data_extractor.cpp", "ecmascript/module/module_path_helper.cpp", "ecmascript/module/napi_module_loader.cpp", + "ecmascript/mutator_lock.cpp", "ecmascript/napi/jsnapi.cpp", "ecmascript/napi/jsnapi_expo.cpp", "ecmascript/object_factory.cpp", @@ -815,6 +823,7 @@ ecma_source = [ "ecmascript/serializer/base_deserializer.cpp", "ecmascript/serializer/base_serializer.cpp", "ecmascript/serializer/value_serializer.cpp", + "ecmascript/shared_object_factory.cpp", "ecmascript/stackmap/ark_stackmap_builder.cpp", "ecmascript/stackmap/ark_stackmap_parser.cpp", "ecmascript/stackmap/litecg/litecg_stackmap_type.cpp", @@ -829,6 +838,8 @@ ecma_source = [ "ecmascript/regexp/regexp_opcode.cpp", "ecmascript/regexp/regexp_parser.cpp", "ecmascript/regexp/regexp_parser_cache.cpp", + "ecmascript/runtime.cpp", + "ecmascript/runtime_lock.cpp", "ecmascript/global_index_map.cpp", "ecmascript/shared_mm/shared_mm.cpp", "ecmascript/tagged_dictionary.cpp", diff --git a/ecmascript/base/tests/string_helper_test.cpp b/ecmascript/base/tests/string_helper_test.cpp index bfb9529a93792dbe30490e6c6ca4a94e4d642e50..f9e5109e023ea85898b6a8c153887a43cc5939c8 100644 --- a/ecmascript/base/tests/string_helper_test.cpp +++ b/ecmascript/base/tests/string_helper_test.cpp @@ -47,6 +47,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/builtins/builtins.cpp b/ecmascript/builtins/builtins.cpp index 46a96a32de2c6cddccc721b8c0e61e6885899975..02ae5ee1e21ac8746daa1d6fc7822f5185ccd870 100644 --- a/ecmascript/builtins/builtins.cpp +++ b/ecmascript/builtins/builtins.cpp @@ -52,9 +52,7 @@ #include "ecmascript/builtins/builtins_set.h" #include "ecmascript/builtins/builtins_sharedarraybuffer.h" #include "ecmascript/builtins/builtins_string.h" -#include "ecmascript/builtins/builtins_shared_function.h" #include "ecmascript/builtins/builtins_string_iterator.h" -#include "ecmascript/builtins/builtins_shared_object.h" #include "ecmascript/builtins/builtins_symbol.h" #include "ecmascript/builtins/builtins_typedarray.h" #include "ecmascript/builtins/builtins_weak_map.h" @@ -98,6 +96,7 @@ #include "ecmascript/marker_cell.h" #include "ecmascript/napi/include/jsnapi.h" #include "ecmascript/object_factory.h" +#include "ecmascript/runtime.h" #ifdef ARK_SUPPORT_INTL #include "ecmascript/builtins/builtins_collator.h" #include "ecmascript/builtins/builtins_date_time_format.h" @@ -136,8 +135,6 @@ using Boolean = builtins::BuiltinsBoolean; using BuiltinsLazyCallback = builtins::BuiltinsLazyCallback; using BuiltinsMap = builtins::BuiltinsMap; using BuiltinsSet = builtins::BuiltinsSet; -using BuiltinsSharedObject = builtins::BuiltinsSharedObject; -using BuiltinsSharedFunction = builtins::BuiltinsSharedFunction; using BuiltinsWeakMap = builtins::BuiltinsWeakMap; using BuiltinsWeakSet = builtins::BuiltinsWeakSet; using BuiltinsWeakRef = builtins::BuiltinsWeakRef; @@ -201,125 +198,12 @@ using SharedArrayBuffer = builtins::BuiltinsSharedArrayBuffer; using BuiltinsAsyncIterator = builtins::BuiltinsAsyncIterator; using AsyncGeneratorObject = builtins::BuiltinsAsyncGenerator; -void Builtins::InitializeSObjectAndSFunction(const JSHandle &env) -{ - [[maybe_unused]] EcmaHandleScope scope(thread_); - const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); - JSHandle nullHandle = globalConst->GetHandledNull(); - // SharedObject.prototype[hclass] - JSHandle sobjPrototypeHClass = factory_->NewEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, - nullHandle); - // SharedObject.prototype - JSHandle sObjFuncPrototype = - factory_->NewJSObjectWithInit(sobjPrototypeHClass); - JSHandle sObjFuncPrototypeVal(sObjFuncPrototype); - // SharedObject.prototype_or_hclass - JSHandle sObjIHClass = - factory_->NewEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, sObjFuncPrototypeVal); - - // SharedFunction.prototype_or_hclass - JSHandle sFuncPrototypeHClass( - factory_->NewEcmaHClass(JSSharedFunction::SIZE, JSType::JS_SHARED_FUNCTION, sObjFuncPrototypeVal)); - InitializeSFunciton(env, sFuncPrototypeHClass); - InitializeSObject(env, sObjIHClass, sObjFuncPrototype); - env->SetSObjectFunctionPrototype(thread_, sObjFuncPrototype); - sObjFuncPrototype->GetJSHClass()->SetExtensible(false); -} - -void Builtins::InitializeSObject(const JSHandle &env, const JSHandle &sObjIHClass, - const JSHandle &sObjFuncPrototype) const -{ - [[maybe_unused]] EcmaHandleScope scope(thread_); - // SharedObject constructor (forbidden use NewBuiltinConstructor) - JSHandle sObjectFunction = - factory_->NewSFunction(env, reinterpret_cast(BuiltinsSharedObject::SharedObjectConstructor), - FunctionKind::BUILTIN_CONSTRUCTOR); - InitializeSCtor(sObjIHClass, sObjectFunction, "SharedObject", FunctionLength::ONE); - env->SetSObjectFunction(thread_, sObjectFunction); - // sObject method. - for (const base::BuiltinFunctionEntry &entry : Object::GetObjectFunctions()) { - SetSFunction(env, JSHandle(sObjectFunction), entry.GetName(), entry.GetEntrypoint(), - entry.GetLength(), entry.GetBuiltinStubId()); - } - // sObject.prototype method - JSHandle sObjFuncPrototypeObj(sObjFuncPrototype); - for (const base::BuiltinFunctionEntry &entry : Object::GetObjectPrototypeFunctions()) { - SetSFunction(env, sObjFuncPrototypeObj, entry.GetName(), entry.GetEntrypoint(), entry.GetLength(), - entry.GetBuiltinStubId()); - } - - // B.2.2.1 sObject.prototype.__proto__ - JSHandle protoKey(factory_->NewFromASCII("__proto__")); - JSHandle protoGetter = - CreateSGetterSetter(env, Object::ProtoGetter, "__proto__", FunctionLength::ZERO); - JSHandle protoSetter = - CreateSGetterSetter(env, Object::ProtoSetter, "__proto__", FunctionLength::ONE); - SetSAccessor(sObjFuncPrototypeObj, protoKey, protoGetter, protoSetter); - sObjectFunction->GetJSHClass()->SetExtensible(false); -} - -void Builtins::InitializeSFunciton(const JSHandle &env, - const JSHandle &sFuncPrototypeHClass) const -{ - [[maybe_unused]] EcmaHandleScope scope(thread_); - // Initialize SharedFunction.prototype - JSHandle sFuncPrototype = factory_->NewJSFunctionByHClass( - reinterpret_cast(Function::FunctionPrototypeInvokeSelf), sFuncPrototypeHClass); - // SharedFunction.prototype.name = "" - SetSFunctionName(sFuncPrototype, thread_->GlobalConstants()->GetHandledEmptyString()); - // SharedFunction.prototype.length = 0 - SetSFunctionLength(sFuncPrototype, FunctionLength::ZERO); - - // SharedFunction.prototype_or_hclass - JSHandle sFuncIHClass = factory_->NewEcmaHClass(JSSharedFunction::SIZE, JSType::JS_SHARED_FUNCTION, - JSHandle(sFuncPrototype)); - sFuncIHClass->SetCallable(true); - sFuncIHClass->SetConstructor(true); - - // new SharedFunction() (forbidden use NewBuiltinConstructor) - JSHandle sFuncFunction = factory_->NewSFunctionByHClass( - reinterpret_cast(BuiltinsSharedFunction::SharedFunctionConstructor), - sFuncIHClass, FunctionKind::BUILTIN_CONSTRUCTOR); - InitializeSCtor(sFuncIHClass, sFuncFunction, "SharedFunction", FunctionLength::ONE); - env->SetSFunctionFunction(thread_, sFuncFunction); - env->SetSFunctionPrototype(thread_, sFuncPrototype); - - JSHandle sFuncPrototypeVal(sFuncPrototype); - JSHandle sConstructorClass = - factory_->NewEcmaHClass(JSSharedFunction::SIZE, JSType::JS_SHARED_FUNCTION, sFuncPrototypeVal); - sConstructorClass->SetConstructor(true); - sConstructorClass->SetCallable(true); - env->SetSConstructorClass(thread_, sConstructorClass); - - JSHandle sNormalFuncClass = - factory_->NewEcmaHClass(JSSharedFunction::SIZE, JSType::JS_SHARED_FUNCTION, sFuncPrototypeVal); - sNormalFuncClass->SetCallable(true); - env->SetSNormalFunctionClass(thread_, sNormalFuncClass); - - JSHandle functionClass = - factory_->CreateSFunctionClassWithoutProto(JSSharedFunction::SIZE, JSType::JS_SHARED_FUNCTION, - env->GetSFunctionPrototype()); - env->SetSFunctionClassWithoutProto(thread_, functionClass); - - JSHandle sFuncPrototypeObj(sFuncPrototype); - SharedStrictModeForbiddenAccessCallerArguments(env, sFuncPrototypeObj); - // Function.prototype method - for (const base::BuiltinFunctionEntry &entry: Function::GetFunctionPrototypeFunctions()) { - SetSFunction(env, sFuncPrototypeObj, entry.GetName(), entry.GetEntrypoint(), - entry.GetLength(), entry.GetBuiltinStubId()); - } - // 19.2.3.5 Function.prototype.toString ( ) - SetSFunction(env, sFuncPrototypeObj, thread_->GlobalConstants()->GetHandledToStringString(), - Function::FunctionPrototypeToString, FunctionLength::ZERO); - sFuncFunction->GetJSHClass()->SetExtensible(false); - sFuncPrototype->GetJSHClass()->SetExtensible(false); -} - void Builtins::Initialize(const JSHandle &env, JSThread *thread, bool lazyInit, bool isRealm) { thread_ = thread; vm_ = thread->GetEcmaVM(); factory_ = vm_->GetFactory(); + sHeap_ = SharedHeap::GetInstance(); [[maybe_unused]] EcmaHandleScope scope(thread_); JSHandle nullHandle(thread, JSTaggedValue::Null()); @@ -444,7 +328,12 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread, bool InitializeBoolean(env, primRefObjHClass); InitializeRegExp(env); InitializeString(env, objFuncPrototypeVal); - InitializeSObjectAndSFunction(env); + auto runtimeGlobalEnv = Runtime::GetInstance()->GetGlobalEnv(); + if (runtimeGlobalEnv.IsHole()) { + InitializeSObjectAndSFunction(env); + } else { + CopySObjectAndSFunction(env, runtimeGlobalEnv); + } JSHandle argumentsClass = factory_->CreateJSArguments(env); env->SetArgumentsClass(thread_, argumentsClass); SetArgumentsSharedAccessor(env); @@ -712,7 +601,7 @@ void Builtins::InitializeSymbol(const JSHandle &env, const JSHandle hasInstanceSymbol(factory_->NewWellKnownSymbolWithChar("Symbol.hasInstance")); + JSHandle hasInstanceSymbol(factory_->NewSWellKnownSymbolWithChar("Symbol.hasInstance")); SetNoneAttributeProperty(symbolFunction, "hasInstance", hasInstanceSymbol); JSHandle isConcatSpreadableSymbol(factory_->NewWellKnownSymbolWithChar("Symbol.isConcatSpreadable")); SetNoneAttributeProperty(symbolFunction, "isConcatSpreadable", isConcatSpreadableSymbol); @@ -2689,8 +2578,9 @@ JSHandle Builtins::NewFunction(const JSHandle &env, const EcmaEntrypoint func, int length, kungfu::BuiltinsStubCSigns::ID builtinId) const { + MemSpaceType methodSpaceType = MemSpaceType::SHARED_NON_MOVABLE; JSHandle function = factory_->NewJSFunction(env, reinterpret_cast(func), - FunctionKind::NORMAL_FUNCTION, builtinId, MemSpaceType::NON_MOVABLE); + FunctionKind::NORMAL_FUNCTION, builtinId, methodSpaceType); JSFunction::SetFunctionLength(thread_, function, JSTaggedValue(length)); JSHandle baseFunction(function); auto globalConst = const_cast(thread_->GlobalConstants()); @@ -3837,103 +3727,6 @@ void Builtins::InitializeDefaultExportOfScript(const JSHandle &env) c return; } -void Builtins::SetSFunctionName(const JSHandle &ctor, std::string_view name) const -{ - JSHandle nameString(factory_->NewFromUtf8(name)); - SetSFunctionName(ctor, nameString); -} - -void Builtins::SetSFunctionName(const JSHandle &ctor, const JSHandle &name) const -{ - const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); - JSHandle nameKey = globalConst->GetHandledNameString(); - PropertyDescriptor nameDesc(thread_, name, false, false, false); - JSObject::DefineOwnProperty(thread_, JSHandle(ctor), nameKey, nameDesc, SCheckMode::SKIP); -} - -void Builtins::SetSFunctionLength(const JSHandle &ctor, int length) const -{ - const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); - JSHandle lengthKeyHandle = globalConst->GetHandledLengthString(); - JSTaggedValue taggedLength(length); - PropertyDescriptor lengthDesc(thread_, JSHandle(thread_, taggedLength), false, false, false); - JSObject::DefineOwnProperty(thread_, JSHandle(ctor), lengthKeyHandle, lengthDesc, SCheckMode::SKIP); -} - -void Builtins::InitializeSCtor(const JSHandle &protoHClass, const JSHandle &ctor, - std::string_view name, int length) const -{ - const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); - SetSFunctionLength(ctor, length); - SetSFunctionName(ctor, name); - - JSHandle constructorKey = globalConst->GetHandledConstructorString(); - PropertyDescriptor descriptor(thread_, JSHandle::Cast(ctor), false, false, false); - JSHandle prototype(thread_, protoHClass->GetProto()); - JSObject::DefineOwnProperty(thread_, prototype, constructorKey, descriptor, SCheckMode::SKIP); - - JSFunction::SetFunctionPrototypeOrInstanceHClass(thread_, ctor, protoHClass.GetTaggedValue()); -} - -JSHandle Builtins::NewSFunction(const JSHandle &env, const JSHandle &key, - EcmaEntrypoint func, int length, - kungfu::BuiltinsStubCSigns::ID builtinId) const -{ - JSHandle function = factory_->NewSFunction(env, reinterpret_cast(func), - FunctionKind::NORMAL_FUNCTION, builtinId, MemSpaceType::NON_MOVABLE); - SetSFunctionLength(function, length); - SetSFunctionName(function, key); - function->GetJSHClass()->SetExtensible(false); - return function; -} - -void Builtins::SetSFunction(const JSHandle &env, const JSHandle &obj, std::string_view key, - EcmaEntrypoint func, int length, kungfu::BuiltinsStubCSigns::ID builtinId) const -{ - JSHandle keyString(factory_->NewFromUtf8(key)); - SetSFunction(env, obj, keyString, func, length, builtinId); -} - -void Builtins::SetSFunction(const JSHandle &env, const JSHandle &obj, - const JSHandle &key, EcmaEntrypoint func, int length, - kungfu::BuiltinsStubCSigns::ID builtinId) const -{ - JSHandle function(NewSFunction(env, key, func, length, builtinId)); - PropertyDescriptor descriptor(thread_, JSHandle(function), false, false, false); - JSObject::DefineOwnProperty(thread_, obj, key, descriptor, SCheckMode::SKIP); -} - -void Builtins::SetSAccessor(const JSHandle &obj, const JSHandle &key, - const JSHandle &getter, const JSHandle &setter) const -{ - JSHandle accessor = factory_->NewAccessorData(); - accessor->SetGetter(thread_, getter); - accessor->SetSetter(thread_, setter); - PropertyAttributes attr = PropertyAttributes::DefaultAccessor(false, false, false); - JSObject::AddAccessor(thread_, JSHandle::Cast(obj), key, accessor, attr); -} - -JSHandle Builtins::CreateSGetterSetter(const JSHandle &env, EcmaEntrypoint func, - std::string_view name, int length) const -{ - JSHandle funcName(factory_->NewFromUtf8(name)); - JSHandle function = NewSFunction(env, funcName, func, length); - return JSHandle(function); -} - -void Builtins::SharedStrictModeForbiddenAccessCallerArguments(const JSHandle &env, - const JSHandle &prototype) const -{ - JSHandle func = - factory_->NewSFunction(env, reinterpret_cast(JSFunction::AccessCallerArgumentsThrowTypeError), - FunctionKind::NORMAL_FUNCTION, kungfu::BuiltinsStubCSigns::INVALID, MemSpaceType::NON_MOVABLE); - - JSHandle caller(factory_->NewFromASCII("caller")); - SetSAccessor(prototype, caller, JSHandle(func), JSHandle(func)); - - JSHandle arguments(factory_->NewFromASCII("arguments")); - SetSAccessor(prototype, arguments, JSHandle(func), JSHandle(func)); -} JSHandle Builtins::CreateArrayUnscopables(JSThread *thread) const { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); @@ -3981,13 +3774,13 @@ JSHandle Builtins::CreateArrayUnscopables(JSThread *thread) const JSHandle valuesKey = globalConst->GetHandledValuesString(); JSObject::CreateDataProperty(thread, unscopableList, valuesKey, trueVal); - + JSHandle toReversedKey((factory->NewFromASCII("toReversed"))); JSObject::CreateDataProperty(thread, unscopableList, toReversedKey, trueVal); - + JSHandle toSortedKey((factory->NewFromASCII("toSorted"))); JSObject::CreateDataProperty(thread, unscopableList, toSortedKey, trueVal); - + JSHandle toSplicedKey((factory->NewFromASCII("toSpliced"))); JSObject::CreateDataProperty(thread, unscopableList, toSplicedKey, trueVal); return JSHandle::Cast(unscopableList); diff --git a/ecmascript/builtins/builtins.h b/ecmascript/builtins/builtins.h index c1fdbaf9921cd0e15c4ddedb5f4d0ef11eef61db..3399b2dbaf944f01948613dc63e73e95033f5525 100644 --- a/ecmascript/builtins/builtins.h +++ b/ecmascript/builtins/builtins.h @@ -50,6 +50,7 @@ private: JSThread *thread_{nullptr}; ObjectFactory *factory_{nullptr}; EcmaVM *vm_{nullptr}; + SharedHeap *sHeap_{nullptr}; JSHandle NewBuiltinConstructor(const JSHandle &env, const JSHandle &prototype, EcmaEntrypoint ctorFunc, std::string_view name, int length, @@ -344,17 +345,28 @@ private: EcmaEntrypoint func, int length) const; void SetNonConstantObject(const JSHandle &obj, std::string_view key, JSHandle &value) const; - void InitializeSObjectAndSFunction(const JSHandle &env); + + // For SharedObject/SharedFunction + void InitializeSObjectAndSFunction(const JSHandle &env) const; + void CopySObjectAndSFunction(const JSHandle &env, const JSTaggedValue &srcEnv) const; void InitializeSObject(const JSHandle &env, const JSHandle &sObjIHClass, - const JSHandle &sObjFuncPrototype) const; - void InitializeSFunciton(const JSHandle &env, - const JSHandle &sFuncPrototypeHClass) const; + const JSHandle &sObjFuncPrototype, + const JSHandle &sFuncPrototype) const; + void InitializeSFunction(const JSHandle &env, + const JSHandle &sFuncPrototype) const; + + JSHandle CreateSObjectFunctionHClass(const JSHandle &sFuncPrototype) const; + JSHandle CreateSObjectPrototypeHClass() const; + JSHandle CreateSFunctionHClass(const JSHandle &sFuncPrototype) const; + JSHandle CreateSFunctionPrototypeHClass(const JSHandle &sObjFuncPrototypeVal) const; + void InitializeSCtor(const JSHandle &protoHClass, const JSHandle &ctor, std::string_view name, int length) const; void SetSFunctionName(const JSHandle &ctor, std::string_view name) const; void SetSFunctionName(const JSHandle &ctor, const JSHandle &name) const; void SetSFunctionLength(const JSHandle &ctor, int length) const; + void SetSFunctionPrototype(const JSHandle &ctor, const JSTaggedValue &prototype) const; JSHandle NewSFunction(const JSHandle &env, const JSHandle &key, EcmaEntrypoint func, int length, @@ -362,18 +374,18 @@ private: kungfu::BuiltinsStubCSigns::INVALID) const; void SetSFunction(const JSHandle &env, const JSHandle &obj, std::string_view key, - EcmaEntrypoint func, int length, kungfu::BuiltinsStubCSigns::ID builtinId = + EcmaEntrypoint func, uint32_t index, int length, kungfu::BuiltinsStubCSigns::ID builtinId = kungfu::BuiltinsStubCSigns::INVALID) const; void SetSFunction(const JSHandle &env, const JSHandle &obj, - const JSHandle &key, EcmaEntrypoint func, int length, + const JSHandle &key, EcmaEntrypoint func, uint32_t index, int length, kungfu::BuiltinsStubCSigns::ID builtinId = kungfu::BuiltinsStubCSigns::INVALID) const; - void SetSAccessor(const JSHandle &obj, const JSHandle &key, + void SetSAccessor(const JSHandle &obj, uint32_t index, const JSHandle &getter, const JSHandle &setter) const; JSHandle CreateSGetterSetter(const JSHandle &env, EcmaEntrypoint func, std::string_view name, int length) const; - void SharedStrictModeForbiddenAccessCallerArguments(const JSHandle &env, + void SharedStrictModeForbiddenAccessCallerArguments(const JSHandle &env, uint32_t &index, const JSHandle &prototype) const; JSHandle CreateArrayUnscopables(JSThread *thread) const; friend class builtins::BuiltinsLazyCallback; diff --git a/ecmascript/builtins/builtins_function.h b/ecmascript/builtins/builtins_function.h index 27233a77e69a7bfe71c3145203e798ac868e38f1..31e6e90167c52fea655402277c1c413c201f6120 100644 --- a/ecmascript/builtins/builtins_function.h +++ b/ecmascript/builtins/builtins_function.h @@ -51,12 +51,40 @@ public: // ecma 19.2.3.6 Function.prototype[@@hasInstance] (V) static JSTaggedValue FunctionPrototypeHasInstance(EcmaRuntimeCallInfo *argv); + static Span> GetFunctionPrototypeProperties() + { + return Span>(FUNCTION_PROTOTYPE_PROPERTIES); + } + + static Span> GetFunctionProperties() + { + return Span>(FUNCTION_PROPERTIES); + } + static Span GetFunctionPrototypeFunctions() { return Span(FUNCTION_PROTOTYPE_FUNCTIONS); } - private: + static constexpr std::array FUNCTION_PROTOTYPE_PROPERTIES = { + std::pair("length", false), + std::pair("name", false), + std::pair("constructor", false), + std::pair("caller", true), + std::pair("arguments", true), + std::pair("apply", false), + std::pair("bind", false), + std::pair("call", false), + std::pair("toString", false), + std::pair("[Symbol.hasInstance]", false), + }; + + static constexpr std::array FUNCTION_PROPERTIES = { + std::pair("length", false), + std::pair("name", false), + std::pair("prototype", false), + }; + #define BUILTIN_FUNCTION_FUNCTION_ENTRY(name, func, length, id) \ base::BuiltinFunctionEntry::Create(name, BuiltinsFunction::func, length, kungfu::BuiltinsStubCSigns::id), diff --git a/ecmascript/builtins/builtins_object.h b/ecmascript/builtins/builtins_object.h index 51dff644a32dd8774204fff18a8c32e6101f29c1..ddb404841e90451657ddeb8ef7cfe0e39db5b2bc 100644 --- a/ecmascript/builtins/builtins_object.h +++ b/ecmascript/builtins/builtins_object.h @@ -180,6 +180,17 @@ public: static JSTaggedValue AssignTaggedValue(JSThread *thread, const JSHandle &source, const JSHandle &toAssign); + + static Span> GetFunctionPrototypeProperties() + { + return Span>(OBJECT_PROTOTYPE_PROPERTIES); + } + + static Span> GetFunctionProperties() + { + return Span>(OBJECT_PROPERTIES); + } + private: #define BUILTIN_OBJECT_FUNCTION_ENTRY(name, func, length, id) \ base::BuiltinFunctionEntry::Create(name, BuiltinsObject::func, length, kungfu::BuiltinsStubCSigns::id), @@ -192,6 +203,24 @@ private: }; #undef BUILTIN_OBJECT_FUNCTION_ENTRY +#define OBJECT_PROPERTIES_PAIR(name, func, length, id) \ + std::pair(name, false), + + static constexpr std::array OBJECT_PROTOTYPE_PROPERTIES = { + std::pair("constructor", false), + BUILTIN_OBJECT_PROTOTYPE_FUNCTIONS(OBJECT_PROPERTIES_PAIR) + std::pair("__proto__", true), + }; + + static constexpr std::array OBJECT_PROPERTIES = { + std::pair("length", false), + std::pair("name", false), + std::pair("prototype", false), + BUILTIN_OBJECT_FUNCTIONS(OBJECT_PROPERTIES_PAIR) + + }; +#undef OBJECT_PROPERTIES_PAIR + static JSTaggedValue ObjectDefineProperties(JSThread *thread, const JSHandle &obj, const JSHandle &prop); static JSTaggedValue GetOwnPropertyKeys(JSThread *thread, const JSHandle &obj, const KeyType &type); diff --git a/ecmascript/builtins/shared_builtins.cpp b/ecmascript/builtins/shared_builtins.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b9344cf978a260982fc808b56202d53ece52c935 --- /dev/null +++ b/ecmascript/builtins/shared_builtins.cpp @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2023 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/builtins/builtins.h" + +#include "ecmascript/builtins/builtins_function.h" +#include "ecmascript/builtins/builtins_object.h" +#include "ecmascript/builtins/builtins_shared_function.h" +#include "ecmascript/builtins/builtins_shared_object.h" + +namespace panda::ecmascript { +using BuiltinsSharedObject = builtins::BuiltinsSharedObject; +using BuiltinsSharedFunction = builtins::BuiltinsSharedFunction; +using Function = builtins::BuiltinsFunction; +using Object = builtins::BuiltinsObject; + +void Builtins::InitializeSObjectAndSFunction(const JSHandle &env) const +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + // SharedObject.prototype[hclass] + JSHandle sobjPrototypeHClass = CreateSObjectPrototypeHClass(); + // SharedObject.prototype + JSHandle sObjFuncPrototype = + factory_->NewSharedOldSpaceJSObject(sobjPrototypeHClass); + JSHandle sObjFuncPrototypeVal(sObjFuncPrototype); + // SharedObject.prototype_or_hclass + auto emptySLayout = thread_->GlobalConstants()->GetHandledEmptySLayoutInfo(); + JSHandle sObjIHClass = + factory_->NewSEcmaHClass(JSSharedObject::SIZE, 0, JSType::JS_SHARED_OBJECT, sObjFuncPrototypeVal, + emptySLayout); + // SharedFunction.prototype_or_hclass + JSHandle sFuncPrototypeHClass = CreateSFunctionPrototypeHClass(sObjFuncPrototypeVal); + // SharedFunction.prototype + JSHandle sFuncPrototype = factory_->NewSFunctionByHClass( + reinterpret_cast(Function::FunctionPrototypeInvokeSelf), sFuncPrototypeHClass, + FunctionKind::NORMAL_FUNCTION); + InitializeSFunction(env, sFuncPrototype); + InitializeSObject(env, sObjIHClass, sObjFuncPrototype, sFuncPrototype); + env->SetSObjectFunctionPrototype(thread_, sObjFuncPrototype); +} + +void Builtins::CopySObjectAndSFunction(const JSHandle &env, const JSTaggedValue &srcEnv) const +{ + // Copy shareds. + ASSERT(srcEnv.IsJSGlobalEnv()); + auto sGlobalEnv = reinterpret_cast(srcEnv.GetTaggedObject()); +#define COPY_ENV_SHARED_FIELDS(Type, Name, INDEX) \ + env->Set##Name(thread_, sGlobalEnv->Get##Name()); + GLOBAL_ENV_SHARED_FIELDS(COPY_ENV_SHARED_FIELDS) +#undef COPY_ENV_SHARED_FIELDS +} + +void Builtins::InitializeSObject(const JSHandle &env, const JSHandle &sObjIHClass, + const JSHandle &sObjFuncPrototype, + const JSHandle &sFuncPrototype) const +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + // SharedObject constructor (forbidden use NewBuiltinConstructor) + JSHandle sObjectFunctionHClass = CreateSObjectFunctionHClass(sFuncPrototype); + JSHandle sObjectFunction = + factory_->NewSFunctionByHClass(reinterpret_cast(BuiltinsSharedObject::SharedObjectConstructor), + sObjectFunctionHClass, FunctionKind::BUILTIN_CONSTRUCTOR); + + InitializeSCtor(sObjIHClass, sObjectFunction, "SharedObject", FunctionLength::ONE); + env->SetSObjectFunction(thread_, sObjectFunction); + // sObject method. + uint32_t fieldIndex = JSFunction::PROTOTYPE_INLINE_PROPERTY_INDEX + 1; + for (const base::BuiltinFunctionEntry &entry : Object::GetObjectFunctions()) { + SetSFunction(env, JSHandle(sObjectFunction), entry.GetName(), entry.GetEntrypoint(), + fieldIndex++, entry.GetLength(), entry.GetBuiltinStubId()); + } + // sObject.prototype method + fieldIndex = 0; // constructor + sObjFuncPrototype->SetPropertyInlinedProps(thread_, fieldIndex++, sObjectFunction.GetTaggedValue()); + for (const base::BuiltinFunctionEntry &entry : Object::GetObjectPrototypeFunctions()) { + SetSFunction(env, sObjFuncPrototype, entry.GetName(), entry.GetEntrypoint(), fieldIndex++, entry.GetLength(), + entry.GetBuiltinStubId()); + } + // B.2.2.1 sObject.prototype.__proto__ + JSHandle protoGetter = + CreateSGetterSetter(env, Object::ProtoGetter, "__proto__", FunctionLength::ZERO); + JSHandle protoSetter = + CreateSGetterSetter(env, Object::ProtoSetter, "__proto__", FunctionLength::ONE); + SetSAccessor(sObjFuncPrototype, fieldIndex, protoGetter, protoSetter); +} + +void Builtins::InitializeSFunction(const JSHandle &env, + const JSHandle &sFuncPrototype) const +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + SetSFunctionLength(sFuncPrototype, FunctionLength::ZERO); + SetSFunctionName(sFuncPrototype, thread_->GlobalConstants()->GetHandledEmptyString()); + // SharedFunction.prototype_or_hclass + auto emptySLayout = thread_->GlobalConstants()->GetHandledEmptySLayoutInfo(); + JSHandle sFuncIHClass = factory_->NewSEcmaHClass(JSSharedFunction::SIZE, 0, JSType::JS_SHARED_FUNCTION, + JSHandle(sFuncPrototype), emptySLayout); + sFuncIHClass->SetCallable(true); + sFuncIHClass->SetConstructor(true); + // SharedFunction.hclass + JSHandle sFuncHClass = CreateSFunctionHClass(sFuncPrototype); + // new SharedFunction() (forbidden use NewBuiltinConstructor) + JSHandle sFuncFunction = factory_->NewSFunctionByHClass( + reinterpret_cast(BuiltinsSharedFunction::SharedFunctionConstructor), + sFuncHClass, FunctionKind::BUILTIN_CONSTRUCTOR); + InitializeSCtor(sFuncIHClass, sFuncFunction, "SharedFunction", FunctionLength::ONE); + env->SetSFunctionFunction(thread_, sFuncFunction); + env->SetSFunctionPrototype(thread_, sFuncPrototype); + + JSHandle sFuncPrototypeVal(sFuncPrototype); + JSHandle functionClass = + factory_->CreateSFunctionClass(JSSharedFunction::SIZE, JSType::JS_SHARED_FUNCTION, + sFuncPrototypeVal); + env->SetSFunctionClassWithoutProto(thread_, functionClass); + + JSHandle functionClassWithoutAccessor = + factory_->CreateSFunctionClass(JSSharedFunction::SIZE, JSType::JS_SHARED_FUNCTION, + sFuncPrototypeVal, false); + env->SetSFunctionClassWithoutAccessor(thread_, functionClassWithoutAccessor); + uint32_t fieldIndex = 2; // 2: length and name + JSHandle sFuncPrototypeObj(sFuncPrototype); + sFuncPrototypeObj->SetPropertyInlinedProps(thread_, fieldIndex++, sFuncFunction.GetTaggedValue()); // constructor + SharedStrictModeForbiddenAccessCallerArguments(env, fieldIndex, sFuncPrototypeObj); + // Function.prototype method + // 19.2.3.1 Function.prototype.apply ( thisArg, argArray ) + SetSFunction(env, sFuncPrototypeObj, "apply", Function::FunctionPrototypeApply, fieldIndex++, FunctionLength::TWO, + BUILTINS_STUB_ID(FunctionPrototypeApply)); + // 19.2.3.2 Function.prototype.bind ( thisArg , ...args) + SetSFunction(env, sFuncPrototypeObj, "bind", Function::FunctionPrototypeBind, fieldIndex++, FunctionLength::ONE); + // 19.2.3.3 Function.prototype.call (thisArg , ...args) + SetSFunction(env, sFuncPrototypeObj, "call", Function::FunctionPrototypeCall, fieldIndex++, FunctionLength::ONE); + // 19.2.3.5 Function.prototype.toString ( ) + SetSFunction(env, sFuncPrototypeObj, thread_->GlobalConstants()->GetHandledToStringString(), + Function::FunctionPrototypeToString, fieldIndex++, FunctionLength::ZERO); + SetSFunction(env, sFuncPrototypeObj, "[Symbol.hasInstance]", + Function::FunctionPrototypeHasInstance, fieldIndex++, FunctionLength::ONE); +} + + +JSHandle Builtins::CreateSObjectFunctionHClass(const JSHandle &sFuncPrototype) const +{ + uint32_t index = 0; + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + auto properties = Object::GetFunctionProperties(); + uint32_t length = properties.size(); + JSHandle layout = factory_->CreateSLayoutInfo(length); + for (const std::pair &each : properties) { + attributes.SetOffset(index); + attributes.SetIsAccessor(each.second); + JSHandle keyString(factory_->NewFromUtf8(each.first)); + layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes); + } + JSHandle sobjPrototypeHClass = + factory_->NewSEcmaHClass(JSSharedFunction::SIZE, length, JSType::JS_SHARED_FUNCTION, + JSHandle(sFuncPrototype), JSHandle(layout)); + sobjPrototypeHClass->SetConstructor(true); + sobjPrototypeHClass->SetCallable(true); + return sobjPrototypeHClass; +} + +JSHandle Builtins::CreateSObjectPrototypeHClass() const +{ + const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); + JSHandle nullHandle = globalConst->GetHandledNull(); + + uint32_t index = 0; + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + auto properties = Object::GetFunctionPrototypeProperties(); + uint32_t length = properties.size(); + JSHandle layout = factory_->CreateSLayoutInfo(length); + for (const std::pair &each : properties) { + attributes.SetOffset(index); + attributes.SetIsAccessor(each.second); + JSHandle keyString(factory_->NewFromUtf8(each.first)); + layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes); + } + + JSHandle sobjPrototypeHClass = + factory_->NewSEcmaHClass(JSSharedObject::SIZE, length, JSType::JS_SHARED_OBJECT, nullHandle, + JSHandle(layout)); + return sobjPrototypeHClass; +} + +JSHandle Builtins::CreateSFunctionHClass(const JSHandle &sFuncPrototype) const +{ + uint32_t index = 0; + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + auto properties = Function::GetFunctionProperties(); + uint32_t length = properties.size(); + JSHandle layout = factory_->CreateSLayoutInfo(length); + for (const std::pair &each : properties) { + attributes.SetOffset(index); + attributes.SetIsAccessor(each.second); + JSHandle keyString(factory_->NewFromUtf8(each.first)); + layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes); + } + JSHandle sobjPrototypeHClass = + factory_->NewSEcmaHClass(JSSharedFunction::SIZE, length, JSType::JS_SHARED_FUNCTION, + JSHandle(sFuncPrototype), JSHandle(layout)); + sobjPrototypeHClass->SetConstructor(true); + sobjPrototypeHClass->SetCallable(true); + return sobjPrototypeHClass; +} + +JSHandle Builtins::CreateSFunctionPrototypeHClass(const JSHandle &sObjFuncPrototypeVal) const +{ + uint32_t index = 0; + auto env = vm_->GetGlobalEnv(); + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + auto properties = Function::GetFunctionPrototypeProperties(); + uint32_t length = properties.size(); + JSHandle layout = factory_->CreateSLayoutInfo(length); + JSHandle keyString; + for (const std::pair &each : properties) { + attributes.SetOffset(index); + attributes.SetIsAccessor(each.second); + if (each.first == "[Symbol.hasInstance]") { + keyString = env->GetHasInstanceSymbol(); + } else { + keyString = JSHandle(factory_->NewFromUtf8(each.first)); + } + layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes); + } + JSHandle sobjPrototypeHClass = + factory_->NewSEcmaHClass(JSSharedFunction::SIZE, length, JSType::JS_SHARED_FUNCTION, sObjFuncPrototypeVal, + JSHandle(layout)); + sobjPrototypeHClass->SetCallable(true); + return sobjPrototypeHClass; +} + +void Builtins::SetSFunctionName(const JSHandle &ctor, std::string_view name) const +{ + JSHandle nameString(factory_->NewFromUtf8(name)); + SetSFunctionName(ctor, nameString); +} + +void Builtins::SetSFunctionName(const JSHandle &ctor, const JSHandle &name) const +{ + auto nameIndex = JSFunction::NAME_INLINE_PROPERTY_INDEX; + ctor->SetPropertyInlinedProps(thread_, nameIndex, name.GetTaggedValue()); +} + +void Builtins::SetSFunctionLength(const JSHandle &ctor, int length) const +{ + JSTaggedValue taggedLength(length); + auto lengthIndex = JSFunction::LENGTH_INLINE_PROPERTY_INDEX; + ctor->SetPropertyInlinedProps(thread_, lengthIndex, taggedLength); +} + +void Builtins::SetSFunctionPrototype(const JSHandle &ctor, const JSTaggedValue &prototype) const +{ + auto prototypeIndex = JSFunction::PROTOTYPE_INLINE_PROPERTY_INDEX; + ctor->SetPropertyInlinedProps(thread_, prototypeIndex, prototype); +} + +void Builtins::InitializeSCtor(const JSHandle &protoHClass, const JSHandle &ctor, + std::string_view name, int length) const +{ + SetSFunctionLength(ctor, length); + SetSFunctionName(ctor, name); + SetSFunctionPrototype(ctor, protoHClass->GetProto()); + ctor->SetProtoOrHClass(thread_, protoHClass); +} + +JSHandle Builtins::NewSFunction(const JSHandle &env, const JSHandle &key, + EcmaEntrypoint func, int length, + kungfu::BuiltinsStubCSigns::ID builtinId) const +{ + JSHandle hclass = JSHandle::Cast(env->GetSFunctionClassWithoutAccessor()); + JSHandle function = factory_->NewSFunctionByHClass(reinterpret_cast(func), + hclass, FunctionKind::NORMAL_FUNCTION, builtinId, MemSpaceType::SHARED_NON_MOVABLE); + SetSFunctionLength(function, length); + SetSFunctionName(function, key); + function->GetJSHClass()->SetExtensible(false); + return function; +} + +void Builtins::SetSFunction(const JSHandle &env, const JSHandle &obj, std::string_view key, + EcmaEntrypoint func, uint32_t index, int length, + kungfu::BuiltinsStubCSigns::ID builtinId) const +{ + JSHandle keyString(factory_->NewFromUtf8(key)); + SetSFunction(env, obj, keyString, func, index, length, builtinId); +} + +void Builtins::SetSFunction(const JSHandle &env, const JSHandle &obj, + const JSHandle &key, EcmaEntrypoint func, uint32_t index, int length, + kungfu::BuiltinsStubCSigns::ID builtinId) const +{ + JSHandle function(NewSFunction(env, key, func, length, builtinId)); + obj->SetPropertyInlinedProps(thread_, index, function.GetTaggedValue()); +} + +void Builtins::SetSAccessor(const JSHandle &obj, uint32_t index, + const JSHandle &getter, const JSHandle &setter) const +{ + JSHandle accessor = factory_->NewSAccessorData(); + accessor->SetGetter(thread_, getter); + accessor->SetSetter(thread_, setter); + obj->SetPropertyInlinedProps(thread_, index, accessor.GetTaggedValue()); +} + +JSHandle Builtins::CreateSGetterSetter(const JSHandle &env, EcmaEntrypoint func, + std::string_view name, int length) const +{ + JSHandle funcName(factory_->NewFromUtf8(name)); + JSHandle function = NewSFunction(env, funcName, func, length); + return JSHandle(function); +} + +void Builtins::SharedStrictModeForbiddenAccessCallerArguments(const JSHandle &env, uint32_t &index, + const JSHandle &prototype) const +{ + JSHandle hclass = JSHandle::Cast(env->GetSFunctionClassWithoutProto()); + JSHandle func = + factory_->NewSFunctionWithAccessor( + reinterpret_cast(JSFunction::AccessCallerArgumentsThrowTypeError), hclass, + FunctionKind::NORMAL_FUNCTION); + // "caller" + SetSAccessor(prototype, index++, JSHandle(func), JSHandle(func)); + // "arguments" + SetSAccessor(prototype, index++, JSHandle(func), JSHandle(func)); +} +} // namespace panda::ecmascript diff --git a/ecmascript/builtins/tests/builtins_bigint_test.cpp b/ecmascript/builtins/tests/builtins_bigint_test.cpp index 72891df710d7ab198742ad1dd831c29e432766f3..0355e5ed2a30992ff7abc7a521ec32b304ce4231 100644 --- a/ecmascript/builtins/tests/builtins_bigint_test.cpp +++ b/ecmascript/builtins/tests/builtins_bigint_test.cpp @@ -49,6 +49,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/builtins/tests/builtins_collator_test.cpp b/ecmascript/builtins/tests/builtins_collator_test.cpp index 39578685e070cacf18f3a782906935012aee4584..d50ee3b628a7160642af569e8a936895bacef64b 100644 --- a/ecmascript/builtins/tests/builtins_collator_test.cpp +++ b/ecmascript/builtins/tests/builtins_collator_test.cpp @@ -49,6 +49,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/builtins/tests/builtins_date_time_format_first_test.cpp b/ecmascript/builtins/tests/builtins_date_time_format_first_test.cpp index 7230e4ff160bce5fda5d48a9eeef3ead87207232..b7fd1f23e3f87736157603f4b1e186b1a73726d1 100644 --- a/ecmascript/builtins/tests/builtins_date_time_format_first_test.cpp +++ b/ecmascript/builtins/tests/builtins_date_time_format_first_test.cpp @@ -52,6 +52,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/builtins/tests/builtins_date_time_format_second_test.cpp b/ecmascript/builtins/tests/builtins_date_time_format_second_test.cpp index a5f4772818f59e939a3051654b1ba8a949bf5c8e..77b80ffe3cfda0e51fdc682f716d216b2a89d25a 100644 --- a/ecmascript/builtins/tests/builtins_date_time_format_second_test.cpp +++ b/ecmascript/builtins/tests/builtins_date_time_format_second_test.cpp @@ -52,6 +52,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/builtins/tests/builtins_displaynames_test.cpp b/ecmascript/builtins/tests/builtins_displaynames_test.cpp index c43a2935254328d814fb7718ca4c3e0feeae6be5..aa9ca6f79825886bb3db6a32c8289b71710b2c10 100644 --- a/ecmascript/builtins/tests/builtins_displaynames_test.cpp +++ b/ecmascript/builtins/tests/builtins_displaynames_test.cpp @@ -46,6 +46,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/builtins/tests/builtins_intl_test.cpp b/ecmascript/builtins/tests/builtins_intl_test.cpp index 3374dc9f575c3e35b07c21b11b9d3b7550307f2c..0084ce1d74fd7ce380827aeb83de19a26a4262e2 100644 --- a/ecmascript/builtins/tests/builtins_intl_test.cpp +++ b/ecmascript/builtins/tests/builtins_intl_test.cpp @@ -47,6 +47,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/builtins/tests/builtins_lazy_test.cpp b/ecmascript/builtins/tests/builtins_lazy_test.cpp index 24f8b1955c5ca0d4774aedbd97e476c46e97a69c..089d6d9f62ec61a33bd210691af430556f5c4a6e 100644 --- a/ecmascript/builtins/tests/builtins_lazy_test.cpp +++ b/ecmascript/builtins/tests/builtins_lazy_test.cpp @@ -51,6 +51,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/builtins/tests/builtins_list_format_first_test.cpp b/ecmascript/builtins/tests/builtins_list_format_first_test.cpp index aa8093e536f402fbc9a8a6641af776e23d6b8da7..11f038aa8a555eafa92c2c5e2ba9898ea1d8a4b2 100644 --- a/ecmascript/builtins/tests/builtins_list_format_first_test.cpp +++ b/ecmascript/builtins/tests/builtins_list_format_first_test.cpp @@ -48,6 +48,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/builtins/tests/builtins_list_format_second_test.cpp b/ecmascript/builtins/tests/builtins_list_format_second_test.cpp index 7c66ec1b1f5a0ebc43015ed8c70364aca3ab0929..ce4b24dbf0d4741e3051ba6614494813b08da8fc 100644 --- a/ecmascript/builtins/tests/builtins_list_format_second_test.cpp +++ b/ecmascript/builtins/tests/builtins_list_format_second_test.cpp @@ -48,6 +48,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/builtins/tests/builtins_locale_test.cpp b/ecmascript/builtins/tests/builtins_locale_test.cpp index 1e7f3790c723218d2e5a1c7a5bfd435e1cda1209..fe1ca3e2138cf9d80ca852adad2401f773d455d5 100644 --- a/ecmascript/builtins/tests/builtins_locale_test.cpp +++ b/ecmascript/builtins/tests/builtins_locale_test.cpp @@ -47,6 +47,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/builtins/tests/builtins_number_format_test.cpp b/ecmascript/builtins/tests/builtins_number_format_test.cpp index 85dd348bc2934c6b5f5af7660cb3868f9b5ed0a7..2c68374e8b26ced13f6d7e8e5c90080ce3857b7e 100644 --- a/ecmascript/builtins/tests/builtins_number_format_test.cpp +++ b/ecmascript/builtins/tests/builtins_number_format_test.cpp @@ -48,6 +48,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/builtins/tests/builtins_plural_rules_test.cpp b/ecmascript/builtins/tests/builtins_plural_rules_test.cpp index a8deb6f473d64a39750700f7180b261c918e88fd..6b2994f27a8968065e1f293887b984d80234f556 100644 --- a/ecmascript/builtins/tests/builtins_plural_rules_test.cpp +++ b/ecmascript/builtins/tests/builtins_plural_rules_test.cpp @@ -47,6 +47,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/builtins/tests/builtins_relative_time_format_test.cpp b/ecmascript/builtins/tests/builtins_relative_time_format_test.cpp index e908bf729f1ef3677d539ca0199eeab68ddde736..d07044a0ca0542bbfb4e98a171b09fd738f03a2d 100644 --- a/ecmascript/builtins/tests/builtins_relative_time_format_test.cpp +++ b/ecmascript/builtins/tests/builtins_relative_time_format_test.cpp @@ -47,6 +47,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/builtins/tests/builtins_segmenter_test.cpp b/ecmascript/builtins/tests/builtins_segmenter_test.cpp index 8dfd376e274b47590f25ef9577255b84550a0803..4546127e013d786de91b77ffab343bacd81070c4 100644 --- a/ecmascript/builtins/tests/builtins_segmenter_test.cpp +++ b/ecmascript/builtins/tests/builtins_segmenter_test.cpp @@ -48,6 +48,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/builtins/tests/builtins_string_test.cpp b/ecmascript/builtins/tests/builtins_string_test.cpp index 56f3f2b29668c820b22a4cd909dee9841a3d9331..fbf691109cd53a8526a9047a70998efde12a6a90 100644 --- a/ecmascript/builtins/tests/builtins_string_test.cpp +++ b/ecmascript/builtins/tests/builtins_string_test.cpp @@ -56,6 +56,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/checkpoint/thread_state_transition.h b/ecmascript/checkpoint/thread_state_transition.h new file mode 100644 index 0000000000000000000000000000000000000000..db9e351482429b139a6ebb3d7d7dd0b715383fd5 --- /dev/null +++ b/ecmascript/checkpoint/thread_state_transition.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2024 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_CHECKPOINT_THREAD_STATE_TRANSITION_H +#define ECMASCRIPT_CHECKPOINT_THREAD_STATE_TRANSITION_H + +#include "ecmascript/runtime.h" + +namespace panda::ecmascript { + +class ThreadStateTransitionScope final { +public: + explicit ThreadStateTransitionScope(JSThread* self, ThreadState newState) + : self_(self) + { + ASSERT(self_ != nullptr); + oldState_ = self_->GetState(); + if (oldState_ != newState) { + self_->UpdateState(newState); + } + } + + ~ThreadStateTransitionScope() + { + if (oldState_ != self_->GetState()) { + self_->UpdateState(oldState_); + } + } + +private: + JSThread* self_; + ThreadState oldState_; + NO_COPY_SEMANTIC(ThreadStateTransitionScope); +}; + +class ThreadSuspensionScope final { +public: + explicit ThreadSuspensionScope(JSThread* self) : scope_(self, ThreadState::IS_SUSPENDED) + { + ASSERT(self->GetState() == ThreadState::IS_SUSPENDED); + } + + ~ThreadSuspensionScope() = default; + +private: + ThreadStateTransitionScope scope_; + NO_COPY_SEMANTIC(ThreadSuspensionScope); +}; + +class ThreadNativeScope final { +public: + explicit ThreadNativeScope(JSThread* self) : scope_(self, ThreadState::NATIVE) + { + ASSERT(self->GetState() == ThreadState::NATIVE); + } + + ~ThreadNativeScope() = default; + +private: + ThreadStateTransitionScope scope_; + NO_COPY_SEMANTIC(ThreadNativeScope); +}; + +class ThreadManagedScope final { +public: + explicit ThreadManagedScope(JSThread* self) : scope_(self, ThreadState::RUNNING) {} + + ~ThreadManagedScope() = default; + +private: + ThreadStateTransitionScope scope_; + NO_COPY_SEMANTIC(ThreadManagedScope); +}; + +class SuspendAllScope final { +public: + explicit SuspendAllScope(JSThread* self) + : self_(self), scope_(self, ThreadState::IS_SUSPENDED) + { + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SuspendAll"); + Runtime::GetInstance()->SuspendAll(self_); + } + ~SuspendAllScope() + { + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "ResumeAll"); + Runtime::GetInstance()->ResumeAll(self_); + } +private: + JSThread* self_; + ThreadStateTransitionScope scope_; + NO_COPY_SEMANTIC(SuspendAllScope); +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_CHECKPOINT_THREAD_STATE_TRANSITION_H diff --git a/ecmascript/common.h b/ecmascript/common.h index a1e5fc3bf14cb4e90352e0fb7f34b852ba19febb..e189594e80a47089d2ec0938bc1d0507ff8ca848 100644 --- a/ecmascript/common.h +++ b/ecmascript/common.h @@ -38,6 +38,7 @@ enum TriggerGCType { FULL_GC, // GC is expected to compress objects into appspawn space; APPSPAWN_FULL_GC, + SHARED_GC, GC_TYPE_LAST }; @@ -90,7 +91,8 @@ enum class RequestAotMode : uint8_t { V(COLLECT_REGION_SET_SIZE) \ SEMI_RECORD_DATA(V) \ PARTIAL_RECORD_DATA(V) \ - FULL_RECORD_DATA(V) + FULL_RECORD_DATA(V) \ + SHARED_RECORD_DATA(V) #define RECORD_DURATION(V) \ V(SEMI_MIN_PAUSE) \ @@ -104,7 +106,10 @@ enum class RequestAotMode : uint8_t { V(OLD_TOTAL_PAUSE) \ V(COMPRESS_MIN_PAUSE) \ V(COMPRESS_MAX_PAUSE) \ - V(COMPRESS_TOTAL_PAUSE) + V(COMPRESS_TOTAL_PAUSE) \ + V(SHARED_MIN_PAUSE) \ + V(SHARED_MAX_PAUSE) \ + V(SHARED_TOTAL_PAUSE) #define SEMI_RECORD_DATA(V) \ V(SEMI_COUNT) \ @@ -126,6 +131,13 @@ enum class RequestAotMode : uint8_t { V(COMPRESS_TOTAL_ALIVE) \ V(COMPRESS_TOTAL_COMMIT) +#define SHARED_RECORD_DATA(V) \ + V(SHARED_COUNT) \ + V(SHARED_ALIVE_SIZE) \ + V(SHARED_TOTAL_ALIVE) \ + V(SHARED_COMMIT_SIZE) \ + V(SHARED_TOTAL_COMMIT) + #define TRACE_GC_SPEED(V) \ V(UPDATE_REFERENCE_SPEED) \ V(OLD_CLEAR_NATIVE_OBJ_SPEED) \ diff --git a/ecmascript/compiler/aot_compiler.cpp b/ecmascript/compiler/aot_compiler.cpp index 38db0a15d7d6e556db1510a9a576e4be97b3ada5..c48732fd1803aa5c139570555a9d4b4ec698b056 100644 --- a/ecmascript/compiler/aot_compiler.cpp +++ b/ecmascript/compiler/aot_compiler.cpp @@ -20,6 +20,7 @@ #include #include "ecmascript/base/string_helper.h" +#include "ecmascript/checkpoint/thread_state_transition.h" #include "ecmascript/compiler/aot_compiler_preprocessor.h" #include "ecmascript/compiler/aot_file/aot_file_manager.h" #include "ecmascript/compiler/pass_manager.h" @@ -90,6 +91,7 @@ int Main(const int argc, const char **argv) } { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); LocalScope scope(vm); arg_list_t pandaFileNames {}; std::map> pkgArgsMap; diff --git a/ecmascript/compiler/aot_compiler_preprocessor.cpp b/ecmascript/compiler/aot_compiler_preprocessor.cpp index 66b65071e5fd830c86c3b981daba252fee2dcbbc..49456b38fa9cfaab64021d66e765377e85c927e2 100644 --- a/ecmascript/compiler/aot_compiler_preprocessor.cpp +++ b/ecmascript/compiler/aot_compiler_preprocessor.cpp @@ -221,14 +221,16 @@ void AotCompilerPreprocessor::GenerateGlobalTypes(const CompilationOptions &cOpt typeRecorder.BindPgoTypeToGateType(jsPandaFile, tsManager, methodLiteral); bcInfo->IterateInfoByType(methodOffset, PGOBCInfo::Type::ARRAY_LITERAL, - [this, tsManager, ptManager, - &recordName]([[maybe_unused]] const uint32_t bcIdx, - [[maybe_unused]] const uint32_t bcOffset, const uint32_t cpIdx) { + [this, tsManager, ptManager, &recordName]([[maybe_unused]] const uint32_t bcIdx, + [[maybe_unused]] const uint32_t bcOffset, const uint32_t cpIdx) { JSHandle constpoolHandle(tsManager->GetConstantPool()); JSThread *thread = vm_->GetJSThread(); + JSTaggedValue unsharedCp = thread->GetCurrentEcmaContext() + ->FindUnsharedConstpool(constpoolHandle.GetTaggedValue()); + ASSERT(ConstantPool::CheckUnsharedConstpool(unsharedCp)); JSTaggedValue arr = ConstantPool::GetLiteralFromCache( - thread, constpoolHandle.GetTaggedValue(), cpIdx, recordName); + thread, unsharedCp, cpIdx, recordName); JSHandle arrayHandle(thread, arr); panda_file::File::EntityId id = ConstantPool::GetIdFromCache(constpoolHandle.GetTaggedValue(), cpIdx); @@ -260,4 +262,4 @@ std::string AotCompilerPreprocessor::GetMainPkgArgsAppSignature() const { return GetMainPkgArgs() == nullptr ? "" : GetMainPkgArgs()->GetAppSignature(); } -} // namespace panda::ecmascript::kungfu \ No newline at end of file +} // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/aot_file/aot_file_manager.cpp b/ecmascript/compiler/aot_file/aot_file_manager.cpp index 2653e5b5c228a922dfb002fdf79bd82fe4e38481..0887c68b3ac02365fa2918a742f6e5396e0bcb51 100644 --- a/ecmascript/compiler/aot_file/aot_file_manager.cpp +++ b/ecmascript/compiler/aot_file/aot_file_manager.cpp @@ -282,6 +282,7 @@ void AOTFileManager::SetAOTMainFuncEntry(JSHandle mainFunc, const JS Method *method = mainFunc->GetCallTarget(); method->SetDeoptThreshold(vm_->GetJSOptions().GetDeoptThreshold()); method->SetCodeEntryAndMarkAOTWhenBinding(static_cast(mainEntry)); + mainFunc->SetCodeEntry(static_cast(mainEntry)); method->SetIsFastCall(isFastCall); #ifndef NDEBUG PrintAOTEntry(jsPandaFile, method, mainEntry); @@ -292,9 +293,14 @@ void AOTFileManager::SetAOTMainFuncEntry(JSHandle mainFunc, const JS methodLiteral->SetIsFastCall(isFastCall); } -void AOTFileManager::SetAOTFuncEntry(const JSPandaFile *jsPandaFile, Method *method, - uint32_t entryIndex, bool *canFastCall) +void AOTFileManager::SetAOTFuncEntry(const JSPandaFile *jsPandaFile, JSFunction *function, + Method *method, uint32_t entryIndex, bool *canFastCall) { + uint64_t methodCodeEntry = method->GetCodeEntryOrLiteral(); + if (function != nullptr && methodCodeEntry != reinterpret_cast(nullptr)) { + function->SetCodeEntry(methodCodeEntry); + return; + } AnFileDataManager *anFileDataManager = AnFileDataManager::GetInstance(); uint32_t anFileInfoIndex = jsPandaFile->GetAOTFileInfoIndex(); const std::shared_ptr anFileInfo = anFileDataManager->SafeGetAnFileInfo(anFileInfoIndex); diff --git a/ecmascript/compiler/aot_file/aot_file_manager.h b/ecmascript/compiler/aot_file/aot_file_manager.h index 9ad080c91a905ab12c2b4aad4ff53b936a72f61c..e0f8e9428c2d327a5ef355de8327be429511b5ad 100644 --- a/ecmascript/compiler/aot_file/aot_file_manager.h +++ b/ecmascript/compiler/aot_file/aot_file_manager.h @@ -60,7 +60,11 @@ public: static constexpr size_t AOT_IHC_INDEX = 2; static constexpr size_t AOT_ELEMENT_INDEX = 3; static constexpr size_t AOT_ELEMENTS_KIND_INDEX = 4; - static constexpr size_t RESERVED_LENGTH = AOT_ELEMENTS_KIND_INDEX; + static constexpr size_t LITERAL_TYPE_INDEX = 5; + static constexpr size_t RESERVED_LENGTH = LITERAL_TYPE_INDEX; + + static constexpr int32_t METHOD_LITERAL_TYPE = 1; + static constexpr int32_t INVALID_LITERAL_TYPE = 0; static AOTLiteralInfo *Cast(TaggedObject *object) { @@ -80,6 +84,7 @@ public: SetChc(JSTaggedValue::Undefined()); SetElementIndex(JSTaggedValue(kungfu::BaseSnapshotInfo::AOT_ELEMENT_INDEX_DEFAULT_VALUE)); SetElementsKind(ElementsKind::GENERIC); + SetLiteralType(JSTaggedValue(INVALID_LITERAL_TYPE)); } inline uint32_t GetCacheLength() const @@ -130,6 +135,16 @@ public: return kind; } + inline void SetLiteralType(JSTaggedValue value) + { + Barriers::SetPrimitive(GetData(), GetLiteralTypeOffset(), value.GetRawData()); + } + + inline int GetLiteralType() const + { + return JSTaggedValue(Barriers::GetValue(GetData(), GetLiteralTypeOffset())).GetInt(); + } + inline void SetObjectToCache(JSThread *thread, uint32_t index, JSTaggedValue value) { Set(thread, index, value); @@ -160,6 +175,11 @@ private: { return JSTaggedValue::TaggedTypeSize() * (GetLength() - AOT_ELEMENTS_KIND_INDEX); } + + inline size_t GetLiteralTypeOffset() const + { + return JSTaggedValue::TaggedTypeSize() * (GetLength() - LITERAL_TYPE_INDEX); + } }; class AOTFileManager { @@ -187,8 +207,8 @@ public: void BindPandaFilesInAotFile(const std::string &aotFileBaseName, const std::string &moduleName); void SetAOTMainFuncEntry(JSHandle mainFunc, const JSPandaFile *jsPandaFile, std::string_view entryPoint); - void SetAOTFuncEntry(const JSPandaFile *jsPandaFile, Method *method, - uint32_t entryIndex, bool *canFastCall = nullptr); + void SetAOTFuncEntry(const JSPandaFile *jsPandaFile, JSFunction *function, + Method *method, uint32_t entryIndex = 0, bool *canFastCall = nullptr); bool LoadAiFile([[maybe_unused]] const std::string &filename); bool LoadAiFile(const JSPandaFile *jsPandaFile); kungfu::ArkStackMapParser* GetStackMapParser() const; diff --git a/ecmascript/compiler/aot_snapshot/aot_snapshot.h b/ecmascript/compiler/aot_snapshot/aot_snapshot.h index bb4ed777e016d925740b393feb4c28f50f960dd1..658da6aa5e3f45e2818643c3b228143f5cbdd3c5 100644 --- a/ecmascript/compiler/aot_snapshot/aot_snapshot.h +++ b/ecmascript/compiler/aot_snapshot/aot_snapshot.h @@ -68,8 +68,8 @@ public: private: JSHandle NewSnapshotConstantPool(uint32_t cacheSize); - void GenerateSnapshotConstantPools(const CMap &allConstantPools, const CString &fileName, - uint32_t fileIndex); + void GenerateSnapshotConstantPools( + const CMap &allConstantPools, const CString &fileName, uint32_t fileIndex); EcmaVM *vm_ {nullptr}; ObjectFactory *factory_ {nullptr}; diff --git a/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.cpp b/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.cpp index e2834cfc93c9bb06514acf08faf1c79d7e58d429..2a7ef8d6cc8b5ab91a032689e764f3854b9cc6ce 100644 --- a/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.cpp +++ b/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.cpp @@ -141,6 +141,7 @@ void MethodSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &globalData, JSHandle aotLiteralInfo = factory->NewAOTLiteralInfo(1); // 1: only one method int initValue = static_cast(AOTLiteralInfo::NO_FUNC_ENTRY_VALUE); aotLiteralInfo->SetObjectToCache(thread_, 0, JSTaggedValue(initValue)); + aotLiteralInfo->SetLiteralType(JSTaggedValue(AOTLiteralInfo::METHOD_LITERAL_TYPE)); if (!ihc->IsUndefined()) { aotLiteralInfo->SetIhc(ihc.GetTaggedValue()); } @@ -160,8 +161,7 @@ void ClassLiteralSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &globalD bool hasAbcId = TryGetABCId(abcId); for (auto item : info_) { const ItemData &data = item.second; - JSHandle cp(thread_, - thread_->GetCurrentEcmaContext()->FindConstpool(jsPandaFile_, data.constantPoolId_)); + JSHandle cp = GetUnsharedConstpool(data); auto literalObj = ConstantPool::GetClassLiteralFromCache(thread_, cp, data.constantPoolIdx_, data.recordName_); JSHandle classLiteral(thread_, literalObj); JSHandle arrayHandle(thread_, classLiteral->GetArray()); @@ -195,8 +195,7 @@ void ObjectLiteralSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &global bool hasAbcId = TryGetABCId(abcId); for (auto item : info_) { const ItemData &data = item.second; - JSHandle cp(thread_, - thread_->GetCurrentEcmaContext()->FindConstpool(jsPandaFile_, data.constantPoolId_)); + JSHandle cp = GetUnsharedConstpool(data); panda_file::File::EntityId id = cp->GetEntityId(data.constantPoolIdx_); JSMutableHandle elements(thread_, JSTaggedValue::Undefined()); JSMutableHandle properties(thread_, JSTaggedValue::Undefined()); @@ -233,8 +232,7 @@ void ArrayLiteralSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &globalD PGOTypeManager *ptManager = thread_->GetCurrentEcmaContext()->GetPTManager(); for (auto item : info_) { const ItemData &data = item.second; - JSHandle cp(thread_, - thread_->GetCurrentEcmaContext()->FindConstpool(jsPandaFile_, data.constantPoolId_)); + JSHandle cp = GetUnsharedConstpool(data); panda_file::File::EntityId id = cp->GetEntityId(data.constantPoolIdx_); JSHandle literal = LiteralDataExtractor::GetDatasIgnoreType( thread_, jsPandaFile_, id, cp, data.recordName_); @@ -253,6 +251,14 @@ void ArrayLiteralSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &globalD } } +JSHandle BaseSnapshotInfo::GetUnsharedConstpool(const ItemData &data) +{ + EcmaContext *context = thread_->GetCurrentEcmaContext(); + JSTaggedValue shareCp = context->FindConstpool(jsPandaFile_, data.constantPoolId_); + JSHandle cp(thread_, context->FindUnsharedConstpool(shareCp)); + return cp; +} + void SnapshotConstantPoolData::Record(const BytecodeInstruction &bcIns, int32_t bcIndex, const CString &recordName, const MethodLiteral *method) { diff --git a/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.h b/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.h index c14febb9f5ca3131eb4adf45a537b2c232f31bba..338b8f35c15df27b13c77ce0d69e9691cb89a43b 100644 --- a/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.h +++ b/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.h @@ -77,6 +77,7 @@ protected: JSHandle ihc, JSHandle chc, int32_t elementIndex = AOT_ELEMENT_INDEX_DEFAULT_VALUE, ElementsKind kind = ElementsKind::GENERIC); + JSHandle GetUnsharedConstpool(const ItemData &data); CUnorderedMap info_ {}; EcmaVM *vm_ {nullptr}; diff --git a/ecmascript/compiler/bc_call_signature.h b/ecmascript/compiler/bc_call_signature.h index 5cda5e9ccc468c903848a1f50ab3a10382de468e..81a6c7efa4822020cdcdfdc7026971a57cd146eb 100644 --- a/ecmascript/compiler/bc_call_signature.h +++ b/ecmascript/compiler/bc_call_signature.h @@ -380,7 +380,9 @@ namespace panda::ecmascript::kungfu { T(HandleCallRuntimeDefinePrivatePropertyPrefImm8Imm16Imm16V8) \ T(HandleCallRuntimeCallInitPrefImm8V8) \ T(HandleCallRuntimeDefineSendableClassPrefImm16Id16Id16Imm16V8) \ - T(HandleCallRuntimeLdSendableClassPrefImm16) + T(HandleCallRuntimeLdSendableClassPrefImm16) \ + T(HandleCallRuntimeLdsendableexternalmodulevarImm8) \ + T(HandleCallRuntimeWideLdsendableexternalmodulevarPrefImm16) #define ASM_INTERPRETER_BC_HELPER_STUB_LIST(V) \ V(SingleStepDebugging) \ diff --git a/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp index 705363c83b405714fe8d40a0fbaee6f01a986947..b313ab0a7bd1efb8bf22b886ed5b2a6f382a4c76 100644 --- a/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp @@ -442,7 +442,7 @@ void BuiltinsObjectStubBuilder::LayoutInfoAssignAllEnumProperty(Variable *result Bind(&next); GateRef key = GetKeyFromLayoutInfo(layout, *idx); - GateRef attr = TruncInt64ToInt32(GetPropAttrFromLayoutInfo(layout, *idx)); + GateRef attr = GetPropAttrFromLayoutInfo(layout, *idx); Label stringKey(env); BRANCH(TaggedIsString(key), &stringKey, &loopEnd); Bind(&stringKey); @@ -727,7 +727,7 @@ void BuiltinsObjectStubBuilder::HasOwnProperty(Variable *result, Label *exit, La BRANCH(TaggedIsString(prop), &keyIsString, slowPath); // 2 : two args Bind(&keyIsString); { - GateRef res = CallNGCRuntime(glue_, RTSTUB_ID(TryToElementsIndexOrFindInStringTable), { glue_, prop }); + GateRef res = CallRuntime(glue_, RTSTUB_ID(TryToElementsIndexOrFindInStringTable), { prop }); BRANCH(TaggedIsNumber(res), &isIndex, ¬Index); Bind(&isIndex); { diff --git a/ecmascript/compiler/bytecodes.cpp b/ecmascript/compiler/bytecodes.cpp index 9e83313ce36fd66b5ca216c37a2738865398ea69..c37a3c8cbd9a8286761cc4b85b5182e8731bbdb3 100644 --- a/ecmascript/compiler/bytecodes.cpp +++ b/ecmascript/compiler/bytecodes.cpp @@ -447,6 +447,8 @@ BytecodeMetaData BytecodeMetaData::InitBytecodeMetaData(const uint8_t *pc) case EcmaOpcode::CALLRUNTIME_DEFINEPRIVATEPROPERTY_PREF_IMM8_IMM16_IMM16_V8: case EcmaOpcode::CALLRUNTIME_CALLINIT_PREF_IMM8_V8: case EcmaOpcode::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8: + case EcmaOpcode::CALLRUNTIME_LDSENDABLEEXTERNALMODULEVAR_PREF_IMM8: + case EcmaOpcode::CALLRUNTIME_WIDELDSENDABLEEXTERNALMODULEVAR_PREF_IMM16: flags |= BytecodeFlags::READ_FUNC; break; case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8: @@ -1126,6 +1128,16 @@ void BytecodeInfo::InitBytecodeInfo(BytecodeCircuitBuilder *builder, info.inputs.emplace_back(Immediate(index)); break; } + case EcmaOpcode::CALLRUNTIME_LDSENDABLEEXTERNALMODULEVAR_PREF_IMM8: { + int32_t index = READ_INST_8_1(); + info.inputs.emplace_back(Immediate(index)); + break; + } + case EcmaOpcode::CALLRUNTIME_WIDELDSENDABLEEXTERNALMODULEVAR_PREF_IMM16: { + int32_t index = READ_INST_16_1(); + info.inputs.emplace_back(Immediate(index)); + break; + } case EcmaOpcode::STCONSTTOGLOBALRECORD_IMM16_ID16: { uint16_t stringId = READ_INST_16_2(); info.inputs.emplace_back(ConstDataId(ConstDataIDType::StringIDType, stringId)); diff --git a/ecmascript/compiler/call_signature.cpp b/ecmascript/compiler/call_signature.cpp index b18a71d67647950b7af5d1c30ca9b7967c0998dc..966c557c34a2ac13d249e5f6b1ca11637ff6b29d 100644 --- a/ecmascript/compiler/call_signature.cpp +++ b/ecmascript/compiler/call_signature.cpp @@ -1850,6 +1850,22 @@ DEF_CALL_SIGNATURE(InsertOldToNewRSet) callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); } +DEF_CALL_SIGNATURE(InsertLocalToShareRSet) +{ + // 3 : 3 input parameters + CallSignature index("InsertLocalToShareRSet", 0, 3, ArgumentsOrder::DEFAULT_ORDER, VariableType::VOID()); + *callSign = index; + // 3 : 3 input parameters + std::array params = { + VariableType::NATIVE_POINTER(), + VariableType::JS_POINTER(), + VariableType::NATIVE_POINTER(), + }; + callSign->SetParameters(params.data()); + callSign->SetGCLeafFunction(true); + callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); +} + DEF_CALL_SIGNATURE(FloatSqrt) { // 1 : 1 input parameters @@ -2144,38 +2160,6 @@ DEF_CALL_SIGNATURE(JsBoundCallInternal) callSign->SetCallConv(CallSignature::CallConv::CCallConv); } -DEF_CALL_SIGNATURE(TryToElementsIndexOrFindInStringTable) -{ - // 2 : 2 input parameters - CallSignature tryToElementsIndexOrFindInStringTable("TryToElementsIndexOrFindInStringTable", 0, 2, - ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY()); - *callSign = tryToElementsIndexOrFindInStringTable; - // 2 : 2 input parameters - std::array params = { - VariableType::NATIVE_POINTER(), - VariableType::JS_POINTER(), - }; - callSign->SetParameters(params.data()); - callSign->SetGCLeafFunction(true); - callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); -} - -DEF_CALL_SIGNATURE(TryGetInternString) -{ - // 2 : 2 input parameters - CallSignature tryGetInternString("TryGetInternString", 0, 2, - ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY()); - *callSign = tryGetInternString; - // 2 : 2 input parameters - std::array params = { - VariableType::NATIVE_POINTER(), - VariableType::JS_POINTER(), - }; - callSign->SetParameters(params.data()); - callSign->SetGCLeafFunction(true); - callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); -} - DEF_CALL_SIGNATURE(CreateArrayFromList) { // 3 : 3 input parameters diff --git a/ecmascript/compiler/call_signature.h b/ecmascript/compiler/call_signature.h index fe4f6f9a06b5dd5dd74d0be0cdc134518e0a7962..f6529e6f6e4c7a89bf9dde460feaad56d20d1f4e 100644 --- a/ecmascript/compiler/call_signature.h +++ b/ecmascript/compiler/call_signature.h @@ -437,6 +437,7 @@ private: V(FatalPrintCustom) \ V(GetActualArgvNoGC) \ V(InsertOldToNewRSet) \ + V(InsertLocalToShareRSet) \ V(DoubleToInt) \ V(DoubleToLength) \ V(FloatMod) \ @@ -475,8 +476,6 @@ private: V(JSFunctionEntry) \ V(OptimizedFastCallEntry) \ V(JSProxyCallInternalWithArgV) \ - V(TryToElementsIndexOrFindInStringTable) \ - V(TryGetInternString) \ V(CreateArrayFromList) \ V(JSObjectGetMethod) \ V(JsProxyCallInternal) \ diff --git a/ecmascript/compiler/circuit_builder.cpp b/ecmascript/compiler/circuit_builder.cpp index 2b648b6aa93995661077413ccbf22b5145cdbe8e..9764b4d56d0a7b7e732baf965f22006427dfa687 100644 --- a/ecmascript/compiler/circuit_builder.cpp +++ b/ecmascript/compiler/circuit_builder.cpp @@ -441,6 +441,17 @@ void CircuitBuilder::AppendFrameArgs(std::vector &args, GateRef hirGate } } +GateRef CircuitBuilder::GetUnsharedConstpool(GateRef constpool) +{ + auto currentLabel = env_->GetCurrentLabel(); + auto currentDepend = currentLabel->GetDepend(); + auto newGate = GetCircuit()->NewGate(circuit_->GetUnsharedConstpool(), MachineType::I64, + { currentDepend, constpool }, + GateType::AnyType()); + currentLabel->SetDepend(newGate); + return newGate; +} + GateRef CircuitBuilder::GetGlobalEnv() { auto currentLabel = env_->GetCurrentLabel(); @@ -523,9 +534,8 @@ GateRef CircuitBuilder::GetMethodFromFunction(GateRef function) GateRef CircuitBuilder::GetModuleFromFunction(GateRef function) { - GateRef method = GetMethodFromFunction(function); - GateRef offset = IntPtr(Method::ECMA_MODULE_OFFSET); - return Load(VariableType::JS_POINTER(), method, offset); + GateRef offset = IntPtr(JSFunction::ECMA_MODULE_OFFSET); + return Load(VariableType::JS_POINTER(), function, offset); } GateRef CircuitBuilder::GetHomeObjectFromFunction(GateRef function) @@ -540,6 +550,28 @@ GateRef CircuitBuilder::GetConstPoolFromFunction(GateRef jsFunc) return Load(VariableType::JS_ANY(), method, IntPtr(Method::CONSTANT_POOL_OFFSET)); } +GateRef CircuitBuilder::GetUnsharedConstpoolFromGlue(GateRef glue, GateRef constpool) +{ + GateRef unshareIdx = GetUnsharedConstpoolIndex(constpool); + GateRef unshareCpOffset = JSThread::GlueData::GetUnSharedConstpoolsOffset(env_->Is32Bit()); + GateRef unshareCpAddr = Load(VariableType::NATIVE_POINTER(), glue, IntPtr(unshareCpOffset)); + return GetUnsharedConstpool(unshareCpAddr, unshareIdx); +} + +GateRef CircuitBuilder::GetUnsharedConstpoolIndex(GateRef constpool) +{ + GateRef constPoolSize = GetLengthOfTaggedArray(constpool); + GateRef unshareIdx = Int32Sub(constPoolSize, Int32(ConstantPool::UNSHARED_CONSTPOOL_INDEX)); + return GetValueFromTaggedArray(constpool, unshareIdx); +} + +GateRef CircuitBuilder::GetUnsharedConstpool(GateRef arrayAddr, GateRef index) +{ + GateRef dataOffset = PtrAdd(arrayAddr, + PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()), ZExtInt32ToPtr(TaggedGetInt(index)))); + return Load(VariableType::JS_ANY(), dataOffset, IntPtr(0)); +} + GateRef CircuitBuilder::GetEmptyArray(GateRef glue) { GateRef gConstAddr = Load(VariableType::JS_ANY(), glue, @@ -734,7 +766,7 @@ GateRef CircuitBuilder::GetObjectFromConstPool(GateRef glue, GateRef hirGate, Ga { constPool, Int32ToTaggedInt(index), module }, hirGate); } else { result = CallRuntime(glue, RTSTUB_ID(GetMethodFromCache), Gate::InvalidGateRef, - { constPool, Int32ToTaggedInt(index), module }, hirGate); + { constPool, Int32ToTaggedInt(index) }, hirGate); } Jump(&exit); } @@ -746,7 +778,7 @@ GateRef CircuitBuilder::GetObjectFromConstPool(GateRef glue, GateRef hirGate, Ga Bind(&isAOTLiteralInfo); { result = CallRuntime(glue, RTSTUB_ID(GetMethodFromCache), Gate::InvalidGateRef, - { constPool, Int32ToTaggedInt(index), module }, hirGate); + { constPool, Int32ToTaggedInt(index) }, hirGate); Jump(&exit); } } else if (type == ConstPoolType::ARRAY_LITERAL) { @@ -800,23 +832,30 @@ void CircuitBuilder::SetHomeObjectToFunction(GateRef glue, GateRef function, Gat Store(VariableType::JS_ANY(), glue, function, offset, value); } +void CircuitBuilder::SetModuleToFunction(GateRef glue, GateRef function, GateRef value) +{ + GateRef offset = IntPtr(JSFunction::ECMA_MODULE_OFFSET); + Store(VariableType::JS_POINTER(), glue, function, offset, value); +} + GateRef CircuitBuilder::GetGlobalEnvValue(VariableType type, GateRef env, size_t index) { auto valueIndex = IntPtr(GlobalEnv::HEADER_SIZE + JSTaggedValue::TaggedTypeSize() * index); return Load(type, env, valueIndex); } -GateRef CircuitBuilder::GetCodeAddr(GateRef method) +GateRef CircuitBuilder::GetCodeAddr(GateRef jsFunc) { - auto codeAddOffset = IntPtr(Method::CODE_ENTRY_OFFSET); - return Load(VariableType::NATIVE_POINTER(), method, codeAddOffset); + auto codeAddOffset = IntPtr(JSFunction::CODE_ENTRY_OFFSET); + return Load(VariableType::NATIVE_POINTER(), jsFunc, codeAddOffset); } GateRef CircuitBuilder::GetHClassGateFromIndex(GateRef gate, int32_t index) { ArgumentAccessor argAcc(circuit_); GateRef constPool = argAcc.GetFrameArgsIn(gate, FrameArgIdx::CONST_POOL); - return LoadHClassFromConstpool(constPool, index); + GateRef unsharedConstpool = GetUnsharedConstpool(constPool); + return LoadHClassFromUnsharedConstpool(unsharedConstpool, index); } GateRef Variable::AddPhiOperand(GateRef val) diff --git a/ecmascript/compiler/circuit_builder.h b/ecmascript/compiler/circuit_builder.h index 49f26635e0f7d48ab1ee804c470477014e123c45..94377cf46cf8929a4b7bdef135833f4826977cc3 100644 --- a/ecmascript/compiler/circuit_builder.h +++ b/ecmascript/compiler/circuit_builder.h @@ -258,8 +258,12 @@ public: GateRef LoadBuiltinObject(size_t offset); // Get + GateRef GetUnsharedConstpool(GateRef constpool); GateRef GetConstPoolFromFunction(GateRef jsFunc); - GateRef GetCodeAddr(GateRef method); + GateRef GetUnsharedConstpoolFromGlue(GateRef glue, GateRef constpool); + GateRef GetUnsharedConstpoolIndex(GateRef constpool); + GateRef GetUnsharedConstpool(GateRef arrayAddr, GateRef index); + GateRef GetCodeAddr(GateRef jsFunc); GateRef GetObjectFromConstPool(GateRef glue, GateRef hirGate, GateRef constPool, GateRef module, GateRef index, ConstPoolType type); GateRef GetFunctionLexicalEnv(GateRef function); @@ -303,6 +307,7 @@ public: void SetLengthToFunction(GateRef glue, GateRef function, GateRef value); void SetLexicalEnvToFunction(GateRef glue, GateRef function, GateRef value); void SetHomeObjectToFunction(GateRef glue, GateRef function, GateRef value); + void SetModuleToFunction(GateRef glue, GateRef function, GateRef value); inline GateRef LogicAnd(GateRef x, GateRef y); inline GateRef LogicOr(GateRef x, GateRef y); @@ -593,7 +598,7 @@ public: GateRef LoadStringLength(GateRef string); GateRef LoadConstOffset(VariableType type, GateRef receiver, size_t offset, MemoryOrder order = MemoryOrder::Default()); - GateRef LoadHClassFromConstpool(GateRef constpool, size_t index); + GateRef LoadHClassFromUnsharedConstpool(GateRef constpool, size_t index); GateRef TypedCall(GateRef hirGate, std::vector args, bool isNoGC); GateRef TypedFastCall(GateRef hirGate, std::vector args, bool isNoGC); inline void SetValueToTaggedArray(VariableType valType, GateRef glue, GateRef array, GateRef index, GateRef val); diff --git a/ecmascript/compiler/common_stubs.cpp b/ecmascript/compiler/common_stubs.cpp index adde4bae3c319487f72c5dfc31251db7949930bc..b1537dbdd42f401385a732344e0adc448c503f98 100644 --- a/ecmascript/compiler/common_stubs.cpp +++ b/ecmascript/compiler/common_stubs.cpp @@ -991,7 +991,7 @@ void JsProxyCallInternalStubBuilder::GenerateCircuit() BRANCH(IsClassConstructor(method), &slowPath1, ¬CallConstructor1); Bind(¬CallConstructor1); GateRef meth = GetMethodFromFunction(method); - GateRef code = GetAotCodeAddr(meth); + GateRef code = GetAotCodeAddr(method); BRANCH(JudgeAotAndFastCallWithMethod(meth, CircuitBuilder::JudgeMethodType::HAS_AOT_FASTCALL), &fastCall1, ¬FastCall1); Bind(&fastCall1); diff --git a/ecmascript/compiler/ecma_opcode_des.h b/ecmascript/compiler/ecma_opcode_des.h index e67ad1244c1913cf66143f5d1a700b9a2d6d5855..5f5f1e84d366796466668c7917448894e411ac1d 100644 --- a/ecmascript/compiler/ecma_opcode_des.h +++ b/ecmascript/compiler/ecma_opcode_des.h @@ -327,6 +327,8 @@ namespace panda::ecmascript::kungfu { V(CALLRUNTIME_CALLINIT_PREF_IMM8_V8) \ V(CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8) \ V(CALLRUNTIME_LDSENDABLECLASS_PREF_IMM16) \ + V(CALLRUNTIME_LDSENDABLEEXTERNALMODULEVAR_PREF_IMM8) \ + V(CALLRUNTIME_WIDELDSENDABLEEXTERNALMODULEVAR_PREF_IMM16) \ inline std::string GetEcmaOpcodeStr(EcmaOpcode opcode) { diff --git a/ecmascript/compiler/interpreter_stub-inl.h b/ecmascript/compiler/interpreter_stub-inl.h index 8e3e618866f839f9424811616f9edf0f3a721bc4..bef47d4ce63685b037e9079c1fec269545055e82 100644 --- a/ecmascript/compiler/interpreter_stub-inl.h +++ b/ecmascript/compiler/interpreter_stub-inl.h @@ -270,15 +270,14 @@ GateRef InterpreterStubBuilder::GetEnvFromFunction(GateRef function) return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::LEXICAL_ENV_OFFSET)); } -GateRef InterpreterStubBuilder::GetProfileTypeInfoFromMethod(GateRef method) +GateRef InterpreterStubBuilder::GetProfileTypeInfoFromFunction(GateRef function) { - return Load(VariableType::JS_POINTER(), method, IntPtr(Method::PROFILE_TYPE_INFO_OFFSET)); + return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::PROFILE_TYPE_INFO_OFFSET)); } GateRef InterpreterStubBuilder::GetModuleFromFunction(GateRef function) { - GateRef method = GetMethodFromFunction(function); - return Load(VariableType::JS_POINTER(), method, IntPtr(Method::ECMA_MODULE_OFFSET)); + return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::ECMA_MODULE_OFFSET)); } GateRef InterpreterStubBuilder::GetHomeObjectFromFunction(GateRef function) @@ -315,6 +314,12 @@ GateRef InterpreterStubBuilder::GetResumeModeFromAsyncGeneratorObject(GateRef ob Int32((1LU << JSAsyncGeneratorObject::ResumeModeBits::SIZE) - 1)); } +void InterpreterStubBuilder::SetModuleToFunction(GateRef glue, GateRef function, GateRef value) +{ + GateRef offset = IntPtr(JSFunction::ECMA_MODULE_OFFSET); + Store(VariableType::JS_POINTER(), glue, function, offset, value); +} + void InterpreterStubBuilder::SetPcToFrame(GateRef glue, GateRef frame, GateRef value) { Store(VariableType::INT64(), glue, frame, diff --git a/ecmascript/compiler/interpreter_stub.cpp b/ecmascript/compiler/interpreter_stub.cpp index 4cf2757a46b73a4632a484f317b76ea26594ece7..2948691fccc033502b91e6d385acb57f74a9eb2f 100644 --- a/ecmascript/compiler/interpreter_stub.cpp +++ b/ecmascript/compiler/interpreter_stub.cpp @@ -2533,7 +2533,7 @@ DECLARE_ASM_HANDLER(HandleReturn) GateRef function = GetFunctionFromFrame(prevState); GateRef method = Load(VariableType::JS_ANY(), function, IntPtr(JSFunctionBase::METHOD_OFFSET)); varConstpool = GetConstpoolFromMethod(method); - varProfileTypeInfo = GetProfileTypeInfoFromMethod(method); + varProfileTypeInfo = GetProfileTypeInfoFromFunction(function); varHotnessCounter = GetHotnessCounterFromMethod(method); GateRef jumpSize = GetCallSizeFromFrame(prevState); CallNGCRuntime(glue, RTSTUB_ID(ResumeRspAndDispatch), @@ -2605,7 +2605,7 @@ DECLARE_ASM_HANDLER(HandleReturnundefined) GateRef function = GetFunctionFromFrame(prevState); GateRef method = Load(VariableType::JS_ANY(), function, IntPtr(JSFunctionBase::METHOD_OFFSET)); varConstpool = GetConstpoolFromMethod(method); - varProfileTypeInfo = GetProfileTypeInfoFromMethod(method); + varProfileTypeInfo = GetProfileTypeInfoFromFunction(function); varHotnessCounter = GetHotnessCounterFromMethod(method); GateRef jumpSize = GetCallSizeFromFrame(prevState); CallNGCRuntime(glue, RTSTUB_ID(ResumeRspAndDispatch), @@ -2687,7 +2687,7 @@ DECLARE_ASM_HANDLER(HandleSuspendgeneratorV8) GateRef function = GetFunctionFromFrame(prevState); GateRef method = Load(VariableType::JS_ANY(), function, IntPtr(JSFunctionBase::METHOD_OFFSET)); varConstpool = GetConstpoolFromMethod(method); - varProfileTypeInfo = GetProfileTypeInfoFromMethod(method); + varProfileTypeInfo = GetProfileTypeInfoFromFunction(function); varHotnessCounter = GetHotnessCounterFromMethod(method); GateRef jumpSize = GetCallSizeFromFrame(prevState); CallNGCRuntime(glue, RTSTUB_ID(ResumeRspAndDispatch), @@ -2768,7 +2768,7 @@ DECLARE_ASM_HANDLER(HandleDeprecatedSuspendgeneratorPrefV8V8) GateRef function = GetFunctionFromFrame(prevState); GateRef method = Load(VariableType::JS_ANY(), function, IntPtr(JSFunctionBase::METHOD_OFFSET)); varConstpool = GetConstpoolFromMethod(method); - varProfileTypeInfo = GetProfileTypeInfoFromMethod(method); + varProfileTypeInfo = GetProfileTypeInfoFromFunction(function); varHotnessCounter = GetHotnessCounterFromMethod(method); GateRef jumpSize = GetCallSizeFromFrame(prevState); CallNGCRuntime(glue, RTSTUB_ID(ResumeRspAndDispatch), @@ -3112,7 +3112,7 @@ DECLARE_ASM_HANDLER(HandleAsyncgeneratorresolveV8V8V8) GateRef function = GetFunctionFromFrame(prevState); GateRef method = Load(VariableType::JS_ANY(), function, IntPtr(JSFunctionBase::METHOD_OFFSET)); varConstpool = GetConstpoolFromMethod(method); - varProfileTypeInfo = GetProfileTypeInfoFromMethod(method); + varProfileTypeInfo = GetProfileTypeInfoFromFunction(function); varHotnessCounter = GetHotnessCounterFromMethod(method); GateRef jumpSize = GetCallSizeFromFrame(prevState); CallNGCRuntime(glue, RTSTUB_ID(ResumeRspAndDispatch), @@ -4388,7 +4388,7 @@ DECLARE_ASM_HANDLER(HandleDefinefuncImm8Id16Imm8) GateRef methodId = ReadInst16_1(pc); GateRef length = ReadInst8_3(pc); NewObjectStubBuilder newBuilder(this); - GateRef result = newBuilder.NewJSFunction(glue, constpool, GetModule(sp), ZExtInt16ToInt32(methodId)); + GateRef result = newBuilder.NewJSFunction(glue, constpool, ZExtInt16ToInt32(methodId)); Label notException(env); CHECK_EXCEPTION_WITH_JUMP(result, ¬Exception); Bind(¬Exception); @@ -4398,6 +4398,7 @@ DECLARE_ASM_HANDLER(HandleDefinefuncImm8Id16Imm8) GateRef envHandle = GetEnvFromFrame(frame); SetLexicalEnvToFunction(glue, result, envHandle); GateRef currentFunc = GetFunctionFromFrame(frame); + SetModuleToFunction(glue, result, GetModuleFromFunction(currentFunc)); SetHomeObjectToFunction(glue, result, GetHomeObjectFromFunction(currentFunc)); callback.ProfileDefineClass(result); varAcc = result; @@ -4412,7 +4413,7 @@ DECLARE_ASM_HANDLER(HandleDefinefuncImm16Id16Imm8) GateRef methodId = ReadInst16_2(pc); GateRef length = ReadInst8_4(pc); NewObjectStubBuilder newBuilder(this); - GateRef result = newBuilder.NewJSFunction(glue, constpool, GetModule(sp), ZExtInt16ToInt32(methodId)); + GateRef result = newBuilder.NewJSFunction(glue, constpool, ZExtInt16ToInt32(methodId)); Label notException(env); CHECK_EXCEPTION_WITH_JUMP(result, ¬Exception); Bind(¬Exception); @@ -4423,6 +4424,7 @@ DECLARE_ASM_HANDLER(HandleDefinefuncImm16Id16Imm8) SetLexicalEnvToFunction(glue, result, envHandle); GateRef currentFunc = GetFunctionFromFrame(frame); SetHomeObjectToFunction(glue, result, GetHomeObjectFromFunction(currentFunc)); + SetModuleToFunction(glue, result, GetModuleFromFunction(currentFunc)); varAcc = result; callback.ProfileDefineClass(result); DISPATCH_WITH_ACC(DEFINEFUNC_IMM16_ID16_IMM8); @@ -4437,8 +4439,9 @@ DECLARE_ASM_HANDLER(HandleDefinemethodImm8Id16Imm8) GateRef length = ReadInst8_3(pc); GateRef lexEnv = GetEnvFromFrame(GetFrame(sp)); DEFVARIABLE(result, VariableType::JS_POINTER(), - GetMethodFromConstPool(glue, constpool, GetModule(sp), ZExtInt16ToInt32(methodId))); - result = CallRuntime(glue, RTSTUB_ID(DefineMethod), { *result, acc, Int8ToTaggedInt(length), lexEnv }); + GetMethodFromConstPool(glue, constpool, ZExtInt16ToInt32(methodId))); + result = CallRuntime(glue, RTSTUB_ID(DefineMethod), { *result, acc, Int8ToTaggedInt(length), + lexEnv, GetModule(sp) }); Label notException(env); CHECK_EXCEPTION_WITH_JUMP(*result, ¬Exception); Bind(¬Exception); @@ -4456,8 +4459,9 @@ DECLARE_ASM_HANDLER(HandleDefinemethodImm16Id16Imm8) GateRef length = ReadInst8_4(pc); GateRef lexEnv = GetEnvFromFrame(GetFrame(sp)); DEFVARIABLE(result, VariableType::JS_POINTER(), - GetMethodFromConstPool(glue, constpool, GetModule(sp), ZExtInt16ToInt32(methodId))); - result = CallRuntime(glue, RTSTUB_ID(DefineMethod), { *result, acc, Int8ToTaggedInt(length), lexEnv }); + GetMethodFromConstPool(glue, constpool, ZExtInt16ToInt32(methodId))); + result = CallRuntime(glue, RTSTUB_ID(DefineMethod), { *result, acc, Int8ToTaggedInt(length), + lexEnv, GetModule(sp) }); Label notException(env); CHECK_EXCEPTION_WITH_JUMP(*result, ¬Exception); Bind(¬Exception); @@ -4800,7 +4804,7 @@ DECLARE_ASM_HANDLER_NOPRINT(ExceptionHandler) GateRef function = GetFunctionFromFrame(GetFrame(*varSp)); GateRef method = Load(VariableType::JS_ANY(), function, IntPtr(JSFunctionBase::METHOD_OFFSET)); varConstpool = GetConstpoolFromMethod(method); - varProfileTypeInfo = GetProfileTypeInfoFromMethod(method); + varProfileTypeInfo = GetProfileTypeInfoFromFunction(function); varHotnessCounter = GetHotnessCounterFromMethod(method); CallNGCRuntime(glue, RTSTUB_ID(ResumeCaughtFrameAndDispatch), { glue, *varSp, *varPc, *varConstpool, @@ -4842,7 +4846,7 @@ DECLARE_ASM_HANDLER(SingleStepDebugging) varAcc = GetAccFromFrame(frameAfter); GateRef function = GetFunctionFromFrame(frameAfter); GateRef method = Load(VariableType::JS_ANY(), function, IntPtr(JSFunctionBase::METHOD_OFFSET)); - varProfileTypeInfo = GetProfileTypeInfoFromMethod(method); + varProfileTypeInfo = GetProfileTypeInfoFromFunction(function); varConstpool = GetConstpoolFromMethod(method); varHotnessCounter = GetHotnessCounterFromMethod(method); } @@ -4921,7 +4925,7 @@ DECLARE_ASM_HANDLER(BCDebuggerEntry) GateRef function = GetFunctionFromFrame(prevState); GateRef method = Load(VariableType::JS_ANY(), function, IntPtr(JSFunctionBase::METHOD_OFFSET)); varConstpool = GetConstpoolFromMethod(method); - varProfileTypeInfo = GetProfileTypeInfoFromMethod(method); + varProfileTypeInfo = GetProfileTypeInfoFromFunction(function); varHotnessCounter = GetHotnessCounterFromMethod(method); GateRef jumpSize = IntPtr(0); CallNGCRuntime(glue, RTSTUB_ID(ResumeRspAndRollback), @@ -5165,6 +5169,48 @@ DECLARE_ASM_HANDLER(HandleCallRuntimeLdSendableClassPrefImm16) DISPATCH_WITH_ACC(CALLRUNTIME_LDSENDABLECLASS_PREF_IMM16); } +DECLARE_ASM_HANDLER(HandleCallRuntimeLdsendableexternalmodulevarImm8) +{ + DEFVARIABLE(varAcc, VariableType::JS_ANY(), acc); + DEFVARIABLE(moduleRef, VariableType::JS_ANY(), Undefined()); + GateRef index = ReadInst8_1(pc); + + // LdSendableExternalModuleVarByIndex may load uninitialized module lazy. Exception could happened. + GateRef currentFunc = GetFunctionFromFrame(GetFrame(sp)); + moduleRef = CallRuntime(glue, RTSTUB_ID(LdSendableExternalModuleVarByIndex), {Int8ToTaggedInt(index), currentFunc}); + + auto env = GetEnvironment(); + Label notException(env); + CHECK_EXCEPTION_WITH_JUMP(*moduleRef, ¬Exception); + Bind(¬Exception); + { + varAcc = *moduleRef; + DISPATCH_WITH_ACC(CALLRUNTIME_LDSENDABLEEXTERNALMODULEVAR_PREF_IMM8); + } +} + +DECLARE_ASM_HANDLER(HandleCallRuntimeWideLdsendableexternalmodulevarPrefImm16) +{ + DEFVARIABLE(varAcc, VariableType::JS_ANY(), acc); + DEFVARIABLE(moduleRef, VariableType::JS_ANY(), Undefined()); + + GateRef index = ReadInst16_1(pc); + + // LdSendableExternalModuleVarByIndex may load uninitialized module lazy. Exception could happened. + GateRef currentFunc = GetFunctionFromFrame(GetFrame(sp)); + moduleRef = + CallRuntime(glue, RTSTUB_ID(LdSendableExternalModuleVarByIndex), {Int16ToTaggedInt(index), currentFunc}); + + auto env = GetEnvironment(); + Label notException(env); + CHECK_EXCEPTION_WITH_JUMP(*moduleRef, ¬Exception); + Bind(¬Exception); + { + varAcc = *moduleRef; + DISPATCH_WITH_ACC(CALLRUNTIME_WIDELDSENDABLEEXTERNALMODULEVAR_PREF_IMM16); + } +} + ASM_INTERPRETER_BC_TYPE_PROFILER_STUB_LIST(DECLARE_ASM_HANDLER_PROFILE) ASM_INTERPRETER_BC_LAYOUT_PROFILER_STUB_LIST(DECLARE_ASM_HANDLER_PROFILE) ASM_INTERPRETER_BC_FUNC_HOT_PROFILER_STUB_LIST(DECLARE_ASM_HANDLER_PROFILE) diff --git a/ecmascript/compiler/interpreter_stub.h b/ecmascript/compiler/interpreter_stub.h index c16441667af587b5b41aa04275d915d74a1e58cf..8235bc193f0ea36a6b0381d16a60aa04b79624c6 100644 --- a/ecmascript/compiler/interpreter_stub.h +++ b/ecmascript/compiler/interpreter_stub.h @@ -102,7 +102,7 @@ public: inline GateRef GetEnvFromFunction(GateRef frame); inline GateRef GetConstpoolFromMethod(GateRef function); inline GateRef GetModule(GateRef sp); - inline GateRef GetProfileTypeInfoFromMethod(GateRef function); + inline GateRef GetProfileTypeInfoFromFunction(GateRef function); inline GateRef GetModuleFromFunction(GateRef function); inline GateRef GetHomeObjectFromFunction(GateRef function); inline GateRef GetResumeModeFromGeneratorObject(GateRef obj); @@ -117,6 +117,7 @@ public: inline void SetAccToFrame(GateRef glue, GateRef frame, GateRef value); inline void SetEnvToFrame(GateRef glue, GateRef frame, GateRef value); inline void SetHomeObjectToFunction(GateRef glue, GateRef function, GateRef value); + inline void SetModuleToFunction(GateRef glue, GateRef function, GateRef value); inline void SetFrameState(GateRef glue, GateRef sp, GateRef function, GateRef acc, GateRef env, GateRef pc, GateRef prev, GateRef type); diff --git a/ecmascript/compiler/later_elimination.cpp b/ecmascript/compiler/later_elimination.cpp index f434f5b2c9cc88956eff99633bb7bf70a1db6eed..4fb6aa360397f7d9116b2307ec8d20b8a54a0234 100644 --- a/ecmascript/compiler/later_elimination.cpp +++ b/ecmascript/compiler/later_elimination.cpp @@ -33,6 +33,7 @@ GateRef LaterElimination::VisitGate(GateRef gate) { auto opcode = acc_.GetOpCode(gate); switch (opcode) { + case OpCode::GET_UNSHARED_CONSTPOOL: case OpCode::GET_GLOBAL_ENV: case OpCode::GET_GLOBAL_ENV_OBJ: case OpCode::GET_GLOBAL_ENV_OBJ_HCLASS: diff --git a/ecmascript/compiler/mcr_circuit_builder.cpp b/ecmascript/compiler/mcr_circuit_builder.cpp index 3ae112b99f38a72b7130e41f9c778ebb9b04e2e9..940f75a297eb39f98e01724811fdcd7e31cdd53a 100644 --- a/ecmascript/compiler/mcr_circuit_builder.cpp +++ b/ecmascript/compiler/mcr_circuit_builder.cpp @@ -851,11 +851,11 @@ GateRef CircuitBuilder::LoadConstOffset(VariableType type, GateRef receiver, siz return ret; } -GateRef CircuitBuilder::LoadHClassFromConstpool(GateRef constpool, size_t index) +GateRef CircuitBuilder::LoadHClassFromUnsharedConstpool(GateRef constpool, size_t index) { auto currentLabel = env_->GetCurrentLabel(); auto currentDepend = currentLabel->GetDepend(); - auto ret = GetCircuit()->NewGate(circuit_->LoadHClassFromConstpool(index), MachineType::I64, + auto ret = GetCircuit()->NewGate(circuit_->LoadHClassFromUnsharedConstpool(index), MachineType::I64, { currentDepend, constpool }, GateType::AnyType()); currentLabel->SetDepend(ret); return ret; diff --git a/ecmascript/compiler/mcr_lowering.cpp b/ecmascript/compiler/mcr_lowering.cpp index 036fa77d0d49218ba447ff3521c6ac33199ed459..351d671bb48ce57870f8ee16d24482ee522e4ce3 100644 --- a/ecmascript/compiler/mcr_lowering.cpp +++ b/ecmascript/compiler/mcr_lowering.cpp @@ -28,6 +28,9 @@ GateRef MCRLowering::VisitGate(GateRef gate) { auto op = acc_.GetOpCode(gate); switch (op) { + case OpCode::GET_UNSHARED_CONSTPOOL: + LowerGetUnsharedConstpool(gate); + break; case OpCode::STATE_SPLIT: DeleteStateSplit(gate); break; @@ -50,7 +53,7 @@ GateRef MCRLowering::VisitGate(GateRef gate) LowerLoadConstOffset(gate); break; case OpCode::LOAD_HCLASS_FROM_CONSTPOOL: - LowerLoadHClassFromConstpool(gate); + LowerLoadHClassFromUnsharedConstpool(gate); break; case OpCode::STORE_CONST_OFFSET: LowerStoreConstOffset(gate); @@ -163,7 +166,7 @@ void MCRLowering::LowerLoadConstOffset(GateRef gate) acc_.ReplaceGate(gate, Circuit::NullGate(), builder_.GetDepend(), result); } -void MCRLowering::LowerLoadHClassFromConstpool(GateRef gate) +void MCRLowering::LowerLoadHClassFromUnsharedConstpool(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef constpool = acc_.GetValueIn(gate, 0); @@ -261,6 +264,18 @@ void MCRLowering::LowerIsSpecificObjectType(GateRef gate) acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } +void MCRLowering::LowerGetUnsharedConstpool(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + GateRef constpool = acc_.GetValueIn(gate, 0); // 0: this object + GateRef newGate = builder_.GetUnsharedConstpoolFromGlue(glue_, constpool); + + acc_.UpdateAllUses(gate, newGate); + + // delete old gate + acc_.DeleteGate(gate); +} + void MCRLowering::DeleteStateSplit(GateRef gate) { auto depend = acc_.GetDep(gate); @@ -825,6 +840,15 @@ void MCRLowering::LowerGetGlobalConstantValue(GateRef gate) acc_.ReplaceGate(gate, Circuit::NullGate(), builder_.GetDepend(), result); } +void MCRLowering::HeapAllocateInSOld(GateRef gate) +{ + GateRef size = acc_.GetValueIn(gate, 0); + GateRef ret = builder_.CallRuntime(glue_, RTSTUB_ID(AllocateInSOld), Gate::InvalidGateRef, + {builder_.ToTaggedInt(size)}, gate); + + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret); +} + void MCRLowering::LowerInt32CheckRightIsZero(GateRef gate) { Environment env(gate, circuit_, &builder_); diff --git a/ecmascript/compiler/mcr_lowering.h b/ecmascript/compiler/mcr_lowering.h index 01a1cd7fa6376688927251d7eb914f10e384f91b..2cfff1dd7304f5b250597b728ba0961b04d165e1 100644 --- a/ecmascript/compiler/mcr_lowering.h +++ b/ecmascript/compiler/mcr_lowering.h @@ -46,8 +46,9 @@ private: void LowerHClassStableArrayCheck(GateRef gate); void LowerElementskindCheck(GateRef gate); void LowerGetConstPool(GateRef gate); + void LowerGetUnsharedConstpool(GateRef gate); void LowerLoadConstOffset(GateRef gate); - void LowerLoadHClassFromConstpool(GateRef gate); + void LowerLoadHClassFromUnsharedConstpool(GateRef gate); void LowerStoreConstOffset(GateRef gate); void LowerConvertHoleAsUndefined(GateRef gate); void LowerCheckAndConvert(GateRef gate); @@ -98,6 +99,7 @@ private: GateRef ConvertTaggedNumberToInt32(GateRef gate, Label *exit); GateRef ConvertTaggedNumberToFloat64(GateRef gate, Label *exit); GateRef ConvertTaggedBooleanToBool(GateRef gate); + void HeapAllocateInSOld(GateRef gate); void InitializeWithSpeicalValue(Label *exit, GateRef object, GateRef glue, GateRef value, GateRef start, GateRef end); diff --git a/ecmascript/compiler/mcr_opcodes.h b/ecmascript/compiler/mcr_opcodes.h index 56311a6071b287c1c8c51aac510922bd0d912ade..dd1b8f7f2d2e748108a25dfe79f5aa8d93588a13 100644 --- a/ecmascript/compiler/mcr_opcodes.h +++ b/ecmascript/compiler/mcr_opcodes.h @@ -91,7 +91,7 @@ namespace panda::ecmascript::kungfu { #define MCR_GATE_META_DATA_LIST_WITH_VALUE(V) \ V(LoadConstOffset, LOAD_CONST_OFFSET, GateFlags::NO_WRITE, 0, 1, 1) \ - V(LoadHClassFromConstpool, LOAD_HCLASS_FROM_CONSTPOOL, GateFlags::NO_WRITE, 0, 1, 1) \ + V(LoadHClassFromUnsharedConstpool, LOAD_HCLASS_FROM_CONSTPOOL, GateFlags::NO_WRITE, 0, 1, 1) \ V(StoreConstOffset, STORE_CONST_OFFSET, GateFlags::NONE_FLAG, 0, 1, 2) \ V(LoadElement, LOAD_ELEMENT, GateFlags::NO_WRITE, 1, 1, 2) \ V(StoreElement, STORE_ELEMENT, GateFlags::NONE_FLAG, 1, 1, 3) \ diff --git a/ecmascript/compiler/new_object_stub_builder.cpp b/ecmascript/compiler/new_object_stub_builder.cpp index 80963fc2f15aa4ad9f8a374a9dfdd81bfefd6b0b..9806c9494a6a9cf84fde108a82769740e969b8b7 100644 --- a/ecmascript/compiler/new_object_stub_builder.cpp +++ b/ecmascript/compiler/new_object_stub_builder.cpp @@ -599,30 +599,39 @@ GateRef NewObjectStubBuilder::LoadHClassFromMethod(GateRef glue, GateRef method) return ret; } -GateRef NewObjectStubBuilder::NewJSFunction(GateRef glue, GateRef constpool, GateRef module, GateRef index) +GateRef NewObjectStubBuilder::NewJSFunction(GateRef glue, GateRef constpool, GateRef index) { auto env = GetEnvironment(); Label subentry(env); env->SubCfgEntry(&subentry); Label exit(env); DEFVARIABLE(ihc, VariableType::JS_ANY(), Undefined()); + DEFVARIABLE(val, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(result, VariableType::JS_ANY(), Undefined()); - auto val = GetValueFromTaggedArray(constpool, index); + + val = GetValueFromTaggedArray(constpool, index); + Label isHeapObject(env); Label afterAOTLiteral(env); - BRANCH(TaggedIsHeapObject(val), &isHeapObject, &afterAOTLiteral); + BRANCH(TaggedIsHeapObject(*val), &isHeapObject, &afterAOTLiteral); { Bind(&isHeapObject); Label isAOTLiteral(env); - BRANCH(IsAOTLiteralInfo(val), &isAOTLiteral, &afterAOTLiteral); + BRANCH(IsAOTLiteralInfo(*val), &isAOTLiteral, &afterAOTLiteral); { Bind(&isAOTLiteral); - ihc = GetIhcFromAOTLiteralInfo(val); + // Avoiding shareobj references to unshareobj. + GateRef unshareIdx = GetUnsharedConstpoolIndex(constpool); + GateRef unshareCpOffset = JSThread::GlueData::GetUnSharedConstpoolsOffset(env->Is32Bit()); + GateRef unshareCpAddr = Load(VariableType::NATIVE_POINTER(), glue, IntPtr(unshareCpOffset)); + GateRef unshareCp = GetUnsharedConstpool(unshareCpAddr, unshareIdx); + val = GetValueFromTaggedArray(unshareCp, index); + ihc = GetIhcFromAOTLiteralInfo(*val); Jump(&afterAOTLiteral); } } Bind(&afterAOTLiteral); - GateRef method = GetMethodFromConstPool(glue, constpool, module, index); + GateRef method = GetMethodFromConstPool(glue, constpool, index); GateRef hclass = LoadHClassFromMethod(glue, method); result = NewJSObject(glue, hclass); SetExtensibleToBitfield(glue, hclass, true); @@ -631,6 +640,16 @@ GateRef NewObjectStubBuilder::NewJSFunction(GateRef glue, GateRef constpool, Gat InitializeJSFunction(glue, *result, kind); SetMethodToFunction(glue, *result, method); + Label isAotWithCallField(env); + Label afterAotWithCallField(env); + BRANCH(IsAotWithCallField(method), &isAotWithCallField, &afterAotWithCallField); + { + Bind(&isAotWithCallField); + SetCodeEntryToFunction(glue, *result, method); + Jump(&afterAotWithCallField); + } + Bind(&afterAotWithCallField); + Label ihcNotUndefined(env); BRANCH(TaggedIsUndefined(*ihc), &exit, &ihcNotUndefined); Bind(&ihcNotUndefined); @@ -651,8 +670,7 @@ void NewObjectStubBuilder::NewJSFunction(GateRef glue, GateRef jsFunc, GateRef i Label hasException(env); Label notException(env); GateRef constPool = GetConstPoolFromFunction(jsFunc); - GateRef module = GetModuleFromFunction(jsFunc); - result->WriteVariable(NewJSFunction(glue, constPool, module, index)); + result->WriteVariable(NewJSFunction(glue, constPool, index)); BRANCH(HasPendingException(glue), &hasException, ¬Exception); Bind(&hasException); { @@ -662,6 +680,7 @@ void NewObjectStubBuilder::NewJSFunction(GateRef glue, GateRef jsFunc, GateRef i { SetLengthToFunction(glue_, result->ReadVariable(), length); SetLexicalEnvToFunction(glue_, result->ReadVariable(), lexEnv); + SetModuleToFunction(glue_, result->ReadVariable(), GetModuleFromFunction(jsFunc)); SetHomeObjectToFunction(glue_, result->ReadVariable(), GetHomeObjectFromFunction(jsFunc)); Jump(success); } @@ -916,6 +935,14 @@ void NewObjectStubBuilder::HeapAlloc(Variable *result, Label *exit, RegionSpaceF } } +void NewObjectStubBuilder::AllocateInSOld(Variable *result, Label *exit) +{ + DEFVARIABLE(ret, VariableType::JS_ANY(), Undefined()); + ret = CallRuntime(glue_, RTSTUB_ID(AllocateInSOld), {IntToTaggedInt(size_)}); + result->WriteVariable(*ret); + Jump(exit); +} + void NewObjectStubBuilder::AllocateInYoungPrologue(Variable *result, Label *callRuntime, Label *exit) { auto env = GetEnvironment(); @@ -1057,7 +1084,7 @@ void NewObjectStubBuilder::AllocLineStringObject(Variable *result, Label *exit, IntPtr(static_cast(MemAlignment::MEM_ALIGN_OBJECT))); } Label afterAllocate(env); - AllocateInYoung(result, &afterAllocate); + AllocateInSOld(result, &afterAllocate); Bind(&afterAllocate); GateRef stringClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, @@ -1075,7 +1102,7 @@ void NewObjectStubBuilder::AllocSlicedStringObject(Variable *result, Label *exit size_ = AlignUp(IntPtr(SlicedString::SIZE), IntPtr(static_cast(MemAlignment::MEM_ALIGN_OBJECT))); Label afterAllocate(env); - AllocateInYoung(result, &afterAllocate); + AllocateInSOld(result, &afterAllocate); Bind(&afterAllocate); GateRef stringClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, @@ -1100,7 +1127,7 @@ void NewObjectStubBuilder::AllocTreeStringObject(Variable *result, Label *exit, size_ = AlignUp(IntPtr(TreeEcmaString::SIZE), IntPtr(static_cast(MemAlignment::MEM_ALIGN_OBJECT))); Label afterAllocate(env); - AllocateInYoung(result, &afterAllocate); + AllocateInSOld(result, &afterAllocate); Bind(&afterAllocate); GateRef stringClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, diff --git a/ecmascript/compiler/new_object_stub_builder.h b/ecmascript/compiler/new_object_stub_builder.h index 9ce9f4bc62771eee77657d760edebcb62558394d..243a75096a8924f4bda1ef6ac8b35d6af1dedb14 100644 --- a/ecmascript/compiler/new_object_stub_builder.h +++ b/ecmascript/compiler/new_object_stub_builder.h @@ -54,7 +54,7 @@ public: GateRef NewJSArrayWithSize(GateRef hclass, GateRef size); GateRef NewJSForinIterator(GateRef glue, GateRef receiver, GateRef keys, GateRef cachedHclass); GateRef LoadHClassFromMethod(GateRef glue, GateRef method); - GateRef NewJSFunction(GateRef glue, GateRef constpool, GateRef module, GateRef index); + GateRef NewJSFunction(GateRef glue, GateRef constpool, GateRef index); void NewJSFunction(GateRef glue, GateRef jsFunc, GateRef index, GateRef length, GateRef lexEnv, Variable *result, Label *success, Label *failed); void InitializeJSFunction(GateRef glue, GateRef func, GateRef kind); @@ -98,6 +98,7 @@ private: void AllocateInYoungPrologue(Variable *result, Label *callRuntime, Label *exit); void AllocateInYoung(Variable *result, Label *exit); void AllocateInYoung(Variable *result, Label *error, Label *noError); + void AllocateInSOld(Variable *result, Label *exit); void InitializeTaggedArrayWithSpeicalValue(Label *exit, GateRef array, GateRef value, GateRef start, GateRef length); GateRef glue_ {Circuit::NullGate()}; diff --git a/ecmascript/compiler/ntype_hcr_lowering.cpp b/ecmascript/compiler/ntype_hcr_lowering.cpp index 927f9c75bcce3f90ffb2797dcb50329bd67c532a..2e7a5db43c7ad1e1fea43dc29ce94a15f1d219be 100644 --- a/ecmascript/compiler/ntype_hcr_lowering.cpp +++ b/ecmascript/compiler/ntype_hcr_lowering.cpp @@ -145,8 +145,9 @@ void NTypeHCRLowering::LowerCreateArguments(GateRef gate, GateRef glue) } } -GateRef NTypeHCRLowering::LoadFromConstPool(GateRef constPool, size_t index, size_t valVecType) +GateRef NTypeHCRLowering::LoadFromConstPool(GateRef constpool, size_t index, size_t valVecType) { + GateRef constPool = builder_.GetUnsharedConstpool(constpool); GateRef constPoolSize = builder_.GetLengthOfTaggedArray(constPool); GateRef valVecIndex = builder_.Int32Sub(constPoolSize, builder_.Int32(valVecType)); GateRef valVec = builder_.GetValueFromTaggedArray(constPool, valVecIndex); @@ -254,9 +255,8 @@ void NTypeHCRLowering::LowerStoreModuleVar(GateRef gate, GateRef glue) GateRef jsFunc = acc_.GetValueIn(gate, 0); GateRef index = acc_.GetValueIn(gate, 1); GateRef value = acc_.GetValueIn(gate, 2); - GateRef method = builder_.GetMethodFromFunction(jsFunc); - GateRef moduleOffset = builder_.IntPtr(Method::ECMA_MODULE_OFFSET); - GateRef module = builder_.Load(VariableType::JS_ANY(), method, moduleOffset); + GateRef moduleOffset = builder_.IntPtr(JSFunction::ECMA_MODULE_OFFSET); + GateRef module = builder_.Load(VariableType::JS_ANY(), jsFunc, moduleOffset); GateRef localExportEntriesOffset = builder_.IntPtr(SourceTextModule::LOCAL_EXPORT_ENTTRIES_OFFSET); GateRef localExportEntries = builder_.Load(VariableType::JS_ANY(), module, localExportEntriesOffset); GateRef nameDictionaryOffset = builder_.IntPtr(SourceTextModule::NAME_DICTIONARY_OFFSET); @@ -286,9 +286,8 @@ void NTypeHCRLowering::LowerLdLocalModuleVar(GateRef gate) Environment env(gate, circuit_, &builder_); GateRef jsFunc = acc_.GetValueIn(gate, 0); GateRef index = acc_.GetValueIn(gate, 1); - GateRef method = builder_.GetMethodFromFunction(jsFunc); - GateRef moduleOffset = builder_.IntPtr(Method::ECMA_MODULE_OFFSET); - GateRef module = builder_.Load(VariableType::JS_ANY(), method, moduleOffset); + GateRef moduleOffset = builder_.IntPtr(JSFunction::ECMA_MODULE_OFFSET); + GateRef module = builder_.Load(VariableType::JS_ANY(), jsFunc, moduleOffset); GateRef nameDictionaryOffset = builder_.IntPtr(SourceTextModule::NAME_DICTIONARY_OFFSET); GateRef dictionary = builder_.Load(VariableType::JS_ANY(), module, nameDictionaryOffset); DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole()); diff --git a/ecmascript/compiler/ntype_hcr_lowering.h b/ecmascript/compiler/ntype_hcr_lowering.h index 4998b2bac01db234947c7d844831c266e52e6c78..6732adbd79bab7625afc32a42900adb43b5ffd4d 100644 --- a/ecmascript/compiler/ntype_hcr_lowering.h +++ b/ecmascript/compiler/ntype_hcr_lowering.h @@ -74,7 +74,9 @@ private: JSTaggedValue GetArrayLiteralValue(uint32_t cpId, uint32_t cpIdx) { JSTaggedValue cp = GetConstantpoolValue(cpId); - return ConstantPool::GetLiteralFromCache(thread_, cp, cpIdx, recordName_); + JSTaggedValue unsharedCp = thread_->GetCurrentEcmaContext()->FindUnsharedConstpool(cp); + return ConstantPool::GetLiteralFromCache( + thread_, unsharedCp, cpIdx, recordName_); } Circuit *circuit_ {nullptr}; diff --git a/ecmascript/compiler/number_speculative_lowering.cpp b/ecmascript/compiler/number_speculative_lowering.cpp index aa9bf54aa7e7c8476a60840b74d964f195ccb45f..cb14beb03b45ef69bc49f8f973a5811a3f31c6fb 100644 --- a/ecmascript/compiler/number_speculative_lowering.cpp +++ b/ecmascript/compiler/number_speculative_lowering.cpp @@ -1007,7 +1007,8 @@ void NumberSpeculativeLowering::VisitLoadPropertyOnProto(GateRef gate) auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET); auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET); - auto holderHC = builder_.LoadHClassFromConstpool(constpool, acc_.GetConstantValue(hclassIndex)); + GateRef unsharedConstpool = builder_.GetUnsharedConstpool(constpool); + auto holderHC = builder_.LoadHClassFromUnsharedConstpool(unsharedConstpool, acc_.GetConstantValue(hclassIndex)); DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype); Label exit(&builder_); Label loopHead(&builder_); diff --git a/ecmascript/compiler/post_schedule.cpp b/ecmascript/compiler/post_schedule.cpp index 2297b0ce90db4e88a4167e838912961798c30abd..248bf1823771b14030ccc0df485023cbd73692ee 100644 --- a/ecmascript/compiler/post_schedule.cpp +++ b/ecmascript/compiler/post_schedule.cpp @@ -72,7 +72,8 @@ void PostSchedule::GenerateExtraBB(ControlFlowGraph &cfg) bool PostSchedule::VisitHeapAlloc(GateRef gate, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx) { - ASSERT(acc_.TryGetValue(gate) == RegionSpaceFlag::IN_YOUNG_SPACE); + ASSERT(acc_.TryGetValue(gate) == RegionSpaceFlag::IN_YOUNG_SPACE || + acc_.TryGetValue(gate) == RegionSpaceFlag::IN_SHARED_OLD_SPACE); std::vector currentBBGates; std::vector successBBGates; std::vector failBBGates; diff --git a/ecmascript/compiler/profiler_stub_builder.cpp b/ecmascript/compiler/profiler_stub_builder.cpp index 16be195c0edea8c4ca7ee70f8caacb2661ea018e..5bcf1fbe50a96b22e495ff1f98128a56d6d5e29b 100644 --- a/ecmascript/compiler/profiler_stub_builder.cpp +++ b/ecmascript/compiler/profiler_stub_builder.cpp @@ -407,7 +407,7 @@ GateRef ProfilerStubBuilder::UpdateTrackTypeInPropAttr(GateRef attr, GateRef val GateRef oldTrackType = GetTrackTypeInPropAttr(attr); DEFVARIABLE(newTrackType, VariableType::INT32(), Int32(static_cast(TrackType::TAGGED))); - DEFVARIABLE(result, VariableType::INT32(), attr); + DEFVARIABLE(result, VariableType::INT64(), attr); Label exit(env); Label judgeValue(env); @@ -451,8 +451,7 @@ void ProfilerStubBuilder::UpdatePropAttrIC( GateRef attrIndex = HandlerBaseGetAttrIndex(handler); GateRef hclass = LoadHClass(receiver); GateRef layout = GetLayoutFromHClass(hclass); - GateRef propAttr = GetPropAttrFromLayoutInfo(layout, attrIndex); - GateRef attr = GetInt32OfTInt(propAttr); + GateRef attr = GetPropAttrFromLayoutInfo(layout, attrIndex); GateRef newAttr = UpdateTrackTypeInPropAttr(attr, value, callback); BRANCH(IsJSShared(receiver), &exit, &handleUnShared); Bind(&handleUnShared); diff --git a/ecmascript/compiler/share_opcodes.h b/ecmascript/compiler/share_opcodes.h index 95f98df31502283b8658c130b200c52107aa1d51..55a233709a80355b32e9b37a6271493f51469ec0 100644 --- a/ecmascript/compiler/share_opcodes.h +++ b/ecmascript/compiler/share_opcodes.h @@ -45,6 +45,7 @@ namespace panda::ecmascript::kungfu { V(IfSuccess, IF_SUCCESS, GateFlags::CONTROL, 1, 0, 0) \ V(IfException, IF_EXCEPTION, GateFlags::CONTROL, 1, 1, 0) \ V(GetException, GET_EXCEPTION, GateFlags::NONE_FLAG, 1, 1, 0) \ + V(GetUnsharedConstpool, GET_UNSHARED_CONSTPOOL, GateFlags::NO_WRITE, 0, 1, 1) \ V(GetGlobalEnv, GET_GLOBAL_ENV, GateFlags::NO_WRITE, 0, 1, 0) \ V(GetSuperConstructor, GET_SUPER_CONSTRUCTOR, GateFlags::NO_WRITE, 1, 1, 1) \ V(CheckSafePointAndStackOver, CHECK_SAFEPOINT_AND_STACKOVER, GateFlags::NO_WRITE, 1, 1, 0) \ diff --git a/ecmascript/compiler/slowpath_lowering.cpp b/ecmascript/compiler/slowpath_lowering.cpp index bc343ea6b5bf39dd2f8df43e824f9eb959badb62..67fb5c6e31d5e916721db66f5c870f7a4c684205 100644 --- a/ecmascript/compiler/slowpath_lowering.cpp +++ b/ecmascript/compiler/slowpath_lowering.cpp @@ -745,6 +745,10 @@ void SlowPathLowering::Lower(GateRef gate) case EcmaOpcode::CALLRUNTIME_LDSENDABLECLASS_PREF_IMM16: LowerLdSendableClass(gate); break; + case EcmaOpcode::CALLRUNTIME_LDSENDABLEEXTERNALMODULEVAR_PREF_IMM8: + case EcmaOpcode::CALLRUNTIME_WIDELDSENDABLEEXTERNALMODULEVAR_PREF_IMM16: + LowerSendableExternalModule(gate); + break; case EcmaOpcode::LDA_STR_ID16: LowerLdStr(gate); break; @@ -2674,7 +2678,7 @@ void SlowPathLowering::LowerDefineMethod(GateRef gate) Label successExit(&builder_); Label exceptionExit(&builder_); GateRef result = LowerCallRuntime(gate, RTSTUB_ID(DefineMethod), - {method, homeObject, builder_.ToTaggedInt(length), env}, true); + {method, homeObject, builder_.ToTaggedInt(length), env, builder_.GetModuleFromFunction(jsFunc)}, true); BRANCH_CIR(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION), &exceptionExit, &successExit); CREATE_DOUBLE_EXIT(successExit, exceptionExit) @@ -2967,7 +2971,7 @@ void SlowPathLowering::LowerFastCall(GateRef gate, GateRef glue, GateRef func, G builder_.Bind(&call); { builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true); - GateRef code = builder_.GetCodeAddr(method); + GateRef code = builder_.GetCodeAddr(func); auto depend = builder_.GetDepend(); const CallSignature *cs = RuntimeStubCSigns::GetOptimizedFastCallSign(); result->WriteVariable(builder_.Call(cs, glue, code, depend, argsFastCall, gate, "callFastAOT")); @@ -2997,7 +3001,7 @@ void SlowPathLowering::LowerFastCall(GateRef gate, GateRef glue, GateRef func, G builder_.Bind(&call1); { builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true); - GateRef code = builder_.GetCodeAddr(method); + GateRef code = builder_.GetCodeAddr(func); auto depend = builder_.GetDepend(); const CallSignature *cs = RuntimeStubCSigns::GetOptimizedCallSign(); result->WriteVariable(builder_.Call(cs, glue, code, depend, args, gate, "callAOT")); @@ -3043,8 +3047,7 @@ void SlowPathLowering::LowerTypedCall(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef func = acc_.GetValueIn(gate, static_cast(CommonArgIdx::FUNC)); - GateRef method = builder_.GetMethodFromFunction(func); - GateRef code = builder_.GetCodeAddr(method); + GateRef code = builder_.GetCodeAddr(func); size_t num = acc_.GetNumValueIn(gate); std::vector args(num); for (size_t i = 0; i < num; ++i) { @@ -3061,8 +3064,7 @@ void SlowPathLowering::LowerTypedFastCall(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef func = acc_.GetValueIn(gate, static_cast(FastCallArgIdx::FUNC)); - GateRef method = builder_.GetMethodFromFunction(func); - GateRef code = builder_.GetCodeAddr(method); + GateRef code = builder_.GetCodeAddr(func); size_t num = acc_.GetNumValueIn(gate); std::vector args(num); for (size_t i = 0; i < num; ++i) { @@ -3278,6 +3280,16 @@ void SlowPathLowering::LowerLdSendableClass(GateRef gate) ReplaceHirWithValue(gate, newGate); } +void SlowPathLowering::LowerSendableExternalModule(GateRef gate) +{ + ASSERT(acc_.GetNumValueIn(gate) == 1); + GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC); + GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0)); + GateRef result = LowerCallRuntime(gate, + RTSTUB_ID(LdSendableExternalModuleVarByIndex), {index, jsFunc}, true); + ReplaceHirWithValue(gate, result); +} + void SlowPathLowering::LowerCallInit(GateRef gate) { // same as callthis0 diff --git a/ecmascript/compiler/slowpath_lowering.h b/ecmascript/compiler/slowpath_lowering.h index b4ddd2a377ff837dfdeaff49bf4702215a0eedb4..b6480eb1720ecdf53a20c9812427b32c7fec100a 100644 --- a/ecmascript/compiler/slowpath_lowering.h +++ b/ecmascript/compiler/slowpath_lowering.h @@ -237,6 +237,7 @@ private: void LowerLdLocalModuleVarByIndex(GateRef gate); void LowerExternalModule(GateRef gate); void LowerGetModuleNamespace(GateRef gate); + void LowerSendableExternalModule(GateRef gate); void LowerSuperCall(GateRef gate); void LowerSuperCallArrow(GateRef gate); void LowerSuperCallSpread(GateRef gate); diff --git a/ecmascript/compiler/stub_builder-inl.h b/ecmascript/compiler/stub_builder-inl.h index fb4e9699acf2c92a164a28c3f17ab57448956276..2a150704efc33c7aadf02754995997c20e531191 100644 --- a/ecmascript/compiler/stub_builder-inl.h +++ b/ecmascript/compiler/stub_builder-inl.h @@ -243,9 +243,9 @@ inline GateRef StubBuilder::CallOptimized(GateRef glue, GateRef code, const std: return result; } -inline GateRef StubBuilder::GetAotCodeAddr(GateRef method) +inline GateRef StubBuilder::GetAotCodeAddr(GateRef jsFunc) { - return env_->GetBuilder()->GetCodeAddr(method); + return env_->GetBuilder()->GetCodeAddr(jsFunc); } inline GateRef StubBuilder::CallStub(GateRef glue, int index, const std::initializer_list& args) @@ -1435,7 +1435,7 @@ inline GateRef StubBuilder::IsWritable(GateRef attr) { return Int32NotEqual( Int32And( - Int32LSR(attr, Int32(PropertyAttributes::WritableField::START_BIT)), + TruncInt64ToInt32(Int64LSR(attr, Int64(PropertyAttributes::WritableField::START_BIT))), Int32((1LLU << PropertyAttributes::WritableField::SIZE) - 1)), Int32(0)); } @@ -1444,7 +1444,7 @@ inline GateRef StubBuilder::IsDefaultAttribute(GateRef attr) { return Int32NotEqual( Int32And( - Int32LSR(attr, Int32(PropertyAttributes::DefaultAttributesField::START_BIT)), + TruncInt64ToInt32(Int64LSR(attr, Int64(PropertyAttributes::DefaultAttributesField::START_BIT))), Int32((1LLU << PropertyAttributes::DefaultAttributesField::SIZE) - 1)), Int32(0)); } @@ -1453,7 +1453,7 @@ inline GateRef StubBuilder::IsConfigable(GateRef attr) { return Int32NotEqual( Int32And( - Int32LSR(attr, Int32(PropertyAttributes::ConfigurableField::START_BIT)), + TruncInt64ToInt32(Int64LSR(attr, Int64(PropertyAttributes::ConfigurableField::START_BIT))), Int32((1LLU << PropertyAttributes::ConfigurableField::SIZE) - 1)), Int32(0)); } @@ -1461,8 +1461,8 @@ inline GateRef StubBuilder::IsConfigable(GateRef attr) inline GateRef StubBuilder::IsAccessor(GateRef attr) { return Int32NotEqual( - Int32And(Int32LSR(attr, - Int32(PropertyAttributes::IsAccessorField::START_BIT)), + Int32And( + TruncInt64ToInt32(Int64LSR(attr, Int64(PropertyAttributes::IsAccessorField::START_BIT))), Int32((1LLU << PropertyAttributes::IsAccessorField::SIZE) - 1)), Int32(0)); } @@ -1470,8 +1470,8 @@ inline GateRef StubBuilder::IsAccessor(GateRef attr) inline GateRef StubBuilder::IsEnumerable(GateRef attr) { return Int32NotEqual( - Int32And(Int32LSR(attr, - Int32(PropertyAttributes::EnumerableField::START_BIT)), + Int32And( + TruncInt64ToInt32(Int64LSR(attr, Int64(PropertyAttributes::EnumerableField::START_BIT))), Int32((1LLU << PropertyAttributes::EnumerableField::SIZE) - 1)), Int32(0)); } @@ -1479,8 +1479,8 @@ inline GateRef StubBuilder::IsEnumerable(GateRef attr) inline GateRef StubBuilder::IsInlinedProperty(GateRef attr) { return Int32NotEqual( - Int32And(Int32LSR(attr, - Int32(PropertyAttributes::IsInlinedPropsField::START_BIT)), + Int32And( + TruncInt64ToInt32(Int64LSR(attr, Int64(PropertyAttributes::IsInlinedPropsField::START_BIT))), Int32((1LLU << PropertyAttributes::IsInlinedPropsField::SIZE) - 1)), Int32(0)); } @@ -1800,18 +1800,18 @@ inline GateRef StubBuilder::GetTransWithProtoHandlerInfo(GateRef obj) inline GateRef StubBuilder::PropAttrGetOffset(GateRef attr) { return Int32And( - Int32LSR(attr, Int32(PropertyAttributes::OffsetField::START_BIT)), + TruncInt64ToInt32(Int64LSR(attr, Int64(PropertyAttributes::OffsetField::START_BIT))), Int32((1LLU << PropertyAttributes::OffsetField::SIZE) - 1)); } // SetDictionaryOrder func in property_attribute.h inline GateRef StubBuilder::SetDictionaryOrderFieldInPropAttr(GateRef attr, GateRef value) { - GateRef mask = Int32LSL( - Int32((1LLU << PropertyAttributes::DictionaryOrderField::SIZE) - 1), - Int32(PropertyAttributes::DictionaryOrderField::START_BIT)); - GateRef newVal = Int32Or(Int32And(attr, Int32Not(mask)), - Int32LSL(value, Int32(PropertyAttributes::DictionaryOrderField::START_BIT))); + GateRef mask = Int64LSL( + Int64((1LLU << PropertyAttributes::DictionaryOrderField::SIZE) - 1), + Int64(PropertyAttributes::DictionaryOrderField::START_BIT)); + GateRef newVal = Int64Or(Int64And(attr, Int64Not(mask)), + Int64LSL(value, Int64(PropertyAttributes::DictionaryOrderField::START_BIT))); return newVal; } @@ -2106,6 +2106,20 @@ inline GateRef StubBuilder::GetValueFromTaggedArray(GateRef array, GateRef index return Load(VariableType::JS_ANY(), array, dataOffset); } +inline GateRef StubBuilder::GetUnsharedConstpoolIndex(GateRef constpool) +{ + GateRef constPoolSize = GetLengthOfTaggedArray(constpool); + GateRef unshareIdx = Int32Sub(constPoolSize, Int32(ConstantPool::UNSHARED_CONSTPOOL_INDEX)); + return GetValueFromTaggedArray(constpool, unshareIdx); +} + +inline GateRef StubBuilder::GetUnsharedConstpool(GateRef arrayAddr, GateRef index) +{ + GateRef dataOffset = + PtrAdd(arrayAddr, PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()), ZExtInt32ToPtr(TaggedGetInt(index)))); + return Load(VariableType::JS_ANY(), dataOffset); +} + inline GateRef StubBuilder::GetValueFromMutantTaggedArray(GateRef elements, GateRef index) { GateRef offset = PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(int64_t))); @@ -2127,8 +2141,8 @@ inline void StubBuilder::CheckUpdateSharedType(bool isDicMode, Variable *result, Bind(&isSharedObj); { Label typeMismatch(env); - GateRef trackType = isDicMode ? GetDictTrackTypeInPropAttr(attr) : GetTrackTypeInPropAttr(attr); - MatchTrackType(trackType, value, executeSetProp, &typeMismatch); + GateRef fieldType = isDicMode ? GetDictSharedFieldTypeInPropAttr(attr) : GetSharedFieldTypeInPropAttr(attr); + MatchFieldType(fieldType, value, executeSetProp, &typeMismatch); Bind(&typeMismatch); { GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetTypeMismatchedSharedProperty)); @@ -2139,12 +2153,12 @@ inline void StubBuilder::CheckUpdateSharedType(bool isDicMode, Variable *result, } } -inline void StubBuilder::MatchTrackType(Variable *result, GateRef glue, GateRef trackType, GateRef value, +inline void StubBuilder::MatchFieldType(Variable *result, GateRef glue, GateRef fieldType, GateRef value, Label *executeSetProp, Label *exit) { auto *env = GetEnvironment(); Label typeMismatch(env); - MatchTrackType(trackType, value, executeSetProp, &typeMismatch); + MatchFieldType(fieldType, value, executeSetProp, &typeMismatch); Bind(&typeMismatch); { GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetTypeMismatchedSharedProperty)); @@ -2154,11 +2168,11 @@ inline void StubBuilder::MatchTrackType(Variable *result, GateRef glue, GateRef } } -inline GateRef StubBuilder::GetTrackTypeFromHandler(GateRef attr) +inline GateRef StubBuilder::GetFieldTypeFromHandler(GateRef attr) { return Int32And(Int32LSR(attr, - Int32(HandlerBase::STrackTypeBit::START_BIT)), - Int32((1LLU << HandlerBase::STrackTypeBit::SIZE) - 1)); + Int32(HandlerBase::SFieldTypeBit::START_BIT)), + Int32((1LLU << HandlerBase::SFieldTypeBit::SIZE) - 1)); } inline GateRef StubBuilder::ClearSharedStoreKind(GateRef handlerInfo) @@ -2213,13 +2227,14 @@ inline void StubBuilder::SetPropAttrToLayoutInfo(GateRef glue, GateRef layout, G { GateRef index = Int32Add(Int32LSL(entry, Int32(LayoutInfo::ELEMENTS_INDEX_LOG2)), Int32(LayoutInfo::ATTR_INDEX_OFFSET)); - GateRef taggedAttr = Int64ToTaggedInt(ZExtInt32ToInt64(attr)); + GateRef taggedAttr = Int64ToTaggedInt(attr); SetValueToTaggedArray(VariableType::JS_ANY(), glue, layout, index, taggedAttr); } inline GateRef StubBuilder::GetPropertyMetaDataFromAttr(GateRef attr) { - return Int32And(Int32LSR(attr, Int32(PropertyAttributes::PropertyMetaDataField::START_BIT)), + return Int32And( + TruncInt64ToInt32(Int64LSR(attr, Int64(PropertyAttributes::PropertyMetaDataField::START_BIT))), Int32((1LLU << PropertyAttributes::PropertyMetaDataField::SIZE) - 1)); } @@ -2462,61 +2477,68 @@ inline GateRef StubBuilder::IsCallable(GateRef obj) inline GateRef StubBuilder::GetOffsetFieldInPropAttr(GateRef attr) { return Int32And( - Int32LSR(attr, Int32(PropertyAttributes::OffsetField::START_BIT)), + TruncInt64ToInt32(Int64LSR(attr, Int64(PropertyAttributes::OffsetField::START_BIT))), Int32((1LLU << PropertyAttributes::OffsetField::SIZE) - 1)); } // SetOffset func in property_attribute.h inline GateRef StubBuilder::SetOffsetFieldInPropAttr(GateRef attr, GateRef value) { - GateRef mask = Int32LSL( - Int32((1LLU << PropertyAttributes::OffsetField::SIZE) - 1), - Int32(PropertyAttributes::OffsetField::START_BIT)); - GateRef newVal = Int32Or(Int32And(attr, Int32Not(mask)), - Int32LSL(value, Int32(PropertyAttributes::OffsetField::START_BIT))); + GateRef mask = Int64LSL( + Int64((1LLU << PropertyAttributes::OffsetField::SIZE) - 1), + Int64(PropertyAttributes::OffsetField::START_BIT)); + GateRef newVal = Int64Or(Int64And(attr, Int64Not(mask)), + Int64LSL(ZExtInt32ToInt64(value), Int64(PropertyAttributes::OffsetField::START_BIT))); return newVal; } // SetIsInlinedProps func in property_attribute.h inline GateRef StubBuilder::SetIsInlinePropsFieldInPropAttr(GateRef attr, GateRef value) { - GateRef mask = Int32LSL( - Int32((1LU << PropertyAttributes::IsInlinedPropsField::SIZE) - 1), - Int32(PropertyAttributes::IsInlinedPropsField::START_BIT)); - GateRef newVal = Int32Or(Int32And(attr, Int32Not(mask)), - Int32LSL(value, Int32(PropertyAttributes::IsInlinedPropsField::START_BIT))); + GateRef mask = Int64LSL( + Int64((1LU << PropertyAttributes::IsInlinedPropsField::SIZE) - 1), + Int64(PropertyAttributes::IsInlinedPropsField::START_BIT)); + GateRef newVal = Int64Or(Int64And(attr, Int64Not(mask)), + Int64LSL(ZExtInt32ToInt64(value), Int64(PropertyAttributes::IsInlinedPropsField::START_BIT))); return newVal; } inline GateRef StubBuilder::SetTrackTypeInPropAttr(GateRef attr, GateRef type) { - GateRef mask = Int32LSL( - Int32((1LU << PropertyAttributes::TrackTypeField::SIZE) - 1), - Int32(PropertyAttributes::TrackTypeField::START_BIT)); - GateRef newVal = Int32Or(Int32And(attr, Int32Not(mask)), - Int32LSL(type, Int32(PropertyAttributes::TrackTypeField::START_BIT))); + GateRef mask = Int64LSL( + Int64((1LU << PropertyAttributes::TrackTypeField::SIZE) - 1), + Int64(PropertyAttributes::TrackTypeField::START_BIT)); + GateRef newVal = Int64Or(Int64And(attr, Int64Not(mask)), + Int64LSL(ZExtInt32ToInt64(type), Int64(PropertyAttributes::TrackTypeField::START_BIT))); return newVal; } +inline GateRef StubBuilder::GetSharedFieldTypeInPropAttr(GateRef attr) +{ + return Int32And( + TruncInt64ToInt32(Int64LSR(attr, Int64(PropertyAttributes::SharedFieldTypeField::START_BIT))), + Int32((1LLU << PropertyAttributes::SharedFieldTypeField::SIZE) - 1)); +} + inline GateRef StubBuilder::GetTrackTypeInPropAttr(GateRef attr) { return Int32And( - Int32LSR(attr, Int32(PropertyAttributes::TrackTypeField::START_BIT)), + TruncInt64ToInt32(Int64LSR(attr, Int64(PropertyAttributes::TrackTypeField::START_BIT))), Int32((1LLU << PropertyAttributes::TrackTypeField::SIZE) - 1)); } -inline GateRef StubBuilder::GetDictTrackTypeInPropAttr(GateRef attr) +inline GateRef StubBuilder::GetDictSharedFieldTypeInPropAttr(GateRef attr) { return Int32And( - Int32LSR(attr, Int32(PropertyAttributes::DictTrackTypeField::START_BIT)), - Int32((1LLU << PropertyAttributes::DictTrackTypeField::SIZE) - 1)); + TruncInt64ToInt32(Int64LSR(attr, Int64(PropertyAttributes::DictSharedFieldTypeField::START_BIT))), + Int32((1LLU << PropertyAttributes::DictSharedFieldTypeField::SIZE) - 1)); } inline GateRef StubBuilder::GetRepInPropAttr(GateRef attr) { return Int32And( - Int32LSR(attr, Int32(PropertyAttributes::RepresentationField::START_BIT)), + TruncInt64ToInt32(Int64LSR(attr, Int64(PropertyAttributes::RepresentationField::START_BIT))), Int32((1LLU << PropertyAttributes::RepresentationField::SIZE) - 1)); } @@ -2532,12 +2554,12 @@ inline GateRef StubBuilder::IsDoubleRepInPropAttr(GateRef rep) inline GateRef StubBuilder::SetTaggedRepInPropAttr(GateRef attr) { - GateRef mask = Int32LSL( - Int32((1LU << PropertyAttributes::RepresentationField::SIZE) - 1), - Int32(PropertyAttributes::RepresentationField::START_BIT)); - GateRef targetType = Int32(static_cast(Representation::TAGGED)); - GateRef newVal = Int32Or(Int32And(attr, Int32Not(mask)), - Int32LSL(targetType, Int32(PropertyAttributes::RepresentationField::START_BIT))); + GateRef mask = Int64LSL( + Int64((1LU << PropertyAttributes::RepresentationField::SIZE) - 1), + Int64(PropertyAttributes::RepresentationField::START_BIT)); + GateRef targetType = Int32(static_cast(Representation::TAGGED)); + GateRef newVal = Int64Or(Int64And(attr, Int64Not(mask)), + Int64LSL(ZExtInt32ToInt64(targetType), Int64(PropertyAttributes::RepresentationField::START_BIT))); return newVal; } @@ -2587,6 +2609,42 @@ inline GateRef StubBuilder::InYoungGeneration(GateRef region) } } +inline GateRef StubBuilder::InSharedHeap(GateRef region) +{ + auto offset = Region::PackedData::GetFlagOffset(env_->Is32Bit()); + GateRef x = Load(VariableType::NATIVE_POINTER(), PtrAdd(IntPtr(offset), region), + IntPtr(0)); + if (env_->Is32Bit()) { + GateRef spaceType = Int32And(x, Int32(RegionSpaceFlag::VALID_SPACE_MASK)); + GateRef greater = Int32GreaterThanOrEqual(spaceType, Int32(RegionSpaceFlag::SHARED_SPACE_BEGIN)); + GateRef less = Int32LessThanOrEqual(spaceType, Int32(RegionSpaceFlag::SHARED_SPACE_END)); + return BoolAnd(greater, less); + } else { + GateRef spaceType = Int64And(x, Int64(RegionSpaceFlag::VALID_SPACE_MASK)); + GateRef greater = Int64GreaterThanOrEqual(spaceType, Int64(RegionSpaceFlag::SHARED_SPACE_BEGIN)); + GateRef less = Int64LessThanOrEqual(spaceType, Int64(RegionSpaceFlag::SHARED_SPACE_END)); + return BoolAnd(greater, less); + } +} + +inline GateRef StubBuilder::InSharedSweepableSpace(GateRef region) +{ + auto offset = Region::PackedData::GetFlagOffset(env_->Is32Bit()); + GateRef x = Load(VariableType::NATIVE_POINTER(), PtrAdd(IntPtr(offset), region), + IntPtr(0)); + if (env_->Is32Bit()) { + GateRef spaceType = Int32And(x, Int32(RegionSpaceFlag::VALID_SPACE_MASK)); + GateRef greater = Int32GreaterThanOrEqual(spaceType, Int32(RegionSpaceFlag::SHARED_SWEEPABLE_SPACE_BEGIN)); + GateRef less = Int32LessThanOrEqual(spaceType, Int32(RegionSpaceFlag::SHARED_SWEEPABLE_SPACE_END)); + return BoolAnd(greater, less); + } else { + GateRef spaceType = Int64And(x, Int64(RegionSpaceFlag::VALID_SPACE_MASK)); + GateRef greater = Int64GreaterThanOrEqual(spaceType, Int64(RegionSpaceFlag::SHARED_SWEEPABLE_SPACE_BEGIN)); + GateRef less = Int64LessThanOrEqual(spaceType, Int64(RegionSpaceFlag::SHARED_SWEEPABLE_SPACE_END)); + return BoolAnd(greater, less); + } +} + inline GateRef StubBuilder::GetParentEnv(GateRef object) { GateRef index = Int32(LexicalEnv::PARENT_ENV_INDEX); @@ -2663,6 +2721,12 @@ inline void StubBuilder::SetHomeObjectToFunction(GateRef glue, GateRef function, Store(VariableType::JS_ANY(), glue, function, offset, value); } +inline void StubBuilder::SetModuleToFunction(GateRef glue, GateRef function, GateRef value) +{ + GateRef offset = IntPtr(JSFunction::ECMA_MODULE_OFFSET); + Store(VariableType::JS_POINTER(), glue, function, offset, value); +} + inline void StubBuilder::SetWorkNodePointerToFunction(GateRef glue, GateRef function, GateRef value) { GateRef offset = IntPtr(JSFunction::WORK_NODE_POINTER_OFFSET); @@ -2675,6 +2739,14 @@ inline void StubBuilder::SetMethodToFunction(GateRef glue, GateRef function, Gat Store(VariableType::JS_ANY(), glue, function, offset, value); } +inline void StubBuilder::SetCodeEntryToFunction(GateRef glue, GateRef function, GateRef value) +{ + GateRef methodOffset = IntPtr(Method::CODEENTRY_LITERAL_OFFSET); + GateRef codeEntry = Load(VariableType::NATIVE_POINTER(), value, methodOffset); + GateRef funcOffset = IntPtr(JSFunctionBase::CODE_ENTRY_OFFSET); + Store(VariableType::NATIVE_POINTER(), glue, function, funcOffset, codeEntry); +} + inline void StubBuilder::SetLengthToFunction(GateRef glue, GateRef function, GateRef value) { GateRef offset = IntPtr(JSFunctionBase::LENGTH_OFFSET); @@ -2870,8 +2942,8 @@ inline GateRef StubBuilder::GetGlobalConstantValue(VariableType type, GateRef gl inline GateRef StubBuilder::GetSingleCharTable(GateRef glue) { - return Load(VariableType::JS_ANY(), glue, - IntPtr(JSThread::GlueData::GetSingleCharTableOffset(env_->Is32Bit()))); + return GetGlobalConstantValue( + VariableType::JS_POINTER(), glue, ConstantIndex::SINGLE_CHAR_TABLE_INDEX); } inline GateRef StubBuilder::GetGlobalEnvValue(VariableType type, GateRef env, size_t index) @@ -3034,8 +3106,7 @@ inline GateRef StubBuilder::IsTypedArray(GateRef obj) inline GateRef StubBuilder::GetProfileTypeInfo(GateRef jsFunc) { - GateRef method = GetMethodFromFunction(jsFunc); - return Load(VariableType::JS_POINTER(), method, IntPtr(Method::PROFILE_TYPE_INFO_OFFSET)); + return Load(VariableType::JS_POINTER(), jsFunc, IntPtr(JSFunction::PROFILE_TYPE_INFO_OFFSET)); } inline void StubBuilder::CheckDetectorName(GateRef glue, GateRef key, Label *fallthrough, Label *slow) @@ -3128,7 +3199,7 @@ inline GateRef StubBuilder::GetKeyIndex(GateRef index) inline GateRef StubBuilder::GetAttr(GateRef layoutInfo, GateRef index) { GateRef fixedIdx = GetAttrIndex(index); - return GetInt32OfTInt(GetValueFromTaggedArray(layoutInfo, fixedIdx)); + return GetInt64OfTInt(GetValueFromTaggedArray(layoutInfo, fixedIdx)); } inline GateRef StubBuilder::GetKey(GateRef layoutInfo, GateRef index) diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index d1fba4c748511ed388dd099675625b8f084976fc..aad5dca9987d5f95109ebf73e974ce2abfd1e4de 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -114,7 +114,7 @@ void StubBuilder::LoopEnd(Label *loopHead) env_->SetCurrentLabel(nullptr); } -void StubBuilder::MatchTrackType(GateRef trackType, GateRef value, Label *executeSetProp, Label *typeMismatch) +void StubBuilder::MatchFieldType(GateRef fieldType, GateRef value, Label *executeSetProp, Label *typeMismatch) { auto *env = GetEnvironment(); Label isNumber(env); @@ -124,11 +124,13 @@ void StubBuilder::MatchTrackType(GateRef trackType, GateRef value, Label *execut Label isString(env); Label checkJSShared(env); Label isJSShared(env); + Label checkBigInt(env); + Label isBigInt(env); Label checkJSNone(env); Label isJSNone(env); Label exit(env); DEFVARIABLE(result, VariableType::BOOL(), False()); - BRANCH(Equal(trackType, Int32(static_cast(TrackType::NUMBER))), &isNumber, &checkBoolean); + BRANCH(Equal(fieldType, Int32(static_cast(SharedFieldType::NUMBER))), &isNumber, &checkBoolean); Bind(&isNumber); { result = TaggedIsNumber(value); @@ -136,7 +138,7 @@ void StubBuilder::MatchTrackType(GateRef trackType, GateRef value, Label *execut } Bind(&checkBoolean); { - BRANCH(Equal(trackType, Int32(static_cast(TrackType::BOOLEAN))), &isBoolean, &checkString); + BRANCH(Equal(fieldType, Int32(static_cast(SharedFieldType::BOOLEAN))), &isBoolean, &checkString); Bind(&isBoolean); { result = TaggedIsBoolean(value); @@ -145,7 +147,7 @@ void StubBuilder::MatchTrackType(GateRef trackType, GateRef value, Label *execut } Bind(&checkString); { - BRANCH(Equal(trackType, Int32(static_cast(TrackType::STRING))), &isString, &checkJSShared); + BRANCH(Equal(fieldType, Int32(static_cast(SharedFieldType::STRING))), &isString, &checkJSShared); Bind(&isString); { result = BoolOr(TaggedIsString(value), TaggedIsNull(value)); @@ -154,16 +156,25 @@ void StubBuilder::MatchTrackType(GateRef trackType, GateRef value, Label *execut } Bind(&checkJSShared); { - BRANCH(Equal(trackType, Int32(static_cast(TrackType::SENDABLE))), &isJSShared, &checkJSNone); + BRANCH(Equal(fieldType, Int32(static_cast(SharedFieldType::SENDABLE))), &isJSShared, &checkBigInt); Bind(&isJSShared); { result = BoolOr(TaggedIsShared(value), TaggedIsNull(value)); Jump(&exit); } } + Bind(&checkBigInt); + { + BRANCH(Equal(fieldType, Int32(static_cast(SharedFieldType::BIG_INT))), &isBigInt, &checkJSNone); + Bind(&isBigInt); + { + result = TaggedIsBigInt(value); + Jump(&exit); + } + } Bind(&checkJSNone); { - BRANCH(Equal(trackType, Int32(static_cast(TrackType::NONE))), &isJSNone, &exit); + BRANCH(Equal(fieldType, Int32(static_cast(SharedFieldType::NONE))), &isJSNone, &exit); Bind(&isJSNone); { // bypass none type @@ -399,7 +410,6 @@ GateRef StubBuilder::IsMatchInTransitionDictionary(GateRef element, GateRef key, return BoolAnd(Equal(element, key), Int32Equal(metaData, attr)); } -// metaData is int32 type GateRef StubBuilder::FindEntryFromTransitionDictionary(GateRef glue, GateRef elements, GateRef key, GateRef metaData) { auto env = GetEnvironment(); @@ -475,9 +485,9 @@ GateRef StubBuilder::FindEntryFromTransitionDictionary(GateRef glue, GateRef ele { Label isMatch(env); Label notMatch(env); - BRANCH( - IsMatchInTransitionDictionary(element, key, metaData, - GetAttributesFromDictionary(elements, *entry)), + BRANCH(IsMatchInTransitionDictionary(element, key, metaData, + // metaData is int32 type + TruncInt64ToInt32(GetAttributesFromDictionary(elements, *entry))), &isMatch, ¬Match); { Bind(&isMatch); @@ -837,7 +847,7 @@ void StubBuilder::JSHClassAddProperty(GateRef glue, GateRef receiver, GateRef ke IntToTaggedInt(inlineProps) }); CopyAllHClass(glue, newJshclass, hclass); CallRuntime(glue, RTSTUB_ID(UpdateLayOutAndAddTransition), - { hclass, newJshclass, key, IntToTaggedInt(attr) }); + { hclass, newJshclass, key, Int64ToTaggedInt(attr) }); #if ECMASCRIPT_ENABLE_IC NotifyHClassChanged(glue, hclass, newJshclass); #endif @@ -889,7 +899,7 @@ GateRef StubBuilder::AddPropertyByName(GateRef glue, GateRef receiver, GateRef k } Bind(&afterCtorCon); // 0x111 : default attribute for property: writable, enumerable, configurable - DEFVARIABLE(attr, VariableType::INT32(), propertyAttributes); + DEFVARIABLE(attr, VariableType::INT64(), propertyAttributes); GateRef numberOfProps = GetNumberOfPropsFromHClass(hclass); GateRef inlinedProperties = GetInlinedPropertiesFromHClass(hclass); Label hasUnusedInProps(env); @@ -909,7 +919,7 @@ GateRef StubBuilder::AddPropertyByName(GateRef glue, GateRef receiver, GateRef k GateRef newHclass = LoadHClass(receiver); GateRef newLayoutInfo = GetLayoutFromHClass(newHclass); GateRef offset = GetInlinedPropOffsetFromHClass(hclass, numberOfProps); - attr = GetInt32OfTInt(GetPropAttrFromLayoutInfo(newLayoutInfo, numberOfProps)); + attr = GetPropAttrFromLayoutInfo(newLayoutInfo, numberOfProps); SetValueWithAttr(glue, receiver, offset, key, value, *attr); result = Undefined(); Jump(&exit); @@ -941,7 +951,7 @@ GateRef StubBuilder::AddPropertyByName(GateRef glue, GateRef receiver, GateRef k Bind(&isDictMode); { GateRef res = CallRuntime(glue, RTSTUB_ID(NameDictPutIfAbsent), - {receiver, *array, key, value, IntToTaggedInt(*attr), TaggedFalse()}); + {receiver, *array, key, value, Int64ToTaggedInt(*attr), TaggedFalse()}); SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, res); Jump(&exit); } @@ -960,7 +970,7 @@ GateRef StubBuilder::AddPropertyByName(GateRef glue, GateRef receiver, GateRef k attr = SetDictionaryOrderFieldInPropAttr(*attr, Int32(PropertyAttributes::MAX_FAST_PROPS_CAPACITY)); GateRef res = CallRuntime(glue, RTSTUB_ID(NameDictPutIfAbsent), - { receiver, *array, key, value, IntToTaggedInt(*attr), TaggedTrue() }); + { receiver, *array, key, value, Int64ToTaggedInt(*attr), TaggedTrue() }); SetPropertiesArray(VariableType::JS_POINTER(), glue, receiver, res); result = Undefined(); Jump(&exit); @@ -1234,11 +1244,22 @@ void StubBuilder::SetValueWithBarrier(GateRef glue, GateRef obj, GateRef offset, Label exit(env); Label isVailedIndex(env); Label notValidIndex(env); - + Label shareBarrier(env); + Label shareBarrierExit(env); // ObjectAddressToRange function may cause obj is not an object. GC may not mark this obj. GateRef objectRegion = ObjectAddressToRange(obj); GateRef valueRegion = ObjectAddressToRange(value); GateRef slotAddr = PtrAdd(TaggedCastToIntPtr(obj), offset); + GateRef objectNotInShare = BoolNot(InSharedHeap(objectRegion)); + GateRef valueRegionInShare = InSharedSweepableSpace(valueRegion); + BRANCH(BoolAnd(objectNotInShare, valueRegionInShare), &shareBarrier, &shareBarrierExit); + Bind(&shareBarrier); + { + // todo(lukai) fastpath + CallNGCRuntime(glue, RTSTUB_ID(InsertLocalToShareRSet), { glue, obj, offset }); + Jump(&shareBarrierExit); + } + Bind(&shareBarrierExit); GateRef objectNotInYoung = BoolNot(InYoungGeneration(objectRegion)); GateRef valueRegionInYoung = InYoungGeneration(valueRegion); BRANCH(BoolAnd(objectNotInYoung, valueRegionInYoung), &isVailedIndex, ¬ValidIndex); @@ -1719,6 +1740,7 @@ GateRef StubBuilder::LoadICWithHandler( Label handlerIsPrototypeHandler(env); Label handlerNotPrototypeHandler(env); Label cellHasChanged(env); + Label cellNotUndefined(env); Label loopHead(env); Label loopEnd(env); DEFVARIABLE(result, VariableType::JS_ANY(), Undefined()); @@ -1775,6 +1797,8 @@ GateRef StubBuilder::LoadICWithHandler( Bind(&handlerIsPrototypeHandler); { GateRef cellValue = GetProtoCell(*handler); + BRANCH(TaggedIsUndefined(cellValue), &loopEnd, &cellNotUndefined); + Bind(&cellNotUndefined); BRANCH(GetHasChanged(cellValue), &cellHasChanged, &loopEnd); Bind(&cellHasChanged); { @@ -2073,6 +2097,7 @@ GateRef StubBuilder::StoreICWithHandler(GateRef glue, GateRef receiver, GateRef Label aotHandlerInfoNotField(env); Label cellHasChanged(env); Label cellNotChanged(env); + Label cellNotUndefined(env); Label aotCellNotChanged(env); Label loopHead(env); Label loopEnd(env); @@ -2099,8 +2124,8 @@ GateRef StubBuilder::StoreICWithHandler(GateRef glue, GateRef receiver, GateRef BRANCH(IsStoreShared(handlerInfo), &isShared, ¬Shared); Bind(&isShared); { - GateRef trackType = GetTrackTypeFromHandler(handlerInfo); - MatchTrackType(&result, glue, trackType, value, &prepareIntHandlerLoop, &exit); + GateRef field = GetFieldTypeFromHandler(handlerInfo); + MatchFieldType(&result, glue, field, value, &prepareIntHandlerLoop, &exit); Bind(&prepareIntHandlerLoop); { handler = IntToTaggedPtr(ClearSharedStoreKind(handlerInfo)); @@ -2151,6 +2176,8 @@ GateRef StubBuilder::StoreICWithHandler(GateRef glue, GateRef receiver, GateRef Bind(&handlerIsPrototypeHandler); { GateRef cellValue = GetProtoCell(*handler); + BRANCH(TaggedIsUndefined(cellValue), &loopEnd, &cellNotUndefined); + Bind(&cellNotUndefined); BRANCH(TaggedIsNull(cellValue), &cellHasChanged, &cellNotNull); Bind(&cellNotNull); { @@ -2378,7 +2405,7 @@ GateRef StubBuilder::GetAttributesFromDictionary(GateRef elements, GateRef entry GateRef attributesIndex = Int32Add(arrayIndex, Int32(DictionaryT::ENTRY_DETAILS_INDEX)); auto attrValue = GetValueFromTaggedArray(elements, attributesIndex); - return GetInt32OfTInt(attrValue); + return GetInt64OfTInt(attrValue); } template @@ -2439,7 +2466,7 @@ inline void StubBuilder::UpdateValueAndAttributes(GateRef glue, GateRef elements GateRef attroffset = PtrMul(ZExtInt32ToPtr(attributesIndex), IntPtr(JSTaggedValue::TaggedTypeSize())); GateRef dataOffset = PtrAdd(attroffset, IntPtr(TaggedArray::DATA_OFFSET)); - Store(VariableType::INT64(), glue, elements, dataOffset, IntToTaggedInt(attr)); + Store(VariableType::INT64(), glue, elements, dataOffset, Int64ToTaggedInt(attr)); } template @@ -2650,7 +2677,7 @@ GateRef StubBuilder::GetPropertyByValue(GateRef glue, GateRef receiver, GateRef Label notFind(env); Label find(env); // if key can't find in stringtabele, key is not propertyname for a object - GateRef res = CallNGCRuntime(glue, RTSTUB_ID(TryGetInternString), { glue, *key }); + GateRef res = CallRuntime(glue, RTSTUB_ID(TryGetInternString), { *key }); BRANCH(TaggedIsHole(res), ¬Find, &find); Bind(¬Find); { @@ -2754,8 +2781,7 @@ GateRef StubBuilder::GetPropertyByName(GateRef glue, GateRef receiver, GateRef k Bind(&hasEntry); { // PropertyAttributes attr(layoutInfo->GetAttr(entry)) - GateRef propAttr = GetPropAttrFromLayoutInfo(layOutInfo, entryA); - GateRef attr = GetInt32OfTInt(propAttr); + GateRef attr = GetPropAttrFromLayoutInfo(layOutInfo, entryA); GateRef value = JSObjectGetProperty(*holder, hclass, attr); Label isAccessor(env); Label notAccessor(env); @@ -2880,7 +2906,7 @@ void StubBuilder::TransitionForRepChange(GateRef glue, GateRef receiver, GateRef IntToTaggedInt(inlineProps) }); CopyAllHClass(glue, newJshclass, hclass); CallRuntime(glue, RTSTUB_ID(CopyAndUpdateObjLayout), - { hclass, newJshclass, key, IntToTaggedInt(attr) }); + { hclass, newJshclass, key, Int64ToTaggedInt(attr) }); #if ECMASCRIPT_ENABLE_IC NotifyHClassChanged(glue, hclass, newJshclass); #endif @@ -2967,7 +2993,7 @@ GateRef StubBuilder::AddElementInternal(GateRef glue, GateRef receiver, GateRef Bind(&isDicMode); { GateRef res = CallRuntime(glue, RTSTUB_ID(NumberDictionaryPut), - { receiver, elements, IntToTaggedInt(index), value, IntToTaggedInt(attr), TaggedFalse() }); + { receiver, elements, IntToTaggedInt(index), value, Int64ToTaggedInt(attr), TaggedFalse() }); SetElementsArray(VariableType::JS_POINTER(), glue, receiver, res); result = True(); Jump(&exit); @@ -2987,7 +3013,7 @@ GateRef StubBuilder::AddElementInternal(GateRef glue, GateRef receiver, GateRef Bind(&isTransToDict); { GateRef res = CallRuntime(glue, RTSTUB_ID(NumberDictionaryPut), - { receiver, elements, IntToTaggedInt(index), value, IntToTaggedInt(attr), TaggedTrue() }); + { receiver, elements, IntToTaggedInt(index), value, Int64ToTaggedInt(attr), TaggedTrue() }); SetElementsArray(VariableType::JS_POINTER(), glue, receiver, res); result = True(); Jump(&exit); @@ -3155,7 +3181,7 @@ GateRef StubBuilder::IsArrayLengthWritable(GateRef glue, GateRef receiver) } Bind(&isNegtiveOne); { - GateRef attr1 = Int32(PropertyAttributes::GetDefaultAttributes()); + GateRef attr1 = Int64(PropertyAttributes::GetDefaultAttributes()); result = IsWritable(attr1); Jump(&exit); } @@ -3163,8 +3189,7 @@ GateRef StubBuilder::IsArrayLengthWritable(GateRef glue, GateRef receiver) Bind(¬DicMode); { GateRef layoutInfo = GetLayoutFromHClass(hclass); - GateRef propAttr = GetPropAttrFromLayoutInfo(layoutInfo, Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX)); - GateRef attr = GetInt32OfTInt(propAttr); + GateRef attr = GetPropAttrFromLayoutInfo(layoutInfo, Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX)); result = IsWritable(attr); Jump(&exit); } @@ -3198,7 +3223,7 @@ GateRef StubBuilder::FindTransitions(GateRef glue, GateRef receiver, GateRef hcl GateRef last = Int32Sub(propNums, Int32(1)); GateRef layoutInfo = GetLayoutFromHClass(transitionHClass); GateRef cachedKey = GetKeyFromLayoutInfo(layoutInfo, last); - GateRef cachedAttr = GetInt32OfTInt(GetPropAttrFromLayoutInfo(layoutInfo, last)); + GateRef cachedAttr = GetPropAttrFromLayoutInfo(layoutInfo, last); GateRef cachedMetaData = GetPropertyMetaDataFromAttr(cachedAttr); Label keyMatch(env); Label isMatch(env); @@ -3455,8 +3480,8 @@ GateRef StubBuilder::SetPropertyByIndex(GateRef glue, GateRef receiver, GateRef { Label success(env); Label failed(env); - BRANCH(AddElementInternal(glue, receiver, index, value, - Int32(PropertyAttributes::GetDefaultAttributes())), &success, &failed); + BRANCH(AddElementInternal(glue, receiver, index, value, Int64(PropertyAttributes::GetDefaultAttributes())), + &success, &failed); Bind(&success); { returnValue = Undefined(); @@ -3582,8 +3607,7 @@ GateRef StubBuilder::SetPropertyByName(GateRef glue, GateRef receiver, GateRef k Bind(&hasEntry); { // PropertyAttributes attr(layoutInfo->GetAttr(entry)) - GateRef propAttr = GetPropAttrFromLayoutInfo(layOutInfo, entry); - GateRef attr = GetInt32OfTInt(propAttr); + GateRef attr = GetPropAttrFromLayoutInfo(layOutInfo, entry); Label isAccessor(env); Label notAccessor(env); BRANCH(IsAccessor(attr), &isAccessor, ¬Accessor); @@ -3764,8 +3788,7 @@ GateRef StubBuilder::SetPropertyByName(GateRef glue, GateRef receiver, GateRef k { GateRef receiverHClass = LoadHClass(receiver); GateRef receiverLayoutInfo = GetLayoutFromHClass(receiverHClass); - GateRef holePropAttr = GetPropAttrFromLayoutInfo(receiverLayoutInfo, *receiverHoleEntry); - GateRef holeAttr = GetInt32OfTInt(holePropAttr); + GateRef holeAttr = GetPropAttrFromLayoutInfo(receiverLayoutInfo, *receiverHoleEntry); JSObjectSetProperty(glue, receiver, receiverHClass, holeAttr, key, value); ProfilerStubBuilder(env).UpdatePropAttrWithValue( glue, jsType, receiverLayoutInfo, holeAttr, *receiverHoleEntry, value, callback); @@ -3787,7 +3810,7 @@ GateRef StubBuilder::SetPropertyByName(GateRef glue, GateRef receiver, GateRef k Bind(&extensible); { result = AddPropertyByName(glue, receiver, key, value, - Int32(PropertyAttributes::GetDefaultAttributes()), callback); + Int64(PropertyAttributes::GetDefaultAttributes()), callback); Jump(&exit); } Bind(&exit); @@ -3864,7 +3887,7 @@ GateRef StubBuilder::SetPropertyByValue(GateRef glue, GateRef receiver, GateRef { Label notFind(env); Label find(env); - GateRef res = CallNGCRuntime(glue, RTSTUB_ID(TryGetInternString), { glue, *varKey }); + GateRef res = CallRuntime(glue, RTSTUB_ID(TryGetInternString), { *varKey }); BRANCH(TaggedIsHole(res), ¬Find, &find); Bind(¬Find); { @@ -4335,7 +4358,7 @@ void StubBuilder::FastSetPropertyByName(GateRef glue, GateRef obj, GateRef key, { Label notFind(env); Label find(env); - GateRef res = CallNGCRuntime(glue, RTSTUB_ID(TryGetInternString), { glue, *keyVar }); + GateRef res = CallRuntime(glue, RTSTUB_ID(TryGetInternString), { *keyVar }); BRANCH(TaggedIsHole(res), ¬Find, &find); Bind(¬Find); { @@ -5964,8 +5987,9 @@ GateRef StubBuilder::GetStringFromConstPool(GateRef glue, GateRef constpool, Gat return env_->GetBuilder()->GetObjectFromConstPool(glue, hirGate, constpool, module, index, ConstPoolType::STRING); } -GateRef StubBuilder::GetMethodFromConstPool(GateRef glue, GateRef constpool, GateRef module, GateRef index) +GateRef StubBuilder::GetMethodFromConstPool(GateRef glue, GateRef constpool, GateRef index) { + GateRef module = Circuit::NullGate(); GateRef hirGate = Circuit::NullGate(); return env_->GetBuilder()->GetObjectFromConstPool(glue, hirGate, constpool, module, index, ConstPoolType::METHOD); } @@ -6975,7 +6999,7 @@ GateRef StubBuilder::JSCallDispatch(GateRef glue, GateRef func, GateRef actualNu BRANCH(Int64LessThanOrEqual(expectedArgc, realNumArgs), &fastCall, &fastCallBridge); Bind(&fastCall); { - GateRef code = GetAotCodeAddr(method); + GateRef code = GetAotCodeAddr(func); switch (mode) { case JSCallMode::CALL_THIS_ARG0: thisValue = data[0]; @@ -7151,7 +7175,7 @@ GateRef StubBuilder::JSCallDispatch(GateRef glue, GateRef func, GateRef actualNu BRANCH(Int64LessThanOrEqual(expectedArgc, realNumArgs), &slowCall, &slowCallBridge); Bind(&slowCall); { - GateRef code = GetAotCodeAddr(method); + GateRef code = GetAotCodeAddr(func); switch (mode) { case JSCallMode::CALL_THIS_ARG0: thisValue = data[0]; diff --git a/ecmascript/compiler/stub_builder.h b/ecmascript/compiler/stub_builder.h index a9f3ba62b27e4a57732f52a182fc8ec4d394c9e8..fa9195dc3ea0b1b5a45427b2e456a2c8622471e9 100644 --- a/ecmascript/compiler/stub_builder.h +++ b/ecmascript/compiler/stub_builder.h @@ -152,7 +152,7 @@ public: GateRef CallNGCRuntime(GateRef glue, int index, const std::initializer_list& args); GateRef FastCallOptimized(GateRef glue, GateRef code, const std::initializer_list& args); GateRef CallOptimized(GateRef glue, GateRef code, const std::initializer_list& args); - GateRef GetAotCodeAddr(GateRef method); + GateRef GetAotCodeAddr(GateRef jsFunc); GateRef CallStub(GateRef glue, int index, const std::initializer_list& args); GateRef CallBuiltinRuntime(GateRef glue, const std::initializer_list& args, bool isNew = false, const char* comment = nullptr); @@ -234,6 +234,8 @@ public: GateRef TaggedIsAccessor(GateRef x); GateRef ObjectAddressToRange(GateRef x); GateRef InYoungGeneration(GateRef region); + GateRef InSharedHeap(GateRef region); + GateRef InSharedSweepableSpace(GateRef region); GateRef TaggedIsGeneratorObject(GateRef x); GateRef TaggedIsJSArray(GateRef x); GateRef TaggedIsAsyncGeneratorObject(GateRef x); @@ -487,12 +489,14 @@ public: GateRef GetInlinedPropertiesFromHClass(GateRef hClass); void ThrowTypeAndReturn(GateRef glue, int messageId, GateRef val); GateRef GetValueFromTaggedArray(GateRef elements, GateRef index); + GateRef GetUnsharedConstpoolIndex(GateRef constpool); + GateRef GetUnsharedConstpool(GateRef array, GateRef index); GateRef GetValueFromMutantTaggedArray(GateRef elements, GateRef index); void CheckUpdateSharedType(bool isDicMode, Variable *result, GateRef glue, GateRef jsType, GateRef attr, GateRef value, Label *executeSetProp, Label *exit); - void MatchTrackType(Variable *result, GateRef glue, GateRef trackType, GateRef value, Label *executeSetProp, + void MatchFieldType(Variable *result, GateRef glue, GateRef fieldType, GateRef value, Label *executeSetProp, Label *exit); - GateRef GetTrackTypeFromHandler(GateRef attr); + GateRef GetFieldTypeFromHandler(GateRef attr); GateRef ClearSharedStoreKind(GateRef handlerInfo); GateRef GetTaggedValueWithElementsKind(GateRef receiver, GateRef index); GateRef SetValueWithElementsKind(GateRef glue, GateRef receiver, GateRef rawValue, GateRef index, @@ -519,7 +523,7 @@ public: GateRef GetPropertiesAddrFromLayoutInfo(GateRef layout); GateRef GetPropertyMetaDataFromAttr(GateRef attr); GateRef GetKeyFromLayoutInfo(GateRef layout, GateRef entry); - void MatchTrackType(GateRef trackType, GateRef value, Label *executeSetProp, Label *typeMismatch); + void MatchFieldType(GateRef fieldType, GateRef value, Label *executeSetProp, Label *typeMismatch); GateRef FindElementWithCache(GateRef glue, GateRef layoutInfo, GateRef hClass, GateRef key, GateRef propsNum); GateRef FindElementFromNumberDictionary(GateRef glue, GateRef elements, GateRef index); @@ -621,7 +625,8 @@ public: GateRef SetIsInlinePropsFieldInPropAttr(GateRef attr, GateRef value); GateRef SetTrackTypeInPropAttr(GateRef attr, GateRef type); GateRef GetTrackTypeInPropAttr(GateRef attr); - GateRef GetDictTrackTypeInPropAttr(GateRef attr); + GateRef GetSharedFieldTypeInPropAttr(GateRef attr); + GateRef GetDictSharedFieldTypeInPropAttr(GateRef attr); GateRef GetRepInPropAttr(GateRef attr); GateRef IsIntRepInPropAttr(GateRef attr); GateRef IsDoubleRepInPropAttr(GateRef attr); @@ -660,7 +665,9 @@ public: void SetProtoOrHClassToFunction(GateRef glue, GateRef function, GateRef value); void SetWorkNodePointerToFunction(GateRef glue, GateRef function, GateRef value); void SetHomeObjectToFunction(GateRef glue, GateRef function, GateRef value); + void SetModuleToFunction(GateRef glue, GateRef function, GateRef value); void SetMethodToFunction(GateRef glue, GateRef function, GateRef value); + void SetCodeEntryToFunction(GateRef glue, GateRef function, GateRef value); void SetLengthToFunction(GateRef glue, GateRef function, GateRef value); GateRef GetGlobalObject(GateRef glue); GateRef GetMethodFromFunction(GateRef function); @@ -683,7 +690,7 @@ public: inline GateRef GetObjectFromConstPool(GateRef constpool, GateRef index); GateRef GetConstPoolFromFunction(GateRef jsFunc); GateRef GetStringFromConstPool(GateRef glue, GateRef constpool, GateRef index); - GateRef GetMethodFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module); + GateRef GetMethodFromConstPool(GateRef glue, GateRef constpool, GateRef index); GateRef GetArrayLiteralFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module); GateRef GetObjectLiteralFromConstPool(GateRef glue, GateRef constpool, GateRef index, GateRef module); void SetExtensibleToBitfield(GateRef glue, GateRef obj, bool isExtensible); diff --git a/ecmascript/compiler/trampoline/aarch64/asm_interpreter_call.cpp b/ecmascript/compiler/trampoline/aarch64/asm_interpreter_call.cpp index 1191d64a18333576641e34c432751b87eab5ccae..ac3cfa347cb19a62c0e832fc910f81bf4b605fa1 100644 --- a/ecmascript/compiler/trampoline/aarch64/asm_interpreter_call.cpp +++ b/ecmascript/compiler/trampoline/aarch64/asm_interpreter_call.cpp @@ -179,7 +179,7 @@ void AsmInterpreterCall::JSCallCommonEntry(ExtendedAssembler *assembler, JSCallM __ Mov(temp, callTargetRegister); __ Ldr(Register(X20), MemoryOperand(methodRegister, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET)); // Reload constpool and profileInfo to make sure gc map work normally - __ Ldr(Register(X22), MemoryOperand(methodRegister, Method::PROFILE_TYPE_INFO_OFFSET)); + __ Ldr(Register(X22), MemoryOperand(temp, JSFunction::PROFILE_TYPE_INFO_OFFSET)); __ Ldr(Register(X21), MemoryOperand(methodRegister, Method::CONSTANT_POOL_OFFSET)); __ Mov(temp, kungfu::BytecodeStubCSigns::ID_ThrowStackOverflowException); @@ -1038,7 +1038,7 @@ void AsmInterpreterCall::GeneratorReEnterAsmInterpDispatch(ExtendedAssembler *as __ Align16(currentSlotRegister); __ Mov(Register(SP), currentSlotRegister); // call bc stub - CallBCStub(assembler, newSp, glue, method, pc, temp); + CallBCStub(assembler, newSp, glue, callTarget, method, pc, temp); __ Bind(&stackOverflow); { @@ -1147,6 +1147,7 @@ void AsmInterpreterCall::DispatchCall(ExtendedAssembler *assembler, Register pcR Register newSpRegister, Register accRegister) { Register glueRegister = __ GlueRegister(); + Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET); Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD); if (glueRegister.GetId() != X19) { @@ -1158,7 +1159,7 @@ void AsmInterpreterCall::DispatchCall(ExtendedAssembler *assembler, Register pcR } else { ASSERT(accRegister == Register(X23)); } - __ Ldr(Register(X22), MemoryOperand(methodRegister, Method::PROFILE_TYPE_INFO_OFFSET)); + __ Ldr(Register(X22), MemoryOperand(callTargetRegister, JSFunction::PROFILE_TYPE_INFO_OFFSET)); __ Ldr(Register(X21), MemoryOperand(methodRegister, Method::CONSTANT_POOL_OFFSET)); __ Mov(Register(X20), pcRegister); __ Mov(Register(FP), newSpRegister); @@ -1292,14 +1293,14 @@ void AsmInterpreterCall::PushGeneratorFrameState(ExtendedAssembler *assembler, R } void AsmInterpreterCall::CallBCStub(ExtendedAssembler *assembler, Register &newSp, Register &glue, - Register &method, Register &pc, Register &temp) + Register &callTarget, Register &method, Register &pc, Register &temp) { // prepare call entry __ Mov(Register(X19), glue); // X19 - glue __ Mov(Register(FP), newSp); // FP - sp __ Mov(Register(X20), pc); // X20 - pc __ Ldr(Register(X21), MemoryOperand(method, Method::CONSTANT_POOL_OFFSET)); // X21 - constantpool - __ Ldr(Register(X22), MemoryOperand(method, Method::PROFILE_TYPE_INFO_OFFSET)); // X22 - profileTypeInfo + __ Ldr(Register(X22), MemoryOperand(callTarget, JSFunction::PROFILE_TYPE_INFO_OFFSET)); // X22 - profileTypeInfo __ Mov(Register(X23), Immediate(JSTaggedValue::Hole().GetRawData())); // X23 - acc __ Ldr(Register(X24), MemoryOperand(method, Method::LITERAL_INFO_OFFSET)); // X24 - hotnessCounter diff --git a/ecmascript/compiler/trampoline/aarch64/common_call.h b/ecmascript/compiler/trampoline/aarch64/common_call.h index 35d688c28047745bd25b3d1b9093dc2810f99eb8..84ece261101267b6cee4fea653a739b788e9b736 100644 --- a/ecmascript/compiler/trampoline/aarch64/common_call.h +++ b/ecmascript/compiler/trampoline/aarch64/common_call.h @@ -235,7 +235,7 @@ private: Register &contextRegister, Register &pcRegister, Register &operatorRegister); static void CallBCStub(ExtendedAssembler *assembler, Register &newSp, Register &glue, - Register &method, Register &pc, Register &temp); + Register &callTarget, Register &method, Register &pc, Register &temp); static void CallNativeEntry(ExtendedAssembler *assembler); diff --git a/ecmascript/compiler/trampoline/aarch64/optimized_call.cpp b/ecmascript/compiler/trampoline/aarch64/optimized_call.cpp index 2ee8c09c5365398265d71312c36f878d5de526c3..6ebdef806a2bf5fe97796adaa17924f6f0b49d6a 100644 --- a/ecmascript/compiler/trampoline/aarch64/optimized_call.cpp +++ b/ecmascript/compiler/trampoline/aarch64/optimized_call.cpp @@ -209,7 +209,7 @@ void OptimizedCall::OptimizedCallAndPushUndefined(ExtendedAssembler *assembler) Register argV(X4); __ Ldr(jsfunc, MemoryOperand(sp, FRAME_SLOT_SIZE)); __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET)); - __ Ldr(codeAddr, MemoryOperand(method, Method::CODE_ENTRY_OFFSET)); + __ Ldr(codeAddr, MemoryOperand(jsfunc, JSFunction::CODE_ENTRY_OFFSET)); __ Ldr(expectedNumArgs, MemoryOperand(method, Method::CALL_FIELD_OFFSET)); __ Lsr(expectedNumArgs, expectedNumArgs, MethodLiteral::NumArgsBits::START_BIT); __ And(expectedNumArgs, expectedNumArgs, @@ -1035,7 +1035,7 @@ void OptimizedCall::CallOptimized(ExtendedAssembler *assembler) Register codeAddr(X5); __ Ldr(jsfunc, MemoryOperand(sp, FRAME_SLOT_SIZE)); __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET)); - __ Ldr(codeAddr, MemoryOperand(method, Method::CODE_ENTRY_OFFSET)); + __ Ldr(codeAddr, MemoryOperand(jsfunc, JSFunction::CODE_ENTRY_OFFSET)); __ Br(codeAddr); } diff --git a/ecmascript/compiler/trampoline/aarch64/optimized_fast_call.cpp b/ecmascript/compiler/trampoline/aarch64/optimized_fast_call.cpp index e476692cb895164db2f27acd3e5a5c1a99135da3..cf22cf9cf34f3fd4e0934ce2b2f5c230e5389b9b 100644 --- a/ecmascript/compiler/trampoline/aarch64/optimized_fast_call.cpp +++ b/ecmascript/compiler/trampoline/aarch64/optimized_fast_call.cpp @@ -227,7 +227,7 @@ void OptimizedFastCall::OptimizedFastCallAndPushUndefined(ExtendedAssembler *ass TempRegister1Scope scope1(assembler); Register method1 = __ TempRegister1(); __ Ldr(method1, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET)); - __ Ldr(X11, MemoryOperand(method1, Method::CODE_ENTRY_OFFSET)); + __ Ldr(X11, MemoryOperand(jsfunc, JSFunction::CODE_ENTRY_OFFSET)); __ Blr(X11); __ Mov(Register(SP), Register(FP)); @@ -308,7 +308,7 @@ void OptimizedFastCall::JSFastCallWithArgV(ExtendedAssembler *assembler) TempRegister1Scope scope1(assembler); Register method = __ TempRegister1(); __ Ldr(method, MemoryOperand(jsfunc, JSFunction::METHOD_OFFSET)); - __ Ldr(X11, MemoryOperand(method, Method::CODE_ENTRY_OFFSET)); + __ Ldr(X11, MemoryOperand(jsfunc, JSFunctionBase::CODE_ENTRY_OFFSET)); __ Blr(X11); __ Mov(Register(SP), Register(FP)); @@ -450,7 +450,7 @@ void OptimizedFastCall::JSFastCallWithArgVAndPushUndefined(ExtendedAssembler *as TempRegister1Scope scope1(assembler); Register method = __ TempRegister1(); __ Ldr(method, MemoryOperand(X1, JSFunction::METHOD_OFFSET)); - __ Ldr(X11, MemoryOperand(method, Method::CODE_ENTRY_OFFSET)); + __ Ldr(X11, MemoryOperand(X1, JSFunction::CODE_ENTRY_OFFSET)); __ Blr(X11); __ Mov(Register(SP), Register(FP)); diff --git a/ecmascript/compiler/trampoline/x64/asm_interpreter_call.cpp b/ecmascript/compiler/trampoline/x64/asm_interpreter_call.cpp index 01b8e4cf57a252b7bcc059a52c1f06fe34520605..874b260b934269e149b9ac61a903605e34199568 100644 --- a/ecmascript/compiler/trampoline/x64/asm_interpreter_call.cpp +++ b/ecmascript/compiler/trampoline/x64/asm_interpreter_call.cpp @@ -118,7 +118,7 @@ void AsmInterpreterCall::GeneratorReEnterAsmInterpDispatch(ExtendedAssembler *as contextRegister, pcRegister, tempRegister); // call bc stub - DispatchCall(assembler, pcRegister, newSpRegister, methodRegister); + DispatchCall(assembler, pcRegister, newSpRegister, callTargetRegister, methodRegister); __ Bind(&stackOverflow); { ThrowStackOverflowExceptionAndReturn(assembler, glueRegister, fpRegister, tempRegister); @@ -329,7 +329,7 @@ void AsmInterpreterCall::JSCallCommonEntry(ExtendedAssembler *assembler, JSCallM __ Movq(callTargetRegister, tempRegister); __ Movq(Operand(methodRegister, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET), r12); // pc: r12 // Reload constpool and profileInfo to make sure gc map work normally - __ Movq(Operand(methodRegister, Method::PROFILE_TYPE_INFO_OFFSET), r14); // profileTypeInfo: r14 + __ Movq(Operand(tempRegister, JSFunction::PROFILE_TYPE_INFO_OFFSET), r14); // profileTypeInfo: r14 __ Movq(Operand(methodRegister, Method::CONSTANT_POOL_OFFSET), rbx); // constantPool: rbx __ Movq(kungfu::BytecodeStubCSigns::ID_ThrowStackOverflowException, tempRegister); @@ -709,7 +709,7 @@ void AsmInterpreterCall::PushVregs(ExtendedAssembler *assembler, Label *stackOve PushFrameState(assembler, prevSpRegister, fpRegister, callTargetRegister, thisRegister, methodRegister, pcRegister, tempRegister); } - DispatchCall(assembler, pcRegister, newSpRegister, methodRegister); + DispatchCall(assembler, pcRegister, newSpRegister, callTargetRegister, methodRegister); } // Input: %r13 - glue @@ -717,7 +717,7 @@ void AsmInterpreterCall::PushVregs(ExtendedAssembler *assembler, Label *stackOve // %r12 - callTarget // %rbx - method void AsmInterpreterCall::DispatchCall(ExtendedAssembler *assembler, Register pcRegister, - Register newSpRegister, Register methodRegister, Register accRegister) + Register newSpRegister, Register callTargetRegister, Register methodRegister, Register accRegister) { Register glueRegister = __ GlueRegister(); Label dispatchCall; @@ -727,7 +727,7 @@ void AsmInterpreterCall::DispatchCall(ExtendedAssembler *assembler, Register pcR __ PushAlignBytes(); __ Bind(&dispatchCall); // profileTypeInfo: r14 - __ Movq(Operand(methodRegister, Method::PROFILE_TYPE_INFO_OFFSET), r14); + __ Movq(Operand(callTargetRegister, JSFunction::PROFILE_TYPE_INFO_OFFSET), r14); // glue may rdi if (glueRegister != r13) { __ Movq(glueRegister, r13); diff --git a/ecmascript/compiler/trampoline/x64/common_call.h b/ecmascript/compiler/trampoline/x64/common_call.h index db159816a7d1b7af0a7c45922af7a075a7f119da..65f4ea5298b626f39e6e4072d38049d80dd8ffe4 100644 --- a/ecmascript/compiler/trampoline/x64/common_call.h +++ b/ecmascript/compiler/trampoline/x64/common_call.h @@ -184,7 +184,7 @@ private: static Register GetNewTargetRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister); static void PushVregs(ExtendedAssembler *assembler, Label *stackOverflow); static void DispatchCall(ExtendedAssembler *assembler, Register pcRegister, Register newSpRegister, - Register methodRegister, Register accRegister = rInvalid); + Register callTargetRegister, Register methodRegister, Register accRegister = rInvalid); static void CallNativeEntry(ExtendedAssembler *assemblSer); static void CallNativeWithArgv(ExtendedAssembler *assembler, bool callNew, bool hasNewTarget = false); static void CallNativeInternal(ExtendedAssembler *assembler, Register nativeCode); diff --git a/ecmascript/compiler/trampoline/x64/optimized_call.cpp b/ecmascript/compiler/trampoline/x64/optimized_call.cpp index aedf3f487a9498a13c56506f8e2c452c9bb31eb2..6363a9fe346450400010823336182dd84d29ced2 100644 --- a/ecmascript/compiler/trampoline/x64/optimized_call.cpp +++ b/ecmascript/compiler/trampoline/x64/optimized_call.cpp @@ -123,7 +123,7 @@ void OptimizedCall::OptimizedCallAndPushUndefined(ExtendedAssembler *assembler) Register codeAddrReg = rsi; __ Movq(Operand(rsp, DOUBLE_SLOT_SIZE), jsFuncReg); // sp + 16 get jsFunc __ Mov(Operand(jsFuncReg, JSFunctionBase::METHOD_OFFSET), method); // get method - __ Mov(Operand(method, Method::CODE_ENTRY_OFFSET), codeAddrReg); + __ Mov(Operand(jsFuncReg, JSFunctionBase::CODE_ENTRY_OFFSET), codeAddrReg); Register methodCallField = rcx; __ Mov(Operand(method, Method::CALL_FIELD_OFFSET), methodCallField); // get call field @@ -1047,7 +1047,7 @@ void OptimizedCall::CallOptimized(ExtendedAssembler *assembler) Register codeAddrReg = rsi; __ Movq(Operand(rsp, DOUBLE_SLOT_SIZE), jsFuncReg); // sp + 16 get jsFunc __ Mov(Operand(jsFuncReg, JSFunctionBase::METHOD_OFFSET), method); // get method - __ Mov(Operand(method, Method::CODE_ENTRY_OFFSET), codeAddrReg); + __ Mov(Operand(jsFuncReg, JSFunctionBase::CODE_ENTRY_OFFSET), codeAddrReg); __ Jmp(codeAddrReg); } @@ -1102,7 +1102,7 @@ void OptimizedCall::DeoptEnterAsmInterp(ExtendedAssembler *assembler) __ Movq(Operand(callTargetRegister, JSFunctionBase::METHOD_OFFSET), methodRegister); __ Leaq(Operand(rsp, AsmInterpretedFrame::GetSize(false)), opRegister); - AsmInterpreterCall::DispatchCall(assembler, r12, opRegister, methodRegister, rsi); + AsmInterpreterCall::DispatchCall(assembler, r12, opRegister, callTargetRegister, methodRegister, rsi); } __ Bind(&stackOverflow); diff --git a/ecmascript/compiler/trampoline/x64/optimized_fast_call.cpp b/ecmascript/compiler/trampoline/x64/optimized_fast_call.cpp index 3dd8b001e46bf628618ad675497db216c7d2bf84..7acb5f0f831f67cc941f1e611f2ad3aae0acc244 100644 --- a/ecmascript/compiler/trampoline/x64/optimized_fast_call.cpp +++ b/ecmascript/compiler/trampoline/x64/optimized_fast_call.cpp @@ -116,7 +116,7 @@ void OptimizedFastCall::OptimizedFastCallAndPushUndefined(ExtendedAssembler *ass Register argvReg = r12; __ Leaq(Operand(rsp, 8 * FRAME_SLOT_SIZE), argvReg); // 8: skip 8 frames to get argv __ Mov(Operand(jsFuncReg, JSFunctionBase::METHOD_OFFSET), method); // get method - __ Mov(Operand(method, Method::CODE_ENTRY_OFFSET), codeAddrReg); // get codeAddress + __ Mov(Operand(jsFuncReg, JSFunctionBase::CODE_ENTRY_OFFSET), codeAddrReg); // get codeAddress __ Mov(Operand(method, Method::CALL_FIELD_OFFSET), methodCallField); // get call field __ Shr(MethodLiteral::NumArgsBits::START_BIT, methodCallField); __ Andl(((1LU << MethodLiteral::NumArgsBits::SIZE) - 1), methodCallField); @@ -262,7 +262,7 @@ void OptimizedFastCall::JSFastCallWithArgV(ExtendedAssembler *assembler) Register method = r12; Register jsFuncReg = rsi; __ Mov(Operand(jsFuncReg, JSFunctionBase::METHOD_OFFSET), method); // get method - __ Mov(Operand(method, Method::CODE_ENTRY_OFFSET), rbx); // get codeAddress + __ Mov(Operand(jsFuncReg, JSFunctionBase::CODE_ENTRY_OFFSET), rbx); // get codeAddress __ Callq(rbx); } @@ -377,7 +377,7 @@ void OptimizedFastCall::JSFastCallWithArgVAndPushUndefined(ExtendedAssembler *as Register method = r12; Register jsFuncReg = rsi; __ Mov(Operand(jsFuncReg, JSFunctionBase::METHOD_OFFSET), method); // get method - __ Mov(Operand(method, Method::CODE_ENTRY_OFFSET), rbx); // get codeAddress + __ Mov(Operand(jsFuncReg, JSFunctionBase::CODE_ENTRY_OFFSET), rbx); // get codeAddress __ Callq(rbx); } #undef __ diff --git a/ecmascript/compiler/type_info_accessors.cpp b/ecmascript/compiler/type_info_accessors.cpp index 849afee0f9def1bdbd1ddbd2f95d1bb9598886c9..6bbf65511bf669c01124683ba47e5320405f4c9f 100644 --- a/ecmascript/compiler/type_info_accessors.cpp +++ b/ecmascript/compiler/type_info_accessors.cpp @@ -770,8 +770,9 @@ void CreateObjWithBufferTypeInfoAccessor::Init() auto imm = acc_.GetConstantValue(index_); auto methodOffset = acc_.TryGetMethodOffset(GetGate()); JSTaggedValue cp = tsManager_->GetConstantPool(methodOffset); + JSTaggedValue unsharedCp = thread_->GetCurrentEcmaContext()->FindUnsharedConstpool(cp); JSTaggedValue obj = ConstantPool::GetLiteralFromCache( - tsManager_->GetEcmaVM()->GetJSThread(), cp, imm, recordName_); + tsManager_->GetEcmaVM()->GetJSThread(), unsharedCp, imm, recordName_); objHandle_ = JSHandle(thread_, obj); } diff --git a/ecmascript/compiler/typed_hcr_lowering.cpp b/ecmascript/compiler/typed_hcr_lowering.cpp index 1815cc38e137ccabfe178b7217c4626ad7cda7e4..c8ff86c403ee589cf1e59e0068d3ed355a67b1f2 100644 --- a/ecmascript/compiler/typed_hcr_lowering.cpp +++ b/ecmascript/compiler/typed_hcr_lowering.cpp @@ -657,11 +657,12 @@ void TypedHCRLowering::LowerPrimitiveToNumber(GateRef dst, GateRef src, GateType acc_.ReplaceGate(dst, builder_.GetState(), builder_.GetDepend(), *result); } -GateRef TypedHCRLowering::LoadFromConstPool(GateRef constPool, size_t index, size_t valVecType) +GateRef TypedHCRLowering::LoadFromConstPool(GateRef constpool, size_t index, size_t valVecType) { - GateRef constPoolSize = builder_.GetLengthOfTaggedArray(constPool); + GateRef unsharedConstpool = builder_.GetUnsharedConstpool(constpool); + GateRef constPoolSize = builder_.GetLengthOfTaggedArray(unsharedConstpool); GateRef valVecIndex = builder_.Int32Sub(constPoolSize, builder_.Int32(valVecType)); - GateRef valVec = builder_.GetValueFromTaggedArray(constPool, valVecIndex); + GateRef valVec = builder_.GetValueFromTaggedArray(unsharedConstpool, valVecIndex); return builder_.LoadFromTaggedArray(valVec, index); } @@ -1630,7 +1631,9 @@ void TypedHCRLowering::LowerLookupHolder(GateRef gate) GateRef receiver = acc_.GetValueIn(gate, 0); GateRef holderHCIndex = acc_.GetValueIn(gate, 1); GateRef constPool = acc_.GetValueIn(gate, 2); // 2: constpool - GateRef holderHC = builder_.LoadHClassFromConstpool(constPool, acc_.GetConstantValue(holderHCIndex)); + GateRef unsharedConstpool = builder_.GetUnsharedConstpool(constPool); + GateRef holderHC = builder_.LoadHClassFromUnsharedConstpool(unsharedConstpool, + acc_.GetConstantValue(holderHCIndex)); DEFVALUE(holder, (&builder_), VariableType::JS_ANY(), receiver); Label loopHead(&builder_); Label exit(&builder_); @@ -1698,7 +1701,8 @@ void TypedHCRLowering::LowerPrototypeCheck(GateRef gate) GateRef frameState = acc_.GetFrameState(gate); uint32_t hclassIndex = acc_.GetHClassIndex(gate); - auto expectedReceiverHC = builder_.LoadHClassFromConstpool(constPool, hclassIndex); + GateRef unsharedConstpool = builder_.GetUnsharedConstpool(constPool); + auto expectedReceiverHC = builder_.LoadHClassFromUnsharedConstpool(unsharedConstpool, hclassIndex); auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), expectedReceiverHC, JSHClass::PROTOTYPE_OFFSET); auto protoHClass = builder_.LoadHClass(prototype); @@ -2042,7 +2046,7 @@ GateRef TypedHCRLowering::AllocateLineString(GateRef glue, GateRef length, GateR GateRef stringClass = builder_.GetGlobalConstantValue(ConstantIndex::LINE_STRING_CLASS_INDEX); builder_.StartAllocate(); - GateRef lineString = builder_.HeapAlloc(glue, *size, GateType::TaggedValue(), RegionSpaceFlag::IN_YOUNG_SPACE); + GateRef lineString = builder_.HeapAlloc(glue, *size, GateType::TaggedValue(), RegionSpaceFlag::IN_SHARED_OLD_SPACE); builder_.StoreConstOffset(VariableType::JS_POINTER(), lineString, 0, stringClass, MemoryOrder::NeedBarrierAndAtomic()); builder_.StoreConstOffset(VariableType::INT32(), lineString, EcmaString::MIX_LENGTH_OFFSET, *mixLength); @@ -2081,7 +2085,8 @@ GateRef TypedHCRLowering::AllocateSlicedString(GateRef glue, GateRef flatString, GateRef size = builder_.IntPtr(AlignUp(SlicedString::SIZE, static_cast(MemAlignment::MEM_ALIGN_OBJECT))); builder_.StartAllocate(); - GateRef slicedString = builder_.HeapAlloc(glue, size, GateType::TaggedValue(), RegionSpaceFlag::IN_YOUNG_SPACE); + GateRef slicedString = builder_.HeapAlloc(glue, size, GateType::TaggedValue(), + RegionSpaceFlag::IN_SHARED_OLD_SPACE); builder_.StoreConstOffset(VariableType::JS_POINTER(), slicedString, 0, stringClass, MemoryOrder::NeedBarrierAndAtomic()); builder_.StoreConstOffset(VariableType::INT32(), slicedString, EcmaString::MIX_LENGTH_OFFSET, *mixLength); @@ -2694,7 +2699,8 @@ void TypedHCRLowering::LowerMonoLoadPropertyOnProto(GateRef gate) auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET); // lookup from receiver for holder - auto holderHC = builder_.LoadHClassFromConstpool(constPool, acc_.GetConstantValue(hclassIndex)); + GateRef unsharedConstpool = builder_.GetUnsharedConstpool(constPool); + auto holderHC = builder_.LoadHClassFromUnsharedConstpool(unsharedConstpool, acc_.GetConstantValue(hclassIndex)); DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype); Label exit(&builder_); Label loopHead(&builder_); @@ -2734,7 +2740,8 @@ void TypedHCRLowering::LowerMonoCallGetterOnProto(GateRef gate, GateRef glue) auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET); // lookup from receiver for holder - auto holderHC = builder_.LoadHClassFromConstpool(constPool, acc_.GetConstantValue(hclassIndex)); + GateRef unsharedConstpool = builder_.GetUnsharedConstpool(constPool); + auto holderHC = builder_.LoadHClassFromUnsharedConstpool(unsharedConstpool, acc_.GetConstantValue(hclassIndex)); DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype); Label exitLoad(&builder_); Label loopHead(&builder_); @@ -2824,7 +2831,8 @@ void TypedHCRLowering::LowerMonoStorePropertyLookUpProto(GateRef gate, GateRef g auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET); auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET); // lookup from receiver for holder - auto holderHC = builder_.LoadHClassFromConstpool(constpool, acc_.GetConstantValue(hclassIndex)); + GateRef unsharedConstpool = builder_.GetUnsharedConstpool(constpool); + auto holderHC = builder_.LoadHClassFromUnsharedConstpool(unsharedConstpool, acc_.GetConstantValue(hclassIndex)); DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype); Label exit(&builder_); Label loopHead(&builder_); @@ -2893,7 +2901,8 @@ void TypedHCRLowering::LowerMonoStoreProperty(GateRef gate, GateRef glue) Label exit(&builder_); Label notProto(&builder_); Label isProto(&builder_); - auto newHolderHC = builder_.LoadHClassFromConstpool(constPool, acc_.GetConstantValue(hclassIndex)); + GateRef unsharedConstpool = builder_.GetUnsharedConstpool(constPool); + auto newHolderHC = builder_.LoadHClassFromUnsharedConstpool(unsharedConstpool, acc_.GetConstantValue(hclassIndex)); builder_.StoreConstOffset(VariableType::JS_ANY(), newHolderHC, JSHClass::PROTOTYPE_OFFSET, prototype); builder_.Branch(builder_.IsProtoTypeHClass(receiverHC), &isProto, ¬Proto, BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT, "isProtoTypeHClass"); @@ -3114,8 +3123,7 @@ void TypedHCRLowering::LowerStringFromSingleCharCode(GateRef gate, GateRef glue) newBuilder.SetParameters(glue, 0); builder_.Bind(&canBeCompress); { - GateRef singleCharTable = builder_.Load(VariableType::JS_ANY(), glue, - builder_.IntPtr(JSThread::GlueData::GetSingleCharTableOffset(env.Is32Bit()))); + GateRef singleCharTable = builder_.GetGlobalConstantValue(ConstantIndex::SINGLE_CHAR_TABLE_INDEX); res = builder_.GetValueFromTaggedArray(singleCharTable, builder_.ZExtInt16ToInt32(*value)); builder_.Jump(&exit); } diff --git a/ecmascript/debugger/debugger_api.cpp b/ecmascript/debugger/debugger_api.cpp index 126e723a10b06d879c8255e0f361c49a9e8348a7..699c285f867132c22ae47649b55c77e292a3702f 100644 --- a/ecmascript/debugger/debugger_api.cpp +++ b/ecmascript/debugger/debugger_api.cpp @@ -441,7 +441,8 @@ JSTaggedValue DebuggerApi::GetCurrentModule(const EcmaVM *ecmaVm) if (method->IsNativeWithCallField()) { continue; } - JSTaggedValue module = method->GetModule(); + JSTaggedValue func = frameHandler.GetFunction(); + JSTaggedValue module = JSFunction::Cast(func.GetTaggedObject())->GetModule(); if (module.IsUndefined()) { continue; } diff --git a/ecmascript/deoptimizer/deoptimizer.cpp b/ecmascript/deoptimizer/deoptimizer.cpp index cb73f06bf696e06910306c8beadb56015272d808..90dfd48542579721e8f1cc394847decb535084ed 100644 --- a/ecmascript/deoptimizer/deoptimizer.cpp +++ b/ecmascript/deoptimizer/deoptimizer.cpp @@ -411,12 +411,13 @@ bool Deoptimizier::CollectVirtualRegisters(Method* method, FrameWriter *frameWri return true; } -void Deoptimizier::Dump(Method* method, kungfu::DeoptType type, size_t depth) +void Deoptimizier::Dump(JSTaggedValue callTarget, kungfu::DeoptType type, size_t depth) { if (thread_->IsPGOProfilerEnable()) { - auto profileTypeInfo = method->GetProfileTypeInfo(); + JSFunction *function = JSFunction::Cast(callTarget); + auto profileTypeInfo = function->GetProfileTypeInfo(); if (profileTypeInfo.IsUndefined()) { - SlowRuntimeStub::NotifyInlineCache(thread_, method); + SlowRuntimeStub::NotifyInlineCache(thread_, function); } } if (traceDeopt_) { @@ -424,7 +425,7 @@ void Deoptimizier::Dump(Method* method, kungfu::DeoptType type, size_t depth) LOG_TRACE(INFO) << "Check Type: " << checkType; std::string data = JsStackInfo::BuildJsStackTrace(thread_, true); LOG_COMPILER(INFO) << "Deoptimize" << data; - const uint8_t *pc = method->GetBytecodeArray() + pc_.at(depth); + const uint8_t *pc = GetMethod(callTarget)->GetBytecodeArray() + pc_.at(depth); BytecodeInstruction inst(pc); LOG_COMPILER(INFO) << inst; } @@ -523,10 +524,10 @@ void Deoptimizier::UpdateAndDumpDeoptInfo(kungfu::DeoptType type) { // depth records the number of layers of nested calls when deopt occurs for (size_t i = 0; i <= inlineDepth_; i++) { - JSTaggedValue CallTarget = GetDeoptValue(i, static_cast(SpecVregIndex::FUNC_INDEX)); - auto method = GetMethod(CallTarget); + JSTaggedValue callTarget = GetDeoptValue(i, static_cast(SpecVregIndex::FUNC_INDEX)); + auto method = GetMethod(callTarget); if (i == inlineDepth_) { - Dump(method, type, i); + Dump(callTarget, type, i); } ASSERT(thread_ != nullptr); uint8_t deoptThreshold = method->GetDeoptThreshold(); @@ -535,9 +536,11 @@ void Deoptimizier::UpdateAndDumpDeoptInfo(kungfu::DeoptType type) method->SetDeoptThreshold(--deoptThreshold); } else { method->ClearAOTStatusWhenDeopt(); - if (method->GetMachineCode() != JSTaggedValue::Undefined()) { - method->SetMachineCode(thread_, JSTaggedValue::Undefined()); + auto func = JSFunction::Cast(callTarget.GetTaggedObject()); + if (func->GetMachineCode() != JSTaggedValue::Undefined()) { + func->SetMachineCode(thread_, JSTaggedValue::Undefined()); } + func->SetCodeEntry(reinterpret_cast(nullptr)); } } } diff --git a/ecmascript/deoptimizer/deoptimizer.h b/ecmascript/deoptimizer/deoptimizer.h index 43355cd70ceb839a938136ecd633dcf30f2da1f8..d85cd4941fbd970f07e9cb0cd29fd5843db8224b 100644 --- a/ecmascript/deoptimizer/deoptimizer.h +++ b/ecmascript/deoptimizer/deoptimizer.h @@ -174,7 +174,7 @@ private: } Method* GetMethod(JSTaggedValue &target); void RelocateCalleeSave(); - void Dump(Method* method, kungfu::DeoptType type, size_t depth); + void Dump(JSTaggedValue callTarget, kungfu::DeoptType type, size_t depth); size_t GetCallSize(size_t curDepth, const uint8_t *resumePc); JSThread *thread_ {nullptr}; uintptr_t *calleeRegAddr_ {nullptr}; diff --git a/ecmascript/dfx/hprof/heap_profiler.cpp b/ecmascript/dfx/hprof/heap_profiler.cpp index 384a58e7df8690473347c81c7a3671265397c835..55571bda661ca6e65a67d28e62e1d86864631c9c 100644 --- a/ecmascript/dfx/hprof/heap_profiler.cpp +++ b/ecmascript/dfx/hprof/heap_profiler.cpp @@ -15,6 +15,7 @@ #include "ecmascript/dfx/hprof/heap_profiler.h" +#include "ecmascript/checkpoint/thread_state_transition.h" #include "ecmascript/dfx/hprof/file_stream.h" #include "ecmascript/dfx/hprof/heap_snapshot.h" #include "ecmascript/ecma_vm.h" @@ -23,6 +24,7 @@ #include "ecmascript/mem/assert_scope.h" #include "ecmascript/mem/concurrent_sweeper.h" #include "ecmascript/mem/heap-inl.h" +#include "ecmascript/mem/shared_heap/shared_concurrent_sweeper.h" #if defined(ENABLE_DUMP_IN_FAULTLOG) #include "faultloggerd_client.h" @@ -127,8 +129,7 @@ void HeapProfiler::MoveEvent(uintptr_t address, TaggedObject *forwardAddress, si void HeapProfiler::UpdateHeapObjects(HeapSnapshot *snapshot) { - vm_->CollectGarbage(TriggerGCType::OLD_GC); - vm_->GetHeap()->GetSweeper()->EnsureAllTaskFinished(); + ForceSharedGC(); snapshot->UpdateNodes(); } @@ -151,23 +152,28 @@ void HeapProfiler::DumpHeapSnapshot([[maybe_unused]] DumpFormat dumpFormat, [[ma bool HeapProfiler::DumpHeapSnapshot(DumpFormat dumpFormat, Stream *stream, Progress *progress, bool isVmMode, bool isPrivate, bool captureNumericValue, bool isFullGC) { - if (isFullGC) { - [[maybe_unused]] bool heapClean = ForceFullGC(vm_); - ASSERT(heapClean); - } - LOG_ECMA(INFO) << "HeapProfiler DumpSnapshot start"; int32_t heapCount = 0; - if (isFullGC) { - size_t heapSize = vm_->GetHeap()->GetLiveObjectSize(); - LOG_ECMA(INFO) << "HeapProfiler DumpSnapshot heap size " << heapSize; - heapCount = static_cast(vm_->GetHeap()->GetHeapObjectCount()); - if (progress != nullptr) { - progress->ReportProgress(0, heapCount); + HeapSnapshot *snapshot = nullptr; + { + if (isFullGC) { + [[maybe_unused]] bool heapClean = ForceFullGC(vm_); + ASSERT(heapClean); } + SuspendAllScope suspendScope(vm_->GetAssociatedJSThread()); + ForceSharedGC(); + LOG_ECMA(INFO) << "HeapProfiler DumpSnapshot start"; + if (isFullGC) { + size_t heapSize = vm_->GetHeap()->GetLiveObjectSize(); + LOG_ECMA(INFO) << "HeapProfiler DumpSnapshot heap size " << heapSize; + heapCount = static_cast(vm_->GetHeap()->GetHeapObjectCount()); + if (progress != nullptr) { + progress->ReportProgress(0, heapCount); + } + } + snapshot = MakeHeapSnapshot(SampleType::ONE_SHOT, isVmMode, isPrivate, captureNumericValue, + false, isFullGC); + ASSERT(snapshot != nullptr); } - HeapSnapshot *snapshot = MakeHeapSnapshot(SampleType::ONE_SHOT, isVmMode, isPrivate, captureNumericValue, - false, isFullGC); - ASSERT(snapshot != nullptr); entryIdMap_->UpdateEntryIdMap(snapshot); isProfiling_ = true; if (progress != nullptr) { @@ -187,6 +193,8 @@ bool HeapProfiler::DumpHeapSnapshot(DumpFormat dumpFormat, Stream *stream, Progr bool HeapProfiler::StartHeapTracking(double timeInterval, bool isVmMode, Stream *stream, bool traceAllocation, bool newThread) { + vm_->CollectGarbage(TriggerGCType::OLD_GC); + SuspendAllScope suspendScope(vm_->GetAssociatedJSThread()); HeapSnapshot *snapshot = MakeHeapSnapshot(SampleType::REAL_TIME, isVmMode, false, false, traceAllocation); if (snapshot == nullptr) { return false; @@ -211,8 +219,13 @@ bool HeapProfiler::UpdateHeapTracking(Stream *stream) if (snapshot == nullptr) { return false; } - snapshot->RecordSampleTime(); - UpdateHeapObjects(snapshot); + + { + vm_->CollectGarbage(TriggerGCType::OLD_GC); + SuspendAllScope suspendScope(vm_->GetAssociatedJSThread()); + snapshot->RecordSampleTime(); + UpdateHeapObjects(snapshot); + } if (stream != nullptr) { snapshot->PushHeapStat(stream); @@ -241,7 +254,11 @@ bool HeapProfiler::StopHeapTracking(Stream *stream, Progress *progress, bool new if (progress != nullptr) { progress->ReportProgress(0, heapCount); } - snapshot->FinishSnapshot(); + { + SuspendAllScope suspendScope(vm_->GetAssociatedJSThread()); + snapshot->FinishSnapshot(); + } + isProfiling_ = false; if (progress != nullptr) { progress->ReportProgress(heapCount, heapCount); @@ -305,6 +322,13 @@ bool HeapProfiler::ForceFullGC(const EcmaVM *vm) return false; } +void HeapProfiler::ForceSharedGC() +{ + SharedHeap *sHeap = SharedHeap::GetInstance(); + sHeap->CollectGarbageImpl(TriggerGCType::SHARED_GC, GCReason::OTHER); + sHeap->GetSweeper()->WaitAllTaskFinished(); +} + HeapSnapshot *HeapProfiler::MakeHeapSnapshot(SampleType sampleType, bool isVmMode, bool isPrivate, bool captureNumericValue, bool traceAllocation, bool isFullGC) { diff --git a/ecmascript/dfx/hprof/heap_profiler.h b/ecmascript/dfx/hprof/heap_profiler.h index 40513afc89be0905144512f36221e3722d02b1ec..9aab2617ff1c62cae7b89ed1c33437c2119903db 100644 --- a/ecmascript/dfx/hprof/heap_profiler.h +++ b/ecmascript/dfx/hprof/heap_profiler.h @@ -112,6 +112,7 @@ private: * trigger full gc to make sure no unreachable objects in heap */ bool ForceFullGC(const EcmaVM *vm); + void ForceSharedGC(); /** * make a new heap snapshot and put it into a container eg, vector diff --git a/ecmascript/dfx/hprof/heap_root_visitor.cpp b/ecmascript/dfx/hprof/heap_root_visitor.cpp index 671ae4a29f4d5fbdb6eca3014758a57a8ac98652..5119fdc91433aeb2e48f17080a5e66c6fd2a5925 100644 --- a/ecmascript/dfx/hprof/heap_root_visitor.cpp +++ b/ecmascript/dfx/hprof/heap_root_visitor.cpp @@ -17,6 +17,7 @@ #include "ecmascript/ecma_vm.h" #include "ecmascript/js_thread.h" +#include "ecmascript/runtime.h" namespace panda::ecmascript { void HeapRootVisitor::VisitHeapRoots(JSThread *thread, const RootVisitor &visitor, @@ -26,6 +27,9 @@ void HeapRootVisitor::VisitHeapRoots(JSThread *thread, const RootVisitor &visito auto ecmaVm = GetVMInstance(thread); ecmaVm->Iterate(visitor, rangeVisitor); thread->Iterate(visitor, rangeVisitor, derivedVisitor); + + // SerializeRoot from shared heap + Runtime::GetInstance()->IterateSerializeRoot(visitor); } EcmaVM *HeapRootVisitor::GetVMInstance(JSThread *thread) const diff --git a/ecmascript/dfx/hprof/heap_snapshot.cpp b/ecmascript/dfx/hprof/heap_snapshot.cpp index e2aca81c79dcb27adf8457f193ce227481d2a9f3..0f0cc7be3acb4ebdd8846d857b600f59af406e4a 100644 --- a/ecmascript/dfx/hprof/heap_snapshot.cpp +++ b/ecmascript/dfx/hprof/heap_snapshot.cpp @@ -534,6 +534,8 @@ CString *HeapSnapshot::GenerateNodeName(TaggedObject *entry) return GetString("ResolvedBinding"); case JSType::RESOLVEDINDEXBINDING_RECORD: return GetString("ResolvedIndexBinding"); + case JSType::RESOLVEDRECORDBINDING_RECORD: + return GetString("ResolvedRecordBinding"); case JSType::JS_MODULE_NAMESPACE: return GetString("ModuleNamespace"); case JSType::JS_API_PLAIN_ARRAY: @@ -641,6 +643,12 @@ NodeType HeapSnapshot::GenerateNodeType(TaggedObject *entry) void HeapSnapshot::FillNodes(bool isInFinish) { + SharedHeap *sHeap = SharedHeap::GetInstance(); + if (sHeap != nullptr) { + sHeap->IterateOverObjects([this, isInFinish](TaggedObject *obj) { + GenerateNode(JSTaggedValue(obj), 0, isInFinish); + }); + } // Iterate Heap Object auto heap = vm_->GetHeap(); if (heap != nullptr) { diff --git a/ecmascript/dfx/vmstat/runtime_stat.h b/ecmascript/dfx/vmstat/runtime_stat.h index 34093bd37239396683e04f6743b14aea65db77d8..20946e870c344b283d79fed2530dc725a2204fa2 100644 --- a/ecmascript/dfx/vmstat/runtime_stat.h +++ b/ecmascript/dfx/vmstat/runtime_stat.h @@ -40,8 +40,8 @@ public: { return runtimeStatEnabled_; } - void StartCount(PandaRuntimeTimer *timer, int callerId); - void StopCount(const PandaRuntimeTimer *timer); + void PUBLIC_API StartCount(PandaRuntimeTimer *timer, int callerId); + void PUBLIC_API StopCount(const PandaRuntimeTimer *timer); void PrintAllStats() const; void ResetAllCount(); void Print() const; diff --git a/ecmascript/dump.cpp b/ecmascript/dump.cpp index ab6f962974bad8d2f133e4912287cad4b9fa5064..117d118961b1c3afd796ca0139081225c7b790e4 100644 --- a/ecmascript/dump.cpp +++ b/ecmascript/dump.cpp @@ -479,9 +479,11 @@ CString JSHClass::DumpJSType(JSType type) case JSType::SOURCE_TEXT_MODULE_RECORD: return "SourceTextModuleRecord"; case JSType::RESOLVEDBINDING_RECORD: - return "ResolvedBingingRecord"; + return "ResolvedBindingRecord"; case JSType::RESOLVEDINDEXBINDING_RECORD: - return "ResolvedIndexBingingRecord"; + return "ResolvedIndexBindingRecord"; + case JSType::RESOLVEDRECORDBINDING_RECORD: + return "ResolvedRecordBindingRecord"; case JSType::IMPORTENTRY_RECORD: return "ImportEntry"; case JSType::LOCAL_EXPORTENTRY_RECORD: @@ -1215,6 +1217,9 @@ static void DumpObject(TaggedObject *obj, std::ostream &os) case JSType::RESOLVEDINDEXBINDING_RECORD: ResolvedIndexBinding::Cast(obj)->Dump(os); break; + case JSType::RESOLVEDRECORDBINDING_RECORD: + ResolvedRecordBinding::Cast(obj)->Dump(os); + break; case JSType::JS_MODULE_NAMESPACE: ModuleNamespace::Cast(obj)->Dump(os); break; @@ -1678,11 +1683,14 @@ void JSFunction::Dump(std::ostream &os) const os << "\n"; os << " - LexicalEnv: "; if (GetClass()->IsJSSharedFunction()) { - os << GetLexicalEnv().GetTaggedObject()<< "\n"; + os << GetLexicalEnv().GetRawData()<< "\n"; } else { GetLexicalEnv().Dump(os); os << "\n"; } + os << " - ProfileTypeInfo: "; + GetProfileTypeInfo().Dump(os); + os << "\n"; os << " - HomeObject: "; GetHomeObject().Dump(os); os << "\n"; @@ -1692,6 +1700,9 @@ void JSFunction::Dump(std::ostream &os) const os << " - Method: "; GetMethod().Dump(os); os << "\n"; + os << " - Module: "; + GetModule().Dump(os); + os << "\n"; JSObject::Dump(os); } @@ -3814,6 +3825,16 @@ void ResolvedIndexBinding::Dump(std::ostream &os) const os << "\n"; } +void ResolvedRecordBinding::Dump(std::ostream &os) const +{ + os << " - Module: "; + GetModuleRecord().Dump(os); + os << "\n"; + os << " - Index: "; + GetIndex(); + os << "\n"; +} + void ModuleNamespace::Dump(std::ostream &os) const { os << " - Exports: "; @@ -3898,12 +3919,6 @@ void Method::Dump(std::ostream &os) const os << " - ConstantPool: "; GetConstantPool().Dump(os); os << "\n"; - os << " - ProfileTypeInfo: "; - GetProfileTypeInfo().Dump(os); - os << "\n"; - os << " - Module: "; - GetModule().Dump(os); - os << "\n"; os << " - FunctionKind: " << static_cast(GetFunctionKind()); os << "\n"; os << " - CodeEntryOrLiteral: " << std::hex << GetCodeEntryOrLiteral() << "\n"; @@ -4400,6 +4415,9 @@ static void DumpObject(TaggedObject *obj, std::vector &vec, bool isVm case JSType::RESOLVEDINDEXBINDING_RECORD: ResolvedIndexBinding::Cast(obj)->DumpForSnapshot(vec); return; + case JSType::RESOLVEDRECORDBINDING_RECORD: + ResolvedRecordBinding::Cast(obj)->DumpForSnapshot(vec); + return; case JSType::JS_MODULE_NAMESPACE: ModuleNamespace::Cast(obj)->DumpForSnapshot(vec); return; @@ -4815,7 +4833,10 @@ void JSFunction::DumpForSnapshot(std::vector &vec) const { vec.emplace_back(CString("ProtoOrHClass"), GetProtoOrHClass()); vec.emplace_back(CString("LexicalEnv"), GetLexicalEnv()); + vec.emplace_back(CString("ProfileTypeInfo"), GetProfileTypeInfo()); vec.emplace_back(CString("HomeObject"), GetHomeObject()); + vec.emplace_back(CString("Module"), GetModule()); + vec.emplace_back(CString("Method"), GetMethod()); if ((!GetMethod().IsNull()) && (!GetMethod().IsUndefined())) { vec.emplace_back(CString("FunctionKind"), JSTaggedValue(static_cast(GetFunctionKind()))); } @@ -4828,9 +4849,6 @@ void Method::DumpForSnapshot(std::vector &vec) const { vec.emplace_back(CString("MethodName"), JSTaggedValue(GetMethodName())); vec.emplace_back(CString("ConstantPool"), GetConstantPool()); - vec.emplace_back(CString("ProfileTypeInfo"), GetProfileTypeInfo()); - vec.emplace_back(CString("Module"), GetModule()); - vec.emplace_back(CString("MachineCode"), GetMachineCode()); } void Program::DumpForSnapshot(std::vector &vec) const @@ -5990,6 +6008,12 @@ void ResolvedIndexBinding::DumpForSnapshot(std::vector &vec) const vec.emplace_back(CString("Index"), JSTaggedValue(GetIndex())); } +void ResolvedRecordBinding::DumpForSnapshot(std::vector &vec) const +{ + vec.emplace_back(CString("ModuleRecord"), GetModuleRecord()); + vec.emplace_back(CString("Index"), JSTaggedValue(GetIndex())); +} + void ModuleNamespace::DumpForSnapshot(std::vector &vec) const { vec.emplace_back(CString("Module"), GetModule()); diff --git a/ecmascript/ecma_context.cpp b/ecmascript/ecma_context.cpp index 9c59ec443f94c64ab9901752dcb02b1e62d58fad..16e086ecd5a38641c45451c2c0c8bc48d4894bd1 100644 --- a/ecmascript/ecma_context.cpp +++ b/ecmascript/ecma_context.cpp @@ -23,6 +23,7 @@ #include "ecmascript/builtins/builtins_string.h" #include "ecmascript/compiler/aot_file/an_file_data_manager.h" #include "ecmascript/compiler/common_stubs.h" +#include "ecmascript/ecma_string.h" #include "ecmascript/ecma_string_table.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" @@ -36,7 +37,9 @@ #include "ecmascript/js_thread.h" #include "ecmascript/log.h" #include "ecmascript/module/module_path_helper.h" +#include "ecmascript/module/js_shared_module.h" #include "ecmascript/object_factory.h" +#include "ecmascript/patch/patch_loader.h" #include "ecmascript/pgo_profiler/pgo_profiler_manager.h" #include "ecmascript/require/js_cjs_module_cache.h" #include "ecmascript/require/js_require_manager.h" @@ -47,6 +50,8 @@ namespace panda::ecmascript { using PathHelper = base::PathHelper; +int32_t EcmaContext::unsharedConstpoolCount_ = 0; + EcmaContext::EcmaContext(JSThread *thread) : thread_(thread), vm_(thread->GetEcmaVM()), @@ -93,18 +98,19 @@ bool EcmaContext::Initialize() [[maybe_unused]] EcmaHandleScope scope(thread_); propertiesCache_ = new PropertiesCache(); regExpParserCache_ = new RegExpParserCache(); + unsharedConstpools_ = new std::array(); + unsharedConstpools_->fill(JSTaggedValue::Hole()); + thread_->SetUnsharedConstpools(reinterpret_cast(unsharedConstpools_->data())); - JSHandle hClassHandle = factory_->InitClassClass(); - + thread_->SetGlobalConst(&globalConst_); + globalConst_.Init(thread_); + JSHandle hClassHandle = JSHandle(thread_, globalConst_.GetHClassClass()); JSHandle globalEnvClass = factory_->NewEcmaHClass( *hClassHandle, GlobalEnv::SIZE, JSType::GLOBAL_ENV); - thread_->SetGlobalConst(&globalConst_); - globalConst_.Init(thread_, *hClassHandle); auto arrayHClassIndexMaps = Elements::InitializeHClassMap(); thread_->SetArrayHClassIndexMap(arrayHClassIndexMaps); - JSHandle globalEnv = factory_->NewGlobalEnv(*globalEnvClass); globalEnv->Init(thread_); globalEnv_ = globalEnv.GetTaggedValue(); @@ -260,6 +266,7 @@ JSTaggedValue EcmaContext::ExecuteAot(size_t actualNumArgs, JSTaggedType *args, const JSTaggedType *prevFp, bool needPushUndefined) { INTERPRETER_TRACE(thread_, ExecuteAot); + ASSERT(thread_->IsInManagedState()); auto entry = thread_->GetRTInterface(kungfu::RuntimeStubCSigns::ID_JSFunctionEntry); // do not modify this log to INFO, this will call many times LOG_ECMA(DEBUG) << "start to execute aot entry: " << (void*)entry; @@ -274,7 +281,7 @@ JSTaggedValue EcmaContext::ExecuteAot(size_t actualNumArgs, JSTaggedType *args, Expected EcmaContext::CommonInvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile, std::string_view entryPoint, JSHandle &func, bool executeFromJob) { - JSHandle method(thread_, func->GetMethod()); + ASSERT(thread_->IsInManagedState()); JSHandle global = GlobalEnv::Cast(globalEnv_.GetTaggedObject())->GetJSGlobalObject(); JSHandle undefined = thread_->GlobalConstants()->GetHandledUndefined(); CString entry = entryPoint.data(); @@ -290,13 +297,14 @@ Expected EcmaContext::CommonInvokeEcmaEntrypoint(const JSPa if (!jsPandaFile->IsBundlePack()) { moduleName = entry; } - JSHandle module = moduleManager_->HostGetImportedModule(moduleName); - method->SetModule(thread_, module); + JSHandle module(moduleManager_->HostGetImportedModule(moduleName)); + // esm -> SourceTextModule; cjs or script -> string of recordName + func->SetModule(thread_, module); } else { // if it is Cjs at present, the module slot of the function is not used. We borrow it to store the recordName, // which can avoid the problem of larger memory caused by the new slot JSHandle recordName = factory_->NewFromUtf8(entry); - method->SetModule(thread_, recordName); + func->SetModule(thread_, recordName); } vm_->CheckStartCpuProfiler(); @@ -436,13 +444,13 @@ void EcmaContext::CJSExecution(JSHandle &func, JSHandlesecond.find(index); @@ -452,11 +460,57 @@ JSTaggedValue EcmaContext::FindConstpool(const JSPandaFile *jsPandaFile, int32_t return constpoolIter->second; } +JSTaggedValue EcmaContext::FindUnsharedConstpool(JSTaggedValue sharedConstpool) +{ + ConstantPool *shareCp = ConstantPool::Cast(sharedConstpool.GetTaggedObject()); + int32_t index = shareCp->GetUnsharedConstpoolIndex().GetInt(); + // unshared constpool index is default INT32_MAX. + ASSERT(0 <= index && index != ConstantPool::CONSTPOOL_TYPE_FLAG && index < UNSHARED_CONSTANTPOOL_COUNT); + JSTaggedValue unsharedConstpool = (*unsharedConstpools_)[index]; + if (unsharedConstpool.IsHole()) { + ASSERT(index != INT32_MAX); + JSHandle unshareCp = + ConstantPool::CreateUnSharedConstPoolBySharedConstpool(vm_, shareCp->GetJSPandaFile(), shareCp); + unsharedConstpool = unshareCp.GetTaggedValue(); + CheckUnsharedConstpoolArrayLimit(index); + SetUnsharedConstpool(index, unsharedConstpool); + } + return unsharedConstpool; +} + +JSHandle EcmaContext::CreateConstpoolPair(JSPandaFile *jsPandaFile, EntityId methodId) +{ + panda_file::IndexAccessor indexAccessor(*jsPandaFile->GetPandaFile(), methodId); + int32_t index = static_cast(indexAccessor.GetHeaderIndex()); + JSHandle constpool = + ConstantPool::CreateUnSharedConstPool(thread_->GetEcmaVM(), jsPandaFile, methodId); + JSHandle sconstpool; + int32_t count = GetAndIncreaseUnsharedConstpoolCount(); + if (jsPandaFile->IsLoadedAOT()) { + sconstpool = ConstantPool::CreateSharedConstPoolForAOT(vm_, constpool, count, index); + } else { + sconstpool = ConstantPool::CreateSharedConstPool( + thread_->GetEcmaVM(), jsPandaFile, methodId, count, index); + } + AddConstpool(jsPandaFile, sconstpool.GetTaggedValue(), index); + CheckUnsharedConstpoolArrayLimit(count); + SetUnsharedConstpool(count, constpool.GetTaggedValue()); + return sconstpool; +} + +void EcmaContext::EraseUnsharedConstpool(JSTaggedValue sharedConstpool) +{ + int32_t index = ConstantPool::Cast(sharedConstpool.GetTaggedObject())->GetUnsharedConstpoolIndex().GetInt(); + // unshared constpool index is default INT32_MAX. + ASSERT(0 <= index && index != ConstantPool::CONSTPOOL_TYPE_FLAG && index < UNSHARED_CONSTANTPOOL_COUNT); + (*unsharedConstpools_)[index] = JSTaggedValue::Hole(); +} + std::optional>> EcmaContext::FindConstpools( const JSPandaFile *jsPandaFile) { - auto iter = cachedConstpools_.find(jsPandaFile); - if (iter == cachedConstpools_.end()) { + auto iter = cachedSharedConstpools_.find(jsPandaFile); + if (iter == cachedSharedConstpools_.end()) { return std::nullopt; } return iter->second; @@ -491,9 +545,18 @@ JSHandle EcmaContext::FindOrCreateConstPool(const JSPandaFile *jsP int32_t index = static_cast(indexAccessor.GetHeaderIndex()); JSTaggedValue constpool = FindConstpoolWithAOT(jsPandaFile, index); if (constpool.IsHole()) { - JSHandle newConstpool = ConstantPool::CreateConstPool(vm_, jsPandaFile, id); - AddConstpool(jsPandaFile, newConstpool.GetTaggedValue(), index); - return newConstpool; + JSHandle newConstpool = ConstantPool::CreateUnSharedConstPool(vm_, jsPandaFile, id); + JSHandle newSConstpool; + int32_t count = GetAndIncreaseUnsharedConstpoolCount(); + if (jsPandaFile->IsLoadedAOT()) { + newSConstpool = ConstantPool::CreateSharedConstPoolForAOT(vm_, newConstpool, count, index); + } else { + newSConstpool = ConstantPool::CreateSharedConstPool(vm_, jsPandaFile, id, count, index); + } + AddConstpool(jsPandaFile, newSConstpool.GetTaggedValue(), index); + CheckUnsharedConstpoolArrayLimit(count); + SetUnsharedConstpool(count, newConstpool.GetTaggedValue()); + return newSConstpool; } return JSHandle(thread_, constpool); } @@ -504,20 +567,30 @@ void EcmaContext::CreateAllConstpool(const JSPandaFile *jsPandaFile) uint32_t index = 0; for (const auto &header : headers) { auto constpoolSize = header.method_idx_size; + JSHandle sconstpool = factory_->NewSConstantPool(constpoolSize); + int32_t count = GetAndIncreaseUnsharedConstpoolCount(); + sconstpool->SetJSPandaFile(jsPandaFile); + sconstpool->SetIndexHeader(&header); + sconstpool->SetUnsharedConstpoolIndex(JSTaggedValue(count)); + sconstpool->SetSharedConstpoolId(JSTaggedValue(index)); + AddConstpool(jsPandaFile, sconstpool.GetTaggedValue(), index); + index++; + JSHandle constpool = factory_->NewConstantPool(constpoolSize); constpool->SetJSPandaFile(jsPandaFile); constpool->SetIndexHeader(&header); - AddConstpool(jsPandaFile, constpool.GetTaggedValue(), index++); + CheckUnsharedConstpoolArrayLimit(count); + SetUnsharedConstpool(count, constpool.GetTaggedValue()); } } void EcmaContext::AddConstpool(const JSPandaFile *jsPandaFile, JSTaggedValue constpool, int32_t index) { ASSERT(constpool.IsConstantPool()); - if (cachedConstpools_.find(jsPandaFile) == cachedConstpools_.end()) { - cachedConstpools_[jsPandaFile] = CMap(); + if (cachedSharedConstpools_.find(jsPandaFile) == cachedSharedConstpools_.end()) { + cachedSharedConstpools_[jsPandaFile] = CMap(); } - auto &constpoolMap = cachedConstpools_[jsPandaFile]; + auto &constpoolMap = cachedSharedConstpools_[jsPandaFile]; ASSERT(constpoolMap.find(index) == constpoolMap.end()); constpoolMap.insert({index, constpool}); } @@ -531,9 +604,9 @@ JSHandle EcmaContext::GetAndClearEcmaUncaughtException() const void EcmaContext::ProcessNativeDelete(const WeakRootVisitor &visitor) { - auto iterator = cachedConstpools_.begin(); - ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "Constpools:" + std::to_string(cachedConstpools_.size())); - while (iterator != cachedConstpools_.end()) { + auto iterator = cachedSharedConstpools_.begin(); + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "Constpools:" + std::to_string(cachedSharedConstpools_.size())); + while (iterator != cachedSharedConstpools_.end()) { auto &constpools = iterator->second; auto constpoolIter = constpools.begin(); while (constpoolIter != constpools.end()) { @@ -543,6 +616,7 @@ void EcmaContext::ProcessNativeDelete(const WeakRootVisitor &visitor) auto fwd = visitor(obj); if (fwd == nullptr) { constpoolIter = constpools.erase(constpoolIter); + EraseUnsharedConstpool(constpoolVal); continue; } } @@ -552,7 +626,7 @@ void EcmaContext::ProcessNativeDelete(const WeakRootVisitor &visitor) LOG_ECMA(INFO) << "remove js pandafile by gc, file:" << iterator->first->GetJSPandaFileDesc(); RelocateConstantString(iterator->first); JSPandaFileManager::GetInstance()->RemoveJSPandaFileVm(vm_, iterator->first); - iterator = cachedConstpools_.erase(iterator); + iterator = cachedSharedConstpools_.erase(iterator); } else { ++iterator; } @@ -561,8 +635,8 @@ void EcmaContext::ProcessNativeDelete(const WeakRootVisitor &visitor) void EcmaContext::ProcessReferences(const WeakRootVisitor &visitor) { - auto iterator = cachedConstpools_.begin(); - while (iterator != cachedConstpools_.end()) { + auto iterator = cachedSharedConstpools_.begin(); + while (iterator != cachedSharedConstpools_.end()) { auto &constpools = iterator->second; auto constpoolIter = constpools.begin(); while (constpoolIter != constpools.end()) { @@ -583,7 +657,7 @@ void EcmaContext::ProcessReferences(const WeakRootVisitor &visitor) LOG_ECMA(INFO) << "remove js pandafile by gc, file:" << iterator->first->GetJSPandaFileDesc(); RelocateConstantString(iterator->first); JSPandaFileManager::GetInstance()->RemoveJSPandaFileVm(vm_, iterator->first); - iterator = cachedConstpools_.erase(iterator); + iterator = cachedSharedConstpools_.erase(iterator); } else { ++iterator; } @@ -595,7 +669,7 @@ void EcmaContext::RelocateConstantString(const JSPandaFile *jsPandaFile) if (!jsPandaFile->IsFirstMergedAbc()) { return; } - vm_->GetEcmaStringTable()->RelocateConstantData(jsPandaFile); + vm_->GetEcmaStringTable()->RelocateConstantData(vm_, jsPandaFile); } JSHandle EcmaContext::GetEcmaUncaughtException() const @@ -705,19 +779,27 @@ bool EcmaContext::ExecutePromisePendingJob() void EcmaContext::ClearBufferData() { - auto iter = cachedConstpools_.begin(); - while (iter != cachedConstpools_.end()) { + auto iter = cachedSharedConstpools_.begin(); + while (iter != cachedSharedConstpools_.end()) { LOG_ECMA(INFO) << "remove js pandafile by vm destruct, file:" << iter->first->GetJSPandaFileDesc(); JSPandaFileManager::GetInstance()->RemoveJSPandaFileVm(vm_, iter->first); iter++; } - cachedConstpools_.clear(); + cachedSharedConstpools_.clear(); + if (unsharedConstpools_ != nullptr) { + delete unsharedConstpools_; + unsharedConstpools_ = nullptr; + thread_->SetUnsharedConstpools(reinterpret_cast(nullptr)); + } } void EcmaContext::SetGlobalEnv(GlobalEnv *global) { - ASSERT(global != nullptr); - globalEnv_ = JSTaggedValue(global); + // In jsthread iteration, SwitchCurrentContext is called to iterate each context. + // If the target context is not fully initialized, the variable "global" will be nullptr. + if (global != nullptr) { + globalEnv_ = JSTaggedValue(global); + } } void EcmaContext::SetMicroJobQueue(job::MicroJobQueue *queue) @@ -797,13 +879,27 @@ void EcmaContext::Iterate(const RootVisitor &v, const RootRangeVisitor &rv) globalConst_.VisitRangeSlot(rv); v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(&globalEnv_))); - v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(®expCache_))); - v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(®expGlobal_))); - v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(&numberToStringResultCache_))); - v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(&stringSplitResultCache_))); - v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(&stringToListResultCache_))); - v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(µJobQueue_))); - v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(&pointerToIndexDictionary_))); + if (!regexpCache_.IsHole()) { + v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(®expCache_))); + } + if (!regexpGlobal_.IsHole()) { + v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(®expGlobal_))); + } + if (!numberToStringResultCache_.IsHole()) { + v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(&numberToStringResultCache_))); + } + if (!stringSplitResultCache_.IsHole()) { + v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(&stringSplitResultCache_))); + } + if (!stringToListResultCache_.IsHole()) { + v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(&stringToListResultCache_))); + } + if (!microJobQueue_.IsHole()) { + v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(µJobQueue_))); + } + if (!pointerToIndexDictionary_.IsHole()) { + v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(&pointerToIndexDictionary_))); + } if (moduleManager_) { moduleManager_->Iterate(v); @@ -835,6 +931,11 @@ void EcmaContext::Iterate(const RootVisitor &v, const RootRangeVisitor &rv) rv(Root::ROOT_VM, ObjectSlot(ToUintPtr(&joinStack_.front())), ObjectSlot(ToUintPtr(&joinStack_.back()) + JSTaggedValue::TaggedTypeSize())); } + + auto start = ObjectSlot(ToUintPtr(unsharedConstpools_->data())); + auto end = ObjectSlot(ToUintPtr(&unsharedConstpools_->data()[UNSHARED_CONSTANTPOOL_COUNT - 1]) + + JSTaggedValue::TaggedTypeSize()); + rv(Root::ROOT_VM, start, end); } size_t EcmaContext::IterateHandle(const RootRangeVisitor &rangeVisitor) diff --git a/ecmascript/ecma_context.h b/ecmascript/ecma_context.h index ede16417afab509b3ddb4ba261e3191b00038054..91bc2b99f38ba479a9a1ec43971fd1dfc8dc9ed8 100644 --- a/ecmascript/ecma_context.h +++ b/ecmascript/ecma_context.h @@ -15,6 +15,7 @@ #ifndef ECMASCRIPT_ECMA_CONTEXT_H #define ECMASCRIPT_ECMA_CONTEXT_H +#include #include #include "ecmascript/base/config.h" #include "ecmascript/common.h" @@ -260,7 +261,10 @@ public: JSTaggedValue PUBLIC_API FindConstpool(const JSPandaFile *jsPandaFile, int32_t index); // For new version instruction. JSTaggedValue PUBLIC_API FindConstpool(const JSPandaFile *jsPandaFile, panda_file::File::EntityId id); + JSTaggedValue PUBLIC_API FindUnsharedConstpool(JSTaggedValue sharedConstpool); + JSHandle CreateConstpoolPair(JSPandaFile *jsPandaFile, EntityId methodId); JSTaggedValue FindConstpoolWithAOT(const JSPandaFile *jsPandaFile, int32_t index); + void EraseUnsharedConstpool(JSTaggedValue sharedConstpool); std::optional>> FindConstpools( const JSPandaFile *jsPandaFile); @@ -496,6 +500,27 @@ public: return isAotEntry_; } + void SetUnsharedConstpool(int32_t unsharedConstpoolIndex, JSTaggedValue constpool) + { + ASSERT(0 <= unsharedConstpoolIndex && unsharedConstpoolIndex < UNSHARED_CONSTANTPOOL_COUNT); + unsharedConstpools_->data()[unsharedConstpoolIndex] = constpool; + } + + int32_t GetAndIncreaseUnsharedConstpoolCount() + { + static std::mutex unsharedConstpoolCountMutex_; + std::lock_guard guard(unsharedConstpoolCountMutex_); + return unsharedConstpoolCount_++; + } + + void CheckUnsharedConstpoolArrayLimit(int32_t index) + { + if (index >= UNSHARED_CONSTANTPOOL_COUNT) { + LOG_ECMA(FATAL) << "the unshared constpool array need to expanding capacity"; + UNREACHABLE(); + } + } + std::tuple CalCallSiteInfo(uintptr_t retAddr) const; private: void CJSExecution(JSHandle &func, JSHandle &thisArg, @@ -535,7 +560,12 @@ private: JSTaggedValue microJobQueue_ {JSTaggedValue::Hole()}; EcmaRuntimeStat *runtimeStat_ {nullptr}; - CMap> cachedConstpools_ {}; + CMap> cachedSharedConstpools_ {}; + // todo(lijiamin) Consider expanding capacity. + static constexpr int32_t UNSHARED_CONSTANTPOOL_COUNT = 10240; + std::array *unsharedConstpools_ = nullptr; + static int32_t unsharedConstpoolCount_; // unshared constpool index. + static constexpr int32_t SHARED_CONSTPOOL_KEY_NOT_FOUND = INT32_MAX; // INT32_MAX :invalid value. // for HotReload of module. CMap> cachedPatchModules_ {}; diff --git a/ecmascript/ecma_global_storage.h b/ecmascript/ecma_global_storage.h index c19d8caedbe7a5e79613a7d3b7dc931a8e3222b1..e4c4b656c0a6cbb9eeaec0c84b2832a0e1eec479 100644 --- a/ecmascript/ecma_global_storage.h +++ b/ecmascript/ecma_global_storage.h @@ -196,13 +196,16 @@ public: return nativeFinalizeCallback_; } - bool CallFreeGlobalCallback() + WeakClearCallback GetFreeGlobalCallback() const + { + return freeGlobalCallback_; + } + + void CallFreeGlobalCallback() { if (freeGlobalCallback_ != nullptr) { freeGlobalCallback_(reference_); - return true; } - return false; } void CallNativeFinalizeCallback() diff --git a/ecmascript/ecma_param_configuration.h b/ecmascript/ecma_param_configuration.h index cc9e3ea5a72f095a52b4d1321e48c64c755d115a..bb18d3d9b6f9aae7c1cd6d10be61cd273a700c33 100644 --- a/ecmascript/ecma_param_configuration.h +++ b/ecmascript/ecma_param_configuration.h @@ -25,19 +25,31 @@ namespace panda::ecmascript { static constexpr size_t DEFAULT_HEAP_SIZE = 448_MB; // Recommended range: 128-448MB static constexpr size_t DEFAULT_WORKER_HEAP_SIZE = 768_MB; // Recommended range: 128_MB, LargeHeap: 768_MB +static constexpr size_t DEFAULT_SHARED_HEAP_SIZE = 778_MB; class EcmaParamConfiguration { public: - EcmaParamConfiguration(bool isWorker, size_t poolSize) - { - if (isWorker) { - maxHeapSize_ = DEFAULT_WORKER_HEAP_SIZE; - } else { - if (poolSize >= DEFAULT_HEAP_SIZE) { - maxHeapSize_ = DEFAULT_HEAP_SIZE; - } else { - maxHeapSize_ = poolSize; // pool is too small, no memory left for worker - } + enum class HeapType : uint8_t { + DEFAULT_HEAP, + WORKER_HEAP, + SHARED_HEAP + }; + + EcmaParamConfiguration(HeapType heapType, size_t poolSize) + { + switch (heapType) { + case HeapType::WORKER_HEAP: + maxHeapSize_ = DEFAULT_WORKER_HEAP_SIZE; + break; + case HeapType::SHARED_HEAP: + maxHeapSize_ = DEFAULT_SHARED_HEAP_SIZE; + break; + default: + if (poolSize >= DEFAULT_HEAP_SIZE) { + maxHeapSize_ = DEFAULT_HEAP_SIZE; + } else { + maxHeapSize_ = poolSize; // pool is too small, no memory left for worker + } } Initialize(); } diff --git a/ecmascript/ecma_string-inl.h b/ecmascript/ecma_string-inl.h index 80cb3c19b9ceba2399051530604eac5f122a801c..d67915947045b15e39639bffebea5190b6aeadb5 100644 --- a/ecmascript/ecma_string-inl.h +++ b/ecmascript/ecma_string-inl.h @@ -21,6 +21,8 @@ #include "ecmascript/ecma_vm.h" #include "ecmascript/js_handle.h" #include "ecmascript/js_tagged_value-inl.h" +#include "ecmascript/mem/heap.h" +#include "ecmascript/mem/space.h" #include "ecmascript/object_factory-inl.h" namespace panda::ecmascript { @@ -157,16 +159,14 @@ inline EcmaString *EcmaString::CreateLineStringNoGC(const EcmaVM *vm, size_t len inline EcmaString *EcmaString::CreateLineStringWithSpaceType(const EcmaVM *vm, size_t length, bool compressed, MemSpaceType type) { + ASSERT(IsSMemSpace(type)); size_t size = compressed ? LineEcmaString::ComputeSizeUtf8(length) : LineEcmaString::ComputeSizeUtf16(length); EcmaString *string = nullptr; switch (type) { - case MemSpaceType::SEMI_SPACE: - string = vm->GetFactory()->AllocLineStringObject(size); - break; - case MemSpaceType::OLD_SPACE: + case MemSpaceType::SHARED_OLD_SPACE: string = vm->GetFactory()->AllocOldSpaceLineStringObject(size); break; - case MemSpaceType::NON_MOVABLE: + case MemSpaceType::SHARED_NON_MOVABLE: string = vm->GetFactory()->AllocNonMovableLineStringObject(size); break; default: @@ -182,13 +182,14 @@ inline SlicedString *EcmaString::CreateSlicedString(const EcmaVM *vm, MemSpaceTy { auto slicedString = SlicedString::Cast(vm->GetFactory()->AllocSlicedStringObject(type)); slicedString->SetRawHashcode(0); - slicedString->SetParent(vm->GetJSThread(), JSTaggedValue::Undefined()); + slicedString->SetParent(vm->GetJSThread(), JSTaggedValue::Undefined(), BarrierMode::SKIP_BARRIER); return slicedString; } inline EcmaString *EcmaString::CreateConstantString(const EcmaVM *vm, const uint8_t *utf8Data, size_t length, bool compressed, MemSpaceType type, uint32_t idOffset) { + ASSERT(IsSMemSpace(type)); auto string = ConstantString::Cast(vm->GetFactory()->AllocConstantStringObject(type)); auto thread = vm->GetJSThread(); string->SetLength(length, compressed); diff --git a/ecmascript/ecma_string.cpp b/ecmascript/ecma_string.cpp index fd50aa075ba5e36f904d73b8293e4ec331694bf9..9444e542dd320590d8bdfa124b2766cb1f51b355 100644 --- a/ecmascript/ecma_string.cpp +++ b/ecmascript/ecma_string.cpp @@ -18,12 +18,14 @@ #include "ecmascript/ecma_string_table.h" #include "ecmascript/js_symbol.h" #include "ecmascript/mem/c_containers.h" +#include "ecmascript/mem/space.h" namespace panda::ecmascript { EcmaString *EcmaString::Concat(const EcmaVM *vm, const JSHandle &left, const JSHandle &right, MemSpaceType type) { + ASSERT(IsSMemSpace(type)); // allocator may trig gc and move src, need to hold it EcmaString *strLeft = *left; EcmaString *strRight = *right; @@ -35,21 +37,9 @@ EcmaString *EcmaString::Concat(const EcmaVM *vm, } if (leftLength == 0) { - if (type == MemSpaceType::OLD_SPACE) { - Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast(*right)); - if (objectRegion->InYoungSpace()) { - return CopyStringToOldSpace(vm, right, rightLength, strRight->IsUtf8()); - } - } return strRight; } if (rightLength == 0) { - if (type == MemSpaceType::OLD_SPACE) { - Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast(*left)); - if (objectRegion->InYoungSpace()) { - return CopyStringToOldSpace(vm, left, leftLength, strLeft->IsUtf8()); - } - } return strLeft; } // if the result string is small, make a LineString @@ -1130,6 +1120,7 @@ EcmaString *EcmaString::Trim(const JSThread *thread, const JSHandle EcmaString *EcmaString::SlowFlatten(const EcmaVM *vm, const JSHandle &string, MemSpaceType type) { ASSERT(string->IsTreeString() || string->IsSlicedString()); + ASSERT(IsSMemSpace(type)); auto thread = vm->GetJSThread(); uint32_t length = string->GetLength(); EcmaString *result = nullptr; @@ -1164,6 +1155,7 @@ EcmaString *EcmaString::Flatten(const EcmaVM *vm, const JSHandle &st FlatStringInfo EcmaString::FlattenAllString(const EcmaVM *vm, const JSHandle &string, MemSpaceType type) { + ASSERT(IsSMemSpace(type)); EcmaString *s = *string; uint32_t startIndex = 0; if (s->IsLineOrConstantString()) { diff --git a/ecmascript/ecma_string.h b/ecmascript/ecma_string.h index c9d1b65a215a28d05123e29025b1b481c62ad744..470dd46b1583511a65743919ec76ccf328b58d80 100644 --- a/ecmascript/ecma_string.h +++ b/ecmascript/ecma_string.h @@ -110,15 +110,15 @@ private: static EcmaString *CreateEmptyString(const EcmaVM *vm); static EcmaString *CreateFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, - bool canBeCompress, MemSpaceType type = MemSpaceType::SEMI_SPACE, bool isConstantString = false, + bool canBeCompress, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE, bool isConstantString = false, uint32_t idOffset = 0); static EcmaString *CreateFromUtf8CompressedSubString(const EcmaVM *vm, const JSHandle &string, uint32_t offset, uint32_t utf8Len, MemSpaceType type = MemSpaceType::SEMI_SPACE); static EcmaString *CreateUtf16StringFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, - MemSpaceType type = MemSpaceType::SEMI_SPACE); + MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE); static EcmaString *CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len, - bool canBeCompress, MemSpaceType type = MemSpaceType::SEMI_SPACE); - static SlicedString *CreateSlicedString(const EcmaVM *vm, MemSpaceType type = MemSpaceType::SEMI_SPACE); + bool canBeCompress, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE); + static SlicedString *CreateSlicedString(const EcmaVM *vm, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE); static EcmaString *CreateLineString(const EcmaVM *vm, size_t length, bool compressed); static EcmaString *CreateLineStringNoGC(const EcmaVM *vm, size_t length, bool compressed); static EcmaString *CreateLineStringWithSpaceType(const EcmaVM *vm, @@ -126,9 +126,9 @@ private: static EcmaString *CreateTreeString(const EcmaVM *vm, const JSHandle &left, const JSHandle &right, uint32_t length, bool compressed); static EcmaString *CreateConstantString(const EcmaVM *vm, const uint8_t *utf8Data, - size_t length, bool compressed, MemSpaceType type = MemSpaceType::SEMI_SPACE, uint32_t idOffset = 0); + size_t length, bool compressed, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE, uint32_t idOffset = 0); static EcmaString *Concat(const EcmaVM *vm, const JSHandle &left, - const JSHandle &right, MemSpaceType type = MemSpaceType::SEMI_SPACE); + const JSHandle &right, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE); static EcmaString *CopyStringToOldSpace(const EcmaVM *vm, const JSHandle &original, uint32_t length, bool compressed); static EcmaString *FastSubString(const EcmaVM *vm, @@ -719,10 +719,10 @@ private: static EcmaString *SlowFlatten(const EcmaVM *vm, const JSHandle &string, MemSpaceType type); static EcmaString *Flatten(const EcmaVM *vm, const JSHandle &string, - MemSpaceType type = MemSpaceType::SEMI_SPACE); + MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE); static FlatStringInfo FlattenAllString(const EcmaVM *vm, const JSHandle &string, - MemSpaceType type = MemSpaceType::SEMI_SPACE); + MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE); static EcmaString *FlattenNoGC(const EcmaVM *vm, EcmaString *string); @@ -1063,7 +1063,7 @@ public: } static EcmaString *CreateFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress, - MemSpaceType type = MemSpaceType::SEMI_SPACE, bool isConstantString = false, + MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE, bool isConstantString = false, uint32_t idOffset = 0) { return EcmaString::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, type, isConstantString, idOffset); @@ -1071,31 +1071,31 @@ public: static EcmaString *CreateFromUtf8CompressedSubString(const EcmaVM *vm, const JSHandle &string, uint32_t offset, uint32_t utf8Len, - MemSpaceType type = MemSpaceType::SEMI_SPACE) + MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE) { return EcmaString::CreateFromUtf8CompressedSubString(vm, string, offset, utf8Len, type); } static EcmaString *CreateConstantString(const EcmaVM *vm, const uint8_t *utf8Data, size_t length, - bool compressed, MemSpaceType type = MemSpaceType::SEMI_SPACE, uint32_t idOffset = 0) + bool compressed, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE, uint32_t idOffset = 0) { return EcmaString::CreateConstantString(vm, utf8Data, length, compressed, type, idOffset); } static EcmaString *CreateUtf16StringFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, - MemSpaceType type = MemSpaceType::SEMI_SPACE) + MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE) { return EcmaString::CreateUtf16StringFromUtf8(vm, utf8Data, utf8Len, type); } static EcmaString *CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len, - bool canBeCompress, MemSpaceType type = MemSpaceType::SEMI_SPACE) + bool canBeCompress, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE) { return EcmaString::CreateFromUtf16(vm, utf16Data, utf16Len, canBeCompress, type); } static EcmaString *Concat(const EcmaVM *vm, const JSHandle &str1Handle, - const JSHandle &str2Handle, MemSpaceType type = MemSpaceType::SEMI_SPACE) + const JSHandle &str2Handle, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE) { return EcmaString::Concat(vm, str1Handle, str2Handle, type); } @@ -1481,19 +1481,19 @@ public: } static EcmaString *Flatten(const EcmaVM *vm, const JSHandle &string, - MemSpaceType type = MemSpaceType::SEMI_SPACE) + MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE) { return EcmaString::Flatten(vm, string, type); } static FlatStringInfo FlattenAllString(const EcmaVM *vm, const JSHandle &string, - MemSpaceType type = MemSpaceType::SEMI_SPACE) + MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE) { return EcmaString::FlattenAllString(vm, string, type); } static EcmaString *SlowFlatten(const EcmaVM *vm, const JSHandle &string, - MemSpaceType type = MemSpaceType::SEMI_SPACE) + MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE) { return EcmaString::SlowFlatten(vm, string, type); } diff --git a/ecmascript/ecma_string_table.cpp b/ecmascript/ecma_string_table.cpp index cb8e5b0979ca10a46168ff484af3d6bf01f58fdc..67e1938518a85aa64bf15c6e23c39ae4bebd3742 100644 --- a/ecmascript/ecma_string_table.cpp +++ b/ecmascript/ecma_string_table.cpp @@ -17,17 +17,21 @@ #include "ecmascript/ecma_string-inl.h" #include "ecmascript/ecma_vm.h" +#include "ecmascript/js_tagged_value.h" #include "ecmascript/js_thread.h" #include "ecmascript/jspandafile/js_pandafile.h" +#include "ecmascript/log_wrapper.h" #include "ecmascript/mem/c_string.h" +#include "ecmascript/mem/heap.h" #include "ecmascript/mem/space.h" #include "ecmascript/object_factory.h" +#include "ecmascript/platform/mutex.h" +#include "ecmascript/runtime.h" +#include "ecmascript/runtime_lock.h" namespace panda::ecmascript { -EcmaStringTable::EcmaStringTable(const EcmaVM *vm) : vm_(vm) {} - -std::pair EcmaStringTable::GetString(const JSHandle &firstString, - const JSHandle &secondString) const +std::pair EcmaStringTable::GetStringThreadUnsafe(const JSHandle &firstString, + const JSHandle &secondString) const { ASSERT(EcmaStringAccessor(firstString).NotTreeString()); ASSERT(EcmaStringAccessor(secondString).NotTreeString()); @@ -44,8 +48,8 @@ std::pair EcmaStringTable::GetString(const JSHandle EcmaStringTable::GetString(const uint8_t *utf8Data, - uint32_t utf8Len, bool canBeCompress) const +std::pair EcmaStringTable::GetStringThreadUnsafe(const uint8_t *utf8Data, uint32_t utf8Len, + bool canBeCompress) const { uint32_t hashCode = EcmaStringAccessor::ComputeHashcodeUtf8(utf8Data, utf8Len, canBeCompress); auto range = table_.equal_range(hashCode); @@ -58,7 +62,8 @@ std::pair EcmaStringTable::GetString(const uint8_t *utf8 return std::make_pair(nullptr, hashCode); } -std::pair EcmaStringTable::GetString(const uint16_t *utf16Data, uint32_t utf16Len) const +std::pair EcmaStringTable::GetStringThreadUnsafe(const uint16_t *utf16Data, + uint32_t utf16Len) const { uint32_t hashCode = EcmaStringAccessor::ComputeHashcodeUtf16(const_cast(utf16Data), utf16Len); auto range = table_.equal_range(hashCode); @@ -71,7 +76,7 @@ std::pair EcmaStringTable::GetString(const uint16_t *utf return std::make_pair(nullptr, hashCode); } -EcmaString *EcmaStringTable::GetString(EcmaString *string) const +EcmaString *EcmaStringTable::GetStringThreadUnsafe(EcmaString *string) const { auto hashcode = EcmaStringAccessor(string).GetHashcode(); auto range = table_.equal_range(hashcode); @@ -84,68 +89,72 @@ EcmaString *EcmaStringTable::GetString(EcmaString *string) const return nullptr; } -void EcmaStringTable::InternString(EcmaString *string) +void EcmaStringTable::InternStringThreadUnsafe(EcmaString *string) { if (EcmaStringAccessor(string).IsInternString()) { return; } // Strings in string table should not be in the young space. - ASSERT(!Region::ObjectAddressToRange(reinterpret_cast(string))->InYoungSpace()); + ASSERT(Region::ObjectAddressToRange(reinterpret_cast(string))->InSharedHeap()); ASSERT(EcmaStringAccessor(string).NotTreeString()); auto hashcode = EcmaStringAccessor(string).GetHashcode(); table_.emplace(hashcode, string); EcmaStringAccessor(string).SetInternString(); } -void EcmaStringTable::InternEmptyString(EcmaString *emptyStr) +void EcmaStringTable::InternEmptyString(JSThread *thread, EcmaString *emptyStr) { - InternString(emptyStr); + RuntimeLockHolder locker(thread, mutex_); + InternStringThreadUnsafe(emptyStr); } -EcmaString *EcmaStringTable::GetOrInternString(const JSHandle &firstString, +EcmaString *EcmaStringTable::GetOrInternString(EcmaVM *vm, const JSHandle &firstString, const JSHandle &secondString) { - auto firstFlat = JSHandle(vm_->GetJSThread(), EcmaStringAccessor::Flatten(vm_, firstString)); - auto secondFlat = JSHandle(vm_->GetJSThread(), EcmaStringAccessor::Flatten(vm_, secondString)); - std::pair result = GetString(firstFlat, secondFlat); + auto firstFlat = JSHandle(vm->GetJSThread(), EcmaStringAccessor::Flatten(vm, firstString)); + auto secondFlat = JSHandle(vm->GetJSThread(), EcmaStringAccessor::Flatten(vm, secondString)); + RuntimeLockHolder locker(vm->GetJSThread(), mutex_); + std::pair result = GetStringThreadUnsafe(firstFlat, secondFlat); if (result.first != nullptr) { return result.first; } - JSHandle concatHandle(vm_->GetJSThread(), - EcmaStringAccessor::Concat(vm_, firstFlat, secondFlat, MemSpaceType::OLD_SPACE)); - EcmaString *concatString = EcmaStringAccessor::Flatten(vm_, concatHandle, MemSpaceType::OLD_SPACE); + JSHandle concatHandle(vm->GetJSThread(), + EcmaStringAccessor::Concat(vm, firstFlat, secondFlat, MemSpaceType::SHARED_OLD_SPACE)); + EcmaString *concatString = EcmaStringAccessor::Flatten(vm, concatHandle, MemSpaceType::SHARED_OLD_SPACE); concatString->SetMixHashcode(result.second); - InternString(concatString); + InternStringThreadUnsafe(concatString); return concatString; } -EcmaString *EcmaStringTable::GetOrInternString(const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress) +EcmaString *EcmaStringTable::GetOrInternString(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, + bool canBeCompress) { - std::pair result = GetString(utf8Data, utf8Len, canBeCompress); + RuntimeLockHolder locker(vm->GetJSThread(), mutex_); + std::pair result = GetStringThreadUnsafe(utf8Data, utf8Len, canBeCompress); if (result.first != nullptr) { return result.first; } EcmaString *str = - EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, canBeCompress, MemSpaceType::OLD_SPACE); + EcmaStringAccessor::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, MemSpaceType::SHARED_OLD_SPACE); str->SetMixHashcode(result.second); - InternString(str); + InternStringThreadUnsafe(str); return str; } -EcmaString *EcmaStringTable::GetOrInternCompressedSubString(const JSHandle &string, +EcmaString *EcmaStringTable::GetOrInternCompressedSubString(EcmaVM *vm, const JSHandle &string, uint32_t offset, uint32_t utf8Len) { auto *utf8Data = EcmaStringAccessor(string).GetDataUtf8() + offset; - std::pair result = GetString(utf8Data, utf8Len, true); + std::pair result = GetStringThreadUnsafe(utf8Data, utf8Len, true); if (result.first != nullptr) { return result.first; } EcmaString *str = EcmaStringAccessor::CreateFromUtf8CompressedSubString( - vm_, string, offset, utf8Len, MemSpaceType::OLD_SPACE); + vm, string, offset, utf8Len); str->SetMixHashcode(result.second); - InternString(str); + InternStringThreadUnsafe(str); return str; } @@ -153,113 +162,129 @@ EcmaString *EcmaStringTable::GetOrInternCompressedSubString(const JSHandle result = GetString(utf8Data, utf8Len, true); + RuntimeLockHolder locker(vm->GetJSThread(), mutex_); + std::pair result = GetStringThreadUnsafe(utf8Data, utf8Len, true); if (result.first != nullptr) { return result.first; } - - EcmaString *str = EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, true, MemSpaceType::NON_MOVABLE); + EcmaString *str = EcmaStringAccessor::CreateFromUtf8(vm, utf8Data, utf8Len, true, MemSpaceType::SHARED_NON_MOVABLE); str->SetMixHashcode(result.second); - InternString(str); + InternStringThreadUnsafe(str); return str; } -EcmaString *EcmaStringTable::GetOrInternString(const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress) +EcmaString *EcmaStringTable::GetOrInternString(EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len, + bool canBeCompress) { - std::pair result = GetString(utf16Data, utf16Len); + RuntimeLockHolder locker(vm->GetJSThread(), mutex_); + std::pair result = GetStringThreadUnsafe(utf16Data, utf16Len); if (result.first != nullptr) { return result.first; } EcmaString *str = - EcmaStringAccessor::CreateFromUtf16(vm_, utf16Data, utf16Len, canBeCompress, MemSpaceType::OLD_SPACE); + EcmaStringAccessor::CreateFromUtf16(vm, utf16Data, utf16Len, canBeCompress, MemSpaceType::SHARED_OLD_SPACE); str->SetMixHashcode(result.second); - InternString(str); + InternStringThreadUnsafe(str); return str; } -EcmaString *EcmaStringTable::GetOrInternString(EcmaString *string) +EcmaString *EcmaStringTable::GetOrInternString(EcmaVM *vm, EcmaString *string) { if (EcmaStringAccessor(string).IsInternString()) { return string; } - JSHandle strHandle(vm_->GetJSThread(), string); + auto thread = vm->GetJSThread(); + JSHandle strHandle(thread, string); // may gc - auto strFlat = EcmaStringAccessor::Flatten(vm_, strHandle, MemSpaceType::OLD_SPACE); + auto strFlat = EcmaStringAccessor::Flatten(vm, strHandle, MemSpaceType::SHARED_OLD_SPACE); if (EcmaStringAccessor(strFlat).IsInternString()) { return strFlat; } - EcmaString *result = GetString(strFlat); + JSHandle strFlatHandle(thread, strFlat); + // may gc + RuntimeLockHolder locker(thread, mutex_); + strFlat = *strFlatHandle; + EcmaString *result = GetStringThreadUnsafe(strFlat); if (result != nullptr) { return result; } - if (EcmaStringAccessor(strFlat).NotTreeString()) { - Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast(strFlat)); - if (objectRegion->InYoungSpace()) { - JSHandle resultHandle(vm_->GetJSThread(), strFlat); - strFlat = EcmaStringAccessor::CopyStringToOldSpace(vm_, - resultHandle, EcmaStringAccessor(strFlat).GetLength(), EcmaStringAccessor(strFlat).IsUtf8()); - } - } - InternString(strFlat); + InternStringThreadUnsafe(strFlat); return strFlat; } -EcmaString *EcmaStringTable::InsertStringToTable(const JSHandle &strHandle) +EcmaString *EcmaStringTable::GetOrInternStringThreadUnsafe(EcmaVM *vm, EcmaString *string) { - auto strFlat = EcmaStringAccessor::Flatten(vm_, strHandle, MemSpaceType::OLD_SPACE); - if (EcmaStringAccessor(strFlat).NotTreeString()) { - Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast(strFlat)); - if (objectRegion->InYoungSpace()) { - JSHandle resultHandle(vm_->GetJSThread(), strFlat); - strFlat = EcmaStringAccessor::CopyStringToOldSpace(vm_, - resultHandle, EcmaStringAccessor(strFlat).GetLength(), EcmaStringAccessor(strFlat).IsUtf8()); - } + if (EcmaStringAccessor(string).IsInternString()) { + return string; } - InternString(strFlat); + JSHandle strHandle(vm->GetJSThread(), string); + EcmaString *strFlat = EcmaStringAccessor::Flatten(vm, strHandle, MemSpaceType::SHARED_OLD_SPACE); + if (EcmaStringAccessor(strFlat).IsInternString()) { + return strFlat; + } + EcmaString *result = GetStringThreadUnsafe(strFlat); + if (result != nullptr) { + return result; + } + + InternStringThreadUnsafe(strFlat); + return strFlat; +} + +EcmaString *EcmaStringTable::InsertStringToTable(EcmaVM *vm, const JSHandle &strHandle) +{ + RuntimeLockHolder locker(vm->GetJSThread(), mutex_); + auto strFlat = EcmaStringAccessor::Flatten(vm, strHandle, MemSpaceType::SHARED_OLD_SPACE); + InternStringThreadUnsafe(strFlat); return strFlat; } -EcmaString *EcmaStringTable::TryGetInternString(EcmaString *string) +EcmaString *EcmaStringTable::TryGetInternString(JSThread *thread, const JSHandle &string) { - return GetString(string); + RuntimeLockHolder locker(thread, mutex_); + return GetStringThreadUnsafe(*string); } -EcmaString *EcmaStringTable::GetOrInternStringWithSpaceType(const uint8_t *utf8Data, uint32_t utf8Len, +EcmaString *EcmaStringTable::GetOrInternStringWithSpaceType(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress, MemSpaceType type, bool isConstantString, uint32_t idOffset) { - std::pair result = GetString(utf8Data, utf8Len, canBeCompress); + ASSERT(IsSMemSpace(type)); + RuntimeLockHolder locker(vm->GetJSThread(), mutex_); + std::pair result = GetStringThreadUnsafe(utf8Data, utf8Len, canBeCompress); if (result.first != nullptr) { return result.first; } - type = type == MemSpaceType::NON_MOVABLE ? MemSpaceType::NON_MOVABLE : MemSpaceType::OLD_SPACE; - EcmaString *str; + type = (type == MemSpaceType::SHARED_NON_MOVABLE) ? type : MemSpaceType::SHARED_OLD_SPACE; + EcmaString *str = nullptr; if (canBeCompress) { // Constant string will be created in this branch. - str = EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, canBeCompress, type, isConstantString, + str = EcmaStringAccessor::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, type, isConstantString, idOffset); } else { - str = EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, canBeCompress, type); + str = EcmaStringAccessor::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, type); } str->SetMixHashcode(result.second); - InternString(str); + InternStringThreadUnsafe(str); return str; } -EcmaString *EcmaStringTable::GetOrInternStringWithSpaceType(const uint8_t *utf8Data, uint32_t utf16Len, +EcmaString *EcmaStringTable::GetOrInternStringWithSpaceType(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len, MemSpaceType type) { - type = type == MemSpaceType::NON_MOVABLE ? MemSpaceType::NON_MOVABLE : MemSpaceType::OLD_SPACE; - EcmaString *str = EcmaStringAccessor::CreateUtf16StringFromUtf8(vm_, utf8Data, utf16Len, type); - EcmaString *result = GetString(str); + ASSERT(IsSMemSpace(type)); + type = (type == MemSpaceType::SHARED_NON_MOVABLE) ? type : MemSpaceType::SHARED_OLD_SPACE; + RuntimeLockHolder locker(vm->GetJSThread(), mutex_); + EcmaString *str = EcmaStringAccessor::CreateUtf16StringFromUtf8(vm, utf8Data, utf16Len, type); + EcmaString *result = GetStringThreadUnsafe(str); if (result != nullptr) { return result; } - InternString(str); + InternStringThreadUnsafe(str); return str; } @@ -269,6 +294,7 @@ void EcmaStringTable::SweepWeakReference(const WeakRootVisitor &visitor) // Strings in string table should not be in the young space. Only old gc will sweep string table. auto *object = it->second; auto fwd = visitor(object); + // todo(hzzhouzebin) wait for shared-gc ASSERT(!Region::ObjectAddressToRange(object)->InYoungSpace()); if (fwd == nullptr) { LOG_ECMA(VERBOSE) << "StringTable: delete string " << std::hex << object; @@ -283,9 +309,10 @@ void EcmaStringTable::SweepWeakReference(const WeakRootVisitor &visitor) } } -void EcmaStringTable::RelocateConstantData(const JSPandaFile *jsPandaFile) +void EcmaStringTable::RelocateConstantData(EcmaVM *vm, const JSPandaFile *jsPandaFile) { - auto thread = vm_->GetJSThread(); + RuntimeLockHolder locker(vm->GetJSThread(), mutex_); + auto thread = vm->GetJSThread(); for (auto it = table_.begin(); it != table_.end();) { auto *object = it->second; if (!EcmaStringAccessor(object).IsConstantString()) { @@ -303,12 +330,13 @@ void EcmaStringTable::RelocateConstantData(const JSPandaFile *jsPandaFile) if (constantStr->GetConstantData() == sd.data) { uint32_t strLen = sd.utf16_length; if (UNLIKELY(strLen == 0)) { - it->second = *(vm_->GetFactory()->GetEmptyString()); + it->second = *(vm->GetFactory()->GetEmptyString()); } size_t byteLength = sd.is_ascii ? 1 : sizeof(uint16_t); - JSHandle newData = vm_->GetFactory()->NewByteArray( + JSMutableHandle newData(vm->GetJSThread(), JSTaggedValue::Undefined()); + newData.Update(vm->GetFactory()->NewByteArray( strLen, byteLength, reinterpret_cast(const_cast(sd.data)), - MemSpaceType::NON_MOVABLE); + MemSpaceType::SHARED_NON_MOVABLE)); constantStr->SetRelocatedData(thread, newData.GetTaggedValue()); constantStr->SetConstantData(static_cast(newData->GetData())); constantStr->SetEntityId(-1); @@ -319,8 +347,9 @@ void EcmaStringTable::RelocateConstantData(const JSPandaFile *jsPandaFile) } } -bool EcmaStringTable::CheckStringTableValidity() +bool EcmaStringTable::CheckStringTableValidity(JSThread *thread) { + RuntimeLockHolder locker(thread, mutex_); for (auto itemOuter = table_.begin(); itemOuter != table_.end(); ++itemOuter) { auto outerString = itemOuter->second; if (!EcmaStringAccessor(outerString).NotTreeString()) { @@ -343,15 +372,15 @@ bool EcmaStringTable::CheckStringTableValidity() return true; } -void SingleCharTable::CreateSingleCharTable(JSThread *thread) +JSTaggedValue SingleCharTable::CreateSingleCharTable(JSThread *thread) { auto table = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(MAX_ONEBYTE_CHARCODE, - JSTaggedValue::Undefined(), MemSpaceType::NON_MOVABLE); + JSTaggedValue::Undefined(), MemSpaceType::SHARED_NON_MOVABLE); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); for (uint32_t i = 1; i < MAX_ONEBYTE_CHARCODE; ++i) { std::string tmp(1, i + 0X00); // 1: size table->Set(thread, i, factory->NewFromASCIINonMovable(tmp).GetTaggedValue()); } - thread->SetSingleCharTable((table.GetTaggedValue())); + return table.GetTaggedValue(); } } // namespace panda::ecmascript diff --git a/ecmascript/ecma_string_table.h b/ecmascript/ecma_string_table.h index a45588a7cd4e79c4f37f221db700b2097d2904c4..c3612618f8048a3a3c22069473aa4c7cad2531ee 100644 --- a/ecmascript/ecma_string_table.h +++ b/ecmascript/ecma_string_table.h @@ -16,9 +16,12 @@ #ifndef ECMASCRIPT_STRING_TABLE_H #define ECMASCRIPT_STRING_TABLE_H +#include "ecmascript/js_tagged_value.h" +#include "ecmascript/js_thread.h" #include "ecmascript/mem/c_containers.h" #include "ecmascript/mem/space.h" #include "ecmascript/mem/visitor.h" +#include "ecmascript/platform/mutex.h" #include "ecmascript/tagged_array-inl.h" namespace panda::ecmascript { @@ -28,51 +31,56 @@ class JSPandaFile; class EcmaStringTable { public: - explicit EcmaStringTable(const EcmaVM *vm); + EcmaStringTable() = default; virtual ~EcmaStringTable() { table_.clear(); } - void InternEmptyString(EcmaString *emptyStr); - EcmaString *GetOrInternString(const JSHandle &firstString, const JSHandle &secondString); - EcmaString *GetOrInternString(const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress); - EcmaString *CreateAndInternStringNonMovable(const uint8_t *utf8Data, uint32_t utf8Len); - EcmaString *GetOrInternString(const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress); - EcmaString *GetOrInternString(EcmaString *string); - EcmaString *GetOrInternCompressedSubString(const JSHandle &string, uint32_t offset, uint32_t utf8Len); - EcmaString *GetOrInternStringWithSpaceType(const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress, - MemSpaceType type, bool isConstantString, uint32_t idOffset); - EcmaString *GetOrInternStringWithSpaceType(const uint8_t *utf8Data, uint32_t utf16Len, + void InternEmptyString(JSThread *thread, EcmaString *emptyStr); + EcmaString *GetOrInternString(EcmaVM *vm, + const JSHandle &firstString, + const JSHandle &secondString); + EcmaString *GetOrInternString(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress); + EcmaString *CreateAndInternStringNonMovable(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len); + EcmaString *GetOrInternString(EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress); + EcmaString *GetOrInternString(EcmaVM *vm, EcmaString *string); + EcmaString *GetOrInternCompressedSubString(EcmaVM *vm, const JSHandle &string, + uint32_t offset, uint32_t utf8Len); + EcmaString *GetOrInternStringWithSpaceType(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, + bool canBeCompress, MemSpaceType type, bool isConstantString, uint32_t idOffset); + EcmaString *GetOrInternStringWithSpaceType(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len, MemSpaceType type); - EcmaString *TryGetInternString(EcmaString *string); - EcmaString *InsertStringToTable(const JSHandle &strHandle); + EcmaString *TryGetInternString(JSThread *thread, const JSHandle &string); + EcmaString *InsertStringToTable(EcmaVM *vm, const JSHandle &strHandle); void SweepWeakReference(const WeakRootVisitor &visitor); - bool CheckStringTableValidity(); - void RelocateConstantData(const JSPandaFile *jsPandaFile); + bool CheckStringTableValidity(JSThread *thread); + void RelocateConstantData(EcmaVM *vm, const JSPandaFile *jsPandaFile); private: NO_COPY_SEMANTIC(EcmaStringTable); NO_MOVE_SEMANTIC(EcmaStringTable); - std::pair GetString( - const JSHandle &firstString, const JSHandle &secondString) const; - std::pair GetString(const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress) const; - std::pair GetString(const uint16_t *utf16Data, uint32_t utf16Len) const; - EcmaString *GetString(EcmaString *string) const; + std::pair GetStringThreadUnsafe(const JSHandle &firstString, + const JSHandle &secondString) const; + std::pair GetStringThreadUnsafe(const uint8_t *utf8Data, uint32_t utf8Len, + bool canBeCompress) const; + std::pair GetStringThreadUnsafe(const uint16_t *utf16Data, uint32_t utf16Len) const; + EcmaString *GetStringThreadUnsafe(EcmaString *string) const; - void InternString(EcmaString *string); + void InternStringThreadUnsafe(EcmaString *string); + EcmaString *GetOrInternStringThreadUnsafe(EcmaVM *vm, EcmaString *string); - void InsertStringIfNotExist(EcmaString *string) + void InsertStringIfNotExistThreadUnsafe(EcmaString *string) { - EcmaString *str = GetString(string); + EcmaString *str = GetStringThreadUnsafe(string); if (str == nullptr) { - InternString(string); + InternStringThreadUnsafe(string); } } CUnorderedMultiMap table_; - const EcmaVM *vm_{nullptr}; + RecursiveMutex mutex_; friend class SnapshotProcessor; friend class BaseDeserializer; }; @@ -83,12 +91,16 @@ public: { return reinterpret_cast(object); } - static void CreateSingleCharTable(JSThread *thread); + static JSTaggedValue CreateSingleCharTable(JSThread *thread); JSTaggedValue GetStringFromSingleCharTable(int32_t ch) { return Get(ch); } private: + SingleCharTable() = default; + ~SingleCharTable() = default; + NO_COPY_SEMANTIC(SingleCharTable); + NO_MOVE_SEMANTIC(SingleCharTable); static constexpr uint32_t MAX_ONEBYTE_CHARCODE = 128; // 0X00-0X7F }; } // namespace panda::ecmascript diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp index 76ce5af08a4d8a2e1c652dae43b7aa82573df329..f5ee338249b0808a64d7fb637a4257b7bcaad62b 100644 --- a/ecmascript/ecma_vm.cpp +++ b/ecmascript/ecma_vm.cpp @@ -18,6 +18,7 @@ #include "ecmascript/base/string_helper.h" #include "ecmascript/builtins/builtins.h" #include "ecmascript/builtins/builtins_ark_tools.h" +#include "ecmascript/checkpoint/thread_state_transition.h" #ifdef ARK_SUPPORT_INTL #include "ecmascript/builtins/builtins_collator.h" #include "ecmascript/builtins/builtins_date_time_format.h" @@ -79,6 +80,7 @@ #include "ecmascript/patch/quick_fix_manager.h" #include "ecmascript/pgo_profiler/pgo_profiler_manager.h" #include "ecmascript/regexp/regexp_parser_cache.h" +#include "ecmascript/runtime.h" #include "ecmascript/runtime_call_id.h" #include "ecmascript/snapshot/mem/snapshot.h" #include "ecmascript/snapshot/mem/snapshot_env.h" @@ -97,22 +99,24 @@ namespace panda::ecmascript { using RandomGenerator = base::RandomGenerator; using PGOProfilerManager = pgo::PGOProfilerManager; AOTFileManager *JsStackInfo::loader = nullptr; -/* static */ -EcmaVM *EcmaVM::Create(const JSRuntimeOptions &options, EcmaParamConfiguration &config) + +EcmaVM *EcmaVM::Create(const JSRuntimeOptions &options) { + Runtime::CreateIfFirstVm(options); + auto heapType = options.IsWorker() ? EcmaParamConfiguration::HeapType::WORKER_HEAP : + EcmaParamConfiguration::HeapType::DEFAULT_HEAP; + auto config = EcmaParamConfiguration(heapType, + MemMapAllocator::GetInstance()->GetCapacity()); + MemMapAllocator::GetInstance()->IncreaseAndCheckReserved(config.GetMaxHeapSize()); JSRuntimeOptions newOptions = options; // only define SUPPORT_ENABLE_ASM_INTERP can enable asm-interpreter #if !defined(SUPPORT_ENABLE_ASM_INTERP) newOptions.SetEnableAsmInterpreter(false); #endif auto vm = new EcmaVM(newOptions, config); - if (UNLIKELY(vm == nullptr)) { - LOG_ECMA(ERROR) << "Failed to create jsvm"; - return nullptr; - } auto jsThread = JSThread::Create(vm); vm->thread_ = jsThread; - vm->Initialize(); + Runtime::GetInstance()->InitializeIfFirstVm(vm); if (JsStackInfo::loader == nullptr) { JsStackInfo::loader = vm->GetAOTFileManager(); } @@ -127,12 +131,12 @@ EcmaVM *EcmaVM::Create(const JSRuntimeOptions &options, EcmaParamConfiguration & // static bool EcmaVM::Destroy(EcmaVM *vm) { - if (vm != nullptr) { - delete vm; - vm = nullptr; - return true; + if (UNLIKELY(vm == nullptr)) { + return false; } - return false; + delete vm; + Runtime::DestroyIfLastVm(); + return true; } void EcmaVM::PreFork() @@ -140,6 +144,7 @@ void EcmaVM::PreFork() heap_->CompactHeapBeforeFork(); heap_->AdjustSpaceSizeForAppSpawn(); heap_->GetReadOnlySpace()->SetReadOnly(); + SharedHeap::GetInstance()->DisableParallelGC(); heap_->DisableParallelGC(); } @@ -147,7 +152,9 @@ void EcmaVM::PostFork() { RandomGenerator::InitRandom(); heap_->SetHeapMode(HeapMode::SHARE); - GetAssociatedJSThread()->SetThreadId(); + GetAssociatedJSThread()->PostFork(); + Taskpool::GetCurrentTaskpool()->Initialize(); + SharedHeap::GetInstance()->EnableParallelGC(GetJSOptions()); heap_->EnableParallelGC(); std::string bundleName = PGOProfilerManager::GetInstance()->GetBundleName(); if (ohos::EnableAotListHelper::GetInstance()->IsDisableBlackList(bundleName)) { @@ -164,8 +171,7 @@ void EcmaVM::PostFork() } EcmaVM::EcmaVM(JSRuntimeOptions options, EcmaParamConfiguration config) - : stringTable_(new EcmaStringTable(this)), - nativeAreaAllocator_(std::make_unique()), + : nativeAreaAllocator_(std::make_unique()), heapRegionAllocator_(std::make_unique()), chunk_(nativeAreaAllocator_.get()), ecmaParamConfiguration_(std::move(config)) @@ -233,6 +239,7 @@ Jit *EcmaVM::GetJit() const bool EcmaVM::Initialize() { ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "EcmaVM::Initialize"); + stringTable_ = Runtime::GetInstance()->GetEcmaStringTable(); InitializePGOProfiler(); Taskpool::GetCurrentTaskpool()->Initialize(); #ifndef PANDA_TARGET_WINDOWS @@ -241,7 +248,7 @@ bool EcmaVM::Initialize() heap_ = new Heap(this); heap_->Initialize(); gcStats_ = chunk_.New(heap_, options_.GetLongPauseTime()); - factory_ = chunk_.New(thread_, heap_); + factory_ = chunk_.New(thread_, heap_, SharedHeap::GetInstance()); if (UNLIKELY(factory_ == nullptr)) { LOG_FULL(FATAL) << "alloc factory_ failed"; UNREACHABLE(); @@ -251,13 +258,13 @@ bool EcmaVM::Initialize() auto context = new EcmaContext(thread_); thread_->PushContext(context); [[maybe_unused]] EcmaHandleScope scope(thread_); + thread_->SetReadyForGCIterating(); snapshotEnv_ = new SnapshotEnv(this); context->Initialize(); snapshotEnv_->AddGlobalConstToMap(); thread_->SetGlueGlobalEnv(reinterpret_cast(context->GetGlobalEnv().GetTaggedType())); thread_->SetGlobalObject(GetGlobalEnv()->GetGlobalObject()); thread_->SetCurrentEcmaContext(context); - SingleCharTable::CreateSingleCharTable(thread_); GenerateInternalNativeMethods(); quickFixManager_ = new QuickFixManager(); if (options_.GetEnableAsmInterpreter()) { @@ -275,6 +282,7 @@ bool EcmaVM::Initialize() EcmaVM::~EcmaVM() { + ASSERT(thread_->IsInRunningStateOrProfiling()); initialized_ = false; #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) if (thread_->isProfiling_) { @@ -349,7 +357,6 @@ EcmaVM::~EcmaVM() } if (stringTable_ != nullptr) { - delete stringTable_; stringTable_ = nullptr; } @@ -388,6 +395,7 @@ JSHandle EcmaVM::GetGlobalEnv() const JSTaggedValue EcmaVM::FastCallAot(size_t actualNumArgs, JSTaggedType *args, const JSTaggedType *prevFp) { INTERPRETER_TRACE(thread_, ExecuteAot); + ASSERT(thread_->IsInManagedState()); auto entry = thread_->GetRTInterface(kungfu::RuntimeStubCSigns::ID_OptimizedFastCallEntry); // do not modify this log to INFO, this will call many times LOG_ECMA(DEBUG) << "start to execute aot entry: " << (void*)entry; @@ -465,8 +473,6 @@ void EcmaVM::ProcessNativeDelete(const WeakRootVisitor &visitor) } } } - - thread_->GetCurrentEcmaContext()->ProcessNativeDelete(visitor); } void EcmaVM::ProcessReferences(const WeakRootVisitor &visitor) @@ -495,12 +501,12 @@ void EcmaVM::ProcessReferences(const WeakRootVisitor &visitor) ++iter; } } - thread_->GetCurrentEcmaContext()->ProcessReferences(visitor); GetPGOProfiler()->ProcessReferences(visitor); } void EcmaVM::PushToNativePointerList(JSNativePointer *pointer) { + ASSERT(!JSTaggedValue(pointer).IsInSharedHeap()); nativePointerList_.emplace_back(pointer); } @@ -555,10 +561,12 @@ void EcmaVM::Iterate(const RootVisitor &v, const RootRangeVisitor &rv) { rv(Root::ROOT_VM, ObjectSlot(ToUintPtr(&internalNativeMethods_.front())), ObjectSlot(ToUintPtr(&internalNativeMethods_.back()) + JSTaggedValue::TaggedTypeSize())); - if (!WIN_OR_MAC_OR_IOS_PLATFORM) { + if (!WIN_OR_MAC_OR_IOS_PLATFORM && snapshotEnv_!= nullptr) { snapshotEnv_->Iterate(v); } - pgoProfiler_->Iterate(v); + if (pgoProfiler_ != nullptr) { + pgoProfiler_->Iterate(v); + } } #if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER) @@ -636,7 +644,7 @@ void EcmaVM::GenerateInternalNativeMethods() size_t length = static_cast(MethodIndex::METHOD_END); constexpr uint32_t numArgs = 2; // function object and this for (size_t i = 0; i < length; i++) { - auto method = factory_->NewMethod(nullptr, MemSpaceType::NON_MOVABLE); + auto method = factory_->NewSMethod(nullptr, MemSpaceType::SHARED_NON_MOVABLE); method->SetNativePointer(InternalMethodTable[i]); method->SetNativeBit(true); method->SetNumArgsWithCallField(numArgs); @@ -830,4 +838,20 @@ bool EcmaVM::IsHmsModule(const CString &moduleStr) const } return true; } + +// Initialize IcuData Path +void EcmaVM::InitializeIcuData(const JSRuntimeOptions &options) +{ + std::string icuPath = options.GetIcuDataPath(); + if (icuPath == "default") { +#if !WIN_OR_MAC_OR_IOS_PLATFORM && !defined(PANDA_TARGET_LINUX) + SetHwIcuDirectory(); +#endif + } else { + std::string absPath; + if (ecmascript::RealPath(icuPath, absPath)) { + u_setDataDirectory(absPath.c_str()); + } + } +} } // namespace panda::ecmascript diff --git a/ecmascript/ecma_vm.h b/ecmascript/ecma_vm.h index 4d8dccb719094d08982161a2cb92db833f56ece2..f7de86ef670c959272f387fc664840ee38de52a2 100644 --- a/ecmascript/ecma_vm.h +++ b/ecmascript/ecma_vm.h @@ -102,7 +102,7 @@ using DeviceDisconnectCallback = std::function; using UncatchableErrorHandler = std::function; class EcmaVM { public: - static EcmaVM *Create(const JSRuntimeOptions &options, EcmaParamConfiguration &config); + static EcmaVM *Create(const JSRuntimeOptions &options); static bool Destroy(EcmaVM *vm); @@ -599,6 +599,8 @@ public: { return thread_->GetThreadId(); } + + static void InitializeIcuData(const JSRuntimeOptions &options); protected: void PrintJSErrorInfo(const JSHandle &exceptionInfo) const; @@ -618,7 +620,7 @@ private: bool icEnabled_ {true}; bool initialized_ {false}; GCStats *gcStats_ {nullptr}; - EcmaStringTable *stringTable_; + EcmaStringTable *stringTable_ {nullptr}; // VM memory management. std::unique_ptr nativeAreaAllocator_; diff --git a/ecmascript/free_object.cpp b/ecmascript/free_object.cpp index 4ed56e3182bd912c1ec34e8efd4d7d3c33e07b46..87ca57b4d5f1bc5dcbf7971ce0ca2db389192b17 100644 --- a/ecmascript/free_object.cpp +++ b/ecmascript/free_object.cpp @@ -14,14 +14,33 @@ */ #include "ecmascript/free_object.h" -#include "ecmascript/object_factory.h" +#include "ecmascript/global_env_constants-inl.h" namespace panda::ecmascript { -FreeObject *FreeObject::FillFreeObject(EcmaVM *vm, uintptr_t address, size_t size) +FreeObject *FreeObject::FillFreeObject(BaseHeap *heap, uintptr_t address, size_t size) { ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast(address), size); - FreeObject *freeObject = vm->GetFactory()->FillFreeObject(address, size); + auto globalConst = heap->GetGlobalConst(); + FreeObject *object = nullptr; + if (size >= FreeObject::SIZE_OFFSET && size < FreeObject::SIZE) { + object = reinterpret_cast(address); + object->SetClassWithoutBarrier( + JSHClass::Cast(globalConst->GetFreeObjectWithOneFieldClass().GetTaggedObject())); + object->SetNext(INVALID_OBJECT); + } else if (size >= FreeObject::SIZE) { + object = reinterpret_cast(address); + object->SetClassWithoutBarrier( + JSHClass::Cast(globalConst->GetFreeObjectWithTwoFieldClass().GetTaggedObject())); + object->SetAvailable(size); + object->SetNext(INVALID_OBJECT); + } else if (size == FreeObject::NEXT_OFFSET) { + object = reinterpret_cast(address); + object->SetClassWithoutBarrier( + JSHClass::Cast(globalConst->GetFreeObjectWithNoneFieldClass().GetTaggedObject())); + } else { + LOG_ECMA(DEBUG) << "Fill free object size is smaller"; + } ASAN_POISON_MEMORY_REGION(reinterpret_cast(address), size); - return freeObject; + return object; } } // namespace panda::ecmascript diff --git a/ecmascript/free_object.h b/ecmascript/free_object.h index ab382c11159fd896ab6f2a0cbc647a7eec0090c8..e73a80a42c3ba1b11f636f9d5b09be87614c053e 100644 --- a/ecmascript/free_object.h +++ b/ecmascript/free_object.h @@ -16,7 +16,7 @@ #ifndef ECMASCRIPT_FREE_OBJECT_H #define ECMASCRIPT_FREE_OBJECT_H -#include "ecmascript/js_hclass.h" +#include "ecmascript/js_hclass-inl.h" #include "ecmascript/mem/barriers.h" #include "ecmascript/mem/tagged_object-inl.h" @@ -29,7 +29,7 @@ public: { return reinterpret_cast(object); } - static FreeObject *FillFreeObject(EcmaVM *vm, uintptr_t address, size_t size); + static FreeObject *FillFreeObject(BaseHeap *heap, uintptr_t address, size_t size); inline bool IsEmpty() const { diff --git a/ecmascript/global_dictionary-inl.h b/ecmascript/global_dictionary-inl.h index 3ead58695c807930fbffe9ee4606ab5b407c749d..a77633e647f154e58c4c9798de6819815bc29c82 100644 --- a/ecmascript/global_dictionary-inl.h +++ b/ecmascript/global_dictionary-inl.h @@ -61,7 +61,7 @@ JSTaggedValue GlobalDictionary::GetValue(int entry) const PropertyAttributes GlobalDictionary::GetAttributes(int entry) const { int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX; - return PropertyAttributes(Get(index).GetInt()); + return PropertyAttributes(Get(index)); } void GlobalDictionary::SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, const JSTaggedValue &value, diff --git a/ecmascript/global_env.cpp b/ecmascript/global_env.cpp index d8594343355864f77db964db555775ef95cb2ff5..f9bae4136b25dc38723c369da63127a54011554c 100644 --- a/ecmascript/global_env.cpp +++ b/ecmascript/global_env.cpp @@ -38,7 +38,7 @@ void GlobalEnv::Init(JSThread *thread) SetGlobalRecord(thread, GlobalDictionary::Create(thread)); JSTaggedValue emptyStr = thread->GlobalConstants()->GetEmptyString(); EcmaStringTable *stringTable = thread->GetEcmaVM()->GetEcmaStringTable(); - stringTable->InternEmptyString(EcmaString::Cast(emptyStr.GetTaggedObject())); + stringTable->InternEmptyString(thread, EcmaString::Cast(emptyStr.GetTaggedObject())); SetTemplateMap(thread, TemplateMap::Create(thread)); SetObjectLiteralHClassCache(thread, JSTaggedValue::Hole()); SetJsonObjectHclassCache(thread, JSTaggedValue::Hole()); diff --git a/ecmascript/global_env_constants-inl.h b/ecmascript/global_env_constants-inl.h index 7db7b518916c624f0264251a38ad3606103210ee..0bd79c367e9072793498c065d1aa5e0ce2061270 100644 --- a/ecmascript/global_env_constants-inl.h +++ b/ecmascript/global_env_constants-inl.h @@ -70,17 +70,18 @@ inline uintptr_t GlobalEnvConstants::GetGlobalConstantAddr(ConstantIndex index) * static_cast(ConstantIndex::Index); \ } -#define DECL_GET_IMPL_WITH_TYPE(Type, Name, Index, Desc) DECL_GET_IMPL_COMMON(Type, Name, Index) - GLOBAL_ENV_CONSTANT_CLASS(DECL_GET_IMPL_WITH_TYPE) // NOLINT(readability-const-return-type) - GLOBAL_ENV_CONSTANT_SPECIAL(DECL_GET_IMPL_WITH_TYPE) // NOLINT(readability-const-return-type) - GLOBAL_ENV_CONSTANT_CONSTANT(DECL_GET_IMPL_WITH_TYPE) // NOLINT(readability-const-return-type) - GLOBAL_ENV_CONSTANT_ACCESSOR(DECL_GET_IMPL_WITH_TYPE) // NOLINT(readability-const-return-type) - GLOBAL_ENV_CACHES(DECL_GET_IMPL_WITH_TYPE) // NOLINT(readability-const-return-type) - #define DECL_GET_IMPL_STRING(Name, Index, Token) DECL_GET_IMPL_COMMON(JSTaggedValue, Name, Index) - GLOBAL_ENV_CONSTANT_STRING(DECL_GET_IMPL_STRING) // NOLINT(readability-const-return-type) +#define DECL_GET_IMPL_WITH_TYPE(Type, Name, Index, Desc) DECL_GET_IMPL_COMMON(Type, Name, Index) + SHARED_GLOBAL_ENV_CONSTANT_CLASS(DECL_GET_IMPL_WITH_TYPE) // NOLINT(readability-const-return-type) + SHARED_GLOBAL_ENV_CONSTANT_STRING(DECL_GET_IMPL_STRING) // NOLINT(readability-const-return-type) + SHARED_GLOBAL_ENV_CONSTANT_ACCESSOR(DECL_GET_IMPL_WITH_TYPE) // NOLINT(readability-const-return-type) + SHARED_GLOBAL_ENV_CONSTANT_SPECIAL(DECL_GET_IMPL_WITH_TYPE); // NOLINT(readability-const-return-type) + GLOBAL_ENV_CONSTANT_CLASS(DECL_GET_IMPL_WITH_TYPE) // NOLINT(readability-const-return-type) + GLOBAL_ENV_CONSTANT_SPECIAL(DECL_GET_IMPL_WITH_TYPE) // NOLINT(readability-const-return-type) + GLOBAL_ENV_CONSTANT_CONSTANT(DECL_GET_IMPL_WITH_TYPE) // NOLINT(readability-const-return-type) + GLOBAL_ENV_CACHES(DECL_GET_IMPL_WITH_TYPE) // NOLINT(readability-const-return-type) +#undef DECL_GET_IMPL_WITH_TYPE #undef DECL_GET_IMPL_STRING - #undef DECL_GET_IMPL_COMMON // clang-format on } // namespace panda::ecmascript diff --git a/ecmascript/global_env_constants.cpp b/ecmascript/global_env_constants.cpp index 43ae950fd005be0006a6de38f0c2691bdb85eca9..55a9ebe289147f98a795f3153c24e099581c702e 100644 --- a/ecmascript/global_env_constants.cpp +++ b/ecmascript/global_env_constants.cpp @@ -19,6 +19,7 @@ #include "ecmascript/builtins/builtins.h" #include "ecmascript/builtins/builtins_global.h" #include "ecmascript/ecma_string-inl.h" +#include "ecmascript/ecma_string_table.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/free_object.h" #include "ecmascript/global_env.h" @@ -72,180 +73,225 @@ #include "ecmascript/method.h" #include "ecmascript/module/js_module_source_text.h" #include "ecmascript/object_factory.h" +#include "ecmascript/runtime.h" #include "ecmascript/subtyping_operator.h" #include "ecmascript/tagged_node.h" #include "ecmascript/ts_types/ts_type.h" namespace panda::ecmascript { -void GlobalEnvConstants::Init(JSThread *thread, JSHClass *hClass) +void GlobalEnvConstants::Init(JSThread *thread) { - InitRootsClass(thread, hClass); - InitGlobalConstant(thread); - InitGlobalCaches(); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + auto *globalConst = Runtime::GetInstance()->GetGlobalEnvConstants(); + if (globalConst != nullptr) { + // 1. Copy shareds. + for (size_t i = static_cast(ConstantIndex::SHARED_BEGIN); + i <= static_cast(ConstantIndex::SHARED_END); i++) { + constants_[i] = globalConst->constants_[i]; + } + } else { + InitSharedRootsClasses(factory); + InitSharedStrings(factory); + InitSharedMiscellanious(thread, factory); + } + // 2. Init non-shareds. + InitMiscellanious(thread, factory); + InitRootsClasses(factory); } -void GlobalEnvConstants::InitRootsClass(JSThread *thread, JSHClass *hClass) +void GlobalEnvConstants::InitSharedStrings(ObjectFactory *factory) +{ + #define INIT_GLOBAL_ENV_CONSTANT_STRING(Name, Index, Token) \ + SetConstant(ConstantIndex::Index, factory->NewFromASCIINonMovable(Token)); + SHARED_GLOBAL_ENV_CONSTANT_STRING(INIT_GLOBAL_ENV_CONSTANT_STRING) + #undef INIT_GLOBAL_ENV_CONSTANT_STRING +} + +void GlobalEnvConstants::InitSharedRootsClasses(ObjectFactory *factory) { // Global constants are readonly. - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHClass *hClass = *factory->InitSClassClass(); SetConstant(ConstantIndex::HCLASS_CLASS_INDEX, JSTaggedValue(hClass)); // To reverse the order, the hclass of string needs to load default supers SetConstant(ConstantIndex::ARRAY_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::TAGGED_ARRAY)); - SetConstant(ConstantIndex::DEFAULT_SUPERS_INDEX, - WeakVector::Create(thread, SubtypingOperator::DEFAULT_SUPERS_CAPACITY, MemSpaceType::NON_MOVABLE)); + factory->NewSEcmaReadOnlyHClass(hClass, 0, JSType::TAGGED_ARRAY)); SetConstant(ConstantIndex::FREE_OBJECT_WITH_NONE_FIELD_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, FreeObject::NEXT_OFFSET, JSType::FREE_OBJECT_WITH_NONE_FIELD)); + factory->NewSEcmaReadOnlyHClass(hClass, FreeObject::NEXT_OFFSET, JSType::FREE_OBJECT_WITH_NONE_FIELD)); SetConstant(ConstantIndex::FREE_OBJECT_WITH_ONE_FIELD_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, FreeObject::SIZE_OFFSET, JSType::FREE_OBJECT_WITH_ONE_FIELD)); + factory->NewSEcmaReadOnlyHClass(hClass, FreeObject::SIZE_OFFSET, JSType::FREE_OBJECT_WITH_ONE_FIELD)); SetConstant(ConstantIndex::FREE_OBJECT_WITH_TWO_FIELD_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, FreeObject::SIZE, JSType::FREE_OBJECT_WITH_TWO_FIELD)); - SetConstant(ConstantIndex::LINE_STRING_CLASS_INDEX, factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::LINE_STRING)); + factory->NewSEcmaReadOnlyHClass(hClass, FreeObject::SIZE, JSType::FREE_OBJECT_WITH_TWO_FIELD)); + SetConstant(ConstantIndex::LINE_STRING_CLASS_INDEX, + factory->NewSEcmaReadOnlyHClass(hClass, 0, JSType::LINE_STRING)); SetConstant(ConstantIndex::SLICED_STRING_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::SLICED_STRING)); + factory->NewSEcmaReadOnlyHClass(hClass, 0, JSType::SLICED_STRING)); SetConstant(ConstantIndex::CONSTANT_STRING_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::CONSTANT_STRING)); - SetConstant(ConstantIndex::TREE_STRING_CLASS_INDEX, factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::TREE_STRING)); + factory->NewSEcmaReadOnlyHClass(hClass, 0, JSType::CONSTANT_STRING)); + SetConstant(ConstantIndex::TREE_STRING_CLASS_INDEX, + factory->NewSEcmaReadOnlyHClass(hClass, 0, JSType::TREE_STRING)); SetConstant(ConstantIndex::BYTE_ARRAY_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::BYTE_ARRAY)); + factory->NewSEcmaReadOnlyHClass(hClass, 0, JSType::BYTE_ARRAY)); SetConstant(ConstantIndex::CONSTANT_POOL_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::CONSTANT_POOL)); + factory->NewSEcmaReadOnlyHClass(hClass, 0, JSType::CONSTANT_POOL)); SetConstant(ConstantIndex::PROFILE_TYPE_INFO_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::PROFILE_TYPE_INFO)); + factory->NewSEcmaReadOnlyHClass(hClass, 0, JSType::PROFILE_TYPE_INFO)); SetConstant(ConstantIndex::AOT_LITERAL_INFO_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::AOT_LITERAL_INFO)); + factory->NewSEcmaReadOnlyHClass(hClass, 0, JSType::AOT_LITERAL_INFO)); SetConstant(ConstantIndex::VTABLE_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::VTABLE)); + factory->NewSEcmaReadOnlyHClass(hClass, 0, JSType::VTABLE)); SetConstant(ConstantIndex::COW_MUTANT_TAGGED_ARRAY_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::COW_MUTANT_TAGGED_ARRAY)); + factory->NewSEcmaReadOnlyHClass(hClass, 0, JSType::COW_MUTANT_TAGGED_ARRAY)); SetConstant(ConstantIndex::MUTANT_TAGGED_ARRAY_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::MUTANT_TAGGED_ARRAY)); - InitGlobalConstantSpecial(thread); + factory->NewSEcmaReadOnlyHClass(hClass, 0, JSType::MUTANT_TAGGED_ARRAY)); SetConstant(ConstantIndex::DICTIONARY_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::TAGGED_DICTIONARY)); + factory->NewSEcmaReadOnlyHClass(hClass, 0, JSType::TAGGED_DICTIONARY)); SetConstant(ConstantIndex::COW_ARRAY_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::COW_TAGGED_ARRAY)); + factory->NewSEcmaReadOnlyHClass(hClass, 0, JSType::COW_TAGGED_ARRAY)); SetConstant(ConstantIndex::BIGINT_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, BigInt::SIZE, JSType::BIGINT)); + factory->NewSEcmaReadOnlyHClass(hClass, BigInt::SIZE, JSType::BIGINT)); SetConstant(ConstantIndex::JS_NATIVE_POINTER_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, JSNativePointer::SIZE, JSType::JS_NATIVE_POINTER)); + factory->NewSEcmaReadOnlyHClass(hClass, JSNativePointer::SIZE, JSType::JS_NATIVE_POINTER)); SetConstant(ConstantIndex::ENV_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::LEXICAL_ENV)); + factory->NewSEcmaReadOnlyHClass(hClass, 0, JSType::LEXICAL_ENV)); SetConstant(ConstantIndex::SYMBOL_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, JSSymbol::SIZE, JSType::SYMBOL)); + factory->NewSEcmaReadOnlyHClass(hClass, JSSymbol::SIZE, JSType::SYMBOL)); SetConstant(ConstantIndex::ACCESSOR_DATA_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, AccessorData::SIZE, JSType::ACCESSOR_DATA)); + factory->NewSEcmaReadOnlyHClass(hClass, AccessorData::SIZE, JSType::ACCESSOR_DATA)); SetConstant(ConstantIndex::INTERNAL_ACCESSOR_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, AccessorData::SIZE, JSType::INTERNAL_ACCESSOR)); - SetConstant(ConstantIndex::JS_PROXY_ORDINARY_CLASS_INDEX, - factory->NewEcmaHClass(hClass, JSProxy::SIZE, JSType::JS_PROXY)); + factory->NewSEcmaReadOnlyHClass(hClass, AccessorData::SIZE, JSType::INTERNAL_ACCESSOR)); SetConstant(ConstantIndex::COMPLETION_RECORD_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, CompletionRecord::SIZE, JSType::COMPLETION_RECORD)); + factory->NewSEcmaReadOnlyHClass(hClass, CompletionRecord::SIZE, JSType::COMPLETION_RECORD)); SetConstant(ConstantIndex::GENERATOR_CONTEST_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, GeneratorContext::SIZE, JSType::JS_GENERATOR_CONTEXT)); + factory->NewSEcmaReadOnlyHClass(hClass, GeneratorContext::SIZE, JSType::JS_GENERATOR_CONTEXT)); SetConstant(ConstantIndex::ASYNC_GENERATOR_REQUEST_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, AsyncGeneratorRequest::SIZE, - JSType::ASYNC_GENERATOR_REQUEST)); + factory->NewSEcmaReadOnlyHClass(hClass, AsyncGeneratorRequest::SIZE, + JSType::ASYNC_GENERATOR_REQUEST)); SetConstant(ConstantIndex::ASYNC_ITERATOR_RECORD_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, AsyncIteratorRecord::SIZE, JSType::ASYNC_ITERATOR_RECORD)); + factory->NewSEcmaReadOnlyHClass(hClass, AsyncIteratorRecord::SIZE, JSType::ASYNC_ITERATOR_RECORD)); SetConstant(ConstantIndex::CAPABILITY_RECORD_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, PromiseCapability::SIZE, JSType::PROMISE_CAPABILITY)); + factory->NewSEcmaReadOnlyHClass(hClass, PromiseCapability::SIZE, JSType::PROMISE_CAPABILITY)); SetConstant(ConstantIndex::REACTIONS_RECORD_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, PromiseReaction::SIZE, JSType::PROMISE_REACTIONS)); + factory->NewSEcmaReadOnlyHClass(hClass, PromiseReaction::SIZE, JSType::PROMISE_REACTIONS)); SetConstant(ConstantIndex::PROMISE_ITERATOR_RECORD_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, PromiseIteratorRecord::SIZE, - JSType::PROMISE_ITERATOR_RECORD)); + factory->NewSEcmaReadOnlyHClass(hClass, PromiseIteratorRecord::SIZE, + JSType::PROMISE_ITERATOR_RECORD)); SetConstant(ConstantIndex::PROMISE_RECORD_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, PromiseRecord::SIZE, JSType::PROMISE_RECORD)); + factory->NewSEcmaReadOnlyHClass(hClass, PromiseRecord::SIZE, JSType::PROMISE_RECORD)); SetConstant(ConstantIndex::PROMISE_RESOLVING_FUNCTIONS_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, ResolvingFunctionsRecord::SIZE, - JSType::RESOLVING_FUNCTIONS_RECORD)); + factory->NewSEcmaReadOnlyHClass(hClass, ResolvingFunctionsRecord::SIZE, + JSType::RESOLVING_FUNCTIONS_RECORD)); SetConstant(ConstantIndex::MICRO_JOB_QUEUE_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, job::MicroJobQueue::SIZE, JSType::MICRO_JOB_QUEUE)); + factory->NewSEcmaReadOnlyHClass(hClass, job::MicroJobQueue::SIZE, JSType::MICRO_JOB_QUEUE)); SetConstant(ConstantIndex::PENDING_JOB_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, job::PendingJob::SIZE, JSType::PENDING_JOB)); + factory->NewSEcmaReadOnlyHClass(hClass, job::PendingJob::SIZE, JSType::PENDING_JOB)); SetConstant(ConstantIndex::PROTO_CHANGE_MARKER_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, ProtoChangeMarker::SIZE, JSType::PROTO_CHANGE_MARKER)); + factory->NewSEcmaReadOnlyHClass(hClass, ProtoChangeMarker::SIZE, JSType::PROTO_CHANGE_MARKER)); SetConstant(ConstantIndex::PROTO_CHANGE_DETAILS_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, ProtoChangeDetails::SIZE, JSType::PROTOTYPE_INFO)); + factory->NewSEcmaReadOnlyHClass(hClass, ProtoChangeDetails::SIZE, JSType::PROTOTYPE_INFO)); SetConstant(ConstantIndex::MARKER_CELL_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, MarkerCell::SIZE, JSType::MARKER_CELL)); + factory->NewSEcmaReadOnlyHClass(hClass, MarkerCell::SIZE, JSType::MARKER_CELL)); SetConstant(ConstantIndex::TRACK_INFO_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, TrackInfo::SIZE, JSType::TRACK_INFO)); + factory->NewSEcmaReadOnlyHClass(hClass, TrackInfo::SIZE, JSType::TRACK_INFO)); SetConstant(ConstantIndex::PROTOTYPE_HANDLER_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, PrototypeHandler::SIZE, JSType::PROTOTYPE_HANDLER)); + factory->NewSEcmaReadOnlyHClass(hClass, PrototypeHandler::SIZE, JSType::PROTOTYPE_HANDLER)); SetConstant(ConstantIndex::TRANSITION_HANDLER_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, TransitionHandler::SIZE, JSType::TRANSITION_HANDLER)); + factory->NewSEcmaReadOnlyHClass(hClass, TransitionHandler::SIZE, JSType::TRANSITION_HANDLER)); SetConstant(ConstantIndex::TRANS_WITH_PROTO_HANDLER_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, TransWithProtoHandler::SIZE, JSType::TRANS_WITH_PROTO_HANDLER)); + factory->NewSEcmaReadOnlyHClass(hClass, TransWithProtoHandler::SIZE, JSType::TRANS_WITH_PROTO_HANDLER)); SetConstant(ConstantIndex::STORE_TS_HANDLER_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, StoreTSHandler::SIZE, JSType::STORE_TS_HANDLER)); + factory->NewSEcmaReadOnlyHClass(hClass, StoreTSHandler::SIZE, JSType::STORE_TS_HANDLER)); SetConstant(ConstantIndex::PROPERTY_BOX_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, PropertyBox::SIZE, JSType::PROPERTY_BOX)); + factory->NewSEcmaReadOnlyHClass(hClass, PropertyBox::SIZE, JSType::PROPERTY_BOX)); SetConstant(ConstantIndex::PROGRAM_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, Program::SIZE, JSType::PROGRAM)); - SetConstant( - ConstantIndex::IMPORT_ENTRY_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, ImportEntry::SIZE, JSType::IMPORTENTRY_RECORD)); - SetConstant( - ConstantIndex::LOCAL_EXPORT_ENTRY_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, LocalExportEntry::SIZE, JSType::LOCAL_EXPORTENTRY_RECORD)); - SetConstant( - ConstantIndex::INDIRECT_EXPORT_ENTRY_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, IndirectExportEntry::SIZE, - JSType::INDIRECT_EXPORTENTRY_RECORD)); - SetConstant( - ConstantIndex::STAR_EXPORT_ENTRY_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, StarExportEntry::SIZE, JSType::STAR_EXPORTENTRY_RECORD)); - SetConstant( - ConstantIndex::SOURCE_TEXT_MODULE_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, SourceTextModule::SIZE, JSType::SOURCE_TEXT_MODULE_RECORD)); - SetConstant( - ConstantIndex::RESOLVED_BINDING_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, ResolvedBinding::SIZE, JSType::RESOLVEDBINDING_RECORD)); - SetConstant( - ConstantIndex::RESOLVED_INDEX_BINDING_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, ResolvedIndexBinding::SIZE, JSType::RESOLVEDINDEXBINDING_RECORD)); - - JSHClass *jsProxyCallableClass = *factory->NewEcmaHClass(hClass, JSProxy::SIZE, JSType::JS_PROXY); - - jsProxyCallableClass->SetCallable(true); - SetConstant(ConstantIndex::JS_PROXY_CALLABLE_CLASS_INDEX, JSTaggedValue(jsProxyCallableClass)); - - JSHClass *jsProxyConstructClass = *factory->NewEcmaHClass(hClass, JSProxy::SIZE, JSType::JS_PROXY); - - jsProxyConstructClass->SetCallable(true); - jsProxyConstructClass->SetConstructor(true); - SetConstant(ConstantIndex::JS_PROXY_CONSTRUCT_CLASS_INDEX, JSTaggedValue(jsProxyConstructClass)); - - SetConstant(ConstantIndex::JS_REALM_CLASS_INDEX, - factory->NewEcmaHClass(hClass, JSRealm::SIZE, JSType::JS_REALM)); + factory->NewSEcmaReadOnlyHClass(hClass, Program::SIZE, JSType::PROGRAM)); + SetConstant(ConstantIndex::IMPORT_ENTRY_CLASS_INDEX, + factory->NewSEcmaReadOnlyHClass(hClass, ImportEntry::SIZE, JSType::IMPORTENTRY_RECORD)); + SetConstant(ConstantIndex::LOCAL_EXPORT_ENTRY_CLASS_INDEX, + factory->NewSEcmaReadOnlyHClass(hClass, LocalExportEntry::SIZE, JSType::LOCAL_EXPORTENTRY_RECORD)); + SetConstant(ConstantIndex::INDIRECT_EXPORT_ENTRY_CLASS_INDEX, + factory->NewSEcmaReadOnlyHClass(hClass, IndirectExportEntry::SIZE, + JSType::INDIRECT_EXPORTENTRY_RECORD)); + SetConstant(ConstantIndex::STAR_EXPORT_ENTRY_CLASS_INDEX, + factory->NewSEcmaReadOnlyHClass(hClass, StarExportEntry::SIZE, JSType::STAR_EXPORTENTRY_RECORD)); + SetConstant(ConstantIndex::SOURCE_TEXT_MODULE_CLASS_INDEX, + factory->NewSEcmaReadOnlyHClass(hClass, SourceTextModule::SIZE, JSType::SOURCE_TEXT_MODULE_RECORD)); + SetConstant(ConstantIndex::RESOLVED_BINDING_CLASS_INDEX, + factory->NewSEcmaReadOnlyHClass(hClass, ResolvedBinding::SIZE, JSType::RESOLVEDBINDING_RECORD)); + SetConstant(ConstantIndex::RESOLVED_INDEX_BINDING_CLASS_INDEX, + factory->NewSEcmaReadOnlyHClass(hClass, ResolvedIndexBinding::SIZE, JSType::RESOLVEDINDEXBINDING_RECORD)); SetConstant(ConstantIndex::MACHINE_CODE_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::MACHINE_CODE_OBJECT)); + factory->NewSEcmaReadOnlyHClass(hClass, 0, JSType::MACHINE_CODE_OBJECT)); SetConstant(ConstantIndex::CLASS_INFO_EXTRACTOR_HCLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, ClassInfoExtractor::SIZE, - JSType::CLASS_INFO_EXTRACTOR)); + factory->NewSEcmaReadOnlyHClass(hClass, ClassInfoExtractor::SIZE, + JSType::CLASS_INFO_EXTRACTOR)); SetConstant(ConstantIndex::TS_OBJECT_TYPE_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, TSObjectType::SIZE, JSType::TS_OBJECT_TYPE)); + factory->NewSEcmaReadOnlyHClass(hClass, TSObjectType::SIZE, JSType::TS_OBJECT_TYPE)); SetConstant(ConstantIndex::TS_CLASS_TYPE_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, TSClassType::SIZE, JSType::TS_CLASS_TYPE)); + factory->NewSEcmaReadOnlyHClass(hClass, TSClassType::SIZE, JSType::TS_CLASS_TYPE)); SetConstant(ConstantIndex::TS_UNION_TYPE_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, TSUnionType::SIZE, JSType::TS_UNION_TYPE)); + factory->NewSEcmaReadOnlyHClass(hClass, TSUnionType::SIZE, JSType::TS_UNION_TYPE)); SetConstant(ConstantIndex::TS_INTERFACE_TYPE_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, TSInterfaceType::SIZE, JSType::TS_INTERFACE_TYPE)); + factory->NewSEcmaReadOnlyHClass(hClass, TSInterfaceType::SIZE, JSType::TS_INTERFACE_TYPE)); SetConstant(ConstantIndex::TS_CLASS_INSTANCE_TYPE_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, TSClassInstanceType::SIZE, - JSType::TS_CLASS_INSTANCE_TYPE)); + factory->NewSEcmaReadOnlyHClass(hClass, TSClassInstanceType::SIZE, + JSType::TS_CLASS_INSTANCE_TYPE)); SetConstant(ConstantIndex::TS_FUNCTION_TYPE_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, TSFunctionType::SIZE, JSType::TS_FUNCTION_TYPE)); + factory->NewSEcmaReadOnlyHClass(hClass, TSFunctionType::SIZE, JSType::TS_FUNCTION_TYPE)); SetConstant(ConstantIndex::TS_ARRAY_TYPE_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, TSArrayType::SIZE, JSType::TS_ARRAY_TYPE)); + factory->NewSEcmaReadOnlyHClass(hClass, TSArrayType::SIZE, JSType::TS_ARRAY_TYPE)); SetConstant(ConstantIndex::TS_ITERATOR_INSTANCE_TYPE_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, TSIteratorInstanceType::SIZE, - JSType::TS_ITERATOR_INSTANCE_TYPE)); + factory->NewSEcmaReadOnlyHClass(hClass, TSIteratorInstanceType::SIZE, + JSType::TS_ITERATOR_INSTANCE_TYPE)); SetConstant(ConstantIndex::TS_NAMESPACE_TYPE_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, TSNamespaceType::SIZE, JSType::TS_NAMESPACE_TYPE)); + factory->NewSEcmaReadOnlyHClass(hClass, TSNamespaceType::SIZE, JSType::TS_NAMESPACE_TYPE)); + SetConstant(ConstantIndex::CELL_RECORD_CLASS_INDEX, + factory->NewSEcmaReadOnlyHClass(hClass, CellRecord::SIZE, JSType::CELL_RECORD)); + SetConstant(ConstantIndex::METHOD_CLASS_INDEX, + factory->NewSEcmaReadOnlyHClass(hClass, Method::SIZE, JSType::METHOD)); + SetConstant(ConstantIndex::LINKED_NODE_CLASS_INDEX, + factory->NewSEcmaReadOnlyHClass(hClass, LinkedNode::SIZE, JSType::LINKED_NODE)); + SetConstant(ConstantIndex::RB_TREENODE_CLASS_INDEX, + factory->NewSEcmaReadOnlyHClass(hClass, RBTreeNode::SIZE, JSType::RB_TREENODE)); + SetConstant(ConstantIndex::CLASS_LITERAL_HCLASS_INDEX, + factory->NewSEcmaReadOnlyHClass(hClass, ClassLiteral::SIZE, JSType::CLASS_LITERAL)); + SetConstant(ConstantIndex::RESOLVED_RECORD_BINDING_CLASS_INDEX, + factory->NewSEcmaReadOnlyHClass(hClass, ResolvedRecordBinding::SIZE, JSType::RESOLVEDRECORDBINDING_RECORD)); +} + +void GlobalEnvConstants::InitSharedMiscellanious(JSThread *thread, ObjectFactory *factory) +{ + // Accessors + auto accessor = factory->NewSInternalAccessor(reinterpret_cast(JSFunction::PrototypeSetter), + reinterpret_cast(JSFunction::PrototypeGetter)); + SetConstant(ConstantIndex::FUNCTION_PROTOTYPE_ACCESSOR, accessor); + accessor = factory->NewSInternalAccessor(nullptr, reinterpret_cast(JSFunction::NameGetter)); + SetConstant(ConstantIndex::FUNCTION_NAME_ACCESSOR, accessor); + accessor = factory->NewSInternalAccessor(nullptr, reinterpret_cast(JSFunction::LengthGetter)); + SetConstant(ConstantIndex::FUNCTION_LENGTH_ACCESSOR, accessor); + accessor = factory->NewSInternalAccessor(reinterpret_cast(JSArray::LengthSetter), + reinterpret_cast(JSArray::LengthGetter)); + SetConstant(ConstantIndex::ARRAY_LENGTH_ACCESSOR, accessor); + // Specials + SetConstant(ConstantIndex::UNDEFINED_INDEX, JSTaggedValue::Undefined()); + SetConstant(ConstantIndex::NULL_INDEX, JSTaggedValue::Null()); + SetConstant(ConstantIndex::TRUE_INDEX, JSTaggedValue::True()); + SetConstant(ConstantIndex::FALSE_INDEX, JSTaggedValue::False()); + // Emptys + auto vm = thread->GetEcmaVM(); + SetConstant(ConstantIndex::EMPTY_STRING_OBJECT_INDEX, JSTaggedValue(EcmaStringAccessor::CreateEmptyString(vm))); + SetConstant(ConstantIndex::SINGLE_CHAR_TABLE_INDEX, SingleCharTable::CreateSingleCharTable(thread)); + SetConstant(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX, factory->NewSEmptyArray()); + SetConstant(ConstantIndex::EMPTY_MUTANT_ARRAY_OBJECT_INDEX, factory->NewSEmptyMutantArray()); + SetConstant(ConstantIndex::EMPTY_SLAYOUT_INFO_OBJECT_INDEX, factory->CreateSLayoutInfo(0)); +} + +void GlobalEnvConstants::InitRootsClasses(ObjectFactory *factory) +{ + JSHClass *hClass = JSHClass::Cast(GetHClassClass().GetTaggedObject()); + + SetConstant(ConstantIndex::JS_REALM_CLASS_INDEX, + factory->NewEcmaHClass(hClass, JSRealm::SIZE, JSType::JS_REALM)); SetConstant(ConstantIndex::JS_REGEXP_ITERATOR_CLASS_INDEX, factory->NewEcmaHClass(hClass, JSRegExpIterator::SIZE, JSType::JS_REG_EXP_ITERATOR)); SetConstant(ConstantIndex::JS_SET_ITERATOR_CLASS_INDEX, @@ -254,9 +300,8 @@ void GlobalEnvConstants::InitRootsClass(JSThread *thread, JSHClass *hClass) factory->NewEcmaHClass(hClass, JSMapIterator::SIZE, JSType::JS_MAP_ITERATOR, 0)); // 0: no inlined props SetConstant(ConstantIndex::JS_ARRAY_ITERATOR_CLASS_INDEX, factory->NewEcmaHClass(hClass, JSArrayIterator::SIZE, JSType::JS_ARRAY_ITERATOR, 0)); - SetConstant( - ConstantIndex::JS_API_ARRAYLIST_ITERATOR_CLASS_INDEX, - factory->NewEcmaHClass(hClass, JSAPIArrayListIterator::SIZE, JSType::JS_API_ARRAYLIST_ITERATOR)); + SetConstant(ConstantIndex::JS_API_ARRAYLIST_ITERATOR_CLASS_INDEX, + factory->NewEcmaHClass(hClass, JSAPIArrayListIterator::SIZE, JSType::JS_API_ARRAYLIST_ITERATOR)); SetConstant(ConstantIndex::JS_API_DEQUE_ITERATOR_CLASS_INDEX, factory->NewEcmaHClass(hClass, JSAPIDequeIterator::SIZE, JSType::JS_API_DEQUE_ITERATOR)); SetConstant(ConstantIndex::JS_API_LIGHTWEIGHTMAP_ITERATOR_CLASS_INDEX, @@ -265,14 +310,12 @@ void GlobalEnvConstants::InitRootsClass(JSThread *thread, JSHClass *hClass) SetConstant(ConstantIndex::JS_API_LIGHTWEIGHTSET_ITERATOR_CLASS_INDEX, factory->NewEcmaHClass(hClass, JSAPILightWeightSetIterator::SIZE, JSType::JS_API_LIGHT_WEIGHT_SET_ITERATOR)); - SetConstant( - ConstantIndex::JS_API_LINKED_LIST_ITERATOR_CLASS_INDEX, - factory->NewEcmaHClass(hClass, JSAPILinkedListIterator::SIZE, JSType::JS_API_LINKED_LIST_ITERATOR)); + SetConstant(ConstantIndex::JS_API_LINKED_LIST_ITERATOR_CLASS_INDEX, + factory->NewEcmaHClass(hClass, JSAPILinkedListIterator::SIZE, JSType::JS_API_LINKED_LIST_ITERATOR)); SetConstant(ConstantIndex::JS_API_LIST_ITERATOR_CLASS_INDEX, factory->NewEcmaHClass(hClass, JSAPIListIterator::SIZE, JSType::JS_API_LIST_ITERATOR)); - SetConstant( - ConstantIndex::JS_API_PLAIN_ARRAY_ITERATOR_CLASS_INDEX, - factory->NewEcmaHClass(hClass, JSAPIPlainArrayIterator::SIZE, JSType::JS_API_PLAIN_ARRAY_ITERATOR)); + SetConstant(ConstantIndex::JS_API_PLAIN_ARRAY_ITERATOR_CLASS_INDEX, + factory->NewEcmaHClass(hClass, JSAPIPlainArrayIterator::SIZE, JSType::JS_API_PLAIN_ARRAY_ITERATOR)); SetConstant(ConstantIndex::JS_API_QUEUE_ITERATOR_CLASS_INDEX, factory->NewEcmaHClass(hClass, JSAPIQueueIterator::SIZE, JSType::JS_API_QUEUE_ITERATOR)); SetConstant(ConstantIndex::JS_API_STACK_ITERATOR_CLASS_INDEX, @@ -287,62 +330,35 @@ void GlobalEnvConstants::InitRootsClass(JSThread *thread, JSHClass *hClass) factory->NewEcmaHClass(hClass, JSAPITreeMapIterator::SIZE, JSType::JS_API_TREEMAP_ITERATOR)); SetConstant(ConstantIndex::JS_API_TREE_SET_ITERATOR_CLASS_INDEX, factory->NewEcmaHClass(hClass, JSAPITreeSetIterator::SIZE, JSType::JS_API_TREESET_ITERATOR)); - SetConstant(ConstantIndex::LINKED_NODE_CLASS_INDEX, - factory->NewEcmaHClass(hClass, LinkedNode::SIZE, JSType::LINKED_NODE)); - SetConstant(ConstantIndex::RB_TREENODE_CLASS_INDEX, - factory->NewEcmaHClass(hClass, RBTreeNode::SIZE, JSType::RB_TREENODE)); - SetConstant(ConstantIndex::CELL_RECORD_CLASS_INDEX, - factory->NewEcmaReadOnlyHClass(hClass, CellRecord::SIZE, JSType::CELL_RECORD)); SetConstant(ConstantIndex::OBJECT_HCLASS_INDEX, factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT)); - SetConstant(ConstantIndex::METHOD_CLASS_INDEX, - factory->NewEcmaHClass(hClass, Method::SIZE, JSType::METHOD)); - SetConstant(ConstantIndex::CLASS_LITERAL_HCLASS_INDEX, - factory->NewEcmaHClass(hClass, ClassLiteral::SIZE, JSType::CLASS_LITERAL)); + SetConstant(ConstantIndex::CLASS_PROTOTYPE_HCLASS_INDEX, + factory->CreateDefaultClassPrototypeHClass(hClass)); + SetConstant(ConstantIndex::CLASS_CONSTRUCTOR_HCLASS_INDEX, + factory->CreateDefaultClassConstructorHClass(hClass)); + SetConstant(ConstantIndex::JS_PROXY_ORDINARY_CLASS_INDEX, + factory->NewEcmaHClass(hClass, JSProxy::SIZE, JSType::JS_PROXY)); + // JS_PROXY_CALLABLE_CLASS_INDEX + JSHClass *jsProxyCallableClass = *factory->NewEcmaHClass(hClass, JSProxy::SIZE, JSType::JS_PROXY); + jsProxyCallableClass->SetCallable(true); + SetConstant(ConstantIndex::JS_PROXY_CALLABLE_CLASS_INDEX, JSTaggedValue(jsProxyCallableClass)); + // JS_PROXY_CONSTRUCT_CLASS_INDEX + JSHClass *jsProxyConstructClass = *factory->NewEcmaHClass(hClass, JSProxy::SIZE, JSType::JS_PROXY); + jsProxyConstructClass->SetCallable(true); + jsProxyConstructClass->SetConstructor(true); + SetConstant(ConstantIndex::JS_PROXY_CONSTRUCT_CLASS_INDEX, JSTaggedValue(jsProxyConstructClass)); } -void GlobalEnvConstants::InitGlobalConstantSpecial(JSThread *thread) +void GlobalEnvConstants::InitMiscellanious(JSThread *thread, ObjectFactory *factory) { - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - // SPECIAL INIT - SetConstant(ConstantIndex::UNDEFINED_INDEX, JSTaggedValue::Undefined()); - SetConstant(ConstantIndex::NULL_INDEX, JSTaggedValue::Null()); - SetConstant(ConstantIndex::TRUE_INDEX, JSTaggedValue::True()); - SetConstant(ConstantIndex::FALSE_INDEX, JSTaggedValue::False()); - auto vm = thread->GetEcmaVM(); - SetConstant(ConstantIndex::EMPTY_STRING_OBJECT_INDEX, JSTaggedValue(EcmaStringAccessor::CreateEmptyString(vm))); - SetConstant(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX, factory->NewEmptyArray()); - SetConstant(ConstantIndex::EMPTY_MUTANT_ARRAY_OBJECT_INDEX, factory->NewEmptyMutantArray()); SetConstant(ConstantIndex::EMPTY_LAYOUT_INFO_OBJECT_INDEX, factory->CreateLayoutInfo(0)); SetConstant(ConstantIndex::EMPTY_TAGGED_QUEUE_OBJECT_INDEX, factory->NewTaggedQueue(0)); -} + SetConstant(ConstantIndex::DEFAULT_SUPERS_INDEX, + WeakVector::Create(thread, SubtypingOperator::DEFAULT_SUPERS_CAPACITY, MemSpaceType::NON_MOVABLE)); -// NOLINTNEXTLINE(readability-function-size) -void GlobalEnvConstants::InitGlobalConstant(JSThread *thread) -{ - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - /* non ECMA standard jsapi containers iterators, init to Undefined first */ + // non ECMA standard jsapi containers iterators, init to Undefined first InitJSAPIContainers(); -#define INIT_GLOBAL_ENV_CONSTANT_STRING(Name, Index, Token) \ - SetConstant(ConstantIndex::Index, factory->NewFromASCIINonMovable(Token)); - - GLOBAL_ENV_CONSTANT_STRING(INIT_GLOBAL_ENV_CONSTANT_STRING) -#undef INIT_GLOBAL_ENV_CONSTANT_STRING - - auto accessor = factory->NewInternalAccessor(reinterpret_cast(JSFunction::PrototypeSetter), - reinterpret_cast(JSFunction::PrototypeGetter)); - SetConstant(ConstantIndex::FUNCTION_PROTOTYPE_ACCESSOR, accessor); - accessor = factory->NewInternalAccessor(nullptr, reinterpret_cast(JSFunction::NameGetter)); - SetConstant(ConstantIndex::FUNCTION_NAME_ACCESSOR, accessor); - accessor = factory->NewInternalAccessor(nullptr, reinterpret_cast(JSFunction::LengthGetter)); - SetConstant(ConstantIndex::FUNCTION_LENGTH_ACCESSOR, accessor); - accessor = factory->NewInternalAccessor(reinterpret_cast(JSArray::LengthSetter), - reinterpret_cast(JSArray::LengthGetter)); - SetConstant(ConstantIndex::ARRAY_LENGTH_ACCESSOR, accessor); - SetConstant(ConstantIndex::CLASS_PROTOTYPE_HCLASS_INDEX, - factory->CreateDefaultClassPrototypeHClass(JSHClass::Cast(GetHClassClass().GetTaggedObject()))); - SetConstant(ConstantIndex::CLASS_CONSTRUCTOR_HCLASS_INDEX, - factory->CreateDefaultClassConstructorHClass(JSHClass::Cast(GetHClassClass().GetTaggedObject()))); + InitGlobalCaches(); } void GlobalEnvConstants::InitGlobalCaches() diff --git a/ecmascript/global_env_constants.h b/ecmascript/global_env_constants.h index 080482f1781d3032b17a8f599f027ebf3ce197ae..e68f19a87b9bdab3cc9c1b4f0a5371d0a6f176d6 100644 --- a/ecmascript/global_env_constants.h +++ b/ecmascript/global_env_constants.h @@ -30,7 +30,7 @@ class JSThread; class ObjectFactory; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define GLOBAL_ENV_CONSTANT_CLASS(V) \ +#define SHARED_GLOBAL_ENV_CONSTANT_CLASS(V) \ /* GC Root */ \ V(JSTaggedValue, HClassClass, HCLASS_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, FreeObjectWithNoneFieldClass, FREE_OBJECT_WITH_NONE_FIELD_CLASS_INDEX, ecma_roots_class) \ @@ -54,7 +54,6 @@ class ObjectFactory; V(JSTaggedValue, SymbolClass, SYMBOL_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, AccessorDataClass, ACCESSOR_DATA_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, InternalAccessorClass, INTERNAL_ACCESSOR_CLASS_INDEX, ecma_roots_class) \ - V(JSTaggedValue, JSProxyOrdinaryClass, JS_PROXY_ORDINARY_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, CompletionRecordClass, COMPLETION_RECORD_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, GeneratorContextClass, GENERATOR_CONTEST_INDEX, ecma_roots_class) \ V(JSTaggedValue, AsyncGeneratorRequestRecordClass, ASYNC_GENERATOR_REQUEST_CLASS_INDEX, ecma_roots_class) \ @@ -83,10 +82,6 @@ class ObjectFactory; V(JSTaggedValue, SourceTextModuleClass, SOURCE_TEXT_MODULE_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, ResolvedBindingClass, RESOLVED_BINDING_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, ResolvedIndexBindingClass, RESOLVED_INDEX_BINDING_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) \ - V(JSTaggedValue, JSRegExpClass, JS_REGEXP_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, MachineCodeClass, MACHINE_CODE_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, ClassInfoExtractorHClass, CLASS_INFO_EXTRACTOR_HCLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, TSObjectTypeClass, TS_OBJECT_TYPE_CLASS_INDEX, ecma_roots_class) \ @@ -98,6 +93,21 @@ class ObjectFactory; V(JSTaggedValue, TSArrayTypeClass, TS_ARRAY_TYPE_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, TSIteratorInstanceTypeClass, TS_ITERATOR_INSTANCE_TYPE_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, TSNamespaceTypeClass, TS_NAMESPACE_TYPE_CLASS_INDEX, ecma_roots_class) \ + V(JSTaggedValue, CellRecordClass, CELL_RECORD_CLASS_INDEX, ecma_roots_class) \ + V(JSTaggedValue, AOTLiteralInfoClass, AOT_LITERAL_INFO_CLASS_INDEX, ecma_roots_class) \ + V(JSTaggedValue, MethodClass, METHOD_CLASS_INDEX, ecma_roots_class) \ + V(JSTaggedValue, LinkedNode, LINKED_NODE_CLASS_INDEX, ecma_roots_class) \ + V(JSTaggedValue, RBTreeNode, RB_TREENODE_CLASS_INDEX, ecma_roots_class) \ + V(JSTaggedValue, ClassLiteralClass, CLASS_LITERAL_HCLASS_INDEX, ecma_roots_class) \ + V(JSTaggedValue, VTableClass, VTABLE_CLASS_INDEX, ecma_roots_class) \ + V(JSTaggedValue, ResolvedRecordBindingClass, RESOLVED_RECORD_BINDING_CLASS_INDEX, ecma_roots_class) \ + +#define GLOBAL_ENV_CONSTANT_CLASS(V) \ + 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) \ + V(JSTaggedValue, JSRegExpClass, JS_REGEXP_CLASS_INDEX, ecma_roots_class) \ + V(JSTaggedValue, JSProxyOrdinaryClass, JS_PROXY_ORDINARY_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, JSSetIteratorClass, JS_SET_ITERATOR_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, JSRegExpIteratorClass, JS_REGEXP_ITERATOR_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, JSMapIteratorClass, JS_MAP_ITERATOR_CLASS_INDEX, ecma_roots_class) \ @@ -116,19 +126,12 @@ class ObjectFactory; V(JSTaggedValue, JSAPIHashSetIteratorClass, JS_API_HASH_SET_ITERATOR_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, JSAPITreeMapIteratorClass, JS_API_TREE_MAP_ITERATOR_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, JSAPITreeSetIteratorClass, JS_API_TREE_SET_ITERATOR_CLASS_INDEX, ecma_roots_class) \ - V(JSTaggedValue, LinkedNode, LINKED_NODE_CLASS_INDEX, ecma_roots_class) \ - V(JSTaggedValue, RBTreeNode, RB_TREENODE_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, JSAPIIteratorFuncHClass, JS_API_ITERATOR_FUNC_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, JSAPIAsyncIteratorFuncHClass, JS_API_ASYNCITERATOR_FUNC_CLASS_INDEX, ecma_roots_class) \ - V(JSTaggedValue, CellRecordClass, CELL_RECORD_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, ObjectClass, OBJECT_HCLASS_INDEX, initial_object_hclass) \ V(JSTaggedValue, IteratorResultClass, ITERATOR_RESULT_CLASS, ecma_roots_class) \ - V(JSTaggedValue, MethodClass, METHOD_CLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, ClassPrototypeClass, CLASS_PROTOTYPE_HCLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, ClassConstructorClass, CLASS_CONSTRUCTOR_HCLASS_INDEX, ecma_roots_class) \ - V(JSTaggedValue, AOTLiteralInfoClass, AOT_LITERAL_INFO_CLASS_INDEX, ecma_roots_class) \ - V(JSTaggedValue, VTableClass, VTABLE_CLASS_INDEX, ecma_roots_class) \ - V(JSTaggedValue, ClassLiteralClass, CLASS_LITERAL_HCLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, ElementNoneClass, ELEMENT_NONE_HCLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, ElementHoleClass, ELEMENT_HOLE_HCLASS_INDEX, ecma_roots_class) \ V(JSTaggedValue, ElementIntClass, ELEMENT_INT_HCLASS_INDEX, ecma_roots_class) \ @@ -144,14 +147,7 @@ class ObjectFactory; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define GLOBAL_ENV_CONSTANT_SPECIAL(V) \ - V(JSTaggedValue, Undefined, UNDEFINED_INDEX, ecma_roots_special) \ - V(JSTaggedValue, Null, NULL_INDEX, ecma_roots_special) \ - V(JSTaggedValue, True, TRUE_INDEX, ecma_roots_special) \ - V(JSTaggedValue, False, FALSE_INDEX, ecma_roots_special) \ - V(JSTaggedValue, EmptyString, EMPTY_STRING_OBJECT_INDEX, ecma_roots_special) \ V(JSTaggedValue, EmptyLayoutInfo, EMPTY_LAYOUT_INFO_OBJECT_INDEX, ecma_roots_special) \ - V(JSTaggedValue, EmptyArray, EMPTY_ARRAY_OBJECT_INDEX, ecma_roots_special) \ - V(JSTaggedValue, EmptyMutantArray, EMPTY_MUTANT_ARRAY_OBJECT_INDEX, ecma_roots_special) \ V(JSTaggedValue, DefaultSupers, DEFAULT_SUPERS_INDEX, ecma_roots_special) \ V(JSTaggedValue, EmptyTaggedQueue, EMPTY_TAGGED_QUEUE_OBJECT_INDEX, ecma_roots_special) \ V(JSTaggedValue, UndefinedCompletionRecord, UNDEFINED_COMPLRTION_RECORD_INDEX, ecma_roots_special) \ @@ -187,7 +183,7 @@ class ObjectFactory; V(JSTaggedValue, StringFromCharCode, STRING_FROM_CHAR_CODE_INDEX, ecma_roots_special) // All of type JSTaggedValue -#define GLOBAL_ENV_CONSTANT_STRING(V) \ +#define SHARED_GLOBAL_ENV_CONSTANT_STRING(V) \ V(ConstructorString, CONSTRUCTOR_STRING_INDEX, "constructor") \ V(PrototypeString, PROTOTYPE_STRING_INDEX, "prototype") \ V(LengthString, LENGTH_STRING_INDEX, "length") \ @@ -517,12 +513,24 @@ class ObjectFactory; V(JSTaggedValue, LinkedListIteratorPrototype, LINKED_LIST_ITERATOR_PROTOTYPE_INDEX, LinkedListIterator) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define GLOBAL_ENV_CONSTANT_ACCESSOR(V) \ +#define SHARED_GLOBAL_ENV_CONSTANT_ACCESSOR(V) \ V(JSTaggedValue, FunctionPrototypeAccessor, FUNCTION_PROTOTYPE_ACCESSOR, ecma_roots_accessor) \ V(JSTaggedValue, FunctionNameAccessor, FUNCTION_NAME_ACCESSOR, ecma_roots_accessor) \ V(JSTaggedValue, FunctionLengthAccessor, FUNCTION_LENGTH_ACCESSOR, ecma_roots_accessor) \ V(JSTaggedValue, ArrayLengthAccessor, ARRAY_LENGTH_ACCESSOR, ecma_roots_accessor) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define SHARED_GLOBAL_ENV_CONSTANT_SPECIAL(V) \ + V(JSTaggedValue, Undefined, UNDEFINED_INDEX, ecma_roots_special) \ + V(JSTaggedValue, Null, NULL_INDEX, ecma_roots_special) \ + V(JSTaggedValue, True, TRUE_INDEX, ecma_roots_special) \ + V(JSTaggedValue, False, FALSE_INDEX, ecma_roots_special) \ + V(JSTaggedValue, EmptyString, EMPTY_STRING_OBJECT_INDEX, ecma_roots_special) \ + V(JSTaggedValue, SingleCharTable, SINGLE_CHAR_TABLE_INDEX, ecma_roots_special) \ + V(JSTaggedValue, EmptySLayoutInfo, EMPTY_SLAYOUT_INFO_OBJECT_INDEX, ecma_roots_special) \ + V(JSTaggedValue, EmptyArray, EMPTY_ARRAY_OBJECT_INDEX, ecma_roots_special) \ + V(JSTaggedValue, EmptyMutantArray, EMPTY_MUTANT_ARRAY_OBJECT_INDEX, ecma_roots_special) + #define GLOBAL_ENV_CACHES(V) \ V(JSTaggedValue, CachedJSCollatorLocales, CACHED_JSCOLLATOR_LOCALES_INDEX, cachedCollatorLocales) @@ -531,16 +539,18 @@ enum class ConstantIndex : size_t { // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define INDEX_FILTER_COMMON(Index) Index, #define INDEX_FILTER_WITH_TYPE(Type, Name, Index, Desc) INDEX_FILTER_COMMON(Index) +#define INDEX_FILTER_STRING(Name, Index, Token) INDEX_FILTER_COMMON(Index) + // Caveats: make sure shareds starts from 0 and placed before non-shareds. + SHARED_GLOBAL_ENV_CONSTANT_CLASS(INDEX_FILTER_WITH_TYPE) + SHARED_GLOBAL_ENV_CONSTANT_STRING(INDEX_FILTER_STRING) + SHARED_GLOBAL_ENV_CONSTANT_ACCESSOR(INDEX_FILTER_WITH_TYPE) + SHARED_GLOBAL_ENV_CONSTANT_SPECIAL(INDEX_FILTER_WITH_TYPE) GLOBAL_ENV_CONSTANT_CLASS(INDEX_FILTER_WITH_TYPE) GLOBAL_ENV_CONSTANT_SPECIAL(INDEX_FILTER_WITH_TYPE) GLOBAL_ENV_CONSTANT_CONSTANT(INDEX_FILTER_WITH_TYPE) - GLOBAL_ENV_CONSTANT_ACCESSOR(INDEX_FILTER_WITH_TYPE) GLOBAL_ENV_CACHES(INDEX_FILTER_WITH_TYPE) -#undef INDEX_FILTER_WITH_TYPE - -#define INDEX_FILTER_STRING(Name, Index, Token) INDEX_FILTER_COMMON(Index) - GLOBAL_ENV_CONSTANT_STRING(INDEX_FILTER_STRING) #undef INDEX_FILTER_STRING +#undef INDEX_FILTER_WITH_TYPE #undef INDEX_FILTER_COMMON CONSTANT_COUNT, @@ -548,6 +558,13 @@ enum class ConstantIndex : size_t { CONSTANT_BEGIN = 0, CONSTANT_END = CONSTANT_COUNT, + SHARED_BEGIN = HCLASS_CLASS_INDEX, + SHARED_END = EMPTY_MUTANT_ARRAY_OBJECT_INDEX, + + SHARED_HCLASS_BEGIN = HCLASS_CLASS_INDEX, + SHARED_HCLASS_END = VTABLE_CLASS_INDEX, + NON_SHARED_HCLASS_BEGIN = JS_PROXY_CALLABLE_CLASS_INDEX, + NON_SHARED_HCLASS_END = ELEMENT_HOLE_TAGGED_HCLASS_INDEX, READ_ONLY_CONSTANT_BEGIN = CONSTANT_BEGIN, READ_ONLY_CONSTANT_END = CONSTANT_END, JSAPI_CONTAINERS_BEGIN = ARRAYLIST_FUNCTION_INDEX, @@ -569,14 +586,7 @@ public: const JSTaggedValue *EndSlot() const; - void Init(JSThread *thread, JSHClass *hClass); - - void InitRootsClass(JSThread *thread, JSHClass *hClass); - void InitGlobalConstantSpecial(JSThread *thread); - - void InitGlobalConstant(JSThread *thread); - void InitGlobalCaches(); - void InitJSAPIContainers(); + void Init(JSThread *thread); void InitSpecialForSnapshot(); @@ -596,19 +606,18 @@ public: const Type Get##Name() const; \ const JSHandle GetHandled##Name() const; \ static size_t GetOffsetOf##Name(); - #define DECL_GET_WITH_TYPE(Type, Name, Index, Desc) DECL_GET_COMMON(Type, Name) +#define DECL_GET_STRING(Name, Index, Token) DECL_GET_COMMON(JSTaggedValue, Name) + SHARED_GLOBAL_ENV_CONSTANT_CLASS(DECL_GET_WITH_TYPE) + SHARED_GLOBAL_ENV_CONSTANT_STRING(DECL_GET_STRING) + SHARED_GLOBAL_ENV_CONSTANT_ACCESSOR(DECL_GET_WITH_TYPE) + SHARED_GLOBAL_ENV_CONSTANT_SPECIAL(DECL_GET_WITH_TYPE) GLOBAL_ENV_CONSTANT_CLASS(DECL_GET_WITH_TYPE) GLOBAL_ENV_CONSTANT_SPECIAL(DECL_GET_WITH_TYPE) GLOBAL_ENV_CONSTANT_CONSTANT(DECL_GET_WITH_TYPE) - GLOBAL_ENV_CONSTANT_ACCESSOR(DECL_GET_WITH_TYPE) GLOBAL_ENV_CACHES(DECL_GET_WITH_TYPE) -#undef DECL_GET_WITH_TYPE - -#define DECL_GET_STRING(Name, Index, Token) DECL_GET_COMMON(JSTaggedValue, Name) - GLOBAL_ENV_CONSTANT_STRING(DECL_GET_STRING) #undef DECL_GET_STRING - +#undef DECL_GET_WITH_TYPE #undef DECL_GET_COMMON void VisitRangeSlot(const RootRangeVisitor &visitor) @@ -672,6 +681,14 @@ public: JSTaggedValue::TaggedTypeSize() * static_cast(ConstantIndex::CONSTANT_COUNT); private: + void InitSharedStrings(ObjectFactory *factory); + void InitSharedRootsClasses(ObjectFactory *factory); + void InitSharedMiscellanious(JSThread *thread, ObjectFactory *factory); + void InitRootsClasses(ObjectFactory *factory); + void InitMiscellanious(JSThread *thread, ObjectFactory *factory); + void InitGlobalCaches(); + void InitJSAPIContainers(); + JSTaggedValue constants_[static_cast(ConstantIndex::CONSTANT_COUNT)]; // NOLINT(modernize-avoid-c-arrays) }; STATIC_ASSERT_EQ_ARCH(sizeof(GlobalEnvConstants), GlobalEnvConstants::SizeArch32, GlobalEnvConstants::SizeArch64); diff --git a/ecmascript/global_env_fields.h b/ecmascript/global_env_fields.h index 10e771c7c60ed3225c4ac88a4b266884d1114ce0..a494967a462f8785f1673060d53fdc42e0cea622 100644 --- a/ecmascript/global_env_fields.h +++ b/ecmascript/global_env_fields.h @@ -26,13 +26,8 @@ V(JSTaggedValue, ObjectFunctionClass, OBJECT_FUNCTION_CLASS_INDEX) \ V(JSTaggedValue, ObjectFunctionPrototype, OBJECT_FUNCTION_PROTOTYPE_INDEX) \ V(JSTaggedValue, ObjectFunctionPrototypeClass, OBJECT_FUNCTION_PROTOTYPE_CLASS_INDEX) \ - V(JSTaggedValue, SObjectFunction, SHARED_OBJECT_FUNCTION_INDEX) \ - V(JSTaggedValue, SObjectFunctionPrototype, SHARED_OBJECT_FUNCTION_PROTOTYPE_INDEX) \ V(JSTaggedValue, FunctionFunction, FUNCTION_FUNCTION_INDEX) \ V(JSTaggedValue, FunctionPrototype, FUNCTION_PROTOTYPE_INDEX) \ - V(JSTaggedValue, SFunctionFunction, SHARED_FUNCTION_FUNCTION_INDEX) \ - V(JSTaggedValue, SFunctionPrototype, SHARED_FUNCTION_PROTOTYPE_INDEX) \ - V(JSTaggedValue, SConstructorClass, SHARED_CONSTRUCTOR_CLASS_INDEX) \ V(JSTaggedValue, NumberFunction, NUMBER_FUNCTION_INDEX) \ V(JSTaggedValue, NumberPrototype, NUMBER_PROTOTYPE_INDEX) \ V(JSTaggedValue, BigIntFunction, BIGINT_FUNCTION_INDEX) \ @@ -189,7 +184,6 @@ V(JSTaggedValue, FunctionClassWithoutProto, FUNCTION_CLASS_WITHOUT_PROTO) \ V(JSTaggedValue, FunctionClassWithoutName, FUNCTION_CLASS_WITHOUT_NAME) \ V(JSTaggedValue, BoundFunctionClass, BOUND_FUNCTION_CLASS) \ - V(JSTaggedValue, SFunctionClassWithoutProto, SHARED_FUNCTION_CLASS_WITHOUT_PROTO) \ V(JSTaggedValue, ArgumentsClass, ARGUMENTS_CLASS) \ V(JSTaggedValue, ArgumentsCallerAccessor, ARGUMENTS_CALLER_ACCESSOR) \ V(JSTaggedValue, ArgumentsCalleeAccessor, ARGUMENTS_CALLEE_ACCESSOR) \ @@ -215,7 +209,6 @@ V(JSTaggedValue, SpecificTypedArrayFunctionClass, SPERCIFIC_TYPED_ARRAY_FUNCTION_CLASS) \ V(JSTaggedValue, ConstructorFunctionClass, CONSTRUCTOR_FUNCTION_CLASS) \ V(JSTaggedValue, NormalFunctionClass, NORMAL_FUNCTION_CLASS) \ - V(JSTaggedValue, SNormalFunctionClass, SHARED_NORMAL_FUNCTION_CLASS) \ V(JSTaggedValue, JSIntlBoundFunctionClass, JS_INTL_BOUND_FUNCTION_CLASS) \ V(JSTaggedValue, NumberFormatLocales, NUMBER_FORMAT_LOCALES_INDEX) \ V(JSTaggedValue, DateTimeFormatLocales, DATE_TIMEFORMAT_LOCALES_INDEX) \ @@ -240,7 +233,18 @@ V(JSTaggedValue, IteratorSymbol, ITERATOR_SYMBOL_INDEX) \ V(JSTaggedValue, SpeciesSymbol, SPECIES_SYMBOL_INDEX) +#define GLOBAL_ENV_SHARED_FIELDS(V) \ + V(JSTaggedValue, SObjectFunction, SHARED_OBJECT_FUNCTION_INDEX) \ + V(JSTaggedValue, SObjectFunctionPrototype, SHARED_OBJECT_FUNCTION_PROTOTYPE_INDEX) \ + V(JSTaggedValue, SFunctionFunction, SHARED_FUNCTION_FUNCTION_INDEX) \ + V(JSTaggedValue, SFunctionPrototype, SHARED_FUNCTION_PROTOTYPE_INDEX) \ + V(JSTaggedValue, SConstructorClass, SHARED_CONSTRUCTOR_CLASS_INDEX) \ + V(JSTaggedValue, SFunctionClassWithoutProto, SHARED_FUNCTION_CLASS_WITHOUT_PROTO) \ + V(JSTaggedValue, SFunctionClassWithoutAccessor, SHARED_FUNCTION_CLASS_WITHOUT_ACCESSOR) \ + V(JSTaggedValue, SNormalFunctionClass, SHARED_NORMAL_FUNCTION_CLASS) + #define GLOBAL_ENV_FIELDS(V) \ + GLOBAL_ENV_SHARED_FIELDS(V) \ GLOBAL_ENV_COMMON_FIELDS(V) \ GLOBAL_ENV_DETECTOR_SYMBOL_FIELDS(V) \ GLOBAL_ENV_DETECTOR_FIELDS(V) diff --git a/ecmascript/ic/ic_handler.h b/ecmascript/ic/ic_handler.h index c863dedbc2c8851979f341fbc9f319a8d17453d5..d1d5c8c5c5e7a62349c3ef076960c959b457e761 100644 --- a/ecmascript/ic/ic_handler.h +++ b/ecmascript/ic/ic_handler.h @@ -67,7 +67,7 @@ public: using SWholeKindBit = KindBit; static_assert(SKindBit::START_BIT == SWholeKindBit::START_BIT); static_assert(SSharedBit::Mask() || SKindBit::Mask() == KindBit::Mask()); - using STrackTypeBit = AttrIndexBit::NextField; + using SFieldTypeBit = AttrIndexBit::NextField; static_assert(static_cast(StoreHandlerKind::S_TOTAL_KINDS) <= (1 << STORE_KIND_BIT_LENGTH)); HandlerBase() = default; @@ -78,9 +78,9 @@ public: return AccessorBit::Get(handler); } - static inline TrackType GetTrackType(uint32_t handler) + static inline SharedFieldType GetFieldType(uint32_t handler) { - return static_cast(STrackTypeBit::Get(handler)); + return static_cast(SFieldTypeBit::Get(handler)); } static inline bool IsNonExist(uint32_t handler) @@ -287,9 +287,9 @@ public: SSharedBit::Set(op.GetReceiver()->IsJSShared(), &handler); TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject()); if (!array->IsDictionaryMode()) { - STrackTypeBit::Set(static_cast(op.GetAttr().GetTrackType()), &handler); + SFieldTypeBit::Set(op.GetAttr().GetSharedFieldType(), &handler); } else { - STrackTypeBit::Set(static_cast(op.GetAttr().GetDictTrackType()), &handler); + SFieldTypeBit::Set(op.GetAttr().GetDictSharedFieldType(), &handler); } if (op.IsElement()) { return StoreElement(thread, op.GetReceiver(), handler); @@ -384,8 +384,11 @@ public: if (op.IsFound()) { handler->SetHolder(thread, op.GetHolder()); } - auto result = JSHClass::EnableProtoChangeMarker(thread, hclass); - handler->SetProtoCell(thread, result); + // ShareToLocal is prohibited + if (!hclass->IsJSShared()) { + auto result = JSHClass::EnableProtoChangeMarker(thread, hclass); + handler->SetProtoCell(thread, result); + } return JSHandle::Cast(handler); } static inline JSHandle StorePrototype(const JSThread *thread, const ObjectOperator &op, @@ -396,8 +399,11 @@ public: JSHandle handlerInfo = StoreHandler::StoreProperty(thread, op); handler->SetHandlerInfo(thread, handlerInfo); handler->SetHolder(thread, op.GetHolder()); - auto result = JSHClass::EnableProtoChangeMarker(thread, hclass); - handler->SetProtoCell(thread, result); + // ShareToLocal is prohibited + if (!hclass->IsJSShared()) { + auto result = JSHClass::EnableProtoChangeMarker(thread, hclass); + handler->SetProtoCell(thread, result); + } return JSHandle::Cast(handler); } diff --git a/ecmascript/ic/ic_runtime_stub-inl.h b/ecmascript/ic/ic_runtime_stub-inl.h index 10a2f9e0c44a7b0f3b436a4231e3764234aadbfd..4e47d953879f785214c9def103aef4cf736ac0e7 100644 --- a/ecmascript/ic/ic_runtime_stub-inl.h +++ b/ecmascript/ic/ic_runtime_stub-inl.h @@ -227,8 +227,8 @@ ARK_INLINE JSTaggedValue ICRuntimeStub::StoreICWithHandler(JSThread *thread, JST } bool isShared = HandlerBase::IsStoreShared(handlerInfo); if (isShared) { - TrackType trackType { HandlerBase::GetTrackType(handlerInfo) }; - if (!ClassHelper::MatchTrackType(trackType, value)) { + SharedFieldType fieldType { HandlerBase::GetFieldType(handlerInfo) }; + if (!ClassHelper::MatchFieldType(fieldType, value)) { THROW_TYPE_ERROR_AND_RETURN((thread), GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty), JSTaggedValue::Exception()); } @@ -265,14 +265,16 @@ JSTaggedValue ICRuntimeStub::StorePrototype(JSThread *thread, JSTaggedValue rece INTERPRETER_TRACE(thread, StorePrototype); ASSERT(handler.IsPrototypeHandler()); PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject()); - auto cellValue = prototypeHandler->GetProtoCell(); - if (cellValue.IsNull()) { - return JSTaggedValue::Hole(); - } - ASSERT(cellValue.IsProtoChangeMarker()); - ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject()); - if (cell->GetHasChanged()) { - return JSTaggedValue::Hole(); + if (!receiver.IsJSShared()) { + auto cellValue = prototypeHandler->GetProtoCell(); + if (cellValue.IsNull()) { + return JSTaggedValue::Hole(); + } + ASSERT(cellValue.IsProtoChangeMarker()); + ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject()); + if (cell->GetHasChanged()) { + return JSTaggedValue::Hole(); + } } auto holder = prototypeHandler->GetHolder(); JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo(); @@ -361,6 +363,7 @@ JSTaggedValue ICRuntimeStub::StoreTransWithProto(JSThread *thread, JSObject *rec { INTERPRETER_TRACE(thread, StoreTransWithProto); ASSERT(handler.IsTransWithProtoHandler()); + ASSERT(!receiver->GetClass()->IsJSShared()); TransWithProtoHandler *transWithProtoHandler = TransWithProtoHandler::Cast(handler.GetTaggedObject()); auto cellValue = transWithProtoHandler->GetProtoCell(); ASSERT(cellValue.IsProtoChangeMarker()); @@ -425,11 +428,13 @@ JSTaggedValue ICRuntimeStub::LoadPrototype(JSThread *thread, JSTaggedValue recei INTERPRETER_TRACE(thread, LoadPrototype); ASSERT(handler.IsPrototypeHandler()); PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject()); - auto cellValue = prototypeHandler->GetProtoCell(); - ASSERT(cellValue.IsProtoChangeMarker()); - ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject()); - if (cell->GetHasChanged()) { - return JSTaggedValue::Hole(); + if (!receiver.IsJSShared()) { + auto cellValue = prototypeHandler->GetProtoCell(); + ASSERT(cellValue.IsProtoChangeMarker()); + ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject()); + if (cell->GetHasChanged()) { + return JSTaggedValue::Hole(); + } } auto holder = prototypeHandler->GetHolder(); JSTaggedValue handlerInfo = prototypeHandler->GetHandlerInfo(); @@ -577,6 +582,10 @@ JSTaggedValue ICRuntimeStub::StoreElement(JSThread *thread, JSObject *receiver, elements->Set(thread, elementIndex, valueHandle); } else { ASSERT(handler.IsPrototypeHandler()); + if (receiver->GetClass()->IsJSShared()) { + THROW_TYPE_ERROR_AND_RETURN(thread, + GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty), JSTaggedValue::Exception()); + } PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(handler.GetTaggedObject()); auto cellValue = prototypeHandler->GetProtoCell(); ASSERT(cellValue.IsProtoChangeMarker()); diff --git a/ecmascript/interpreter/fast_runtime_stub-inl.h b/ecmascript/interpreter/fast_runtime_stub-inl.h index d69c0784b41644d4090a222eff01d920d954616f..d80f467950ab1be00b043b1de292eb5ab2a42117 100644 --- a/ecmascript/interpreter/fast_runtime_stub-inl.h +++ b/ecmascript/interpreter/fast_runtime_stub-inl.h @@ -289,7 +289,7 @@ JSTaggedValue FastRuntimeStub::NewThisObject(JSThread *thread, JSTaggedValue cto Method *method = Method::Cast(ctorHandle->GetMethod().GetTaggedObject()); state->function = ctorHandle.GetTaggedValue(); state->constpool = method->GetConstantPool(); - state->profileTypeInfo = method->GetProfileTypeInfo(); + state->profileTypeInfo = ctorHandle->GetProfileTypeInfo(); state->env = ctorHandle->GetLexicalEnv(); return obj.GetTaggedValue(); diff --git a/ecmascript/interpreter/interpreter-inl.h b/ecmascript/interpreter/interpreter-inl.h index b3d5d85e5e1bc94e1f67d5f31a1c7d5564a83e69..dac406ff3a38f1ad04cceec3fd217c28e3470604 100644 --- a/ecmascript/interpreter/interpreter-inl.h +++ b/ecmascript/interpreter/interpreter-inl.h @@ -39,6 +39,7 @@ #include "ecmascript/runtime_call_id.h" #include "ecmascript/stubs/runtime_stubs.h" #include "ecmascript/template_string.h" +#include "ecmascript/checkpoint/thread_state_transition.h" #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h" #endif @@ -141,7 +142,7 @@ using CommonStubCSigns = kungfu::CommonStubCSigns; #define SET_ACC(val) (acc = val) // NOLINT(cppcoreguidelines-macro-usage) #define GET_METHOD_FROM_CACHE(index) \ - ConstantPool::GetMethodFromCache(thread, constpool, module, index) + ConstantPool::GetMethodFromCache(thread, constpool, index) #define GET_STR_FROM_CACHE(index) \ ConstantPool::GetStringFromCache(thread, constpool, index) @@ -616,6 +617,7 @@ using CommonStubCSigns = kungfu::CommonStubCSigns; JSTaggedValue EcmaInterpreter::ExecuteNative(EcmaRuntimeCallInfo *info) { JSThread *thread = info->GetThread(); + ASSERT(thread->IsInManagedState()); INTERPRETER_TRACE(thread, ExecuteNative); // current is entry frame. @@ -634,8 +636,11 @@ JSTaggedValue EcmaInterpreter::ExecuteNative(EcmaRuntimeCallInfo *info) ECMAObject *callTarget = reinterpret_cast(info->GetFunctionValue().GetTaggedObject()); Method *method = callTarget->GetCallTarget(); LOG_INST() << "Entry: Runtime Call."; - JSTaggedValue tagged = - reinterpret_cast(const_cast(method->GetNativePointer()))(info); + JSTaggedValue tagged; + { + ASSERT(thread == JSThread::GetCurrent()); + tagged = reinterpret_cast(const_cast(method->GetNativePointer()))(info); + } LOG_INST() << "Exit: Runtime Call."; InterpretedEntryFrame *entryState = GET_ENTRY_FRAME(sp); @@ -652,6 +657,7 @@ JSTaggedValue EcmaInterpreter::Execute(EcmaRuntimeCallInfo *info) } JSThread *thread = info->GetThread(); + ASSERT(thread->IsInManagedState()); INTERPRETER_TRACE(thread, Execute); // check stack overflow before re-enter interpreter STACK_LIMIT_CHECK(thread, thread->GetException()); @@ -740,7 +746,7 @@ JSTaggedValue EcmaInterpreter::Execute(EcmaRuntimeCallInfo *info) state->constpool = method->GetConstantPool(); JSHandle thisFunc = JSHandle::Cast(func); - state->profileTypeInfo = method->GetProfileTypeInfo(); + state->profileTypeInfo = thisFunc->GetProfileTypeInfo(); state->base.prev = sp; state->base.type = FrameType::INTERPRETER_FRAME; state->env = thisFunc->GetLexicalEnv(); @@ -822,7 +828,7 @@ JSTaggedValue EcmaInterpreter::GeneratorReEnterInterpreter(JSThread *thread, JSH state->function = func.GetTaggedValue(); state->thisObj = context->GetThis(); state->constpool = method->GetConstantPool(); - state->profileTypeInfo = method->GetProfileTypeInfo(); + state->profileTypeInfo = func->GetProfileTypeInfo(); state->acc = context->GetAcc(); state->base.prev = breakSp; state->base.type = FrameType::INTERPRETER_FRAME; @@ -980,7 +986,8 @@ std::pair EcmaInterpreter::GetCurrentEntryPoint(JS if (method->IsNativeWithCallField()) { continue; } - JSHandle module(thread, method->GetModule()); + JSTaggedValue func = frameHandler.GetFunction(); + JSHandle module(thread, JSFunction::Cast(func.GetTaggedObject())->GetModule()); if (module->IsSourceTextModule()) { SourceTextModule *sourceTextModule = SourceTextModule::Cast(module->GetTaggedObject()); @@ -1012,7 +1019,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t constexpr size_t numOps = 0x100; constexpr size_t numThrowOps = 10; constexpr size_t numWideOps = 20; - constexpr size_t numCallRuntimeOps = 9; + constexpr size_t numCallRuntimeOps = 11; constexpr size_t numDeprecatedOps = 47; static std::array instDispatchTable { @@ -1403,7 +1410,8 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t setVregsAndFrameNotNative: startReg--; deprecatedSetVregsAndFrameNotNative: { - if (JSFunction::Cast(funcObject)->IsClassConstructor()) { + JSFunction *func = JSFunction::Cast(funcObject); + if (func->IsClassConstructor()) { { [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle error = @@ -1449,8 +1457,8 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t state->thisObj = JSTaggedValue(thisObj); state->acc = JSTaggedValue::Hole(); state->constpool = methodHandle->GetConstantPool(); - state->profileTypeInfo = methodHandle->GetProfileTypeInfo(); - JSTaggedValue env = JSFunction::Cast(funcObject)->GetLexicalEnv(); + state->profileTypeInfo = func->GetProfileTypeInfo(); + JSTaggedValue env = func->GetLexicalEnv(); state->env = env; thread->SetCurrentSPFrame(newSp); LOG_INST() << "Entry: Runtime Call " << std::hex << reinterpret_cast(sp) << " " @@ -3310,7 +3318,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t state->function = superCtor; state->constpool = methodHandle->GetConstantPool(); - state->profileTypeInfo = methodHandle->GetProfileTypeInfo(); + state->profileTypeInfo = superCtorFunc->GetProfileTypeInfo(); state->env = superCtorFunc->GetLexicalEnv(); } @@ -3446,7 +3454,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t state->function = superCtor; state->constpool = methodHandle->GetConstantPool(); - state->profileTypeInfo = methodHandle->GetProfileTypeInfo(); + state->profileTypeInfo = superCtorFunc->GetProfileTypeInfo(); state->env = superCtorFunc->GetLexicalEnv(); } @@ -3582,7 +3590,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t state->function = superCtor; state->constpool = methodHandle->GetConstantPool(); - state->profileTypeInfo = methodHandle->GetProfileTypeInfo(); + state->profileTypeInfo = superCtorFunc->GetProfileTypeInfo(); state->env = superCtorFunc->GetLexicalEnv(); } @@ -3718,7 +3726,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t state->function = superCtor; state->constpool = methodHandle->GetConstantPool(); - state->profileTypeInfo = methodHandle->GetProfileTypeInfo(); + state->profileTypeInfo = superCtorFunc->GetProfileTypeInfo(); state->env = superCtorFunc->GetLexicalEnv(); } @@ -3776,7 +3784,6 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t << " imm:" << imm; SAVE_ACC(); auto constpool = GetConstantPool(sp); - auto module = GetEcmaModule(sp); JSObject *result = JSObject::Cast(GET_METHOD_FROM_CACHE(imm).GetTaggedObject()); RESTORE_ACC(); JSTaggedValue env = GET_ACC(); @@ -4090,7 +4097,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t state->function = ctor; state->constpool = methodHandle->GetConstantPool(); - state->profileTypeInfo = methodHandle->GetProfileTypeInfo(); + state->profileTypeInfo = ctorFunc->GetProfileTypeInfo(); state->env = ctorFunc->GetLexicalEnv(); } @@ -4227,7 +4234,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t state->function = ctor; state->constpool = methodHandle->GetConstantPool(); - state->profileTypeInfo = methodHandle->GetProfileTypeInfo(); + state->profileTypeInfo = ctorFunc->GetProfileTypeInfo(); state->env = ctorFunc->GetLexicalEnv(); } @@ -4363,7 +4370,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t state->function = ctor; state->constpool = methodHandle->GetConstantPool(); - state->profileTypeInfo = methodHandle->GetProfileTypeInfo(); + state->profileTypeInfo = ctorFunc->GetProfileTypeInfo(); state->env = ctorFunc->GetLexicalEnv(); } @@ -4578,7 +4585,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t uint16_t imm = READ_INST_16_1(); LOG_INST() << "intrinsics::createarraywithbuffer" << " imm:" << imm; - auto constpool = GetConstantPool(sp); + auto constpool = GetUnsharedConstpool(thread, sp); JSArray *result = JSArray::Cast(GET_LITERA_FROM_CACHE(imm, ConstPoolType::ARRAY_LITERAL, GetEcmaModule(sp)).GetTaggedObject()); SAVE_PC(); @@ -4591,7 +4598,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t uint16_t imm = READ_INST_16_2(); LOG_INST() << "intrinsics::createarraywithbuffer" << " imm:" << imm; - auto constpool = GetConstantPool(sp); + auto constpool = GetUnsharedConstpool(thread, sp); JSArray *result = JSArray::Cast(GET_LITERA_FROM_CACHE(imm, ConstPoolType::ARRAY_LITERAL, GetEcmaModule(sp)).GetTaggedObject()); SAVE_PC(); @@ -4605,7 +4612,6 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t LOG_INST() << "intrinsics::createarraywithbuffer" << " imm:" << imm; auto constpool = GetConstantPool(sp); - auto module = GetEcmaModule(sp); JSArray *result = JSArray::Cast(GET_METHOD_FROM_CACHE(imm).GetTaggedObject()); SAVE_PC(); JSTaggedValue res = SlowRuntimeStub::CreateArrayWithBuffer(thread, factory, result); @@ -4617,7 +4623,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t uint16_t imm = READ_INST_16_1(); LOG_INST() << "intrinsics::createobjectwithbuffer" << " imm:" << imm; - auto constpool = GetConstantPool(sp); + auto constpool = GetUnsharedConstpool(thread, sp); JSObject *result = JSObject::Cast(GET_LITERA_FROM_CACHE(imm, ConstPoolType::OBJECT_LITERAL, GetEcmaModule(sp)).GetTaggedObject()); SAVE_PC(); @@ -4631,7 +4637,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t uint16_t imm = READ_INST_16_2(); LOG_INST() << "intrinsics::createobjectwithbuffer" << " imm:" << imm; - auto constpool = GetConstantPool(sp); + auto constpool = GetUnsharedConstpool(thread, sp); JSObject *result = JSObject::Cast(GET_LITERA_FROM_CACHE(imm, ConstPoolType::OBJECT_LITERAL, GetEcmaModule(sp)).GetTaggedObject()); SAVE_PC(); @@ -4646,7 +4652,6 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t LOG_INST() << "intrinsics::createobjectwithbuffer" << " imm:" << imm; auto constpool = GetConstantPool(sp); - auto module = GetEcmaModule(sp); JSObject *result = JSObject::Cast(GET_METHOD_FROM_CACHE(imm).GetTaggedObject()); SAVE_PC(); @@ -4914,12 +4919,11 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t LOG_INST() << "intrinsics::definefunc length: " << length; auto constpool = GetConstantPool(sp); - auto module = GetEcmaModule(sp); InterpretedFrame *state = GET_FRAME(sp); JSTaggedValue envHandle = state->env; JSFunction *currentFunc = JSFunction::Cast((GET_FRAME(sp)->function).GetTaggedObject()); - auto res = SlowRuntimeStub::DefineFunc(thread, constpool, methodId, module, + auto res = SlowRuntimeStub::DefineFunc(thread, constpool, methodId, currentFunc->GetModule(), length, envHandle, currentFunc->GetHomeObject()); JSFunction *jsFunc = JSFunction::Cast(res.GetTaggedObject()); @@ -4932,12 +4936,11 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t LOG_INST() << "intrinsics::definefunc length: " << length; auto constpool = GetConstantPool(sp); - auto module = GetEcmaModule(sp); InterpretedFrame *state = GET_FRAME(sp); JSTaggedValue envHandle = state->env; JSFunction *currentFunc = JSFunction::Cast((GET_FRAME(sp)->function).GetTaggedObject()); - auto res = SlowRuntimeStub::DefineFunc(thread, constpool, methodId, module, + auto res = SlowRuntimeStub::DefineFunc(thread, constpool, methodId, currentFunc->GetModule(), length, envHandle, currentFunc->GetHomeObject()); JSFunction *jsFunc = JSFunction::Cast(res.GetTaggedObject()); @@ -4950,7 +4953,6 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t LOG_INST() << "intrinsics::definemethod length: " << length; SAVE_ACC(); auto constpool = GetConstantPool(sp); - auto module = GetEcmaModule(sp); Method *method = Method::Cast(GET_METHOD_FROM_CACHE(methodId).GetTaggedObject()); ASSERT(method != nullptr); RESTORE_ACC(); @@ -4960,7 +4962,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t InterpretedFrame *state = GET_FRAME(sp); JSTaggedValue taggedCurEnv = state->env; - auto res = SlowRuntimeStub::DefineMethod(thread, method, homeObject, length, taggedCurEnv); + auto res = SlowRuntimeStub::DefineMethod(thread, method, homeObject, length, taggedCurEnv, GetEcmaModule(sp)); INTERPRETER_RETURN_IF_ABRUPT(res); JSFunction *result = JSFunction::Cast(res.GetTaggedObject()); SET_ACC(JSTaggedValue(result)); @@ -4973,7 +4975,6 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t LOG_INST() << "intrinsics::definemethod length: " << length; SAVE_ACC(); auto constpool = GetConstantPool(sp); - auto module = GetEcmaModule(sp); Method *method = Method::Cast(GET_METHOD_FROM_CACHE(methodId).GetTaggedObject()); ASSERT(method != nullptr); RESTORE_ACC(); @@ -4983,7 +4984,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t InterpretedFrame *state = GET_FRAME(sp); JSTaggedValue taggedCurEnv = state->env; - auto res = SlowRuntimeStub::DefineMethod(thread, method, homeObject, length, taggedCurEnv); + auto res = SlowRuntimeStub::DefineMethod(thread, method, homeObject, length, taggedCurEnv, GetEcmaModule(sp)); INTERPRETER_RETURN_IF_ABRUPT(res); JSFunction *result = JSFunction::Cast(res.GetTaggedObject()); SET_ACC(JSTaggedValue(result)); @@ -7521,6 +7522,26 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t SET_ACC(res); DISPATCH(CALLRUNTIME_LDSENDABLECLASS_PREF_IMM16); } + HANDLE_OPCODE(CALLRUNTIME_LDSENDABLEEXTERNALMODULEVAR_PREF_IMM8) { + int32_t index = READ_INST_8_1(); + JSTaggedValue funcObj = GetFunction(sp); + LOG_INST() << "intrinsics::ldsendableexternalmodulevar index:" << index; + + JSTaggedValue moduleVar = SlowRuntimeStub::LdSendableExternalModuleVar(thread, index, funcObj); + INTERPRETER_RETURN_IF_ABRUPT(moduleVar); + SET_ACC(moduleVar); + DISPATCH(CALLRUNTIME_LDSENDABLEEXTERNALMODULEVAR_PREF_IMM8); + } + HANDLE_OPCODE(CALLRUNTIME_WIDELDSENDABLEEXTERNALMODULEVAR_PREF_IMM16) { + int32_t index = READ_INST_16_1(); + JSTaggedValue funcObj = GetFunction(sp); + LOG_INST() << "intrinsics::ldsendableexternalmodulevar index:" << index; + + JSTaggedValue moduleVar = SlowRuntimeStub::LdSendableExternalModuleVar(thread, index, funcObj); + INTERPRETER_RETURN_IF_ABRUPT(moduleVar); + SET_ACC(moduleVar); + DISPATCH(CALLRUNTIME_WIDELDSENDABLEEXTERNALMODULEVAR_PREF_IMM16); + } #include "templates/debugger_instruction_handler.inl" } #endif @@ -7629,7 +7650,7 @@ JSTaggedValue EcmaInterpreter::GetEcmaModule(JSTaggedType *sp) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) JSFunction *currentFunc = JSFunction::Cast((GET_FRAME(sp)->function).GetTaggedObject()); - return currentFunc->GetCallTarget()->GetModule(); + return currentFunc->GetModule(); } JSTaggedValue EcmaInterpreter::GetConstantPool(JSTaggedType *sp) @@ -7639,6 +7660,12 @@ JSTaggedValue EcmaInterpreter::GetConstantPool(JSTaggedType *sp) return state->constpool; } +JSTaggedValue EcmaInterpreter::GetUnsharedConstpool(JSThread* thread, JSTaggedType *sp) +{ + InterpretedFrame *state = reinterpret_cast(sp) - 1; + return thread->GetCurrentEcmaContext()->FindUnsharedConstpool(state->constpool); +} + bool EcmaInterpreter::UpdateHotnessCounter(JSThread* thread, JSTaggedType *sp, JSTaggedValue acc, int32_t offset) { InterpretedFrame *state = GET_FRAME(sp); @@ -7658,7 +7685,7 @@ bool EcmaInterpreter::UpdateHotnessCounter(JSThread* thread, JSTaggedType *sp, J auto thisFunc = JSFunction::Cast(state->function.GetTaggedObject()); method = thisFunc->GetCallTarget(); // for CheckSafepoint, method need retrieve. method->SetHotnessCounter(EcmaInterpreter::METHOD_HOTNESS_THRESHOLD); - auto res = SlowRuntimeStub::NotifyInlineCache(thread, method); + auto res = SlowRuntimeStub::NotifyInlineCache(thread, thisFunc); state->profileTypeInfo = res; return true; } else { diff --git a/ecmascript/interpreter/interpreter.h b/ecmascript/interpreter/interpreter.h index 878b6185d71ec986b5ce8454996b861821faf97e..30b50642e7108a596d013ce8b0a6e22d13e4d615 100644 --- a/ecmascript/interpreter/interpreter.h +++ b/ecmascript/interpreter/interpreter.h @@ -60,6 +60,7 @@ public: static inline JSTaggedValue GetRuntimeProfileTypeInfo(JSTaggedType *sp); static inline JSTaggedValue GetConstantPool(JSTaggedType *sp); + static inline JSTaggedValue GetUnsharedConstpool(JSThread* thread, JSTaggedType *sp); static inline JSTaggedValue GetEcmaModule(JSTaggedType *sp); static inline bool UpdateHotnessCounter(JSThread* thread, JSTaggedType *sp, JSTaggedValue acc, int32_t offset); static inline void NotifyBytecodePcChanged(JSThread *thread); diff --git a/ecmascript/interpreter/interpreter_assembly.cpp b/ecmascript/interpreter/interpreter_assembly.cpp index 0e2e1149de2c084cada4d10e4d12f7c121e8afa2..a3ae900f12f75d28111b67e1b240e205a9fbb1f2 100644 --- a/ecmascript/interpreter/interpreter_assembly.cpp +++ b/ecmascript/interpreter/interpreter_assembly.cpp @@ -3280,6 +3280,20 @@ void InterpreterAssembly::HandleWideLdexternalmodulevarPrefImm16( DISPATCH(WIDE_LDEXTERNALMODULEVAR_PREF_IMM16); } +void InterpreterAssembly::HandleCallRuntimeWideLdsendableexternalmodulevarPrefImm16( + JSThread *thread, const uint8_t *pc, JSTaggedType *sp, JSTaggedValue constpool, JSTaggedValue profileTypeInfo, + JSTaggedValue acc, int16_t hotnessCounter) +{ + int32_t index = READ_INST_16_1(); + JSTaggedValue thisFunc = GetFunction(sp); + LOG_INST() << "intrinsics::ldsendableexternalmodulevar index:" << index; + + JSTaggedValue moduleVar = SlowRuntimeStub::LdSendableExternalModuleVar(thread, index, thisFunc); + INTERPRETER_RETURN_IF_ABRUPT(moduleVar); + SET_ACC(moduleVar); + DISPATCH(CALLRUNTIME_WIDELDSENDABLEEXTERNALMODULEVAR_PREF_IMM16); +} + void InterpreterAssembly::HandleWideLdlocalmodulevarPrefImm16( JSThread *thread, const uint8_t *pc, JSTaggedType *sp, JSTaggedValue constpool, JSTaggedValue profileTypeInfo, JSTaggedValue acc, int16_t hotnessCounter) @@ -3577,7 +3591,7 @@ void InterpreterAssembly::HandleWideSupercallarrowrangePrefImm16V8( state->function = superCtor; state->constpool = methodHandle->GetConstantPool(); - state->profileTypeInfo = methodHandle->GetProfileTypeInfo(); + state->profileTypeInfo = superCtorFunc->GetProfileTypeInfo(); state->env = superCtorFunc->GetLexicalEnv(); } @@ -3720,7 +3734,7 @@ void InterpreterAssembly::HandleWideSupercallthisrangePrefImm16V8( state->function = superCtor; state->constpool = methodHandle->GetConstantPool(); - state->profileTypeInfo = methodHandle->GetProfileTypeInfo(); + state->profileTypeInfo = superCtorFunc->GetProfileTypeInfo(); state->env = superCtorFunc->GetLexicalEnv(); } @@ -3908,7 +3922,7 @@ void InterpreterAssembly::HandleWideNewobjrangePrefImm16V8( state->function = ctor; state->constpool = methodHandle->GetConstantPool(); - state->profileTypeInfo = methodHandle->GetProfileTypeInfo(); + state->profileTypeInfo = ctorFunc->GetProfileTypeInfo(); state->env = ctorFunc->GetLexicalEnv(); } @@ -3979,7 +3993,7 @@ void InterpreterAssembly::HandleDeprecatedCreateobjecthavingmethodPrefImm16( SAVE_ACC(); constpool = GetConstantPool(sp); JSObject *result = - JSObject::Cast(ConstantPool::GetMethodFromCache(thread, constpool, GetModule(sp), imm).GetTaggedObject()); + JSObject::Cast(ConstantPool::GetMethodFromCache(thread, constpool, imm).GetTaggedObject()); RESTORE_ACC(); JSTaggedValue env = GET_ACC(); @@ -4770,7 +4784,7 @@ void InterpreterAssembly::HandleDeprecatedCreateobjectwithbufferPrefImm16( << " imm:" << imm; constpool = GetConstantPool(sp); JSObject *result = - JSObject::Cast(ConstantPool::GetMethodFromCache(thread, constpool, GetModule(sp), imm).GetTaggedObject()); + JSObject::Cast(ConstantPool::GetMethodFromCache(thread, constpool, imm).GetTaggedObject()); SAVE_PC(); EcmaVM *ecmaVm = thread->GetEcmaVM(); @@ -4790,7 +4804,7 @@ void InterpreterAssembly::HandleDeprecatedCreatearraywithbufferPrefImm16( << " imm:" << imm; constpool = GetConstantPool(sp); JSArray *result = - JSArray::Cast(ConstantPool::GetMethodFromCache(thread, constpool, GetModule(sp), imm).GetTaggedObject()); + JSArray::Cast(ConstantPool::GetMethodFromCache(thread, constpool, imm).GetTaggedObject()); SAVE_PC(); EcmaVM *ecmaVm = thread->GetEcmaVM(); ObjectFactory *factory = ecmaVm->GetFactory(); @@ -6595,6 +6609,20 @@ void InterpreterAssembly::HandleLdexternalmodulevarImm8( DISPATCH(LDEXTERNALMODULEVAR_IMM8); } +void InterpreterAssembly::HandleCallRuntimeLdsendableexternalmodulevarImm8( + JSThread *thread, const uint8_t *pc, JSTaggedType *sp, JSTaggedValue constpool, JSTaggedValue profileTypeInfo, + JSTaggedValue acc, int16_t hotnessCounter) +{ + int32_t index = READ_INST_8_1(); + JSTaggedValue thisFunc = GetFunction(sp); + LOG_INST() << "intrinsics::ldsendableexternalmodulevar index:" << index; + + JSTaggedValue moduleVar = SlowRuntimeStub::LdSendableExternalModuleVar(thread, index, thisFunc); + INTERPRETER_RETURN_IF_ABRUPT(moduleVar); + SET_ACC(moduleVar); + DISPATCH(CALLRUNTIME_LDSENDABLEEXTERNALMODULEVAR_PREF_IMM8); +} + void InterpreterAssembly::HandleDefinemethodImm16Id16Imm8( JSThread *thread, const uint8_t *pc, JSTaggedType *sp, JSTaggedValue constpool, JSTaggedValue profileTypeInfo, JSTaggedValue acc, int16_t hotnessCounter) @@ -6605,7 +6633,7 @@ void InterpreterAssembly::HandleDefinemethodImm16Id16Imm8( SAVE_ACC(); constpool = GetConstantPool(sp); Method *method = - Method::Cast(ConstantPool::GetMethodFromCache(thread, constpool, GetModule(sp), methodId).GetTaggedObject()); + Method::Cast(ConstantPool::GetMethodFromCache(thread, constpool, methodId).GetTaggedObject()); ASSERT(method != nullptr); RESTORE_ACC(); @@ -6614,7 +6642,7 @@ void InterpreterAssembly::HandleDefinemethodImm16Id16Imm8( InterpretedFrame *state = (reinterpret_cast(sp) - 1); JSTaggedValue taggedCurEnv = state->env; - auto res = SlowRuntimeStub::DefineMethod(thread, method, homeObject, length, taggedCurEnv); + auto res = SlowRuntimeStub::DefineMethod(thread, method, homeObject, length, taggedCurEnv, GetModule(sp)); INTERPRETER_RETURN_IF_ABRUPT(res); JSFunction *result = JSFunction::Cast(res.GetTaggedObject()); @@ -6715,7 +6743,7 @@ void InterpreterAssembly::HandleDefinemethodImm8Id16Imm8( SAVE_ACC(); constpool = GetConstantPool(sp); Method *method = - Method::Cast(ConstantPool::GetMethodFromCache(thread, constpool, GetModule(sp), methodId).GetTaggedObject()); + Method::Cast(ConstantPool::GetMethodFromCache(thread, constpool, methodId).GetTaggedObject()); ASSERT(method != nullptr); RESTORE_ACC(); @@ -6723,7 +6751,7 @@ void InterpreterAssembly::HandleDefinemethodImm8Id16Imm8( JSTaggedValue homeObject = GET_ACC(); InterpretedFrame *state = (reinterpret_cast(sp) - 1); JSTaggedValue taggedCurEnv = state->env; - auto res = SlowRuntimeStub::DefineMethod(thread, method, homeObject, length, taggedCurEnv); + auto res = SlowRuntimeStub::DefineMethod(thread, method, homeObject, length, taggedCurEnv, GetModule(sp)); INTERPRETER_RETURN_IF_ABRUPT(res); JSFunction *result = JSFunction::Cast(res.GetTaggedObject()); @@ -6881,7 +6909,7 @@ void InterpreterAssembly::HandleSupercallarrowrangeImm8Imm8V8( state->function = superCtor; state->constpool = methodHandle->GetConstantPool(); - state->profileTypeInfo = methodHandle->GetProfileTypeInfo(); + state->profileTypeInfo = superCtorFunc->GetProfileTypeInfo(); state->env = superCtorFunc->GetLexicalEnv(); } @@ -7024,7 +7052,7 @@ void InterpreterAssembly::HandleSupercallthisrangeImm8Imm8V8( state->function = superCtor; state->constpool = methodHandle->GetConstantPool(); - state->profileTypeInfo = methodHandle->GetProfileTypeInfo(); + state->profileTypeInfo = superCtorFunc->GetProfileTypeInfo(); state->env = superCtorFunc->GetLexicalEnv(); } @@ -7200,7 +7228,7 @@ void InterpreterAssembly::HandleNewobjrangeImm16Imm8V8( state->function = ctor; state->constpool = methodHandle->GetConstantPool(); - state->profileTypeInfo = methodHandle->GetProfileTypeInfo(); + state->profileTypeInfo = ctorFunc->GetProfileTypeInfo(); state->env = ctorFunc->GetLexicalEnv(); } @@ -7342,7 +7370,7 @@ void InterpreterAssembly::HandleNewobjrangeImm8Imm8V8( state->function = ctor; state->constpool = methodHandle->GetConstantPool(); - state->profileTypeInfo = methodHandle->GetProfileTypeInfo(); + state->profileTypeInfo = ctorFunc->GetProfileTypeInfo(); state->env = ctorFunc->GetLexicalEnv(); } @@ -7426,7 +7454,7 @@ void InterpreterAssembly::HandleCreateobjectwithbufferImm16Id16( uint16_t imm = READ_INST_16_2(); LOG_INST() << "intrinsics::createobjectwithbuffer" << " imm:" << imm; - constpool = GetConstantPool(sp); + constpool = GetUnsharedConstpool(thread, sp); JSObject *result = JSObject::Cast( ConstantPool::GetLiteralFromCache( thread, constpool, imm, GetModule(sp)).GetTaggedObject()); @@ -7447,7 +7475,7 @@ void InterpreterAssembly::HandleCreateobjectwithbufferImm8Id16( uint16_t imm = READ_INST_16_1(); LOG_INST() << "intrinsics::createobjectwithbuffer" << " imm:" << imm; - constpool = GetConstantPool(sp); + constpool = GetUnsharedConstpool(thread, sp); JSObject *result = JSObject::Cast( ConstantPool::GetLiteralFromCache( thread, constpool, imm, GetModule(sp)).GetTaggedObject()); @@ -7484,7 +7512,7 @@ void InterpreterAssembly::HandleCreatearraywithbufferImm8Id16( uint16_t imm = READ_INST_16_1(); LOG_INST() << "intrinsics::createarraywithbuffer" << " imm:" << imm; - constpool = GetConstantPool(sp); + constpool = GetUnsharedConstpool(thread, sp); JSArray *result = JSArray::Cast( ConstantPool::GetLiteralFromCache( thread, constpool, imm, GetModule(sp)).GetTaggedObject()); @@ -7632,20 +7660,26 @@ JSTaggedValue InterpreterAssembly::GetConstantPool(JSTaggedType *sp) return method->GetConstantPool(); } +JSTaggedValue InterpreterAssembly::GetUnsharedConstpool(JSThread* thread, JSTaggedType *sp) +{ + AsmInterpretedFrame *state = reinterpret_cast(sp) - 1; + Method *method = JSFunction::Cast(state->function.GetTaggedObject())->GetCallTarget(); + return thread->GetCurrentEcmaContext()->FindUnsharedConstpool(method->GetConstantPool()); +} + JSTaggedValue InterpreterAssembly::GetModule(JSTaggedType *sp) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) AsmInterpretedFrame *state = reinterpret_cast(sp) - 1; - Method *method = JSFunction::Cast(state->function.GetTaggedObject())->GetCallTarget(); - return method->GetModule(); + return JSFunction::Cast(state->function.GetTaggedObject())->GetModule(); } JSTaggedValue InterpreterAssembly::GetProfileTypeInfo(JSTaggedType *sp) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) AsmInterpretedFrame *state = reinterpret_cast(sp) - 1; - Method *method = JSFunction::Cast(state->function.GetTaggedObject())->GetCallTarget(); - return method->GetProfileTypeInfo(); + JSFunction *function = JSFunction::Cast(state->function.GetTaggedObject()); + return function->GetProfileTypeInfo(); } JSTaggedType *InterpreterAssembly::GetAsmInterpreterFramePointer(AsmInterpretedFrame *state) @@ -7690,10 +7724,9 @@ inline JSTaggedValue InterpreterAssembly::UpdateHotnessCounter(JSThread* thread, AsmInterpretedFrame *state = GET_ASM_FRAME(sp); thread->CheckSafepoint(); JSFunction* function = JSFunction::Cast(state->function.GetTaggedObject()); - Method *method = function->GetCallTarget(); - JSTaggedValue profileTypeInfo = method->GetProfileTypeInfo(); + JSTaggedValue profileTypeInfo = function->GetProfileTypeInfo(); if (profileTypeInfo.IsUndefined()) { - return SlowRuntimeStub::NotifyInlineCache(thread, method); + return SlowRuntimeStub::NotifyInlineCache(thread, function); } return profileTypeInfo; } diff --git a/ecmascript/interpreter/interpreter_assembly.h b/ecmascript/interpreter/interpreter_assembly.h index eeb68af97ba0f4853f3d35ea3f40958c99fc0414..e514a3ea37c7746fbfba6c56e8f36dd123e3a700 100644 --- a/ecmascript/interpreter/interpreter_assembly.h +++ b/ecmascript/interpreter/interpreter_assembly.h @@ -49,6 +49,7 @@ public: static JSTaggedValue GetNewTarget(JSTaggedType *sp); static JSTaggedValue GetThis(JSTaggedType *sp); static JSTaggedValue GetConstantPool(JSTaggedType *sp); + static JSTaggedValue GetUnsharedConstpool(JSThread* thread, JSTaggedType *sp); static JSTaggedValue GetModule(JSTaggedType *sp); static JSTaggedValue GetProfileTypeInfo(JSTaggedType *sp); static uint32_t GetNumArgs(JSTaggedType *sp, uint32_t restIdx, uint32_t &startIdx); diff --git a/ecmascript/interpreter/slow_runtime_stub.cpp b/ecmascript/interpreter/slow_runtime_stub.cpp index 2a29b54b8375a905fd4b85439184a52dea05628d..92e08fa22f96d94c1bd9592b42f863e0849e3c57 100644 --- a/ecmascript/interpreter/slow_runtime_stub.cpp +++ b/ecmascript/interpreter/slow_runtime_stub.cpp @@ -1022,14 +1022,15 @@ JSTaggedValue SlowRuntimeStub::SuperCallSpread(JSThread *thread, JSTaggedValue f } JSTaggedValue SlowRuntimeStub::DefineMethod(JSThread *thread, Method *method, JSTaggedValue homeObject, - uint16_t length, JSTaggedValue env) + uint16_t length, JSTaggedValue env, JSTaggedValue module) { INTERPRETER_TRACE(thread, DefineMethod); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle methodHandle(thread, method); JSHandle homeObjectHandle(thread, homeObject); JSHandle envHandle(thread, env); - return RuntimeStubs::RuntimeDefineMethod(thread, methodHandle, homeObjectHandle, length, envHandle); + JSHandle moduleHandle(thread, module); + return RuntimeStubs::RuntimeDefineMethod(thread, methodHandle, homeObjectHandle, length, envHandle, moduleHandle); } JSTaggedValue SlowRuntimeStub::LdSendableClass(JSThread *thread, JSTaggedValue env, uint16_t level) @@ -1040,6 +1041,14 @@ JSTaggedValue SlowRuntimeStub::LdSendableClass(JSThread *thread, JSTaggedValue e return RuntimeStubs::RuntimeLdSendableClass(envHandle, level); } +JSTaggedValue SlowRuntimeStub::LdSendableExternalModuleVar(JSThread *thread, int32_t index, JSTaggedValue thisFunc) +{ + RUNTIME_TRACE(thread, LdSendableExternalModuleVarByIndex); + [[maybe_unused]] EcmaHandleScope scope(thread); + + return RuntimeStubs::RuntimeLdSendableExternalModuleVar(thread, index, thisFunc); +} + JSTaggedValue SlowRuntimeStub::LdSuperByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, JSTaggedValue thisFunc) { @@ -1080,14 +1089,14 @@ void SlowRuntimeStub::ThrowDeleteSuperProperty(JSThread *thread) return RuntimeStubs::RuntimeThrowDeleteSuperProperty(thread); } -JSTaggedValue SlowRuntimeStub::NotifyInlineCache(JSThread *thread, Method *method) +JSTaggedValue SlowRuntimeStub::NotifyInlineCache(JSThread *thread, JSFunction *function) { INTERPRETER_TRACE(thread, NotifyInlineCache); [[maybe_unused]] EcmaHandleScope handleScope(thread); - JSHandle methodHandle(thread, method); - uint32_t slotSize = methodHandle->GetSlotSize(); - return RuntimeStubs::RuntimeNotifyInlineCache(thread, methodHandle, slotSize); + JSHandle functionHandle(thread, function); + uint32_t slotSize = functionHandle->GetCallTarget()->GetSlotSize(); + return RuntimeStubs::RuntimeNotifyInlineCache(thread, functionHandle, slotSize); } JSTaggedValue SlowRuntimeStub::ResolveClass(JSThread *thread, JSTaggedValue ctor, TaggedArray *literal, diff --git a/ecmascript/interpreter/slow_runtime_stub.h b/ecmascript/interpreter/slow_runtime_stub.h index 0e20f328009b7132f93a3178f5deea857d5b415c..f0462d53ee62032c7bd0de5bfaab9c3c9105fdd3 100644 --- a/ecmascript/interpreter/slow_runtime_stub.h +++ b/ecmascript/interpreter/slow_runtime_stub.h @@ -118,6 +118,7 @@ public: static void StModuleVar(JSThread *thread, int32_t index, JSTaggedValue value); static JSTaggedValue LdLocalModuleVar(JSThread *thread, int32_t index); static JSTaggedValue LdExternalModuleVar(JSThread *thread, int32_t index); + static JSTaggedValue LdSendableExternalModuleVar(JSThread *thread, int32_t index, JSTaggedValue thisFunc); static JSTaggedValue CreateRegExpWithLiteral(JSThread *thread, JSTaggedValue pattern, uint8_t flags); static JSTaggedValue GetIteratorNext(JSThread *thread, JSTaggedValue obj, JSTaggedValue method); @@ -152,12 +153,12 @@ public: JSTaggedValue array); static JSTaggedValue DynamicImport(JSThread *thread, JSTaggedValue specifier, JSTaggedValue func); static JSTaggedValue DefineMethod(JSThread *thread, Method *method, JSTaggedValue homeObject, - uint16_t length, JSTaggedValue env); + uint16_t length, JSTaggedValue env, JSTaggedValue module); static JSTaggedValue LdSendableClass(JSThread *thread, JSTaggedValue env, uint16_t level); static JSTaggedValue LdSuperByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, JSTaggedValue thisFunc); static JSTaggedValue StSuperByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, JSTaggedValue value, JSTaggedValue thisFunc); - static JSTaggedValue NotifyInlineCache(JSThread *thread, Method *method); + static JSTaggedValue NotifyInlineCache(JSThread *thread, JSFunction *function); static JSTaggedValue ThrowReferenceError(JSThread *thread, JSTaggedValue prop, const char *desc); static JSTaggedValue ResolveClass(JSThread *thread, JSTaggedValue ctor, TaggedArray *literal, JSTaggedValue base, diff --git a/ecmascript/interpreter/templates/call_runtime_instruction_dispatch.inl b/ecmascript/interpreter/templates/call_runtime_instruction_dispatch.inl index 21c26a53619b5cb88c76bd2e1d90b7074fa0352f..29405a9f0433510188414680369dad4e33a9b4af 100755 --- a/ecmascript/interpreter/templates/call_runtime_instruction_dispatch.inl +++ b/ecmascript/interpreter/templates/call_runtime_instruction_dispatch.inl @@ -21,4 +21,6 @@ &&HANDLE_CALLRUNTIME_DEFINEPRIVATEPROPERTY_PREF_IMM8_IMM16_IMM16_V8, &&HANDLE_CALLRUNTIME_CALLINIT_PREF_IMM8_V8, &&HANDLE_CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8, - &&HANDLE_CALLRUNTIME_LDSENDABLECLASS_PREF_IMM16, \ No newline at end of file + &&HANDLE_CALLRUNTIME_LDSENDABLECLASS_PREF_IMM16, + &&HANDLE_CALLRUNTIME_LDSENDABLEEXTERNALMODULEVAR_PREF_IMM8, + &&HANDLE_CALLRUNTIME_WIDELDSENDABLEEXTERNALMODULEVAR_PREF_IMM16, \ No newline at end of file diff --git a/ecmascript/jit/jit.cpp b/ecmascript/jit/jit.cpp index 74fca7721c75efb58e4e1b98896bedf0900ae572..6e9b86af90fd7292932c44d90ec79e3557b4058d 100644 --- a/ecmascript/jit/jit.cpp +++ b/ecmascript/jit/jit.cpp @@ -140,16 +140,16 @@ void Jit::Compile(EcmaVM *vm, JSHandle &jsFunction, JitCompileMode m return; } - if (method->GetMachineCode() == JSTaggedValue::Hole()) { + if (jsFunction->GetMachineCode() == JSTaggedValue::Hole()) { LOG_JIT(DEBUG) << "skip method, as it compiling:" << methodName; return; } - if (method->GetMachineCode() != JSTaggedValue::Undefined()) { + if (jsFunction->GetMachineCode() != JSTaggedValue::Undefined()) { LOG_JIT(DEBUG) << "skip method, as it has been jit compiled:" << methodName; return; } // using hole value to indecate compiling. todo: reset when failed - method->SetMachineCode(vm->GetJSThread(), JSTaggedValue::Hole()); + jsFunction->SetMachineCode(vm->GetJSThread(), JSTaggedValue::Hole()); { CString msg = "compile method:" + methodName + ", in work thread"; diff --git a/ecmascript/jit/jit_task.cpp b/ecmascript/jit/jit_task.cpp index c26c5388a6ad351359b8da33d99fc2b3f9168a34..1afd60c41b928e1a75b283ba0ed0996d762032ae 100644 --- a/ecmascript/jit/jit_task.cpp +++ b/ecmascript/jit/jit_task.cpp @@ -67,11 +67,11 @@ void JitTask::InstallCode() // oom? uintptr_t codeAddr = machineCodeObj->GetFuncAddr(); FuncEntryDes *funcEntryDes = reinterpret_cast(machineCodeObj->GetFuncEntryDes()); - methodHandle->SetCompiledFuncEntry(codeAddr, funcEntryDes->isFastCall_); + jsFunction_->SetCompiledFuncEntry(codeAddr, funcEntryDes->isFastCall_); methodHandle->SetDeoptThreshold(vm_->GetJSOptions().GetDeoptThreshold()); - methodHandle->SetMachineCode(vm_->GetJSThread(), machineCodeObj); + jsFunction_->SetMachineCode(vm_->GetJSThread(), machineCodeObj); - LOG_JIT(DEBUG) <<"Install machine code:" << GetMethodInfo(); + LOG_JIT(DEBUG) << "Install machine code:" << GetMethodInfo(); } void JitTask::PersistentHandle() diff --git a/ecmascript/js_array.cpp b/ecmascript/js_array.cpp index 6a57a87e4c39a2ca6aefb9638cbc918961e7e3b0..b6afa2f210ab3d37960c31d94844bdd865fc7d5b 100644 --- a/ecmascript/js_array.cpp +++ b/ecmascript/js_array.cpp @@ -219,7 +219,7 @@ void JSArray::SetCapacity(JSThread *thread, const JSHandle &array, uin JSTaggedValue::StringToElementIndex(value, &output); JSTaggedValue key(static_cast(output)); int entry = dictHandle->FindEntry(key); - uint32_t attr = dictHandle->GetAttributes(entry).GetValue(); + auto attr = dictHandle->GetAttributes(entry).GetValue(); PropertyAttributes propAttr(attr); if (propAttr.IsConfigurable()) { JSHandle newDict = NumberDictionary::Remove(thread, dictHandle, entry); diff --git a/ecmascript/js_function.cpp b/ecmascript/js_function.cpp index 17643f42960f73d044d7f7d2cb3283aa9adcffdb..fb30050e20735ee6e749e9bb50d666f1c198098f 100644 --- a/ecmascript/js_function.cpp +++ b/ecmascript/js_function.cpp @@ -28,6 +28,7 @@ #include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/mem/c_containers.h" #include "ecmascript/module/js_module_source_text.h" +#include "ecmascript/module/js_shared_module.h" #include "ecmascript/object_factory.h" #include "ecmascript/tagged_array.h" #include "ecmascript/require/js_require_manager.h" @@ -35,12 +36,7 @@ namespace panda::ecmascript { void JSFunction::InitializeJSFunction(JSThread *thread, const JSHandle &func, FunctionKind kind) { - func->SetProtoOrHClass(thread, JSTaggedValue::Hole(), SKIP_BARRIER); - func->SetHomeObject(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); - func->SetWorkNodePointer(reinterpret_cast(nullptr)); - func->SetLexicalEnv(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); - func->SetMethod(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); - + InitializeWithDefaultValue(thread, func); auto globalConst = thread->GlobalConstants(); if (HasPrototype(kind)) { JSHandle accessor = globalConst->GetHandledFunctionPrototypeAccessor(); @@ -83,6 +79,31 @@ void JSFunction::InitializeJSFunction(JSThread *thread, const JSHandle &func, FunctionKind kind) +{ + InitializeWithDefaultValue(thread, func); + auto globalConst = thread->GlobalConstants(); + if (HasAccessor(kind)) { + JSHandle accessor = globalConst->GetHandledFunctionNameAccessor(); + func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue()); + accessor = globalConst->GetHandledFunctionLengthAccessor(); + func->SetPropertyInlinedProps(thread, LENGTH_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue()); + } +} + +void JSFunction::InitializeWithDefaultValue(JSThread *thread, const JSHandle &func) +{ + func->SetProtoOrHClass(thread, JSTaggedValue::Hole(), SKIP_BARRIER); + func->SetHomeObject(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); + func->SetWorkNodePointer(reinterpret_cast(nullptr)); + func->SetLexicalEnv(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); + func->SetMachineCode(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); + func->SetProfileTypeInfo(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); + func->SetMethod(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); + func->SetModule(thread, JSTaggedValue::Undefined(), SKIP_BARRIER); + func->SetCodeEntry(reinterpret_cast(nullptr)); +} + JSHandle JSFunction::NewJSFunctionPrototype(JSThread *thread, const JSHandle &func) { JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); @@ -440,6 +461,7 @@ JSTaggedValue JSFunction::Invoke(EcmaRuntimeCallInfo *info, const JSHandle mainFunc, JSHandle &thisArg, std::string_view entryPoint, CJSInfo* cjsInfo) { + ASSERT(thread->IsInManagedState()); if (mainFunc->IsClassConstructor()) { { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); @@ -511,6 +533,7 @@ std::vector JSFunction::GetArgsData(bool isFastCall, JSHandle func, EcmaRuntimeCallInfo *info) { + ASSERT(thread->IsInManagedState()); Method *method = func->GetCallTarget(); JSTaggedValue resultValue; uint32_t numArgs = method->GetNumArgsWithCallField(); @@ -839,6 +862,19 @@ JSHandle JSFunction::GetOrCreateDerivedJSHClass(JSThread *thread, JSHa return newJSHClass; } +JSTaggedValue JSFunction::GetRecordName() const +{ + JSTaggedValue module = GetModule(); + if (module.IsSourceTextModule()) { + return SourceTextModule::GetModuleName(module); + } + if (module.IsString()) { + return module; + } + LOG_INTERPRETER(DEBUG) << "record name is undefined"; + return JSTaggedValue::Hole(); +} + // Those interface below is discarded void JSFunction::InitializeJSFunction(JSThread *thread, [[maybe_unused]] const JSHandle &env, const JSHandle &func, FunctionKind kind) @@ -900,6 +936,49 @@ void JSFunction::SetFunctionExtraInfo(JSThread *thread, void *nativeFunc, } } +void JSFunction::SetSFunctionExtraInfo( + JSThread *thread, void *nativeFunc, const DeleteEntryPoint &deleter, void *data, size_t nativeBindingsize) +{ + JSTaggedType hashField = Barriers::GetValue(this, HASH_OFFSET); + EcmaVM *vm = thread->GetEcmaVM(); + JSHandle value(thread, JSTaggedValue(hashField)); + JSHandle obj(thread, this); + JSHandle pointer = + vm->GetFactory()->NewSJSNativePointer(nativeFunc, deleter, data, false, nativeBindingsize); + if (!obj->HasHash()) { + Barriers::SetObject(thread, *obj, HASH_OFFSET, pointer.GetTaggedValue().GetRawData()); + return; + } + if (value->IsHeapObject()) { + if (value->IsJSNativePointer()) { + Barriers::SetObject(thread, *obj, HASH_OFFSET, pointer.GetTaggedValue().GetRawData()); + return; + } + JSHandle array(value); + + uint32_t nativeFieldCount = array->GetExtraLength(); + if (array->GetLength() >= nativeFieldCount + RESOLVED_MAX_SIZE) { + array->Set(thread, nativeFieldCount + FUNCTION_EXTRA_INDEX, pointer); + } else { + JSHandle newArray = + vm->GetFactory()->NewSTaggedArrayWithoutInit(nativeFieldCount + RESOLVED_MAX_SIZE); + newArray->SetExtraLength(nativeFieldCount); + for (uint32_t i = 0; i < nativeFieldCount; i++) { + newArray->Set(thread, i, array->Get(i)); + } + newArray->Set(thread, nativeFieldCount + HASH_INDEX, array->Get(nativeFieldCount + HASH_INDEX)); + newArray->Set(thread, nativeFieldCount + FUNCTION_EXTRA_INDEX, pointer); + Barriers::SetObject(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData()); + } + } else { + JSHandle newArray = vm->GetFactory()->NewSTaggedArrayWithoutInit(RESOLVED_MAX_SIZE); + newArray->SetExtraLength(0); + newArray->Set(thread, HASH_INDEX, value); + newArray->Set(thread, FUNCTION_EXTRA_INDEX, pointer); + Barriers::SetObject(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData()); + } +} + JSTaggedValue JSFunction::GetFunctionExtraInfo() const { JSTaggedType hashField = Barriers::GetValue(this, HASH_OFFSET); @@ -973,6 +1052,18 @@ void JSFunction::InitializeForConcurrentFunction(JSThread *thread) JSHandle module = JSHandle::Cast(moduleRecord); module->SetStatus(ecmascript::ModuleStatus::INSTANTIATED); ecmascript::SourceTextModule::EvaluateForConcurrent(thread, module, method); - method->SetModule(thread, module); + this->SetModule(thread, moduleRecord); +} + +void JSFunctionBase::SetCompiledFuncEntry(uintptr_t codeEntry, bool isFastCall) +{ + ASSERT(codeEntry != 0); + Method* method = Method::Cast(GetMethod()); + method->SetCodeEntryAndMarkAOTWhenBinding(codeEntry); + + method->SetIsFastCall(isFastCall); + MethodLiteral *methodLiteral = method->GetMethodLiteral(); + methodLiteral->SetAotCodeBit(true); + methodLiteral->SetIsFastCall(isFastCall); } } // namespace panda::ecmascript diff --git a/ecmascript/js_function.h b/ecmascript/js_function.h index c35b8f8ab22d9d98a45b24fccd040b6f3fe5f473..695703f05eee2c88aac082655181674340165d7f 100644 --- a/ecmascript/js_function.h +++ b/ecmascript/js_function.h @@ -58,18 +58,15 @@ public: return Method::ConstCast(method.GetTaggedObject())->GetFunctionKind(); } - JSTaggedValue GetModule() const - { - JSTaggedValue method = GetMethod(); - return Method::ConstCast(method.GetTaggedObject())->GetModule(); - } + void SetCompiledFuncEntry(uintptr_t codeEntry, bool isFastCall); static constexpr size_t METHOD_OFFSET = JSObject::SIZE; - ACCESSORS(Method, METHOD_OFFSET, LENGTH_OFFSET) + ACCESSORS(Method, METHOD_OFFSET, CODE_ENTRY_OFFSET) + ACCESSORS_PRIMITIVE_FIELD(CodeEntry, uintptr_t, CODE_ENTRY_OFFSET, LENGTH_OFFSET) ACCESSORS_PRIMITIVE_FIELD(Length, uint32_t, LENGTH_OFFSET, LAST_OFFSET) DEFINE_ALIGN_SIZE(LAST_OFFSET); - DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, METHOD_OFFSET, LENGTH_OFFSET) + DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, METHOD_OFFSET, CODE_ENTRY_OFFSET) DECL_DUMP() }; @@ -225,6 +222,8 @@ public: void SetFunctionExtraInfo(JSThread *thread, void *nativeFunc, const DeleteEntryPoint &deleter, void *data, size_t nativeBindingsize = 0); + void SetSFunctionExtraInfo( + JSThread *thread, void *nativeFunc, const DeleteEntryPoint &deleter, void *data, size_t nativeBindingsize = 0); JSTaggedValue GetFunctionExtraInfo() const; JSTaggedValue GetNativeFunctionExtraInfo() const; @@ -234,6 +233,9 @@ public: static void InitializeJSFunction(JSThread *thread, const JSHandle &func, FunctionKind kind = FunctionKind::NORMAL_FUNCTION); + static void InitializeSFunction(JSThread *thread, const JSHandle &func, + FunctionKind kind = FunctionKind::NORMAL_FUNCTION); + static void InitializeWithDefaultValue(JSThread *thread, const JSHandle &func); static JSHClass *PUBLIC_API GetOrCreateInitialJSHClass(JSThread *thread, const JSHandle &fun); static JSHandle GetInstanceJSHClass(JSThread *thread, JSHandle constructor, JSHandle newTarget); @@ -241,8 +243,11 @@ public: static constexpr size_t PROTO_OR_DYNCLASS_OFFSET = JSFunctionBase::SIZE; ACCESSORS(ProtoOrHClass, PROTO_OR_DYNCLASS_OFFSET, LEXICAL_ENV_OFFSET) // For runtime native function, the LexicalEnv field is used to store GlobalEnv, such as RegExp's native function - ACCESSORS(LexicalEnv, LEXICAL_ENV_OFFSET, HOME_OBJECT_OFFSET) - ACCESSORS(HomeObject, HOME_OBJECT_OFFSET, WORK_NODE_POINTER_OFFSET) + ACCESSORS(LexicalEnv, LEXICAL_ENV_OFFSET, MACHINECODE_OFFSET) + ACCESSORS(MachineCode, MACHINECODE_OFFSET, PROFILE_TYPE_INFO_OFFSET) + ACCESSORS(ProfileTypeInfo, PROFILE_TYPE_INFO_OFFSET, HOME_OBJECT_OFFSET) + ACCESSORS(HomeObject, HOME_OBJECT_OFFSET, ECMA_MODULE_OFFSET) + ACCESSORS(Module, ECMA_MODULE_OFFSET, WORK_NODE_POINTER_OFFSET) ACCESSORS_PRIMITIVE_FIELD(WorkNodePointer, uintptr_t, WORK_NODE_POINTER_OFFSET, LAST_OFFSET) DEFINE_ALIGN_SIZE(LAST_OFFSET); @@ -329,10 +334,9 @@ class JSAsyncModuleFulfilledFunction : public JSFunction { public: CAST_CHECK(JSAsyncModuleFulfilledFunction, IsJSAsyncModuleFulfilledFunction); - static constexpr size_t MODULE_OFFSET = JSFunction::SIZE; - ACCESSORS(Module, MODULE_OFFSET, SIZE); + static constexpr size_t SIZE = JSFunction::SIZE; - DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, MODULE_OFFSET, SIZE) + DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, SIZE, SIZE) DECL_DUMP() }; @@ -341,10 +345,9 @@ class JSAsyncModuleRejectedFunction : public JSFunction { public: CAST_CHECK(JSAsyncModuleRejectedFunction, IsJSAsyncModuleRejectedFunction); - static constexpr size_t MODULE_OFFSET = JSFunction::SIZE; - ACCESSORS(Module, MODULE_OFFSET, SIZE); + static constexpr size_t SIZE = JSFunction::SIZE; - DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, MODULE_OFFSET, SIZE) + DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, SIZE, SIZE) DECL_DUMP() }; diff --git a/ecmascript/js_hclass-inl.h b/ecmascript/js_hclass-inl.h index a22c2c296490bb67a8f3f79729fc1cbde53e356d..4f071ba39e3f3315a52cc632cc480e7ca156edd8 100644 --- a/ecmascript/js_hclass-inl.h +++ b/ecmascript/js_hclass-inl.h @@ -46,17 +46,19 @@ void JSHClass::AddTransitions(const JSThread *thread, const JSHandle & if (cachedHClass->HasProps()) { uint32_t last = cachedHClass->LastPropIndex(); LayoutInfo* layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject()); - auto attr = JSHandle(thread, JSTaggedValue(layoutInfo->GetAttr(last).GetPropertyMetaData())); + auto metaData = JSHandle(thread, + JSTaggedValue(layoutInfo->GetAttr(last).GetPropertyMetaData())); auto lastKey = JSHandle(thread, layoutInfo->GetKey(last)); auto lastHClass = JSHandle(thread, cachedHClass); dict.Update(TransitionsDictionary::Create(thread)); - transitions = TransitionsDictionary::PutIfAbsent(thread, dict, lastKey, lastHClass, attr).GetTaggedValue(); + transitions = TransitionsDictionary::PutIfAbsent(thread, dict, lastKey, lastHClass, + metaData).GetTaggedValue(); } } - auto attr = JSHandle(thread, JSTaggedValue(attributes.GetPropertyMetaData())); + auto metaData = JSHandle(thread, JSTaggedValue(attributes.GetPropertyMetaData())); dict.Update(transitions); - transitions = - TransitionsDictionary::PutIfAbsent(thread, dict, key, JSHandle(child), attr).GetTaggedValue(); + transitions = TransitionsDictionary::PutIfAbsent(thread, dict, key, JSHandle(child), + metaData).GetTaggedValue(); parent->SetTransitions(thread, transitions); } @@ -81,11 +83,13 @@ void JSHClass::AddProtoTransitions(const JSThread *thread, const JSHandleHasProps()) { uint32_t last = cachedHClass->LastPropIndex(); LayoutInfo* layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject()); - auto attr = JSHandle(thread, JSTaggedValue(layoutInfo->GetAttr(last).GetPropertyMetaData())); + auto metaData = JSHandle(thread, + JSTaggedValue(layoutInfo->GetAttr(last).GetPropertyMetaData())); auto lastKey = JSHandle(thread, layoutInfo->GetKey(last)); auto lastHClass = JSHandle(thread, cachedHClass); dict.Update(TransitionsDictionary::Create(thread)); - transitions = TransitionsDictionary::PutIfAbsent(thread, dict, lastKey, lastHClass, attr).GetTaggedValue(); + transitions = TransitionsDictionary::PutIfAbsent(thread, dict, lastKey, lastHClass, + metaData).GetTaggedValue(); } } dict.Update(transitions); @@ -94,7 +98,7 @@ void JSHClass::AddProtoTransitions(const JSThread *thread, const JSHandleSetTransitions(thread, transitions); } -inline JSHClass *JSHClass::FindTransitions(const JSTaggedValue &key, const JSTaggedValue &attributes) +inline JSHClass *JSHClass::FindTransitions(const JSTaggedValue &key, const JSTaggedValue &metaData) { DISALLOW_GARBAGE_COLLECTION; JSTaggedValue transitions = GetTransitions(); @@ -108,9 +112,9 @@ inline JSHClass *JSHClass::FindTransitions(const JSTaggedValue &key, const JSTag } int last = static_cast(cachedHClass->LastPropIndex()); LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject()); - auto attr = layoutInfo->GetAttr(last).GetPropertyMetaData(); - auto cachedKey = layoutInfo->GetKey(last); - if (attr == attributes.GetInt() && key == cachedKey) { + auto lastMetaData = layoutInfo->GetAttr(last).GetPropertyMetaData(); + auto lastKey = layoutInfo->GetKey(last); + if (lastMetaData == metaData.GetInt() && key == lastKey) { return cachedHClass; } return nullptr; @@ -118,7 +122,7 @@ inline JSHClass *JSHClass::FindTransitions(const JSTaggedValue &key, const JSTag ASSERT(transitions.IsTaggedArray()); TransitionsDictionary *dict = TransitionsDictionary::Cast(transitions.GetTaggedObject()); - auto entry = dict->FindEntry(key, attributes); + auto entry = dict->FindEntry(key, metaData); if (entry == -1) { return nullptr; } diff --git a/ecmascript/js_hclass.cpp b/ecmascript/js_hclass.cpp index c534469083f6eca6fb42bf30363480d9753e79ed..0cd146c9a6d0591856930e13ff28e5f5438fa496 100644 --- a/ecmascript/js_hclass.cpp +++ b/ecmascript/js_hclass.cpp @@ -128,15 +128,14 @@ void TransitionsDictionary::Rehash(const JSThread *thread, TransitionsDictionary newTable->SetHoleEntriesCount(thread, 0); } -// class JSHClass -void JSHClass::Initialize(const JSThread *thread, uint32_t size, JSType type, uint32_t inlinedProps) +void JSHClass::InitializeWithDefaultValue(const JSThread *thread, uint32_t size, JSType type, uint32_t inlinedProps) { DISALLOW_GARBAGE_COLLECTION; ClearBitField(); if (JSType::JS_OBJECT_FIRST <= type && type <= JSType::JS_OBJECT_LAST) { SetObjectSize(size + inlinedProps * JSTaggedValue::TaggedTypeSize()); SetInlinedPropsStart(size); - SetLayout(thread, thread->GlobalConstants()->GetEmptyLayoutInfo()); + SetLayout(thread, JSTaggedValue::Null()); } else { SetObjectSize(size); SetLayout(thread, JSTaggedValue::Null()); @@ -157,9 +156,31 @@ void JSHClass::Initialize(const JSThread *thread, uint32_t size, JSType type, ui SetProtoChangeMarker(thread, JSTaggedValue::Null()); SetProtoChangeDetails(thread, JSTaggedValue::Null()); SetEnumCache(thread, JSTaggedValue::Null()); + SetSupers(thread, JSTaggedValue::Undefined()); + SetLevel(0); + SetVTable(thread, JSTaggedValue::Undefined()); +} + +// class JSHClass +void JSHClass::Initialize(const JSThread *thread, uint32_t size, JSType type, uint32_t inlinedProps) +{ + InitializeWithDefaultValue(thread, size, type, inlinedProps); + if (JSType::JS_OBJECT_FIRST <= type && type <= JSType::JS_OBJECT_LAST) { + SetLayout(thread, thread->GlobalConstants()->GetEmptyLayoutInfo()); + } InitTSInheritInfo(thread); } +// for sharedHeap +void JSHClass::Initialize(const JSThread *thread, uint32_t size, JSType type, + uint32_t inlinedProps, const JSHandle &layout) +{ + InitializeWithDefaultValue(thread, size, type, inlinedProps); + if (JSType::JS_OBJECT_FIRST <= type && type <= JSType::JS_OBJECT_LAST) { + SetLayout(thread, layout); + } +} + void JSHClass::InitTSInheritInfo(const JSThread *thread) { // Supers and Level are used to record the relationship between TSHClass. @@ -400,7 +421,7 @@ void JSHClass::OptimizePrototypeForIC(const JSThread *thread, const JSHandle hclass(thread, proto->GetTaggedObject()->GetClass()); ASSERT(!Region::ObjectAddressToRange(reinterpret_cast(*hclass))->InReadOnlySpace()); if (!hclass->IsPrototype()) { - if (!hclass->IsTS()) { + if (!hclass->IsTS() && !hclass->IsJSShared()) { // The local IC and on-proto IC are different, because the former don't need to notify the whole // prototype-chain or listen the changes of prototype chain, but the latter do. Therefore, when // an object becomes a prototype object at the first time, we need to copy its hidden class in @@ -915,6 +936,9 @@ void JSHClass::RefreshUsers(const JSThread *thread, const JSHandle &ol bool JSHClass::HasTSSubtyping() const { // if fill TS inherit info, supers must not be empty + if (!GetSupers().IsHeapObject()) { + return false; + } WeakVector *supers = WeakVector::Cast(GetSupers().GetTaggedObject()); return !(supers->Empty()); } diff --git a/ecmascript/js_hclass.h b/ecmascript/js_hclass.h index a953a8144d8f26b1ce8098c2e610c9bc62d673c2..294e794d6189ef80ed0d44bcf1e07b07bf8978e1 100644 --- a/ecmascript/js_hclass.h +++ b/ecmascript/js_hclass.h @@ -62,6 +62,7 @@ namespace panda::ecmascript { class ProtoChangeDetails; class PropertyLookupResult; +class SharedHeap; namespace pgo { class HClassLayoutDesc; class PGOHClassTreeDesc; @@ -108,7 +109,7 @@ struct Reference; JS_URI_ERROR, /* ////////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_SYNTAX_ERROR, /* ////////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_OOM_ERROR, /* ////////////////////////////////////////////////////////////////////////////-PADDING */ \ - JS_TERMINATION_ERROR, /* JS_ERROR_LAST ///////////////////////////////////////////////////////////////////// */\ + JS_TERMINATION_ERROR, /* JS_ERROR_LAST //////////////////////////////////////////////////////////////////// */ \ \ JS_REG_EXP, /* ///////////////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_SET, /* ///////////////////////////////////////////////////////////////////////////////////-PADDING */ \ @@ -190,18 +191,18 @@ struct Reference; JS_FLOAT32_ARRAY, /* ////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_FLOAT64_ARRAY, /* ////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_BIGINT64_ARRAY, /* ////////////////////////////////////////////////////////////////////////-PADDING */ \ - JS_BIGUINT64_ARRAY, /* JS_TYPED_ARRAY_LAST ///////////////////////////////////////////////////////////// */\ + JS_BIGUINT64_ARRAY, /* JS_TYPED_ARRAY_LAST //////////////////////////////////////////////////////////// */ \ JS_PRIMITIVE_REF, /* number\boolean\string. SPECIAL indexed objects end, DON'T CHANGE HERE ////////-PADDING */ \ JS_MODULE_NAMESPACE, /* ///////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_CJS_MODULE, /* /////////////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_CJS_EXPORTS, /* ////////////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_CJS_REQUIRE, /* ////////////////////////////////////////////////////////////////////////////////-PADDING */ \ - JS_GLOBAL_OBJECT, /* JS_OBJECT_LAST/////////////////////////////////////////////////////////////////-PADDING */\ - JS_PROXY, /* ECMA_OBJECT_LAST ////////////////////////////////////////////////////////////////////////////// */\ + JS_GLOBAL_OBJECT, /* JS_OBJECT_LAST////////////////////////////////////////////////////////////////-PADDING */ \ + JS_PROXY, /* ECMA_OBJECT_LAST ///////////////////////////////////////////////////////////////////////////// */ \ \ HCLASS, /* //////////////////////////////////////////////////////////////////////////////////-PADDING */ \ - LINE_STRING, /* //////////////////////////////////////////////////////////////////////////////////-PADDING */\ - CONSTANT_STRING, /* ///////////////////////////////////////////////////////////////////////////////-PADDING */\ + LINE_STRING, /* /////////////////////////////////////////////////////////////////////////////////-PADDING */ \ + CONSTANT_STRING, /* //////////////////////////////////////////////////////////////////////////////-PADDING */ \ SLICED_STRING, /* ////////////////////////////////////////////////////////////////////////////////-PADDING */ \ TREE_STRING, /* //////////////////////////////////////////////////////////////////////////////////-PADDING */ \ BIGINT, /* //////////////////////////////////////////////////////////////////////////////////-PADDING */ \ @@ -229,7 +230,7 @@ struct Reference; TRANSITION_HANDLER, /* //////////////////////////////////////////////////////////////////////////-PADDING */ \ TRANS_WITH_PROTO_HANDLER, /* ///////////////////////////////////////////////////////////////////-PADDING */ \ STORE_TS_HANDLER, /* ////////////////////////////////////////////////////////////////////////-PADDING */ \ - PROPERTY_BOX, /* /////////////////////////////////////////////////////////////////////////////////-PADDING */ \ + PROPERTY_BOX, /* //////////////////////////////////////////////////////////////////////////////////-PADDING */ \ PROTO_CHANGE_MARKER, /* ///////////////////////////////////////////////////////////////////////////-PADDING */ \ MARKER_CELL, /* ///////////////////////////////////////////////////////////////////////////////////-PADDING */ \ TRACK_INFO, /* ///////////////////////////////////////////////////////////////////////////////////-PADDING */ \ @@ -246,18 +247,19 @@ struct Reference; ASYNC_GENERATOR_REQUEST, /* ///////////////////////////////////////////////////////////////////////-PADDING */ \ ASYNC_ITERATOR_RECORD, /* ///////////////////////////////////////////////////////////////////////-PADDING */ \ PROMISE_ITERATOR_RECORD, /* ////////////////////////////////////////////////////////////////////-PADDING */ \ - MICRO_JOB_QUEUE, /* /////////////////////////////////////////////////////////////////////////////-PADDING */ \ - PENDING_JOB, /* /////////////////////////////////////////////////////////////////////////////-PADDING */ \ - MODULE_RECORD, /* //////////////////////////////////////////////////////////////////////////////-PADDING */ \ - SOURCE_TEXT_MODULE_RECORD, /* //////////////////////////////////////////////////////////////////-PADDING */ \ - IMPORTENTRY_RECORD, /* /////////////////////////////////////////////////////////////////////////-PADDING */ \ - LOCAL_EXPORTENTRY_RECORD, /* ///////////////////////////////////////////////////////////////////-PADDING */ \ - INDIRECT_EXPORTENTRY_RECORD, /* ////////////////////////////////////////////////////////////////-PADDING */ \ - STAR_EXPORTENTRY_RECORD, /* ////////////////////////////////////////////////////////////////////-PADDING */ \ - RESOLVEDBINDING_RECORD, /* /////////////////////////////////////////////////////////////////////-PADDING */ \ - RESOLVEDINDEXBINDING_RECORD, /* ////////////////////////////////////////////////////////////////-PADDING */ \ + MICRO_JOB_QUEUE, /* ///////////////////////////////////////////////////////////////////////////////-PADDING */ \ + PENDING_JOB, /* ///////////////////////////////////////////////////////////////////////////////-PADDING */ \ + MODULE_RECORD, /* /////////////////////////////////////////////////////////////////////////////////-PADDING */ \ + SOURCE_TEXT_MODULE_RECORD, /* /////////////////////////////////////////////////////////////////////-PADDING */ \ + IMPORTENTRY_RECORD, /* ////////////////////////////////////////////////////////////////////////////-PADDING */ \ + LOCAL_EXPORTENTRY_RECORD, /* //////////////////////////////////////////////////////////////////////-PADDING */ \ + INDIRECT_EXPORTENTRY_RECORD, /* ///////////////////////////////////////////////////////////////////-PADDING */ \ + STAR_EXPORTENTRY_RECORD, /* ///////////////////////////////////////////////////////////////////////-PADDING */ \ + RESOLVEDBINDING_RECORD, /* ////////////////////////////////////////////////////////////////////////-PADDING */ \ + RESOLVEDINDEXBINDING_RECORD, /* ///////////////////////////////////////////////////////////////////-PADDING */ \ + RESOLVEDRECORDBINDING_RECORD, /* //////////////////////////////////////////////////////////////////-PADDING */ \ CELL_RECORD, /* //////////////////////////////////////////////////////////////////////////-PADDING */ \ - COMPLETION_RECORD, /* JS_RECORD_LAST /////////////////////////////////////////////////////////////////////// */\ + COMPLETION_RECORD, /* JS_RECORD_LAST ////////////////////////////////////////////////////////////////////// */ \ MACHINE_CODE_OBJECT, \ CLASS_INFO_EXTRACTOR, /* //////////////////////////////////////////////////////////////////////////-PADDING */ \ TS_ARRAY_TYPE, /* ////////////////////////////////////////////////////////////////////////////////-PADDING */ \ @@ -275,33 +277,33 @@ struct Reference; TYPE_LAST = AOT_LITERAL_INFO, /* //////////////////////////////////////////////////////////////////-PADDING */ \ \ JS_FUNCTION_FIRST = JS_FUNCTION, /* ///////////////////////////////////////////////////////////////-PADDING */ \ - JS_FUNCTION_LAST = JS_ASYNC_AWAIT_STATUS_FUNCTION, /* //////////////////////////////////////////////-PADDING */\ + JS_FUNCTION_LAST = JS_ASYNC_AWAIT_STATUS_FUNCTION, /* /////////////////////////////////////////////-PADDING */ \ \ JS_OBJECT_FIRST = JS_OBJECT, /* ///////////////////////////////////////////////////////////////////-PADDING */ \ - JS_OBJECT_LAST = JS_GLOBAL_OBJECT, /* //////////////////////////////////////////////////////////////-PADDING */\ + JS_OBJECT_LAST = JS_GLOBAL_OBJECT, /* /////////////////////////////////////////////////////////////-PADDING */ \ \ ECMA_OBJECT_FIRST = JS_OBJECT, /* /////////////////////////////////////////////////////////////////-PADDING */ \ - ECMA_OBJECT_LAST = JS_PROXY, /* /////////////////////////////////////////////////////////////////-PADDING */\ + ECMA_OBJECT_LAST = JS_PROXY, /* ////////////////////////////////////////////////////////////////-PADDING */ \ \ JS_ERROR_FIRST = JS_ERROR, /* ////////////////////////////////////////////////////////////////-PADDING */ \ - JS_ERROR_LAST = JS_TERMINATION_ERROR, /* ////////////////////////////////////////////////////////-PADDING */\ + JS_ERROR_LAST = JS_TERMINATION_ERROR, /* ///////////////////////////////////////////////////////-PADDING */ \ \ JS_ITERATOR_FIRST = JS_ITERATOR, /* //////////////////////////////////////////////////////////-PADDING */ \ - JS_ITERATOR_LAST = JS_STRING_ITERATOR, /* //////////////////////////////////////////////////////////-PADDING */\ + JS_ITERATOR_LAST = JS_STRING_ITERATOR, /* /////////////////////////////////////////////////////////-PADDING */ \ \ JS_RECORD_FIRST = PROMISE_CAPABILITY, /* //////////////////////////////////////////////////////////-PADDING */ \ - JS_RECORD_LAST = COMPLETION_RECORD, /* ///////////////////////////////////////////////////////-PADDING */ \ + JS_RECORD_LAST = COMPLETION_RECORD, /* /////////////////////////////////////////////////////////-PADDING */ \ \ JS_TYPED_ARRAY_FIRST = JS_TYPED_ARRAY, /* /////////////////////////////////////////////////////////-PADDING */ \ - JS_TYPED_ARRAY_LAST = JS_BIGUINT64_ARRAY, /* ///////////////////////////////////////////////////////-PADDING */\ + JS_TYPED_ARRAY_LAST = JS_BIGUINT64_ARRAY, /* //////////////////////////////////////////////////////-PADDING */ \ \ MODULE_RECORD_FIRST = MODULE_RECORD, /* ///////////////////////////////////////////////////////////-PADDING */ \ MODULE_RECORD_LAST = SOURCE_TEXT_MODULE_RECORD, /* ////////////////////////////////////////////////-PADDING */ \ \ TS_TYPE_FIRST = TS_ARRAY_TYPE, /* /////////////////////////////////////////////////////////////////-PADDING */ \ - TS_TYPE_LAST = TS_NAMESPACE_TYPE, /* ///////////////////////////////////////////////////////////////-PADDING */\ + TS_TYPE_LAST = TS_NAMESPACE_TYPE, /* //////////////////////////////////////////////////////////////-PADDING */ \ \ - STRING_FIRST = LINE_STRING, /* /////////////////////////////////////////////////////////////////////-PADDING */\ + STRING_FIRST = LINE_STRING, /* ////////////////////////////////////////////////////////////////////-PADDING */ \ STRING_LAST = TREE_STRING /* /////////////////////////////////////////////////////////////////////-PADDING */ enum class JSType : uint8_t { @@ -392,7 +394,9 @@ public: // size need to add inlined property numbers void Initialize(const JSThread *thread, uint32_t size, JSType type, uint32_t inlinedProps); - + // for sharedHeap + void Initialize(const JSThread *thread, uint32_t size, JSType type, uint32_t inlinedProps, + const JSHandle &layout); static JSHandle Clone(const JSThread *thread, const JSHandle &jshclass, bool withoutInlinedProperties = false, uint32_t incInlinedProperties = 0); static JSHandle CloneWithoutInlinedProperties(const JSThread *thread, const JSHandle &jshclass); @@ -1608,6 +1612,11 @@ public: return GetObjectType() == JSType::RESOLVEDINDEXBINDING_RECORD; } + inline bool IsResolvedRecordBinding() const + { + return GetObjectType() == JSType::RESOLVEDRECORDBINDING_RECORD; + } + inline bool IsModuleNamespace() const { return GetObjectType() == JSType::JS_MODULE_NAMESPACE; @@ -1858,7 +1867,7 @@ public: return GetProto(); } - inline JSHClass *FindTransitions(const JSTaggedValue &key, const JSTaggedValue &attributes); + inline JSHClass *FindTransitions(const JSTaggedValue &key, const JSTaggedValue &metaData); DECL_DUMP() @@ -1891,6 +1900,8 @@ private: JSHandle &newJsHClass, const JSHandle &key, const PropertyAttributes &attr); + void InitializeWithDefaultValue(const JSThread *thread, uint32_t size, JSType type, uint32_t inlinedProps); + inline void Copy(const JSThread *thread, const JSHClass *jshclass); uint32_t *GetBitFieldAddr() const diff --git a/ecmascript/js_object.cpp b/ecmascript/js_object.cpp index d2c882f91cd1cbf4b341c3785a15e00f493c5ab0..fe407e85662568e5cb5b5eb7ecd9dbffbc082625 100644 --- a/ecmascript/js_object.cpp +++ b/ecmascript/js_object.cpp @@ -875,7 +875,7 @@ bool JSObject::SetPropertyForDataDescriptor(ObjectOperator *op, const JSHandleIsFound() && receiver->IsJSShared()) { - if (!ClassHelper::MatchTrackType(op->GetTrackType(), value.GetTaggedValue())) { + if (!ClassHelper::MatchFieldType(op->GetSharedFieldType(), value.GetTaggedValue())) { if (mayThrow) { THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty), false); } @@ -913,7 +913,7 @@ bool JSObject::SetPropertyForDataDescriptor(ObjectOperator *op, const JSHandleIsJSShared() && - !ClassHelper::MatchTrackType(op->GetTrackType(), value.GetTaggedValue())) { + !ClassHelper::MatchFieldType(op->GetSharedFieldType(), value.GetTaggedValue())) { if (mayThrow) { THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty), false); } @@ -1256,7 +1256,7 @@ bool JSObject::ValidateDataDescriptorWhenConfigurable(ObjectOperator *op, const if (!desc.HasValue()) { THROW_TYPE_ERROR_AND_RETURN(op->GetThread(), GET_MESSAGE_STRING(UpdateSendableAttributes), false); } - if (!ClassHelper::MatchTrackType(current.GetTrackType(), desc.GetValue().GetTaggedValue())) { + if (!ClassHelper::MatchFieldType(current.GetSharedFieldType(), desc.GetValue().GetTaggedValue())) { THROW_TYPE_ERROR_AND_RETURN(op->GetThread(), GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty), false); } } diff --git a/ecmascript/js_object.h b/ecmascript/js_object.h index 1558514d8c42dc1de6507125457089cdd7019b5f..5fb9b157a961f5aa60828a87b26bc7160ec35e26 100644 --- a/ecmascript/js_object.h +++ b/ecmascript/js_object.h @@ -109,14 +109,14 @@ public: key_ = key; } - inline void SetTrackType(TrackType trackType) + inline void SetSharedFieldType(SharedFieldType fieldType) { - trackType_ = trackType; + fieldType_ = fieldType; } - inline TrackType GetTrackType() const + inline SharedFieldType GetSharedFieldType() const { - return trackType_; + return fieldType_; } inline bool IsWritable() const @@ -243,7 +243,7 @@ private: bool hasWritable_ {false}; bool hasEnumerable_ {false}; bool hasConfigurable_ {false}; - TrackType trackType_ {TrackType::NONE}; + SharedFieldType fieldType_ {SharedFieldType::NONE}; JSHandle value_ {}; JSHandle getter_ {}; diff --git a/ecmascript/js_runtime_options.cpp b/ecmascript/js_runtime_options.cpp index 80346fbcd2b20b450c76406bdd98061df01bf5fe..e43b7256b2eb04360924e3d65692955c6168c2b2 100644 --- a/ecmascript/js_runtime_options.cpp +++ b/ecmascript/js_runtime_options.cpp @@ -79,6 +79,7 @@ const std::string PUBLIC_API HELP_OPTION_MSG = "--compiler-opt-bc-range: Range list for EcmaOpCode range Example '1:2,5:8'\n" "--compiler-opt-bc-range-help: Range list for EcmaOpCode range help. Default: 'false''\n" "--enable-force-gc: Enable force gc when allocating object. Default: 'true'\n" + "--force-shared-gc-frequency: How frequency force shared gc . Default: '1'\n" "--enable-ic: Switch of inline cache. Default: 'true'\n" "--enable-runtime-stat: Enable statistics of runtime state. Default: 'false'\n" "--compiler-opt-array-bounds-check-elimination: Enable Index Check elimination. Default: 'true'\n" @@ -209,10 +210,8 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) {"enable-ic", required_argument, nullptr, OPTION_ENABLE_IC}, {"enable-runtime-stat", required_argument, nullptr, OPTION_ENABLE_RUNTIME_STAT}, {"compiler-opt-constant-folding", required_argument, nullptr, OPTION_COMPILER_OPT_CONSTANT_FOLDING}, - {"compiler-opt-array-bounds-check-elimination", - required_argument, - nullptr, - OPTION_COMPILER_OPT_ARRAY_BOUNDS_CHECK_ELIMINATION}, + {"compiler-opt-array-bounds-check-elimination", required_argument, nullptr, + OPTION_COMPILER_OPT_ARRAY_BOUNDS_CHECK_ELIMINATION}, {"compiler-opt-type-lowering", required_argument, nullptr, OPTION_COMPILER_OPT_TYPE_LOWERING}, {"compiler-opt-early-elimination", required_argument, nullptr, OPTION_COMPILER_OPT_EARLY_ELIMINATION}, {"compiler-opt-later-elimination", required_argument, nullptr, OPTION_COMPILER_OPT_LATER_ELIMINATION}, @@ -225,6 +224,7 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) {"compiler-opt-track-field", required_argument, nullptr, OPTION_COMPILER_OPT_TRACK_FIELD}, {"entry-point", required_argument, nullptr, OPTION_ENTRY_POINT}, {"force-full-gc", required_argument, nullptr, OPTION_FORCE_FULL_GC}, + {"force-shared-gc-frequency", required_argument, nullptr, OPTION_ENABLE_FORCE_SHARED_GC_FREQUENCY}, {"gc-thread-num", required_argument, nullptr, OPTION_GC_THREADNUM}, {"heap-size-limit", required_argument, nullptr, OPTION_HEAP_SIZE_LIMIT}, {"help", no_argument, nullptr, OPTION_HELP}, @@ -244,7 +244,6 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) {"merge-abc", required_argument, nullptr, OPTION_MERGE_ABC}, {"enable-context", required_argument, nullptr, OPTION_ENABLE_CONTEXT}, {"compiler-opt-level", required_argument, nullptr, OPTION_ASM_OPT_LEVEL}, - {"options", no_argument, nullptr, OPTION_OPTIONS}, {"compiler-print-type-info", required_argument, nullptr, OPTION_COMPILER_PRINT_TYPE_INFO}, {"reloc-mode", required_argument, nullptr, OPTION_RELOCATION_MODE}, {"serializer-buffer-size-limit", required_argument, nullptr, OPTION_SERIALIZER_BUFFER_SIZE_LIMIT}, @@ -271,10 +270,8 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) {"compiler-pkg-info", required_argument, nullptr, OPTION_COMPILER_PKG_INFO}, {"compiler-external-pkg-info", required_argument, nullptr, OPTION_COMPILER_EXTERNAL_PKG_INFO}, {"compiler-enable-external-pkg", required_argument, nullptr, OPTION_COMPILER_ENABLE_EXTERNAL_PKG}, - {"compiler-enable-lexenv-specialization", - required_argument, - nullptr, - OPTION_COMPILER_ENABLE_LEXENV_SPECIALIZATION}, + {"compiler-enable-lexenv-specialization", required_argument, nullptr, + OPTION_COMPILER_ENABLE_LEXENV_SPECIALIZATION}, {"compiler-enable-native-inline", required_argument, nullptr, OPTION_COMPILER_ENABLE_NATIVE_INLINE}, {"compiler-enable-lowering-builtin", required_argument, nullptr, OPTION_COMPILER_ENABLE_LOWERING_BUILTIN}, {"compiler-enable-litecg", required_argument, nullptr, OPTION_COMPILER_ENABLE_LITECG}, @@ -502,6 +499,14 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) return false; } break; + case OPTION_ENABLE_FORCE_SHARED_GC_FREQUENCY: + ret = ParseUint32Param("force-shared-gc-frequency", &argUint32); + if (ret) { + SetForceSharedGCFrequency(argUint32); + } else { + return false; + } + break; case OPTION_ENABLE_IC: ret = ParseBoolParam(&argBool); if (ret) { @@ -1039,7 +1044,7 @@ bool JSRuntimeOptions::SetDefaultValue(char* argv) return false; } - if (optopt > OPTION_OPTIONS) { // unknown argument + if (optopt >= OPTION_LAST) { // unknown argument LOG_ECMA(ERROR) << "getopt: \"" << argv <<"\" argument has invalid parameter value \n"; return false; } diff --git a/ecmascript/js_runtime_options.h b/ecmascript/js_runtime_options.h index 50c7b16ce7837a3cd9659824426e951132c49570..4272ff9033cc4b865b767e47f88d6223ea72455c 100644 --- a/ecmascript/js_runtime_options.h +++ b/ecmascript/js_runtime_options.h @@ -65,10 +65,12 @@ extern const std::string PUBLIC_API HELP_OPTION_MSG; enum CommandValues { OPTION_DEFAULT, + OPTION_HELP, OPTION_ENABLE_ARK_TOOLS, OPTION_STUB_FILE, OPTION_ENABLE_FORCE_GC, OPTION_FORCE_FULL_GC, + OPTION_ENABLE_FORCE_SHARED_GC_FREQUENCY, OPTION_ARK_PROPERTIES, OPTION_ARK_BUNDLENAME, OPTION_GC_THREADNUM, @@ -125,12 +127,11 @@ enum CommandValues { OPTION_COMPILER_OPT_PGOTYPE, OPTION_COMPILER_OPT_TRACK_FIELD, OPTION_COMPILER_OPT_GLOBAL_TYPEINFER, - OPTION_HELP, OPTION_COMPILER_PGO_PROFILER_PATH, + OPTION_SPLIT_ONE, OPTION_COMPILER_PGO_HOTNESS_THRESHOLD, OPTION_COMPILER_PGO_SAVE_MIN_INTERVAL, OPTION_ENABLE_PGO_PROFILER, - OPTION_OPTIONS, OPTION_PRINT_EXECUTE_TIME, OPTION_COMPILER_VERIFY_VTABLE, OPTION_COMPILER_SELECT_METHODS, @@ -170,7 +171,9 @@ enum CommandValues { OPTION_COMPILER_OPT_BC_RANGE_HELP, OPTION_COMPILER_OPT_ESCAPE_ANALYSIS, OPTION_COMPILER_TRACE_ESCAPE_ANALYSIS, + OPTION_LAST, }; +static_assert(OPTION_SPLIT_ONE == 64); class PUBLIC_API JSRuntimeOptions { public: @@ -332,6 +335,16 @@ public: forceFullGc_ = value; } + void SetForceSharedGCFrequency(size_t frequency) + { + forceSharedGc_ = frequency; + } + + uint32_t GetForceSharedGCFrequency() const + { + return forceSharedGc_; + } + void SetGcThreadNum(size_t num) { gcThreadNum_ = num; @@ -587,7 +600,7 @@ public: bool WasSetCompilerLogOption() const { - return 1ULL << static_cast(OPTION_COMPILER_LOG_OPT) & wasSet_ && + return WasOptionSet(OPTION_COMPILER_LOG_OPT) && GetCompilerLogOption().find("none") == std::string::npos; } @@ -603,7 +616,7 @@ public: bool WasSetMethodsListForLog() const { - return 1ULL << static_cast(OPTION_COMPILER_LOG_METHODS) & wasSet_ && + return WasOptionSet(OPTION_COMPILER_LOG_METHODS) && GetCompilerLogOption().find("none") == std::string::npos && GetCompilerLogOption().find("all") == std::string::npos; } @@ -1154,11 +1167,6 @@ public: compilerModuleMethods_ = compilerModuleMethods; } - void WasSet(int opt) - { - wasSet_ |= 1ULL << static_cast(opt); - } - void SetTraceDeopt(bool value) { traceDeopt_ = value; @@ -1525,9 +1533,22 @@ private: return std::equal(needle.begin(), needle.end(), haystack.begin()); } + void WasSet(int option) + { + if (option < OPTION_SPLIT_ONE) { + wasSetPartOne_ |= (1ULL << static_cast(option)); + } else { + wasSetPartTwo_ |= (1ULL << static_cast(option - OPTION_SPLIT_ONE)); + } + } + bool WasOptionSet(int option) const { - return ((1ULL << static_cast(option)) & wasSet_) != 0; + if (option < OPTION_SPLIT_ONE) { + return ((1ULL << static_cast(option)) & wasSetPartOne_) != 0; + } + + return ((1ULL << static_cast(option - OPTION_SPLIT_ONE)) & wasSetPartTwo_) != 0; } bool ParseBoolParam(bool* argBool); @@ -1544,6 +1565,7 @@ private: bool compilerEnableExternalPkg_ {true}; bool enableForceGc_ {true}; bool forceFullGc_ {true}; + uint32_t forceSharedGc_ {1}; int arkProperties_ = GetDefaultProperties(); std::string arkBundleName_ = {""}; uint32_t gcThreadNum_ {7}; // 7: default thread num @@ -1601,7 +1623,8 @@ private: bool enableGlobalTypeInfer_ {false}; bool enableOptTrackField_ {true}; uint32_t compilerModuleMethods_ {100}; - uint64_t wasSet_ {0}; + uint64_t wasSetPartOne_ {0}; + uint64_t wasSetPartTwo_ {0}; bool enableContext_ {false}; bool enablePrintExecuteTime_ {false}; bool enablePGOProfiler_ {false}; diff --git a/ecmascript/js_serializer.cpp b/ecmascript/js_serializer.cpp index c480c1106b77fd58dcf89cb43eb2679e97b49c5c..fe91690849c89d6fedc6952b6279e225d710c037 100644 --- a/ecmascript/js_serializer.cpp +++ b/ecmascript/js_serializer.cpp @@ -514,6 +514,12 @@ bool JSSerializer::WriteJSFunction(const JSHandle &value) return false; } JSHandle method(thread_, func->GetMethod()); + if (Method::Cast(method.GetTaggedValue())->IsAotWithCallField()) { + uintptr_t codeEntry = func->GetCodeEntry(); + if (!WriteRawData(&codeEntry, sizeof(uintptr_t))) { + return false; + } + } if (!SerializeJSTaggedValue(method)) { return false; } @@ -1316,7 +1322,7 @@ JSHandle JSDeserializer::ReadMethod() if (!ReadNativePointer(&methodLiteral)) { return JSHandle(); } - JSHandle method = factory_->NewMethod(reinterpret_cast(methodLiteral)); + JSHandle method = factory_->NewSMethod(reinterpret_cast(methodLiteral)); JSHandle methodTag(method); referenceMap_.emplace(objectId_++, methodTag); @@ -1379,6 +1385,13 @@ JSHandle JSDeserializer::ReadJSFunction() JSHandle method = JSHandle::Cast(methodVal); func->SetMethod(thread_, method); func->InitializeForConcurrentFunction(thread_); + if (method->IsAotWithCallField()) { + uintptr_t codeEntry; + if (!ReadNativePointer(&codeEntry)) { + return JSHandle(); + } + func->SetCodeEntry(codeEntry); + } return funcTag; } diff --git a/ecmascript/js_tagged_value-inl.h b/ecmascript/js_tagged_value-inl.h index 9051ad29d12ef4d4b44309df7068c00afcf8153b..b8bea07178d368826e12cde8c5ec87ca4d23427c 100644 --- a/ecmascript/js_tagged_value-inl.h +++ b/ecmascript/js_tagged_value-inl.h @@ -1472,6 +1472,11 @@ inline bool JSTaggedValue::IsResolvedIndexBinding() const return IsHeapObject() && GetTaggedObject()->GetClass()->IsResolvedIndexBinding(); } +inline bool JSTaggedValue::IsResolvedRecordBinding() const +{ + return IsHeapObject() && GetTaggedObject()->GetClass()->IsResolvedRecordBinding(); +} + inline bool JSTaggedValue::IsModuleNamespace() const { return IsHeapObject() && GetTaggedObject()->GetClass()->IsModuleNamespace(); diff --git a/ecmascript/js_tagged_value.cpp b/ecmascript/js_tagged_value.cpp index 96bd8d161c4c35204c6922f52a5e277a5dbaf9da..b57fa2420b933ad3743469d09a3a175194430d6f 100644 --- a/ecmascript/js_tagged_value.cpp +++ b/ecmascript/js_tagged_value.cpp @@ -58,6 +58,24 @@ JSHandle GetTypeString(JSThread *thread, PreferredPrimitiveType type return JSHandle::Cast(globalConst->GetHandledStringString()); } +bool JSTaggedValue::IsInSharedHeap() const +{ + if (IsHeapObject()) { + Region *region = Region::ObjectAddressToRange(value_); + return region->InSharedHeap(); + } + return false; +} + +bool JSTaggedValue::IsInSharedSweepableSpace() const +{ + if (IsHeapObject()) { + Region *region = Region::ObjectAddressToRange(value_); + return region->InSharedSweepableSpace(); + } + return false; +} + JSHandle JSTaggedValue::ToPropertyKey(JSThread *thread, const JSHandle &tagged) { if (tagged->IsStringOrSymbol() || tagged->IsNumber()) { diff --git a/ecmascript/js_tagged_value.h b/ecmascript/js_tagged_value.h index d8c8b5ae069fcc18389b7596cf3b16f0558cbfcf..aa20bb88b21306ad3e761be446d0c11ddaa6eb10 100644 --- a/ecmascript/js_tagged_value.h +++ b/ecmascript/js_tagged_value.h @@ -650,10 +650,13 @@ public: bool IsStarExportEntry() const; bool IsResolvedBinding() const; bool IsResolvedIndexBinding() const; + bool IsResolvedRecordBinding() const; bool IsModuleNamespace() const; bool IsJSSharedObject() const; bool IsJSSharedFunction() const; bool IsJSShared() const; + bool PUBLIC_API IsInSharedHeap() const; + bool IsInSharedSweepableSpace() const; static bool IsSameTypeOrHClass(JSTaggedValue x, JSTaggedValue y); static ComparisonResult Compare(JSThread *thread, const JSHandle &x, @@ -696,6 +699,18 @@ private: const JSHandle &key, const JSHandle &value); static JSHandle NativePointerToString(JSThread *thread, const JSHandle &tagged); + + static ARK_INLINE JSTaggedValue WrapUint64(uint64_t v) + { + return JSTaggedValue(static_cast(v) | TAG_INT); + } + static ARK_INLINE uint64_t UnwrapToUint64(JSTaggedValue v) + { + ASSERT_PRINT(v.IsInt(), "can not convert JSTaggedValue to Int :" << std::hex << v.GetRawData()); + return static_cast(v.GetRawData() & (~TAG_INT)); + } + + friend class PropertyAttributes; }; STATIC_ASSERT_EQ_ARCH(sizeof(JSTaggedValue), JSTaggedValue::SizeArch32, JSTaggedValue::SizeArch64); } // namespace panda::ecmascript diff --git a/ecmascript/js_thread.cpp b/ecmascript/js_thread.cpp index 29a95fd6008b466d7f371b0b28325c28d1b9d3b2..bda4e14854d636684b1cf4e38c064fae2a5e26db 100644 --- a/ecmascript/js_thread.cpp +++ b/ecmascript/js_thread.cpp @@ -14,6 +14,8 @@ */ #include "ecmascript/js_thread.h" + +#include "ecmascript/runtime.h" #include "ecmascript/builtin_entries.h" #include "ecmascript/enum_conversion.h" #include "ecmascript/js_tagged_value.h" @@ -47,10 +49,18 @@ namespace panda::ecmascript { using CommonStubCSigns = panda::ecmascript::kungfu::CommonStubCSigns; using BytecodeStubCSigns = panda::ecmascript::kungfu::BytecodeStubCSigns; +thread_local JSThread *currentThread = nullptr; + +JSThread *JSThread::GetCurrent() +{ + return currentThread; +} + // static JSThread *JSThread::Create(EcmaVM *vm) { auto jsThread = new JSThread(vm); + AsmInterParsedOption asmInterOpt = vm->GetJSOptions().GetAsmInterParsedOption(); if (asmInterOpt.enableAsm) { jsThread->EnableAsmInterpreter(); @@ -67,6 +77,13 @@ JSThread *JSThread::Create(EcmaVM *vm) jsThread->glueData_.stackLimit_ = GetAsmStackLimit(); jsThread->glueData_.stackStart_ = GetCurrentStackPosition(); + + Runtime::GetInstance()->RegisterThread(jsThread); + // If it is not true, we created a new thread for future fork + if (currentThread == nullptr) { + currentThread = jsThread; + jsThread->UpdateState(ThreadState::NATIVE); + } return jsThread; } @@ -100,6 +117,7 @@ JSThread::JSThread(EcmaVM *vm) : id_(os::thread::GetCurrentThreadId()), vm_(vm) JSThread::~JSThread() { + readyForGCIterating_ = false; if (globalStorage_ != nullptr) { GetEcmaVM()->GetChunk()->Delete(globalStorage_); globalStorage_ = nullptr; @@ -126,6 +144,15 @@ JSThread::~JSThread() delete vmThreadControl_; vmThreadControl_ = nullptr; } + if (currentThread == this) { + UpdateState(ThreadState::TERMINATED); + currentThread = nullptr; + } else { + // We have created this JSThread instance but hadn't forked it. + ASSERT(GetState() == ThreadState::CREATED); + UpdateState(ThreadState::TERMINATED); + } + Runtime::GetInstance()->UnregisterThread(this); } void JSThread::SetException(JSTaggedValue exception) @@ -177,6 +204,36 @@ const JSTaggedType *JSThread::GetCurrentInterpretedFrame() const return GetCurrentSPFrame(); } +void JSThread::InvokeWeakNodeFreeGlobalCallBack() +{ + while (!weakNodeFreeGlobalCallbacks_.empty()) { + auto callbackPair = weakNodeFreeGlobalCallbacks_.back(); + weakNodeFreeGlobalCallbacks_.pop_back(); + ASSERT(callbackPair.first != nullptr && callbackPair.second != nullptr); + auto callback = callbackPair.first; + (*callback)(callbackPair.second); + } +} + +void JSThread::InvokeWeakNodeNativeFinalizeCallback() +{ + // the second callback may lead to another GC, if this, return directly; + if (runningNativeFinalizeCallbacks_) { + return; + } + runningNativeFinalizeCallbacks_ = true; + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "InvokeNativeFinalizeCallbacks num:" + + std::to_string(weakNodeNativeFinalizeCallbacks_.size())); + while (!weakNodeNativeFinalizeCallbacks_.empty()) { + auto callbackPair = weakNodeNativeFinalizeCallbacks_.back(); + weakNodeNativeFinalizeCallbacks_.pop_back(); + ASSERT(callbackPair.first != nullptr && callbackPair.second != nullptr); + auto callback = callbackPair.first; + (*callback)(callbackPair.second); + } + runningNativeFinalizeCallbacks_ = false; +} + bool JSThread::IsStartGlobalLeakCheck() const { return GetEcmaVM()->GetJSOptions().IsStartGlobalLeakCheck(); @@ -192,6 +249,16 @@ bool JSThread::EnableGlobalPrimitiveLeakCheck() const return GetEcmaVM()->GetJSOptions().EnableGlobalPrimitiveLeakCheck(); } +bool JSThread::IsInRunningStateOrProfiling() const +{ + bool result = IsInRunningState(); +#if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER) + return result || vm_->GetHeapProfile() != nullptr; +#else + return result; +#endif +} + void JSThread::WriteToStackTraceFd(std::ostringstream &buffer) const { if (stackTraceFd_ < 0) { @@ -222,7 +289,6 @@ void JSThread::Iterate(const RootVisitor &visitor, const RootRangeVisitor &range if (!glueData_.exception_.IsHole()) { visitor(Root::ROOT_VM, ObjectSlot(ToUintPtr(&glueData_.exception_))); } - visitor(Root::ROOT_VM, ObjectSlot(ToUintPtr(&glueData_.singleCharTable_))); rangeVisitor( Root::ROOT_VM, ObjectSlot(glueData_.builtinEntries_.Begin()), ObjectSlot(glueData_.builtinEntries_.End())); @@ -322,9 +388,9 @@ void JSThread::IterateHandleWithCheck(const RootVisitor &visitor, const RootRang } } -void JSThread::IterateWeakEcmaGlobalStorage(const WeakRootVisitor &visitor) +void JSThread::IterateWeakEcmaGlobalStorage(const WeakRootVisitor &visitor, bool isSharedGC) { - auto callBack = [this, visitor](WeakNode *node) { + auto callBack = [this, visitor, isSharedGC](WeakNode *node) { JSTaggedValue value(node->GetObject()); if (!value.IsHeapObject()) { return; @@ -339,8 +405,15 @@ void JSThread::IterateWeakEcmaGlobalStorage(const WeakRootVisitor &visitor) weakNodeNativeFinalizeCallbacks_.push_back(std::make_pair(nativeFinalizeCallback, node->GetReference())); } - if (!node->CallFreeGlobalCallback()) { + auto freeGlobalCallBack = node->GetFreeGlobalCallback(); + if (!freeGlobalCallBack) { + // If no callback, dispose global immediately DisposeGlobalHandle(ToUintPtr(node)); + } else if (isSharedGC) { + // For shared GC, free global should defer execute in its own thread + weakNodeFreeGlobalCallbacks_.push_back(std::make_pair(freeGlobalCallBack, node->GetReference())); + } else { + node->CallFreeGlobalCallback(); } } else if (fwd != object) { // update @@ -563,6 +636,12 @@ bool JSThread::CheckSafepoint() SetTerminationRequestWithoutLock(false); } + if (IsSuspended()) { + interruptMutex_.Unlock(); + WaitSuspension(); + interruptMutex_.Lock(); + } + // vmThreadControl_ 's thread_ is current JSThread's this. if (VMNeedSuspensionWithoutLock()) { interruptMutex_.Unlock(); @@ -754,7 +833,11 @@ void JSThread::SwitchCurrentContext(EcmaContext *currentContext, bool isInIterat glueData_.currentContext_->SetStackLimit(GetStackLimit()); glueData_.currentContext_->SetStackStart(GetStackStart()); glueData_.currentContext_->SetGlobalEnv(GetGlueGlobalEnv()); - glueData_.currentContext_->GetGlobalEnv()->SetJSGlobalObject(this, glueData_.globalObject_); + // When the glueData_.currentContext_ is not fully initialized,glueData_.globalObject_ will be hole. + // Assigning hole to JSGlobalObject could cause a mistake at builtins initalization. + if (!glueData_.globalObject_.IsHole()) { + glueData_.currentContext_->GetGlobalEnv()->SetJSGlobalObject(this, glueData_.globalObject_); + } SetCurrentSPFrame(currentContext->GetCurrentFrame()); SetLastLeaveFrame(currentContext->GetLeaveFrame()); @@ -864,4 +947,153 @@ bool JSThread::IsPropertyCacheCleared() const } return true; } + +void JSThread::UpdateState(ThreadState newState) +{ + ThreadState oldState = GetState(); + if (oldState == ThreadState::RUNNING && newState != ThreadState::RUNNING) { + TransferFromRunningToSuspended(newState); + } else if (oldState != ThreadState::RUNNING && newState == ThreadState::RUNNING) { + TransferToRunning(); + } else { + // Here can be some extra checks... + StoreState(newState, false); + } +} + +void JSThread::SuspendThread(bool internalSuspend) +{ + LockHolder lock(suspendLock_); + if (!internalSuspend) { + // do smth here if we want to combine internal and external suspension + } + uint32_t old_count = suspendCount_++; + if (old_count == 0) { + SetFlag(ThreadFlag::SUSPEND_REQUEST); + SetCheckSafePointStatus(); + } +} + +void JSThread::ResumeThread(bool internalSuspend) +{ + LockHolder lock(suspendLock_); + if (!internalSuspend) { + // do smth here if we want to combine internal and external suspension + } + if (suspendCount_ > 0) { + suspendCount_--; + if (suspendCount_ == 0) { + ClearFlag(ThreadFlag::SUSPEND_REQUEST); + ResetCheckSafePointStatus(); + } + } + suspendCondVar_.Signal(); +} + +void JSThread::WaitSuspension() +{ + constexpr int TIMEOUT = 100; + ThreadState oldState = GetState(); + UpdateState(ThreadState::IS_SUSPENDED); + { + LockHolder lock(suspendLock_); + while (suspendCount_ > 0) { + suspendCondVar_.TimedWait(&suspendLock_, TIMEOUT); + // we need to do smth if Runtime is terminating at this point + } + ASSERT(!IsSuspended()); + } + UpdateState(oldState); +} + +void JSThread::ManagedCodeBegin() +{ + ASSERT(!IsInManagedState()); + UpdateState(ThreadState::RUNNING); +} + +void JSThread::ManagedCodeEnd() +{ + ASSERT(IsInManagedState()); + UpdateState(ThreadState::NATIVE); +} + +void JSThread::TransferFromRunningToSuspended(ThreadState newState) +{ + ASSERT(currentThread == this); + StoreState(newState, false); + ASSERT(Runtime::GetInstance()->GetMutatorLock()->HasLock()); + Runtime::GetInstance()->GetMutatorLock()->Unlock(); +} + +void JSThread::TransferToRunning() +{ + ASSERT(currentThread == this); + StoreState(ThreadState::RUNNING, true); + // Invoke free weak global callback when thread switch to running + if (!weakNodeFreeGlobalCallbacks_.empty()) { + InvokeWeakNodeFreeGlobalCallBack(); + } +} + +void JSThread::StoreState(ThreadState newState, bool lockMutatorLock) +{ + while (true) { + ThreadStateAndFlags oldStateAndFlags; + oldStateAndFlags.asInt = stateAndFlags_.asInt; + if (lockMutatorLock && oldStateAndFlags.asStruct.flags != ThreadFlag::NO_FLAGS) { + WaitSuspension(); + continue; + } + ThreadStateAndFlags newStateAndFlags; + newStateAndFlags.asStruct.flags = oldStateAndFlags.asStruct.flags; + newStateAndFlags.asStruct.state = newState; + + if (lockMutatorLock) { + Runtime::GetInstance()->GetMutatorLock()->ReadLock(); + } + + if (stateAndFlags_.asAtomicInt.compare_exchange_weak(oldStateAndFlags.asNonvolatileInt, + newStateAndFlags.asNonvolatileInt, std::memory_order_release)) { + break; + } + + // CAS failed. Unlock mutator lock + if (lockMutatorLock) { + ASSERT(Runtime::GetInstance()->GetMutatorLock()->HasLock()); + Runtime::GetInstance()->GetMutatorLock()->Unlock(); + } + } +} + +void JSThread::PostFork() +{ + SetThreadId(); + if (currentThread == nullptr) { + currentThread = this; + ASSERT(GetState() == ThreadState::CREATED); + UpdateState(ThreadState::NATIVE); + } else { + // We tried to call fork in the same thread + ASSERT(currentThread == this); + ASSERT(GetState() == ThreadState::NATIVE); + } +} +#ifndef NDEBUG +bool JSThread::IsInManagedState() const +{ + ASSERT(this == JSThread::GetCurrent()); + return GetMutatorLockState() == MutatorLock::MutatorLockState::RDLOCK && GetState() == ThreadState::RUNNING; +} + +MutatorLock::MutatorLockState JSThread::GetMutatorLockState() const +{ + return mutatorLockState_; +} + +void JSThread::SetMutatorLockState(MutatorLock::MutatorLockState newState) +{ + mutatorLockState_ = newState; +} +#endif } // namespace panda::ecmascript diff --git a/ecmascript/js_thread.h b/ecmascript/js_thread.h index eb0edaac7017b6c993149ae881d42d9facbb4533..cb522aa21211f8658b70e66e1e98b111450d9b27 100644 --- a/ecmascript/js_thread.h +++ b/ecmascript/js_thread.h @@ -29,7 +29,9 @@ #include "ecmascript/js_tagged_value.h" #include "ecmascript/js_thread_hclass_entries.h" #include "ecmascript/js_thread_stub_entries.h" +#include "ecmascript/log_wrapper.h" #include "ecmascript/mem/visitor.h" +#include "ecmascript/mutator_lock.h" namespace panda::ecmascript { class EcmaContext; @@ -40,7 +42,6 @@ class PropertiesCache; template class EcmaGlobalStorage; class Node; -class SingleCharTable; class DebugNode; class VmThreadControl; using WeakClearCallback = void (*)(void *); @@ -64,6 +65,34 @@ enum class BCStubStatus: uint8_t { enum class StableArrayChangeKind { PROTO, NOT_PROTO }; +enum ThreadFlag : uint16_t { + NO_FLAGS = 0 << 0, + SUSPEND_REQUEST = 1 << 0 +}; + +static constexpr uint32_t THREAD_STATE_OFFSET = 16; +enum class ThreadState : uint16_t { + CREATED = 0, + RUNNING = 1, + NATIVE = 2, + WAIT = 3, + IS_SUSPENDED = 4, + TERMINATED = 5, +}; + +union ThreadStateAndFlags { + explicit ThreadStateAndFlags(uint32_t val = 0): asInt(val) {} + struct { + volatile uint16_t flags; + volatile ThreadState state; + } asStruct; + volatile uint32_t asInt; + uint32_t asNonvolatileInt; + std::atomic asAtomicInt; +private: + NO_COPY_SEMANTIC(ThreadStateAndFlags); +}; + static constexpr uint32_t MAIN_THREAD_INDEX = 0; class JSThread { @@ -101,6 +130,7 @@ public: } static JSThread *Create(EcmaVM *vm); + static JSThread *GetCurrent(); int GetNestedLevel() const { @@ -170,6 +200,16 @@ public: glueData_.newSpaceAllocationEndAddress_ = end; } + uintptr_t GetUnsharedConstpools() const + { + return glueData_.unsharedConstpools_; + } + + void SetUnsharedConstpools(uintptr_t unsharedConstpools) + { + glueData_.unsharedConstpools_ = unsharedConstpools; + } + void SetIsStartHeapSampling(bool isStart) { glueData_.isStartHeapSampling_ = isStart ? JSTaggedValue::True() : JSTaggedValue::False(); @@ -190,11 +230,6 @@ public: void PUBLIC_API CheckJSTaggedType(JSTaggedType value) const; bool PUBLIC_API CpuProfilerCheckJSTaggedType(JSTaggedType value) const; - std::vector> *GetWeakNodeNativeFinalizeCallbacks() - { - return &weakNodeNativeFinalizeCallbacks_; - } - void PUBLIC_API SetException(JSTaggedValue exception); JSTaggedValue GetException() const @@ -325,17 +360,14 @@ public: return id_.load(std::memory_order_relaxed); } - void SetThreadId() - { - id_.store(JSThread::GetCurrentThreadId(), std::memory_order_relaxed); - } + void PostFork(); static ThreadId GetCurrentThreadId() { return os::thread::GetCurrentThreadId(); } - void IterateWeakEcmaGlobalStorage(const WeakRootVisitor &visitor); + void IterateWeakEcmaGlobalStorage(const WeakRootVisitor &visitor, bool isSharedGC = false); PUBLIC_API PropertiesCache *GetPropertiesCache() const; @@ -482,6 +514,16 @@ public: return enableLazyBuiltins_; } + void SetReadyForGCIterating() + { + readyForGCIterating_ = true; + } + + bool ReadyForGCIterating() const + { + return readyForGCIterating_; + } + static constexpr size_t GetGlueDataOffset() { return MEMBER_OFFSET(JSThread, glueData_); @@ -749,6 +791,8 @@ public: glueData_.isDebugMode_ = false; } + void InvokeWeakNodeFreeGlobalCallBack(); + void InvokeWeakNodeNativeFinalizeCallback(); bool IsStartGlobalLeakCheck() const; bool EnableGlobalObjectLeakCheck() const; bool EnableGlobalPrimitiveLeakCheck() const; @@ -800,8 +844,8 @@ public: JSTaggedValue, base::AlignedPointer, BuiltinEntries, - JSTaggedValue, - base::AlignedBool> { + base::AlignedBool, + base::AlignedPointer> { enum class Index : size_t { BCStubEntriesIndex = 0, ExceptionIndex, @@ -832,8 +876,8 @@ public: EntryFrameDroppedStateIndex, CurrentContextIndex, BuiltinEntriesIndex, - SingleCharTableIndex, IsTracingIndex, + unsharedConstpoolsIndex, NumOfMembers }; static_assert(static_cast(Index::NumOfMembers) == NumOfTypes); @@ -993,14 +1037,14 @@ public: return GetOffset(Index::BuiltinEntriesIndex)>(isArch32); } - static size_t GetSingleCharTableOffset(bool isArch32) + static size_t GetIsTracingOffset(bool isArch32) { - return GetOffset(Index::SingleCharTableIndex)>(isArch32); + return GetOffset(Index::IsTracingIndex)>(isArch32); } - static size_t GetIsTracingOffset(bool isArch32) + static size_t GetUnSharedConstpoolsOffset(bool isArch32) { - return GetOffset(Index::IsTracingIndex)>(isArch32); + return GetOffset(Index::unsharedConstpoolsIndex)>(isArch32); } alignas(EAS) BCStubEntries bcStubEntries_; @@ -1021,8 +1065,8 @@ public: alignas(EAS) JSTaggedType *frameBase_ {nullptr}; alignas(EAS) uint64_t stackStart_ {0}; alignas(EAS) uint64_t stackLimit_ {0}; - alignas(EAS) GlobalEnv *glueGlobalEnv_; - alignas(EAS) GlobalEnvConstants *globalConst_; + alignas(EAS) GlobalEnv *glueGlobalEnv_ {nullptr}; + alignas(EAS) GlobalEnvConstants *globalConst_ {nullptr}; alignas(EAS) bool allowCrossThreadExecution_ {false}; alignas(EAS) volatile uint64_t interruptVector_ {0}; alignas(EAS) JSTaggedValue isStartHeapSampling_ {JSTaggedValue::False()}; @@ -1032,8 +1076,8 @@ public: alignas(EAS) uint64_t entryFrameDroppedState_ {FrameDroppedState::StateFalse}; alignas(EAS) EcmaContext *currentContext_ {nullptr}; alignas(EAS) BuiltinEntries builtinEntries_; - alignas(EAS) JSTaggedValue singleCharTable_ {JSTaggedValue::Hole()}; alignas(EAS) bool isTracing_ {false}; + alignas(EAS) uintptr_t unsharedConstpools_ {0}; }; STATIC_ASSERT_EQ_ARCH(sizeof(GlueData), GlueData::SizeArch32, GlueData::SizeArch64); @@ -1047,13 +1091,8 @@ public: JSTaggedValue GetSingleCharTable() const { - ASSERT(glueData_.singleCharTable_ != JSTaggedValue::Hole()); - return glueData_.singleCharTable_; - } - - void SetSingleCharTable(JSTaggedValue singleCharTable) - { - glueData_.singleCharTable_ = singleCharTable; + ASSERT(glueData_.globalConst_->GetSingleCharTable() != JSTaggedValue::Hole()); + return glueData_.globalConst_->GetSingleCharTable(); } void SwitchCurrentContext(EcmaContext *currentContext, bool isInIterate = false); @@ -1075,6 +1114,40 @@ public: void InitializeBuiltinObject(const std::string& key); void InitializeBuiltinObject(); + inline bool IsThreadSafe() + { + return IsMainThread() || IsSuspended(); + } + + inline bool IsSuspended() + { + return ReadFlag(ThreadFlag::SUSPEND_REQUEST); + } + + bool IsInRunningState() const + { + return GetState() == ThreadState::RUNNING; + } + + bool IsInRunningStateOrProfiling() const; + + ThreadState GetState() const + { + uint32_t stateAndFlags = stateAndFlags_.asAtomicInt.load(std::memory_order_acquire); + return static_cast(stateAndFlags >> THREAD_STATE_OFFSET); + } + void UpdateState(ThreadState newState); + void SuspendThread(bool internalSuspend); + void ResumeThread(bool internalSuspend); + void WaitSuspension(); + PUBLIC_API void ManagedCodeBegin(); + PUBLIC_API void ManagedCodeEnd(); +#ifndef NDEBUG + bool IsInManagedState() const; + MutatorLock::MutatorLockState GetMutatorLockState() const; + void SetMutatorLockState(MutatorLock::MutatorLockState newState); +#endif + private: NO_COPY_SEMANTIC(JSThread); NO_MOVE_SEMANTIC(JSThread); @@ -1092,6 +1165,28 @@ private: arrayHClassIndexMap_ = map; } + void SetThreadId() + { + id_.store(JSThread::GetCurrentThreadId(), std::memory_order_relaxed); + } + + void TransferFromRunningToSuspended(ThreadState newState); + void TransferToRunning(); + void StoreState(ThreadState newState, bool lockMutatorLock); + bool ReadFlag(ThreadFlag flag) const + { + return (stateAndFlags_.asStruct.flags & static_cast(flag)) != 0; + } + void SetFlag(ThreadFlag flag) + { + stateAndFlags_.asAtomicInt.fetch_or(flag, std::memory_order_seq_cst); + } + + void ClearFlag(ThreadFlag flag) + { + stateAndFlags_.asAtomicInt.fetch_and(UINT32_MAX ^ flag, std::memory_order_seq_cst); + } + void DumpStack() DUMP_API_ATTR; static size_t GetAsmStackLimit(); @@ -1109,6 +1204,8 @@ private: int nestedLevel_ = 0; NativeAreaAllocator *nativeAreaAllocator_ {nullptr}; HeapRegionAllocator *heapRegionAllocator_ {nullptr}; + bool runningNativeFinalizeCallbacks_ {false}; + std::vector> weakNodeFreeGlobalCallbacks_ {}; std::vector> weakNodeNativeFinalizeCallbacks_ {}; EcmaGlobalStorage *globalStorage_ {nullptr}; @@ -1130,7 +1227,7 @@ private: VmThreadControl *vmThreadControl_ {nullptr}; bool enableStackSourceFile_ {true}; bool enableLazyBuiltins_ {false}; - + bool readyForGCIterating_ {false}; // CpuProfiler bool isProfiling_ {false}; bool gcState_ {false}; @@ -1145,6 +1242,15 @@ private: EcmaContext *currentContext_ {nullptr}; mutable Mutex interruptMutex_; + Mutex suspendLock_; + int32_t suspendCount_ {0}; + ConditionVariable suspendCondVar_; + + ThreadStateAndFlags stateAndFlags_ {}; +#ifndef NDEBUG + MutatorLock::MutatorLockState mutatorLockState_ = MutatorLock::MutatorLockState::UNLOCKED; +#endif + friend class GlobalHandleCollection; friend class EcmaVM; friend class EcmaContext; diff --git a/ecmascript/jspandafile/class_info_extractor.cpp b/ecmascript/jspandafile/class_info_extractor.cpp index b87938567a765f5bdea26c2761610e49368439bc..4b3e80c5dc1f768f28b2188e73421212843385fb 100644 --- a/ecmascript/jspandafile/class_info_extractor.cpp +++ b/ecmascript/jspandafile/class_info_extractor.cpp @@ -22,7 +22,8 @@ namespace panda::ecmascript { void ClassInfoExtractor::BuildClassInfoExtractorFromLiteral(JSThread *thread, JSHandle &extractor, - const JSHandle &literal) + const JSHandle &literal, + ClassKind kind) { [[maybe_unused]] EcmaHandleScope handleScope(thread); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); @@ -36,9 +37,18 @@ void ClassInfoExtractor::BuildClassInfoExtractorFromLiteral(JSThread *thread, JS } // Reserve sufficient length to prevent frequent creation. - JSHandle nonStaticKeys = factory->NewOldSpaceTaggedArray(nonStaticNum + NON_STATIC_RESERVED_LENGTH); - JSHandle nonStaticProperties = + JSHandle nonStaticKeys; + JSHandle nonStaticProperties; factory->NewOldSpaceTaggedArray(nonStaticNum + NON_STATIC_RESERVED_LENGTH); + if (kind == ClassKind::SENDABLE) { + nonStaticKeys = factory->NewSOldSpaceTaggedArray(nonStaticNum + NON_STATIC_RESERVED_LENGTH); + nonStaticProperties = + factory->NewSOldSpaceTaggedArray(nonStaticNum + NON_STATIC_RESERVED_LENGTH); + } else { + nonStaticKeys = factory->NewOldSpaceTaggedArray(nonStaticNum + NON_STATIC_RESERVED_LENGTH); + nonStaticProperties = + factory->NewOldSpaceTaggedArray(nonStaticNum + NON_STATIC_RESERVED_LENGTH); + } nonStaticKeys->Set(thread, CONSTRUCTOR_INDEX, globalConst->GetConstructorString()); Method *method = Method::Cast(extractor->GetConstructorMethod().GetTaggedObject()); @@ -62,8 +72,15 @@ void ClassInfoExtractor::BuildClassInfoExtractorFromLiteral(JSThread *thread, JS uint32_t staticNum = literalBufferLength == 0 ? 0 : (literalBufferLength - 1) / 2 - nonStaticNum; // Reserve sufficient length to prevent frequent creation. - JSHandle staticKeys = factory->NewOldSpaceTaggedArray(staticNum + STATIC_RESERVED_LENGTH); - JSHandle staticProperties = factory->NewOldSpaceTaggedArray(staticNum + STATIC_RESERVED_LENGTH); + JSHandle staticKeys; + JSHandle staticProperties; + if (kind == ClassKind::SENDABLE) { + staticKeys = factory->NewSOldSpaceTaggedArray(staticNum + STATIC_RESERVED_LENGTH); + staticProperties = factory->NewSOldSpaceTaggedArray(staticNum + STATIC_RESERVED_LENGTH); + } else { + staticKeys = factory->NewOldSpaceTaggedArray(staticNum + STATIC_RESERVED_LENGTH); + staticProperties = factory->NewOldSpaceTaggedArray(staticNum + STATIC_RESERVED_LENGTH); + } staticKeys->Set(thread, LENGTH_INDEX, globalConst->GetLengthString()); staticKeys->Set(thread, NAME_INDEX, globalConst->GetNameString()); @@ -327,8 +344,7 @@ JSHandle ClassInfoExtractor::CreateSendableHClass(JSThread *thread, JS uint32_t maxInline = isProtoClass ? JSSharedObject::MAX_INLINE : JSSharedFunction::MAX_INLINE; if (LIKELY(length + extraLength <= maxInline)) { JSMutableHandle key(thread, JSTaggedValue::Undefined()); - JSHandle layout = factory->CreateLayoutInfo(length + extraLength, MemSpaceType::OLD_SPACE, - GrowMode::KEEP); + JSHandle layout = factory->CreateSLayoutInfo(length + extraLength); for (uint32_t index = 0; index < length; ++index) { key.Update(keys->Get(index)); ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key"); @@ -341,14 +357,14 @@ JSHandle ClassInfoExtractor::CreateSendableHClass(JSThread *thread, JS attributes.SetOffset(index); layout->AddKey(thread, index, key.GetTaggedValue(), attributes); } - hclass = isProtoClass ? factory->NewEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, length) : - factory->NewEcmaHClass(JSSharedFunction::SIZE, JSType::JS_SHARED_FUNCTION, length + extraLength); + hclass = isProtoClass ? factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, length) : + factory->NewSEcmaHClass(JSSharedFunction::SIZE, JSType::JS_SHARED_FUNCTION, length + extraLength); hclass->SetLayout(thread, layout); hclass->SetNumberOfProps(length); } else { // dictionary mode - hclass = isProtoClass ? factory->NewEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, 0) : - factory->NewEcmaHClass(JSSharedFunction::SIZE, JSType::JS_SHARED_FUNCTION, 0); + hclass = isProtoClass ? factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, 0) : + factory->NewSEcmaHClass(JSSharedFunction::SIZE, JSType::JS_SHARED_FUNCTION, 0); hclass->SetIsDictionaryMode(true); hclass->SetNumberOfProps(0); } @@ -393,7 +409,7 @@ JSHandle ClassHelper::DefineClassFromExtractor(JSThread *thread, con for (uint32_t index = 0; index < nonStaticLength; ++index) { propValue.Update(nonStaticProperties->Get(index)); if (propValue->IsJSFunction()) { - JSHandle propFunc = factory->CloneJSFuction(JSHandle::Cast(propValue)); + JSHandle propFunc = factory->CloneJSFunction(JSHandle::Cast(propValue)); propFunc->SetHomeObject(thread, prototype); propFunc->SetLexicalEnv(thread, lexenv); propValue.Update(propFunc); @@ -419,7 +435,7 @@ JSHandle ClassHelper::DefineClassFromExtractor(JSThread *thread, con for (uint32_t index = 0; index < staticLength; ++index) { propValue.Update(staticProperties->Get(index)); if (propValue->IsJSFunction()) { - JSHandle propFunc = factory->CloneJSFuction(JSHandle::Cast(propValue)); + JSHandle propFunc = factory->CloneJSFunction(JSHandle::Cast(propValue)); propFunc->SetHomeObject(thread, constructor); propFunc->SetLexicalEnv(thread, lexenv); propValue.Update(propFunc); @@ -486,7 +502,7 @@ JSHandle ClassHelper::DefineClassWithIHClass(JSThread *thread, for (uint32_t index = 0; index < nonStaticLength; ++index) { propValue.Update(nonStaticProperties->Get(index)); if (propValue->IsJSFunction()) { - JSHandle propFunc = factory->CloneJSFuction(JSHandle::Cast(propValue)); + JSHandle propFunc = factory->CloneJSFunction(JSHandle::Cast(propValue)); propFunc->SetHomeObject(thread, prototype); propFunc->SetLexicalEnv(thread, lexenv); propValue.Update(propFunc); @@ -513,7 +529,7 @@ JSHandle ClassHelper::DefineClassWithIHClass(JSThread *thread, for (uint32_t index = 0; index < staticLength; ++index) { propValue.Update(staticProperties->Get(index)); if (propValue->IsJSFunction()) { - JSHandle propFunc = factory->CloneJSFuction(JSHandle::Cast(propValue)); + JSHandle propFunc = factory->CloneJSFunction(JSHandle::Cast(propValue)); propFunc->SetHomeObject(thread, constructor); propFunc->SetLexicalEnv(thread, lexenv); propValue.Update(propFunc); @@ -595,7 +611,7 @@ JSHandle ClassHelper::BuildDictionaryProperties(JSThread *thread propKey.Update(keys->Get(index)); propValue.Update(properties->Get(index)); if (propValue->IsJSFunction()) { - JSHandle propFunc = factory->CloneJSFuction(JSHandle::Cast(propValue)); + JSHandle propFunc = factory->CloneJSFunction(JSHandle::Cast(propValue)); propFunc->SetHomeObject(thread, object); propFunc->SetLexicalEnv(thread, lexenv); propValue.Update(propFunc); @@ -606,39 +622,34 @@ JSHandle ClassHelper::BuildDictionaryProperties(JSThread *thread return dict; } -bool ClassHelper::MatchTrackType(TrackType trackType, JSTaggedValue value) +bool ClassHelper::MatchFieldType(SharedFieldType fieldType, JSTaggedValue value) { bool checkRet = false; - switch (trackType) { - case TrackType::NUMBER: { + switch (fieldType) { + case SharedFieldType::NUMBER: { checkRet = value.IsNumber(); break; } - case TrackType::INT: { - checkRet = value.IsInt(); - break; - } - case TrackType::DOUBLE: { - checkRet = value.IsDouble(); - break; - } - case TrackType::BOOLEAN: { + case SharedFieldType::BOOLEAN: { checkRet = value.IsBoolean(); break; } - case TrackType::STRING: { + case SharedFieldType::STRING: { checkRet = value.IsString() || value.IsNull(); break; } - case TrackType::SENDABLE: { + case SharedFieldType::BIG_INT: { + checkRet = value.IsBigInt(); + break; + } + case SharedFieldType::SENDABLE: { checkRet = value.IsJSShared() || value.IsNull(); break; } - case TrackType::NONE: { + case SharedFieldType::NONE: { checkRet = true; break; } - case TrackType::TAGGED: default: break; } @@ -676,7 +687,7 @@ JSHandle SendableClassDefiner::DefineSendableClassFromExtractor(JSTh SendableClassDefiner::FilterDuplicatedKeys(thread, nonStaticKeys, nonStaticProperties); JSHandle prototypeHClass = ClassInfoExtractor::CreateSendableHClass(thread, nonStaticKeys, nonStaticProperties, true); - JSHandle prototype = factory->NewOldSpaceJSObject(prototypeHClass); + JSHandle prototype = factory->NewSharedOldSpaceJSObject(prototypeHClass); uint32_t length = staticFieldArray->GetLength(); uint32_t staticFields = length / 2; // 2: key-type JSHandle constructorHClass = @@ -687,8 +698,8 @@ JSHandle SendableClassDefiner::DefineSendableClassFromExtractor(JSTh auto layout = JSHandle(thread, constructorHClass->GetLayout()); AddFieldTypeToHClass(thread, staticFieldArray, layout, constructorHClass); } - JSHandle constructor = factory->NewJSFunctionByHClass(method, constructorHClass, - MemSpaceType::NON_MOVABLE); + + JSHandle constructor = factory->NewSFunctionByHClass(method, constructorHClass); // non-static nonStaticProperties->Set(thread, 0, constructor); @@ -746,7 +757,7 @@ JSHandle SendableClassDefiner::DefineSendableClassFromExtractor(JSTh JSMutableHandle nameDict(thread, dict); if (staticFields > 0) { AddFieldTypeToDict(thread, staticFieldArray, nameDict, - PropertyAttributes::Default(false, true, false)); + PropertyAttributes::Default(true, true, false)); } constructor->SetProperties(thread, nameDict); } @@ -816,7 +827,7 @@ JSHandle SendableClassDefiner::BuildSendableDictionaryProperties ASSERT(keys->GetLength() == properties->GetLength()); JSMutableHandle dict( - thread, NameDictionary::Create(thread, NameDictionary::ComputeHashTableSize(length))); + thread, NameDictionary::CreateInSharedHeap(thread, NameDictionary::ComputeHashTableSize(length))); JSMutableHandle propKey(thread, JSTaggedValue::Undefined()); JSMutableHandle propValue(thread, JSTaggedValue::Undefined()); for (uint32_t index = 0; index < length; index++) { @@ -851,20 +862,20 @@ void SendableClassDefiner::AddFieldTypeToHClass(JSThread *thread, const JSHandle uint32_t length = fieldTypeArray->GetLength(); JSMutableHandle key(thread, JSTaggedValue::Undefined()); uint32_t index = static_cast(layout->NumberOfElements()); - PropertyAttributes attributes = PropertyAttributes::Default(true, true, false); - attributes.SetIsInlinedProps(true); - attributes.SetRepresentation(Representation::TAGGED); for (uint32_t i = 0; i < length; i += 2) { // 2: key-value pair; + PropertyAttributes attributes = PropertyAttributes::Default(true, true, false); key.Update(fieldTypeArray->Get(i)); ASSERT(key->IsString()); - TrackType type = FromFieldType(FieldType(fieldTypeArray->Get(i + 1).GetInt())); + SharedFieldType type = FromFieldType(FieldType(fieldTypeArray->Get(i + 1).GetInt())); int entry = layout->FindElementWithCache(thread, *hclass, key.GetTaggedValue(), index); if (entry != -1) { attributes = layout->GetAttr(entry); - attributes.SetTrackType(type); + attributes.SetSharedFieldType(type); layout->SetNormalAttr(thread, entry, attributes); } else { - attributes.SetTrackType(type); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + attributes.SetSharedFieldType(type); attributes.SetOffset(index); layout->AddKey(thread, index++, key.GetTaggedValue(), attributes); } @@ -889,8 +900,8 @@ void SendableClassDefiner::AddFieldTypeToDict(JSThread *thread, const JSHandleGet(i)); ASSERT(key->IsString()); - TrackType type = FromFieldType(FieldType(fieldTypeArray->Get(i + 1).GetInt())); - attributes.SetTrackType(type); + SharedFieldType type = FromFieldType(FieldType(fieldTypeArray->Get(i + 1).GetInt())); + attributes.SetSharedFieldType(type); attributes.SetBoxType(PropertyBoxType::UNDEFINED); JSHandle newDict = NameDictionary::Put(thread, dict, key, value, attributes); dict.Update(newDict); @@ -919,15 +930,15 @@ void SendableClassDefiner::DefineSendableInstanceHClass(JSThread *thread, const JSHandle iHClass; if (base->IsHole() || base->IsNull()) { if (fieldNum == 0) { - iHClass = factory->NewEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, fieldNum); + iHClass = factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, fieldNum); } else if (LIKELY(fieldNum <= JSSharedObject::MAX_INLINE)) { - iHClass = factory->NewEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, fieldNum); - JSHandle layout = factory->CreateLayoutInfo(fieldNum, MemSpaceType::OLD_SPACE, GrowMode::KEEP); + iHClass = factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, fieldNum); + JSHandle layout = factory->CreateSLayoutInfo(fieldNum); AddFieldTypeToHClass(thread, fieldTypeArray, layout, iHClass); } else { - iHClass = factory->NewEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, 0); + iHClass = factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, 0); JSHandle dict = - NameDictionary::Create(thread, NameDictionary::ComputeHashTableSize(fieldNum)); + NameDictionary::CreateInSharedHeap(thread, NameDictionary::ComputeHashTableSize(fieldNum)); AddFieldTypeToHClass(thread, fieldTypeArray, dict, iHClass); } } else { @@ -940,15 +951,15 @@ void SendableClassDefiner::DefineSendableInstanceHClass(JSThread *thread, const JSHandle baseLayout(thread, baseIHClass->GetLayout()); auto newLength = baseLength + fieldNum; if (fieldNum == 0) { - iHClass = factory->NewEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, fieldNum); + iHClass = factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, fieldNum); } else if (LIKELY(newLength <= JSSharedObject::MAX_INLINE)) { - iHClass = factory->NewEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, newLength); - JSHandle layout = factory->CopyAndReSort(baseLayout, baseLength, newLength); + iHClass = factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, newLength); + JSHandle layout = factory->CopyAndReSortSLayoutInfo(baseLayout, baseLength, newLength); AddFieldTypeToHClass(thread, fieldTypeArray, layout, iHClass); } else { - iHClass = factory->NewEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, 0); + iHClass = factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, 0); JSHandle dict = - NameDictionary::Create(thread, NameDictionary::ComputeHashTableSize(newLength)); + NameDictionary::CreateInSharedHeap(thread, NameDictionary::ComputeHashTableSize(newLength)); auto globalConst = const_cast(thread->GlobalConstants()); JSHandle value = globalConst->GetHandledUndefined(); JSMutableHandle key(thread, JSTaggedValue::Undefined()); @@ -964,11 +975,12 @@ void SendableClassDefiner::DefineSendableInstanceHClass(JSThread *thread, const } else { JSHandle baseDict(thread, baseIHClass->GetLayout()); auto baseLength = baseDict->EntriesCount(); + auto newLength = fieldNum + baseLength; JSHandle dict = - NameDictionary::Create(thread, NameDictionary::ComputeHashTableSize(fieldNum + baseLength)); + NameDictionary::CreateInSharedHeap(thread, NameDictionary::ComputeHashTableSize(newLength)); baseDict->Rehash(thread, *dict); dict->SetNextEnumerationIndex(thread, baseDict->GetNextEnumerationIndex()); - iHClass = factory->NewEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, 0); + iHClass = factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, 0); AddFieldTypeToHClass(thread, fieldTypeArray, dict, iHClass); } } @@ -1037,7 +1049,7 @@ bool SendableClassDefiner::TryUpdateExistValue(JSThread *thread, JSMutableHandle } } else { if (value->IsJSFunction() && JSHandle(value)->IsGetterOrSetter()) { - JSHandle accessor = thread->GetEcmaVM()->GetFactory()->NewAccessorData(); + JSHandle accessor = thread->GetEcmaVM()->GetFactory()->NewSAccessorData(); UpdateValueToAccessor(thread, value, accessor); } } @@ -1047,7 +1059,7 @@ bool SendableClassDefiner::TryUpdateExistValue(JSThread *thread, JSMutableHandle void SendableClassDefiner::TryUpdateValue(JSThread *thread, JSMutableHandle &value) { if (value->IsJSFunction() && JSHandle(value)->IsGetterOrSetter()) { - JSHandle accessor = thread->GetEcmaVM()->GetFactory()->NewAccessorData(); + JSHandle accessor = thread->GetEcmaVM()->GetFactory()->NewSAccessorData(); UpdateValueToAccessor(thread, value, accessor); } } diff --git a/ecmascript/jspandafile/class_info_extractor.h b/ecmascript/jspandafile/class_info_extractor.h index 555819310476f8370a1ba81f6342e6dac1f571a5..87a5c335a9e42e74e4fbfca13748dd033e5546fb 100644 --- a/ecmascript/jspandafile/class_info_extractor.h +++ b/ecmascript/jspandafile/class_info_extractor.h @@ -33,6 +33,7 @@ enum class FieldType { STRING = (1 << 1), BOOLEAN = (1 << 2), TS_TYPE_REF = (1 << 3), + BIG_INT = (1 << 4), }; class ClassInfoExtractor : public TaggedObject { public: @@ -54,7 +55,8 @@ public: CAST_CHECK(ClassInfoExtractor, IsClassInfoExtractor); static void BuildClassInfoExtractorFromLiteral(JSThread *thread, JSHandle &extractor, - const JSHandle &literal); + const JSHandle &literal, + ClassKind kind = ClassKind::NON_SENDABLE); static JSHandle CreatePrototypeHClass(JSThread *thread, JSHandle &keys, @@ -113,7 +115,7 @@ public: const JSHandle &ihclass, const JSHandle &constructorHClass); - static bool PUBLIC_API MatchTrackType(TrackType trackType, JSTaggedValue value); + static bool PUBLIC_API MatchFieldType(SharedFieldType fieldType, JSTaggedValue value); private: static JSHandle BuildDictionaryProperties(JSThread *thread, const JSHandle &object, JSHandle &keys, @@ -140,20 +142,23 @@ public: const JSHandle &properties); private: - static TrackType FromFieldType(FieldType type) + static SharedFieldType FromFieldType(FieldType type) { switch (type) { case FieldType::NONE: - return TrackType::NONE; + return SharedFieldType::NONE; case FieldType::NUMBER: - return TrackType::NUMBER; + return SharedFieldType::NUMBER; case FieldType::STRING: - return TrackType::STRING; + return SharedFieldType::STRING; case FieldType::BOOLEAN: - return TrackType::BOOLEAN; + return SharedFieldType::BOOLEAN; case FieldType::TS_TYPE_REF: - return TrackType::SENDABLE; + return SharedFieldType::SENDABLE; + case FieldType::BIG_INT: + return SharedFieldType::BIG_INT; default: + LOG_ECMA(FATAL) << "Unsupport fieldType in shared object with type: " << static_cast(type); UNREACHABLE(); } } diff --git a/ecmascript/jspandafile/js_pandafile.cpp b/ecmascript/jspandafile/js_pandafile.cpp index fd602bcc479f4e7b16237bb21c0a12b7254701da..491992fdf3d9d91a32670c08ec3c502c04567fac 100644 --- a/ecmascript/jspandafile/js_pandafile.cpp +++ b/ecmascript/jspandafile/js_pandafile.cpp @@ -253,6 +253,14 @@ CString JSPandaFile::GetEntryPoint(const CString &recordName) const return CString(); } +CString JSPandaFile::GetRecordName(const CString &entryPoint) const +{ + if (entryPoint.empty() || entryPoint == JSPandaFile::ENTRY_FUNCTION_NAME) { + return GetJSPandaFileDesc(); + } + return entryPoint; +} + bool JSPandaFile::FindOhmUrlInPF(const CString &recordName, CString &entryPoint) const { Span classIndexes = pf_->GetClasses(); diff --git a/ecmascript/jspandafile/js_pandafile.h b/ecmascript/jspandafile/js_pandafile.h index 6ceafbee25763f1d6c0c58532f4503569b2c5dc1..14475c2d478764fd041be85668ba333d3e8160af 100644 --- a/ecmascript/jspandafile/js_pandafile.h +++ b/ecmascript/jspandafile/js_pandafile.h @@ -366,6 +366,7 @@ public: return isRecordWithBundleName_; } CString GetEntryPoint(const CString &recordName) const; + CString GetRecordName(const CString &entryPoint) const; bool FindOhmUrlInPF(const CString &recordName, CString &entryPoint) const; uint32_t GetAOTFileInfoIndex() const { diff --git a/ecmascript/jspandafile/js_pandafile_executor.cpp b/ecmascript/jspandafile/js_pandafile_executor.cpp index 807a8d12939da5d6f00e0241592237edf391a3ca..860ed7c0f5028e0bb5bf357e9825d205183af8b8 100644 --- a/ecmascript/jspandafile/js_pandafile_executor.cpp +++ b/ecmascript/jspandafile/js_pandafile_executor.cpp @@ -21,6 +21,7 @@ #include "ecmascript/compiler/aot_file/aot_file_manager.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/js_file_path.h" +#include "ecmascript/js_thread.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" #include "ecmascript/jspandafile/program_object.h" #include "ecmascript/log_wrapper.h" @@ -29,6 +30,7 @@ #include "ecmascript/module/js_module_manager.h" #include "ecmascript/module/module_path_helper.h" #include "ecmascript/patch/quick_fix_manager.h" +#include "ecmascript/checkpoint/thread_state_transition.h" namespace panda::ecmascript { using PathHelper = base::PathHelper; @@ -86,6 +88,11 @@ Expected JSPandaFileExecutor::ExecuteFromAbcFile(JSThread * THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false)); } if (jsPandaFile->IsModule(recordInfo)) { + bool needToFinishManagedCode = false; + if (thread->GetState() != ThreadState::RUNNING) { + needToFinishManagedCode = true; + thread->ManagedCodeBegin(); + } [[maybe_unused]] EcmaHandleScope scope(thread); ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); JSHandle moduleRecord(thread->GlobalConstants()->GetHandledUndefined()); @@ -102,6 +109,9 @@ Expected JSPandaFileExecutor::ExecuteFromAbcFile(JSThread * module->SetStatus(ModuleStatus::INSTANTIATED); BindPandaFilesForAot(vm, jsPandaFile.get()); SourceTextModule::Evaluate(thread, module, nullptr, 0, executeFromJob); + if (needToFinishManagedCode) { + thread->ManagedCodeEnd(); + } if (thread->HasPendingException()) { return Unexpected(false); } @@ -220,6 +230,11 @@ Expected JSPandaFileExecutor::CommonExecuteBuffer(JSThread Expected JSPandaFileExecutor::Execute(JSThread *thread, const JSPandaFile *jsPandaFile, std::string_view entryPoint, bool executeFromJob) { + bool needToFinishManagedCode = false; + if (thread->GetState() != ThreadState::RUNNING) { + needToFinishManagedCode = true; + thread->ManagedCodeBegin(); + } // For Ark application startup EcmaContext *context = thread->GetCurrentEcmaContext(); @@ -233,6 +248,9 @@ Expected JSPandaFileExecutor::Execute(JSThread *thread, con result = context->InvokeEcmaEntrypoint(jsPandaFile, entryPoint, executeFromJob); } + if (needToFinishManagedCode) { + thread->ManagedCodeEnd(); + } return result; } @@ -350,4 +368,42 @@ Expected JSPandaFileExecutor::ExecuteModuleBufferSecure(JST } return CommonExecuteBuffer(thread, name, entry, jsPandaFile.get()); } + +// RecordName is the ohmurl-path of js files. +// The first js file waiting be executed should use ES Module format. +Expected JSPandaFileExecutor::LazyExecuteModule( + JSThread *thread, const CString &recordName, const CString &filename, bool isMergedAbc) +{ + LOG_FULL(INFO) << "recordName : " << recordName << ", in abc : " << filename; + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "JSPandaFileExecutor::LazyExecuteModule"); + std::shared_ptr jsPandaFile = + JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, filename, recordName); + if (jsPandaFile == nullptr) { + LOG_FULL(FATAL) << "Load file with filename '" << filename << "' failed, "; + } + + if (isMergedAbc) { + if (!jsPandaFile->HasRecord(recordName)) { + CString msg = "cannot find record '" + recordName + "', in lazy load abc: " + filename; + THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false)); + } + // [[todo::DaiHN]]check is es module + } + + [[maybe_unused]] EcmaHandleScope scope(thread); + // The first js file should execute at current vm. + ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); + JSHandle moduleRecord(thread->GlobalConstants()->GetHandledUndefined()); + if (isMergedAbc) { + moduleRecord = moduleManager->HostResolveImportedModuleWithMerge(filename, recordName); + } else { + moduleRecord = moduleManager->HostResolveImportedModule(filename); + } + SourceTextModule::Instantiate(thread, moduleRecord); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, Unexpected(false)); + JSHandle module = JSHandle::Cast(moduleRecord); + BindPandaFilesForAot(thread->GetEcmaVM(), jsPandaFile.get()); + SourceTextModule::Evaluate(thread, module, nullptr, 0); + return JSTaggedValue::Undefined(); +} } // namespace panda::ecmascript diff --git a/ecmascript/jspandafile/js_pandafile_executor.h b/ecmascript/jspandafile/js_pandafile_executor.h index 6e8faa01b23bc745cf603ab21aa443f90525ca59..c50174af796097a142a24e68af98e7454da47fbb 100644 --- a/ecmascript/jspandafile/js_pandafile_executor.h +++ b/ecmascript/jspandafile/js_pandafile_executor.h @@ -47,6 +47,8 @@ public: bool needUpdate = false); static Expected CommonExecuteBuffer(JSThread *thread, const CString &filename, const CString &entry, const JSPandaFile *jsPandaFile); + static Expected LazyExecuteModule( + JSThread *thread, const CString &recordName, const CString &filename, bool isMergedAbc); }; } // namespace panda::ecmascript #endif // ECMASCRIPT_JSPANDAFILE_JS_PANDAFILE_EXECUTOR_H diff --git a/ecmascript/jspandafile/literal_data_extractor.cpp b/ecmascript/jspandafile/literal_data_extractor.cpp index 842437c6ed17863f9499e67779cab982189aeefc..5c33428ac045e61b674cb562e7596f3e7b2ba519 100644 --- a/ecmascript/jspandafile/literal_data_extractor.cpp +++ b/ecmascript/jspandafile/literal_data_extractor.cpp @@ -22,6 +22,7 @@ #include "ecmascript/js_tagged_value.h" #include "ecmascript/js_thread.h" #include "ecmascript/module/js_module_manager.h" +#include "ecmascript/module/js_shared_module.h" #include "ecmascript/patch/quick_fix_manager.h" #include "ecmascript/tagged_array-inl.h" @@ -67,7 +68,7 @@ void LiteralDataExtractor::ExtractObjectDatas(JSThread *thread, const JSPandaFil } case LiteralTag::STRING: { StringData sd = jsPandaFile->GetStringData(EntityId(std::get(value))); - EcmaString *str = factory->GetRawStringFromStringTable(sd, MemSpaceType::OLD_SPACE); + EcmaString *str = factory->GetRawStringFromStringTable(sd, MemSpaceType::SHARED_OLD_SPACE); jt = JSTaggedValue(str); uint32_t elementIndex = 0; if (JSTaggedValue::ToElementIndex(jt, &elementIndex) && ppos % pairSize == 0) { @@ -181,7 +182,7 @@ JSHandle LiteralDataExtractor::EnumerateLiteralVals(JSThread *threa } case LiteralTag::STRING: { StringData sd = jsPandaFile->GetStringData(EntityId(std::get(value))); - EcmaString *str = factory->GetRawStringFromStringTable(sd, MemSpaceType::OLD_SPACE); + EcmaString *str = factory->GetRawStringFromStringTable(sd, MemSpaceType::SHARED_OLD_SPACE); jt = JSTaggedValue(str); break; } @@ -242,8 +243,10 @@ JSHandle LiteralDataExtractor::EnumerateLiteralVals(JSThread *threa return literals; } -JSHandle LiteralDataExtractor::CreateJSFunctionInLiteral(EcmaVM *vm, JSHandle method, - FunctionKind kind, ClassKind classKind) +JSHandle LiteralDataExtractor::CreateJSFunctionInLiteral(EcmaVM *vm, + const JSHandle &method, + FunctionKind kind, + ClassKind classKind) { ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); @@ -294,29 +297,13 @@ JSHandle LiteralDataExtractor::DefineMethodInLiteral(JSThread *threa kind = literalKind; } bool canFastCall = false; - - CString moduleName = jsPandaFile->GetJSPandaFileDesc(); - CString entry = JSPandaFile::ENTRY_FUNCTION_NAME; - if (!entryPoint.empty()) { - moduleName = entryPoint; - entry = entryPoint; - } - JSRecordInfo recordInfo; - bool hasRecord = jsPandaFile->CheckAndGetRecordInfo(entry, recordInfo); - if (!hasRecord) { - LOG_ECMA(FATAL) << "cannot find record '" + entry + "', please check the request path."; - } - JSMutableHandle module(thread, JSTaggedValue::Undefined()); - if (jsPandaFile->IsModule(recordInfo)) { - module.Update(thread->GetCurrentEcmaContext()->GetModuleManager()->HostGetImportedModule(moduleName)); - } else { - module.Update(factory->NewFromUtf8(moduleName)); - } - - JSHandle method = factory->NewMethod(jsPandaFile, methodLiteral, constpool, - module, entryIndex, isLoadedAOT, &canFastCall); + JSHandle method = + factory->NewSMethod(jsPandaFile, methodLiteral, constpool, entryIndex, isLoadedAOT, &canFastCall); JSHandle functionClass; JSHandle jsFunc = CreateJSFunctionInLiteral(vm, method, kind, classKind); + ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); + JSHandle module = moduleManager->GenerateFuncModule(jsPandaFile, entryPoint, classKind); + jsFunc->SetModule(thread, module.GetTaggedValue()); jsFunc->SetLength(length); return jsFunc; } @@ -400,7 +387,7 @@ void LiteralDataExtractor::ExtractObjectDatas(JSThread *thread, const JSPandaFil } case LiteralTag::STRING: { StringData sd = jsPandaFile->GetStringData(EntityId(std::get(value))); - EcmaString *str = factory->GetRawStringFromStringTable(sd, MemSpaceType::OLD_SPACE); + EcmaString *str = factory->GetRawStringFromStringTable(sd, MemSpaceType::SHARED_OLD_SPACE); jt = JSTaggedValue(str); uint32_t elementIndex = 0; if (JSTaggedValue::ToElementIndex(jt, &elementIndex) && ppos % pairSize == 0) { @@ -486,7 +473,12 @@ JSHandle LiteralDataExtractor::GetDatasIgnoreType(JSThread *thread, ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); LiteralDataAccessor lda = jsPandaFile->GetLiteralDataAccessor(); uint32_t num = lda.GetLiteralValsNum(id) / 2; // 2: half - JSHandle literals = JSHandle(factory->NewCOWTaggedArray(num)); + JSHandle literals; + if (classKind == ClassKind::SENDABLE) { + literals = JSHandle(factory->NewSCOWTaggedArray(num)); + } else { + literals = JSHandle(factory->NewCOWTaggedArray(num)); + } uint32_t pos = 0; uint32_t methodId = 0; FunctionKind kind; @@ -511,7 +503,7 @@ JSHandle LiteralDataExtractor::GetDatasIgnoreType(JSThread *thread, } case LiteralTag::STRING: { StringData sd = jsPandaFile->GetStringData(EntityId(std::get(value))); - EcmaString *str = factory->GetRawStringFromStringTable(sd, MemSpaceType::OLD_SPACE); + EcmaString *str = factory->GetRawStringFromStringTable(sd, MemSpaceType::SHARED_OLD_SPACE); jt = JSTaggedValue(str); break; } diff --git a/ecmascript/jspandafile/literal_data_extractor.h b/ecmascript/jspandafile/literal_data_extractor.h index b8fad132e564a14a43b5e7e64617ee120793d509..8f34c98d3846366b80e465d2fb0c6ce364e4578e 100644 --- a/ecmascript/jspandafile/literal_data_extractor.h +++ b/ecmascript/jspandafile/literal_data_extractor.h @@ -65,8 +65,8 @@ public: static void PUBLIC_API GetMethodOffsets(const JSPandaFile *jsPandaFile, EntityId id, std::vector &methodOffsets); private: - static JSHandle CreateJSFunctionInLiteral(EcmaVM *vm, JSHandle method, FunctionKind kind, - ClassKind classKind); + static JSHandle CreateJSFunctionInLiteral(EcmaVM *vm, const JSHandle &method, + FunctionKind kind, ClassKind classKind); static JSHandle EnumerateLiteralVals(JSThread *thread, panda_file::LiteralDataAccessor &lda, const JSPandaFile *jsPandaFile, size_t index, JSHandle constpool, const CString &entryPoint = ""); diff --git a/ecmascript/jspandafile/method_literal.h b/ecmascript/jspandafile/method_literal.h index dbcf89c288a087747db608c13696bd02f3e68719..cf33de4d187a9f14ff0b7232321fa6f937c2a9df 100644 --- a/ecmascript/jspandafile/method_literal.h +++ b/ecmascript/jspandafile/method_literal.h @@ -99,11 +99,6 @@ public: return IsNativeWithCallField(callField_); } - bool IsAotWithCallField() const - { - return IsAotWithCallField(callField_); - } - uint32_t GetNumArgsWithCallField() const { return GetNumArgsWithCallField(callField_); diff --git a/ecmascript/jspandafile/panda_file_translator.cpp b/ecmascript/jspandafile/panda_file_translator.cpp index 8c812f0346c276888e01a01b0dc58244ad2de4c4..cc82a66a28d4ae1901904d506b0ed77dd5f9eaad 100644 --- a/ecmascript/jspandafile/panda_file_translator.cpp +++ b/ecmascript/jspandafile/panda_file_translator.cpp @@ -105,28 +105,36 @@ JSHandle PandaFileTranslator::GenerateProgram(EcmaVM *vm, const JSPanda std::string_view entryPoint) { uint32_t mainMethodIndex = jsPandaFile->GetMainMethodIndex(entryPoint.data()); - JSHandle constpool; + JSHandle sconstpool; bool isNewVersion = jsPandaFile->IsNewVersion(); if (isNewVersion) { - constpool = vm->GetJSThread()->GetCurrentEcmaContext()->FindOrCreateConstPool( + sconstpool = vm->GetJSThread()->GetCurrentEcmaContext()->FindOrCreateConstPool( jsPandaFile, EntityId(mainMethodIndex)); } else { - JSTaggedValue constpoolVal = vm->GetJSThread()->GetCurrentEcmaContext()->FindConstpool(jsPandaFile, 0); + EcmaContext *context = vm->GetJSThread()->GetCurrentEcmaContext(); + JSTaggedValue constpoolVal = context->FindConstpool(jsPandaFile, 0); + JSHandle unsharedConstpool; if (constpoolVal.IsHole()) { - constpool = ParseConstPool(vm, jsPandaFile); + std::pair, JSHandle> constpoolPair = ParseConstPool(vm, jsPandaFile); + sconstpool = constpoolPair.first; + unsharedConstpool = constpoolPair.second; // old version dont support multi constpool - vm->GetJSThread()->GetCurrentEcmaContext()->AddConstpool(jsPandaFile, constpool.GetTaggedValue()); + context->AddConstpool(jsPandaFile, sconstpool.GetTaggedValue()); + context->SetUnsharedConstpool( + sconstpool->GetUnsharedConstpoolIndex().GetInt(), unsharedConstpool.GetTaggedValue()); } else { - constpool = JSHandle(vm->GetJSThread(), constpoolVal); + sconstpool = JSHandle(vm->GetJSThread(), constpoolVal); + unsharedConstpool = JSHandle( + vm->GetJSThread(), context->FindUnsharedConstpool(sconstpool.GetTaggedValue())); } if (!jsPandaFile->IsBundlePack()) { - ParseFuncAndLiteralConstPool(vm, jsPandaFile, entryPoint.data(), constpool); + ParseFuncAndLiteralConstPool(vm, jsPandaFile, entryPoint.data(), sconstpool, unsharedConstpool); } } MethodLiteral *mainMethodLiteral = jsPandaFile->FindMethodLiteral(mainMethodIndex); - return GenerateProgramInternal(vm, mainMethodLiteral, constpool); + return GenerateProgramInternal(vm, mainMethodLiteral, sconstpool); } JSHandle PandaFileTranslator::GenerateProgramInternal(EcmaVM *vm, @@ -142,12 +150,12 @@ JSHandle PandaFileTranslator::GenerateProgramInternal(EcmaVM *vm, program->SetMainFunction(thread, JSTaggedValue::Undefined()); } else { JSHandle env = vm->GetGlobalEnv(); - JSHandle method = factory->NewMethod(mainMethodLiteral); + JSHandle method = factory->NewSMethod(mainMethodLiteral); JSHandle hclass = JSHandle::Cast(env->GetFunctionClassWithProto()); JSHandle mainFunc = factory->NewJSFunctionByHClass(method, hclass); // Main function is created profileTypeInfo by default. if (thread->IsPGOProfilerEnable()) { - SlowRuntimeStub::NotifyInlineCache(thread, method.GetObject()); + SlowRuntimeStub::NotifyInlineCache(thread, mainFunc.GetObject()); } program->SetMainFunction(thread, mainFunc.GetTaggedValue()); method->SetConstantPool(thread, constpool); @@ -155,10 +163,12 @@ JSHandle PandaFileTranslator::GenerateProgramInternal(EcmaVM *vm, return program; } -JSHandle PandaFileTranslator::ParseConstPool(EcmaVM *vm, const JSPandaFile *jsPandaFile) +std::pair, JSHandle> PandaFileTranslator::ParseConstPool( + EcmaVM *vm, const JSPandaFile *jsPandaFile) { JSThread *thread = vm->GetJSThread(); ObjectFactory *factory = vm->GetFactory(); + JSHandle sconstpool = AllocateSharedConstPool(vm, jsPandaFile); JSHandle constpool = AllocateConstPool(vm, jsPandaFile); [[maybe_unused]] EcmaHandleScope handleScope(thread); @@ -169,7 +179,7 @@ JSHandle PandaFileTranslator::ParseConstPool(EcmaVM *vm, const JSP if (type == ConstPoolType::STRING) { panda_file::File::EntityId id(it.first); auto foundStr = jsPandaFile->GetStringData(id); - auto string = factory->GetRawStringFromStringTable(foundStr, MemSpaceType::OLD_SPACE, + auto string = factory->GetRawStringFromStringTable(foundStr, MemSpaceType::SHARED_OLD_SPACE, jsPandaFile->IsFirstMergedAbc(), it.first); constpool->SetObjectToCache(thread, value.GetConstpoolIndex(), JSTaggedValue(string)); } else if (type == ConstPoolType::OBJECT_LITERAL) { @@ -177,7 +187,7 @@ JSHandle PandaFileTranslator::ParseConstPool(EcmaVM *vm, const JSP JSMutableHandle elements(thread, JSTaggedValue::Undefined()); JSMutableHandle properties(thread, JSTaggedValue::Undefined()); LiteralDataExtractor::ExtractObjectDatas( - thread, jsPandaFile, index, elements, properties, constpool); + thread, jsPandaFile, index, elements, properties, sconstpool); JSHandle obj = JSObject::CreateObjectFromProperties(thread, properties); JSMutableHandle key(thread, JSTaggedValue::Undefined()); JSMutableHandle valueHandle(thread, JSTaggedValue::Undefined()); @@ -194,7 +204,7 @@ JSHandle PandaFileTranslator::ParseConstPool(EcmaVM *vm, const JSP } else if (type == ConstPoolType::ARRAY_LITERAL) { size_t index = static_cast(it.first); JSHandle literal = LiteralDataExtractor::GetDatasIgnoreType( - thread, jsPandaFile, index, constpool); + thread, jsPandaFile, index, sconstpool); uint32_t length = literal->GetLength(); JSHandle arr(JSArray::ArrayCreate(thread, JSTaggedNumber(length))); @@ -203,7 +213,7 @@ JSHandle PandaFileTranslator::ParseConstPool(EcmaVM *vm, const JSP } else if (type == ConstPoolType::CLASS_LITERAL) { size_t index = static_cast(it.first); JSHandle literal = LiteralDataExtractor::GetDatasIgnoreTypeForClass( - thread, jsPandaFile, index, constpool); + thread, jsPandaFile, index, sconstpool); JSHandle classLiteral = factory->NewClassLiteral(); classLiteral->SetArray(thread, literal); constpool->SetObjectToCache(thread, value.GetConstpoolIndex(), classLiteral.GetTaggedValue()); @@ -216,16 +226,17 @@ JSHandle PandaFileTranslator::ParseConstPool(EcmaVM *vm, const JSP ASSERT(methodLiteral != nullptr); methodLiteral->SetFunctionKind(JSPandaFile::GetFunctionKind(type)); - JSHandle method = factory->NewMethod(methodLiteral); + JSHandle method = factory->NewSMethod(methodLiteral); constpool->SetObjectToCache(thread, value.GetConstpoolIndex(), method.GetTaggedValue()); - method->SetConstantPool(thread, constpool.GetTaggedValue()); + method->SetConstantPool(thread, sconstpool.GetTaggedValue()); } } - return constpool; + return std::make_pair(sconstpool, constpool); } void PandaFileTranslator::ParseFuncAndLiteralConstPool(EcmaVM *vm, const JSPandaFile *jsPandaFile, const CString &entryPoint, + JSHandle sconstpool, JSHandle constpool) { auto &recordInfo = const_cast(jsPandaFile)->FindRecordInfo(entryPoint); @@ -247,7 +258,7 @@ void PandaFileTranslator::ParseFuncAndLiteralConstPool(EcmaVM *vm, const JSPanda JSMutableHandle elements(thread, JSTaggedValue::Undefined()); JSMutableHandle properties(thread, JSTaggedValue::Undefined()); LiteralDataExtractor::ExtractObjectDatas( - thread, jsPandaFile, index, elements, properties, constpool, entryPoint); + thread, jsPandaFile, index, elements, properties, sconstpool, entryPoint); JSHandle obj = JSObject::CreateObjectFromProperties(thread, properties); JSMutableHandle key(thread, JSTaggedValue::Undefined()); JSMutableHandle valueHandle(thread, JSTaggedValue::Undefined()); @@ -264,7 +275,7 @@ void PandaFileTranslator::ParseFuncAndLiteralConstPool(EcmaVM *vm, const JSPanda } else if (type == ConstPoolType::ARRAY_LITERAL) { size_t index = static_cast(it.first); JSHandle literal = LiteralDataExtractor::GetDatasIgnoreType( - thread, jsPandaFile, index, constpool, entryPoint); + thread, jsPandaFile, index, sconstpool, entryPoint); uint32_t length = literal->GetLength(); JSHandle arr(JSArray::ArrayCreate(thread, JSTaggedNumber(length))); arr->SetElements(thread, literal); @@ -272,7 +283,7 @@ void PandaFileTranslator::ParseFuncAndLiteralConstPool(EcmaVM *vm, const JSPanda } else if (type == ConstPoolType::CLASS_LITERAL) { size_t index = static_cast(it.first); JSHandle literal = LiteralDataExtractor::GetDatasIgnoreTypeForClass( - thread, jsPandaFile, index, constpool, entryPoint); + thread, jsPandaFile, index, sconstpool, entryPoint); JSHandle classLiteral = factory->NewClassLiteral(); classLiteral->SetArray(thread, literal); constpool->SetObjectToCache(thread, value.GetConstpoolIndex(), classLiteral.GetTaggedValue()); @@ -285,20 +296,33 @@ void PandaFileTranslator::ParseFuncAndLiteralConstPool(EcmaVM *vm, const JSPanda ASSERT(methodLiteral != nullptr); methodLiteral->SetFunctionKind(JSPandaFile::GetFunctionKind(type)); - JSHandle method = factory->NewMethod(methodLiteral); + JSHandle method = factory->NewSMethod(methodLiteral); constpool->SetObjectToCache(thread, value.GetConstpoolIndex(), method.GetTaggedValue()); - method->SetConstantPool(thread, constpool.GetTaggedValue()); + method->SetConstantPool(thread, sconstpool.GetTaggedValue()); } } recordInfo.SetParsedConstpoolVM(vm); } +JSHandle PandaFileTranslator::AllocateSharedConstPool(EcmaVM *vm, const JSPandaFile *jsPandaFile) +{ + ObjectFactory *factory = vm->GetFactory(); + EcmaContext *context = vm->GetJSThread()->GetCurrentEcmaContext(); + uint32_t constpoolIndex = jsPandaFile->GetConstpoolIndex(); + JSHandle sconstpool = factory->NewSConstantPool(constpoolIndex); + sconstpool->SetJSPandaFile(jsPandaFile); + sconstpool->SetUnsharedConstpoolIndex(JSTaggedValue(context->GetAndIncreaseUnsharedConstpoolCount())); + sconstpool->SetSharedConstpoolId(JSTaggedValue(0)); // 0 :old version has one constpool. + return sconstpool; +} + JSHandle PandaFileTranslator::AllocateConstPool(EcmaVM *vm, const JSPandaFile *jsPandaFile) { ObjectFactory *factory = vm->GetFactory(); uint32_t constpoolIndex = jsPandaFile->GetConstpoolIndex(); JSHandle constpool = factory->NewConstantPool(constpoolIndex); constpool->SetJSPandaFile(jsPandaFile); + constpool->SetUnsharedConstpoolIndex(JSTaggedValue(ConstantPool::CONSTPOOL_TYPE_FLAG)); return constpool; } diff --git a/ecmascript/jspandafile/panda_file_translator.h b/ecmascript/jspandafile/panda_file_translator.h index acc812babfd05c3c2b643051edf606d836e87666..b7eb66295c31a166f8a9742613796d1583be68f3 100644 --- a/ecmascript/jspandafile/panda_file_translator.h +++ b/ecmascript/jspandafile/panda_file_translator.h @@ -47,10 +47,12 @@ private: static void FixInstructionId32(const OldBytecodeInst &inst, uint32_t index, uint32_t fixOrder = 0); static void FixOpcode(MethodLiteral *method, const OldBytecodeInst &inst); static void UpdateICOffset(MethodLiteral *method, uint8_t *pc); - static JSHandle ParseConstPool(EcmaVM *vm, const JSPandaFile *jsPandaFile); + static std::pair, JSHandle> ParseConstPool( + EcmaVM *vm, const JSPandaFile *jsPandaFile); static void ParseFuncAndLiteralConstPool(EcmaVM *vm, const JSPandaFile *jsPandaFile, const CString &entryPoint, - JSHandle constpool); + JSHandle sconstpool, JSHandle constpool); static JSHandle AllocateConstPool(EcmaVM *vm, const JSPandaFile *jsPandaFile); + static JSHandle AllocateSharedConstPool(EcmaVM *vm, const JSPandaFile *jsPandaFile); friend class PatchLoader; }; diff --git a/ecmascript/jspandafile/program_object.h b/ecmascript/jspandafile/program_object.h index 61ca128a3c2ddcb00f19c716fe864200f64bdf84..830243d56b9e223f1240e72d1cb54322ae072b3a 100644 --- a/ecmascript/jspandafile/program_object.h +++ b/ecmascript/jspandafile/program_object.h @@ -16,6 +16,7 @@ #ifndef ECMASCRIPT_JSPANDAFILE_PROGRAM_OBJECT_H #define ECMASCRIPT_JSPANDAFILE_PROGRAM_OBJECT_H +#include #include "ecmascript/compiler/aot_file/aot_file_manager.h" #include "ecmascript/ecma_macros.h" #include "ecmascript/global_env.h" @@ -26,6 +27,7 @@ #include "ecmascript/jspandafile/js_pandafile_manager.h" #include "ecmascript/jspandafile/literal_data_extractor.h" #include "ecmascript/module/js_module_manager.h" +#include "ecmascript/module/js_shared_module.h" #include "ecmascript/patch/quick_fix_manager.h" #include "ecmascript/pgo_profiler/pgo_profiler.h" @@ -59,6 +61,10 @@ public: * | object literal(JSObject) | | * | class literal(ClassLiteral) | v * +--------------------------------+---- + * | unshared constpool index |int32_t + * +--------------------------------+---- + * | shared constpool id |int32_t + * +--------------------------------+---- * | AOTHClassInfo |TaggedArray * +--------------------------------+---- * | AOTArrayInfo |TaggedArray @@ -77,9 +83,15 @@ public: static constexpr size_t CONSTANT_INDEX_INFO_INDEX = 3; static constexpr size_t AOT_ARRAY_INFO_INDEX = 4; static constexpr size_t AOT_HCLASS_INFO_INDEX = 5; + static constexpr size_t UNSHARED_CONSTPOOL_INDEX = 6; + static constexpr size_t SHARED_CONSTPOOL_ID = 7; static constexpr size_t RESERVED_POOL_LENGTH = INDEX_HEADER_INDEX; // divide the gc area - static constexpr size_t EXTEND_DATA_NUM = 3; // AOTHClassInfo, AOTArrayInfo, ConstIndexInfo + // AOTHClassInfo, AOTArrayInfo, ConstIndexInfo, unsharedConstpoolIndex, constpoolId + static constexpr size_t EXTEND_DATA_NUM = 5; + + static constexpr int32_t CONSTPOOL_TYPE_FLAG = INT32_MAX; // INT32_MAX : unshared constpool. + static constexpr int32_t CONSTPOOL_INVALID_ID = 0; static ConstantPool *Cast(TaggedObject *object) { @@ -87,8 +99,8 @@ public: return static_cast(object); } - static JSHandle CreateConstPool(EcmaVM *vm, const JSPandaFile *jsPandaFile, - panda_file::File::EntityId id) + static JSHandle CreateUnSharedConstPool(EcmaVM *vm, const JSPandaFile *jsPandaFile, + panda_file::File::EntityId id) { const panda_file::File::IndexHeader *mainIndex = jsPandaFile->GetPandaFile()->GetIndexHeader(id); LOG_ECMA_IF(mainIndex == nullptr, FATAL) << "Unknown methodId: " << id.GetOffset(); @@ -117,6 +129,132 @@ public: return constpool; } + static JSHandle CreateUnSharedConstPoolBySharedConstpool( + EcmaVM *vm, const JSPandaFile *jsPandaFile, ConstantPool *shareCp) + { + const panda_file::File::IndexHeader *mainIndex = shareCp->GetIndexHeader(); + auto constpoolSize = mainIndex->method_idx_size; + + JSHandle constpool(vm->GetJSThread(), JSTaggedValue::Hole()); + bool isLoadedAOT = jsPandaFile->IsLoadedAOT(); + if (isLoadedAOT) { +#if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) + int32_t cpId = shareCp->GetSharedConstpoolId().GetInt(); + constpool = GetDeserializedConstantPool(vm, jsPandaFile, cpId); +#else + LOG_FULL(FATAL) << "Aot don't support Windows and MacOS platform"; + UNREACHABLE(); +#endif + } + if (constpool.GetTaggedValue().IsHole()) { + ObjectFactory *factory = vm->GetFactory(); + constpool = factory->NewConstantPool(constpoolSize); + } + + constpool->SetJSPandaFile(jsPandaFile); + constpool->SetIndexHeader(mainIndex); + + return constpool; + } + + static JSHandle CreateSharedConstPool(EcmaVM *vm, const JSPandaFile *jsPandaFile, + panda_file::File::EntityId id, + int32_t unsharedConstpoolIndex = 0, + int32_t cpId = 0) + { + const panda_file::File::IndexHeader *mainIndex = jsPandaFile->GetPandaFile()->GetIndexHeader(id); + LOG_ECMA_IF(mainIndex == nullptr, FATAL) << "Unknown methodId: " << id.GetOffset(); + auto constpoolSize = mainIndex->method_idx_size; + + JSHandle constpool(vm->GetJSThread(), JSTaggedValue::Hole()); + if (constpool.GetTaggedValue().IsHole()) { + ObjectFactory *factory = vm->GetFactory(); + constpool = factory->NewSConstantPool(constpoolSize); + } + + constpool->SetJSPandaFile(jsPandaFile); + constpool->SetIndexHeader(mainIndex); + constpool->SetUnsharedConstpoolIndex(JSTaggedValue(unsharedConstpoolIndex)); + constpool->SetSharedConstpoolId(JSTaggedValue(cpId)); + + return constpool; + } + + static JSHandle CreateSharedConstPoolForAOT( + EcmaVM *vm, JSHandle constpool, int32_t unsharedConstpoolIndex = 0, int32_t cpId = 0) + { + JSHandle sconstpool(vm->GetJSThread(), JSTaggedValue::Hole()); + uint32_t capacity = constpool->GetConstpoolSize(); + if (sconstpool.GetTaggedValue().IsHole()) { + ObjectFactory *factory = vm->GetFactory(); + sconstpool = factory->NewSConstantPool(capacity); + } + + for (uint32_t i = 0; i < capacity; i++) { + JSTaggedValue val = constpool->GetObjectFromCache(i); + JSThread *thread = vm->GetJSThread(); + if (val.IsString()) { + sconstpool->SetObjectToCache(thread, i, val); + } else if (val.IsAOTLiteralInfo() && (AOTLiteralInfo::Cast(val.GetTaggedObject())-> + GetLiteralType() == AOTLiteralInfo::METHOD_LITERAL_TYPE)) { + JSHandle valHandle(thread, val); + JSHandle methodLiteral = CopySharedMethodAOTLiteralInfo(vm, valHandle); + sconstpool->SetObjectToCache(thread, i, methodLiteral.GetTaggedValue()); + } + } + + JSHandle array(vm->GetJSThread()->GlobalConstants()->GetHandledEmptyArray()); + sconstpool->SetAotHClassInfo(array.GetTaggedValue()); + sconstpool->SetAotArrayInfo(array.GetTaggedValue()); + sconstpool->SetConstantIndexInfo(array.GetTaggedValue()); + sconstpool->SetJSPandaFile(constpool->GetJSPandaFile()); + sconstpool->SetIndexHeader(constpool->GetIndexHeader()); + sconstpool->SetUnsharedConstpoolIndex(JSTaggedValue(unsharedConstpoolIndex)); + sconstpool->SetSharedConstpoolId(JSTaggedValue(cpId)); + return sconstpool; + } + + static JSHandle CopySharedMethodAOTLiteralInfo(EcmaVM *vm, + JSHandle methodLiteralInfo) + { + ObjectFactory *factory = vm->GetFactory(); + JSHandle SAOTLiteralInfo = factory->NewSAOTLiteralInfo(1); + for (uint32_t i = 0; i < methodLiteralInfo->GetCacheLength(); i++) { + SAOTLiteralInfo->SetObjectToCache(vm->GetJSThread(), i, methodLiteralInfo->GetObjectFromCache(i)); + } + SAOTLiteralInfo->SetLiteralType(JSTaggedValue(methodLiteralInfo->GetLiteralType())); + return SAOTLiteralInfo; + } + + static bool CheckUnsharedConstpool(JSTaggedValue constpool) + { + int32_t index = ConstantPool::Cast(constpool.GetTaggedObject())->GetUnsharedConstpoolIndex().GetInt(); + if (index == CONSTPOOL_TYPE_FLAG) { + return true; + } + return false; + } + + inline void SetUnsharedConstpoolIndex(const JSTaggedValue index) + { + Barriers::SetPrimitive(GetData(), GetUnsharedConstpoolIndexOffset(), index); + } + + inline JSTaggedValue GetUnsharedConstpoolIndex() const + { + return Barriers::GetValue(GetData(), GetUnsharedConstpoolIndexOffset()); + } + + inline void SetSharedConstpoolId(const JSTaggedValue index) + { + Barriers::SetPrimitive(GetData(), GetSharedConstpoolIdOffset(), index); + } + + inline JSTaggedValue GetSharedConstpoolId() const + { + return Barriers::GetValue(GetData(), GetSharedConstpoolIdOffset()); + } + panda_file::File::EntityId GetEntityId(uint32_t index) const { JSPandaFile *jsPandaFile = GetJSPandaFile(); @@ -171,6 +309,8 @@ public: SetConstantIndexInfo(array.GetTaggedValue()); SetJSPandaFile(nullptr); SetIndexHeader(nullptr); + SetUnsharedConstpoolIndex(JSTaggedValue(CONSTPOOL_TYPE_FLAG)); + SetSharedConstpoolId(JSTaggedValue(CONSTPOOL_INVALID_ID)); } inline uint32_t GetCacheLength() const @@ -178,6 +318,11 @@ public: return GetLength() - RESERVED_POOL_LENGTH; } + inline uint32_t GetConstpoolSize() const + { + return GetLength() - RESERVED_POOL_LENGTH - EXTEND_DATA_NUM; + } + inline void SetJSPandaFile(const void *jsPandaFile) { Barriers::SetPrimitive(GetData(), GetJSPandaFileOffset(), jsPandaFile); @@ -213,13 +358,30 @@ public: Set(thread, index, value); } + static void CASSetObjectToCache( + JSThread *thread, const JSTaggedValue constpool, uint32_t index, JSTaggedValue value) + { + const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject()); + JSHandle constpoolHandle(thread, constpool); + std::atomic *atomicVal = reinterpret_cast *>( + reinterpret_cast(taggedPool) + DATA_OFFSET + index * JSTaggedValue::TaggedTypeSize()); + JSTaggedValue tempVal = taggedPool->GetObjectFromCache(index); + JSTaggedValue expected = taggedPool->GetJSPandaFile()->IsLoadedAOT() && tempVal.IsAOTLiteralInfo() ? + tempVal : JSTaggedValue::Hole(); + JSTaggedValue desired = value; + if (std::atomic_compare_exchange_strong_explicit(atomicVal, &expected, desired, + std::memory_order_release, std::memory_order_relaxed)) { + // set val by Barrier. + constpoolHandle->SetObjectToCache(thread, index, value); + } + } + inline JSTaggedValue GetObjectFromCache(uint32_t index) const { return Get(index); } - static JSTaggedValue GetMethodFromCache( - JSThread *thread, JSTaggedValue constpool, JSTaggedValue module, uint32_t index) + static JSTaggedValue GetMethodFromCache(JSThread *thread, JSTaggedValue constpool, uint32_t index) { const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject()); auto val = taggedPool->GetObjectFromCache(index); @@ -243,19 +405,25 @@ public: return val; } + if (!taggedPool->GetJSPandaFile()->IsNewVersion()) { + JSTaggedValue unsharedCp = thread->GetCurrentEcmaContext()->FindUnsharedConstpool(constpool); + taggedPool = ConstantPool::Cast(unsharedCp.GetTaggedObject()); + return taggedPool->Get(index); + } + [[maybe_unused]] EcmaHandleScope handleScope(thread); ASSERT(jsPandaFile->IsNewVersion()); JSHandle constpoolHandle(thread, constpool); - JSHandle moduleHandle(thread, module); EcmaVM *vm = thread->GetEcmaVM(); EntityId id = constpoolHandle->GetEntityId(index); MethodLiteral *methodLiteral = jsPandaFile->FindMethodLiteral(id.GetOffset()); ASSERT(methodLiteral != nullptr); ObjectFactory *factory = vm->GetFactory(); - JSHandle method = factory->NewMethod(jsPandaFile, methodLiteral, constpoolHandle, moduleHandle, - entryIndex, isLoadedAOT && hasEntryIndex); - constpoolHandle->SetObjectToCache(thread, index, method.GetTaggedValue()); + JSHandle method = factory->NewSMethod( + jsPandaFile, methodLiteral, constpoolHandle, entryIndex, isLoadedAOT && hasEntryIndex); + + CASSetObjectToCache(thread, constpool, index, method.GetTaggedValue()); return method.GetTaggedValue(); } @@ -265,8 +433,7 @@ public: [[maybe_unused]] EcmaHandleScope handleScope(thread); // Do not use cache when sendable for get wrong obj from cache, // shall be fix or refactor during shared object implements - JSTaggedValue val = (kind == ClassKind::NON_SENDABLE) ? constpool->GetObjectFromCache(literal) : - JSTaggedValue::Hole(); + JSTaggedValue val = constpool->GetObjectFromCache(literal); JSPandaFile *jsPandaFile = constpool->GetJSPandaFile(); // For AOT @@ -284,12 +451,20 @@ public: panda_file::File::EntityId literalId = constpool->GetEntityId(literal); bool needSetAotFlag = isLoadedAOT && !entryIndexes.GetTaggedValue().IsUndefined(); JSHandle literalArray = LiteralDataExtractor::GetDatasIgnoreType( - thread, jsPandaFile, literalId, constpool, entry, needSetAotFlag, entryIndexes, nullptr, - kind); - JSHandle classLiteral = factory->NewClassLiteral(); + thread, jsPandaFile, literalId, constpool, entry, needSetAotFlag, entryIndexes, nullptr, kind); + JSHandle classLiteral; + if (kind == ClassKind::SENDABLE) { + classLiteral = factory->NewSClassLiteral(); + } else { + classLiteral = factory->NewClassLiteral(); + } classLiteral->SetArray(thread, literalArray); val = classLiteral.GetTaggedValue(); - constpool->SetObjectToCache(thread, literal, val); + if (kind == ClassKind::SENDABLE) { + CASSetObjectToCache(thread, constpool.GetTaggedValue(), literal, val); + } else { + constpool->SetObjectToCache(thread, literal, val); + } } return val; @@ -449,6 +624,11 @@ public: const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject()); auto val = taggedPool->Get(index); if (val.IsHole()) { + if (!taggedPool->GetJSPandaFile()->IsNewVersion()) { + JSTaggedValue unsharedCp = thread->GetCurrentEcmaContext()->FindUnsharedConstpool(constpool); + taggedPool = ConstantPool::Cast(unsharedCp.GetTaggedObject()); + return taggedPool->Get(index); + } [[maybe_unused]] EcmaHandleScope handleScope(thread); JSPandaFile *jsPandaFile = taggedPool->GetJSPandaFile(); @@ -458,11 +638,11 @@ public: EcmaVM *vm = thread->GetEcmaVM(); ObjectFactory *factory = vm->GetFactory(); JSHandle constpoolHandle(thread, constpool); - auto string = factory->GetRawStringFromStringTable(foundStr, MemSpaceType::OLD_SPACE, + auto string = factory->GetRawStringFromStringTable(foundStr, MemSpaceType::SHARED_OLD_SPACE, jsPandaFile->IsFirstMergedAbc(), id.GetOffset()); val = JSTaggedValue(string); - constpoolHandle->SetObjectToCache(thread, index, val); + CASSetObjectToCache(thread, constpool, index, val); } return val; @@ -498,6 +678,16 @@ private: return JSTaggedValue::TaggedTypeSize() * (GetLength() - AOT_HCLASS_INFO_INDEX); } + inline size_t GetUnsharedConstpoolIndexOffset() const + { + return JSTaggedValue::TaggedTypeSize() * (GetLength() - UNSHARED_CONSTPOOL_INDEX); + } + + inline size_t GetSharedConstpoolIdOffset() const + { + return JSTaggedValue::TaggedTypeSize() * (GetLength() - SHARED_CONSTPOOL_ID); + } + inline size_t GetLastOffset() const { return JSTaggedValue::TaggedTypeSize() * GetLength() + DATA_OFFSET; diff --git a/ecmascript/jspandafile/tests/js_pandafile_executor_test.cpp b/ecmascript/jspandafile/tests/js_pandafile_executor_test.cpp index 34f0a79de40bc8fdafbbe71cfcc7a7882e45f817..0fea531e3f1a0d99117b9d883489f749ef770db0 100644 --- a/ecmascript/jspandafile/tests/js_pandafile_executor_test.cpp +++ b/ecmascript/jspandafile/tests/js_pandafile_executor_test.cpp @@ -43,12 +43,12 @@ public: void SetUp() override { - TestHelper::CreateEcmaVMWithScope(instance, thread, scope); + TestHelper::CreateEcmaVMWithScope(instance, thread, scope, false, false, false); } void TearDown() override { - TestHelper::DestroyEcmaVMWithScope(instance, scope); + TestHelper::DestroyEcmaVMWithScope(instance, scope, false); } EcmaVM *instance {nullptr}; diff --git a/ecmascript/jspandafile/tests/js_pandafile_manager_test.cpp b/ecmascript/jspandafile/tests/js_pandafile_manager_test.cpp index 2038aff0ee3011224bfe300f464890b8ef088a1d..d222fa2016358e84fbc50db74f83ebcda7ef3bcf 100644 --- a/ecmascript/jspandafile/tests/js_pandafile_manager_test.cpp +++ b/ecmascript/jspandafile/tests/js_pandafile_manager_test.cpp @@ -153,21 +153,23 @@ HWTEST_F_L0(JSPandaFileManagerTest, MultiEcmaVM_Add_Find_Remove_JSPandaFile) pfManager->AddJSPandaFileVm(instance, pf1); pfManager->AddJSPandaFileVm(instance, pf2); - JSHandle constpool1 = instance->GetFactory()->NewConstantPool(1); - JSHandle constpool2 = instance->GetFactory()->NewConstantPool(2); + JSHandle constpool1 = instance->GetFactory()->NewSConstantPool(1); + JSHandle constpool2 = instance->GetFactory()->NewSConstantPool(2); instance->GetJSThread()->GetCurrentEcmaContext()->AddConstpool(pf1.get(), constpool1.GetTaggedValue(), 0); instance->GetJSThread()->GetCurrentEcmaContext()->AddConstpool(pf2.get(), constpool2.GetTaggedValue(), 0); - EcmaVM *instance1; - EcmaHandleScope *scope1; - JSThread *thread1; - TestHelper::CreateEcmaVMWithScope(instance1, thread1, scope1); - - std::shared_ptr loadedPf1 = - pfManager->LoadJSPandaFile(thread1, filename1, JSPandaFile::ENTRY_MAIN_FUNCTION); - instance1->GetJSThread()->GetCurrentEcmaContext()->AddConstpool(pf1.get(), constpool1.GetTaggedValue(), 0); - EXPECT_TRUE(pf1 == loadedPf1); - TestHelper::DestroyEcmaVMWithScope(instance1, scope1); // Remove 'instance1' when ecmaVM destruct. + std::thread t1([&]() { + EcmaVM *instance1; + EcmaHandleScope *scope1; + JSThread *thread1; + TestHelper::CreateEcmaVMWithScope(instance1, thread1, scope1); + std::shared_ptr loadedPf1 = + pfManager->LoadJSPandaFile(thread1, filename1, JSPandaFile::ENTRY_MAIN_FUNCTION); + instance1->GetJSThread()->GetCurrentEcmaContext()->AddConstpool(pf1.get(), constpool1.GetTaggedValue(), 0); + EXPECT_TRUE(pf1 == loadedPf1); + TestHelper::DestroyEcmaVMWithScope(instance1, scope1); // Remove 'instance1' when ecmaVM destruct. + }); + t1.join(); std::shared_ptr foundPf1 = pfManager->FindJSPandaFile(filename1); EXPECT_TRUE(foundPf1 != nullptr); @@ -194,8 +196,13 @@ void CreateJSPandaFileAndConstpool(EcmaVM *vm) pfManager->AddJSPandaFileVm(vm, pf); [[maybe_unused]] EcmaHandleScope handleScope(vm->GetJSThread()); - JSHandle constpool = vm->GetFactory()->NewConstantPool(1); - vm->GetJSThread()->GetCurrentEcmaContext()->AddConstpool(pf.get(), constpool.GetTaggedValue(), 0); + JSHandle constpool = vm->GetFactory()->NewSConstantPool(1); + auto context = vm->GetJSThread()->GetCurrentEcmaContext(); + auto unsharedConstpoolIndex = context->GetAndIncreaseUnsharedConstpoolCount(); + JSHandle newConstpool = vm->GetFactory()->NewConstantPool(1); + constpool->SetUnsharedConstpoolIndex(JSTaggedValue(unsharedConstpoolIndex)); + context->SetUnsharedConstpool(unsharedConstpoolIndex, newConstpool.GetTaggedValue()); + context->AddConstpool(pf.get(), constpool.GetTaggedValue(), 0); } HWTEST_F_L0(JSPandaFileManagerTest, GC_Add_Find_Remove_JSPandaFile) @@ -204,8 +211,9 @@ HWTEST_F_L0(JSPandaFileManagerTest, GC_Add_Find_Remove_JSPandaFile) JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance(); CreateJSPandaFileAndConstpool(instance); - instance->CollectGarbage(ecmascript::TriggerGCType::FULL_GC); // Remove 'instance' and JSPandafile when trigger GC. - + // Remove 'instance' and JSPandafile when trigger GC. + SharedHeap::GetInstance()->CollectGarbage(instance->GetJSThread(), ecmascript::TriggerGCType::SHARED_GC, + GCReason::OTHER); std::shared_ptr afterRemovePf = pfManager->FindJSPandaFile(filename); EXPECT_EQ(afterRemovePf, nullptr); } diff --git a/ecmascript/jspandafile/tests/quick_fix_test.cpp b/ecmascript/jspandafile/tests/quick_fix_test.cpp index b20da18f5fa4a65f6cc06c31c5df39fccfe5aa8b..820dccf178d3c475eba7833807c677c5d96bfd14 100644 --- a/ecmascript/jspandafile/tests/quick_fix_test.cpp +++ b/ecmascript/jspandafile/tests/quick_fix_test.cpp @@ -42,12 +42,12 @@ public: void SetUp() override { - TestHelper::CreateEcmaVMWithScope(instance, thread, scope); + TestHelper::CreateEcmaVMWithScope(instance, thread, scope, false, false, false); } void TearDown() override { - TestHelper::DestroyEcmaVMWithScope(instance, scope); + TestHelper::DestroyEcmaVMWithScope(instance, scope, false); } EcmaVM *instance {nullptr}; diff --git a/ecmascript/mem/allocator-inl.h b/ecmascript/mem/allocator-inl.h index 5242a3b2844122c0c6b9a9a455d984cc5d3da838..ae44aa983b163e1677da117719bce07d89a329d5 100644 --- a/ecmascript/mem/allocator-inl.h +++ b/ecmascript/mem/allocator-inl.h @@ -67,7 +67,7 @@ uintptr_t BumpPointerAllocator::Allocate(size_t size) return result; } -FreeListAllocator::FreeListAllocator(Heap *heap) : heap_(heap) +FreeListAllocator::FreeListAllocator(BaseHeap *heap) : heap_(heap) { freeList_ = std::make_unique(); } @@ -77,7 +77,7 @@ void FreeListAllocator::Initialize(Region *region) bpAllocator_.Reset(region->GetBegin(), region->GetEnd()); } -void FreeListAllocator::Reset(Heap *heap) +void FreeListAllocator::Reset(BaseHeap *heap) { heap_ = heap; freeList_ = std::make_unique(); @@ -137,7 +137,7 @@ void FreeListAllocator::FillBumpPointer() { size_t size = bpAllocator_.Available(); if (size != 0) { - FreeObject::FillFreeObject(heap_->GetEcmaVM(), bpAllocator_.GetTop(), size); + FreeObject::FillFreeObject(heap_, bpAllocator_.GetTop(), size); } } @@ -157,7 +157,7 @@ void FreeListAllocator::Free(uintptr_t begin, size_t size, bool isAdd) ASSERT(heap_ != nullptr); ASSERT(size >= 0); if (size != 0) { - FreeObject::FillFreeObject(heap_->GetEcmaVM(), begin, size); + FreeObject::FillFreeObject(heap_, begin, size); ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast(begin), size); freeList_->Free(begin, size, isAdd); ASAN_POISON_MEMORY_REGION(reinterpret_cast(begin), size); diff --git a/ecmascript/mem/allocator.h b/ecmascript/mem/allocator.h index faab338c644cd86ba88846ba28313ff4b8426a86..deebc4db36621a3a2ca109efa17287eb455fee4c 100644 --- a/ecmascript/mem/allocator.h +++ b/ecmascript/mem/allocator.h @@ -23,7 +23,7 @@ namespace panda::ecmascript { class Region; -class Heap; +class BaseHeap; class Allocator { public: @@ -87,10 +87,10 @@ public: NO_COPY_SEMANTIC(FreeListAllocator); NO_MOVE_SEMANTIC(FreeListAllocator); - inline explicit FreeListAllocator(Heap *heap); + inline explicit FreeListAllocator(BaseHeap *heap); inline void Initialize(Region *region); - inline void Reset(Heap *heap); + inline void Reset(BaseHeap *heap); inline uintptr_t Allocate(size_t size); inline void AddFree(Region *region); @@ -134,7 +134,7 @@ private: BumpPointerAllocator bpAllocator_; std::unique_ptr freeList_ {nullptr}; - Heap *heap_{nullptr}; + BaseHeap *heap_{nullptr}; size_t allocationSizeAccumulator_ {0}; }; } // namespace panda::ecmascript diff --git a/ecmascript/mem/barriers-inl.h b/ecmascript/mem/barriers-inl.h index 6e78c73b1d8f4312b3cb75d7a78376d3b6101d48..8ee9ff0e778b98b103e8834beed6557b4ca1409c 100644 --- a/ecmascript/mem/barriers-inl.h +++ b/ecmascript/mem/barriers-inl.h @@ -40,8 +40,10 @@ static ARK_INLINE void WriteBarrier(const JSThread *thread, void *obj, size_t of // Should align with '8' in 64 and 32 bit platform ASSERT((slotAddr % static_cast(MemAlignment::MEM_ALIGN_OBJECT)) == 0); objectRegion->InsertOldToNewRSet(slotAddr); + } else if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) { + objectRegion->AtomicInsertLocalToShareRSet(slotAddr); } - + ASSERT(!objectRegion->InSharedHeap() || valueRegion->InSharedHeap()); if (thread->IsConcurrentMarkingOrFinished()) { Barriers::Update(thread, slotAddr, objectRegion, reinterpret_cast(value), valueRegion, writeType); diff --git a/ecmascript/mem/barriers.cpp b/ecmascript/mem/barriers.cpp index 1ee1161447a9342bc3679aed37dea1c6f3e257e9..fd2a5516ef88a9ae4755b77b40cfffbd7f03eff8 100644 --- a/ecmascript/mem/barriers.cpp +++ b/ecmascript/mem/barriers.cpp @@ -21,6 +21,9 @@ namespace panda::ecmascript { void Barriers::Update(const JSThread *thread, uintptr_t slotAddr, Region *objectRegion, TaggedObject *value, Region *valueRegion, WriteBarrierType writeType) { + if (valueRegion->InSharedHeap()) { + return; + } auto heap = thread->GetEcmaVM()->GetHeap(); if (heap->IsConcurrentFullMark()) { if (valueRegion->InCollectSet() && !objectRegion->InYoungSpaceOrCSet()) { diff --git a/ecmascript/mem/concurrent_sweeper.cpp b/ecmascript/mem/concurrent_sweeper.cpp index c58930602b51781289a1d48ea29d37a48d187843..0bda8fda82fa6cbda69d8b893642ffa43bc5e56a 100644 --- a/ecmascript/mem/concurrent_sweeper.cpp +++ b/ecmascript/mem/concurrent_sweeper.cpp @@ -98,7 +98,6 @@ void ConcurrentSweeper::WaitAllTaskFinished() void ConcurrentSweeper::EnsureAllTaskFinished() { - CHECK_JS_THREAD(heap_->GetEcmaVM()); if (!isSweeping_) { return; } @@ -152,6 +151,7 @@ void ConcurrentSweeper::ClearRSetInRange(Region *current, uintptr_t freeStart, u } else { current->ClearOldToNewRSetInRange(freeStart, freeEnd); } + current->AtomicClearLocalToShareRSetInRange(freeStart, freeEnd); current->ClearCrossRegionRSetInRange(freeStart, freeEnd); } diff --git a/ecmascript/mem/full_gc.cpp b/ecmascript/mem/full_gc.cpp index 40a7a25a44068a7492e6cb4e1e98df021a047fb2..e3954f452a7e016edbcd1d983c87fa3810d54286 100644 --- a/ecmascript/mem/full_gc.cpp +++ b/ecmascript/mem/full_gc.cpp @@ -25,6 +25,7 @@ #include "ecmascript/mem/mem.h" #include "ecmascript/mem/parallel_marker-inl.h" #include "ecmascript/mem/space-inl.h" +#include "ecmascript/mem/verification.h" #include "ecmascript/mem/visitor.h" #include "ecmascript/mem/gc_stats.h" #include "ecmascript/ecma_string_table.h" @@ -56,6 +57,11 @@ void FullGC::RunPhases() Mark(); Sweep(); Finish(); + if (UNLIKELY(heap_->ShouldVerifyHeap())) { + // verify mark + LOG_ECMA(DEBUG) << "start verify post fullgc"; + Verification(heap_, VerifyKind::VERIFY_SHARED_RSET_POST_FULL_GC).VerifyAll(); + } heap_->NotifyHeapAliveSizeAfterGC(heap_->GetHeapObjectSize()); } @@ -124,7 +130,7 @@ void FullGC::Sweep() Region *objectRegion = Region::ObjectAddressToRange(header); if (!HasEvacuated(objectRegion)) { - if (!objectRegion->Test(header)) { + if (!objectRegion->InSharedHeap() && !objectRegion->Test(header)) { slot.Clear(); } } else { @@ -140,7 +146,6 @@ void FullGC::Sweep() } } - auto stringTable = heap_->GetEcmaVM()->GetEcmaStringTable(); WeakRootVisitor gcUpdateWeak = [this](TaggedObject *header) { Region *objectRegion = Region::ObjectAddressToRange(header); if (!objectRegion) { @@ -148,7 +153,8 @@ void FullGC::Sweep() return reinterpret_cast(ToUintPtr(nullptr)); } if (!HasEvacuated(objectRegion)) { - if (objectRegion->Test(header)) { + // The weak object in shared heap is always alive during fullGC. + if (objectRegion->InSharedHeap() || objectRegion->Test(header)) { return header; } return reinterpret_cast(ToUintPtr(nullptr)); @@ -160,7 +166,6 @@ void FullGC::Sweep() } return reinterpret_cast(ToUintPtr(nullptr)); }; - stringTable->SweepWeakReference(gcUpdateWeak); heap_->GetEcmaVM()->GetJSThread()->IterateWeakEcmaGlobalStorage(gcUpdateWeak); heap_->GetEcmaVM()->ProcessReferences(gcUpdateWeak); diff --git a/ecmascript/mem/gc_stats.cpp b/ecmascript/mem/gc_stats.cpp index d6d63f2c9e06399858a9b1a40b75dc02c56d07b2..ebb275e0253ccb24ef7a784dfe97fa879e7f6dae 100644 --- a/ecmascript/mem/gc_stats.cpp +++ b/ecmascript/mem/gc_stats.cpp @@ -533,7 +533,7 @@ void GCStats::RecordGCSpeed() GCType GCStats::GetGCType(TriggerGCType gcType) { - if (!heap_->GetJSThread()->IsReadyToMark()) { + if (heap_ && !heap_->IsReadyToMark()) { return heap_->IsConcurrentFullMark() ? GCType::PARTIAL_OLD_GC : GCType::PARTIAL_YOUNG_GC; } switch (gcType) { @@ -543,6 +543,8 @@ GCType GCStats::GetGCType(TriggerGCType gcType) return GCType::PARTIAL_OLD_GC; case TriggerGCType::FULL_GC: return GCType::COMPRESS_GC; + case TriggerGCType::SHARED_GC: + return GCType::SHARED_GC; default: return GCType::OTHER; } @@ -564,4 +566,123 @@ bool GCStats::CheckIfLongTimePause() } return false; } + +void SharedGCStats::PrintStatisticResult() +{ + LOG_GC(INFO) << "/******************* SharedGCStats statistic: *******************/"; + PrintSharedGCSummaryStatistic(); + PrintGCMemoryStatistic(); +} + +void SharedGCStats::PrintGCStatistic() +{ + if (enableGCTracer_) { + LOG_GC(INFO) << " [ " << GetGCTypeName() << " ] " + << sizeToMB(recordData_[(uint8_t)RecordData::START_OBJ_SIZE]) << " (" + << sizeToMB(recordData_[(uint8_t)RecordData::START_COMMIT_SIZE]) << ") -> " + << sizeToMB(recordData_[(uint8_t)RecordData::END_OBJ_SIZE]) << " (" + << sizeToMB(recordData_[(uint8_t)RecordData::END_COMMIT_SIZE]) << ") MB, " + << scopeDuration_[Scope::ScopeId::TotalGC] << "ms, " << GCReasonToString(); + PrintSharedGCDuration(); + PrintGCMemoryStatistic(); + PrintSharedGCSummaryStatistic(); + } + InitializeRecordList(); +} + +void SharedGCStats::PrintSharedGCSummaryStatistic() +{ + LOG_GC(INFO) << "/***************** GC summary statistic: *****************/"; + LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("SharedGC occurs count") + << STATS_DATA_FORMAT(GetRecordData(RecordData::SHARED_COUNT)) << "\n" + << STATS_DESCRIPTION_FORMAT("SharedGC max pause:") + << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SHARED_MAX_PAUSE)) << "ms\n" + << STATS_DESCRIPTION_FORMAT("SharedGC min pause:") + << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SHARED_MIN_PAUSE)) << "ms\n" + << STATS_DESCRIPTION_FORMAT("SharedGC average pause:") + << STATS_DATA_FORMAT(GetRecordDuration(RecordDuration::SHARED_TOTAL_PAUSE) / + GetRecordData(RecordData::SHARED_COUNT)) << "ms\n" + << STATS_DESCRIPTION_FORMAT("SharedHeap average alive rate:") + << STATS_DATA_FORMAT(double(GetRecordData(RecordData::SHARED_TOTAL_ALIVE)) / + GetRecordData(RecordData::SHARED_TOTAL_COMMIT)); +} + +void SharedGCStats::PrintGCMemoryStatistic() +{ + NativeAreaAllocator *nativeAreaAllocator = sHeap_->GetNativeAreaAllocator(); + HeapRegionAllocator *heapRegionAllocator = sHeap_->GetHeapRegionAllocator(); + LOG_GC(INFO) << "/****************** GC Memory statistic: *****************/"; + LOG_GC(INFO) << "AllSpaces used:" + << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetHeapObjectSize())) << "KB" + << " committed:" + << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetCommittedSize())) << "KB\n" + << "SharedOldSpace used:" + << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetOldSpace()->GetHeapObjectSize())) << "KB" + << " committed:" + << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetOldSpace()->GetCommittedSize())) << "KB\n" + << "SharedNonMovableSpace used:" + << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetNonMovableSpace()->GetHeapObjectSize())) << "KB" + << " committed:" + << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetNonMovableSpace()->GetCommittedSize())) << "KB\n" + << "SharedHugeObjectSpace used:" + << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetHugeObjectSpace()->GetHeapObjectSize())) << "KB" + << " committed:" + << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetHugeObjectSpace()->GetCommittedSize())) << "KB\n"; + + LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Anno memory usage size:") + << STATS_DATA_FORMAT(sizeToMB(heapRegionAllocator->GetAnnoMemoryUsage())) << "MB\n" + << STATS_DESCRIPTION_FORMAT("Native memory usage size:") + << STATS_DATA_FORMAT(sizeToMB(nativeAreaAllocator->GetNativeMemoryUsage())) << "MB\n"; + + LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Heap alive rate:") + << STATS_DATA_FORMAT(double(GetRecordData(RecordData::SHARED_ALIVE_SIZE)) / + GetRecordData(RecordData::SHARED_COMMIT_SIZE)); +} + +void SharedGCStats::PrintSharedGCDuration() +{ + LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("TotalGC:") + << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::TotalGC]) << "ms\n" + << STATS_DESCRIPTION_FORMAT("Initialize:") + << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Initialize]) << "ms\n" + << STATS_DESCRIPTION_FORMAT("Mark:") + << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Mark]) << "ms\n" + << STATS_DESCRIPTION_FORMAT("Sweep:") + << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Sweep]) << "ms\n" + << STATS_DESCRIPTION_FORMAT("Finish:") + << STATS_DATA_FORMAT(scopeDuration_[Scope::ScopeId::Finish]) << "ms"; +} + +void SharedGCStats::RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason) +{ + size_t commitSize = sHeap_->GetCommittedSize(); + SetRecordData(RecordData::START_OBJ_SIZE, sHeap_->GetHeapObjectSize()); + SetRecordData(RecordData::START_COMMIT_SIZE, commitSize); + SetRecordData(RecordData::SHARED_COMMIT_SIZE, commitSize); + IncreaseRecordData(RecordData::SHARED_TOTAL_COMMIT, commitSize); + gcType_ = GetGCType(gcType); + reason_ = reason; +} + +void SharedGCStats::RecordStatisticAfterGC() +{ + SetRecordData(RecordData::END_OBJ_SIZE, sHeap_->GetHeapObjectSize()); + SetRecordData(RecordData::END_COMMIT_SIZE, sHeap_->GetCommittedSize()); + + float duration = scopeDuration_[Scope::ScopeId::TotalGC]; + if (GetRecordData(RecordData::SHARED_COUNT) == 0) { + SetRecordDuration(RecordDuration::SHARED_MIN_PAUSE, duration); + SetRecordDuration(RecordDuration::SHARED_MAX_PAUSE, duration); + } else { + SetRecordDuration(RecordDuration::SHARED_MIN_PAUSE, + std::min(GetRecordDuration(RecordDuration::SHARED_MIN_PAUSE), duration)); + SetRecordDuration(RecordDuration::SHARED_MAX_PAUSE, + std::max(GetRecordDuration(RecordDuration::SHARED_MAX_PAUSE), duration)); + } + IncreaseRecordData(RecordData::SHARED_COUNT); + IncreaseRecordDuration(RecordDuration::SHARED_TOTAL_PAUSE, duration); + size_t heapAliveSize = sHeap_->GetHeapObjectSize(); + SetRecordData(RecordData::SHARED_ALIVE_SIZE, heapAliveSize); + IncreaseRecordData(RecordData::SHARED_TOTAL_ALIVE, heapAliveSize); +} } // namespace panda::ecmascript diff --git a/ecmascript/mem/gc_stats.h b/ecmascript/mem/gc_stats.h index f8229df03bd39ac3c5f285ace0dddc3f4b105a2f..e486d88510e3f1aaca64ba4eeff0475ce65b5be3 100644 --- a/ecmascript/mem/gc_stats.h +++ b/ecmascript/mem/gc_stats.h @@ -27,12 +27,14 @@ namespace panda::ecmascript { class Heap; +class SharedHeap; enum class GCType : int { STW_YOUNG_GC = 0, PARTIAL_YOUNG_GC, PARTIAL_OLD_GC, COMPRESS_GC, + SHARED_GC, OTHER, START, }; @@ -71,12 +73,12 @@ public: explicit GCStats(const Heap *heap) : heap_(heap) {} GCStats(const Heap *heap, size_t longPuaseTime) : heap_(heap), longPauseTime_(longPuaseTime) {} - ~GCStats() = default; + virtual ~GCStats() = default; - void PrintStatisticResult(); - void PrintGCMemoryStatistic(); + virtual void PrintStatisticResult(); + virtual void PrintGCMemoryStatistic(); bool CheckIfLongTimePause(); - void PrintGCStatistic(); + virtual void PrintGCStatistic(); float GetGCSpeed(SpeedData data) { @@ -114,6 +116,8 @@ public: return "HPP OldGC"; case GCType::COMPRESS_GC: return "CompressGC"; + case GCType::SHARED_GC: + return "SharedGC"; default: return "UnknownType"; } @@ -130,9 +134,9 @@ public: return std::min(copiedRate + promotedRate, 1.0); } - void RecordGCSpeed(); - void RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason); - void RecordStatisticAfterGC(); + virtual void RecordGCSpeed(); + virtual void RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason); + virtual void RecordStatisticAfterGC(); class Scope : public ClockScope { public: @@ -160,7 +164,7 @@ public: GCStats* stats_; }; -private: +protected: bool CheckIfNeedPrint(GCType type); void PrintVerboseGCStatistic(); void PrintGCDurationStatistic(); @@ -252,6 +256,29 @@ private: NO_COPY_SEMANTIC(GCStats); NO_MOVE_SEMANTIC(GCStats); }; + +class SharedGCStats : public GCStats { +public: + SharedGCStats(const SharedHeap *sHeap, bool enableGCTracer) + : GCStats(nullptr), sHeap_(sHeap), enableGCTracer_(enableGCTracer) + { + SetRecordData(RecordData::SHARED_COUNT, 0); + } + ~SharedGCStats() = default; + + void PrintStatisticResult() override; + void PrintGCMemoryStatistic() override; + void PrintGCStatistic() override; + + void RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason) override; + void RecordStatisticAfterGC() override; +private: + void PrintSharedGCDuration(); + void PrintSharedGCSummaryStatistic(); + + const SharedHeap *sHeap_ {nullptr}; + bool enableGCTracer_ {false}; +}; } // namespace panda::ecmascript #endif // ECMASCRIPT_MEM_GC_STATS_H diff --git a/ecmascript/mem/heap-inl.h b/ecmascript/mem/heap-inl.h index 6fcd4d8b2ca5909ba2d10843c7f69b2ae08a701a..1ac64c5bbd58210eee1f08e3aaa55db471da04e4 100644 --- a/ecmascript/mem/heap-inl.h +++ b/ecmascript/mem/heap-inl.h @@ -39,10 +39,42 @@ namespace panda::ecmascript { DumpHeapSnapshotBeforeOOM(); \ } \ StatisticHeapDetail(); \ + ThrowOutOfMemoryError(GetJSThread(), size, message); \ (object) = reinterpret_cast((space)->Allocate(size)); \ - ThrowOutOfMemoryError(size, message); \ + } + +#define CHECK_SOBJ_AND_THROW_OOM_ERROR(thread, object, size, space, message) \ + if (UNLIKELY((object) == nullptr)) { \ + size_t oomOvershootSize = GetEcmaParamConfiguration().GetOutOfMemoryOvershootSize(); \ + (space)->IncreaseOutOfMemoryOvershootSize(oomOvershootSize); \ + ThrowOutOfMemoryError(thread, size, message); \ + (object) = reinterpret_cast((space)->Allocate(thread, size)); \ } +template +void SharedHeap::EnumerateOldSpaceRegions(const Callback &cb) const +{ + sOldSpace_->EnumerateRegions(cb); + sNonMovableSpace_->EnumerateRegions(cb); + sHugeObjectSpace_->EnumerateRegions(cb); +} + +template +void SharedHeap::EnumerateOldSpaceRegionsWithRecord(const Callback &cb) const +{ + sOldSpace_->EnumerateRegionsWithRecord(cb); + sNonMovableSpace_->EnumerateRegionsWithRecord(cb); + sHugeObjectSpace_->EnumerateRegionsWithRecord(cb); +} + +template +void SharedHeap::IterateOverObjects(const Callback &cb) const +{ + sOldSpace_->IterateOverObjects(cb); + sNonMovableSpace_->IterateOverObjects(cb); + sHugeObjectSpace_->IterateOverObjects(cb); +} + template void Heap::EnumerateOldSpaceRegions(const Callback &cb, Region *region) const { @@ -259,6 +291,19 @@ TaggedObject *Heap::AllocateClassClass(JSHClass *hclass, size_t size) return object; } +TaggedObject *SharedHeap::AllocateClassClass(JSHClass *hclass, size_t size) +{ + size = AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT)); + auto object = reinterpret_cast(sNonMovableSpace_->AllocateWithoutGC(size)); + if (UNLIKELY(object == nullptr)) { + LOG_ECMA_MEM(FATAL) << "Heap::AllocateClassClass can not allocate any space"; + UNREACHABLE(); + } + *reinterpret_cast(ToUintPtr(object)) = reinterpret_cast(hclass); + // todo(Gymee) OnAllocateEvent + return object; +} + TaggedObject *Heap::AllocateHugeObject(size_t size) { // Check whether it is necessary to trigger Old GC before expanding to avoid OOM risk. @@ -270,12 +315,13 @@ TaggedObject *Heap::AllocateHugeObject(size_t size) object = reinterpret_cast(hugeObjectSpace_->Allocate(size, thread_)); if (UNLIKELY(object == nullptr)) { // if allocate huge object OOM, temporarily increase space size to avoid vm crash - size_t oomOvershootSize = GetEcmaVM()->GetEcmaParamConfiguration().GetOutOfMemoryOvershootSize(); + size_t oomOvershootSize = config_.GetOutOfMemoryOvershootSize(); oldSpace_->IncreaseOutOfMemoryOvershootSize(oomOvershootSize); DumpHeapSnapshotBeforeOOM(); StatisticHeapDetail(); object = reinterpret_cast(hugeObjectSpace_->Allocate(size, thread_)); - ThrowOutOfMemoryError(size, "Heap::AllocateHugeObject"); + ThrowOutOfMemoryError(thread_, size, "Heap::AllocateHugeObject"); + object = reinterpret_cast(hugeObjectSpace_->Allocate(size, thread_)); if (UNLIKELY(object == nullptr)) { FatalOutOfMemoryError(size, "Heap::AllocateHugeObject"); } @@ -387,9 +433,12 @@ void Heap::ReclaimRegions(TriggerGCType gcType) // only call in js-thread void Heap::ClearSlotsRange(Region *current, uintptr_t freeStart, uintptr_t freeEnd) { - current->AtomicClearSweepingRSetInRange(freeStart, freeEnd); - current->ClearOldToNewRSetInRange(freeStart, freeEnd); - current->AtomicClearCrossRegionRSetInRange(freeStart, freeEnd); + if (!current->InYoungSpace()) { + current->AtomicClearSweepingRSetInRange(freeStart, freeEnd); + current->ClearOldToNewRSetInRange(freeStart, freeEnd); + current->AtomicClearCrossRegionRSetInRange(freeStart, freeEnd); + } + current->AtomicClearLocalToShareRSetInRange(freeStart, freeEnd); } size_t Heap::GetCommittedSize() const @@ -434,6 +483,106 @@ void Heap::InitializeIdleStatusControl(std::function callback) enableIdleGC_ = ecmaVm_->GetJSOptions().EnableIdleGC(); } } + +TaggedObject *SharedHeap::AllocateNonMovableOrHugeObject(JSThread *thread, JSHClass *hclass) +{ + size_t size = hclass->GetObjectSize(); + return AllocateNonMovableOrHugeObject(thread, hclass, size); +} + +TaggedObject *SharedHeap::AllocateNonMovableOrHugeObject(JSThread *thread, JSHClass *hclass, size_t size) +{ + size = AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT)); + if (size > MAX_REGULAR_HEAP_OBJECT_SIZE) { + return AllocateHugeObject(thread, hclass, size); + } + auto object = reinterpret_cast(sNonMovableSpace_->Allocate(thread, size)); + CHECK_SOBJ_AND_THROW_OOM_ERROR(thread, object, size, sNonMovableSpace_, + "SharedHeap::AllocateNonMovableOrHugeObject"); + object->SetClass(thread, hclass); + // todo(lukai) OnAllocateEvent + return object; +} + +TaggedObject *SharedHeap::AllocateOldOrHugeObject(JSThread *thread, JSHClass *hclass) +{ + size_t size = hclass->GetObjectSize(); + return AllocateOldOrHugeObject(thread, hclass, size); +} + +TaggedObject *SharedHeap::AllocateOldOrHugeObject(JSThread *thread, JSHClass *hclass, size_t size) +{ + size = AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT)); + if (size > MAX_REGULAR_HEAP_OBJECT_SIZE) { + return AllocateHugeObject(thread, hclass, size); + } + auto object = reinterpret_cast(sOldSpace_->Allocate(thread, size)); + CHECK_SOBJ_AND_THROW_OOM_ERROR(thread, object, size, sOldSpace_, "SharedHeap::AllocateOldOrHugeObject"); + object->SetClass(thread, hclass); + // todo(lukai) OnAllocateEvent + return object; +} + +TaggedObject *SharedHeap::AllocateOldOrHugeObject(JSThread *thread, size_t size) +{ + size = AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT)); + if (size > MAX_REGULAR_HEAP_OBJECT_SIZE) { + return AllocateHugeObject(thread, size); + } + + auto object = reinterpret_cast(sOldSpace_->Allocate(thread, size)); + CHECK_SOBJ_AND_THROW_OOM_ERROR(thread, object, size, sOldSpace_, "SharedHeap::AllocateOldOrHugeObject"); + return object; +} + +TaggedObject *SharedHeap::AllocateHugeObject(JSThread *thread, JSHClass *hclass, size_t size) +{ + auto object = AllocateHugeObject(thread, size); + object->SetClass(thread, hclass); + // todo(lukai) OnAllocateEvent + return object; +} + +TaggedObject *SharedHeap::AllocateHugeObject(JSThread *thread, size_t size) +{ + // Check whether it is necessary to trigger Shared GC before expanding to avoid OOM risk. + CheckHugeAndTriggerGC(thread, size); + auto *object = reinterpret_cast(sHugeObjectSpace_->Allocate(thread, size)); + if (UNLIKELY(object == nullptr)) { + CollectGarbage(thread, TriggerGCType::SHARED_GC, GCReason::ALLOCATION_LIMIT); + object = reinterpret_cast(sHugeObjectSpace_->Allocate(thread, size)); + if (UNLIKELY(object == nullptr)) { + // if allocate huge object OOM, temporarily increase space size to avoid vm crash + size_t oomOvershootSize = config_.GetOutOfMemoryOvershootSize(); + sHugeObjectSpace_->IncreaseOutOfMemoryOvershootSize(oomOvershootSize); + // todo(lukai) DumpHeapSnapshotBeforeOOM + ThrowOutOfMemoryError(thread, size, "SharedHeap::AllocateHugeObject"); + object = reinterpret_cast(sHugeObjectSpace_->Allocate(thread, size)); + if (UNLIKELY(object == nullptr)) { + FatalOutOfMemoryError(size, "SharedHeap::AllocateHugeObject"); + } + } + } + return object; +} + +TaggedObject *SharedHeap::AllocateReadOnlyOrHugeObject(JSThread *thread, JSHClass *hclass) +{ + size_t size = hclass->GetObjectSize(); + return AllocateReadOnlyOrHugeObject(thread, hclass, size); +} + +TaggedObject *SharedHeap::AllocateReadOnlyOrHugeObject(JSThread *thread, JSHClass *hclass, size_t size) +{ + size = AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT)); + if (size > MAX_REGULAR_HEAP_OBJECT_SIZE) { + return AllocateHugeObject(thread, hclass, size); + } + auto object = reinterpret_cast(sReadOnlySpace_->Allocate(thread, size)); + CHECK_SOBJ_AND_THROW_OOM_ERROR(thread, object, size, sReadOnlySpace_, "SharedHeap::AllocateReadOnlyOrHugeObject"); + object->SetClass(thread, hclass); + return object; +} } // namespace panda::ecmascript #endif // ECMASCRIPT_MEM_HEAP_INL_H diff --git a/ecmascript/mem/heap.cpp b/ecmascript/mem/heap.cpp index b51f1c1c594976faf7b4e9e66297c1fcc963ca20..33b36eca2e90b3a86489736cba1811d6bea1caca 100644 --- a/ecmascript/mem/heap.cpp +++ b/ecmascript/mem/heap.cpp @@ -19,6 +19,8 @@ #include #include "ecmascript/base/block_hook_scope.h" +#include "ecmascript/checkpoint/thread_state_transition.h" +#include "ecmascript/ecma_string_table.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/free_object.h" #include "ecmascript/js_finalization_registry.h" @@ -31,16 +33,19 @@ #include "ecmascript/mem/incremental_marker.h" #include "ecmascript/mem/mark_stack.h" #include "ecmascript/mem/mem_controller.h" -#include "ecmascript/mem/partial_gc.h" #include "ecmascript/mem/native_area_allocator.h" +#include "ecmascript/mem/partial_gc.h" #include "ecmascript/mem/parallel_evacuator.h" #include "ecmascript/mem/parallel_marker-inl.h" +#include "ecmascript/mem/shared_heap/shared_concurrent_sweeper.h" +#include "ecmascript/mem/shared_heap/shared_gc_marker-inl.h" +#include "ecmascript/mem/shared_heap/shared_gc.h" #include "ecmascript/mem/stw_young_gc.h" #include "ecmascript/mem/verification.h" #include "ecmascript/mem/work_manager.h" #include "ecmascript/mem/gc_stats.h" -#include "ecmascript/ecma_string_table.h" #include "ecmascript/runtime_call_id.h" +#include "ecmascript/runtime_lock.h" #if !WIN_OR_MAC_OR_IOS_PLATFORM #include "ecmascript/dfx/hprof/heap_profiler_interface.h" #include "ecmascript/dfx/hprof/heap_profiler.h" @@ -54,17 +59,215 @@ #endif namespace panda::ecmascript { -Heap::Heap(EcmaVM *ecmaVm) : ecmaVm_(ecmaVm), thread_(ecmaVm->GetJSThread()), - nativeAreaAllocator_(ecmaVm->GetNativeAreaAllocator()), - heapRegionAllocator_(ecmaVm->GetHeapRegionAllocator()) {} +SharedHeap* SharedHeap::GetInstance() +{ + EcmaParamConfiguration config(EcmaParamConfiguration::HeapType::SHARED_HEAP, + MemMapAllocator::GetInstance()->GetCapacity()); + static SharedHeap *shareHeap = new SharedHeap(config); + return shareHeap; +} + +bool SharedHeap::CheckAndTriggerGC(JSThread *thread, size_t size) +{ + if ((OldSpaceExceedLimit() || OldSpaceExceedCapacity(size) || GetHeapObjectSize() > globalSpaceAllocLimit_) && + !NeedStopCollection()) { + CollectGarbage(thread, TriggerGCType::SHARED_GC, GCReason::ALLOCATION_LIMIT); + return true; + } + return false; +} + +bool SharedHeap::CheckHugeAndTriggerGC(JSThread *thread, size_t size) +{ + if (sHugeObjectSpace_->CommittedSizeExceed(size) && !NeedStopCollection()) { + CollectGarbage(thread, TriggerGCType::SHARED_GC, GCReason::ALLOCATION_LIMIT); + return true; + } + return false; +} + +void SharedHeap::Initialize(NativeAreaAllocator *nativeAreaAllocator, HeapRegionAllocator *heapRegionAllocator, + const JSRuntimeOptions &option) +{ + sGCStats_ = new SharedGCStats(this, option.EnableGCTracer()); + nativeAreaAllocator_ = nativeAreaAllocator; + heapRegionAllocator_ = heapRegionAllocator; + shouldVerifyHeap_ = option.EnableHeapVerify(); + parallelGC_ = option.EnableParallelGC(); + size_t maxHeapSize = config_.GetMaxHeapSize(); + size_t nonmovableSpaceCapacity = config_.GetDefaultNonMovableSpaceSize(); + sNonMovableSpace_ = new SharedNonMovableSpace(this, nonmovableSpaceCapacity, nonmovableSpaceCapacity); + + size_t readOnlySpaceCapacity = config_.GetDefaultReadOnlySpaceSize(); + size_t oldSpaceCapacity = (maxHeapSize - nonmovableSpaceCapacity - readOnlySpaceCapacity) / 2; // 2: half + globalSpaceAllocLimit_ = maxHeapSize; + + sOldSpace_ = new SharedOldSpace(this, oldSpaceCapacity, oldSpaceCapacity); + sReadOnlySpace_ = new SharedReadOnlySpace(this, readOnlySpaceCapacity, readOnlySpaceCapacity); + sHugeObjectSpace_ = new SharedHugeObjectSpace(this, heapRegionAllocator_, oldSpaceCapacity, oldSpaceCapacity); +} + +void SharedHeap::PostInitialization(const GlobalEnvConstants *globalEnvConstants, const JSRuntimeOptions &option) +{ + globalEnvConstants_ = globalEnvConstants; + uint32_t totalThreadNum = Taskpool::GetCurrentTaskpool()->GetTotalThreadNum(); + maxMarkTaskCount_ = totalThreadNum - 1; + sWorkManager_ = new SharedGCWorkManager(this, totalThreadNum + 1); + sharedGCMarker_ = new SharedGCMarker(sWorkManager_); + sSweeper_ = new SharedConcurrentSweeper(this, option.EnableConcurrentSweep() ? + EnableConcurrentSweepType::ENABLE : EnableConcurrentSweepType::CONFIG_DISABLE); + sharedGC_ = new SharedGC(this); +} + +void SharedHeap::PostGCMarkingTask() +{ + IncreaseTaskCount(); + Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique(-1, this)); +} + +bool SharedHeap::ParallelMarkTask::Run(uint32_t threadIndex) +{ + // Synchronizes-with. Ensure that WorkManager::Initialize must be seen by MarkerThreads. + while (!sHeap_->GetWorkManager()->HasInitialized()); + sHeap_->GetSharedGCMarker()->ProcessMarkStack(threadIndex); + sHeap_->ReduceTaskCount(); + return true; +} + +bool SharedHeap::AsyncClearTask::Run([[maybe_unused]] uint32_t threadIndex) +{ + sHeap_->ReclaimRegions(); + return true; +} + +void SharedHeap::CollectGarbage(JSThread *thread, [[maybe_unused]]TriggerGCType gcType, [[maybe_unused]]GCReason reason) +{ + // This lock can be removed after Shared Heap GC starts to run only in a special daemon thread + RuntimeLockHolder gcLockHolder(thread, gcCollectGarbageMutex_); + ASSERT(gcType == TriggerGCType::SHARED_GC); + gcType_ = gcType; + { + SuspendAllScope scope(thread); + CollectGarbageImpl(gcType, reason); + } + // Don't process weak node nativeFinalizeCallback here. These callbacks would be called after localGC. +} + +void SharedHeap::CollectGarbageImpl(TriggerGCType gcType, GCReason reason) +{ + Prepare(); + GetEcmaGCStats()->RecordStatisticBeforeGC(gcType, reason); + if (UNLIKELY(ShouldVerifyHeap())) { + // pre gc heap verify + LOG_ECMA(DEBUG) << "pre gc shared heap verify"; + SharedHeapVerification(this, VerifyKind::VERIFY_PRE_SHARED_GC).VerifyAll(); + } + sharedGC_->RunPhases(); + if (UNLIKELY(ShouldVerifyHeap())) { + // pre gc heap verify + LOG_ECMA(DEBUG) << "after gc shared heap verify"; + SharedHeapVerification(this, VerifyKind::VERIFY_POST_SHARED_GC).VerifyAll(); + } + GetEcmaGCStats()->RecordStatisticAfterGC(); + GetEcmaGCStats()->PrintGCStatistic(); +} + +void SharedHeap::Prepare() +{ + WaitRunningTaskFinished(); + sSweeper_->EnsureAllTaskFinished(); + WaitClearTaskFinished(); +} + +void SharedHeap::PrepareRecordRegionsForReclaim() +{ + sOldSpace_->SetRecordRegion(); + sNonMovableSpace_->SetRecordRegion(); + sHugeObjectSpace_->SetRecordRegion(); +} + +void SharedHeap::Reclaim() +{ + PrepareRecordRegionsForReclaim(); + sHugeObjectSpace_->ReclaimHugeRegion(); + if (parallelGC_) { + clearTaskFinished_ = false; + Taskpool::GetCurrentTaskpool()->PostTask( + std::make_unique(JSThread::GetCurrentThreadId(), this)); + } else { + ReclaimRegions(); + } +} + +void SharedHeap::ReclaimRegions() +{ + sSweeper_->WaitAllTaskFinished(); + EnumerateOldSpaceRegionsWithRecord([] (Region *region) { + region->ClearMarkGCBitset(); + region->ResetAliveObject(); + }); + if (!clearTaskFinished_) { + LockHolder holder(waitClearTaskFinishedMutex_); + clearTaskFinished_ = true; + waitClearTaskFinishedCV_.SignalAll(); + } +} + +void SharedHeap::DisableParallelGC() +{ + Prepare(); + parallelGC_ = false; + maxMarkTaskCount_ = 0; + sSweeper_->ConfigConcurrentSweep(false); +} + +void SharedHeap::EnableParallelGC(JSRuntimeOptions &option) +{ + uint32_t totalThreadNum = Taskpool::GetCurrentTaskpool()->GetTotalThreadNum(); + maxMarkTaskCount_ = totalThreadNum - 1; + parallelGC_ = option.EnableParallelGC(); + if (auto workThreadNum = sWorkManager_->GetTotalThreadNum(); + workThreadNum != totalThreadNum + 1) { + LOG_ECMA_MEM(ERROR) << "TheadNum mismatch, totalThreadNum(sWorkerManager): " << workThreadNum << ", " + << "totalThreadNum(taskpool): " << totalThreadNum + 1; + delete sWorkManager_; + sWorkManager_ = new SharedGCWorkManager(this, totalThreadNum + 1); + sharedGCMarker_->ResetWorkManager(sWorkManager_); + sharedGC_->ResetWorkManager(sWorkManager_); + } + sSweeper_->ConfigConcurrentSweep(option.EnableConcurrentSweep()); +} + +size_t SharedHeap::VerifyHeapObjects(VerifyKind verifyKind) const +{ + size_t failCount = 0; + { + VerifyObjectVisitor verifier(this, &failCount, verifyKind); + sOldSpace_->IterateOverObjects(verifier); + } + { + VerifyObjectVisitor verifier(this, &failCount, verifyKind); + sNonMovableSpace_->IterateOverObjects(verifier); + } + { + VerifyObjectVisitor verifier(this, &failCount, verifyKind); + sHugeObjectSpace_->IterateOverObjects(verifier); + } + return failCount; +} + +Heap::Heap(EcmaVM *ecmaVm) + : BaseHeap(ecmaVm->GetEcmaParamConfiguration()), + ecmaVm_(ecmaVm), thread_(ecmaVm->GetJSThread()) {} void Heap::Initialize() { memController_ = new MemController(this); - auto &config = ecmaVm_->GetEcmaParamConfiguration(); - size_t maxHeapSize = config.GetMaxHeapSize(); - size_t minSemiSpaceCapacity = config.GetMinSemiSpaceSize(); - size_t maxSemiSpaceCapacity = config.GetMaxSemiSpaceSize(); + nativeAreaAllocator_ = ecmaVm_->GetNativeAreaAllocator(); + heapRegionAllocator_ = ecmaVm_->GetHeapRegionAllocator(); + size_t maxHeapSize = config_.GetMaxHeapSize(); + size_t minSemiSpaceCapacity = config_.GetMinSemiSpaceSize(); + size_t maxSemiSpaceCapacity = config_.GetMaxSemiSpaceSize(); activeSemiSpace_ = new SemiSpace(this, minSemiSpaceCapacity, maxSemiSpaceCapacity); activeSemiSpace_->Restart(); activeSemiSpace_->SetWaterLine(); @@ -77,18 +280,18 @@ void Heap::Initialize() shouldVerifyHeap_ = ecmaVm_->GetJSOptions().EnableHeapVerify(); // not set up from space - size_t readOnlySpaceCapacity = config.GetDefaultReadOnlySpaceSize(); + size_t readOnlySpaceCapacity = config_.GetDefaultReadOnlySpaceSize(); readOnlySpace_ = new ReadOnlySpace(this, readOnlySpaceCapacity, readOnlySpaceCapacity); appSpawnSpace_ = new AppSpawnSpace(this, maxHeapSize); - size_t nonmovableSpaceCapacity = config.GetDefaultNonMovableSpaceSize(); + size_t nonmovableSpaceCapacity = config_.GetDefaultNonMovableSpaceSize(); if (ecmaVm_->GetJSOptions().WasSetMaxNonmovableSpaceCapacity()) { nonmovableSpaceCapacity = ecmaVm_->GetJSOptions().MaxNonmovableSpaceCapacity(); } nonMovableSpace_ = new NonMovableSpace(this, nonmovableSpaceCapacity, nonmovableSpaceCapacity); nonMovableSpace_->Initialize(); - size_t snapshotSpaceCapacity = config.GetDefaultSnapshotSpaceSize(); + size_t snapshotSpaceCapacity = config_.GetDefaultSnapshotSpaceSize(); snapshotSpace_ = new SnapshotSpace(this, snapshotSpaceCapacity, snapshotSpaceCapacity); - size_t machineCodeSpaceCapacity = config.GetDefaultMachineCodeSpaceSize(); + size_t machineCodeSpaceCapacity = config_.GetDefaultMachineCodeSpaceSize(); machineCodeSpace_ = new MachineCodeSpace(this, machineCodeSpaceCapacity, machineCodeSpaceCapacity); size_t capacities = minSemiSpaceCapacity * 2 + nonmovableSpaceCapacity + snapshotSpaceCapacity + @@ -260,10 +463,18 @@ void Heap::Prepare() WaitClearTaskFinished(); } +void Heap::GetHeapPrepare() +{ + // Ensure local and shared heap prepared. + Prepare(); + SharedHeap *sHeap = SharedHeap::GetInstance(); + sHeap->Prepare(); +} + void Heap::Resume(TriggerGCType gcType) { if (mode_ != HeapMode::SPAWN && - activeSemiSpace_->AdjustCapacity(inactiveSemiSpace_->GetAllocatedSizeSinceGC())) { + activeSemiSpace_->AdjustCapacity(inactiveSemiSpace_->GetAllocatedSizeSinceGC(), thread_)) { // if activeSpace capacity changes, oldSpace maximumCapacity should change, too. size_t multiple = 2; size_t oldSpaceMaxLimit = 0; @@ -325,7 +536,6 @@ void Heap::DisableParallelGC() void Heap::EnableParallelGC() { - Taskpool::GetCurrentTaskpool()->Initialize(); parallelGC_ = ecmaVm_->GetJSOptions().EnableParallelGC(); maxEvacuateTaskCount_ = Taskpool::GetCurrentTaskpool()->GetTotalThreadNum(); if (auto totalThreadNum = workManager_->GetTotalThreadNum(); @@ -364,8 +574,10 @@ TriggerGCType Heap::SelectGCType() const void Heap::CollectGarbage(TriggerGCType gcType, GCReason reason) { { + ASSERT(thread_->IsInRunningStateOrProfiling()); RecursionScope recurScope(this); - if (thread_->IsCrossThreadExecutionEnable() || (InSensitiveStatus() && !ObjectExceedMaxHeapSize())) { + if (thread_->IsCrossThreadExecutionEnable() || GetOnSerializeEvent() || + (InSensitiveStatus() && !ObjectExceedMaxHeapSize())) { ProcessGCListeners(); return; } @@ -373,7 +585,6 @@ void Heap::CollectGarbage(TriggerGCType gcType, GCReason reason) [[maybe_unused]] GcStateScope scope(thread_); #endif CHECK_NO_GC - if (UNLIKELY(ShouldVerifyHeap())) { // pre gc heap verify LOG_ECMA(DEBUG) << "pre gc heap verify"; @@ -396,9 +607,9 @@ void Heap::CollectGarbage(TriggerGCType gcType, GCReason reason) memController_->StartCalculationBeforeGC(); StatisticHeapObject(gcType); if (!GetJSThread()->IsReadyToMark() && markType_ == MarkType::MARK_FULL) { - ecmaVm_->GetEcmaGCStats()->SetGCReason(reason); + GetEcmaGCStats()->SetGCReason(reason); } else { - ecmaVm_->GetEcmaGCStats()->RecordStatisticBeforeGC(gcType, reason); + GetEcmaGCStats()->RecordStatisticBeforeGC(gcType, reason); } gcType_ = gcType; GetEcmaVM()->GetPGOProfiler()->WaitPGODumpPause(); @@ -432,7 +643,7 @@ void Heap::CollectGarbage(TriggerGCType gcType, GCReason reason) SetMarkType(MarkType::MARK_FULL); if (fullConcurrentMarkRequested && idleTask_ == IdleTaskType::NO_TASK) { LOG_ECMA(INFO) << "Trigger old gc here may cost long time, trigger full concurrent mark instead"; - oldSpace_->SetOvershootSize(GetEcmaVM()->GetEcmaParamConfiguration().GetOldSpaceOvershootSize()); + oldSpace_->SetOvershootSize(config_.GetOldSpaceOvershootSize()); TriggerConcurrentMarking(); oldGCRequested_ = true; ProcessGCListeners(); @@ -464,7 +675,7 @@ void Heap::CollectGarbage(TriggerGCType gcType, GCReason reason) sweeper_->EnsureAllTaskFinished(); DumpHeapSnapshotBeforeOOM(false); StatisticHeapDetail(); - ThrowOutOfMemoryError(oldSpace_->GetMergeSize(), " OldSpace::Merge"); + ThrowOutOfMemoryError(thread_, oldSpace_->GetMergeSize(), " OldSpace::Merge"); oldSpace_->ResetMergeSize(); shouldThrowOOMError_ = false; } @@ -488,8 +699,8 @@ void Heap::CollectGarbage(TriggerGCType gcType, GCReason reason) concurrentMarker_->EnableConcurrentMarking(EnableConcurrentMarkType::DISABLE); } // GC log - ecmaVm_->GetEcmaGCStats()->RecordStatisticAfterGC(); - ecmaVm_->GetEcmaGCStats()->PrintGCStatistic(); + GetEcmaGCStats()->RecordStatisticAfterGC(); + GetEcmaGCStats()->PrintGCStatistic(); } if (gcType_ == TriggerGCType::OLD_GC) { @@ -501,7 +712,7 @@ void Heap::CollectGarbage(TriggerGCType gcType, GCReason reason) } // Weak node nativeFinalizeCallback may execute JS and change the weakNodeList status, // even lead to another GC, so this have to invoke after this GC process. - InvokeWeakNodeNativeFinalizeCallback(); + thread_->InvokeWeakNodeNativeFinalizeCallback(); if (UNLIKELY(ShouldVerifyHeap())) { // verify post gc heap verify @@ -519,23 +730,26 @@ void Heap::CollectGarbage(TriggerGCType gcType, GCReason reason) ProcessGCListeners(); } -void Heap::ThrowOutOfMemoryError(size_t size, std::string functionName, bool NonMovableObjNearOOM) +void BaseHeap::ThrowOutOfMemoryError(JSThread *thread, size_t size, std::string functionName, + bool NonMovableObjNearOOM) { - ecmaVm_->GetEcmaGCStats()->PrintGCMemoryStatistic(); + GetEcmaGCStats()->PrintGCMemoryStatistic(); std::ostringstream oss; if (NonMovableObjNearOOM) { oss << "OutOfMemory when nonmovable live obj size: " << size << " bytes" << " function name: " << functionName.c_str(); } else { - oss << "OutOfMemory when trying to allocate " << size << " bytes" << " function name: " << functionName.c_str(); + oss << "OutOfMemory when trying to allocate " << size << " bytes" << " function name: " + << functionName.c_str(); } LOG_ECMA_MEM(ERROR) << oss.str().c_str(); - THROW_OOM_ERROR(thread_, oss.str().c_str()); + THROW_OOM_ERROR(thread, oss.str().c_str()); } -void Heap::ThrowOutOfMemoryErrorForDefault(size_t size, std::string functionName, bool NonMovableObjNearOOM) +void BaseHeap::ThrowOutOfMemoryErrorForDefault(JSThread *thread, size_t size, std::string functionName, + bool NonMovableObjNearOOM) { - ecmaVm_->GetEcmaGCStats()->PrintGCMemoryStatistic(); + GetEcmaGCStats()->PrintGCMemoryStatistic(); std::ostringstream oss; if (NonMovableObjNearOOM) { oss << "OutOfMemory when nonmovable live obj size: " << size << " bytes" @@ -544,17 +758,17 @@ void Heap::ThrowOutOfMemoryErrorForDefault(size_t size, std::string functionName oss << "OutOfMemory when trying to allocate " << size << " bytes" << " function name: " << functionName.c_str(); } LOG_ECMA_MEM(ERROR) << oss.str().c_str(); - EcmaVM *ecmaVm = (thread_)->GetEcmaVM(); + EcmaVM *ecmaVm = thread->GetEcmaVM(); JSHandle env = ecmaVm->GetGlobalEnv(); JSHandle error = JSHandle::Cast(env->GetOOMErrorObject()); - (thread_)->SetException(error.GetTaggedValue()); + thread->SetException(error.GetTaggedValue()); ecmaVm->HandleUncatchableError(); } -void Heap::FatalOutOfMemoryError(size_t size, std::string functionName) +void BaseHeap::FatalOutOfMemoryError(size_t size, std::string functionName) { - ecmaVm_->GetEcmaGCStats()->PrintGCMemoryStatistic(); + GetEcmaGCStats()->PrintGCMemoryStatistic(); LOG_ECMA_MEM(FATAL) << "OOM fatal when trying to allocate " << size << " bytes" << " function name: " << functionName.c_str(); } @@ -565,7 +779,7 @@ void Heap::CheckNonMovableSpaceOOM() sweeper_->EnsureAllTaskFinished(); DumpHeapSnapshotBeforeOOM(false); StatisticHeapDetail(); - ThrowOutOfMemoryError(nonMovableSpace_->GetHeapObjectSize(), "Heap::CheckNonMovableSpaceOOM", true); + ThrowOutOfMemoryError(thread_, nonMovableSpace_->GetHeapObjectSize(), "Heap::CheckNonMovableSpaceOOM", true); } } @@ -783,8 +997,7 @@ void Heap::AddToKeptObjects(JSHandle value) const void Heap::AdjustSpaceSizeForAppSpawn() { SetHeapMode(HeapMode::SPAWN); - auto &config = ecmaVm_->GetEcmaParamConfiguration(); - size_t minSemiSpaceCapacity = config.GetMinSemiSpaceSize(); + size_t minSemiSpaceCapacity = config_.GetMinSemiSpaceSize(); activeSemiSpace_->SetInitialCapacity(minSemiSpaceCapacity); auto committedSize = appSpawnSpace_->GetCommittedSize(); appSpawnSpace_->SetInitialCapacity(committedSize); @@ -837,7 +1050,7 @@ void Heap::RecomputeLimits() size_t maxOldSpaceCapacity = oldSpace_->GetMaximumCapacity() - newSpaceCapacity; size_t newOldSpaceLimit = memController_->CalculateAllocLimit(oldSpaceSize, MIN_OLD_SPACE_LIMIT, maxOldSpaceCapacity, newSpaceCapacity, growingFactor); - size_t maxGlobalSize = ecmaVm_->GetEcmaParamConfiguration().GetMaxHeapSize() - newSpaceCapacity; + size_t maxGlobalSize = config_.GetMaxHeapSize() - newSpaceCapacity; size_t newGlobalSpaceLimit = memController_->CalculateAllocLimit(GetHeapObjectSize(), MIN_HEAP_SIZE, maxGlobalSize, newSpaceCapacity, growingFactor); globalSpaceAllocLimit_ = newGlobalSpaceLimit; @@ -862,7 +1075,7 @@ bool Heap::CheckAndTriggerOldGC(size_t size) bool isFullMarking = IsConcurrentFullMark() && GetJSThread()->IsMarking(); bool isNativeSizeLargeTrigger = isFullMarking ? false : GlobalNativeSizeLargerThanLimit(); if (isFullMarking && oldSpace_->GetOvershootSize() == 0) { - oldSpace_->SetOvershootSize(GetEcmaVM()->GetEcmaParamConfiguration().GetOldSpaceOvershootSize()); + oldSpace_->SetOvershootSize(config_.GetOldSpaceOvershootSize()); } if ((isNativeSizeLargeTrigger || OldSpaceExceedLimit() || OldSpaceExceedCapacity(size) || GetHeapObjectSize() > globalSpaceAllocLimit_ + oldSpace_->GetOvershootSize()) && @@ -949,8 +1162,8 @@ void Heap::CalculateIdleDuration() // update reference duration idlePredictDuration_ = 0.0f; size_t updateReferenceSpeed = markType_ == MarkType::MARK_YOUNG ? - ecmaVm_->GetEcmaGCStats()->GetGCSpeed(SpeedData::YOUNG_UPDATE_REFERENCE_SPEED) : - ecmaVm_->GetEcmaGCStats()->GetGCSpeed(SpeedData::UPDATE_REFERENCE_SPEED); + GetEcmaGCStats()->GetGCSpeed(SpeedData::YOUNG_UPDATE_REFERENCE_SPEED) : + GetEcmaGCStats()->GetGCSpeed(SpeedData::UPDATE_REFERENCE_SPEED); if (updateReferenceSpeed != 0) { idlePredictDuration_ += (float)GetHeapObjectSize() / updateReferenceSpeed; } @@ -958,9 +1171,9 @@ void Heap::CalculateIdleDuration() // clear native object duration size_t clearNativeObjSpeed = 0; if (markType_ == MarkType::MARK_YOUNG) { - clearNativeObjSpeed = ecmaVm_->GetEcmaGCStats()->GetGCSpeed(SpeedData::YOUNG_CLEAR_NATIVE_OBJ_SPEED); + clearNativeObjSpeed = GetEcmaGCStats()->GetGCSpeed(SpeedData::YOUNG_CLEAR_NATIVE_OBJ_SPEED); } else if (markType_ == MarkType::MARK_FULL) { - clearNativeObjSpeed = ecmaVm_->GetEcmaGCStats()->GetGCSpeed(SpeedData::OLD_CLEAR_NATIVE_OBJ_SPEED); + clearNativeObjSpeed = GetEcmaGCStats()->GetGCSpeed(SpeedData::OLD_CLEAR_NATIVE_OBJ_SPEED); } if (clearNativeObjSpeed != 0) { @@ -968,10 +1181,10 @@ void Heap::CalculateIdleDuration() } // sweep and evacuate duration - size_t youngEvacuateSpeed = ecmaVm_->GetEcmaGCStats()->GetGCSpeed(SpeedData::YOUNG_EVACUATE_SPACE_SPEED); - size_t sweepSpeed = ecmaVm_->GetEcmaGCStats()->GetGCSpeed(SpeedData::SWEEP_SPEED); - size_t oldEvacuateSpeed = ecmaVm_->GetEcmaGCStats()->GetGCSpeed(SpeedData::OLD_EVACUATE_SPACE_SPEED); - double survivalRate = ecmaVm_->GetEcmaGCStats()->GetAvgSurvivalRate(); + size_t youngEvacuateSpeed = GetEcmaGCStats()->GetGCSpeed(SpeedData::YOUNG_EVACUATE_SPACE_SPEED); + size_t sweepSpeed = GetEcmaGCStats()->GetGCSpeed(SpeedData::SWEEP_SPEED); + size_t oldEvacuateSpeed = GetEcmaGCStats()->GetGCSpeed(SpeedData::OLD_EVACUATE_SPACE_SPEED); + double survivalRate = GetEcmaGCStats()->GetAvgSurvivalRate(); if (markType_ == MarkType::MARK_YOUNG && youngEvacuateSpeed != 0) { idlePredictDuration_ += survivalRate * activeSemiSpace_->GetHeapObjectSize() / youngEvacuateSpeed; } else if (markType_ == MarkType::MARK_FULL) { @@ -979,7 +1192,7 @@ void Heap::CalculateIdleDuration() idlePredictDuration_ += (float)GetHeapObjectSize() / sweepSpeed; } if (oldEvacuateSpeed != 0) { - size_t collectRegionSetSize = GetEcmaVM()->GetEcmaGCStats()->GetRecordData( + size_t collectRegionSetSize = GetEcmaGCStats()->GetRecordData( RecordData::COLLECT_REGION_SET_SIZE); idlePredictDuration_ += (survivalRate * activeSemiSpace_->GetHeapObjectSize() + collectRegionSetSize) / oldEvacuateSpeed; @@ -987,7 +1200,7 @@ void Heap::CalculateIdleDuration() } // Idle YoungGC mark duration - size_t markSpeed = ecmaVm_->GetEcmaGCStats()->GetGCSpeed(SpeedData::MARK_SPEED); + size_t markSpeed = GetEcmaGCStats()->GetGCSpeed(SpeedData::MARK_SPEED); if (idleTask_ == IdleTaskType::YOUNG_GC && markSpeed != 0) { idlePredictDuration_ += (float)activeSemiSpace_->GetHeapObjectSize() / markSpeed; } @@ -1085,8 +1298,7 @@ void Heap::TryTriggerConcurrentMarking() double newSpaceAllocSpeed = memController_->GetNewSpaceAllocationThroughputPerMS(); double newSpaceConcurrentMarkSpeed = memController_->GetNewSpaceConcurrentMarkSpeedPerMS(); if (newSpaceConcurrentMarkSpeed == 0 || newSpaceAllocSpeed == 0) { - auto &config = ecmaVm_->GetEcmaParamConfiguration(); - if (activeSemiSpace_->GetCommittedSize() >= config.GetSemiSpaceTriggerConcurrentMark()) { + if (activeSemiSpace_->GetCommittedSize() >= config_.GetSemiSpaceTriggerConcurrentMark()) { markType_ = MarkType::MARK_YOUNG; TriggerConcurrentMarking(); OPTIONAL_LOG(ecmaVm_, INFO) << "Trigger the first semi mark" << fullGCRequested_; @@ -1163,22 +1375,6 @@ void Heap::TriggerConcurrentMarking() } } -void Heap::WaitRunningTaskFinished() -{ - LockHolder holder(waitTaskFinishedMutex_); - while (runningTaskCount_ > 0) { - waitTaskFinishedCV_.Wait(&waitTaskFinishedMutex_); - } -} - -void Heap::WaitClearTaskFinished() -{ - LockHolder holder(waitClearTaskFinishedMutex_); - while (!clearTaskFinished_) { - waitClearTaskFinishedCV_.Wait(&waitClearTaskFinishedMutex_); - } -} - void Heap::WaitAllTasksFinished() { WaitRunningTaskFinished(); @@ -1201,12 +1397,6 @@ void Heap::PostParallelGCTask(ParallelGCTaskPhase gcTask) std::make_unique(GetJSThread()->GetThreadId(), this, gcTask)); } -void Heap::IncreaseTaskCount() -{ - LockHolder holder(waitTaskFinishedMutex_); - runningTaskCount_++; -} - void Heap::ChangeGCParams(bool inBackground) { inBackground_ = inBackground; @@ -1239,6 +1429,16 @@ void Heap::ChangeGCParams(bool inBackground) } } +GCStats *Heap::GetEcmaGCStats() +{ + return ecmaVm_->GetEcmaGCStats(); +} + +JSObjectResizingStrategy *Heap::GetJSObjectResizingStrategy() +{ + return ecmaVm_->GetJSObjectResizingStrategy(); +} + void Heap::TriggerIdleCollection(int idleMicroSec) { if (idleTask_ == IdleTaskType::NO_TASK) { @@ -1308,7 +1508,7 @@ void Heap::NotifyFinishColdStart(bool isMainThread) int64_t semiRemainSize = static_cast(GetNewSpace()->GetInitialCapacity() - GetNewSpace()->GetCommittedSize()); int64_t overshootSize = - static_cast(GetEcmaVM()->GetEcmaParamConfiguration().GetOldSpaceOvershootSize()) - semiRemainSize; + static_cast(config_.GetOldSpaceOvershootSize()) - semiRemainSize; // overshoot size should be larger than 0. GetNewSpace()->SetOverShootSize(std::max(overshootSize, (int64_t)0)); GetNewSpace()->SetWaterLineWithoutGC(); @@ -1347,7 +1547,7 @@ void Heap::HandleExitHighSensitiveEvent() int64_t semiRemainSize = static_cast(GetNewSpace()->GetInitialCapacity() - GetNewSpace()->GetCommittedSize()); int64_t overshootSize = - static_cast(GetEcmaVM()->GetEcmaParamConfiguration().GetOldSpaceOvershootSize()) - semiRemainSize; + static_cast(config_.GetOldSpaceOvershootSize()) - semiRemainSize; // overshoot size should be larger than 0. GetNewSpace()->SetOverShootSize(std::max(overshootSize, (int64_t)0)); GetNewSpace()->SetWaterLineWithoutGC(); @@ -1363,8 +1563,8 @@ void Heap::HandleExitHighSensitiveEvent() // concurrent mark bool Heap::ObjectExceedMaxHeapSize() const { - size_t configMaxHeapSize = ecmaVm_->GetEcmaParamConfiguration().GetMaxHeapSize(); - size_t overshootSize = ecmaVm_->GetEcmaParamConfiguration().GetOldSpaceOvershootSize(); + size_t configMaxHeapSize = config_.GetMaxHeapSize(); + size_t overshootSize = config_.GetOldSpaceOvershootSize(); return GetHeapObjectSize() > configMaxHeapSize - overshootSize; } @@ -1385,25 +1585,10 @@ bool Heap::NeedStopCollection() LOG_GC(INFO) << "SmartGC: force expand will cause OOM, have to trigger gc"; GetNewSpace()->SetOverShootSize( GetNewSpace()->GetCommittedSize() - GetNewSpace()->GetInitialCapacity() + - ecmaVm_->GetEcmaParamConfiguration().GetOldSpaceOvershootSize()); + config_.GetOldSpaceOvershootSize()); return false; } -bool Heap::CheckCanDistributeTask() -{ - LockHolder holder(waitTaskFinishedMutex_); - return runningTaskCount_ < maxMarkTaskCount_; -} - -void Heap::ReduceTaskCount() -{ - LockHolder holder(waitTaskFinishedMutex_); - runningTaskCount_--; - if (runningTaskCount_ == 0) { - waitTaskFinishedCV_.SignalAll(); - } -} - bool Heap::ParallelGCTask::Run(uint32_t threadIndex) { // Synchronizes-with. Ensure that WorkManager::Initialize must be seen by MarkerThreads. @@ -1475,11 +1660,10 @@ size_t Heap::GetLiveObjectSize() const size_t Heap::GetHeapLimitSize() const { // Obtains the theoretical upper limit of space that can be allocated to JS heap. - auto &config = ecmaVm_->GetEcmaParamConfiguration(); - return config.GetMaxHeapSize(); + return config_.GetMaxHeapSize(); } -bool Heap::IsAlive(TaggedObject *object) const +bool BaseHeap::IsAlive(TaggedObject *object) const { if (!ContainObject(object)) { LOG_GC(ERROR) << "The region is already free"; @@ -1496,7 +1680,7 @@ bool Heap::IsAlive(TaggedObject *object) const return !isFree; } -bool Heap::ContainObject(TaggedObject *object) const +bool BaseHeap::ContainObject(TaggedObject *object) const { /* * fixme: There's no absolutely safe appraoch to doing this, given that the region object is currently @@ -1511,26 +1695,6 @@ bool Heap::ContainObject(TaggedObject *object) const return region->InHeapSpace(); } -void Heap::InvokeWeakNodeNativeFinalizeCallback() -{ - // the second callback may lead to another GC, if this, return directly; - if (runningNativeFinalizeCallbacks_) { - return; - } - runningNativeFinalizeCallbacks_ = true; - auto weakNodeNativeFinalizeCallBacks = thread_->GetWeakNodeNativeFinalizeCallbacks(); - ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "InvokeNativeFinalizeCallbacks num:" - + std::to_string(weakNodeNativeFinalizeCallBacks->size())); - while (!weakNodeNativeFinalizeCallBacks->empty()) { - auto callbackPair = weakNodeNativeFinalizeCallBacks->back(); - weakNodeNativeFinalizeCallBacks->pop_back(); - ASSERT(callbackPair.first != nullptr && callbackPair.second != nullptr); - auto callback = callbackPair.first; - (*callback)(callbackPair.second); - } - runningNativeFinalizeCallbacks_ = false; -} - void Heap::PrintHeapInfo(TriggerGCType gcType) const { OPTIONAL_LOG(ecmaVm_, INFO) << "-----------------------Statistic Heap Object------------------------"; @@ -1666,4 +1830,40 @@ void Heap::RemoveGCListener(GCListenerId listenerId) gcListeners_.erase(listenerId); } +void BaseHeap::IncreaseTaskCount() +{ + LockHolder holder(waitTaskFinishedMutex_); + runningTaskCount_++; +} + +void BaseHeap::WaitRunningTaskFinished() +{ + LockHolder holder(waitTaskFinishedMutex_); + while (runningTaskCount_ > 0) { + waitTaskFinishedCV_.Wait(&waitTaskFinishedMutex_); + } +} + +bool BaseHeap::CheckCanDistributeTask() +{ + LockHolder holder(waitTaskFinishedMutex_); + return runningTaskCount_ < maxMarkTaskCount_; +} + +void BaseHeap::ReduceTaskCount() +{ + LockHolder holder(waitTaskFinishedMutex_); + runningTaskCount_--; + if (runningTaskCount_ == 0) { + waitTaskFinishedCV_.SignalAll(); + } +} + +void BaseHeap::WaitClearTaskFinished() +{ + LockHolder holder(waitClearTaskFinishedMutex_); + while (!clearTaskFinished_) { + waitClearTaskFinishedCV_.Wait(&waitClearTaskFinishedMutex_); + } +} } // namespace panda::ecmascript diff --git a/ecmascript/mem/heap.h b/ecmascript/mem/heap.h index b1149d045c2b6e5ed70c3c568e3d7c4fbce6ac73..accca24841f4fc48f5e5068b9e467b8a6c6ed9cf 100644 --- a/ecmascript/mem/heap.h +++ b/ecmascript/mem/heap.h @@ -21,6 +21,7 @@ #include "ecmascript/js_thread.h" #include "ecmascript/mem/linear_space.h" #include "ecmascript/mem/mark_stack.h" +#include "ecmascript/mem/shared_heap/shared_space.h" #include "ecmascript/mem/sparse_space.h" #include "ecmascript/mem/work_manager.h" #include "ecmascript/taskpool/taskpool.h" @@ -30,6 +31,7 @@ class ConcurrentMarker; class ConcurrentSweeper; class EcmaVM; class FullGC; +class GCStats; class HeapRegionAllocator; class HeapTracker; #if !WIN_OR_MAC_OR_IOS_PLATFORM @@ -43,6 +45,9 @@ class MemController; class NativeAreaAllocator; class ParallelEvacuator; class PartialGC; +class SharedConcurrentSweeper; +class SharedGC; +class SharedGCMarker; class STWYoungGC; using IdleNotifyStatusCallback = std::function; @@ -86,18 +91,476 @@ enum class VerifyKind { VERIFY_EVACUATE_YOUNG, VERIFY_CONCURRENT_MARK_FULL, VERIFY_EVACUATE_OLD, - VERIFY_EVACUATE_FULL + VERIFY_EVACUATE_FULL, + VERIFY_SHARED_RSET_POST_FULL_GC, + VERIFY_PRE_SHARED_GC, + VERIFY_POST_SHARED_GC }; -class Heap { +class BaseHeap { +public: + BaseHeap(const EcmaParamConfiguration &config) : config_(config) {} + virtual ~BaseHeap() = default; + NO_COPY_SEMANTIC(BaseHeap); + NO_MOVE_SEMANTIC(BaseHeap); + + virtual bool IsMarking() const = 0; + + virtual bool IsReadyToMark() const = 0; + + virtual bool NeedStopCollection() = 0; + + virtual void TryTriggerConcurrentMarking() = 0; + + virtual void TryTriggerIdleCollection() = 0; + + virtual void TryTriggerIncrementalMarking() = 0; + + virtual bool OldSpaceExceedCapacity(size_t size) const = 0; + + virtual bool OldSpaceExceedLimit() const = 0; + + virtual inline size_t GetCommittedSize() const = 0; + + virtual inline size_t GetHeapObjectSize() const = 0; + + virtual void ChangeGCParams(bool inBackground) = 0; + + virtual const GlobalEnvConstants *GetGlobalConst() const = 0; + + virtual GCStats *GetEcmaGCStats() = 0; + + void SetMarkType(MarkType markType) + { + markType_ = markType; + } + + bool IsFullMark() const + { + return markType_ == MarkType::MARK_FULL; + } + + bool IsConcurrentFullMark() const + { + return markType_ == MarkType::MARK_FULL; + } + + TriggerGCType GetGCType() const + { + return gcType_; + } + + bool IsAlive(TaggedObject *object) const; + + bool ContainObject(TaggedObject *object) const; + + void SetOnSerializeEvent(bool isSerialize) + { + onSerializeEvent_ = isSerialize; + if (!onSerializeEvent_ && !InSensitiveStatus()) { + TryTriggerIncrementalMarking(); + TryTriggerIdleCollection(); + TryTriggerConcurrentMarking(); + } + } + + bool GetOnSerializeEvent() const + { + return onSerializeEvent_; + } + + bool GetOldGCRequested() + { + return oldGCRequested_; + } + + EcmaParamConfiguration GetEcmaParamConfiguration() const + { + return config_; + } + + NativeAreaAllocator *GetNativeAreaAllocator() const + { + return nativeAreaAllocator_; + } + + HeapRegionAllocator *GetHeapRegionAllocator() const + { + return heapRegionAllocator_; + } + + void ShouldThrowOOMError(bool shouldThrow) + { + shouldThrowOOMError_ = shouldThrow; + } + + bool IsInBackground() const + { + return inBackground_; + } + + // ONLY used for heap verification. + bool IsVerifying() const + { + return isVerifying_; + } + + // ONLY used for heap verification. + void SetVerifying(bool verifying) + { + isVerifying_ = verifying; + } + + void NotifyHeapAliveSizeAfterGC(size_t size) + { + heapAliveSizeAfterGC_ = size; + } + + size_t GetHeapAliveSizeAfterGC() const + { + return heapAliveSizeAfterGC_; + } + + bool InSensitiveStatus() const + { + return sensitiveStatus_.load(std::memory_order_relaxed) == AppSensitiveStatus::ENTER_HIGH_SENSITIVE + || onStartupEvent_; + } + + AppSensitiveStatus GetSensitiveStatus() const + { + return sensitiveStatus_.load(std::memory_order_relaxed); + } + + bool onStartUpEvent() const + { + return onStartupEvent_; + } + + void SetSensitiveStatus(AppSensitiveStatus status) + { + sensitiveStatus_.store(status, std::memory_order_release);; + } + + bool CASSensitiveStatus(AppSensitiveStatus expect, AppSensitiveStatus status) + { + return sensitiveStatus_.compare_exchange_strong(expect, status, std::memory_order_seq_cst); + } + + void NotifyPostFork() + { + LockHolder holder(finishColdStartMutex_); + onStartupEvent_ = true; + LOG_GC(INFO) << "SmartGC: enter app cold start"; + } + + // Whether should verify heap during gc. + bool ShouldVerifyHeap() const + { + return shouldVerifyHeap_; + } + + void ThrowOutOfMemoryErrorForDefault(JSThread *thread, size_t size, std::string functionName, + bool NonMovableObjNearOOM = false); + + uint32_t GetMaxMarkTaskCount() const + { + return maxMarkTaskCount_; + } + + bool CheckCanDistributeTask(); + void IncreaseTaskCount(); + void ReduceTaskCount(); + void WaitRunningTaskFinished(); + void WaitClearTaskFinished(); + void ThrowOutOfMemoryError(JSThread *thread, size_t size, std::string functionName, + bool NonMovableObjNearOOM = false); + +protected: + void FatalOutOfMemoryError(size_t size, std::string functionName); + + const EcmaParamConfiguration config_; + MarkType markType_ {MarkType::MARK_YOUNG}; + TriggerGCType gcType_ {TriggerGCType::YOUNG_GC}; + Mutex gcCollectGarbageMutex_; + // Region allocators. + NativeAreaAllocator *nativeAreaAllocator_ {nullptr}; + HeapRegionAllocator *heapRegionAllocator_ {nullptr}; + + size_t heapAliveSizeAfterGC_ {0}; + size_t globalSpaceAllocLimit_ {0}; + // parallel marker task count. + uint32_t runningTaskCount_ {0}; + uint32_t maxMarkTaskCount_ {0}; + Mutex waitTaskFinishedMutex_; + ConditionVariable waitTaskFinishedCV_; + Mutex waitClearTaskFinishedMutex_; + ConditionVariable waitClearTaskFinishedCV_; + bool clearTaskFinished_ {true}; + bool inBackground_ {false}; + bool shouldThrowOOMError_ {false}; + bool oldGCRequested_ {false}; + bool onSerializeEvent_ {false}; + std::atomic sensitiveStatus_ {AppSensitiveStatus::NORMAL_SCENE}; + bool onStartupEvent_ {false}; + Mutex finishColdStartMutex_; + // ONLY used for heap verification. + bool shouldVerifyHeap_ {false}; + bool isVerifying_ {false}; +}; + +class SharedHeap : public BaseHeap { +public: + SharedHeap(const EcmaParamConfiguration &config) : BaseHeap(config) {} + virtual ~SharedHeap() = default; + + static SharedHeap* GetInstance(); + + void Initialize(NativeAreaAllocator *nativeAreaAllocator, HeapRegionAllocator *heapRegionAllocator, + const JSRuntimeOptions &option); + + void PostInitialization(const GlobalEnvConstants *globalEnvConstants, const JSRuntimeOptions &option); + + void EnableParallelGC(JSRuntimeOptions &option); + void DisableParallelGC(); + class ParallelMarkTask : public Task { + public: + ParallelMarkTask(int32_t id, SharedHeap *heap) + : Task(id), sHeap_(heap) {}; + ~ParallelMarkTask() override = default; + bool Run(uint32_t threadIndex) override; + + NO_COPY_SEMANTIC(ParallelMarkTask); + NO_MOVE_SEMANTIC(ParallelMarkTask); + + private: + SharedHeap *sHeap_ {nullptr}; + }; + + class AsyncClearTask : public Task { + public: + AsyncClearTask(int32_t id, SharedHeap *heap) + : Task(id), sHeap_(heap) {} + ~AsyncClearTask() override = default; + bool Run(uint32_t threadIndex) override; + + NO_COPY_SEMANTIC(AsyncClearTask); + NO_MOVE_SEMANTIC(AsyncClearTask); + private: + SharedHeap *sHeap_; + }; + bool IsMarking() const override + { + LOG_FULL(ERROR) << "SharedHeap IsMarking() not support yet"; + return false; + } + + bool IsReadyToMark() const override + { + return true; + } + + bool NeedStopCollection() override + { + return onSerializeEvent_; + } + + bool CheckAndTriggerGC(JSThread *thread, size_t size = 0); + + bool CheckHugeAndTriggerGC(JSThread *thread, size_t size); + + void TryTriggerConcurrentMarking() override + { + LOG_FULL(ERROR) << "SharedHeap TryTriggerConcurrentMarking() not support yet"; + return; + } + + void TryTriggerIdleCollection() override + { + LOG_FULL(ERROR) << "SharedHeap TryTriggerIdleCollection() not support yet"; + return; + } + + void TryTriggerIncrementalMarking() override + { + LOG_FULL(ERROR) << "SharedHeap TryTriggerIncrementalMarking() not support yet"; + return; + } + + bool OldSpaceExceedCapacity(size_t size) const override + { + size_t totalSize = sOldSpace_->GetCommittedSize() + size; + return totalSize >= sOldSpace_->GetMaximumCapacity() + sOldSpace_->GetOutOfMemoryOvershootSize(); + } + + bool OldSpaceExceedLimit() const override + { + return sOldSpace_->GetHeapObjectSize() >= sOldSpace_->GetInitialCapacity(); + } + + SharedConcurrentSweeper *GetSweeper() const + { + return sSweeper_; + } + + bool IsParallelGCEnabled() const + { + return parallelGC_; + } + + SharedOldSpace *GetOldSpace() const + { + return sOldSpace_; + } + + SharedNonMovableSpace *GetNonMovableSpace() const + { + return sNonMovableSpace_; + } + + SharedHugeObjectSpace *GetHugeObjectSpace() const + { + return sHugeObjectSpace_; + } + + SharedReadOnlySpace *GetReadOnlySpace() const + { + return sReadOnlySpace_; + } + + void CollectGarbage(JSThread *thread, TriggerGCType gcType, GCReason reason); + void CollectGarbageImpl(TriggerGCType gcType, GCReason reason); + + void SetMaxMarkTaskCount(uint32_t maxTaskCount) + { + maxMarkTaskCount_ = maxTaskCount; + } + + inline size_t GetCommittedSize() const override + { + size_t result = sOldSpace_->GetCommittedSize() + + sHugeObjectSpace_->GetCommittedSize() + + sNonMovableSpace_->GetCommittedSize() + + sReadOnlySpace_->GetCommittedSize(); + return result; + } + + inline size_t GetHeapObjectSize() const override + { + size_t result = sOldSpace_->GetHeapObjectSize() + + sHugeObjectSpace_->GetHeapObjectSize() + + sNonMovableSpace_->GetHeapObjectSize() + + sReadOnlySpace_->GetCommittedSize(); + return result; + } + + void ChangeGCParams([[maybe_unused]]bool inBackground) override + { + LOG_FULL(ERROR) << "SharedHeap ChangeGCParams() not support yet"; + return; + } + + GCStats *GetEcmaGCStats() override + { + return sGCStats_; + } + + inline void SetGlobalEnvConstants(const GlobalEnvConstants *globalEnvConstants) + { + globalEnvConstants_ = globalEnvConstants; + } + + inline const GlobalEnvConstants *GetGlobalConst() const override + { + return globalEnvConstants_; + } + + SharedSparseSpace *GetSpaceWithType(MemSpaceType type) const + { + switch (type) { + case MemSpaceType::SHARED_OLD_SPACE: + return sOldSpace_; + case MemSpaceType::SHARED_NON_MOVABLE: + return sNonMovableSpace_; + default: + LOG_ECMA(FATAL) << "this branch is unreachable"; + UNREACHABLE(); + break; + } + } + + void Prepare(); + void Reclaim(); + void PostGCMarkingTask(); + + SharedGCWorkManager *GetWorkManager() const + { + return sWorkManager_; + } + + SharedGCMarker *GetSharedGCMarker() const + { + return sharedGCMarker_; + } + + void PrepareRecordRegionsForReclaim(); + + template + void EnumerateOldSpaceRegions(const Callback &cb) const; + + template + void EnumerateOldSpaceRegionsWithRecord(const Callback &cb) const; + + template + void IterateOverObjects(const Callback &cb) const; + + inline TaggedObject *AllocateClassClass(JSHClass *hclass, size_t size); + + inline TaggedObject *AllocateNonMovableOrHugeObject(JSThread *thread, JSHClass *hclass); + + inline TaggedObject *AllocateNonMovableOrHugeObject(JSThread *thread, JSHClass *hclass, size_t size); + + inline TaggedObject *AllocateOldOrHugeObject(JSThread *thread, JSHClass *hclass); + + inline TaggedObject *AllocateOldOrHugeObject(JSThread *thread, JSHClass *hclass, size_t size); + + inline TaggedObject *AllocateOldOrHugeObject(JSThread *thread, size_t size); + + inline TaggedObject *AllocateHugeObject(JSThread *thread, JSHClass *hclass, size_t size); + + inline TaggedObject *AllocateHugeObject(JSThread *thread, size_t size); + + inline TaggedObject *AllocateReadOnlyOrHugeObject(JSThread *thread, JSHClass *hclass); + + inline TaggedObject *AllocateReadOnlyOrHugeObject(JSThread *thread, JSHClass *hclass, size_t size); + + size_t VerifyHeapObjects(VerifyKind verifyKind) const; +private: + void ReclaimRegions(); + + bool parallelGC_ {true}; + GCStats *sGCStats_ {nullptr}; + const GlobalEnvConstants *globalEnvConstants_ {nullptr}; + SharedOldSpace *sOldSpace_ {nullptr}; + SharedNonMovableSpace *sNonMovableSpace_ {nullptr}; + SharedReadOnlySpace *sReadOnlySpace_ {nullptr}; + SharedHugeObjectSpace *sHugeObjectSpace_ {nullptr}; + SharedGCWorkManager *sWorkManager_ {nullptr}; + SharedConcurrentSweeper *sSweeper_ {nullptr}; + SharedGC *sharedGC_ {nullptr}; + SharedGCMarker *sharedGCMarker_ {nullptr}; +}; + +class Heap : public BaseHeap { public: explicit Heap(EcmaVM *ecmaVm); - ~Heap() = default; + virtual ~Heap() = default; NO_COPY_SEMANTIC(Heap); NO_MOVE_SEMANTIC(Heap); void Initialize(); void Destroy(); void Prepare(); + void GetHeapPrepare(); void Resume(TriggerGCType gcType); void ResumeForAppSpawn(); void CompactHeapBeforeFork(); @@ -242,63 +705,14 @@ public: return workManager_; } - MemController *GetMemController() const - { - return memController_; - } - - bool InSensitiveStatus() const + const GlobalEnvConstants *GetGlobalConst() const override { - return sensitiveStatus_.load(std::memory_order_relaxed) == AppSensitiveStatus::ENTER_HIGH_SENSITIVE - || onStartupEvent_; + return thread_->GlobalConstants(); } - AppSensitiveStatus GetSensitiveStatus() const - { - return sensitiveStatus_.load(std::memory_order_relaxed); - } - - bool onStartUpEvent() const - { - return onStartupEvent_; - } - - void SetSensitiveStatus(AppSensitiveStatus status) - { - sensitiveStatus_.store(status, std::memory_order_release);; - } - - bool CASSensitiveStatus(AppSensitiveStatus expect, AppSensitiveStatus status) - { - return sensitiveStatus_.compare_exchange_strong(expect, status, std::memory_order_seq_cst); - } - - void NotifyPostFork() - { - LockHolder holder(finishColdStartMutex_); - onStartupEvent_ = true; - LOG_GC(INFO) << "SmartGC: enter app cold start"; - } - - void SetOnSerializeEvent(bool isSerialize) - { - onSerializeEvent_ = isSerialize; - if (!onSerializeEvent_ && !InSensitiveStatus()) { - TryTriggerIncrementalMarking(); - TryTriggerIdleCollection(); - TryTriggerConcurrentMarking(); - } - } - - bool GetOnSerializeEvent() const - { - return onSerializeEvent_; - } - - // Whether should verify heap during gc. - bool ShouldVerifyHeap() const + MemController *GetMemController() const { - return shouldVerifyHeap_; + return memController_; } /* @@ -329,22 +743,10 @@ public: // Snapshot inline uintptr_t AllocateSnapshotSpace(size_t size); - NativeAreaAllocator *GetNativeAreaAllocator() const - { - return nativeAreaAllocator_; - } - - HeapRegionAllocator *GetHeapRegionAllocator() const - { - return heapRegionAllocator_; - } - /* * GC triggers. */ - void CollectGarbage(TriggerGCType gcType, GCReason reason = GCReason::OTHER); - bool CheckAndTriggerOldGC(size_t size = 0); bool CheckAndTriggerHintGC(); TriggerGCType SelectGCType() const; @@ -358,20 +760,22 @@ public: { return parallelGC_; } - void ChangeGCParams(bool inBackground); + void ChangeGCParams(bool inBackground) override; + + GCStats *GetEcmaGCStats() override; + + JSObjectResizingStrategy *GetJSObjectResizingStrategy(); + void TriggerIdleCollection(int idleMicroSec); void NotifyMemoryPressure(bool inHighMemoryPressure); - bool CheckCanDistributeTask(); - void WaitRunningTaskFinished(); - - void TryTriggerConcurrentMarking(); + void TryTriggerConcurrentMarking() override; void AdjustBySurvivalRate(size_t originalNewSpaceSize); void TriggerConcurrentMarking(); bool CheckCanTriggerConcurrentMarking(); - void TryTriggerIdleCollection(); - void TryTriggerIncrementalMarking(); + void TryTriggerIdleCollection() override; + void TryTriggerIncrementalMarking() override; void CalculateIdleDuration(); void UpdateWorkManager(WorkManager *workManager); /* @@ -380,20 +784,6 @@ public: */ bool CheckOngoingConcurrentMarking(); - /* - * Functions invoked during GC. - */ - - void SetMarkType(MarkType markType) - { - markType_ = markType; - } - - bool IsConcurrentFullMark() const - { - return markType_ == MarkType::MARK_FULL; - } - inline void SwapNewSpace(); inline void SwapOldSpace(); @@ -436,9 +826,20 @@ public: memGrowingtype_ = memGrowingType; } - inline size_t GetCommittedSize() const; + size_t CalculateLinearSpaceOverShoot() + { + return oldSpace_->GetMaximumCapacity() - oldSpace_->GetInitialCapacity(); + } + + inline size_t GetCommittedSize() const override; + + inline size_t GetHeapObjectSize() const override; + + size_t GetRegionCachedSize() const + { + return activeSemiSpace_->GetInitialCapacity(); + } - inline size_t GetHeapObjectSize() const; size_t GetLiveObjectSize() const; inline uint32_t GetHeapObjectCount() const; @@ -452,11 +853,6 @@ public: size_t GetHeapLimitSize() const; - uint32_t GetMaxMarkTaskCount() const - { - return maxMarkTaskCount_; - } - uint32_t GetMaxEvacuateTaskCount() const { return maxEvacuateTaskCount_; @@ -488,7 +884,7 @@ public: void ClearIdleTask(); - bool IsEmptyIdleTask() const + bool IsEmptyIdleTask() { return idleTask_ == IdleTaskType::NO_TASK; } @@ -503,7 +899,7 @@ public: bool ObjectExceedMaxHeapSize() const; - bool NeedStopCollection(); + bool NeedStopCollection() override; #if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER) void StartHeapTracking() @@ -534,23 +930,20 @@ public: template void IterateOverObjects(const Callback &cb) const; - bool IsAlive(TaggedObject *object) const; - bool ContainObject(TaggedObject *object) const; - size_t VerifyHeapObjects(VerifyKind verifyKind = VerifyKind::VERIFY_PRE_GC) const; size_t VerifyOldToNewRSet(VerifyKind verifyKind = VerifyKind::VERIFY_PRE_GC) const; void StatisticHeapObject(TriggerGCType gcType) const; void StatisticHeapDetail() const; void PrintHeapInfo(TriggerGCType gcType) const; - bool OldSpaceExceedCapacity(size_t size) const + bool OldSpaceExceedCapacity(size_t size) const override { size_t totalSize = oldSpace_->GetCommittedSize() + hugeObjectSpace_->GetCommittedSize() + size; return totalSize >= oldSpace_->GetMaximumCapacity() + oldSpace_->GetOvershootSize() + oldSpace_->GetOutOfMemoryOvershootSize(); } - bool OldSpaceExceedLimit() const + bool OldSpaceExceedLimit() const override { size_t totalSize = oldSpace_->GetHeapObjectSize() + hugeObjectSpace_->GetHeapObjectSize(); return totalSize >= oldSpace_->GetInitialCapacity() + oldSpace_->GetOvershootSize(); @@ -558,18 +951,6 @@ public: void AdjustSpaceSizeForAppSpawn(); - // ONLY used for heap verification. - bool IsVerifying() const - { - return isVerifying_; - } - - // ONLY used for heap verification. - void SetVerifying(bool verifying) - { - isVerifying_ = verifying; - } - static bool ShouldMoveToRoSpace(JSHClass *hclass, TaggedObject *object) { return hclass->IsString() && !Region::ObjectAddressToRange(object)->InHugeObjectSpace(); @@ -585,19 +966,11 @@ public: fullMarkRequested_ = fullMarkRequested; } - void ShouldThrowOOMError(bool shouldThrow) - { - shouldThrowOOMError_ = shouldThrow; - } - void SetHeapMode(HeapMode mode) { mode_ = mode; } - void ThrowOutOfMemoryError(size_t size, std::string functionName, bool NonMovableObjNearOOM = false); - void ThrowOutOfMemoryErrorForDefault(size_t size, std::string functionName, bool NonMovableObjNearOOM = false); - void IncreaseNativeBindingSize(size_t size); void IncreaseNativeBindingSize(JSNativePointer *object); void ResetNativeBindingSize() @@ -622,19 +995,14 @@ public: void TryTriggerFullMarkByNativeSize(); - void NotifyHeapAliveSizeAfterGC(size_t size) - { - heapAliveSizeAfterGC_ = size; - } - - size_t GetHeapAliveSizeAfterGC() const + bool IsMarking() const override { - return heapAliveSizeAfterGC_; + return thread_->IsMarking(); } - bool IsInBackground() const + bool IsReadyToMark() const override { - return inBackground_; + return thread_->IsReadyToMark(); } bool IsYoungGC() const @@ -642,16 +1010,6 @@ public: return gcType_ == TriggerGCType::YOUNG_GC; } - bool GetOldGCRequested() - { - return oldGCRequested_; - } - - TriggerGCType GetGCType() const - { - return gcType_; - } - void CheckNonMovableSpaceOOM(); std::tuple CalCallSiteInfo(uintptr_t retAddr) const; @@ -664,15 +1022,10 @@ private: static constexpr int BACKGROUND_GROW_LIMIT = 2_MB; // Threadshold that HintGC will actually trigger GC. static constexpr double SURVIVAL_RATE_THRESHOLD = 0.5; - void FatalOutOfMemoryError(size_t size, std::string functionName); void RecomputeLimits(); void AdjustOldSpaceLimit(); // record lastRegion for each space, which will be used in ReclaimRegions() void PrepareRecordRegionsForReclaim(); - void IncreaseTaskCount(); - void ReduceTaskCount(); - void WaitClearTaskFinished(); - void InvokeWeakNodeNativeFinalizeCallback(); void DumpHeapSnapshotBeforeOOM(bool isFullGC = true); inline void ReclaimRegions(TriggerGCType gcType); inline size_t CalculateCommittedCacheSize(); @@ -806,66 +1159,38 @@ private: // Work manager managing the tasks mostly generated in the GC mark phase. WorkManager *workManager_ {nullptr}; - MarkType markType_ {MarkType::MARK_YOUNG}; - bool parallelGC_ {true}; bool fullGCRequested_ {false}; - bool oldGCRequested_ {false}; bool fullMarkRequested_ {false}; bool oldSpaceLimitAdjusted_ {false}; - bool shouldThrowOOMError_ {false}; - bool runningNativeFinalizeCallbacks_ {false}; bool enableIdleGC_ {false}; HeapMode mode_ { HeapMode::NORMAL }; - size_t globalSpaceAllocLimit_ {0}; + /* + * The memory controller providing memory statistics (by allocations and coleections), + * which is used for GC heuristics. + */ + MemController *memController_ {nullptr}; size_t promotedSize_ {0}; size_t semiSpaceCopiedSize_ {0}; size_t nativeBindingSize_{0}; size_t globalSpaceNativeLimit_ {0}; MemGrowingType memGrowingtype_ {MemGrowingType::HIGH_THROUGHPUT}; - TriggerGCType gcType_ {TriggerGCType::YOUNG_GC}; - bool clearTaskFinished_ {true}; - Mutex waitClearTaskFinishedMutex_; - ConditionVariable waitClearTaskFinishedCV_; - uint32_t runningTaskCount_ {0}; - // parallel marker task number. - uint32_t maxMarkTaskCount_ {0}; // parallel evacuator task number. uint32_t maxEvacuateTaskCount_ {0}; - Mutex finishColdStartMutex_; Mutex waitTaskFinishedMutex_; ConditionVariable waitTaskFinishedCV_; - /* - * The memory controller providing memory statistics (by allocations and coleections), - * which is used for GC heuristics. - */ - MemController *memController_ {nullptr}; - - // Region allocators. - NativeAreaAllocator *nativeAreaAllocator_ {nullptr}; - HeapRegionAllocator *heapRegionAllocator_ {nullptr}; - // Application status - bool inBackground_ {false}; IdleNotifyStatusCallback notifyIdleStatusCallback {nullptr}; - std::atomic sensitiveStatus_ {AppSensitiveStatus::NORMAL_SCENE}; - bool onStartupEvent_ {false}; - bool onSerializeEvent_ {false}; IdleTaskType idleTask_ {IdleTaskType::NO_TASK}; float idlePredictDuration_ {0.0f}; - size_t heapAliveSizeAfterGC_ {0}; double idleTaskFinishTime_ {0.0}; int32_t recursionDepth_ {0}; - // ONLY used for heap verification. - bool shouldVerifyHeap_ {false}; - bool isVerifying_ {false}; - /* * The listeners which are called at the end of GC */ diff --git a/ecmascript/mem/heap_region_allocator.cpp b/ecmascript/mem/heap_region_allocator.cpp index 701e57e9259e7f424f500488bce7547825a05077..ff756445848f904b570d258f6b71d3dc34c2c034 100644 --- a/ecmascript/mem/heap_region_allocator.cpp +++ b/ecmascript/mem/heap_region_allocator.cpp @@ -16,8 +16,7 @@ #include "ecmascript/mem/heap_region_allocator.h" #include "ecmascript/ecma_vm.h" -#include "ecmascript/js_thread.h" -#include "ecmascript/mem/heap.h" +#include "ecmascript/mem/heap-inl.h" #include "ecmascript/mem/mark_stack.h" #include "ecmascript/mem/mem_map_allocator.h" #include "ecmascript/mem/region.h" @@ -27,7 +26,7 @@ namespace panda::ecmascript { constexpr size_t PANDA_POOL_ALIGNMENT_IN_BYTES = 256_KB; -Region *HeapRegionAllocator::AllocateAlignedRegion(Space *space, size_t capacity, JSThread* thread) +Region *HeapRegionAllocator::AllocateAlignedRegion(Space *space, size_t capacity, JSThread* thread, BaseHeap *heap) { if (capacity == 0) { LOG_ECMA_MEM(FATAL) << "capacity must have a size bigger than 0"; @@ -35,16 +34,20 @@ Region *HeapRegionAllocator::AllocateAlignedRegion(Space *space, size_t capacity } RegionSpaceFlag flags = space->GetRegionFlag(); bool isRegular = (flags != RegionSpaceFlag::IN_HUGE_OBJECT_SPACE && - flags != RegionSpaceFlag::IN_HUGE_MACHINE_CODE_SPACE); + flags != RegionSpaceFlag::IN_HUGE_MACHINE_CODE_SPACE && + flags != RegionSpaceFlag::IN_SHARED_HUGE_OBJECT_SPACE); bool isMachineCode = (flags == RegionSpaceFlag::IN_MACHINE_CODE_SPACE || flags == RegionSpaceFlag::IN_HUGE_MACHINE_CODE_SPACE); - auto pool = MemMapAllocator::GetInstance()->Allocate(thread->GetThreadId(), capacity, DEFAULT_REGION_SIZE, + auto tid = thread ? thread->GetThreadId() : JSThread::GetCurrentThreadId(); + auto pool = MemMapAllocator::GetInstance()->Allocate(tid, capacity, DEFAULT_REGION_SIZE, ToSpaceTypeName(space->GetSpaceType()), isRegular, isMachineCode); void *mapMem = pool.GetMem(); if (mapMem == nullptr) { - const_cast(thread->GetEcmaVM()->GetHeap())->ThrowOutOfMemoryErrorForDefault(DEFAULT_REGION_SIZE, - "HeapRegionAllocator::AllocateAlignedRegion", false); + if (thread != nullptr) { + heap->ThrowOutOfMemoryErrorForDefault(thread, DEFAULT_REGION_SIZE, + "HeapRegionAllocator::AllocateAlignedRegion", false); + } LOG_ECMA_MEM(FATAL) << "pool is empty " << annoMemoryUsage_.load(std::memory_order_relaxed); UNREACHABLE(); } @@ -64,7 +67,7 @@ Region *HeapRegionAllocator::AllocateAlignedRegion(Space *space, size_t capacity uintptr_t begin = AlignUp(mem + sizeof(Region), static_cast(MemAlignment::MEM_ALIGN_REGION)); uintptr_t end = mem + capacity; - Region *region = new (ToVoidPtr(mem)) Region(thread, mem, begin, end, flags); + Region *region = new (ToVoidPtr(mem)) Region(heap->GetNativeAreaAllocator(), mem, begin, end, flags); std::atomic_thread_fence(std::memory_order_seq_cst); return region; } @@ -72,7 +75,8 @@ Region *HeapRegionAllocator::AllocateAlignedRegion(Space *space, size_t capacity void HeapRegionAllocator::FreeRegion(Region *region, size_t cachedSize) { auto size = region->GetCapacity(); - bool isRegular = !region->InHugeObjectSpace() && !region->InHugeMachineCodeSpace(); + bool isRegular = !region->InHugeObjectSpace() && !region->InHugeMachineCodeSpace() && + !region->InSharedHugeObjectSpace(); auto allocateBase = region->GetAllocateBase(); DecreaseAnnoMemoryUsage(size); diff --git a/ecmascript/mem/heap_region_allocator.h b/ecmascript/mem/heap_region_allocator.h index b45ecfd3ccd0b530cbe8d1f9243e79048418b6fc..0f99515360f75c3739b917b37b3eaf2cdba26679 100644 --- a/ecmascript/mem/heap_region_allocator.h +++ b/ecmascript/mem/heap_region_allocator.h @@ -21,7 +21,7 @@ #include "ecmascript/mem/mem.h" namespace panda::ecmascript { -class JSThread; +class BaseHeap; class Region; class Space; @@ -30,7 +30,7 @@ public: HeapRegionAllocator() = default; virtual ~HeapRegionAllocator() = default; - Region *AllocateAlignedRegion(Space *space, size_t capacity, JSThread* thread); + Region *AllocateAlignedRegion(Space *space, size_t capacity, JSThread* thread, BaseHeap *heap); void FreeRegion(Region *region, size_t cachedSize); void IncreaseAnnoMemoryUsage(size_t bytes) diff --git a/ecmascript/mem/linear_space.cpp b/ecmascript/mem/linear_space.cpp index 57731c13194e9771d991700ecd530122399ae2a0..cd61042477327a968835858f9ed9499f8ebfa731 100644 --- a/ecmascript/mem/linear_space.cpp +++ b/ecmascript/mem/linear_space.cpp @@ -25,12 +25,14 @@ namespace panda::ecmascript { LinearSpace::LinearSpace(Heap *heap, MemSpaceType type, size_t initialCapacity, size_t maximumCapacity) : Space(heap, heap->GetHeapRegionAllocator(), type, initialCapacity, maximumCapacity), + localHeap_(heap), waterLine_(0) { } uintptr_t LinearSpace::Allocate(size_t size, bool isPromoted) { + ASSERT(localHeap_->GetJSThread()->IsInRunningStateOrProfiling()); auto object = allocator_.Allocate(size); if (object != 0) { #ifdef ECMASCRIPT_SUPPORT_HEAPSAMPLING @@ -42,18 +44,18 @@ uintptr_t LinearSpace::Allocate(size_t size, bool isPromoted) return object; } if (Expand(isPromoted)) { - if (!isPromoted && !heap_->NeedStopCollection()) { - heap_->TryTriggerIncrementalMarking(); - heap_->TryTriggerIdleCollection(); - heap_->TryTriggerConcurrentMarking(); + if (!isPromoted && !localHeap_->NeedStopCollection()) { + localHeap_->TryTriggerIncrementalMarking(); + localHeap_->TryTriggerIdleCollection(); + localHeap_->TryTriggerConcurrentMarking(); } object = allocator_.Allocate(size); - } else if (heap_->GetJSThread()->IsMarking() || !heap_->IsEmptyIdleTask()) { + } else if (localHeap_->IsMarking() || !localHeap_->IsEmptyIdleTask()) { // Temporary adjust semi space capacity - if (heap_->IsConcurrentFullMark()) { - overShootSize_ = heap_->GetOldSpace()->GetMaximumCapacity() - heap_->GetOldSpace()->GetInitialCapacity(); + if (localHeap_->IsConcurrentFullMark()) { + overShootSize_ = localHeap_->CalculateLinearSpaceOverShoot(); } else { - size_t stepOverShootSize = heap_->GetEcmaVM()->GetEcmaParamConfiguration().GetSemiSpaceStepOvershootSize(); + size_t stepOverShootSize = localHeap_->GetEcmaParamConfiguration().GetSemiSpaceStepOvershootSize(); size_t maxOverShootSize = std::max(initialCapacity_ / 2, stepOverShootSize); // 2: half if (overShootSize_ < maxOverShootSize) { overShootSize_ += stepOverShootSize; @@ -75,7 +77,7 @@ uintptr_t LinearSpace::Allocate(size_t size, bool isPromoted) bool LinearSpace::Expand(bool isPromoted) { if (committedSize_ >= initialCapacity_ + overShootSize_ + outOfMemoryOvershootSize_ && - !heap_->NeedStopCollection()) { + !localHeap_->NeedStopCollection()) { return false; } @@ -95,7 +97,8 @@ bool LinearSpace::Expand(bool isPromoted) } currentRegion->SetHighWaterMark(top); } - Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, heap_->GetJSThread()); + JSThread *thread = localHeap_->GetJSThread(); + Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, thread, localHeap_); allocator_.Reset(region->GetBegin(), region->GetEnd()); AddRegion(region); @@ -169,7 +172,8 @@ SemiSpace::SemiSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity) void SemiSpace::Initialize() { - Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, heap_->GetJSThread()); + JSThread *thread = localHeap_->GetJSThread(); + Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, thread, localHeap_); AddRegion(region); allocator_.Reset(region->GetBegin(), region->GetEnd()); } @@ -261,7 +265,7 @@ void SemiSpace::SetOverShootSize(size_t size) overShootSize_ = size; } -bool SemiSpace::AdjustCapacity(size_t allocatedSizeSinceGC) +bool SemiSpace::AdjustCapacity(size_t allocatedSizeSinceGC, JSThread *thread) { if (allocatedSizeSinceGC <= initialCapacity_ * GROW_OBJECT_SURVIVAL_RATE / GROWING_FACTOR) { return false; @@ -275,8 +279,8 @@ bool SemiSpace::AdjustCapacity(size_t allocatedSizeSinceGC) size_t newCapacity = initialCapacity_ * GROWING_FACTOR; SetInitialCapacity(std::min(newCapacity, maximumCapacity_)); if (newCapacity == maximumCapacity_) { - heap_->GetEcmaVM()->GetJSObjectResizingStrategy()->UpdateGrowStep( - heap_->GetJSThread(), + localHeap_->GetJSObjectResizingStrategy()->UpdateGrowStep( + thread, JSObjectResizingStrategy::PROPERTIES_GROW_SIZE * 2); // 2: double } return true; @@ -284,13 +288,13 @@ bool SemiSpace::AdjustCapacity(size_t allocatedSizeSinceGC) if (initialCapacity_ <= minimumCapacity_) { return false; } - double speed = heap_->GetMemController()->GetNewSpaceAllocationThroughputPerMS(); + double speed = localHeap_->GetMemController()->GetNewSpaceAllocationThroughputPerMS(); if (speed > LOW_ALLOCATION_SPEED_PER_MS) { return false; } size_t newCapacity = initialCapacity_ / GROWING_FACTOR; SetInitialCapacity(std::max(newCapacity, minimumCapacity_)); - heap_->GetEcmaVM()->GetJSObjectResizingStrategy()->UpdateGrowStep(heap_->GetJSThread()); + localHeap_->GetJSObjectResizingStrategy()->UpdateGrowStep(thread); return true; } return false; @@ -312,6 +316,6 @@ size_t SemiSpace::GetAllocatedSizeSinceGC(uintptr_t top) const SnapshotSpace::SnapshotSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity) : LinearSpace(heap, MemSpaceType::SNAPSHOT_SPACE, initialCapacity, maximumCapacity) {} -ReadOnlySpace::ReadOnlySpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity) - : LinearSpace(heap, MemSpaceType::READ_ONLY_SPACE, initialCapacity, maximumCapacity) {} +ReadOnlySpace::ReadOnlySpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity, MemSpaceType type) + : LinearSpace(heap, type, initialCapacity, maximumCapacity) {} } // namespace panda::ecmascript diff --git a/ecmascript/mem/linear_space.h b/ecmascript/mem/linear_space.h index f5067a465c11fa77dd9773d84c5058aee5160a79..87f96920a04eac13acf13b812821de89382d6e07 100644 --- a/ecmascript/mem/linear_space.h +++ b/ecmascript/mem/linear_space.h @@ -45,6 +45,7 @@ public: void InvokeAllocationInspector(Address object, size_t size, size_t alignedSize); protected: + Heap *localHeap_; BumpPointerAllocator allocator_; size_t overShootSize_ {0}; size_t allocateAfterLastGC_ {0}; @@ -65,7 +66,7 @@ public: uintptr_t AllocateSync(size_t size); void SetOverShootSize(size_t size); - bool AdjustCapacity(size_t allocatedSizeSinceGC); + bool AdjustCapacity(size_t allocatedSizeSinceGC, JSThread *thread); void SetWaterLine(); void SetWaterLineWithoutGC(); @@ -112,7 +113,8 @@ private: class ReadOnlySpace : public LinearSpace { public: - ReadOnlySpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity); + ReadOnlySpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity, + MemSpaceType type = MemSpaceType::READ_ONLY_SPACE); ~ReadOnlySpace() override = default; void SetReadOnly() { diff --git a/ecmascript/mem/mark_stack.h b/ecmascript/mem/mark_stack.h index d1e40c94554c8357ce4c9ecfa82aefb2743db9fa..50bc7688f0984184372267f9e4f628d43860c456 100644 --- a/ecmascript/mem/mark_stack.h +++ b/ecmascript/mem/mark_stack.h @@ -97,14 +97,12 @@ template class ContinuousStack : public Stack { public: ContinuousStack() = default; - explicit ContinuousStack(Heap *heap) : heap_(heap) {} ~ContinuousStack() override = default; NO_COPY_SEMANTIC(ContinuousStack); NO_MOVE_SEMANTIC(ContinuousStack); - inline void BeginMarking(Heap *heap, ContinuousStack *other) + inline void BeginMarking(ContinuousStack *other) { - heap_ = heap; currentArea_ = other->currentArea_; if (currentArea_ == nullptr) { currentArea_ = NativeAreaAllocator::AllocateSpace(DEFAULT_MARK_STACK_SIZE); @@ -161,7 +159,6 @@ private: ResetBegin(currentArea_->GetBegin(), currentArea_->GetEnd()); } - Heap *heap_ {nullptr}; Area *currentArea_ {nullptr}; EcmaList areaList_ {}; EcmaList unusedList_ {}; diff --git a/ecmascript/mem/mem.h b/ecmascript/mem/mem.h index bbd81412fe2d6df56bbef1011eb35c98d9457bd1..c76d8afa7e1c1d108b76cd2c448df6903b17ceb3 100644 --- a/ecmascript/mem/mem.h +++ b/ecmascript/mem/mem.h @@ -46,7 +46,9 @@ static constexpr size_t LOW_POOL_SIZE = 64_MB; static constexpr size_t MIN_MEM_POOL_CAPACITY = 64_MB; static constexpr size_t WORKER_NUM = 8; static constexpr size_t PHY_SIZE_MULTIPLE = WORKER_NUM + 1; -static constexpr size_t STANDARD_POOL_SIZE = WORKER_NUM * DEFAULT_WORKER_HEAP_SIZE + DEFAULT_HEAP_SIZE; +// todo(Gymee) fix size for shared heap +static constexpr size_t STANDARD_POOL_SIZE = + WORKER_NUM * DEFAULT_WORKER_HEAP_SIZE + DEFAULT_HEAP_SIZE + DEFAULT_SHARED_HEAP_SIZE; #if defined(PANDA_TARGET_32) static constexpr size_t MAX_GLOBAL_NATIVE_LIMIT = 512_MB; diff --git a/ecmascript/mem/mem_common.h b/ecmascript/mem/mem_common.h index 8ed62bdc06fc78d69fa21d79876ddba3d91901af..8d6aca9bf8f5e82738c001234f248db1cf3e73f3 100644 --- a/ecmascript/mem/mem_common.h +++ b/ecmascript/mem/mem_common.h @@ -16,6 +16,7 @@ #ifndef ECMASCRIPT_MEM_MEM_COMMON_H #define ECMASCRIPT_MEM_MEM_COMMON_H +#include #include namespace panda::ecmascript { diff --git a/ecmascript/mem/mem_map_allocator.cpp b/ecmascript/mem/mem_map_allocator.cpp index 9d0dd72fe197d37f1a7eed1fb42dcb3b052e1bf4..b8f4e408049d646b54fe55db1b5dbe0069909902 100644 --- a/ecmascript/mem/mem_map_allocator.cpp +++ b/ecmascript/mem/mem_map_allocator.cpp @@ -14,6 +14,7 @@ */ #include "ecmascript/mem/mem_map_allocator.h" +#include "ecmascript/js_thread.h" #include "ecmascript/platform/map.h" #include "ecmascript/platform/os.h" diff --git a/ecmascript/mem/object_xray.h b/ecmascript/mem/object_xray.h index 092f27ff8f9d68cde3f04c913d9041e76c98c86d..724ad2b7bfbf46c324049c57b9f7b399a1068058 100644 --- a/ecmascript/mem/object_xray.h +++ b/ecmascript/mem/object_xray.h @@ -105,6 +105,7 @@ #include "ecmascript/mem/slots.h" #include "ecmascript/module/js_module_namespace.h" #include "ecmascript/module/js_module_source_text.h" +#include "ecmascript/module/js_shared_module.h" #include "ecmascript/tagged_node.h" #include "ecmascript/ts_types/ts_type.h" #include "ecmascript/ts_types/ts_type_table.h" @@ -115,17 +116,17 @@ namespace panda::ecmascript { class ObjectXRay { public: - explicit ObjectXRay(EcmaVM *ecmaVm) : ecmaVm_(ecmaVm) {} + ObjectXRay() = default; ~ObjectXRay() = default; - inline void VisitVMRoots(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor, - const RootBaseAndDerivedVisitor &derivedVisitor) const + static inline void VisitVMRoots(EcmaVM *vm, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor, + const RootBaseAndDerivedVisitor &derivedVisitor) { - ecmaVm_->Iterate(visitor, rangeVisitor); - ecmaVm_->GetJSThread()->Iterate(visitor, rangeVisitor, derivedVisitor); + vm->Iterate(visitor, rangeVisitor); + vm->GetAssociatedJSThread()->Iterate(visitor, rangeVisitor, derivedVisitor); } template - inline void VisitObjectBody(TaggedObject *object, JSHClass *klass, const EcmaObjectRangeVisitor &visitor) + static inline void VisitObjectBody(TaggedObject *object, JSHClass *klass, const EcmaObjectRangeVisitor &visitor) { // handle body JSType type = klass->GetObjectType(); @@ -682,6 +683,9 @@ public: case JSType::RESOLVEDINDEXBINDING_RECORD: ResolvedIndexBinding::Cast(object)->VisitRangeSlot(visitor); break; + case JSType::RESOLVEDRECORDBINDING_RECORD: + ResolvedRecordBinding::Cast(object)->VisitRangeSlot(visitor); + break; case JSType::JS_MODULE_NAMESPACE: ModuleNamespace::Cast(object)->VisitRangeSlot(visitor); break; @@ -705,9 +709,6 @@ public: UNREACHABLE(); } } - -private: - EcmaVM *ecmaVm_ {nullptr}; }; } // namespace panda::ecmascript diff --git a/ecmascript/mem/parallel_evacuator-inl.h b/ecmascript/mem/parallel_evacuator-inl.h index f03335c1fd0d9ff262bda78a33ea0b23c4126ebc..6030ae054c7dc5a59cf836d3dade14589932fc32 100644 --- a/ecmascript/mem/parallel_evacuator-inl.h +++ b/ecmascript/mem/parallel_evacuator-inl.h @@ -98,6 +98,9 @@ void ParallelEvacuator::UpdateObjectSlot(ObjectSlot &slot) { JSTaggedValue value(slot.GetTaggedType()); if (value.IsHeapObject()) { + if (value.IsInSharedHeap()) { + return; + } if (value.IsWeakForHeapObject()) { return UpdateWeakObjectSlot(value.GetTaggedWeakRef(), slot); } @@ -129,15 +132,48 @@ void ParallelEvacuator::UpdateWeakObjectSlot(TaggedObject *value, ObjectSlot &sl slot.Clear(); } return; + } else if (objectRegion->InSharedHeap()) { + return; } if (heap_->IsConcurrentFullMark()) { + ASSERT(!objectRegion->InSharedHeap()); if (!objectRegion->Test(value)) { slot.Clear(); } } } +void ParallelEvacuator::UpdateLocalToShareRSet(TaggedObject *object, JSHClass *cls) +{ + Region *region = Region::ObjectAddressToRange(object); + ASSERT(!region->InSharedHeap()); + auto callbackWithCSet = [this, region](TaggedObject *root, ObjectSlot start, ObjectSlot end, VisitObjectArea area) { + if (area == VisitObjectArea::IN_OBJECT) { + if (VisitBodyInObj(root, start, end, [&](ObjectSlot slot) { SetLocalToShareRSet(slot, region); })) { + return; + }; + } + for (ObjectSlot slot = start; slot < end; slot++) { + SetLocalToShareRSet(slot, region); + } + }; + ObjectXRay::VisitObjectBody(object, cls, callbackWithCSet); +} + +void ParallelEvacuator::SetLocalToShareRSet(ObjectSlot slot, Region *region) +{ + ASSERT(!region->InSharedHeap()); + JSTaggedType value = slot.GetTaggedType(); + if (!JSTaggedValue(value).IsHeapObject()) { + return; + } + Region *valueRegion = Region::ObjectAddressToRange(value); + if (valueRegion->InSharedSweepableSpace()) { + region->AtomicInsertLocalToShareRSet(slot.SlotAddress()); + } +} + void ParallelEvacuator::SetObjectFieldRSet(TaggedObject *object, JSHClass *cls) { Region *region = Region::ObjectAddressToRange(object); @@ -151,7 +187,7 @@ void ParallelEvacuator::SetObjectFieldRSet(TaggedObject *object, JSHClass *cls) SetObjectRSet(slot, region); } }; - objXRay_.VisitObjectBody(object, cls, callbackWithCSet); + ObjectXRay::VisitObjectBody(object, cls, callbackWithCSet); } void ParallelEvacuator::SetObjectRSet(ObjectSlot slot, Region *region) diff --git a/ecmascript/mem/parallel_evacuator.cpp b/ecmascript/mem/parallel_evacuator.cpp index 18eb4cd7b3a6aed3e275a6f5ef101bd80c210be6..c944f80235d9440c46910b9cd779184f3036002f 100644 --- a/ecmascript/mem/parallel_evacuator.cpp +++ b/ecmascript/mem/parallel_evacuator.cpp @@ -175,6 +175,9 @@ void ParallelEvacuator::EvacuateRegion(TlabAllocator *allocator, Region *region, if (actualPromoted) { SetObjectFieldRSet(reinterpret_cast(address), klass); } + if (region->HasLocalToShareRememberedSet()) { + UpdateLocalToShareRSet(reinterpret_cast(address), klass); + } }); promotedSize_.fetch_add(promotedSize); } @@ -182,7 +185,7 @@ void ParallelEvacuator::EvacuateRegion(TlabAllocator *allocator, Region *region, void ParallelEvacuator::VerifyHeapObject(TaggedObject *object) { auto klass = object->GetClass(); - objXRay_.VisitObjectBody(object, klass, + ObjectXRay::VisitObjectBody(object, klass, [&](TaggedObject *root, ObjectSlot start, ObjectSlot end, VisitObjectArea area) { if (area == VisitObjectArea::IN_OBJECT) { if (VisitBodyInObj(root, start, end, [&](ObjectSlot slot) { VerifyValue(object, slot); })) { @@ -203,6 +206,9 @@ void ParallelEvacuator::VerifyValue(TaggedObject *object, ObjectSlot slot) return; } Region *objectRegion = Region::ObjectAddressToRange(value.GetTaggedObject()); + if (objectRegion->InSharedHeap()) { + return; + } if (!heap_->IsConcurrentFullMark() && !objectRegion->InYoungSpace()) { return; } @@ -279,7 +285,7 @@ void ParallelEvacuator::UpdateRoot() } }; - objXRay_.VisitVMRoots(gcUpdateYoung, gcUpdateRangeYoung, gcUpdateDerived); + ObjectXRay::VisitVMRoots(heap_->GetEcmaVM(), gcUpdateYoung, gcUpdateRangeYoung, gcUpdateDerived); } void ParallelEvacuator::UpdateRecordWeakReference() @@ -307,7 +313,6 @@ void ParallelEvacuator::UpdateWeakReference() MEM_ALLOCATE_AND_GC_TRACE(heap_->GetEcmaVM(), UpdateWeakReference); ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::UpdateWeakReference"); UpdateRecordWeakReference(); - auto stringTable = heap_->GetEcmaVM()->GetEcmaStringTable(); bool isFullMark = heap_->IsConcurrentFullMark(); WeakRootVisitor gcUpdateWeak = [isFullMark](TaggedObject *header) { Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast(header)); @@ -315,6 +320,10 @@ void ParallelEvacuator::UpdateWeakReference() LOG_GC(ERROR) << "PartialGC updateWeakReference: region is nullptr, header is " << header; return reinterpret_cast(ToUintPtr(nullptr)); } + // The weak object in shared heap is always alive during partialGC. + if (objectRegion->InSharedHeap()) { + return header; + } if (objectRegion->InYoungSpaceOrCSet()) { if (objectRegion->InNewToNewSet()) { if (objectRegion->Test(header)) { @@ -335,10 +344,6 @@ void ParallelEvacuator::UpdateWeakReference() } return header; }; - if (isFullMark) { - // Only old gc will sweep string table. - stringTable->SweepWeakReference(gcUpdateWeak); - } heap_->GetEcmaVM()->GetJSThread()->IterateWeakEcmaGlobalStorage(gcUpdateWeak); heap_->GetEcmaVM()->ProcessReferences(gcUpdateWeak); @@ -412,7 +417,7 @@ void ParallelEvacuator::UpdateAndSweepNewRegionReference(Region *region) uintptr_t freeEnd = ToUintPtr(mem); if (freeStart != freeEnd) { size_t freeSize = freeEnd - freeStart; - FreeObject::FillFreeObject(heap_->GetEcmaVM(), freeStart, freeSize); + FreeObject::FillFreeObject(heap_, freeStart, freeSize); SemiSpace *toSpace = heap_->GetNewSpace(); toSpace->DecreaseSurvivalObjectSize(freeSize); } @@ -421,13 +426,13 @@ void ParallelEvacuator::UpdateAndSweepNewRegionReference(Region *region) }); CHECK_REGION_END(freeStart, freeEnd); if (freeStart < freeEnd) { - FreeObject::FillFreeObject(heap_->GetEcmaVM(), freeStart, freeEnd - freeStart); + FreeObject::FillFreeObject(heap_, freeStart, freeEnd - freeStart); } } void ParallelEvacuator::UpdateNewObjectField(TaggedObject *object, JSHClass *cls) { - objXRay_.VisitObjectBody(object, cls, + ObjectXRay::VisitObjectBody(object, cls, [this](TaggedObject *root, ObjectSlot start, ObjectSlot end, VisitObjectArea area) { if (area == VisitObjectArea::IN_OBJECT) { if (VisitBodyInObj(root, start, end, [&](ObjectSlot slot) { UpdateObjectSlot(slot); })) { diff --git a/ecmascript/mem/parallel_evacuator.h b/ecmascript/mem/parallel_evacuator.h index d435135f0140a50d122f87fac6134395e12bc309..4365e2791c9ea38652285a57e01015dea31cc3e5 100644 --- a/ecmascript/mem/parallel_evacuator.h +++ b/ecmascript/mem/parallel_evacuator.h @@ -33,7 +33,7 @@ namespace panda::ecmascript { class ParallelEvacuator { public: - explicit ParallelEvacuator(Heap *heap) : heap_(heap), objXRay_(heap->GetEcmaVM()) {} + explicit ParallelEvacuator(Heap *heap) : heap_(heap) {} ~ParallelEvacuator() = default; void Initialize(); void Finalize(); @@ -138,6 +138,9 @@ private: inline void SetObjectFieldRSet(TaggedObject *object, JSHClass *cls); inline void SetObjectRSet(ObjectSlot slot, Region *region); + inline void UpdateLocalToShareRSet(TaggedObject *object, JSHClass *cls); + inline void SetLocalToShareRSet(ObjectSlot slot, Region *region); + inline bool IsWholeRegionEvacuate(Region *region); void VerifyValue(TaggedObject *object, ObjectSlot slot); void VerifyHeapObject(TaggedObject *object); @@ -166,7 +169,6 @@ private: Heap *heap_; TlabAllocator *allocator_ {nullptr}; - ObjectXRay objXRay_; uintptr_t waterLine_ = 0; std::vector> workloads_; diff --git a/ecmascript/mem/parallel_marker-inl.h b/ecmascript/mem/parallel_marker-inl.h index e5255391a4077d90d68987abf1ba14874f63d10d..df53153d29e63d82679c959be9e1413b73a6751c 100644 --- a/ecmascript/mem/parallel_marker-inl.h +++ b/ecmascript/mem/parallel_marker-inl.h @@ -71,8 +71,8 @@ inline void NonMovableMarker::MarkValue(uint32_t threadId, ObjectSlot &slot, Reg inline void NonMovableMarker::MarkObject(uint32_t threadId, TaggedObject *object) { Region *objectRegion = Region::ObjectAddressToRange(object); - - if (!heap_->IsConcurrentFullMark() && !objectRegion->InYoungSpace()) { + if ((!heap_->IsConcurrentFullMark() && !objectRegion->InYoungSpace()) || + objectRegion->InSharedHeap()) { return; } @@ -253,12 +253,45 @@ inline void MovableMarker::UpdateForwardAddressIfSuccess(uint32_t threadId, Tagg inline bool MovableMarker::UpdateForwardAddressIfFailed(TaggedObject *object, uintptr_t toAddress, size_t size, ObjectSlot slot) { - FreeObject::FillFreeObject(heap_->GetEcmaVM(), toAddress, size); + FreeObject::FillFreeObject(heap_, toAddress, size); TaggedObject *dst = MarkWord(object).ToForwardingAddress(); slot.Update(dst); return Region::ObjectAddressToRange(dst)->InYoungSpace(); } +void MovableMarker::UpdateLocalToShareRSet(TaggedObject *object, JSHClass *cls) +{ + Region *region = Region::ObjectAddressToRange(object); + ASSERT(!region->InSharedHeap()); + auto callbackWithCSet = [this, region](TaggedObject *root, ObjectSlot start, ObjectSlot end, VisitObjectArea area) { + if (area == VisitObjectArea::IN_OBJECT) { + if (VisitBodyInObj(root, start, end, + [&](ObjectSlot slot, [[maybe_unused]]TaggedObject *root) { + SetLocalToShareRSet(slot, region); + })) { + return; + }; + } + for (ObjectSlot slot = start; slot < end; slot++) { + SetLocalToShareRSet(slot, region); + } + }; + ObjectXRay::VisitObjectBody(object, cls, callbackWithCSet); +} + +void MovableMarker::SetLocalToShareRSet(ObjectSlot slot, Region *region) +{ + ASSERT(!region->InSharedHeap()); + JSTaggedType value = slot.GetTaggedType(); + if (!JSTaggedValue(value).IsHeapObject()) { + return; + } + Region *valueRegion = Region::ObjectAddressToRange(value); + if (valueRegion->InSharedSweepableSpace()) { + region->AtomicInsertLocalToShareRSet(slot.SlotAddress()); + } +} + inline void SemiGCMarker::MarkValue(uint32_t threadId, TaggedObject *root, ObjectSlot slot) { JSTaggedValue value(slot.GetTaggedType()); @@ -345,7 +378,7 @@ inline SlotStatus CompressGCMarker::MarkObject(uint32_t threadId, TaggedObject * { Region *objectRegion = Region::ObjectAddressToRange(object); if (!NeedEvacuate(objectRegion)) { - if (objectRegion->AtomicMark(object)) { + if (!objectRegion->InSharedHeap() && objectRegion->AtomicMark(object)) { workManager_->Push(threadId, object); } return SlotStatus::CLEAR_SLOT; @@ -395,6 +428,10 @@ inline SlotStatus CompressGCMarker::EvacuateObject(uint32_t threadId, TaggedObje MarkWord::FromForwardingAddress(forwardAddress)); if (result == oldValue) { UpdateForwardAddressIfSuccess(threadId, object, klass, forwardAddress, size, markWord, slot); + Region *region = Region::ObjectAddressToRange(object); + if (region->HasLocalToShareRememberedSet()) { + UpdateLocalToShareRSet(reinterpret_cast(forwardAddress), klass); + } if (isAppSpawn_ && klass->IsString()) { // calculate and set hashcode for read-only ecmastring in advance EcmaStringAccessor(reinterpret_cast(forwardAddress)).GetHashcode(); @@ -414,7 +451,8 @@ inline void CompressGCMarker::RecordWeakReference(uint32_t threadId, JSTaggedTyp inline bool CompressGCMarker::NeedEvacuate(Region *region) { if (isAppSpawn_) { - return !region->InHugeObjectSpace() && !region->InReadOnlySpace() && !region->InNonMovableSpace(); + return !region->InHugeObjectSpace() && !region->InReadOnlySpace() && !region->InNonMovableSpace() && + !region->InSharedHeap(); } return region->InYoungOrOldSpace(); } diff --git a/ecmascript/mem/parallel_marker.cpp b/ecmascript/mem/parallel_marker.cpp index 8126beaf80547a3c292c834417d700e2bfc0c866..95b834a19d271646383f031fe64b72b4b0650f53 100644 --- a/ecmascript/mem/parallel_marker.cpp +++ b/ecmascript/mem/parallel_marker.cpp @@ -19,13 +19,14 @@ #include "ecmascript/mem/visitor.h" namespace panda::ecmascript { -Marker::Marker(Heap *heap) : heap_(heap), objXRay_(heap->GetEcmaVM()), workManager_(heap->GetWorkManager()) {} +Marker::Marker(Heap *heap) : heap_(heap), workManager_(heap->GetWorkManager()) {} void Marker::MarkRoots(uint32_t threadId) { TRACE_GC(GCStats::Scope::ScopeId::MarkRoots, heap_->GetEcmaVM()->GetEcmaGCStats()); ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "GC::MarkRoots"); - objXRay_.VisitVMRoots( + ObjectXRay::VisitVMRoots( + heap_->GetEcmaVM(), std::bind(&Marker::HandleRoots, this, threadId, std::placeholders::_1, std::placeholders::_2), std::bind(&Marker::HandleRangeRoots, this, threadId, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), @@ -92,7 +93,7 @@ void NonMovableMarker::ProcessMarkStack(uint32_t threadId) JSHClass *jsHclass = obj->SynchronizedGetClass(); MarkObject(threadId, jsHclass); - objXRay_.VisitObjectBody(obj, jsHclass, visitor); + ObjectXRay::VisitObjectBody(obj, jsHclass, visitor); } } @@ -134,7 +135,7 @@ void NonMovableMarker::ProcessIncrementalMarkStack(uint32_t threadId, uint32_t m JSHClass *jsHclass = obj->GetClass(); MarkObject(threadId, jsHclass); - objXRay_.VisitObjectBody(obj, jsHclass, visitor); + ObjectXRay::VisitObjectBody(obj, jsHclass, visitor); if (heap_->GetIncrementalMarker()->IsTriggeredIncrementalMark() && visitAddrNum >= markStepSize) { costTime = heap_->GetIncrementalMarker()->GetCurrentTimeInMs() - startTime; heap_->GetIncrementalMarker()->UpdateMarkingSpeed(visitAddrNum, costTime); @@ -171,7 +172,7 @@ void SemiGCMarker::ProcessMarkStack(uint32_t threadId) } auto jsHclass = obj->GetClass(); - objXRay_.VisitObjectBody(obj, jsHclass, visitor); + ObjectXRay::VisitObjectBody(obj, jsHclass, visitor); } } @@ -200,7 +201,7 @@ void CompressGCMarker::ProcessMarkStack(uint32_t threadId) auto jsHClass = obj->GetClass(); ObjectSlot objectSlot(ToUintPtr(obj)); MarkObject(threadId, jsHClass, objectSlot); - objXRay_.VisitObjectBody(obj, jsHClass, visitor); + ObjectXRay::VisitObjectBody(obj, jsHClass, visitor); } } diff --git a/ecmascript/mem/parallel_marker.h b/ecmascript/mem/parallel_marker.h index 8923c74686750687057c677569a625363a2588bd..5dcfe5cc59b7ab597016cf7611c45dd157331450 100644 --- a/ecmascript/mem/parallel_marker.h +++ b/ecmascript/mem/parallel_marker.h @@ -82,7 +82,6 @@ protected: } Heap *heap_ {nullptr}; - ObjectXRay objXRay_ {nullptr}; WorkManager *workManager_ {nullptr}; friend class Heap; @@ -134,6 +133,10 @@ protected: uintptr_t toAddress, size_t size, const MarkWord &markWord, ObjectSlot slot, bool isPromoted = false); inline bool UpdateForwardAddressIfFailed(TaggedObject *object, uintptr_t toAddress, size_t size, ObjectSlot slot); + + inline void UpdateLocalToShareRSet(TaggedObject *object, JSHClass *cls); + + inline void SetLocalToShareRSet(ObjectSlot slot, Region *region); }; class SemiGCMarker : public MovableMarker { diff --git a/ecmascript/mem/partial_gc.cpp b/ecmascript/mem/partial_gc.cpp index 1fcfbf93b6312f74e400e7d6039ec60c9dfe9222..8c15af63bf21f9df40bdfbf5b973a0ed8fa3b67d 100644 --- a/ecmascript/mem/partial_gc.cpp +++ b/ecmascript/mem/partial_gc.cpp @@ -160,6 +160,7 @@ void PartialGC::ProcessNativeDelete() TRACE_GC(GCStats::Scope::ScopeId::ClearNativeObject, heap_->GetEcmaVM()->GetEcmaGCStats()); WeakRootVisitor gcUpdateWeak = [this](TaggedObject *header) { Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast(header)); + ASSERT(!objectRegion->InSharedHeap()); if (!objectRegion->InYoungSpaceOrCSet() && !heap_->IsConcurrentFullMark()) { return header; } diff --git a/ecmascript/mem/region-inl.h b/ecmascript/mem/region-inl.h index 24861c1d1013fa4f63c3068c847838a0423747bd..4e1894a697a82121bbe14e80e9fa4505f50b25e0 100644 --- a/ecmascript/mem/region-inl.h +++ b/ecmascript/mem/region-inl.h @@ -26,7 +26,7 @@ namespace panda::ecmascript { inline RememberedSet *Region::CreateRememberedSet() { auto bitSize = GCBitset::SizeOfGCBitset(GetCapacity()); - auto setAddr = thread_->GetNativeAreaAllocator()->Allocate(bitSize + RememberedSet::GCBITSET_DATA_OFFSET); + auto setAddr = nativeAreaAllocator_->Allocate(bitSize + RememberedSet::GCBITSET_DATA_OFFSET); auto ret = new (setAddr) RememberedSet(bitSize); ret->ClearAll(); std::atomic_thread_fence(std::memory_order_seq_cst); @@ -60,6 +60,17 @@ inline RememberedSet *Region::GetOrCreateOldToNewRememberedSet() return packedData_.oldToNewSet_; } +inline RememberedSet *Region::GetOrCreateLocalToShareRememberedSet() +{ + if (UNLIKELY(localToShareSet_ == nullptr)) { + LockHolder lock(*lock_); + if (localToShareSet_ == nullptr) { + localToShareSet_ = CreateRememberedSet(); + } + } + return localToShareSet_; +} + inline void Region::MergeRSetForConcurrentSweeping() { if (sweepingRSet_ == nullptr) { @@ -114,6 +125,17 @@ inline bool Region::TestOldToNew(uintptr_t addr) return set->TestBit(ToUintPtr(this), addr); } +// ONLY used for heap verification. +inline bool Region::TestLocalToShare(uintptr_t addr) +{ + ASSERT(InRange(addr)); + // Only used for heap verification, so donot need to use lock + if (localToShareSet_ == nullptr) { + return false; + } + return localToShareSet_->TestBit(ToUintPtr(this), addr); +} + template inline void Region::IterateAllMarkedBits(Visitor visitor) const { @@ -140,6 +162,46 @@ inline void Region::AtomicInsertCrossRegionRSet(uintptr_t addr) set->AtomicInsert(ToUintPtr(this), addr); } +inline bool Region::HasLocalToShareRememberedSet() const +{ + return localToShareSet_ != nullptr; +} + +inline void Region::InsertLocalToShareRSet(uintptr_t addr) +{ + auto set = GetOrCreateLocalToShareRememberedSet(); + set->Insert(ToUintPtr(this), addr); +} + +inline void Region::AtomicInsertLocalToShareRSet(uintptr_t addr) +{ + auto set = GetOrCreateLocalToShareRememberedSet(); + set->AtomicInsert(ToUintPtr(this), addr); +} + +inline void Region::AtomicClearLocalToShareRSetInRange(uintptr_t start, uintptr_t end) +{ + if (localToShareSet_ != nullptr) { + localToShareSet_->AtomicClearRange(ToUintPtr(this), start, end); + } +} + +inline void Region::DeleteLocalToShareRSet() +{ + if (localToShareSet_ != nullptr) { + nativeAreaAllocator_->Free(localToShareSet_, localToShareSet_->Size()); + localToShareSet_ = nullptr; + } +} + +template +inline void Region::AtomicIterateAllLocalToShareBits(Visitor visitor) +{ + if (localToShareSet_ != nullptr) { + localToShareSet_->AtomicIterateAllMarkedBits(ToUintPtr(this), visitor); + } +} + template inline void Region::IterateAllCrossRegionBits(Visitor visitor) const { @@ -172,7 +234,7 @@ inline void Region::AtomicClearCrossRegionRSetInRange(uintptr_t start, uintptr_t inline void Region::DeleteCrossRegionRSet() { if (crossRegionSet_ != nullptr) { - thread_->GetNativeAreaAllocator()->Free(crossRegionSet_, crossRegionSet_->Size()); + nativeAreaAllocator_->Free(crossRegionSet_, crossRegionSet_->Size()); crossRegionSet_ = nullptr; } } @@ -230,7 +292,7 @@ inline void Region::ClearOldToNewRSetInRange(uintptr_t start, uintptr_t end) inline void Region::DeleteOldToNewRSet() { if (packedData_.oldToNewSet_ != nullptr) { - thread_->GetNativeAreaAllocator()->Free(packedData_.oldToNewSet_, packedData_.oldToNewSet_->Size()); + nativeAreaAllocator_->Free(packedData_.oldToNewSet_, packedData_.oldToNewSet_->Size()); packedData_.oldToNewSet_ = nullptr; } } @@ -252,7 +314,7 @@ inline void Region::ClearSweepingRSetInRange(uintptr_t start, uintptr_t end) inline void Region::DeleteSweepingRSet() { if (sweepingRSet_ != nullptr) { - thread_->GetNativeAreaAllocator()->Free(sweepingRSet_, sweepingRSet_->Size()); + nativeAreaAllocator_->Free(sweepingRSet_, sweepingRSet_->Size()); sweepingRSet_ = nullptr; } } diff --git a/ecmascript/mem/region.h b/ecmascript/mem/region.h index 4e3e25b0ac8337c8f209569300e6867cdf6cd2b2..a943b66cae267b25ecb8bdacad1ac9b6ac853b2e 100644 --- a/ecmascript/mem/region.h +++ b/ecmascript/mem/region.h @@ -48,8 +48,16 @@ enum RegionSpaceFlag { IN_READ_ONLY_SPACE = 0x0E, IN_APPSPAWN_SPACE = 0X0F, IN_HUGE_MACHINE_CODE_SPACE = 0x10, - + IN_SHARED_NON_MOVABLE = 0x11, + IN_SHARED_OLD_SPACE = 0x12, + IN_SHARED_HUGE_OBJECT_SPACE = 0x13, + IN_SHARED_READ_ONLY_SPACE = 0x14, VALID_SPACE_MASK = 0xFF, + + SHARED_SPACE_BEGIN = IN_SHARED_NON_MOVABLE, + SHARED_SPACE_END = IN_SHARED_READ_ONLY_SPACE, + SHARED_SWEEPABLE_SPACE_BEGIN = IN_SHARED_NON_MOVABLE, + SHARED_SWEEPABLE_SPACE_END = IN_SHARED_HUGE_OBJECT_SPACE, }; enum RegionGCFlags { @@ -91,6 +99,14 @@ static inline std::string ToSpaceTypeName(uint8_t space) return "appspawn space"; case RegionSpaceFlag::IN_HUGE_MACHINE_CODE_SPACE: return "huge machine code space"; + case RegionSpaceFlag::IN_SHARED_NON_MOVABLE: + return "shared non movable space"; + case RegionSpaceFlag::IN_SHARED_OLD_SPACE: + return "shared old space"; + case RegionSpaceFlag::IN_SHARED_READ_ONLY_SPACE: + return "shared read only space"; + case RegionSpaceFlag::IN_SHARED_HUGE_OBJECT_SPACE: + return "shared huge object space"; default: return "invalid space"; } @@ -104,9 +120,10 @@ static inline std::string ToSpaceTypeName(uint8_t space) class Region { public: - Region(JSThread *thread, uintptr_t allocateBase, uintptr_t begin, uintptr_t end, RegionSpaceFlag spaceType) + Region(NativeAreaAllocator *allocator, uintptr_t allocateBase, uintptr_t begin, uintptr_t end, + RegionSpaceFlag spaceType) : packedData_(begin, end, spaceType), - thread_(thread), + nativeAreaAllocator_(allocator), allocateBase_(allocateBase), end_(end), highWaterMark_(end), @@ -195,9 +212,18 @@ public: bool Test(void *addr) const; // ONLY used for heap verification. bool TestOldToNew(uintptr_t addr); + bool TestLocalToShare(uintptr_t addr); template void IterateAllMarkedBits(Visitor visitor) const; void ClearMarkGCBitset(); + // local to share remembered set + bool HasLocalToShareRememberedSet() const; + void InsertLocalToShareRSet(uintptr_t addr); + void AtomicInsertLocalToShareRSet(uintptr_t addr); + void AtomicClearLocalToShareRSetInRange(uintptr_t start, uintptr_t end); + template + void AtomicIterateAllLocalToShareBits(Visitor visitor); + void DeleteLocalToShareRSet(); // Cross region remembered set void InsertCrossRegionRSet(uintptr_t addr); void AtomicInsertCrossRegionRSet(uintptr_t addr); @@ -300,11 +326,45 @@ public: return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_READ_ONLY_SPACE; } + bool InSharedOldSpace() const + { + return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_SHARED_OLD_SPACE; + } + + bool InSharedNonMovableSpace() const + { + return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_SHARED_NON_MOVABLE; + } + + bool InSharedHugeObjectSpace() const + { + return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_SHARED_HUGE_OBJECT_SPACE; + } + + bool InSharedReadOnlySpace() const + { + return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_SHARED_READ_ONLY_SPACE; + } + bool InAppSpawnSpace() const { return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_APPSPAWN_SPACE; } + // Not including shared read only space. + bool InSharedSweepableSpace() const + { + auto flag = packedData_.flags_.spaceFlag_; + return flag >= RegionSpaceFlag::SHARED_SWEEPABLE_SPACE_BEGIN && + flag <= RegionSpaceFlag::SHARED_SWEEPABLE_SPACE_END; + } + + bool InSharedHeap() const + { + auto flag = packedData_.flags_.spaceFlag_; + return flag >= RegionSpaceFlag::SHARED_SPACE_BEGIN && flag <= RegionSpaceFlag::SHARED_SPACE_END; + } + bool InHeapSpace() const { uint8_t space = packedData_.flags_.spaceFlag_; @@ -316,7 +376,11 @@ public: space == RegionSpaceFlag::IN_NON_MOVABLE_SPACE || space == RegionSpaceFlag::IN_SNAPSHOT_SPACE || space == RegionSpaceFlag::IN_READ_ONLY_SPACE || - space == RegionSpaceFlag::IN_APPSPAWN_SPACE); + space == RegionSpaceFlag::IN_APPSPAWN_SPACE || + space == RegionSpaceFlag::IN_SHARED_NON_MOVABLE || + space == RegionSpaceFlag::IN_SHARED_OLD_SPACE || + space == RegionSpaceFlag::IN_SHARED_READ_ONLY_SPACE || + space == RegionSpaceFlag::IN_SHARED_HUGE_OBJECT_SPACE); } bool InCollectSet() const @@ -562,7 +626,8 @@ public: flags_.spaceFlag_ = spaceType; flags_.gcFlags_ = 0; bitsetSize_ = (spaceType == RegionSpaceFlag::IN_HUGE_OBJECT_SPACE || - spaceType == RegionSpaceFlag::IN_HUGE_MACHINE_CODE_SPACE) ? + spaceType == RegionSpaceFlag::IN_HUGE_MACHINE_CODE_SPACE || + spaceType == RegionSpaceFlag::IN_SHARED_HUGE_OBJECT_SPACE) ? GCBitset::BYTE_PER_WORD : GCBitset::SizeOfGCBitset(end - begin); markGCBitset_ = new (ToVoidPtr(begin)) GCBitset(); markGCBitset_->Clear(bitsetSize_); @@ -608,17 +673,10 @@ private: RememberedSet *CreateRememberedSet(); RememberedSet *GetOrCreateCrossRegionRememberedSet(); RememberedSet *GetOrCreateOldToNewRememberedSet(); + RememberedSet *GetOrCreateLocalToShareRememberedSet(); PackedData packedData_; - /* - * The thread instance here is used by the GC barriers to get marking related information - * and perform marking related operations. The barriers will indirectly access such information - * via. the objects' associated regions. - * fixme: Figure out a more elegant solution to bridging the barrier - * and the information / operations it depends on. Then we can get rid of this from the region, - * and consequently, the region allocator, the spaces using the region allocator, etc. - */ - JSThread *thread_; + NativeAreaAllocator *nativeAreaAllocator_; uintptr_t allocateBase_; uintptr_t end_; @@ -630,6 +688,7 @@ private: RememberedSet *crossRegionSet_ {nullptr}; RememberedSet *sweepingRSet_ {nullptr}; + RememberedSet *localToShareSet_ {nullptr}; Span freeObjectSets_; Mutex *lock_ {nullptr}; uint64_t wasted_; diff --git a/ecmascript/mem/shared_heap/shared_concurrent_sweeper.cpp b/ecmascript/mem/shared_heap/shared_concurrent_sweeper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0fe06d378bf49423870a270df14b5de4c0db2a50 --- /dev/null +++ b/ecmascript/mem/shared_heap/shared_concurrent_sweeper.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2024 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/mem/shared_heap/shared_concurrent_sweeper.h" + +#include "ecmascript/ecma_macros.h" +#include "ecmascript/mem/heap.h" +#include "ecmascript/mem/region-inl.h" +#include "ecmascript/mem/space-inl.h" +#include "ecmascript/taskpool/taskpool.h" + +namespace panda::ecmascript { +SharedConcurrentSweeper::SharedConcurrentSweeper(SharedHeap *heap, EnableConcurrentSweepType type) + : sHeap_(heap), + enableType_(type) +{ +} + +void SharedConcurrentSweeper::PostTask() +{ + auto tid = JSThread::GetCurrentThreadId(); + if (ConcurrentSweepEnabled()) { + Taskpool::GetCurrentTaskpool()->PostTask( + std::make_unique(tid, this, SHARED_OLD_SPACE)); + Taskpool::GetCurrentTaskpool()->PostTask( + std::make_unique(tid, this, SHARED_NON_MOVABLE)); + } +} + +void SharedConcurrentSweeper::Sweep() +{ + if (ConcurrentSweepEnabled()) { + // Add all region to region list. Ensure all task finish + sHeap_->GetOldSpace()->PrepareSweeping(); + sHeap_->GetNonMovableSpace()->PrepareSweeping(); + // Prepare + isSweeping_ = true; + for (int spaceIndex = 0; spaceIndex < SHARED_SWEEPING_SPACE_NUM; spaceIndex++) { + remainingTaskNum_[spaceIndex] = SHARED_SWEEPING_SPACE_NUM; + } + } else { + sHeap_->GetOldSpace()->Sweep(); + sHeap_->GetNonMovableSpace()->Sweep(); + } + sHeap_->GetHugeObjectSpace()->Sweep(); +} + +void SharedConcurrentSweeper::AsyncSweepSpace(MemSpaceType type, bool isMain) +{ + auto space = sHeap_->GetSpaceWithType(type); + space->AsyncSweep(isMain); + int spaceIndex = type - SHARED_SWEEPING_SPACE_BEGIN; + LockHolder holder(mutexs_[spaceIndex]); + if (--remainingTaskNum_[spaceIndex] == 0) { + cvs_[spaceIndex].SignalAll(); + } +} + +void SharedConcurrentSweeper::WaitAllTaskFinished() +{ + if (!isSweeping_) { + return; + } + for (int spaceIndex = 0; spaceIndex < SHARED_SWEEPING_SPACE_NUM; spaceIndex++) { + if (remainingTaskNum_[spaceIndex] > 0) { + LockHolder holder(mutexs_[spaceIndex]); + while (remainingTaskNum_[spaceIndex] > 0) { + cvs_[spaceIndex].Wait(&mutexs_[spaceIndex]); + } + } + } +} + +// call in suspendAll thread. +void SharedConcurrentSweeper::EnsureAllTaskFinished() +{ + if (!isSweeping_) { + return; + } + for (int spaceIndex = 0; spaceIndex < SHARED_SWEEPING_SPACE_NUM; spaceIndex++) { + int type = spaceIndex + SHARED_SWEEPING_SPACE_BEGIN; + WaitingTaskFinish(static_cast(type)); + } + isSweeping_ = false; + if (IsRequestDisabled()) { + enableType_ = EnableConcurrentSweepType::DISABLE; + } +} + +// call in mutator thread +void SharedConcurrentSweeper::EnsureTaskFinished(MemSpaceType type) +{ + if (!isSweeping_) { + return; + } + WaitingTaskFinish(type); +} + +void SharedConcurrentSweeper::WaitingTaskFinish(MemSpaceType type) +{ + int spaceIndex = type - SHARED_SWEEPING_SPACE_BEGIN; + if (remainingTaskNum_[spaceIndex] > 0) { + { + LockHolder holder(mutexs_[spaceIndex]); + remainingTaskNum_[spaceIndex]++; + } + AsyncSweepSpace(type, true); + LockHolder holder(mutexs_[spaceIndex]); + while (remainingTaskNum_[spaceIndex] > 0) { + cvs_[spaceIndex].Wait(&mutexs_[spaceIndex]); + } + } + SharedSparseSpace *space = sHeap_->GetSpaceWithType(type); + space->FinishFillSweptRegion(); +} + +void SharedConcurrentSweeper::TryFillSweptRegion() +{ + sHeap_->GetOldSpace()->TryFillSweptRegion(); + sHeap_->GetNonMovableSpace()->TryFillSweptRegion(); +} + +bool SharedConcurrentSweeper::SweeperTask::Run([[maybe_unused]] uint32_t threadIndex) +{ + if (type_ == SHARED_NON_MOVABLE) { + sweeper_->AsyncSweepSpace(SHARED_NON_MOVABLE, false); + sweeper_->AsyncSweepSpace(SHARED_OLD_SPACE, false); + } else { + ASSERT(type_ == SHARED_OLD_SPACE); + sweeper_->AsyncSweepSpace(SHARED_OLD_SPACE, false); + sweeper_->AsyncSweepSpace(SHARED_NON_MOVABLE, false); + } + + return true; +} + +void SharedConcurrentSweeper::EnableConcurrentSweep(EnableConcurrentSweepType type) +{ + if (IsConfigDisabled()) { + return; + } + if (ConcurrentSweepEnabled() && isSweeping_ && type == EnableConcurrentSweepType::DISABLE) { + enableType_ = EnableConcurrentSweepType::REQUEST_DISABLE; + } else { + enableType_ = type; + } +} +} // namespace panda::ecmascript diff --git a/ecmascript/mem/shared_heap/shared_concurrent_sweeper.h b/ecmascript/mem/shared_heap/shared_concurrent_sweeper.h new file mode 100644 index 0000000000000000000000000000000000000000..3e12f1ac812353ab0439f6e402e8ba709b3cacd7 --- /dev/null +++ b/ecmascript/mem/shared_heap/shared_concurrent_sweeper.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2024 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_MEM_SHARED_HEAP_SHARED_CONCURRENT_SWEEPER_H +#define ECMASCRIPT_MEM_SHARED_HEAP_SHARED_CONCURRENT_SWEEPER_H + +#include "ecmascript/mem/concurrent_sweeper.h" + +namespace panda::ecmascript { +class SharedHeap; + +class SharedConcurrentSweeper { +public: + SharedConcurrentSweeper(SharedHeap *heap, EnableConcurrentSweepType type); + ~SharedConcurrentSweeper() = default; + + NO_COPY_SEMANTIC(SharedConcurrentSweeper); + NO_MOVE_SEMANTIC(SharedConcurrentSweeper); + + void PostTask(); + void Sweep(); + + void WaitAllTaskFinished(); + // Help to finish sweeping task. It can be called through js thread + void EnsureAllTaskFinished(); + // Ensure task finish. It can be called through js thread + void EnsureTaskFinished(MemSpaceType type); + + void TryFillSweptRegion(); + + void EnableConcurrentSweep(EnableConcurrentSweepType type); + + bool IsSweeping() + { + return isSweeping_; + } + + bool ConcurrentSweepEnabled() + { + return !IsDisabled(); + } + + void ConfigConcurrentSweep(bool enabled) + { + enableType_ = enabled ? EnableConcurrentSweepType::ENABLE : + EnableConcurrentSweepType::CONFIG_DISABLE; + } + + bool IsDisabled() const + { + return enableType_ == EnableConcurrentSweepType::DISABLE || + enableType_ == EnableConcurrentSweepType::CONFIG_DISABLE; + } + + bool IsRequestDisabled() const + { + return enableType_ == EnableConcurrentSweepType::REQUEST_DISABLE; + } + + bool IsConfigDisabled() const + { + return enableType_ == EnableConcurrentSweepType::CONFIG_DISABLE; + } +private: + class SweeperTask : public Task { + public: + SweeperTask(int32_t id, SharedConcurrentSweeper *sweeper, MemSpaceType type) + : Task(id), sweeper_(sweeper), type_(type) {}; + ~SweeperTask() override = default; + bool Run(uint32_t threadIndex) override; + + NO_COPY_SEMANTIC(SweeperTask); + NO_MOVE_SEMANTIC(SweeperTask); + + private: + SharedConcurrentSweeper *sweeper_; + MemSpaceType type_; + }; + + void AsyncSweepSpace(MemSpaceType type, bool isMain); + + void WaitingTaskFinish(MemSpaceType type); + + std::array mutexs_; + std::array cvs_; + std::array remainingTaskNum_ = {0, 0}; + + SharedHeap *sHeap_; + EnableConcurrentSweepType enableType_ {EnableConcurrentSweepType::CONFIG_DISABLE}; + bool isSweeping_ {false}; +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_MEM_SHARED_HEAP_SHARED_CONCURRENT_SWEEPER_H diff --git a/ecmascript/mem/shared_heap/shared_gc.cpp b/ecmascript/mem/shared_heap/shared_gc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be36883ad4c24f3aea01beb93dd3325f691a56ec --- /dev/null +++ b/ecmascript/mem/shared_heap/shared_gc.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2024 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/mem/shared_heap/shared_gc.h" + +#include "ecmascript/ecma_string_table.h" +#include "ecmascript/ecma_vm.h" +#include "ecmascript/mem/barriers-inl.h" +#include "ecmascript/mem/mark_stack.h" +#include "ecmascript/mem/mem.h" +#include "ecmascript/mem/parallel_marker-inl.h" +#include "ecmascript/mem/shared_heap/shared_concurrent_sweeper.h" +#include "ecmascript/mem/shared_heap/shared_gc_marker-inl.h" +#include "ecmascript/mem/space-inl.h" +#include "ecmascript/mem/visitor.h" +#include "ecmascript/mem/gc_stats.h" +#include "ecmascript/runtime.h" + +namespace panda::ecmascript { +void SharedGC::RunPhases() +{ + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGC::RunPhases"); + TRACE_GC(GCStats::Scope::ScopeId::TotalGC, sHeap_->GetEcmaGCStats()); + Initialize(); + Mark(); + Sweep(); + Finish(); +} + +void SharedGC::Initialize() +{ + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGC::Initialize"); + TRACE_GC(GCStats::Scope::ScopeId::Initialize, sHeap_->GetEcmaGCStats()); + sHeap_->EnumerateOldSpaceRegions([](Region *current) { + ASSERT(current->InSharedSweepableSpace()); + current->ResetAliveObject(); + }); + sWorkManager_->Initialize(); +} +void SharedGC::Mark() +{ + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGC::Mark"); + TRACE_GC(GCStats::Scope::ScopeId::Mark, sHeap_->GetEcmaGCStats()); + sHeap_->GetSharedGCMarker()->MarkSerializeRoots(MAIN_THREAD_INDEX); + Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) { + ASSERT(!thread->IsInRunningState()); + auto vm = thread->GetEcmaVM(); + vm->GetHeap()->GetSweeper()->EnsureAllTaskFinished(); + sHeap_->GetSharedGCMarker()->MarkRoots(MAIN_THREAD_INDEX, vm); + sHeap_->GetSharedGCMarker()->ProcessLocalToShare(MAIN_THREAD_INDEX, const_cast(vm->GetHeap())); + }); + sHeap_->WaitRunningTaskFinished(); +} + +void SharedGC::Sweep() +{ + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGC::Sweep"); + TRACE_GC(GCStats::Scope::ScopeId::Sweep, sHeap_->GetEcmaGCStats()); + UpdateRecordWeakReference(); + WeakRootVisitor gcUpdateWeak = [](TaggedObject *header) { + Region *objectRegion = Region::ObjectAddressToRange(header); + if (!objectRegion) { + LOG_GC(ERROR) << "SharedGC updateWeakReference: region is nullptr, header is " << header; + return reinterpret_cast(ToUintPtr(nullptr)); + } + if (!objectRegion->InSharedSweepableSpace() || objectRegion->Test(header)) { + return header; + } + return reinterpret_cast(ToUintPtr(nullptr)); + }; + Runtime::GetInstance()->GetEcmaStringTable()->SweepWeakReference(gcUpdateWeak); + + Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) { + ASSERT(!thread->IsInRunningState()); + thread->GetCurrentEcmaContext()->ProcessNativeDelete(gcUpdateWeak); + thread->IterateWeakEcmaGlobalStorage(gcUpdateWeak, true); + }); + + sHeap_->GetSweeper()->Sweep(); + sHeap_->GetSweeper()->PostTask(); +} + +void SharedGC::Finish() +{ + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGC::Finish"); + TRACE_GC(GCStats::Scope::ScopeId::Finish, sHeap_->GetEcmaGCStats()); + sHeap_->Reclaim(); + sWorkManager_->Finish(); + sHeap_->GetSweeper()->TryFillSweptRegion(); +} + +void SharedGC::UpdateRecordWeakReference() +{ + auto totalThreadCount = Taskpool::GetCurrentTaskpool()->GetTotalThreadNum() + 1; + for (uint32_t i = 0; i < totalThreadCount; i++) { + ProcessQueue *queue = sHeap_->GetWorkManager()->GetWeakReferenceQueue(i); + + while (true) { + auto obj = queue->PopBack(); + if (UNLIKELY(obj == nullptr)) { + break; + } + ObjectSlot slot(ToUintPtr(obj)); + JSTaggedValue value(slot.GetTaggedType()); + if (value.IsWeak()) { + auto header = value.GetTaggedWeakRef(); + Region *objectRegion = Region::ObjectAddressToRange(header); + if (!objectRegion->Test(header)) { + slot.Clear(); + } + } + } + } +} + +void SharedGC::ResetWorkManager(SharedGCWorkManager *workManager) +{ + sWorkManager_ = workManager; +} +} // namespace panda::ecmascript diff --git a/ecmascript/mem/shared_heap/shared_gc.h b/ecmascript/mem/shared_heap/shared_gc.h new file mode 100644 index 0000000000000000000000000000000000000000..2e38d3b26b7ea9f167350163a5682962beb18da1 --- /dev/null +++ b/ecmascript/mem/shared_heap/shared_gc.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024 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_MEM_SHARED_HEAP_SHARED_GC_H +#define ECMASCRIPT_MEM_SHARED_HEAP_SHARED_GC_H + +#include "ecmascript/mem/allocator.h" +#include "ecmascript/mem/garbage_collector.h" +#include "ecmascript/mem/heap.h" +#include "ecmascript/mem/mark_stack.h" +#include "ecmascript/mem/mark_word.h" +#include "ecmascript/mem/mem.h" +#include "ecmascript/mem/work_manager.h" + +namespace panda::ecmascript { +class SharedGC : public GarbageCollector { +public: + explicit SharedGC(SharedHeap *heap) : sHeap_(heap), sWorkManager_(heap->GetWorkManager()) {} + ~SharedGC() override = default; + NO_COPY_SEMANTIC(SharedGC); + NO_MOVE_SEMANTIC(SharedGC); + + void RunPhases() override; + void ResetWorkManager(SharedGCWorkManager *workManager); +protected: + void Initialize() override; + void Mark() override; + void Sweep() override; + void Finish() override; + +private: + void UpdateRecordWeakReference(); + + SharedHeap *sHeap_ {nullptr}; + SharedGCWorkManager *sWorkManager_ {nullptr}; +}; +} // namespace panda::ecmascript + +#endif // ECMASCRIPT_MEM_SHARED_HEAP_SHARED_GC_H diff --git a/ecmascript/mem/shared_heap/shared_gc_marker-inl.h b/ecmascript/mem/shared_heap/shared_gc_marker-inl.h new file mode 100644 index 0000000000000000000000000000000000000000..6deac5c8b0b2c321d9d1daa0de44ef7c4fbe5a3f --- /dev/null +++ b/ecmascript/mem/shared_heap/shared_gc_marker-inl.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2024 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_MEM_SHARED_HEAP_SHARED_GC_MARKER_INL_H +#define ECMASCRIPT_MEM_SHARED_HEAP_SHARED_GC_MARKER_INL_H + +#include "ecmascript/mem/shared_heap/shared_gc_marker.h" + +#include "ecmascript/js_hclass-inl.h" +#include "ecmascript/mem/heap-inl.h" +#include "ecmascript/mem/region-inl.h" + +namespace panda::ecmascript { +inline void SharedGCMarker::MarkObject(uint32_t threadId, TaggedObject *object) +{ + Region *objectRegion = Region::ObjectAddressToRange(object); + ASSERT(objectRegion->InSharedHeap()); + if (!objectRegion->InSharedReadOnlySpace() && objectRegion->AtomicMark(object)) { + sWorkManager_->Push(threadId, object); + } +} + +inline void SharedGCMarker::MarkValue(uint32_t threadId, ObjectSlot &slot) +{ + JSTaggedValue value(slot.GetTaggedType()); + if (value.IsInSharedSweepableSpace()) { + if (!value.IsWeakForHeapObject()) { + MarkObject(threadId, value.GetTaggedObject()); + } else { + RecordWeakReference(threadId, reinterpret_cast(slot.SlotAddress())); + } + } +} + +inline void SharedGCMarker::HandleRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot) +{ + JSTaggedValue value(slot.GetTaggedType()); + if (value.IsInSharedSweepableSpace()) { + MarkObject(threadId, value.GetTaggedObject()); + } +} + +inline void SharedGCMarker::HandleRangeRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot start, + ObjectSlot end) +{ + for (ObjectSlot slot = start; slot < end; slot++) { + JSTaggedValue value(slot.GetTaggedType()); + if (value.IsInSharedSweepableSpace()) { + if (value.IsWeakForHeapObject()) { + LOG_ECMA_MEM(FATAL) << "Weak Reference in SharedGCMarker roots"; + } + MarkObject(threadId, value.GetTaggedObject()); + } + } +} + +inline void SharedGCMarker::HandleDerivedRoots([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base, + [[maybe_unused]] ObjectSlot derived, + [[maybe_unused]] uintptr_t baseOldObject) +{ + // It is only used to update the derived value. The mark of share GC does not need to update slot +} + +template +ARK_INLINE bool SharedGCMarker::VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, + Callback callback) +{ + auto hclass = root->SynchronizedGetClass(); + int index = 0; + auto layout = LayoutInfo::UncheckCast(hclass->GetLayout().GetTaggedObject()); + ObjectSlot realEnd = start; + realEnd += layout->GetPropertiesCapacity(); + end = end > realEnd ? realEnd : end; + for (ObjectSlot slot = start; slot < end; slot++) { + auto attr = layout->GetAttr(index++); + if (attr.IsTaggedRep()) { + callback(slot); + } + } + return true; +} + +inline void SharedGCMarker::ProcessLocalToShare(uint32_t threadId, Heap *localHeap) +{ + localHeap->EnumerateRegions( + std::bind(&SharedGCMarker::HandleLocalToShareRSet, this, threadId, std::placeholders::_1)); + ProcessMarkStack(threadId); +} + +inline void SharedGCMarker::RecordWeakReference(uint32_t threadId, JSTaggedType *slot) +{ + sWorkManager_->PushWeakReference(threadId, slot); +} + +// Don't call this function when mutator thread is running. +inline void SharedGCMarker::HandleLocalToShareRSet(uint32_t threadId, Region *region) +{ + // If the mem does not point to a shared object, the related bit in localToShareRSet will be cleared. + region->AtomicIterateAllLocalToShareBits([this, threadId](void *mem) -> bool { + ObjectSlot slot(ToUintPtr(mem)); + JSTaggedValue value(slot.GetTaggedType()); + if (value.IsInSharedSweepableSpace()) { + if (value.IsWeakForHeapObject()) { + RecordWeakReference(threadId, reinterpret_cast(mem)); + } else { + MarkObject(threadId, value.GetTaggedObject()); + } + return true; + } else { + // clear bit. + return false; + } + }); +} +} // namespace panda::ecmascript +#endif // ECMASCRIPT_MEM_SHARED_HEAP_SHARED_GC_MARKER_INL_H diff --git a/ecmascript/mem/shared_heap/shared_gc_marker.cpp b/ecmascript/mem/shared_heap/shared_gc_marker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65a027cdc3cb7fd509dfecb191364b89110b5f03 --- /dev/null +++ b/ecmascript/mem/shared_heap/shared_gc_marker.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024 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/mem/shared_heap/shared_gc_marker-inl.h" + +#include "ecmascript/mem/object_xray.h" +#include "ecmascript/mem/visitor.h" +#include "ecmascript/runtime.h" + +namespace panda::ecmascript { +void SharedGCMarker::MarkRoots(uint32_t threadId, EcmaVM *localVm) +{ + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarker::MarkRoots"); + ObjectXRay::VisitVMRoots( + localVm, + std::bind(&SharedGCMarker::HandleRoots, this, threadId, std::placeholders::_1, std::placeholders::_2), + std::bind(&SharedGCMarker::HandleRangeRoots, this, threadId, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3), + std::bind(&SharedGCMarker::HandleDerivedRoots, this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4)); + sWorkManager_->PushWorkNodeToGlobal(threadId, false); +} + +void SharedGCMarker::MarkSerializeRoots(uint32_t threadId) +{ + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarker::MarkSerializeRoots"); + auto callback = + std::bind(&SharedGCMarker::HandleRoots, this, threadId, std::placeholders::_1, std::placeholders::_2); + Runtime::GetInstance()->IterateSerializeRoot(callback); +} + +void SharedGCMarker::ProcessMarkStack(uint32_t threadId) +{ + auto cb = [&](ObjectSlot slot) { + MarkValue(threadId, slot); + }; + auto visitor = [this, threadId, cb](TaggedObject *root, ObjectSlot start, ObjectSlot end, + VisitObjectArea area) { + if (area == VisitObjectArea::IN_OBJECT) { + if (VisitBodyInObj(root, start, end, cb)) { + return; + } + } + for (ObjectSlot slot = start; slot < end; slot++) { + MarkValue(threadId, slot); + } + }; + TaggedObject *obj = nullptr; + while (true) { + obj = nullptr; + if (!sWorkManager_->Pop(threadId, &obj)) { + break; + } + JSHClass *hclass = obj->SynchronizedGetClass(); + auto size = hclass->SizeFromJSHClass(obj); + Region *region = Region::ObjectAddressToRange(obj); + ASSERT(region->InSharedSweepableSpace()); + region->IncreaseAliveObjectSafe(size); + MarkObject(threadId, hclass); + ObjectXRay::VisitObjectBody(obj, hclass, visitor); + } +} + +void SharedGCMarker::ResetWorkManager(SharedGCWorkManager *workManager) +{ + sWorkManager_ = workManager; +} +} // namespace panda::ecmascript \ No newline at end of file diff --git a/ecmascript/mem/shared_heap/shared_gc_marker.h b/ecmascript/mem/shared_heap/shared_gc_marker.h new file mode 100644 index 0000000000000000000000000000000000000000..d1c4daf21b91964315a67b51f740560ccbe1c14e --- /dev/null +++ b/ecmascript/mem/shared_heap/shared_gc_marker.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024 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_MEM_SHARED_HEAP_SHARED_GC_MARKER_H +#define ECMASCRIPT_MEM_SHARED_HEAP_SHARED_GC_MARKER_H + +#include "ecmascript/js_hclass.h" +#include "ecmascript/mem/slots.h" +#include "ecmascript/mem/work_manager.h" + +namespace panda::ecmascript { +class Region; +class TaggedObject; + +class SharedGCMarker { +public: + explicit SharedGCMarker(SharedGCWorkManager *workManger) : sWorkManager_(workManger) {} + ~SharedGCMarker() = default; + + void ResetWorkManager(SharedGCWorkManager *workManager); + void MarkRoots(uint32_t threadId, EcmaVM *localVm); + void MarkSerializeRoots(uint32_t threadId); + void ProcessMarkStack(uint32_t threadId); + template + inline bool VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, Callback callback); + inline void MarkValue(uint32_t threadId, ObjectSlot &slot); + inline void MarkObject(uint32_t threadId, TaggedObject *object); + inline void HandleRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot); + inline void HandleRangeRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot start, + ObjectSlot end); + inline void HandleDerivedRoots(Root type, ObjectSlot base, ObjectSlot derived, + uintptr_t baseOldObject); + + inline void ProcessLocalToShare(uint32_t threadId, Heap *localHeap); + inline void HandleLocalToShareRSet(uint32_t threadId, Region *region); + inline void RecordWeakReference(uint32_t threadId, JSTaggedType *ref); + +private: + SharedGCWorkManager *sWorkManager_ { nullptr }; +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_MEM_SHARED_HEAP_SHARED_GC_MARKER_H \ No newline at end of file diff --git a/ecmascript/mem/shared_heap/shared_space.cpp b/ecmascript/mem/shared_heap/shared_space.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b5e70b0b8569f42c4dbe08882ba1404bafa2fc3a --- /dev/null +++ b/ecmascript/mem/shared_heap/shared_space.cpp @@ -0,0 +1,461 @@ +/* + * Copyright (c) 2024 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/mem/shared_heap/shared_space.h" + +#include "ecmascript/js_hclass-inl.h" +#include "ecmascript/mem/allocator-inl.h" +#include "ecmascript/mem/free_object_set.h" +#include "ecmascript/mem/heap-inl.h" +#include "ecmascript/mem/shared_heap/shared_concurrent_sweeper.h" + +namespace panda::ecmascript { +SharedSparseSpace::SharedSparseSpace(SharedHeap *heap, + MemSpaceType type, + size_t initialCapacity, + size_t maximumCapacity) + : Space(heap, heap->GetHeapRegionAllocator(), type, initialCapacity, maximumCapacity), + sweepState_(SweepState::NO_SWEEP), + sHeap_(heap), + liveObjectSize_(0) +{ + allocator_ = new FreeListAllocator(heap); +} + +void SharedSparseSpace::Reset() +{ + allocator_->RebuildFreeList(); + ReclaimRegions(); + liveObjectSize_ = 0; +} + +void SharedSparseSpace::ResetTopPointer(uintptr_t top) +{ + allocator_->ResetTopPointer(top); +} + +// only used in share heap initialize before first vmThread created. +uintptr_t SharedSparseSpace::AllocateWithoutGC(size_t size) +{ + uintptr_t object = TryAllocate(size); + CHECK_SOBJECT_AND_INC_OBJ_SIZE(size); + object = AllocateWithExpand(nullptr, size); + CHECK_SOBJECT_AND_INC_OBJ_SIZE(size); + return object; +} + +uintptr_t SharedSparseSpace::Allocate(JSThread *thread, size_t size, bool allowGC) +{ + ASSERT(thread->IsInRunningStateOrProfiling()); + uintptr_t object = TryAllocate(size); + CHECK_SOBJECT_AND_INC_OBJ_SIZE(size); + if (sweepState_ == SweepState::SWEEPING) { + object = AllocateAfterSweepingCompleted(size); + CHECK_SOBJECT_AND_INC_OBJ_SIZE(size); + } + // Check whether it is necessary to trigger Shared GC before expanding to avoid OOM risk. + if (allowGC && sHeap_->CheckAndTriggerGC(thread)) { + object = TryAllocate(size); + CHECK_SOBJECT_AND_INC_OBJ_SIZE(size); + } + object = AllocateWithExpand(thread, size); + CHECK_SOBJECT_AND_INC_OBJ_SIZE(size); + if (allowGC) { + sHeap_->CollectGarbage(thread, TriggerGCType::SHARED_GC, GCReason::ALLOCATION_FAILED); + object = Allocate(thread, size, false); + } + return object; +} + +uintptr_t SharedSparseSpace::AllocateNoGCAndExpand([[maybe_unused]] JSThread *thread, size_t size) +{ + ASSERT(thread->IsInRunningStateOrProfiling()); + uintptr_t object = TryAllocate(size); + CHECK_SOBJECT_AND_INC_OBJ_SIZE(size); + if (sweepState_ == SweepState::SWEEPING) { + object = AllocateAfterSweepingCompleted(size); + CHECK_SOBJECT_AND_INC_OBJ_SIZE(size); + } + return object; +} + +uintptr_t SharedSparseSpace::TryAllocate(size_t size) +{ + LockHolder lock(allocateLock_); + return allocator_->Allocate(size); +} + +uintptr_t SharedSparseSpace::AllocateWithExpand(JSThread *thread, size_t size) +{ + LockHolder lock(allocateLock_); + // In order to avoid expand twice by different threads, try allocate first. + auto object = allocator_->Allocate(size); + if (object == 0 && Expand(thread)) { + object = allocator_->Allocate(size); + } + return object; +} + +bool SharedSparseSpace::Expand(JSThread *thread) +{ + if (CommittedSizeExceed()) { + LOG_ECMA_MEM(INFO) << "Expand::Committed size " << committedSize_ << " of Sparse Space is too big. "; + return false; + } + Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, thread, sHeap_); + region->InitializeFreeObjectSets(); + AddRegion(region); + allocator_->AddFree(region); + return true; +} + +Region *SharedSparseSpace::AllocateDeserializeRegion(JSThread *thread) +{ + Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, thread, sHeap_); + region->InitializeFreeObjectSets(); + return region; +} + +void SharedSparseSpace::MergeDeserializeAllocateRegions(const std::vector &allocateRegions) +{ + LockHolder lock(allocateLock_); + for (auto region : allocateRegions) { + AddRegion(region); + allocator_->AddFree(region); + allocator_->ResetTopPointer(region->GetHighWaterMark()); + region->SetHighWaterMark(region->GetEnd()); + } +} + +uintptr_t SharedSparseSpace::AllocateAfterSweepingCompleted(size_t size) +{ + LockHolder lock(allocateLock_); + if (sweepState_ != SweepState::SWEEPING) { + return allocator_->Allocate(size); + } + if (TryFillSweptRegion()) { + auto object = allocator_->Allocate(size); + if (object != 0) { + return object; + } + } + // Parallel sweep and fill + sHeap_->GetSweeper()->EnsureTaskFinished(spaceType_); + return allocator_->Allocate(size); +} + +void SharedSparseSpace::PrepareSweeping() +{ + liveObjectSize_ = 0; + EnumerateRegions([this](Region *current) { + IncreaseLiveObjectSize(current->AliveObject()); + current->ResetWasted(); + AddSweepingRegion(current); + }); + SortSweepingRegion(); + sweepState_ = SweepState::SWEEPING; + allocator_->RebuildFreeList(); +} + +void SharedSparseSpace::AsyncSweep(bool isMain) +{ + Region *current = GetSweepingRegionSafe(); + while (current != nullptr) { + FreeRegion(current, isMain); + // Main thread sweeping region is added; + if (!isMain) { + AddSweptRegionSafe(current); + } + current = GetSweepingRegionSafe(); + } +} + +void SharedSparseSpace::Sweep() +{ + liveObjectSize_ = 0; + allocator_->RebuildFreeList(); + EnumerateRegions([this](Region *current) { + IncreaseLiveObjectSize(current->AliveObject()); + current->ResetWasted(); + FreeRegion(current); + }); +} + +bool SharedSparseSpace::TryFillSweptRegion() +{ + if (sweptList_.empty()) { + return false; + } + Region *region = nullptr; + while ((region = GetSweptRegionSafe()) != nullptr) { + allocator_->CollectFreeObjectSet(region); + region->ResetSwept(); + } + return true; +} + +bool SharedSparseSpace::FinishFillSweptRegion() +{ + bool ret = TryFillSweptRegion(); + sweepState_ = SweepState::SWEPT; + return ret; +} + +void SharedSparseSpace::AddSweepingRegion(Region *region) +{ + sweepingList_.emplace_back(region); +} + +void SharedSparseSpace::SortSweepingRegion() +{ + // Sweep low alive object size at first + std::sort(sweepingList_.begin(), sweepingList_.end(), [](Region *first, Region *second) { + return first->AliveObject() < second->AliveObject(); + }); +} + +Region *SharedSparseSpace::GetSweepingRegionSafe() +{ + LockHolder holder(lock_); + Region *region = nullptr; + if (!sweepingList_.empty()) { + region = sweepingList_.back(); + sweepingList_.pop_back(); + } + return region; +} + +void SharedSparseSpace::AddSweptRegionSafe(Region *region) +{ + LockHolder holder(lock_); + sweptList_.emplace_back(region); +} + +Region *SharedSparseSpace::GetSweptRegionSafe() +{ + LockHolder holder(lock_); + Region *region = nullptr; + if (!sweptList_.empty()) { + region = sweptList_.back(); + sweptList_.pop_back(); + } + return region; +} + +void SharedSparseSpace::FreeRegion(Region *current, bool isMain) +{ + uintptr_t freeStart = current->GetBegin(); + current->IterateAllMarkedBits([this, &freeStart, isMain](void *mem) { + auto header = reinterpret_cast(mem); + auto klass = header->GetClass(); + auto size = klass->SizeFromJSHClass(header); + + uintptr_t freeEnd = ToUintPtr(mem); + if (freeStart != freeEnd) { + FreeLiveRange(freeStart, freeEnd, isMain); + } + freeStart = freeEnd + size; + }); + uintptr_t freeEnd = current->GetEnd(); + if (freeStart != freeEnd) { + FreeLiveRange(freeStart, freeEnd, isMain); + } +} + +void SharedSparseSpace::FreeLiveRange(uintptr_t freeStart, uintptr_t freeEnd, bool isMain) +{ + // No need to clear rememberset here, because shared region has no remember set now. + allocator_->Free(freeStart, freeEnd - freeStart, isMain); +} + +void SharedSparseSpace::IterateOverObjects(const std::function &visitor) const +{ + allocator_->FillBumpPointer(); + EnumerateRegions([&](Region *region) { + uintptr_t curPtr = region->GetBegin(); + uintptr_t endPtr = region->GetEnd(); + while (curPtr < endPtr) { + auto freeObject = FreeObject::Cast(curPtr); + size_t objSize; + // If curPtr is freeObject, It must to mark unpoison first. + ASAN_UNPOISON_MEMORY_REGION(freeObject, TaggedObject::TaggedObjectSize()); + if (!freeObject->IsFreeObject()) { + auto obj = reinterpret_cast(curPtr); + visitor(obj); + objSize = obj->GetClass()->SizeFromJSHClass(obj); + } else { + freeObject->AsanUnPoisonFreeObject(); + objSize = freeObject->Available(); + freeObject->AsanPoisonFreeObject(); + } + curPtr += objSize; + CHECK_OBJECT_SIZE(objSize); + } + CHECK_REGION_END(curPtr, endPtr); + }); +} + +size_t SharedSparseSpace::GetHeapObjectSize() const +{ + return liveObjectSize_; +} + +void SharedSparseSpace::IncreaseAllocatedSize(size_t size) +{ + allocator_->IncreaseAllocatedSize(size); +} + +size_t SharedSparseSpace::GetTotalAllocatedSize() const +{ + return allocator_->GetAllocatedSize(); +} + +void SharedSparseSpace::InvokeAllocationInspector(Address object, size_t size, size_t alignedSize) +{ + ASSERT(size <= alignedSize); + if (LIKELY(!allocationCounter_.IsActive())) { + return; + } + if (alignedSize >= allocationCounter_.NextBytes()) { + allocationCounter_.InvokeAllocationInspector(object, size, alignedSize); + } + allocationCounter_.AdvanceAllocationInspector(alignedSize); +} + +SharedNonMovableSpace::SharedNonMovableSpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity) + : SharedSparseSpace(heap, MemSpaceType::SHARED_NON_MOVABLE, initialCapacity, maximumCapacity) +{ +} + +SharedOldSpace::SharedOldSpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity) + : SharedSparseSpace(heap, MemSpaceType::SHARED_OLD_SPACE, initialCapacity, maximumCapacity) +{ +} + +SharedReadOnlySpace::SharedReadOnlySpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity) + : Space( + heap, heap->GetHeapRegionAllocator(), MemSpaceType::SHARED_READ_ONLY_SPACE, initialCapacity, maximumCapacity) +{ +} + +bool SharedReadOnlySpace::Expand(JSThread *thread) +{ + if (committedSize_ >= initialCapacity_ + outOfMemoryOvershootSize_ && + !heap_->NeedStopCollection()) { + return false; + } + uintptr_t top = allocator_.GetTop(); + auto currentRegion = GetCurrentRegion(); + if (currentRegion != nullptr) { + currentRegion->SetHighWaterMark(top); + } + Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, thread, heap_); + allocator_.Reset(region->GetBegin(), region->GetEnd()); + AddRegion(region); + return true; +} + +uintptr_t SharedReadOnlySpace::Allocate(JSThread *thread, size_t size) +{ + ASSERT(thread->IsInRunningStateOrProfiling()); + LockHolder holder(allocateLock_); + auto object = allocator_.Allocate(size); + if (object != 0) { + return object; + } + if (Expand(thread)) { + object = allocator_.Allocate(size); + } + return object; +} + +SharedHugeObjectSpace::SharedHugeObjectSpace(BaseHeap *heap, HeapRegionAllocator *heapRegionAllocator, + size_t initialCapacity, size_t maximumCapacity) + : Space(heap, heapRegionAllocator, MemSpaceType::SHARED_HUGE_OBJECT_SPACE, initialCapacity, maximumCapacity) +{ +} + + +uintptr_t SharedHugeObjectSpace::Allocate(JSThread *thread, size_t objectSize) +{ + ASSERT(thread->IsInRunningStateOrProfiling()); + LockHolder lock(allocateLock_); + // In HugeObject allocation, we have a revervation of 8 bytes for markBitSet in objectSize. + // In case Region is not aligned by 16 bytes, HUGE_OBJECT_BITSET_SIZE is 8 bytes more. + size_t alignedSize = AlignUp(objectSize + sizeof(Region) + HUGE_OBJECT_BITSET_SIZE, PANDA_POOL_ALIGNMENT_IN_BYTES); + if (CommittedSizeExceed(alignedSize)) { + LOG_ECMA_MEM(INFO) << "Committed size " << committedSize_ << " of huge object space is too big."; + return 0; + } + Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, alignedSize, thread, heap_); + AddRegion(region); + // It need to mark unpoison when huge object being allocated. + ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast(region->GetBegin()), objectSize); +#ifdef ECMASCRIPT_SUPPORT_HEAPSAMPLING + InvokeAllocationInspector(region->GetBegin(), objectSize); +#endif + return region->GetBegin(); +} + +void SharedHugeObjectSpace::Sweep() +{ + Region *currentRegion = GetRegionList().GetFirst(); + while (currentRegion != nullptr) { + Region *next = currentRegion->GetNext(); + bool isMarked = false; + currentRegion->IterateAllMarkedBits([&isMarked]([[maybe_unused]] void *mem) { isMarked = true; }); + if (!isMarked) { + GetRegionList().RemoveNode(currentRegion); + hugeNeedFreeList_.AddNode(currentRegion); + } + currentRegion = next; + } +} + +size_t SharedHugeObjectSpace::GetHeapObjectSize() const +{ + return committedSize_; +} + +void SharedHugeObjectSpace::IterateOverObjects(const std::function &objectVisitor) const +{ + EnumerateRegions([&](Region *region) { + uintptr_t curPtr = region->GetBegin(); + objectVisitor(reinterpret_cast(curPtr)); + }); +} + +void SharedHugeObjectSpace::ReclaimHugeRegion() +{ + if (hugeNeedFreeList_.IsEmpty()) { + return; + } + do { + Region *last = hugeNeedFreeList_.PopBack(); + ClearAndFreeRegion(last); + } while (!hugeNeedFreeList_.IsEmpty()); +} + +void SharedHugeObjectSpace::InvokeAllocationInspector(Address object, size_t objectSize) +{ + if (LIKELY(!allocationCounter_.IsActive())) { + return; + } + if (objectSize >= allocationCounter_.NextBytes()) { + allocationCounter_.InvokeAllocationInspector(object, objectSize, objectSize); + } + allocationCounter_.AdvanceAllocationInspector(objectSize); +} +} // namespace panda::ecmascript diff --git a/ecmascript/mem/shared_heap/shared_space.h b/ecmascript/mem/shared_heap/shared_space.h new file mode 100644 index 0000000000000000000000000000000000000000..46761a007711d2d62a0784d6cc5ead82acd75239 --- /dev/null +++ b/ecmascript/mem/shared_heap/shared_space.h @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2024 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_MEM_SHARED_SHARED_SPACE_H +#define ECMASCRIPT_MEM_SHARED_SHARED_SPACE_H + +#include "ecmascript/mem/mem_common.h" +#include "ecmascript/mem/sparse_space.h" + +namespace panda::ecmascript { +#ifdef ECMASCRIPT_SUPPORT_HEAPSAMPLING +#define CHECK_SOBJECT_AND_INC_OBJ_SIZE(size) \ + if (object != 0) { \ + IncreaseLiveObjectSize(size); \ + if (sHeap_->IsReadyToMark()) { \ + Region::ObjectAddressToRange(object)->IncreaseAliveObject(size); \ + } \ + InvokeAllocationInspector(object, size, size); \ + return object; \ + } +#else +#define CHECK_SOBJECT_AND_INC_OBJ_SIZE(size) \ + if (object != 0) { \ + IncreaseLiveObjectSize(size); \ + if (heap_->IsReadyToMark()) { \ + Region::ObjectAddressToRange(object)->IncreaseAliveObject(size); \ + } \ + return object; \ + } +#endif + +class SharedHeap; + +class SharedSparseSpace : public Space { +public: + SharedSparseSpace(SharedHeap *heap, MemSpaceType type, size_t initialCapacity, size_t maximumCapacity); + ~SharedSparseSpace() override + { + delete allocator_; + } + NO_COPY_SEMANTIC(SharedSparseSpace); + NO_MOVE_SEMANTIC(SharedSparseSpace); + + void Reset(); + + uintptr_t AllocateWithoutGC(size_t size); + + uintptr_t Allocate(JSThread *thread, size_t size, bool allowGC = true); + + // For work deserialize + void ResetTopPointer(uintptr_t top); + uintptr_t AllocateNoGCAndExpand(JSThread *thread, size_t size); + Region *AllocateDeserializeRegion(JSThread *thread); + void MergeDeserializeAllocateRegions(const std::vector &allocateRegions); + + // For sweeping + void PrepareSweeping(); + void AsyncSweep(bool isMain); + void Sweep(); + + bool TryFillSweptRegion(); + // Ensure All region finished sweeping + bool FinishFillSweptRegion(); + + void AddSweepingRegion(Region *region); + void SortSweepingRegion(); + Region *GetSweepingRegionSafe(); + void AddSweptRegionSafe(Region *region); + Region *GetSweptRegionSafe(); + + void FreeRegion(Region *current, bool isMain = true); + void FreeLiveRange(uintptr_t freeStart, uintptr_t freeEnd, bool isMain); + + void IterateOverObjects(const std::function &objectVisitor) const; + + size_t GetHeapObjectSize() const; + + void IncreaseAllocatedSize(size_t size); + + void IncreaseLiveObjectSize(size_t size) + { + liveObjectSize_ += size; + } + + void DecreaseLiveObjectSize(size_t size) + { + liveObjectSize_ -= size; + } + + bool CommittedSizeExceed() + { + return committedSize_ >= maximumCapacity_ + outOfMemoryOvershootSize_; + } + + size_t GetTotalAllocatedSize() const; + + void InvokeAllocationInspector(Address object, size_t size, size_t alignedSize); + +protected: + FreeListAllocator *allocator_; + SweepState sweepState_ = SweepState::NO_SWEEP; + +private: + uintptr_t AllocateWithExpand(JSThread *thread, size_t size); + uintptr_t TryAllocate(size_t size); + bool Expand(JSThread *thread); + // For sweeping + uintptr_t AllocateAfterSweepingCompleted(size_t size); + + Mutex lock_; + Mutex allocateLock_; + SharedHeap *sHeap_ {nullptr}; + std::vector sweepingList_; + std::vector sweptList_; + size_t liveObjectSize_ {0}; +}; + +class SharedNonMovableSpace : public SharedSparseSpace { +public: + SharedNonMovableSpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity); + ~SharedNonMovableSpace() override = default; + NO_COPY_SEMANTIC(SharedNonMovableSpace); + NO_MOVE_SEMANTIC(SharedNonMovableSpace); +}; + +class SharedOldSpace : public SharedSparseSpace { +public: + SharedOldSpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity); + ~SharedOldSpace() override = default; + NO_COPY_SEMANTIC(SharedOldSpace); + NO_MOVE_SEMANTIC(SharedOldSpace); +}; + +class SharedReadOnlySpace : public Space { +public: + SharedReadOnlySpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity); + ~SharedReadOnlySpace() override = default; + void SetReadOnly() + { + auto cb = [](Region *region) { + region->SetReadOnlyAndMarked(); + }; + EnumerateRegions(cb); + } + + void ClearReadOnly() + { + auto cb = [](Region *region) { + region->ClearReadOnly(); + }; + EnumerateRegions(cb); + } + + bool Expand(JSThread *thread); + + uintptr_t Allocate(JSThread *thread, size_t size); + + NO_COPY_SEMANTIC(SharedReadOnlySpace); + NO_MOVE_SEMANTIC(SharedReadOnlySpace); + +private: + Mutex allocateLock_; + BumpPointerAllocator allocator_; +}; + +class SharedHugeObjectSpace : public Space { +public: + SharedHugeObjectSpace(BaseHeap *heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity, + size_t maximumCapacity); + ~SharedHugeObjectSpace() override = default; + NO_COPY_SEMANTIC(SharedHugeObjectSpace); + NO_MOVE_SEMANTIC(SharedHugeObjectSpace); + uintptr_t Allocate(JSThread *thread, size_t objectSize); + void Sweep(); + size_t GetHeapObjectSize() const; + void IterateOverObjects(const std::function &objectVisitor) const; + + void ReclaimHugeRegion(); + + void InvokeAllocationInspector(Address object, size_t objectSize); + + bool CommittedSizeExceed(size_t size) const + { + return committedSize_ + size >= maximumCapacity_ + outOfMemoryOvershootSize_; + } +private: + static constexpr size_t HUGE_OBJECT_BITSET_SIZE = 16; + EcmaList hugeNeedFreeList_ {}; + Mutex allocateLock_; +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_MEM_SHARED_SHARED_SPACE_H diff --git a/ecmascript/mem/space-inl.h b/ecmascript/mem/space-inl.h index 356da0c58412fdbbcb2c9621d0e4c21341bd38f8..35d80c294686731ecaeb7f144cfd34185fef65d7 100644 --- a/ecmascript/mem/space-inl.h +++ b/ecmascript/mem/space-inl.h @@ -96,6 +96,18 @@ RegionSpaceFlag Space::GetRegionFlag() const case MemSpaceType::APPSPAWN_SPACE: flags = RegionSpaceFlag::IN_APPSPAWN_SPACE; break; + case MemSpaceType::SHARED_NON_MOVABLE: + flags = RegionSpaceFlag::IN_SHARED_NON_MOVABLE; + break; + case MemSpaceType::SHARED_OLD_SPACE: + flags = RegionSpaceFlag::IN_SHARED_OLD_SPACE; + break; + case MemSpaceType::SHARED_READ_ONLY_SPACE: + flags = RegionSpaceFlag::IN_SHARED_READ_ONLY_SPACE; + break; + case MemSpaceType::SHARED_HUGE_OBJECT_SPACE: + flags = RegionSpaceFlag::IN_SHARED_HUGE_OBJECT_SPACE; + break; default: LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); diff --git a/ecmascript/mem/space.cpp b/ecmascript/mem/space.cpp index 812977007bdf7b7fe9618624c6f54c9659634429..a60523481a14697df288c71ac0f7d053651b0cb2 100644 --- a/ecmascript/mem/space.cpp +++ b/ecmascript/mem/space.cpp @@ -22,7 +22,7 @@ #include "ecmascript/mem/space.h" namespace panda::ecmascript { -Space::Space(Heap* heap, HeapRegionAllocator *heapRegionAllocator, +Space::Space(BaseHeap* heap, HeapRegionAllocator *heapRegionAllocator, MemSpaceType spaceType, size_t initialCapacity, size_t maximumCapacity) : heap_(heap), @@ -66,12 +66,14 @@ void Space::ClearAndFreeRegion(Region *region, size_t cachedSize) LOG_ECMA_MEM(DEBUG) << "Clear region from:" << region << " to " << ToSpaceTypeName(spaceType_); region->DeleteCrossRegionRSet(); region->DeleteOldToNewRSet(); + region->DeleteLocalToShareRSet(); region->DeleteSweepingRSet(); DecreaseCommitted(region->GetCapacity()); DecreaseObjectSize(region->GetSize()); if (spaceType_ == MemSpaceType::OLD_SPACE || spaceType_ == MemSpaceType::NON_MOVABLE || spaceType_ == MemSpaceType::MACHINE_CODE_SPACE || spaceType_ == MemSpaceType::LOCAL_SPACE || - spaceType_ == MemSpaceType::APPSPAWN_SPACE) { + spaceType_ == MemSpaceType::APPSPAWN_SPACE || spaceType_ == MemSpaceType::SHARED_NON_MOVABLE || + spaceType_ == MemSpaceType::SHARED_OLD_SPACE) { region->DestroyFreeObjectSets(); } heapRegionAllocator_->FreeRegion(region, cachedSize); @@ -98,6 +100,7 @@ HugeMachineCodeSpace::HugeMachineCodeSpace(Heap *heap, HeapRegionAllocator *heap uintptr_t HugeObjectSpace::Allocate(size_t objectSize, JSThread *thread) { + ASSERT(thread->IsInRunningStateOrProfiling()); // In HugeObject allocation, we have a revervation of 8 bytes for markBitSet in objectSize. // In case Region is not aligned by 16 bytes, HUGE_OBJECT_BITSET_SIZE is 8 bytes more. size_t alignedSize = AlignUp(objectSize + sizeof(Region) + HUGE_OBJECT_BITSET_SIZE, PANDA_POOL_ALIGNMENT_IN_BYTES); @@ -105,7 +108,7 @@ uintptr_t HugeObjectSpace::Allocate(size_t objectSize, JSThread *thread) LOG_ECMA_MEM(INFO) << "Committed size " << committedSize_ << " of huge object space is too big."; return 0; } - Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, alignedSize, thread); + Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, alignedSize, thread, heap_); AddRegion(region); // It need to mark unpoison when huge object being allocated. ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast(region->GetBegin()), objectSize); diff --git a/ecmascript/mem/space.h b/ecmascript/mem/space.h index 613f6bc84c2422a4f7f85425af472b712221e26c..e59f9a228a5595b153be6f0897ec619a52a0f386 100644 --- a/ecmascript/mem/space.h +++ b/ecmascript/mem/space.h @@ -39,11 +39,26 @@ enum MemSpaceType { READ_ONLY_SPACE, APPSPAWN_SPACE, HUGE_MACHINE_CODE_SPACE, + SHARED_NON_MOVABLE, + SHARED_OLD_SPACE, + SHARED_READ_ONLY_SPACE, + SHARED_HUGE_OBJECT_SPACE, SPACE_TYPE_LAST, // Count of different types + SHARED_BEGIN = SHARED_NON_MOVABLE, + SHARED_END = SHARED_HUGE_OBJECT_SPACE, + // Free region means memory maybe always in use and can not be evacuated FREE_LIST_NUM = MACHINE_CODE_SPACE - OLD_SPACE + 1, + SHARED_SWEEPING_SPACE_BEGIN = SHARED_NON_MOVABLE, + SHARED_SWEEPING_SPACE_END = SHARED_OLD_SPACE, + SHARED_SWEEPING_SPACE_NUM = SHARED_SWEEPING_SPACE_END - SHARED_SWEEPING_SPACE_BEGIN + 1, }; +static inline bool IsSMemSpace(MemSpaceType type) +{ + return (type >= MemSpaceType::SHARED_BEGIN) && (type <= MemSpaceType::SHARED_END); +} + static inline std::string ToSpaceTypeName(MemSpaceType type) { switch (type) { @@ -69,6 +84,14 @@ static inline std::string ToSpaceTypeName(MemSpaceType type) return "appspawn space"; case HUGE_MACHINE_CODE_SPACE: return "huge machine code space"; + case SHARED_NON_MOVABLE: + return "shared non movable space"; + case SHARED_OLD_SPACE: + return "shared old space"; + case SHARED_READ_ONLY_SPACE: + return "shared read only space"; + case SHARED_HUGE_OBJECT_SPACE: + return "shared huge object space"; default: return "unknown space"; } @@ -76,7 +99,7 @@ static inline std::string ToSpaceTypeName(MemSpaceType type) class Space { public: - Space(Heap* heap, HeapRegionAllocator *regionAllocator, MemSpaceType spaceType, size_t initialCapacity, + Space(BaseHeap* heap, HeapRegionAllocator *regionAllocator, MemSpaceType spaceType, size_t initialCapacity, size_t maximumCapacity); virtual ~Space() = default; NO_COPY_SEMANTIC(Space); @@ -221,7 +244,7 @@ public: protected: void ClearAndFreeRegion(Region *region, size_t cachedSize = 0); - Heap *heap_ {nullptr}; + BaseHeap *heap_ {nullptr}; HeapRegionAllocator *heapRegionAllocator_ {nullptr}; EcmaList regionList_ {}; MemSpaceType spaceType_ {}; @@ -236,9 +259,9 @@ protected: class HugeObjectSpace : public Space { public: - HugeObjectSpace(Heap* heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity, + HugeObjectSpace(Heap *heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity, size_t maximumCapacity); - HugeObjectSpace(Heap* heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity, + HugeObjectSpace(Heap *heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity, size_t maximumCapacity, MemSpaceType spaceType); ~HugeObjectSpace() override = default; NO_COPY_SEMANTIC(HugeObjectSpace); @@ -259,7 +282,7 @@ private: class HugeMachineCodeSpace : public HugeObjectSpace { public: - HugeMachineCodeSpace(Heap* heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity, + HugeMachineCodeSpace(Heap *heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity, size_t maximumCapacity); }; diff --git a/ecmascript/mem/sparse_space.cpp b/ecmascript/mem/sparse_space.cpp index a41278b8659237dfd69382a1f0338d85171c1a2b..c4443ace2f9d84302ba535d901efad2292534412 100644 --- a/ecmascript/mem/sparse_space.cpp +++ b/ecmascript/mem/sparse_space.cpp @@ -27,6 +27,7 @@ namespace panda::ecmascript { SparseSpace::SparseSpace(Heap *heap, MemSpaceType type, size_t initialCapacity, size_t maximumCapacity) : Space(heap, heap->GetHeapRegionAllocator(), type, initialCapacity, maximumCapacity), sweepState_(SweepState::NO_SWEEP), + localHeap_(heap), liveObjectSize_(0) { allocator_ = new FreeListAllocator(heap); @@ -34,8 +35,8 @@ SparseSpace::SparseSpace(Heap *heap, MemSpaceType type, size_t initialCapacity, void SparseSpace::Initialize() { - Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, - heap_->GetJSThread()); + JSThread *thread = localHeap_->GetJSThread(); + Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, thread, localHeap_); region->InitializeFreeObjectSets(); AddRegion(region); @@ -56,6 +57,7 @@ void SparseSpace::ResetTopPointer(uintptr_t top) uintptr_t SparseSpace::Allocate(size_t size, bool allowGC) { + ASSERT(localHeap_->GetJSThread()->IsInRunningStateOrProfiling()); auto object = allocator_->Allocate(size); CHECK_OBJECT_AND_INC_OBJ_SIZE(size); @@ -65,7 +67,7 @@ uintptr_t SparseSpace::Allocate(size_t size, bool allowGC) } // Check whether it is necessary to trigger Old GC before expanding to avoid OOM risk. - if (allowGC && heap_->CheckAndTriggerOldGC()) { + if (allowGC && localHeap_->CheckAndTriggerOldGC()) { object = allocator_->Allocate(size); CHECK_OBJECT_AND_INC_OBJ_SIZE(size); } @@ -76,7 +78,7 @@ uintptr_t SparseSpace::Allocate(size_t size, bool allowGC) } if (allowGC) { - heap_->CollectGarbage(TriggerGCType::OLD_GC, GCReason::ALLOCATION_FAILED); + localHeap_->CollectGarbage(TriggerGCType::OLD_GC, GCReason::ALLOCATION_FAILED); object = Allocate(size, false); // Size is already increment } @@ -89,8 +91,8 @@ bool SparseSpace::Expand() LOG_ECMA_MEM(INFO) << "Expand::Committed size " << committedSize_ << " of Sparse Space is too big. "; return false; } - - Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, heap_->GetJSThread()); + JSThread *thread = localHeap_->GetJSThread(); + Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, thread, localHeap_); region->InitializeFreeObjectSets(); AddRegion(region); allocator_->AddFree(region); @@ -100,7 +102,6 @@ bool SparseSpace::Expand() uintptr_t SparseSpace::AllocateAfterSweepingCompleted(size_t size) { ASSERT(sweepState_ == SweepState::SWEEPING); - MEM_ALLOCATE_AND_GC_TRACE(heap_->GetEcmaVM(), ConcurrentSweepingWait); if (TryFillSweptRegion()) { auto object = allocator_->Allocate(size); if (object != 0) { @@ -108,7 +109,7 @@ uintptr_t SparseSpace::AllocateAfterSweepingCompleted(size_t size) } } // Parallel sweep and fill - heap_->GetSweeper()->EnsureTaskFinished(spaceType_); + localHeap_->GetSweeper()->EnsureTaskFinished(spaceType_); return allocator_->Allocate(size); } @@ -270,7 +271,7 @@ void SparseSpace::FreeRegion(Region *current, bool isMain) void SparseSpace::FreeLiveRange(Region *current, uintptr_t freeStart, uintptr_t freeEnd, bool isMain) { - heap_->GetSweeper()->ClearRSetInRange(current, freeStart, freeEnd); + localHeap_->GetSweeper()->ClearRSetInRange(current, freeStart, freeEnd); allocator_->Free(freeStart, freeEnd - freeStart, isMain); } @@ -411,10 +412,10 @@ void OldSpace::Merge(LocalSpace *localSpace) IncreaseLiveObjectSize(region->AliveObject()); allocator_->CollectFreeObjectSet(region); }); - size_t hugeSpaceCommitSize = heap_->GetHugeObjectSpace()->GetCommittedSize(); + size_t hugeSpaceCommitSize = localHeap_->GetHugeObjectSpace()->GetCommittedSize(); if (committedSize_ + hugeSpaceCommitSize > GetOverShootMaximumCapacity()) { LOG_ECMA_MEM(ERROR) << "Merge::Committed size " << committedSize_ << " of old space is too big. "; - heap_->ShouldThrowOOMError(true); + localHeap_->ShouldThrowOOMError(true); IncreaseMergeSize(committedSize_ - oldCommittedSize); // if throw OOM, temporarily increase space size to avoid vm crash IncreaseOutOfMemoryOvershootSize(committedSize_ + hugeSpaceCommitSize - GetOverShootMaximumCapacity()); @@ -426,13 +427,13 @@ void OldSpace::Merge(LocalSpace *localSpace) void OldSpace::SelectCSet() { - if (heap_->GetJSThread()->IsMarking()) { - heap_->GetEcmaVM()->GetEcmaGCStats()->RecordStatisticBeforeGC(TriggerGCType::OLD_GC, GCReason::OTHER); + if (localHeap_->IsMarking()) { + localHeap_->GetEcmaGCStats()->RecordStatisticBeforeGC(TriggerGCType::OLD_GC, GCReason::OTHER); } CheckRegionSize(); // 1、Select region which alive object larger than limit int64_t evacuateSizeLimit = 0; - if (!heap_->IsInBackground()) { + if (!localHeap_->IsInBackground()) { evacuateSizeLimit = PARTIAL_GC_MAX_EVACUATION_SIZE_FOREGROUND; EnumerateRegions([this](Region *region) { if (!region->MostObjectAlive()) { @@ -459,7 +460,8 @@ void OldSpace::SelectCSet() // Limit cset size unsigned long selectedRegionNumber = 0; - int64_t expectFreeSize = static_cast(heap_->GetCommittedSize() - heap_->GetHeapAliveSizeAfterGC()); + int64_t expectFreeSize = + static_cast(localHeap_->GetCommittedSize() - localHeap_->GetHeapAliveSizeAfterGC()); int64_t evacuateSize = std::min(evacuateSizeLimit, expectFreeSize); EnumerateCollectRegionSet([&](Region *current) { if (evacuateSize > 0) { @@ -469,14 +471,14 @@ void OldSpace::SelectCSet() return; } }); - OPTIONAL_LOG(heap_->GetEcmaVM(), INFO) << "Max evacuation size is 6_MB. The CSet region number: " + LOG_ECMA_MEM(DEBUG) << "Max evacuation size is 6_MB. The CSet region number: " << selectedRegionNumber; selectedRegionNumber = std::max(selectedRegionNumber, GetSelectedRegionNumber()); if (collectRegionSet_.size() > selectedRegionNumber) { collectRegionSet_.resize(selectedRegionNumber); } - heap_->GetEcmaVM()->GetEcmaGCStats()->SetRecordData( + localHeap_->GetEcmaGCStats()->SetRecordData( RecordData::COLLECT_REGION_SET_SIZE, collectRegionSet_.size() * Region::AVERAGE_REGION_EVACUATE_SIZE); EnumerateCollectRegionSet([&](Region *current) { RemoveRegion(current); @@ -485,14 +487,14 @@ void OldSpace::SelectCSet() current->SetGCFlag(RegionGCFlags::IN_COLLECT_SET); }); sweepState_ = SweepState::NO_SWEEP; - OPTIONAL_LOG(heap_->GetEcmaVM(), INFO) << "Select CSet success: number is " << collectRegionSet_.size(); + LOG_ECMA_MEM(DEBUG) << "Select CSet success: number is " << collectRegionSet_.size(); } void OldSpace::CheckRegionSize() { #ifndef NDEBUG if (sweepState_ == SweepState::SWEEPING) { - heap_->GetSweeper()->EnsureTaskFinished(spaceType_); + localHeap_->GetSweeper()->EnsureTaskFinished(spaceType_); } size_t available = allocator_->GetAvailableSize(); size_t wasted = allocator_->GetWastedSize(); @@ -518,10 +520,11 @@ void OldSpace::RevertCSet() void OldSpace::ReclaimCSet() { - size_t cachedSize = heap_->GetNewSpace()->GetInitialCapacity(); + size_t cachedSize = localHeap_->GetRegionCachedSize(); EnumerateCollectRegionSet([this, &cachedSize](Region *region) { region->DeleteCrossRegionRSet(); region->DeleteOldToNewRSet(); + region->DeleteLocalToShareRSet(); region->DeleteSweepingRSet(); region->DestroyFreeObjectSets(); heapRegionAllocator_->FreeRegion(region, cachedSize); @@ -559,8 +562,8 @@ void LocalSpace::Stop() uintptr_t NonMovableSpace::CheckAndAllocate(size_t size) { if (maximumCapacity_ == committedSize_ && GetHeapObjectSize() > MAX_NONMOVABLE_LIVE_OBJ_SIZE && - !heap_->GetOldGCRequested()) { - heap_->CollectGarbage(TriggerGCType::OLD_GC, GCReason::ALLOCATION_LIMIT); + !localHeap_->GetOldGCRequested()) { + localHeap_->CollectGarbage(TriggerGCType::OLD_GC, GCReason::ALLOCATION_LIMIT); } return Allocate(size); } diff --git a/ecmascript/mem/sparse_space.h b/ecmascript/mem/sparse_space.h index 653e0b8a1832d16fb51a29decc393045c5a08246..d7f8ef95be69e2218278221ce3f565335e188703 100644 --- a/ecmascript/mem/sparse_space.h +++ b/ecmascript/mem/sparse_space.h @@ -20,23 +20,23 @@ #include "ecmascript/mem/mem_common.h" #ifdef ECMASCRIPT_SUPPORT_HEAPSAMPLING -#define CHECK_OBJECT_AND_INC_OBJ_SIZE(size) \ - if (object != 0) { \ - IncreaseLiveObjectSize(size); \ - if (!heap_->IsConcurrentFullMark() || heap_->GetJSThread()->IsReadyToMark()) { \ - Region::ObjectAddressToRange(object)->IncreaseAliveObject(size); \ - } \ - InvokeAllocationInspector(object, size, size); \ - return object; \ +#define CHECK_OBJECT_AND_INC_OBJ_SIZE(size) \ + if (object != 0) { \ + IncreaseLiveObjectSize(size); \ + if (!heap_->IsConcurrentFullMark() || heap_->IsReadyToMark()) { \ + Region::ObjectAddressToRange(object)->IncreaseAliveObject(size); \ + } \ + InvokeAllocationInspector(object, size, size); \ + return object; \ } #else -#define CHECK_OBJECT_AND_INC_OBJ_SIZE(size) \ - if (object != 0) { \ - IncreaseLiveObjectSize(size); \ - if (!heap_->IsConcurrentFullMark() || heap_->GetJSThread()->IsReadyToMark()) { \ - Region::ObjectAddressToRange(object)->IncreaseAliveObject(size); \ - } \ - return object; \ +#define CHECK_OBJECT_AND_INC_OBJ_SIZE(size) \ + if (object != 0) { \ + IncreaseLiveObjectSize(size); \ + if (!heap_->IsConcurrentFullMark() || heap_->IsReadyToMark()) { \ + Region::ObjectAddressToRange(object)->IncreaseAliveObject(size); \ + } \ + return object; \ } #endif @@ -136,6 +136,7 @@ public: protected: FreeListAllocator *allocator_; SweepState sweepState_ = SweepState::NO_SWEEP; + Heap *localHeap_ {nullptr}; private: // For sweeping diff --git a/ecmascript/mem/stw_young_gc.cpp b/ecmascript/mem/stw_young_gc.cpp index 6c02773ba02aa3ccc7f6ab991565e1a6d60d25eb..5518b6a4ac32d4fd6e20eb7da910b9e0e48aeeae 100644 --- a/ecmascript/mem/stw_young_gc.cpp +++ b/ecmascript/mem/stw_young_gc.cpp @@ -117,8 +117,6 @@ void STWYoungGC::Sweep() } } } - - auto stringTable = heap_->GetEcmaVM()->GetEcmaStringTable(); WeakRootVisitor gcUpdateWeak = [](TaggedObject *header) { Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast(header)); if (!objectRegion->InYoungSpace()) { @@ -132,7 +130,6 @@ void STWYoungGC::Sweep() } return reinterpret_cast(ToUintPtr(nullptr)); }; - stringTable->SweepWeakReference(gcUpdateWeak); heap_->GetEcmaVM()->GetJSThread()->IterateWeakEcmaGlobalStorage(gcUpdateWeak); heap_->GetEcmaVM()->ProcessReferences(gcUpdateWeak); } diff --git a/ecmascript/mem/tagged_object.h b/ecmascript/mem/tagged_object.h index 238753b810bc9f5c2ae62e39264873dbe91cade6..3c69b4d817fb3bd2ad88b32f491773bd176fb63a 100644 --- a/ecmascript/mem/tagged_object.h +++ b/ecmascript/mem/tagged_object.h @@ -53,6 +53,7 @@ private: MarkWordType class_; friend class Heap; + friend class SharedHeap; friend class ObjectFactory; friend class EcmaString; }; diff --git a/ecmascript/mem/tlab_allocator-inl.h b/ecmascript/mem/tlab_allocator-inl.h index 654ee31cabf1545c32a6008e7adb1ff7c9bb7a79..9911fc4fdb71e004ae468641e65b8e4645c64c50 100644 --- a/ecmascript/mem/tlab_allocator-inl.h +++ b/ecmascript/mem/tlab_allocator-inl.h @@ -37,7 +37,7 @@ TlabAllocator::TlabAllocator(Heap *heap) inline void TlabAllocator::Finalize() { if (youngAllocator_.Available() != 0) { - FreeObject::FillFreeObject(heap_->GetEcmaVM(), youngAllocator_.GetTop(), youngAllocator_.Available()); + FreeObject::FillFreeObject(heap_, youngAllocator_.GetTop(), youngAllocator_.Available()); youngAllocator_.Reset(); } @@ -111,7 +111,7 @@ bool TlabAllocator::ExpandYoung() uintptr_t buffer = heap_->AllocateYoungSync(MIN_BUFFER_SIZE); if (buffer == 0) { if (youngAllocator_.Available() != 0) { - FreeObject::FillFreeObject(heap_->GetEcmaVM(), youngAllocator_.GetTop(), youngAllocator_.Available()); + FreeObject::FillFreeObject(heap_, youngAllocator_.GetTop(), youngAllocator_.Available()); } return false; } @@ -121,7 +121,7 @@ bool TlabAllocator::ExpandYoung() buffer = youngAllocator_.GetTop(); } else { if (youngAllocator_.Available() != 0) { - FreeObject::FillFreeObject(heap_->GetEcmaVM(), youngAllocator_.GetTop(), youngAllocator_.Available()); + FreeObject::FillFreeObject(heap_, youngAllocator_.GetTop(), youngAllocator_.Available()); } } youngAllocator_.Reset(buffer, end); diff --git a/ecmascript/mem/verification.cpp b/ecmascript/mem/verification.cpp index c8b6333f4e0d18a62394db1b6cfaaf62ecc8259a..ae65393541b39308039ddf789960c8a89ad40de6 100644 --- a/ecmascript/mem/verification.cpp +++ b/ecmascript/mem/verification.cpp @@ -16,12 +16,14 @@ #include "ecmascript/mem/verification.h" #include "ecmascript/js_tagged_value-inl.h" +#include "ecmascript/mem/concurrent_sweeper.h" +#include "ecmascript/mem/shared_heap/shared_concurrent_sweeper.h" #include "ecmascript/mem/slots.h" #include "ecmascript/mem/visitor.h" -#include "ecmascript/mem/concurrent_sweeper.h" +#include "ecmascript/runtime.h" namespace panda::ecmascript { -void LogErrorForObjSlot(const Heap *heap, const char *headerInfo, TaggedObject *obj, ObjectSlot slot, +void LogErrorForObjSlot(const BaseHeap *heap, const char *headerInfo, TaggedObject *obj, ObjectSlot slot, TaggedObject *value) { TaggedObject *slotValue = slot.GetTaggedObject(); @@ -50,7 +52,7 @@ void LogErrorForObjSlot(const Heap *heap, const char *headerInfo, TaggedObject * UNREACHABLE(); } -void LogErrorForObj(const Heap *heap, const char *headerInfo, TaggedObject *obj) +void LogErrorForObj(const BaseHeap *heap, const char *headerInfo, TaggedObject *obj) { Region *region = Region::ObjectAddressToRange(obj); LOG_GC(FATAL) << headerInfo @@ -65,7 +67,7 @@ void LogErrorForObj(const Heap *heap, const char *headerInfo, TaggedObject *obj) } // Only used for verify InactiveSemiSpace -void VerifyObjectVisitor::VerifyInactiveSemiSpaceMarkedObject(const Heap *heap, void *addr) +void VerifyObjectVisitor::VerifyInactiveSemiSpaceMarkedObject(const BaseHeap *heap, void *addr) { TaggedObject *object = reinterpret_cast(addr); Region *objectRegion = Region::ObjectAddressToRange(object); @@ -91,7 +93,7 @@ void VerifyObjectVisitor::VerifyInactiveSemiSpaceMarkedObject(const Heap *heap, void VerifyObjectVisitor::VisitAllObjects(TaggedObject *obj) { auto jsHclass = obj->GetClass(); - objXRay_.VisitObjectBody( + ObjectXRay::VisitObjectBody( obj, jsHclass, [this](TaggedObject *root, ObjectSlot start, ObjectSlot end, VisitObjectArea area) { if (area == VisitObjectArea::IN_OBJECT) { @@ -155,6 +157,13 @@ void VerifyObjectVisitor::VerifyObjectSlotLegal(ObjectSlot slot, TaggedObject *o case VerifyKind::VERIFY_EVACUATE_FULL: VerifyEvacuateFull(object, slot, value.GetTaggedObject()); break; + case VerifyKind::VERIFY_SHARED_RSET_POST_FULL_GC: + VerifySharedRSetPostFullGC(object, slot, value.GetTaggedObject()); + break; + case VerifyKind::VERIFY_PRE_SHARED_GC: + case VerifyKind::VERIFY_POST_SHARED_GC: + VerifySharedObjectReference(object, slot, value.GetTaggedObject()); + break; default: LOG_GC(FATAL) << "unknown verify kind:" << static_cast(verifyKind_); UNREACHABLE(); @@ -166,6 +175,7 @@ void VerifyObjectVisitor::VerifyMarkYoung(TaggedObject *object, ObjectSlot slot, { Region *objectRegion = Region::ObjectAddressToRange(object); Region *valueRegion = Region::ObjectAddressToRange(value); + ASSERT(!objectRegion->InSharedHeap()); if (!objectRegion->InYoungSpace() && valueRegion->InYoungSpace()) { if (!objectRegion->TestOldToNew(slot.SlotAddress())) { LogErrorForObjSlot(heap_, "Verify MarkYoung: Old object, slot miss old_to_new bit.", object, slot, value); @@ -174,6 +184,12 @@ void VerifyObjectVisitor::VerifyMarkYoung(TaggedObject *object, ObjectSlot slot, object, slot, value); } } + if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) { + if (!objectRegion->TestLocalToShare(slot.SlotAddress())) { + LogErrorForObjSlot(heap_, "Verify MarkYoung: Local object, slot local_to_share bit = 0, " + "but SharedHeap object.", object, slot, value); + } + } if (objectRegion->Test(object)) { if (!objectRegion->InYoungSpace() && !objectRegion->InAppSpawnSpace() && !objectRegion->InReadOnlySpace()) { LogErrorForObj(heap_, "Verify MarkYoung: Marked object, NOT in Young/AppSpawn/ReadOnly Space", object); @@ -183,7 +199,7 @@ void VerifyObjectVisitor::VerifyMarkYoung(TaggedObject *object, ObjectSlot slot, object, slot, value); } if (valueRegion->Test(value) && !(valueRegion->InYoungSpace() || valueRegion->InAppSpawnSpace() || - valueRegion->InReadOnlySpace())) { + valueRegion->InReadOnlySpace() || valueRegion->InSharedHeap())) { LogErrorForObjSlot(heap_, "Verify MarkYoung: Marked object, slot marked, but NOT in " "Young/AppSpawn/ReadOnly Space.", object, slot, value); } @@ -207,6 +223,12 @@ void VerifyObjectVisitor::VerifyEvacuateYoung(TaggedObject *object, ObjectSlot s } } } + if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) { + if (!objectRegion->TestLocalToShare(slot.SlotAddress())) { + LogErrorForObjSlot(heap_, "Verify EvacuateYoung: Local object, slot local_to_share bit = 0, " + "but SharedHeap object.", object, slot, value); + } + } if (objectRegion->InActiveSemiSpace()) { if (valueRegion->InInactiveSemiSpace()) { LogErrorForObjSlot(heap_, "Verify EvacuateYoung: ActiveSpace object, slot in InactiveSpace(FromSpace).", @@ -225,10 +247,16 @@ void VerifyObjectVisitor::VerifyMarkFull(TaggedObject *object, ObjectSlot slot, } } if (objectRegion->Test(object)) { - if (!valueRegion->Test(value)) { + if (!valueRegion->InSharedHeap() && !valueRegion->Test(value)) { LogErrorForObjSlot(heap_, "Verify MarkFull: Marked object, slot miss gc_mark bit.", object, slot, value); } } + if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) { + if (!objectRegion->TestLocalToShare(slot.SlotAddress())) { + LogErrorForObjSlot(heap_, "Verify VerifyMarkFull: Local object, slot local_to_share bit = 0, " + "but SharedHeap object.", object, slot, value); + } + } } void VerifyObjectVisitor::VerifyEvacuateOld([[maybe_unused]]TaggedObject *root, @@ -245,6 +273,35 @@ void VerifyObjectVisitor::VerifyEvacuateFull([[maybe_unused]]TaggedObject *root, VerifyEvacuateYoung(root, slot, value); } +void VerifyObjectVisitor::VerifySharedObjectReference(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const +{ + Region *objectRegion = Region::ObjectAddressToRange(object); + Region *valueRegion = Region::ObjectAddressToRange(value); + if (objectRegion->InSharedHeap()) { + if (!valueRegion->InSharedHeap()) { + LogErrorForObjSlot(heap_, "Verify SharedObjectReference: Shared object references a local object", + object, slot, value); + } + } else if (valueRegion->InSharedSweepableSpace()) { + if (!objectRegion->TestLocalToShare(slot.SlotAddress())) { + LogErrorForObjSlot(heap_, "Verify SharedObjectReference: Local object, slot local_to_share bit = 0, " + "but SharedHeap object.", object, slot, value); + } + } +} + +void VerifyObjectVisitor::VerifySharedRSetPostFullGC(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const +{ + Region *objectRegion = Region::ObjectAddressToRange(object); + Region *valueRegion = Region::ObjectAddressToRange(value); + if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) { + if (!objectRegion->TestLocalToShare(slot.SlotAddress())) { + LogErrorForObjSlot(heap_, "Verify SharedRSetPostFullGC: Local object, slot local_to_share bit = 0, " + "but SharedHeap object.", object, slot, value); + } + } +} + void VerifyObjectVisitor::operator()(TaggedObject *obj, JSTaggedValue value) { ObjectSlot slot(reinterpret_cast(obj)); @@ -281,10 +338,20 @@ size_t Verification::VerifyRoot() const { size_t failCount = 0; RootVisitor visitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot slot) { + JSTaggedValue value(slot.GetTaggedType()); + // Skip verifying shared object in local gc verification. + if (value.IsInSharedHeap()) { + return; + } VerifyObjectSlot(slot, &failCount); }; RootRangeVisitor rangeVisitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end) { for (ObjectSlot slot = start; slot < end; slot++) { + JSTaggedValue value(slot.GetTaggedType()); + // Skip verifying shared object in local gc verification. + if (value.IsInSharedHeap()) { + return; + } VerifyObjectSlot(slot, &failCount); } }; @@ -292,7 +359,7 @@ size_t Verification::VerifyRoot() const []([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base, [[maybe_unused]] ObjectSlot derived, [[maybe_unused]] uintptr_t baseOldObject) { }; - objXRay_.VisitVMRoots(visitor, rangeVisitor, derivedVisitor); + ObjectXRay::VisitVMRoots(heap_->GetEcmaVM(), visitor, rangeVisitor, derivedVisitor); if (failCount > 0) { LOG_GC(ERROR) << "VerifyRoot detects deadObject count is " << failCount; } @@ -327,4 +394,63 @@ void Verification::VerifyObjectSlot(const ObjectSlot &slot, size_t *failCount) c VerifyObjectVisitor(heap_, failCount, verifyKind_)(value.GetTaggedObject()); } } + +void SharedHeapVerification::VerifyAll() const +{ + [[maybe_unused]] VerifyScope verifyScope(sHeap_); + sHeap_->GetSweeper()->EnsureAllTaskFinished(); + size_t result = VerifyRoot(); + result += VerifyHeap(); + if (result > 0) { + LOG_GC(FATAL) << "Verify (type=" << static_cast(verifyKind_) + << ") corrupted and " << result << " corruptions"; + } +} + +size_t SharedHeapVerification::VerifyRoot() const +{ + size_t failCount = 0; + RootVisitor visitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot slot) { + VerifyObjectSlot(slot, &failCount); + }; + RootRangeVisitor rangeVisitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end) { + for (ObjectSlot slot = start; slot < end; slot++) { + VerifyObjectSlot(slot, &failCount); + } + }; + RootBaseAndDerivedVisitor derivedVisitor = + []([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base, [[maybe_unused]] ObjectSlot derived, + [[maybe_unused]] uintptr_t baseOldObject) { + }; + Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) { + ASSERT(!thread->IsInRunningState()); + auto vm = thread->GetEcmaVM(); + auto localHeap = const_cast(vm->GetHeap()); + localHeap->GetSweeper()->EnsureAllTaskFinished(); + ObjectXRay::VisitVMRoots(vm, visitor, rangeVisitor, derivedVisitor); + if (failCount > 0) { + LOG_GC(ERROR) << "SharedHeap VerifyRoot detects deadObject count is " << failCount; + } + }); + return failCount; +} + +size_t SharedHeapVerification::VerifyHeap() const +{ + size_t failCount = sHeap_->VerifyHeapObjects(verifyKind_); + if (failCount > 0) { + LOG_GC(ERROR) << "SharedHeap VerifyHeap detects deadObject count is " << failCount; + } + return failCount; +} + +void SharedHeapVerification::VerifyObjectSlot(const ObjectSlot &slot, size_t *failCount) const +{ + JSTaggedValue value(slot.GetTaggedType()); + if (value.IsWeak()) { + VerifyObjectVisitor(sHeap_, failCount, verifyKind_)(value.GetTaggedWeakRef()); + } else if (value.IsHeapObject()) { + VerifyObjectVisitor(sHeap_, failCount, verifyKind_)(value.GetTaggedObject()); + } +} } // namespace panda::ecmascript diff --git a/ecmascript/mem/verification.h b/ecmascript/mem/verification.h index 456e5a6f1d448a3bec604b869c3633874756bb60..205ef3c139afdf8989cb57a3d0962faed247842b 100644 --- a/ecmascript/mem/verification.h +++ b/ecmascript/mem/verification.h @@ -29,7 +29,7 @@ static constexpr uint32_t INVALID_THRESHOLD = 0x40000; class VerifyScope { public: - VerifyScope(Heap *heap) : heap_(heap) + VerifyScope(BaseHeap *heap) : heap_(heap) { heap_->SetVerifying(true); } @@ -39,7 +39,7 @@ public: heap_->SetVerifying(false); } private: - Heap *heap_ {nullptr}; + BaseHeap *heap_ {nullptr}; }; // Verify the object body @@ -47,11 +47,11 @@ private: class VerifyObjectVisitor { public: // Only used for verify InactiveSemiSpace - static void VerifyInactiveSemiSpaceMarkedObject(const Heap *heap, void *addr); + static void VerifyInactiveSemiSpaceMarkedObject(const BaseHeap *heap, void *addr); - VerifyObjectVisitor(const Heap *heap, size_t *failCount, + VerifyObjectVisitor(const BaseHeap *heap, size_t *failCount, VerifyKind verifyKind = VerifyKind::VERIFY_PRE_GC) - : heap_(heap), failCount_(failCount), objXRay_(heap->GetEcmaVM()), verifyKind_(verifyKind) + : heap_(heap), failCount_(failCount), verifyKind_(verifyKind) { } ~VerifyObjectVisitor() = default; @@ -76,17 +76,18 @@ private: void VerifyMarkFull(TaggedObject *obj, ObjectSlot slot, TaggedObject *value) const; void VerifyEvacuateOld(TaggedObject *obj, ObjectSlot slot, TaggedObject *value) const; void VerifyEvacuateFull(TaggedObject *obj, ObjectSlot slot, TaggedObject *value) const; + void VerifySharedRSetPostFullGC(TaggedObject *obj, ObjectSlot slot, TaggedObject *value) const; + void VerifySharedObjectReference(TaggedObject *obj, ObjectSlot slot, TaggedObject *value) const; - const Heap* const heap_ {nullptr}; + const BaseHeap* const heap_ {nullptr}; size_t* const failCount_ {nullptr}; - ObjectXRay objXRay_; VerifyKind verifyKind_; }; class Verification { public: explicit Verification(Heap *heap, VerifyKind verifyKind = VerifyKind::VERIFY_PRE_GC) - : heap_(heap), objXRay_(heap->GetEcmaVM()), verifyKind_(verifyKind) {} + : heap_(heap), verifyKind_(verifyKind) {} ~Verification() = default; void VerifyAll() const; @@ -101,7 +102,26 @@ private: NO_MOVE_SEMANTIC(Verification); Heap *heap_ {nullptr}; - ObjectXRay objXRay_; + VerifyKind verifyKind_; +}; + +class SharedHeapVerification { +public: + explicit SharedHeapVerification(SharedHeap *heap, VerifyKind verifyKind) + : sHeap_(heap), verifyKind_(verifyKind) {} + ~SharedHeapVerification() = default; + + void VerifyAll() const; + + size_t VerifyRoot() const; + size_t VerifyHeap() const; +private: + void VerifyObjectSlot(const ObjectSlot &slot, size_t *failCount) const; + + NO_COPY_SEMANTIC(SharedHeapVerification); + NO_MOVE_SEMANTIC(SharedHeapVerification); + + SharedHeap *sHeap_ {nullptr}; VerifyKind verifyKind_; }; } // namespace panda::ecmascript diff --git a/ecmascript/mem/work_manager.cpp b/ecmascript/mem/work_manager.cpp index c5dfa7f1a35ee01a79bfe9ea38f2e81131e2789f..c26888e5a9db67374ac81e50dcc3fd99406e1b44 100644 --- a/ecmascript/mem/work_manager.cpp +++ b/ecmascript/mem/work_manager.cpp @@ -25,17 +25,49 @@ #include "ecmascript/mem/parallel_marker-inl.h" #include "ecmascript/mem/partial_gc.h" #include "ecmascript/mem/region.h" +#include "ecmascript/mem/shared_heap/shared_gc_marker-inl.h" #include "ecmascript/mem/tlab_allocator-inl.h" namespace panda::ecmascript { +WorkManagerBase::WorkManagerBase(NativeAreaAllocator *allocator) + : spaceChunk_(allocator), workSpace_(0), spaceStart_(0), spaceEnd_(0) +{ + workSpace_ = ToUintPtr(GetSpaceChunk()->Allocate(WORKNODE_SPACE_SIZE)); +} + +WorkNode *WorkManagerBase::AllocateWorkNode() +{ + LockHolder lock(mtx_); + size_t allocatedSize = sizeof(WorkNode) + sizeof(Stack) + STACK_AREA_SIZE; + ASSERT(allocatedSize < WORKNODE_SPACE_SIZE); + + uintptr_t begin = spaceStart_; + if (begin + allocatedSize >= spaceEnd_) { + agedSpaces_.emplace_back(workSpace_); + workSpace_ = ToUintPtr(GetSpaceChunk()->Allocate(WORKNODE_SPACE_SIZE)); + spaceStart_ = workSpace_; + spaceEnd_ = workSpace_ + WORKNODE_SPACE_SIZE; + begin = spaceStart_; + } + spaceStart_ = begin + allocatedSize; + Stack *stack = reinterpret_cast(begin + sizeof(WorkNode)); + stack->ResetBegin(begin + sizeof(WorkNode) + sizeof(Stack), begin + allocatedSize); + WorkNode *work = reinterpret_cast(begin); + return new (work) WorkNode(stack); +} + +WorkManagerBase::~WorkManagerBase() +{ + GetSpaceChunk()->Free(reinterpret_cast(workSpace_)); +} + WorkManager::WorkManager(Heap *heap, uint32_t threadNum) - : heap_(heap), threadNum_(threadNum), spaceChunk_(heap_->GetNativeAreaAllocator()), continuousQueue_ { nullptr }, - workSpace_(0), spaceStart_(0), spaceEnd_(0), parallelGCTaskPhase_(UNDEFINED_TASK) + : WorkManagerBase(heap->GetNativeAreaAllocator()), heap_(heap), threadNum_(threadNum), + continuousQueue_ { nullptr }, parallelGCTaskPhase_(UNDEFINED_TASK) { for (uint32_t i = 0; i < threadNum_; i++) { - continuousQueue_.at(i) = new ProcessQueue(heap); + continuousQueue_.at(i) = new ProcessQueue(); } - workSpace_ = ToUintPtr(GetSpaceChunk()->Allocate(WORKNODE_SPACE_SIZE)); } WorkManager::~WorkManager() @@ -46,8 +78,6 @@ WorkManager::~WorkManager() delete continuousQueue_.at(i); continuousQueue_.at(i) = nullptr; } - - GetSpaceChunk()->Free(reinterpret_cast(workSpace_)); } bool WorkManager::Push(uint32_t threadId, TaggedObject *object) @@ -78,7 +108,7 @@ void WorkManager::PushWorkNodeToGlobal(uint32_t threadId, bool postTask) workStack_.Push(inNode); inNode = AllocateWorkNode(); if (postTask && heap_->IsParallelGCEnabled() && heap_->CheckCanDistributeTask() && - !(heap_->GetJSThread()->IsMarking() && heap_->GetIncrementalMarker()->IsTriggeredIncrementalMark())) { + !(heap_->IsMarking() && heap_->GetIncrementalMarker()->IsTriggeredIncrementalMark())) { heap_->PostParallelGCTask(parallelGCTaskPhase_); } } @@ -125,10 +155,7 @@ size_t WorkManager::Finish() aliveSize += holder.aliveSize_; } - while (!agedSpaces_.empty()) { - GetSpaceChunk()->Free(reinterpret_cast(agedSpaces_.back())); - agedSpaces_.pop_back(); - } + FinishBase(); initialized_.store(false, std::memory_order_release); return aliveSize; } @@ -146,14 +173,13 @@ void WorkManager::Finish(size_t &aliveSize, size_t &promotedSize) void WorkManager::Initialize(TriggerGCType gcType, ParallelGCTaskPhase taskPhase) { parallelGCTaskPhase_ = taskPhase; - spaceStart_ = workSpace_; - spaceEnd_ = workSpace_ + WORKNODE_SPACE_SIZE; + InitializeBase(); for (uint32_t i = 0; i < threadNum_; i++) { WorkNodeHolder &holder = works_.at(i); holder.inNode_ = AllocateWorkNode(); holder.outNode_ = AllocateWorkNode(); holder.weakQueue_ = new ProcessQueue(); - holder.weakQueue_->BeginMarking(heap_, continuousQueue_.at(i)); + holder.weakQueue_->BeginMarking(continuousQueue_.at(i)); holder.aliveSize_ = 0; holder.promotedSize_ = 0; if (gcType != TriggerGCType::OLD_GC) { @@ -167,24 +193,97 @@ void WorkManager::Initialize(TriggerGCType gcType, ParallelGCTaskPhase taskPhase initialized_.store(true, std::memory_order_release); } -WorkNode *WorkManager::AllocateWorkNode() +SharedGCWorkManager::SharedGCWorkManager(SharedHeap *heap, uint32_t threadNum) + : WorkManagerBase(heap->GetNativeAreaAllocator()), sHeap_(heap), threadNum_(threadNum), + continuousQueue_ { nullptr } { - LockHolder lock(mtx_); - size_t allocatedSize = sizeof(WorkNode) + sizeof(Stack) + STACK_AREA_SIZE; - ASSERT(allocatedSize < WORKNODE_SPACE_SIZE); + for (uint32_t i = 0; i < threadNum_; i++) { + continuousQueue_.at(i) = new ProcessQueue(); + } +} - uintptr_t begin = spaceStart_; - if (begin + allocatedSize >= spaceEnd_) { - agedSpaces_.emplace_back(workSpace_); - workSpace_ = ToUintPtr(GetSpaceChunk()->Allocate(WORKNODE_SPACE_SIZE)); - spaceStart_ = workSpace_; - spaceEnd_ = workSpace_ + WORKNODE_SPACE_SIZE; - begin = spaceStart_; +SharedGCWorkManager::~SharedGCWorkManager() +{ + Finish(); + for (uint32_t i = 0; i < threadNum_; i++) { + continuousQueue_.at(i)->Destroy(); + delete continuousQueue_.at(i); + continuousQueue_.at(i) = nullptr; } - spaceStart_ = begin + allocatedSize; - Stack *stack = reinterpret_cast(begin + sizeof(WorkNode)); - stack->ResetBegin(begin + sizeof(WorkNode) + sizeof(Stack), begin + allocatedSize); - WorkNode *work = reinterpret_cast(begin); - return new (work) WorkNode(stack); +} + +void SharedGCWorkManager::Initialize() +{ + InitializeBase(); + for (uint32_t i = 0; i < threadNum_; i++) { + SharedGCWorkNodeHolder &holder = works_.at(i); + holder.inNode_ = AllocateWorkNode(); + holder.outNode_ = AllocateWorkNode(); + holder.weakQueue_ = new ProcessQueue(); + holder.weakQueue_->BeginMarking(continuousQueue_.at(i)); + } + if (initialized_.load(std::memory_order_relaxed)) { + LOG_ECMA(FATAL) << "this branch is unreachable"; + UNREACHABLE(); + } + initialized_.store(true, std::memory_order_release); +} + +void SharedGCWorkManager::Finish() +{ + for (uint32_t i = 0; i < threadNum_; i++) { + SharedGCWorkNodeHolder &holder = works_.at(i); + if (holder.weakQueue_ != nullptr) { + holder.weakQueue_->FinishMarking(continuousQueue_.at(i)); + delete holder.weakQueue_; + holder.weakQueue_ = nullptr; + } + } + FinishBase(); + initialized_.store(false, std::memory_order_release); +} + +bool SharedGCWorkManager::Push(uint32_t threadId, TaggedObject *object) +{ + WorkNode *&inNode = works_.at(threadId).inNode_; + if (!inNode->PushObject(ToUintPtr(object))) { + PushWorkNodeToGlobal(threadId); + return inNode->PushObject(ToUintPtr(object)); + } + return true; +} + +void SharedGCWorkManager::PushWorkNodeToGlobal(uint32_t threadId, bool postTask) +{ + WorkNode *&inNode = works_.at(threadId).inNode_; + if (!inNode->IsEmpty()) { + workStack_.Push(inNode); + inNode = AllocateWorkNode(); + if (postTask && sHeap_->IsParallelGCEnabled() && sHeap_->CheckCanDistributeTask()) { + sHeap_->PostGCMarkingTask(); + } + } +} + +bool SharedGCWorkManager::Pop(uint32_t threadId, TaggedObject **object) +{ + WorkNode *&outNode = works_.at(threadId).outNode_; + WorkNode *&inNode = works_.at(threadId).inNode_; + if (!outNode->PopObject(reinterpret_cast(object))) { + if (!inNode->IsEmpty()) { + WorkNode *tmp = outNode; + outNode = inNode; + inNode = tmp; + } else if (!PopWorkNodeFromGlobal(threadId)) { + return false; + } + return outNode->PopObject(reinterpret_cast(object)); + } + return true; +} + +bool SharedGCWorkManager::PopWorkNodeFromGlobal(uint32_t threadId) +{ + return workStack_.Pop(&works_.at(threadId).outNode_); } } // namespace panda::ecmascript diff --git a/ecmascript/mem/work_manager.h b/ecmascript/mem/work_manager.h index 4d26468a41a992e7d37d10e9139d0a3477ef010a..45e84689e2cefab5dee68d4b2541271ae90b432e 100644 --- a/ecmascript/mem/work_manager.h +++ b/ecmascript/mem/work_manager.h @@ -28,6 +28,7 @@ static constexpr uint32_t MARKSTACK_MAX_SIZE = 100; static constexpr uint32_t STACK_AREA_SIZE = sizeof(uintptr_t) * MARKSTACK_MAX_SIZE; class Heap; +class SharedHeap; class Stack; class SemiSpaceCollector; class TlabAllocator; @@ -132,11 +133,49 @@ struct WorkNodeHolder { size_t promotedSize_ = 0; }; -class WorkManager final { +class WorkManagerBase { +public: + WorkManagerBase(NativeAreaAllocator *allocator); + virtual ~WorkManagerBase(); + + WorkSpaceChunk *GetSpaceChunk() const + { + return const_cast(&spaceChunk_); + } + + void InitializeBase() + { + spaceStart_ = workSpace_; + spaceEnd_ = workSpace_ + WORKNODE_SPACE_SIZE; + } + + void FinishBase() + { + while (!agedSpaces_.empty()) { + GetSpaceChunk()->Free(reinterpret_cast(agedSpaces_.back())); + agedSpaces_.pop_back(); + } + } + + WorkNode *AllocateWorkNode(); + + Mutex mtx_; +private: + NO_COPY_SEMANTIC(WorkManagerBase); + NO_MOVE_SEMANTIC(WorkManagerBase); + + WorkSpaceChunk spaceChunk_; + uintptr_t workSpace_; + uintptr_t spaceStart_; + uintptr_t spaceEnd_; + std::vector agedSpaces_; +}; + +class WorkManager : public WorkManagerBase { public: WorkManager() = delete; WorkManager(Heap *heap, uint32_t threadNum); - ~WorkManager(); + ~WorkManager() override; void Initialize(TriggerGCType gcType, ParallelGCTaskPhase taskPhase); size_t Finish(); @@ -194,35 +233,75 @@ public: { return threadNum_; } + inline bool HasInitialized() const { return initialized_.load(std::memory_order_acquire); } - WorkSpaceChunk *GetSpaceChunk() const - { - return const_cast(&spaceChunk_); - } - private: NO_COPY_SEMANTIC(WorkManager); NO_MOVE_SEMANTIC(WorkManager); - WorkNode *AllocateWorkNode(); - Heap *heap_; uint32_t threadNum_; - WorkSpaceChunk spaceChunk_; std::array works_; std::array *, MAX_TASKPOOL_THREAD_NUM + 1> continuousQueue_; GlobalWorkStack workStack_; - uintptr_t workSpace_; - uintptr_t spaceStart_; - uintptr_t spaceEnd_; - std::vector agedSpaces_; - Mutex mtx_; ParallelGCTaskPhase parallelGCTaskPhase_; std::atomic initialized_ {false}; }; + +struct SharedGCWorkNodeHolder { + WorkNode *inNode_ {nullptr}; + WorkNode *outNode_ {nullptr}; + ProcessQueue *weakQueue_ {nullptr}; +}; + +class SharedGCWorkManager : public WorkManagerBase { +public: + SharedGCWorkManager(SharedHeap *heap, uint32_t threadNum); + ~SharedGCWorkManager() override; + + void Initialize(); + void Finish(); + + bool Push(uint32_t threadId, TaggedObject *object); + bool Pop(uint32_t threadId, TaggedObject **object); + + bool PopWorkNodeFromGlobal(uint32_t threadId); + void PushWorkNodeToGlobal(uint32_t threadId, bool postTask = true); + + inline void PushWeakReference(uint32_t threadId, JSTaggedType *weak) + { + works_.at(threadId).weakQueue_->PushBack(weak); + } + + inline ProcessQueue *GetWeakReferenceQueue(uint32_t threadId) const + { + return works_.at(threadId).weakQueue_; + } + + inline uint32_t GetTotalThreadNum() + { + return threadNum_; + } + + inline bool HasInitialized() const + { + return initialized_.load(std::memory_order_acquire); + } + +private: + NO_COPY_SEMANTIC(SharedGCWorkManager); + NO_MOVE_SEMANTIC(SharedGCWorkManager); + + SharedHeap *sHeap_; + uint32_t threadNum_; + std::array works_; + std::array *, MAX_TASKPOOL_THREAD_NUM + 1> continuousQueue_; + GlobalWorkStack workStack_; + std::atomic initialized_ {false}; +}; } // namespace panda::ecmascript #endif // ECMASCRIPT_MEM_WORK_MANAGER_H diff --git a/ecmascript/method.cpp b/ecmascript/method.cpp index eb074bd03a9a072fe0de185fa8bad5b4e4449aea..50bb762559af71b37f24bd761daf11bf5bdd1e44 100644 --- a/ecmascript/method.cpp +++ b/ecmascript/method.cpp @@ -98,41 +98,13 @@ JSHandle Method::Create(JSThread *thread, const JSPandaFile *jsPandaFile return JSHandle(thread, patchVal); } - JSHandle method = vm->GetFactory()->NewMethod(methodLiteral); + JSHandle method; + method = vm->GetFactory()->NewSMethod(methodLiteral); JSHandle newConstpool = thread->GetCurrentEcmaContext()->FindOrCreateConstPool(jsPandaFile, methodId); method->SetConstantPool(thread, newConstpool); return method; } -const JSTaggedValue Method::GetRecordName() const -{ - JSTaggedValue module = GetModule(); - if (module.IsSourceTextModule()) { - JSTaggedValue recordName = SourceTextModule::Cast(module.GetTaggedObject())->GetEcmaModuleRecordName(); - if (!recordName.IsString()) { - LOG_INTERPRETER(DEBUG) << "module record name is undefined"; - return JSTaggedValue::Hole(); - } - return recordName; - } - if (module.IsString()) { - return module; - } - LOG_INTERPRETER(DEBUG) << "record name is undefined"; - return JSTaggedValue::Hole(); -} - -void Method::SetCompiledFuncEntry(uintptr_t codeEntry, bool isFastCall) -{ - ASSERT(codeEntry != 0); - SetCodeEntryAndMarkAOTWhenBinding(codeEntry); - - SetIsFastCall(isFastCall); - MethodLiteral *methodLiteral = GetMethodLiteral(); - methodLiteral->SetAotCodeBit(true); - methodLiteral->SetIsFastCall(isFastCall); -} - void Method::SetCodeEntryAndMarkAOTWhenBinding(uintptr_t codeEntry) { SetAotCodeBit(true); diff --git a/ecmascript/method.h b/ecmascript/method.h index a11b185b6c8e90e632819e815cb0819b3cba31bb..e64d8a77dd996bbefa52c857ccec7baff92af596 100644 --- a/ecmascript/method.h +++ b/ecmascript/method.h @@ -78,11 +78,6 @@ public: return IsNativeBit::Decode(callField); } - bool IsAotWithCallField(uint64_t callField) const - { - return IsAotCodeBit::Decode(callField); - } - bool OnlyHaveThisWithCallField(uint64_t callField) const { return (callField & CALL_TYPE_MASK) == 1; // 1: the first bit of callFiled is HaveThisBit @@ -410,8 +405,6 @@ public: uint32_t FindCatchBlock(uint32_t pc) const; - const JSTaggedValue GetRecordName() const; - /* callfield */ static constexpr size_t VREGS_ARGS_NUM_BITS = 28; // 28: maximum 268,435,455 static constexpr uint64_t AOT_FASTCALL_BITS = 0x5; // 0x5LU: aot and fastcall bit field @@ -438,15 +431,12 @@ public: using IsCallNapiBit = DeoptTypeBits::NextFlag; // offset 28 static constexpr size_t CONSTANT_POOL_OFFSET = TaggedObjectSize(); - ACCESSORS(ConstantPool, CONSTANT_POOL_OFFSET, PROFILE_TYPE_INFO_OFFSET) - ACCESSORS(ProfileTypeInfo, PROFILE_TYPE_INFO_OFFSET, MACHINECODE_OFFSET) - ACCESSORS(MachineCode, MACHINECODE_OFFSET, ECMA_MODULE_OFFSET) - ACCESSORS(Module, ECMA_MODULE_OFFSET, CALL_FIELD_OFFSET) + ACCESSORS(ConstantPool, CONSTANT_POOL_OFFSET, CALL_FIELD_OFFSET) ACCESSORS_PRIMITIVE_FIELD(CallField, uint64_t, CALL_FIELD_OFFSET, NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET) // Native method decides this filed is NativePointer or BytecodeArray pointer. ACCESSORS_NATIVE_FIELD( - NativePointerOrBytecodeArray, void, NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET, CODE_ENTRY_OFFSET) - ACCESSORS_PRIMITIVE_FIELD(CodeEntryOrLiteral, uintptr_t, CODE_ENTRY_OFFSET, LITERAL_INFO_OFFSET) + NativePointerOrBytecodeArray, void, NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET, CODEENTRY_LITERAL_OFFSET) + ACCESSORS_PRIMITIVE_FIELD(CodeEntryOrLiteral, uintptr_t, CODEENTRY_LITERAL_OFFSET, LITERAL_INFO_OFFSET) // hotness counter is encoded in a js method field, the first uint16_t in a uint64_t. ACCESSORS_PRIMITIVE_FIELD(LiteralInfo, uint64_t, LITERAL_INFO_OFFSET, EXTRA_LITERAL_INFO_OFFSET) ACCESSORS_PRIMITIVE_FIELD(ExtraLiteralInfo, uint64_t, EXTRA_LITERAL_INFO_OFFSET, LAST_OFFSET) diff --git a/ecmascript/module/js_module_manager.cpp b/ecmascript/module/js_module_manager.cpp index b7820bfa67068c9f0a349835ab443605a31905ce..8c75f2a14a547b5873642af4c40cab6381f6e543 100644 --- a/ecmascript/module/js_module_manager.cpp +++ b/ecmascript/module/js_module_manager.cpp @@ -26,6 +26,7 @@ #include "ecmascript/linked_hash_table.h" #include "ecmascript/module/js_module_deregister.h" #include "ecmascript/module/js_module_source_text.h" +#include "ecmascript/module/js_shared_module.h" #include "ecmascript/module/module_data_extractor.h" #include "ecmascript/module/module_path_helper.h" #include "ecmascript/require/js_cjs_module.h" @@ -47,8 +48,39 @@ ModuleManager::ModuleManager(EcmaVM *vm) : vm_(vm) JSTaggedValue ModuleManager::GetCurrentModule() { FrameHandler frameHandler(vm_->GetJSThread()); - Method *currentMethod = frameHandler.GetMethod(); - return currentMethod->GetModule(); + JSTaggedValue currentFunc = frameHandler.GetFunction(); + JSTaggedValue module = JSFunction::Cast(currentFunc.GetTaggedObject())->GetModule(); + if (SourceTextModule::IsSendableFunctionModule(module)) { + JSTaggedValue recordName = SourceTextModule::GetModuleName(module); + return HostGetImportedModule(recordName).GetTaggedValue(); + } + return module; +} + +JSHandle ModuleManager::GenerateFuncModule(const JSPandaFile *jsPandaFile, + const CString &entryPoint, ClassKind classKind) +{ + CString recordName = jsPandaFile->GetRecordName(entryPoint); + JSRecordInfo recordInfo; + jsPandaFile->CheckAndGetRecordInfo(recordName, recordInfo); + if (jsPandaFile->IsModule(recordInfo)) { + JSHandle module(HostGetImportedModule(recordName)); + if (classKind == ClassKind::NON_SENDABLE) { + return module; + } else { + // [[todo::DaiHN]] Sendable class defined in Shared Module would set Shared Module directly. + // Clone isolate module at shared-heap to mark sendable class. + return SendableClassModule::GenerateSendableFuncModule(vm_->GetJSThread(), module); + } + } + return JSHandle(vm_->GetFactory()->NewFromUtf8(recordName)); +} + +JSHandle ModuleManager::GenerateSendableFuncModule(const JSHandle &module) +{ + // [[todo::DaiHN]] Sendable class defined in Shared Module would set Shared Module directly. + // Clone isolate module at shared-heap to mark sendable class. + return SendableClassModule::GenerateSendableFuncModule(vm_->GetJSThread(), module); } JSTaggedValue ModuleManager::GetModuleValueInner(int32_t index) diff --git a/ecmascript/module/js_module_manager.h b/ecmascript/module/js_module_manager.h index 11bed30d833791dedd11d58d19192b9a77522142..7c30f0440433fc58996e102768c3fda4a64d51ac 100644 --- a/ecmascript/module/js_module_manager.h +++ b/ecmascript/module/js_module_manager.h @@ -72,6 +72,9 @@ public: JSThread *thread, std::string &recordNameStr, std::string &baseFileName); JSTaggedValue GetCurrentModule(); + JSHandle GenerateFuncModule(const JSPandaFile *jsPandaFile, const CString &entryPoint, + ClassKind classKind = ClassKind::NON_SENDABLE); + JSHandle GenerateSendableFuncModule(const JSHandle &module); JSTaggedValue GetNativeModuleValue(JSThread *thread, JSTaggedValue currentModule, JSTaggedValue resolvedModule, ResolvedIndexBinding *binding); JSTaggedValue GetNativeModuleValue(JSThread *thread, JSTaggedValue currentModule, diff --git a/ecmascript/module/js_module_source_text.h b/ecmascript/module/js_module_source_text.h index fae96b799c195effde5ffe42b86cccd987814811..1a03d67b63e6252581da96ccd5f1f8ca3e9d8030 100644 --- a/ecmascript/module/js_module_source_text.h +++ b/ecmascript/module/js_module_source_text.h @@ -49,6 +49,13 @@ enum class LoadingTypes : uint8_t { OTHERS }; +enum class SharedTypes : uint8_t { + UNSENDABLE_MODULE = 0x01, + SENDABLE_FUNCTION_MODULE, + SHARED_MODULE, + TOTAL_KINDS, +}; + class SourceTextModule final : public ModuleRecord { public: static constexpr int UNDEFINED_INDEX = -1; @@ -152,6 +159,17 @@ public: moduleType == ModuleTypes::INTERNAL_MODULE; } + inline static bool IsModuleInSharedHeap(JSHandle currentModule) + { + return currentModule->GetSharedType() > SharedTypes::UNSENDABLE_MODULE; + } + + inline static bool IsSendableFunctionModule(JSTaggedValue currentModule) + { + return SourceTextModule::Cast(currentModule.GetTaggedObject())->GetSharedType() == + SharedTypes::SENDABLE_FUNCTION_MODULE; + } + 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); @@ -182,6 +200,7 @@ public: static constexpr size_t HASTLA_BITS = 1; static constexpr size_t LOADING_TYPE_BITS = 3; static constexpr uint16_t REGISTER_COUNTS = 16; + static constexpr size_t IS_SHARED_TYPE_BITS = 2; FIRST_BIT_FIELD(BitField, Status, ModuleStatus, STATUS_BITS) NEXT_BIT_FIELD(BitField, Types, ModuleTypes, MODULE_TYPE_BITS, Status) @@ -189,6 +208,9 @@ public: NEXT_BIT_FIELD(BitField, HasTLA, bool, HASTLA_BITS, IsNewBcVersion) NEXT_BIT_FIELD(BitField, LoadingTypes, LoadingTypes, LOADING_TYPE_BITS, HasTLA) NEXT_BIT_FIELD(BitField, RegisterCounts, uint16_t, REGISTER_COUNTS, LoadingTypes) + NEXT_BIT_FIELD(BitField, SharedType, SharedTypes, IS_SHARED_TYPE_BITS, RegisterCounts) + + static_assert(static_cast(SharedTypes::TOTAL_KINDS) <= (1 << IS_SHARED_TYPE_BITS)); DECL_DUMP() DECL_VISIT_OBJECT(SOURCE_TEXT_MODULE_OFFSET, EVALUATION_ERROR_OFFSET) diff --git a/ecmascript/module/js_shared_module.cpp b/ecmascript/module/js_shared_module.cpp new file mode 100644 index 0000000000000000000000000000000000000000..67cd93df29f8a0ed783f90a0108766248e81c5b8 --- /dev/null +++ b/ecmascript/module/js_shared_module.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024 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_shared_module.h" +#include "ecmascript/tagged_array-inl.h" +namespace panda::ecmascript { +JSHandle SendableClassModule::GenerateSendableFuncModule(JSThread *thread, + const JSHandle &module) +{ + // esm -> SourceTextModule; cjs or script -> string of recordName + if (!module->IsSourceTextModule()) { + ASSERT(module->IsString()); + return module; + } + JSHandle currentModule = JSHandle::Cast(module); + // Only clone module in isolate-heap. + if (SourceTextModule::IsModuleInSharedHeap(currentModule)) { + return module; + } + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle sModule = factory->NewSModule(); + JSHandle currentEnvironment(thread, currentModule->GetEnvironment()); + JSHandle sendableEnvironment = SendableClassModule::CloneModuleEnvironment(thread, + currentEnvironment); + sModule->SetSharedType(SharedTypes::SENDABLE_FUNCTION_MODULE); + sModule->SetEnvironment(thread, sendableEnvironment); + sModule->SetEcmaModuleFilename(thread, currentModule->GetEcmaModuleFilename()); + sModule->SetEcmaModuleRecordName(thread, currentModule->GetEcmaModuleRecordName()); + return JSHandle(sModule); +} + +JSHandle SendableClassModule::CloneRecordBinding(JSThread *thread, JSTaggedValue indexBinding) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(indexBinding.GetTaggedObject()); + JSTaggedValue resolvedModule = binding->GetModule(); + JSHandle record(thread, SourceTextModule::GetModuleName(resolvedModule)); + int32_t index = binding->GetIndex(); + return JSHandle::Cast(factory->NewSResolvedRecordBindingRecord(record, index)); +} + +JSHandle SendableClassModule::CloneModuleEnvironment(JSThread *thread, + const JSHandle &moduleEnvironment) +{ + if (moduleEnvironment->IsUndefined()) { + return moduleEnvironment; + } + JSHandle currentEnvironment(moduleEnvironment); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + int enumKeys = currentEnvironment->GetLength(); + JSHandle sendableEnvironment = factory->NewSDictionaryArray(enumKeys); + for (int idx = 0; idx < enumKeys; idx++) { + JSTaggedValue key = currentEnvironment->Get(idx); + // [[todo::DaiHN will consider ResolvedBinding]] + if (key.IsResolvedIndexBinding()) { + JSHandle recordBinding = SendableClassModule::CloneRecordBinding(thread, key); + sendableEnvironment->Set(thread, idx, recordBinding); + } + continue; + } + return JSHandle(sendableEnvironment); +} +} // namespace panda::ecmascript diff --git a/ecmascript/module/js_shared_module.h b/ecmascript/module/js_shared_module.h new file mode 100644 index 0000000000000000000000000000000000000000..b0e31ef613cfafda34f6123cf023c610e2cc0a7a --- /dev/null +++ b/ecmascript/module/js_shared_module.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 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_SHARED_MODULE_H +#define ECMASCRIPT_MODULE_JS_SHARED_MODULE_H + +#include "ecmascript/module/js_module_source_text.h" + +namespace panda::ecmascript { +class SendableClassModule { +public: + static JSHandle GenerateSendableFuncModule(JSThread *thread, const JSHandle &module); + +private: + static JSHandle CloneRecordBinding(JSThread *thread, JSTaggedValue indexBinding); + static JSHandle CloneModuleEnvironment(JSThread *thread, + const JSHandle &moduleEnvironment); +}; + +class ResolvedRecordBinding final : public Record { +public: + CAST_CHECK(ResolvedRecordBinding, IsResolvedRecordBinding); + + static constexpr size_t MODULE_RECORD_OFFSET = Record::SIZE; + ACCESSORS(ModuleRecord, MODULE_RECORD_OFFSET, INDEX_OFFSET); + ACCESSORS_PRIMITIVE_FIELD(Index, int32_t, INDEX_OFFSET, END_OFFSET); + DEFINE_ALIGN_SIZE(END_OFFSET); + + DECL_DUMP() + DECL_VISIT_OBJECT(MODULE_RECORD_OFFSET, INDEX_OFFSET) +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_MODULE_JS_SHARED_MODULE_H diff --git a/ecmascript/module/js_shared_module_manager.cpp b/ecmascript/module/js_shared_module_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9f2e7c4550da7e143142f72a11dd0c6012a20432 --- /dev/null +++ b/ecmascript/module/js_shared_module_manager.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2024 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_shared_module_manager.h" + +#include "ecmascript/compiler/aot_file/aot_file_manager.h" +#include "ecmascript/global_env.h" +#include "ecmascript/interpreter/fast_runtime_stub-inl.h" +#include "ecmascript/interpreter/slow_runtime_stub.h" +#include "ecmascript/interpreter/frame_handler.h" +#include "ecmascript/js_array.h" +#include "ecmascript/jspandafile/js_pandafile.h" +#include "ecmascript/jspandafile/js_pandafile_executor.h" +#include "ecmascript/jspandafile/js_pandafile_manager.h" +#include "ecmascript/linked_hash_table.h" +#include "ecmascript/module/js_module_deregister.h" +#include "ecmascript/module/js_module_source_text.h" +#include "ecmascript/module/module_data_extractor.h" +#include "ecmascript/module/module_path_helper.h" +#include "ecmascript/require/js_cjs_module.h" +#include "ecmascript/tagged_dictionary.h" +#ifdef PANDA_TARGET_WINDOWS +#include +#endif + +namespace panda::ecmascript { +using StringHelper = base::StringHelper; +using JSPandaFile = ecmascript::JSPandaFile; +using JSRecordInfo = ecmascript::JSPandaFile::JSRecordInfo; + +SharedModuleManager* SharedModuleManager::GetInstance() +{ + static SharedModuleManager* instance = new SharedModuleManager(); + return instance; +} + +JSHandle SharedModuleManager::GetImportedSModule(JSThread *thread, JSTaggedValue referencing) +{ + NameDictionary *dict = NameDictionary::Cast(resolvedSharedModules_.GetTaggedObject()); + int entry = dict->FindEntry(referencing); + LOG_ECMA_IF(entry == -1, FATAL) << "Can not get module: " + << ConvertToString(referencing); + JSTaggedValue result = dict->GetValue(entry); + return JSHandle(thread, result); +} + +JSTaggedValue SharedModuleManager::GetSendableModuleValue(JSThread *thread, int32_t index, JSTaggedValue jsFunc) const +{ + JSTaggedValue currentModule = JSFunction::Cast(jsFunc.GetTaggedObject())->GetModule(); + return GetSendableModuleValueImpl(thread, index, currentModule); +} + +JSTaggedValue SharedModuleManager::GetSendableModuleValueImpl( + JSThread *thread, int32_t index, JSTaggedValue currentModule) const +{ + if (currentModule.IsUndefined()) { + LOG_FULL(FATAL) << "GetModuleValueOutter currentModule failed"; + UNREACHABLE(); + } + + SourceTextModule *module = SourceTextModule::Cast(currentModule.GetTaggedObject()); + JSTaggedValue moduleEnvironment = module->GetEnvironment(); + if (moduleEnvironment.IsUndefined()) { + return thread->GlobalConstants()->GetUndefined(); + } + ASSERT(moduleEnvironment.IsTaggedArray()); + JSTaggedValue resolvedBinding = TaggedArray::Cast(moduleEnvironment.GetTaggedObject())->Get(index); + if (resolvedBinding.IsResolvedRecordBinding()) { + ResolvedRecordBinding *binding = ResolvedRecordBinding::Cast(resolvedBinding.GetTaggedObject()); + JSTaggedValue moduleRecord = binding->GetModuleRecord(); + ASSERT(moduleRecord.IsString()); + // moduleRecord is string, find at current vm + ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); + JSHandle resolvedModule; + if (moduleManager->IsImportedModuleLoaded(moduleRecord)) { + resolvedModule = moduleManager->HostGetImportedModule(moduleRecord); + } else { + auto isMergedAbc = !module->GetEcmaModuleRecordName().IsUndefined(); + CString record = ConvertToString(moduleRecord); + CString fileName = ConvertToString(module->GetEcmaModuleFilename()); + if (JSPandaFileExecutor::LazyExecuteModule(thread, record, fileName, isMergedAbc)) { + resolvedModule = moduleManager->HostGetImportedModule(moduleRecord); + } + LOG_ECMA(FATAL) << "LazyExecuteModule failed"; + } + // [[todo::DaiHN will consider HotReload]] + // [[todo::DaiHN should consider json, cjs and native module later]] + ASSERT(resolvedModule->GetTypes() == ModuleTypes::ECMA_MODULE); + return resolvedModule->GetModuleValue(thread, binding->GetIndex(), false); + } else if (resolvedBinding.IsResolvedIndexBinding()) { + ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolvedBinding.GetTaggedObject()); + SourceTextModule *resolvedModule = SourceTextModule::Cast(binding->GetModule().GetTaggedObject()); + return resolvedModule->GetModuleValue(thread, binding->GetIndex(), false); + } + UNREACHABLE(); +} +} // namespace panda::ecmascript diff --git a/ecmascript/module/js_shared_module_manager.h b/ecmascript/module/js_shared_module_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..ab4d169a1c204aa3334250c40ab7e540347233b0 --- /dev/null +++ b/ecmascript/module/js_shared_module_manager.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 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_SHARED_MODULE_MANAGER_H +#define ECMASCRIPT_MODULE_JS_SHARED_MODULE_MANAGER_H + +#include "ecmascript/js_tagged_value-inl.h" +#include "ecmascript/jspandafile/js_pandafile.h" +#include "ecmascript/module/js_module_manager.h" +#include "ecmascript/module/js_module_source_text.h" +#include "ecmascript/napi/jsnapi_helper.h" +#include "ecmascript/tagged_dictionary.h" + +namespace panda::ecmascript { +class SharedModuleManager { +public: + static SharedModuleManager *GetInstance(); + + void Initialize(const EcmaVM *vm) + { + resolvedSharedModules_ = NameDictionary::CreateInSharedHeap(vm->GetJSThread(), + DEAULT_DICTIONART_CAPACITY).GetTaggedValue(); + } + JSTaggedValue GetSendableModuleValue(JSThread *thread, int32_t index, JSTaggedValue jsFunc) const; + JSTaggedValue GetSendableModuleValueImpl(JSThread *thread, int32_t index, JSTaggedValue currentModule) const; + +private: + SharedModuleManager() = default; + ~SharedModuleManager() = default; + + NO_COPY_SEMANTIC(SharedModuleManager); + NO_MOVE_SEMANTIC(SharedModuleManager); + JSHandle GetImportedSModule(JSThread *thread, JSTaggedValue referencing); + + static constexpr uint32_t DEAULT_DICTIONART_CAPACITY = 4; + + JSTaggedValue resolvedSharedModules_ {JSTaggedValue::Hole()}; + + friend class EcmaVM; + friend class PatchLoader; +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_MODULE_JS_SHARED_MODULE_MANAGER_H diff --git a/ecmascript/module/tests/ecma_module_test.cpp b/ecmascript/module/tests/ecma_module_test.cpp index 021a8c6119ec41f56ead26faf1c5eaa6979f1408..e0972dd89477d5b1b68ffe92ddbbbbfb70fff401 100644 --- a/ecmascript/module/tests/ecma_module_test.cpp +++ b/ecmascript/module/tests/ecma_module_test.cpp @@ -28,6 +28,7 @@ #include "ecmascript/module/module_path_helper.h" #include "ecmascript/tests/test_helper.h" #include "ecmascript/linked_hash_table.h" +#include "ecmascript/checkpoint/thread_state_transition.h" using namespace panda::ecmascript; @@ -222,6 +223,7 @@ HWTEST_F_L0(EcmaModuleTest, GetRecordName2) HWTEST_F_L0(EcmaModuleTest, GetExportObjectIndex) { + ThreadNativeScope nativeScope(thread); std::string baseFileName = MODULE_ABC_PATH "module_test_module_test_C.abc"; JSNApi::EnableUserUncaughtErrorHandler(instance); diff --git a/ecmascript/mutator_lock.cpp b/ecmascript/mutator_lock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e45ba317746fb3533d9bbf1d6e10473fdd9ff137 --- /dev/null +++ b/ecmascript/mutator_lock.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024 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/platform/mutex.h" +#include "ecmascript/mutator_lock.h" +#include "ecmascript/js_thread.h" +#include "js_thread.h" + +namespace panda::ecmascript { +#ifndef NDEBUG +void MutatorLock::ReadLock() +{ + ASSERT(!HasLock()); + RWLock::ReadLock(); + SetState(MutatorLockState::RDLOCK); +} + +void MutatorLock::WriteLock() +{ + ASSERT(!HasLock()); + RWLock::WriteLock(); + SetState(MutatorLockState::WRLOCK); +} + +bool MutatorLock::TryReadLock() +{ + ASSERT(!HasLock()); + bool res = RWLock::TryReadLock(); + if (res) { + SetState(MutatorLockState::RDLOCK); + } + return res; +} + +bool MutatorLock::TryWriteLock() +{ + ASSERT(!HasLock()); + bool res = RWLock::TryWriteLock(); + if (res) { + SetState(MutatorLockState::WRLOCK); + } + return res; +} + +void MutatorLock::Unlock() +{ + ASSERT(HasLock()); + RWLock::Unlock(); + SetState(MutatorLockState::UNLOCKED); +} + +bool MutatorLock::HasLock() const +{ + return GetState() != MutatorLockState::UNLOCKED; +} + +MutatorLock::MutatorLockState MutatorLock::GetState() const +{ + return JSThread::GetCurrent()->GetMutatorLockState(); +} + +void MutatorLock::SetState(MutatorLock::MutatorLockState newState) +{ + JSThread::GetCurrent()->SetMutatorLockState(newState); +} +#endif +} // namespace panda::ecmascript \ No newline at end of file diff --git a/ecmascript/mutator_lock.h b/ecmascript/mutator_lock.h new file mode 100644 index 0000000000000000000000000000000000000000..49bc6ba54b70df8546aa851eedc2b39a22447e46 --- /dev/null +++ b/ecmascript/mutator_lock.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 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_MUTATOR_LOCK_H +#define ECMASCRIPT_MUTATOR_LOCK_H + +#include "ecmascript/platform/mutex.h" + +namespace panda::ecmascript { +class MutatorLock : public RWLock { +#ifndef NDEBUG +public: + enum MutatorLockState { UNLOCKED, RDLOCK, WRLOCK }; + void ReadLock(); + void WriteLock(); + bool TryReadLock(); + bool TryWriteLock(); + void Unlock(); + bool HasLock() const; + +private: + MutatorLockState GetState() const; + void SetState(MutatorLockState newState); +#endif +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_MUTATOR_LOCK_H \ No newline at end of file diff --git a/ecmascript/napi/dfx_jsnapi.cpp b/ecmascript/napi/dfx_jsnapi.cpp index 87f5be35a443822068f669eeb225a459ff2acfa6..12f336bef6fc16478db6b02736c91173a705f0a6 100644 --- a/ecmascript/napi/dfx_jsnapi.cpp +++ b/ecmascript/napi/dfx_jsnapi.cpp @@ -17,6 +17,7 @@ #include "ecmascript/base/block_hook_scope.h" #include "ecmascript/builtins/builtins_ark_tools.h" +#include "ecmascript/checkpoint/thread_state_transition.h" #include "ecmascript/dfx/hprof/heap_profiler.h" #include "ecmascript/dfx/stackinfo/js_stackinfo.h" #include "ecmascript/dfx/tracing/tracing.h" @@ -405,11 +406,12 @@ void DFXJSNApi::SetOverLimit(EcmaVM *vm, bool state) void DFXJSNApi::GetHeapPrepare(const EcmaVM *vm) { - const_cast(vm->GetHeap())->Prepare(); + const_cast(vm->GetHeap())->GetHeapPrepare(); } void DFXJSNApi::NotifyApplicationState(EcmaVM *vm, bool inBackground) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); const_cast(vm->GetHeap())->ChangeGCParams(inBackground); } @@ -420,6 +422,7 @@ void DFXJSNApi::NotifyIdleStatusControl(const EcmaVM *vm, std::functionGetJSThread()); const_cast(vm->GetHeap())->TriggerIdleCollection(idleMicroSec); } @@ -430,6 +433,7 @@ void DFXJSNApi::NotifyMemoryPressure(EcmaVM *vm, bool inHighMemoryPressure) void DFXJSNApi::NotifyFinishColdStart(EcmaVM *vm, bool isConvinced) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); if (isConvinced) { const_cast(vm->GetHeap())->NotifyFinishColdStart(); } else { diff --git a/ecmascript/napi/include/jsnapi_expo.h b/ecmascript/napi/include/jsnapi_expo.h index 97604348eda2eb84f7ac1194eb717b47e70fe57a..62d7042a9a2f04adf85d96139f34460c799b7114 100644 --- a/ecmascript/napi/include/jsnapi_expo.h +++ b/ecmascript/napi/include/jsnapi_expo.h @@ -501,7 +501,7 @@ private: template friend class Local; }; - + // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions, hicpp-special-member-functions) class ECMA_PUBLIC_API PropertyAttribute { public: @@ -640,6 +640,9 @@ public: static Local NewWithNamedProperties(const EcmaVM *vm, size_t propertyCount, const char **keys, const Local *values); static Local CreateAccessorData(const EcmaVM *vm, Local getter, Local setter); + static Local CreateSendableAccessorData(const EcmaVM *vm, + Local getter, + Local setter); bool ConvertToNativeBindingObject(const EcmaVM *vm, Local value); bool Set(const EcmaVM *vm, Local key, Local value); bool Set(const EcmaVM *vm, uint32_t key, Local value); @@ -680,14 +683,39 @@ using FunctionCallback = Local(*)(JsiRuntimeCallInfo*); using InternalFunctionCallback = JSValueRef(*)(JsiRuntimeCallInfo*); class ECMA_PUBLIC_API FunctionRef : public ObjectRef { public: + struct SendablePropertiesInfo { + Local keys; + Local values; + PropertyAttribute *attributes; + }; + struct SendablePropertiesInfos { + SendablePropertiesInfo instancePropertiesInfo; + SendablePropertiesInfo staticPropertiesInfo; + SendablePropertiesInfo nonStaticPropertiesInfo; + }; static Local New(EcmaVM *vm, FunctionCallback nativeFunc, Deleter deleter = nullptr, void *data = nullptr, bool callNapi = false, size_t nativeBindingsize = 0); static Local New(EcmaVM *vm, InternalFunctionCallback nativeFunc, Deleter deleter, void *data = nullptr, bool callNapi = false, size_t nativeBindingsize = 0); + static Local NewSendable(EcmaVM *vm, + InternalFunctionCallback nativeFunc, + Deleter deleter, + void *data = nullptr, + bool callNapi = false, + size_t nativeBindingsize = 0); static Local NewClassFunction(EcmaVM *vm, FunctionCallback nativeFunc, Deleter deleter, void *data, bool callNapi = false, size_t nativeBindingsize = 0); static Local NewClassFunction(EcmaVM *vm, InternalFunctionCallback nativeFunc, Deleter deleter, void *data, bool callNapi = false, size_t nativeBindingsize = 0); + static Local NewSendableClassFunction(const EcmaVM *vm, + InternalFunctionCallback nativeFunc, + Deleter deleter, + void *data, + Local name, + SendablePropertiesInfos infos, + Local parent, + bool callNapi = false, + size_t nativeBindingsize = 0); JSValueRef* CallForNapi(const EcmaVM *vm, JSValueRef *thisObj, JSValueRef *const argv[], int32_t length); Local Call(const EcmaVM *vm, Local thisObj, const Local argv[], @@ -1087,7 +1115,7 @@ public: Local Then(const EcmaVM *vm, Local handler); Local Finally(const EcmaVM *vm, Local handler); Local Then(const EcmaVM *vm, Local onFulfilled, Local onRejected); - + Local GetPromiseState(const EcmaVM *vm); Local GetPromiseResult(const EcmaVM *vm); }; @@ -1266,12 +1294,6 @@ public: static void SetSourceMapTranslateCallback(EcmaVM *vm, SourceMapTranslateCallback cb); static void SetNativeStackCallback(EcmaVM *vm, NativeStackCallback cb); static void SetHostEnqueueJob(const EcmaVM* vm, Local cb); - static void InitializeIcuData(const ecmascript::JSRuntimeOptions &options); - static void InitializeMemMapAllocator(); - static void InitializePGOProfiler(const ecmascript::JSRuntimeOptions &options); - static void DestroyAnDataManager(); - static void DestroyMemMapAllocator(); - static void DestroyPGOProfiler(); static EcmaVM* CreateEcmaVM(const ecmascript::JSRuntimeOptions &options); static void PreFork(EcmaVM *vm); static void PostFork(EcmaVM *vm, const RuntimeOption &option); @@ -1279,7 +1301,6 @@ public: static bool DeleteWorker(EcmaVM *hostVm, EcmaVM *workerVm); static void GetStackBeforeCallNapiSuccess(EcmaVM *vm, bool &getStackBeforeCallNapiSuccess); static void GetStackAfterCallNapi(EcmaVM *vm); - static PatchErrorCode LoadPatch(EcmaVM *vm, const std::string &patchFileName, const std::string &baseFileName); static PatchErrorCode LoadPatch(EcmaVM *vm, const std::string &patchFileName, const void *patchBuffer, size_t patchSize, @@ -1318,7 +1339,6 @@ public: int32_t triggerMode)> &cb); static void SetSearchHapPathTracker(EcmaVM *vm, std::function cb); - private: static int vmCount_; static bool initialize_; @@ -1388,4 +1408,4 @@ public: static Local Next(const EcmaVM *vm, ecmascript::EcmaRuntimeCallInfo *ecmaRuntimeCallInfo); }; } -#endif \ No newline at end of file +#endif diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index b88880d04e032e9a7df11fbc75f9465507174160..418d30c692a41cc1063d3f31f54c95ea9939f7e8 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -34,6 +34,7 @@ #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h" #endif #include "ecmascript/byte_array.h" +#include "ecmascript/checkpoint/thread_state_transition.h" #include "ecmascript/compiler/aot_file/an_file_data_manager.h" #include "ecmascript/compiler/aot_file/aot_file_manager.h" #include "ecmascript/debugger/js_debugger_manager.h" @@ -201,6 +202,7 @@ using ModulePathHelper = ecmascript::ModulePathHelper; const EcmaVM *vm, Local buffer, int32_t byteOffset, int32_t length) \ { \ CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); \ + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); \ JSHandle env = vm->GetGlobalEnv(); \ \ JSHandle func = env->Get##Type##Function(); \ @@ -225,6 +227,7 @@ TYPED_ARRAY_ALL(TYPED_ARRAY_NEW) Local JSON::Parse(const EcmaVM *vm, Local string) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); auto ecmaStr = EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(*string).GetTaggedObject()); JSHandle result; if (EcmaStringAccessor(ecmaStr).IsUtf8()) { @@ -242,6 +245,7 @@ Local JSON::Parse(const EcmaVM *vm, Local string) Local JSON::Stringify(const EcmaVM *vm, Local json) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); auto constants = thread->GlobalConstants(); JsonStringifier stringifier(thread); JSHandle str = stringifier.Stringify( @@ -253,6 +257,7 @@ Local JSON::Stringify(const EcmaVM *vm, Local json) Local RegExpRef::GetOriginalSource(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); JSHandle regExp(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(regExp, FATAL); JSTaggedValue source = regExp->GetOriginalSource(); @@ -380,6 +385,7 @@ Local GeneratorObjectRef::GetGeneratorState(const EcmaVM *vm) Local GeneratorObjectRef::GetGeneratorFunction(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); JSHandle jsGenerator(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(jsGenerator, FATAL); JSHandle generatorContext(thread, jsGenerator->GetGeneratorContext()); @@ -390,6 +396,7 @@ Local GeneratorObjectRef::GetGeneratorFunction(const EcmaVM *vm) Local GeneratorObjectRef::GetGeneratorReceiver(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); JSHandle jsGenerator(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(jsGenerator, FATAL); JSHandle generatorContext(thread, jsGenerator->GetGeneratorContext()); @@ -400,6 +407,7 @@ Local GeneratorObjectRef::GetGeneratorReceiver(const EcmaVM *vm) Local CollatorRef::GetCompareFunction(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); #ifdef ARK_SUPPORT_INTL JSHandle jsCollator(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(jsCollator, FATAL); @@ -414,6 +422,7 @@ Local CollatorRef::GetCompareFunction(const EcmaVM *vm) Local DataTimeFormatRef::GetFormatFunction(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); #ifdef ARK_SUPPORT_INTL JSHandle jsDateTimeFormat(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(jsDateTimeFormat, FATAL); @@ -428,6 +437,7 @@ Local DataTimeFormatRef::GetFormatFunction(const EcmaVM *vm) Local NumberFormatRef::GetFormatFunction(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); #ifdef ARK_SUPPORT_INTL JSHandle jsNumberFormat(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(jsNumberFormat, FATAL); @@ -465,7 +475,11 @@ JSTaggedValue Callback::RegisterCallback(ecmascript::EcmaRuntimeCallInfo *ecmaRu getStackBeforeCallNapiSuccess = thread->GetEcmaVM()->GetProfiler()->GetStackBeforeCallNapi(thread); } #endif - Local result = nativeFunc(jsiRuntimeCallInfo); + Local result; + { + ecmascript::ThreadNativeScope nativeScope(thread); + result = nativeFunc(jsiRuntimeCallInfo); + } #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) if (thread->GetIsProfiling() && function->IsCallNapi() && getStackBeforeCallNapiSuccess) { thread->GetEcmaVM()->GetProfiler()->GetStackAfterCallNapi(thread); diff --git a/ecmascript/napi/jsnapi_expo.cpp b/ecmascript/napi/jsnapi_expo.cpp index e1820207da4fbf6d4bcd9fe9af9ce2119ab3859d..bfdad46757d338a198fc01b7531b7ba2a994d4db 100644 --- a/ecmascript/napi/jsnapi_expo.cpp +++ b/ecmascript/napi/jsnapi_expo.cpp @@ -37,6 +37,7 @@ #endif #include "ecmascript/accessor_data.h" #include "ecmascript/byte_array.h" +#include "ecmascript/checkpoint/thread_state_transition.h" #include "ecmascript/compiler/aot_file/an_file_data_manager.h" #include "ecmascript/compiler/aot_file/aot_file_manager.h" #include "ecmascript/debugger/js_debugger_manager.h" @@ -86,6 +87,7 @@ #include "ecmascript/pgo_profiler/pgo_profiler_manager.h" #include "ecmascript/platform/file.h" #include "ecmascript/regexp/regexp_parser.h" +#include "ecmascript/runtime.h" #include "ecmascript/serializer/base_deserializer.h" #include "ecmascript/serializer/value_serializer.h" #include "ecmascript/tagged_array.h" @@ -196,9 +198,11 @@ namespace { // NOLINTNEXTLINE(fuchsia-statically-constructed-objects) constexpr std::string_view ENTRY_POINTER = "_GLOBAL::func_main_0"; } + int JSNApi::vmCount_ = 0; bool JSNApi::initialize_ = false; static Mutex *mutex = new panda::Mutex(); + #define XPM_PROC_LENGTH 50 #define PROC_SELF_XPM_REGION_PATH "/proc/self/xpm_region" @@ -233,6 +237,7 @@ Local JSValueRef::ToObject(const EcmaVM *vm) if (IsUndefined() || IsNull()) { return Undefined(vm); } + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj(JSTaggedValue::ToObject(thread, JSNApiHelper::ToJSHandle(this))); LOG_IF_SPECIAL(obj, ERROR); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); @@ -242,6 +247,7 @@ Local JSValueRef::ToObject(const EcmaVM *vm) Local JSValueRef::ToString(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); if (!obj->IsString()) { @@ -254,6 +260,7 @@ Local JSValueRef::ToString(const EcmaVM *vm) Local JSValueRef::ToNativePointer(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); return JSNApiHelper::ToLocal(obj); @@ -267,6 +274,7 @@ bool JSValueRef::BooleaValue() int64_t JSValueRef::IntegerValue(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle tagged = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(tagged, ERROR); if (tagged->IsNumber()) { @@ -300,6 +308,7 @@ int32_t JSValueRef::Int32Value(const EcmaVM *vm) Local JSValueRef::ToBoolean(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); JSHandle booleanObj(thread, JSTaggedValue(obj->ToBoolean())); @@ -309,6 +318,7 @@ Local JSValueRef::ToBoolean(const EcmaVM *vm) Local JSValueRef::ToBigInt(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); JSHandle bigIntObj(thread, JSTaggedValue::ToBigInt(thread, obj)); @@ -319,6 +329,7 @@ Local JSValueRef::ToBigInt(const EcmaVM *vm) Local JSValueRef::ToNumber(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); JSHandle number(thread, JSTaggedValue::ToNumber(thread, obj)); @@ -338,6 +349,7 @@ bool JSValueRef::IsStrictEquals(const EcmaVM *vm, Local value) Local JSValueRef::Typeof(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedValue value = FastRuntimeStub::FastTypeOf(thread, JSNApiHelper::ToJSTaggedValue(this)); return JSNApiHelper::ToLocal(JSHandle(thread, value)); } @@ -345,6 +357,7 @@ Local JSValueRef::Typeof(const EcmaVM *vm) bool JSValueRef::InstanceOf(const EcmaVM *vm, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle origin = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(origin, ERROR); JSHandle target = JSNApiHelper::ToJSHandle(value); @@ -807,6 +820,7 @@ Local DataViewRef::New( const EcmaVM *vm, Local arrayBuffer, uint32_t byteOffset, uint32_t byteLength) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle buffer(JSNApiHelper::ToJSHandle(arrayBuffer)); @@ -832,6 +846,7 @@ uint32_t DataViewRef::ByteOffset() Local DataViewRef::GetArrayBuffer(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle dataView(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(dataView, FATAL); JSHandle arrayBuffer(thread, dataView->GetViewedArrayBuffer()); @@ -843,6 +858,7 @@ Local DataViewRef::GetArrayBuffer(const EcmaVM *vm) Local PrimitiveRef::GetValue(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); if (obj->IsJSPrimitiveRef()) { @@ -859,6 +875,7 @@ Local NumberRef::New(const EcmaVM *vm, double input) // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); if (std::isnan(input)) { input = ecmascript::base::NAN_VALUE; } @@ -871,6 +888,7 @@ Local NumberRef::New(const EcmaVM *vm, int32_t input) // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle number(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(number); } @@ -880,6 +898,7 @@ Local NumberRef::New(const EcmaVM *vm, uint32_t input) // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle number(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(number); } @@ -889,6 +908,7 @@ Local NumberRef::New(const EcmaVM *vm, int64_t input) // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle number(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(number); } @@ -904,6 +924,7 @@ double NumberRef::Value() Local MapRef::Get(const EcmaVM *vm, Local key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); return JSNApiHelper::ToLocal(JSHandle(thread, map->Get(thread, JSNApiHelper::ToJSTaggedValue(*key)))); @@ -912,6 +933,7 @@ Local MapRef::Get(const EcmaVM *vm, Local key) void MapRef::Set(const EcmaVM *vm, Local key, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); JSMap::Set(thread, map, JSNApiHelper::ToJSHandle(key), JSNApiHelper::ToJSHandle(value)); } @@ -919,6 +941,7 @@ void MapRef::Set(const EcmaVM *vm, Local key, Local valu Local MapRef::New(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle constructor = env->GetBuiltinsMapFunction(); @@ -1059,6 +1082,7 @@ Local SetIteratorRef::GetKind(const EcmaVM *vm) Local SetIteratorRef::New(const EcmaVM *vm, Local set) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle jsSet(JSNApiHelper::ToJSHandle(set)); IterationKind iterKind = IterationKind::KEY_AND_VALUE; JSHandle setIteratorKeyAndValue = @@ -1093,6 +1117,7 @@ Local SetIteratorRef::Next(const EcmaVM *vm, ecmascript::EcmaRuntimeCa Local BufferRef::New(const EcmaVM *vm, int32_t length) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle arrayBuffer = JSHandle::Cast(factory->NewJSArrayBuffer(length)); JSHandle env = vm->GetGlobalEnv(); @@ -1114,6 +1139,7 @@ Local BufferRef::New( const EcmaVM *vm, void *buffer, int32_t length, const Deleter &deleter, void *data) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle arrayBuffer = factory->NewJSArrayBuffer(buffer, length, reinterpret_cast(deleter), data); @@ -1189,6 +1215,7 @@ JSTaggedValue BufferRef::BufferToStringCallback(ecmascript::EcmaRuntimeCallInfo Local PromiseCapabilityRef::New(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle constructor(globalEnv->GetPromiseFunction()); JSHandle capability(JSPromise::NewPromiseCapability(thread, constructor)); @@ -1207,6 +1234,7 @@ Local PromiseCapabilityRef::GetPromise(const EcmaVM *vm) bool PromiseCapabilityRef::Resolve(const EcmaVM *vm, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle arg = JSNApiHelper::ToJSHandle(value); @@ -1230,6 +1258,7 @@ bool PromiseCapabilityRef::Resolve(const EcmaVM *vm, Local value) bool PromiseCapabilityRef::Reject(const EcmaVM *vm, Local reason) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle arg = JSNApiHelper::ToJSHandle(reason); @@ -1257,6 +1286,7 @@ Local SymbolRef::New(const EcmaVM *vm, Local description) // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle symbol = factory->NewJSSymbol(); if (!description.IsEmpty()) { @@ -1269,6 +1299,7 @@ Local SymbolRef::New(const EcmaVM *vm, Local description) Local SymbolRef::GetDescription(const EcmaVM *vm) { CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedValue description = JSSymbol::Cast( JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject())->GetDescription(); if (!description.IsString()) { @@ -1285,6 +1316,7 @@ Local BooleanRef::New(const EcmaVM *vm, bool value) // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle boolean(thread, JSTaggedValue(value)); return JSNApiHelper::ToLocal(boolean); } @@ -1302,6 +1334,7 @@ Local StringRef::NewFromUtf8(const EcmaVM *vm, const char *utf8, int // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); if (length < 0) { JSHandle current(factory->NewFromUtf8(utf8)); @@ -1316,6 +1349,7 @@ Local StringRef::NewFromUtf16(const EcmaVM *vm, const char16_t *utf16 // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); if (length < 0) { JSHandle current(factory->NewFromUtf16(utf16)); @@ -1346,6 +1380,7 @@ uint32_t StringRef::Length() int32_t StringRef::Utf8Length(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle strHandle(vm->GetJSThread(), EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(this))); return EcmaStringAccessor(EcmaStringAccessor::Flatten(vm, strHandle)).GetUtf8Length(); } @@ -1374,6 +1409,7 @@ int StringRef::WriteLatin1(char *buffer, int length) Local StringRef::GetNapiWrapperString(const EcmaVM *vm) { CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle napiWapperString = thread->GlobalConstants()->GetHandledNapiWrapperString(); return JSNApiHelper::ToLocal(napiWapperString); } @@ -1409,6 +1445,7 @@ Local BigIntRef::New(const EcmaVM *vm, uint64_t input) // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle big = BigInt::Uint64ToBigInt(thread, input); JSHandle bigint = JSHandle::Cast(big); return JSNApiHelper::ToLocal(bigint); @@ -1419,6 +1456,7 @@ Local BigIntRef::New(const EcmaVM *vm, int64_t input) // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle big = BigInt::Int64ToBigInt(thread, input); JSHandle bigint = JSHandle::Cast(big); return JSNApiHelper::ToLocal(bigint); @@ -1429,6 +1467,7 @@ Local BigIntRef::CreateBigWords(const EcmaVM *vm, bool sign, uint32_ // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle big = BigInt::CreateBigWords(thread, sign, size, words); JSHandle bigint = JSHandle::Cast(big); return JSNApiHelper::ToLocal(bigint); @@ -1439,6 +1478,7 @@ void BigIntRef::BigIntToInt64(const EcmaVM *vm, int64_t *value, bool *lossless) // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle bigintVal(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(bigintVal, ERROR); BigInt::BigIntToInt64(thread, bigintVal, value, lossless); @@ -1449,6 +1489,7 @@ void BigIntRef::BigIntToUint64(const EcmaVM *vm, uint64_t *value, bool *lossless // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle bigintVal(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(bigintVal, ERROR); BigInt::BigIntToUint64(thread, bigintVal, value, lossless); @@ -1485,6 +1526,7 @@ uint32_t BigIntRef::GetWordsArraySize() // ----------------------------------- HandleScope ------------------------------------- LocalScope::LocalScope(const EcmaVM *vm) : thread_(vm->GetJSThread()) { + ecmascript::ThreadManagedScope managedScope(reinterpret_cast(thread_)); auto context = reinterpret_cast(thread_)->GetCurrentEcmaContext(); prevNext_ = context->GetHandleScopeStorageNext(); prevEnd_ = context->GetHandleScopeStorageEnd(); @@ -1494,6 +1536,7 @@ LocalScope::LocalScope(const EcmaVM *vm) : thread_(vm->GetJSThread()) LocalScope::LocalScope(const EcmaVM *vm, JSTaggedType value) : thread_(vm->GetJSThread()) { + ecmascript::ThreadManagedScope managedScope(reinterpret_cast(thread_)); auto context = reinterpret_cast(thread_)->GetCurrentEcmaContext(); ecmascript::EcmaHandleScope::NewHandle(reinterpret_cast(thread_), value); prevNext_ = context->GetHandleScopeStorageNext(); @@ -1504,6 +1547,7 @@ LocalScope::LocalScope(const EcmaVM *vm, JSTaggedType value) : thread_(vm->GetJS LocalScope::~LocalScope() { + ecmascript::ThreadManagedScope managedScope(reinterpret_cast(thread_)); auto context = reinterpret_cast(thread_)->GetCurrentEcmaContext(); context->HandleScopeCountDec(); context->SetHandleScopeStorageNext(static_cast(prevNext_)); @@ -1527,6 +1571,7 @@ Local IntegerRef::New(const EcmaVM *vm, int input) // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(thread); JSHandle integer(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(integer); } @@ -1536,6 +1581,7 @@ Local IntegerRef::NewFromUnsigned(const EcmaVM *vm, unsigned int inp // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(thread); JSHandle integer(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(integer); } @@ -1551,6 +1597,7 @@ int IntegerRef::Value() Local ObjectRef::New(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle constructor(globalEnv->GetObjectFunction()); @@ -1563,6 +1610,7 @@ Local ObjectRef::NewWithProperties(const EcmaVM *vm, size_t propertyC const PropertyAttribute *attributes) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle obj; auto CreateObjImpl = [vm, propertyCount, keys, attributes] (uintptr_t head) -> JSHandle { @@ -1595,6 +1643,7 @@ Local ObjectRef::NewWithNamedProperties(const EcmaVM *vm, size_t prop const char **keys, const Local *values) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); ObjectFactory *factory = vm->GetFactory(); JSHandle obj = factory->CreateJSObjectWithNamedProperties(propertyCount, keys, values); @@ -1606,6 +1655,7 @@ Local ObjectRef::CreateAccessorData(const EcmaVM *vm, Local getter, Local setter) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle getterValue = JSNApiHelper::ToJSHandle(getter); JSHandle setterValue = JSNApiHelper::ToJSHandle(setter); JSHandle accessor = thread->GetEcmaVM()->GetFactory()->NewAccessorData(); @@ -1614,9 +1664,23 @@ Local ObjectRef::CreateAccessorData(const EcmaVM *vm, return JSNApiHelper::ToLocal(JSHandle::Cast(accessor)); } +Local ObjectRef::CreateSendableAccessorData(const EcmaVM *vm, + Local getter, + Local setter) +{ + CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + JSHandle getterValue = JSNApiHelper::ToJSHandle(getter); + JSHandle setterValue = JSNApiHelper::ToJSHandle(setter); + JSHandle accessor = thread->GetEcmaVM()->GetFactory()->NewSAccessorData(); + accessor->SetGetter(thread, getterValue); + accessor->SetSetter(thread, setterValue); + return JSNApiHelper::ToLocal(JSHandle::Cast(accessor)); +} + bool ObjectRef::ConvertToNativeBindingObject(const EcmaVM *vm, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); [[maybe_unused]] LocalScope scope(vm); JSHandle object = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(object, ERROR); @@ -1632,6 +1696,7 @@ bool ObjectRef::ConvertToNativeBindingObject(const EcmaVM *vm, Local key, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); [[maybe_unused]] LocalScope scope(vm); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); @@ -1648,6 +1713,7 @@ bool ObjectRef::Set(const EcmaVM *vm, Local key, Local v bool ObjectRef::Set(const EcmaVM *vm, uint32_t key, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); [[maybe_unused]] LocalScope scope(vm); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); @@ -1663,6 +1729,7 @@ bool ObjectRef::SetAccessorProperty(const EcmaVM *vm, Local key, Loc Local setter, PropertyAttribute attribute) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); [[maybe_unused]] LocalScope scope(vm); JSHandle getterValue = JSNApiHelper::ToJSHandle(getter); JSHandle setterValue = JSNApiHelper::ToJSHandle(setter); @@ -1679,6 +1746,7 @@ bool ObjectRef::SetAccessorProperty(const EcmaVM *vm, Local key, Loc Local ObjectRef::Get(const EcmaVM *vm, Local key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); @@ -1697,6 +1765,7 @@ Local ObjectRef::Get(const EcmaVM *vm, Local key) Local ObjectRef::Get(const EcmaVM *vm, int32_t key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); @@ -1713,6 +1782,7 @@ Local ObjectRef::Get(const EcmaVM *vm, int32_t key) bool ObjectRef::GetOwnProperty(const EcmaVM *vm, Local key, PropertyAttribute &property) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); JSHandle keyValue = JSNApiHelper::ToJSHandle(key); @@ -1744,6 +1814,7 @@ bool ObjectRef::GetOwnProperty(const EcmaVM *vm, Local key, Property Local ObjectRef::GetOwnPropertyNames(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(obj, ERROR); JSHandle array(JSTaggedValue::GetOwnPropertyKeys(thread, obj)); @@ -1757,6 +1828,7 @@ Local ObjectRef::GetAllPropertyNames(const EcmaVM *vm, uint32_t filter // This interface is only used by napi. // This interface currently only supports normal objects. CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(obj, ERROR); JSHandle array(JSTaggedValue::GetAllPropertyKeys(thread, obj, filter)); @@ -1768,6 +1840,7 @@ Local ObjectRef::GetAllPropertyNames(const EcmaVM *vm, uint32_t filter Local ObjectRef::GetOwnEnumerablePropertyNames(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(obj, ERROR); JSHandle array(JSObject::EnumerableOwnNames(thread, obj)); @@ -1779,6 +1852,7 @@ Local ObjectRef::GetOwnEnumerablePropertyNames(const EcmaVM *vm) Local ObjectRef::GetPrototype(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(object, ERROR); JSHandle prototype(thread, JSTaggedValue::GetPrototype(thread, JSHandle(object))); @@ -1789,6 +1863,7 @@ Local ObjectRef::GetPrototype(const EcmaVM *vm) bool ObjectRef::SetPrototype(const EcmaVM *vm, Local prototype) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); JSHandle proto(JSNApiHelper::ToJSHandle(prototype)); return JSTaggedValue::SetPrototype(thread, JSHandle(object), JSHandle(proto)); @@ -1797,6 +1872,7 @@ bool ObjectRef::SetPrototype(const EcmaVM *vm, Local prototype) bool ObjectRef::DefineProperty(const EcmaVM *vm, Local key, PropertyAttribute attribute) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(object, ERROR); JSHandle keyValue(JSNApiHelper::ToJSHandle(key)); @@ -1808,6 +1884,7 @@ bool ObjectRef::DefineProperty(const EcmaVM *vm, Local key, Property bool ObjectRef::Has(const EcmaVM *vm, Local key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(object, ERROR); JSHandle keyValue(JSNApiHelper::ToJSHandle(key)); @@ -1817,6 +1894,7 @@ bool ObjectRef::Has(const EcmaVM *vm, Local key) bool ObjectRef::Has(const EcmaVM *vm, uint32_t key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(object, ERROR); return JSTaggedValue::HasProperty(thread, object, key); @@ -1825,6 +1903,7 @@ bool ObjectRef::Has(const EcmaVM *vm, uint32_t key) bool ObjectRef::Delete(const EcmaVM *vm, Local key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(object, ERROR); JSHandle keyValue(JSNApiHelper::ToJSHandle(key)); @@ -1834,6 +1913,7 @@ bool ObjectRef::Delete(const EcmaVM *vm, Local key) bool ObjectRef::Delete(const EcmaVM *vm, uint32_t key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(object, ERROR); JSHandle keyHandle(thread, JSTaggedValue(key)); @@ -1843,6 +1923,7 @@ bool ObjectRef::Delete(const EcmaVM *vm, uint32_t key) Local ObjectRef::Freeze(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle object = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(object, ERROR); @@ -1867,6 +1948,7 @@ Local ObjectRef::Freeze(const EcmaVM *vm) Local ObjectRef::Seal(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle object = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(object, ERROR); @@ -1891,6 +1973,7 @@ Local ObjectRef::Seal(const EcmaVM *vm) void ObjectRef::SetNativePointerFieldCount(const EcmaVM *vm, int32_t count) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); // ObjectRef::New may return special value if exception occurs. // So we need do special value check before use it. DCHECK_SPECIAL_VALUE(this); @@ -1920,6 +2003,7 @@ void ObjectRef::SetNativePointerField(const EcmaVM *vm, int32_t index, void *nat NativePointerCallback callBack, void *data, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); // ObjectRef::New may return special value if exception occurs. // So we need do special value check before use it. DCHECK_SPECIAL_VALUE(this); @@ -1931,6 +2015,7 @@ void ObjectRef::SetNativePointerField(const EcmaVM *vm, int32_t index, void *nat Local NativePointerRef::New(const EcmaVM *vm, void *nativePointer, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle obj = factory->NewJSNativePointer(nativePointer, nullptr, nullptr, false, nativeBindingsize); @@ -1941,6 +2026,7 @@ Local NativePointerRef::New( const EcmaVM *vm, void *nativePointer, NativePointerCallback callBack, void *data, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle obj = factory->NewJSNativePointer(nativePointer, callBack, data, false, nativeBindingsize); @@ -1958,6 +2044,7 @@ void *NativePointerRef::Value() Local ArrayBufferRef::New(const EcmaVM *vm, int32_t length) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle arrayBuffer = factory->NewJSArrayBuffer(length); return JSNApiHelper::ToLocal(JSHandle(arrayBuffer)); @@ -1967,6 +2054,7 @@ Local ArrayBufferRef::New( const EcmaVM *vm, void *buffer, int32_t length, const Deleter &deleter, void *data) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle arrayBuffer = factory->NewJSArrayBuffer(buffer, length, reinterpret_cast(deleter), data); @@ -1976,6 +2064,7 @@ Local ArrayBufferRef::New( int32_t ArrayBufferRef::ByteLength([[maybe_unused]] const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(arrayBuffer, FATAL); return arrayBuffer->GetArrayBufferByteLength(); @@ -1995,6 +2084,7 @@ void *ArrayBufferRef::GetBuffer() void ArrayBufferRef::Detach(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); arrayBuffer->Detach(thread); } @@ -2010,6 +2100,7 @@ bool ArrayBufferRef::IsDetach() Local DateRef::New(const EcmaVM *vm, double time) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle dateFunction(globalEnv->GetDateFunction()); @@ -2021,6 +2112,7 @@ Local DateRef::New(const EcmaVM *vm, double time) Local DateRef::ToString(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle date(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(date, ERROR); JSTaggedValue dateStr = date->ToString(thread); @@ -2070,6 +2162,7 @@ uint32_t TypedArrayRef::ArrayLength([[maybe_unused]] const EcmaVM *vm) Local TypedArrayRef::GetArrayBuffer(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); JSHandle typeArray(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(typeArray, ERROR); JSHandle arrayBuffer(thread, JSTypedArray::GetOffHeapBuffer(thread, typeArray)); @@ -2081,6 +2174,7 @@ Local FunctionRef::New(EcmaVM *vm, FunctionCallback nativeFunc, Deleter deleter, void *data, bool callNapi, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle current(factory->NewJSFunction(env, reinterpret_cast(Callback::RegisterCallback))); @@ -2093,6 +2187,7 @@ Local FunctionRef::New(EcmaVM *vm, InternalFunctionCallback nativeF Deleter deleter, void *data, bool callNapi, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle current(factory->NewJSFunction(env, reinterpret_cast(nativeFunc))); @@ -2101,6 +2196,23 @@ Local FunctionRef::New(EcmaVM *vm, InternalFunctionCallback nativeF return JSNApiHelper::ToLocal(JSHandle(current)); } +Local FunctionRef::NewSendable(EcmaVM *vm, + InternalFunctionCallback nativeFunc, + Deleter deleter, + void *data, + bool callNapi, + size_t nativeBindingsize) +{ + CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); + ObjectFactory *factory = vm->GetFactory(); + JSHandle env = vm->GetGlobalEnv(); + JSHandle current(factory->NewSFunction(env, reinterpret_cast(nativeFunc))); + current->SetSFunctionExtraInfo(thread, nullptr, deleter, data, nativeBindingsize); + current->SetCallNapi(callNapi); + return JSNApiHelper::ToLocal(JSHandle(current)); +} + static void InitClassFunction(EcmaVM *vm, JSHandle &func, bool callNapi) { CROSS_THREAD_CHECK(vm); @@ -2125,6 +2237,7 @@ Local FunctionRef::NewClassFunction(EcmaVM *vm, FunctionCallback na Deleter deleter, void *data, bool callNapi, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); @@ -2142,6 +2255,7 @@ Local FunctionRef::NewClassFunction(EcmaVM *vm, InternalFunctionCal Deleter deleter, void *data, bool callNapi, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); @@ -2155,11 +2269,225 @@ Local FunctionRef::NewClassFunction(EcmaVM *vm, InternalFunctionCal return scope.Escape(result); } +ecmascript::SharedFieldType GetSharedFieldType(Local value) +{ + auto valueHandle = JSNApiHelper::ToJSHandle(value); + if (valueHandle->IsUndefined()) { + return ecmascript::SharedFieldType::NONE; + } + if (valueHandle->IsNumber()) { + return ecmascript::SharedFieldType::NUMBER; + } + if (valueHandle->IsString()) { + return ecmascript::SharedFieldType::STRING; + } + if (valueHandle->IsBoolean()) { + return ecmascript::SharedFieldType::BOOLEAN; + } + if (valueHandle->IsObject()) { + return ecmascript::SharedFieldType::SENDABLE; + } + if (valueHandle->IsBigInt()) { + return ecmascript::SharedFieldType::BIG_INT; + } + LOG_ECMA(ERROR) << "SharedFieldType"; + return ecmascript::SharedFieldType::NONE; +} + +JSHandle CreateInlinedSendableHClass(JSThread *thread, + FunctionRef::SendablePropertiesInfo info, + bool isProtoClass) +{ + EcmaVM *vm = thread->GetEcmaVM(); + ObjectFactory *factory = vm->GetFactory(); + JSHandle hclass; + uint32_t length = info.keys->Length(vm); + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + JSHandle layout = factory->CreateSLayoutInfo(length); + + for (uint32_t i = 0; i < length; ++i) { + key.Update(JSNApiHelper::ToJSHandle(info.keys->Get(vm, i))); + ASSERT(key->IsString()); + ecmascript::SharedFieldType type = GetSharedFieldType(info.values->Get(vm, i)); + ecmascript::PropertyAttributes attr = ecmascript::PropertyAttributes::Default( + info.attributes[i].IsWritable(), info.attributes[i].IsEnumerable(), info.attributes[i].IsConfigurable()); + if (UNLIKELY(JSNApiHelper::ToJSHandle(info.attributes[i].GetValue(vm))->IsAccessor())) { + attr.SetIsAccessor(true); + } + attr.SetIsInlinedProps(true); + attr.SetRepresentation(ecmascript::Representation::TAGGED); + attr.SetSharedFieldType(type); + attr.SetOffset(i); + layout->AddKey(thread, i, key.GetTaggedValue(), attr); + } + hclass = isProtoClass ? factory->NewSEcmaHClass(ecmascript::JSSharedObject::SIZE, + ecmascript::JSType::JS_SHARED_OBJECT, length) + : factory->NewSEcmaHClass(ecmascript::JSSharedFunction::SIZE, + ecmascript::JSType::JS_SHARED_FUNCTION, length); + hclass->SetLayout(thread, layout); + hclass->SetNumberOfProps(length); + + return hclass; +} + +JSHandle CreateDictSendableHClass(JSThread *thread, + FunctionRef::SendablePropertiesInfo info, + bool isProtoClass) +{ + EcmaVM *vm = thread->GetEcmaVM(); + ObjectFactory *factory = vm->GetFactory(); + JSHandle hclass; + uint32_t length = info.keys->Length(vm); + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + JSMutableHandle dict(thread, + ecmascript::NameDictionary::CreateInSharedHeap(thread, + ecmascript::NameDictionary::ComputeHashTableSize(length))); + auto globalConst = const_cast(thread->GlobalConstants()); + JSHandle value = globalConst->GetHandledUndefined(); + + for (uint32_t i = 0; i < length; ++i) { + key.Update(JSNApiHelper::ToJSHandle(info.keys->Get(vm, i))); + ASSERT(key->IsString()); + ecmascript::SharedFieldType type = GetSharedFieldType(info.values->Get(vm, i)); + ecmascript::PropertyAttributes attr = ecmascript::PropertyAttributes::Default( + info.attributes[i].IsWritable(), info.attributes[i].IsEnumerable(), info.attributes[i].IsConfigurable()); + attr.SetSharedFieldType(type); + attr.SetBoxType(ecmascript::PropertyBoxType::UNDEFINED); + JSHandle newDict = ecmascript::NameDictionary::Put(thread, dict, key, value, attr); + dict.Update(newDict); + } + hclass = + isProtoClass + ? factory->NewSEcmaHClass(ecmascript::JSSharedObject::SIZE, ecmascript::JSType::JS_SHARED_OBJECT, 0) + : factory->NewSEcmaHClass(ecmascript::JSSharedFunction::SIZE, ecmascript::JSType::JS_SHARED_FUNCTION, 0); + hclass->SetLayout(thread, dict); + hclass->SetNumberOfProps(0); + hclass->SetIsDictionaryMode(true); + + return hclass; +} + +JSHandle CreateSendableHClass(JSThread *thread, FunctionRef::SendablePropertiesInfo info, bool isProtoClass) +{ + EcmaVM *vm = thread->GetEcmaVM(); + uint32_t length = info.keys->Length(vm); + uint32_t maxInline = + isProtoClass ? ecmascript::JSSharedObject::MAX_INLINE : ecmascript::JSSharedFunction::MAX_INLINE; + JSHandle hclass; + + if (LIKELY(length <= maxInline)) { + hclass = CreateInlinedSendableHClass(thread, info, isProtoClass); + } else { + hclass = CreateDictSendableHClass(thread, info, isProtoClass); + } + if (isProtoClass) { + hclass->SetClassPrototype(true); + hclass->SetIsPrototype(true); + } else { + hclass->SetClassConstructor(true); + hclass->SetConstructor(true); + } + + return hclass; +} + +void SetInlinedAndDictProps(JSThread *thread, + FunctionRef::SendablePropertiesInfo info, + JSHandle hclass, + JSHandle obj) +{ + EcmaVM *vm = thread->GetEcmaVM(); + JSMutableHandle propKey(thread, JSTaggedValue::Undefined()); + JSMutableHandle propValue(thread, JSTaggedValue::Undefined()); + + uint32_t length = info.keys->Length(vm); + if (LIKELY(!hclass->IsDictionaryMode())) { + for (uint32_t i = 0; i < length; ++i) { + propValue.Update(JSNApiHelper::ToJSHandle(info.attributes[i].GetValue(vm))); + obj->SetPropertyInlinedProps(thread, i, propValue.GetTaggedValue()); + } + } else { + JSMutableHandle dict(thread, + ecmascript::NameDictionary::CreateInSharedHeap(thread, + ecmascript::NameDictionary::ComputeHashTableSize(length))); + for (uint32_t i = 0; i < length; i++) { + ecmascript::PropertyAttributes attr = ecmascript::PropertyAttributes::Default( + info.attributes[i].IsWritable(), info.attributes[i].IsEnumerable(), + info.attributes[i].IsConfigurable()); + propKey.Update(JSNApiHelper::ToJSHandle(info.keys->Get(vm, i))); + propValue.Update(JSNApiHelper::ToJSHandle(info.attributes[i].GetValue(vm))); + JSHandle newDict = + ecmascript::NameDictionary::PutIfAbsent(thread, dict, propKey, propValue, attr); + dict.Update(newDict); + } + obj->SetProperties(thread, dict); + } +} + +Local FunctionRef::NewSendableClassFunction(const EcmaVM *vm, + InternalFunctionCallback nativeFunc, + Deleter deleter, + void *data, + Local name, + SendablePropertiesInfos propertiesInfos, + Local parent, + bool callNapi, + size_t nativeBindingSize) +{ + CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); + EscapeLocalScope scope(vm); + ObjectFactory *factory = vm->GetFactory(); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + + auto [instancePropertiesInfo, staticPropertiesInfo, nonStaticPropertiesInfo] = propertiesInfos; + JSHandle nameKey = globalConst->GetHandledNameString(); + staticPropertiesInfo.keys->Set(vm, 0, JSNApiHelper::ToLocal(nameKey)); + staticPropertiesInfo.values->Set(vm, 0, name); + JSHandle constructorKey = globalConst->GetHandledConstructorString(); + nonStaticPropertiesInfo.keys->Set(vm, 0, JSNApiHelper::ToLocal(constructorKey)); + nonStaticPropertiesInfo.values->Set(vm, 0, JSValueRef::Null(vm)); + + JSHandle prototypeHClass = CreateSendableHClass(thread, nonStaticPropertiesInfo, true); + JSHandle prototype = factory->NewSharedOldSpaceJSObject(prototypeHClass); + JSHandle constructorHClass = CreateSendableHClass(thread, staticPropertiesInfo, false); + JSHandle constructor = factory->NewSFunctionByHClass( + reinterpret_cast(nativeFunc), constructorHClass, ecmascript::FunctionKind::CLASS_CONSTRUCTOR); + + staticPropertiesInfo.attributes[0] = PropertyAttribute(name, false, false, false); + nonStaticPropertiesInfo.attributes[0] = PropertyAttribute( + JSNApiHelper::ToLocal(JSHandle::Cast(constructor)), false, false, false); + SetInlinedAndDictProps(thread, nonStaticPropertiesInfo, prototypeHClass, prototype); + SetInlinedAndDictProps(thread, staticPropertiesInfo, constructorHClass, JSHandle::Cast(constructor)); + + if (!parent->IsNull()) { + auto parentPrototype = parent->GetFunctionPrototype(vm); + prototypeHClass->SetPrototype(thread, JSNApiHelper::ToJSHandle(parentPrototype)); + constructorHClass->SetPrototype(thread, JSNApiHelper::ToJSHandle(parent)); + } + prototype->GetJSHClass()->SetExtensible(false); + constructor->SetHomeObject(thread, prototype); + constructor->SetProtoOrHClass(thread, prototype); + constructor->SetLexicalEnv(thread, constructor); + constructor->SetCallNapi(callNapi); + constructor->SetSFunctionExtraInfo(thread, nullptr, deleter, data, nativeBindingSize); + + JSHandle iHClass = CreateSendableHClass(thread, instancePropertiesInfo, true); + iHClass->SetPrototype(thread, JSHandle(prototype)); + iHClass->SetExtensible(false); + constructor->SetProtoOrHClass(thread, iHClass); + constructor->GetJSHClass()->SetExtensible(false); + + Local result = JSNApiHelper::ToLocal(JSHandle(constructor)); + return scope.Escape(result); +} + Local FunctionRef::Call(const EcmaVM *vm, Local thisObj, const Local argv[], // NOLINTNEXTLINE(modernize-avoid-c-arrays) int32_t length) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); FunctionCallScope callScope(EcmaVM::ConstCast(vm)); if (!IsFunction()) { @@ -2191,6 +2519,7 @@ JSValueRef* FunctionRef::CallForNapi(const EcmaVM *vm, JSValueRef *thisObj, int32_t length) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, *JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); JSTaggedValue result; FunctionCallScope callScope(EcmaVM::ConstCast(vm)); ASSERT(IsFunction()); // IsFunction check has been done in napi. @@ -2244,6 +2573,7 @@ Local FunctionRef::Constructor(const EcmaVM *vm, int32_t length) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); FunctionCallScope callScope(EcmaVM::ConstCast(vm)); if (!IsFunction()) { return JSValueRef::Undefined(vm); @@ -2271,6 +2601,7 @@ JSValueRef* FunctionRef::ConstructorOptimize(const EcmaVM *vm, int32_t length) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, *JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedValue result; FunctionCallScope callScope(EcmaVM::ConstCast(vm)); ASSERT(IsFunction()); // IsFunction check has been done in napi. @@ -2297,6 +2628,7 @@ JSValueRef* FunctionRef::ConstructorOptimize(const EcmaVM *vm, Local FunctionRef::GetFunctionPrototype(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle func = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(func, FATAL); JSHandle prototype(thread, JSHandle(func)->GetFunctionPrototype()); @@ -2306,6 +2638,7 @@ Local FunctionRef::GetFunctionPrototype(const EcmaVM *vm) bool FunctionRef::Inherit(const EcmaVM *vm, Local parent) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); [[maybe_unused]] LocalScope scope(vm); JSHandle parentValue = JSNApiHelper::ToJSHandle(parent); JSHandle parentHandle = JSHandle::Cast(parentValue); @@ -2325,6 +2658,7 @@ bool FunctionRef::Inherit(const EcmaVM *vm, Local parent) void FunctionRef::SetName(const EcmaVM *vm, Local name) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); [[maybe_unused]] LocalScope scope(vm); JSFunction *func = JSFunction::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject()); JSTaggedValue key = JSNApiHelper::ToJSTaggedValue(*name); @@ -2334,6 +2668,7 @@ void FunctionRef::SetName(const EcmaVM *vm, Local name) Local FunctionRef::GetName(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle func(thread, JSNApiHelper::ToJSTaggedValue(this)); JSHandle name = JSFunctionBase::GetFunctionName(thread, func); @@ -2344,6 +2679,7 @@ Local FunctionRef::GetName(const EcmaVM *vm) Local FunctionRef::GetSourceCode(const EcmaVM *vm, int lineNumber) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle func(thread, JSNApiHelper::ToJSTaggedValue(this)); JSHandle method(thread, func->GetMethod()); @@ -2351,7 +2687,8 @@ Local FunctionRef::GetSourceCode(const EcmaVM *vm, int lineNumber) DebugInfoExtractor *debugExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile); ecmascript::CString entry = JSPandaFile::ENTRY_FUNCTION_NAME; if (!jsPandaFile->IsBundlePack()) { - JSTaggedValue recordName = method->GetRecordName(); + JSFunction *function = JSFunction::Cast(func.GetTaggedValue().GetTaggedObject()); + JSTaggedValue recordName = function->GetRecordName(); ASSERT(!recordName.IsHole()); entry = ConvertToString(recordName); } @@ -2379,6 +2716,7 @@ Local FunctionRef::GetSourceCode(const EcmaVM *vm, int lineNumber) bool FunctionRef::IsNative(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle func(thread, JSNApiHelper::ToJSTaggedValue(this)); JSHandle method(thread, func->GetMethod()); return method->IsNativeWithCallField(); @@ -2387,6 +2725,7 @@ bool FunctionRef::IsNative(const EcmaVM *vm) void FunctionRef::SetData(const EcmaVM *vm, void *data, Deleter deleter, bool callNapi) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle funcValue = JSNApiHelper::ToJSHandle(this); JSHandle function(funcValue); function->SetFunctionExtraInfo(thread, nullptr, deleter, data, 0); @@ -2396,6 +2735,7 @@ void FunctionRef::SetData(const EcmaVM *vm, void *data, Deleter deleter, bool ca void* FunctionRef::GetData(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, nullptr); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle funcValue = JSNApiHelper::ToJSHandle(this); JSHandle function(funcValue); if (!function->IsCallNapi()) { @@ -2405,7 +2745,7 @@ void* FunctionRef::GetData(const EcmaVM *vm) if (!extraInfoValue.IsNativePointer()) { return nullptr; } - JSHandle extraInfo(thread, extraInfoValue); + auto extraInfo = JSNativePointer::Cast(extraInfoValue.GetTaggedObject()); return extraInfo->GetData(); } @@ -2413,6 +2753,7 @@ void* FunctionRef::GetData(const EcmaVM *vm) Local ArrayRef::New(const EcmaVM *vm, uint32_t length) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedNumber arrayLen(length); JSHandle array = JSArray::ArrayCreate(thread, arrayLen); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); @@ -2428,6 +2769,7 @@ uint32_t ArrayRef::Length([[maybe_unused]] const EcmaVM *vm) Local ArrayRef::GetValueAt(const EcmaVM *vm, Local obj, uint32_t index) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object = JSNApiHelper::ToJSHandle(obj); JSHandle result = JSArray::FastGetPropertyByValue(thread, object, index); return JSNApiHelper::ToLocal(result); @@ -2436,6 +2778,7 @@ Local ArrayRef::GetValueAt(const EcmaVM *vm, Local obj, bool ArrayRef::SetValueAt(const EcmaVM *vm, Local obj, uint32_t index, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle objectHandle = JSNApiHelper::ToJSHandle(obj); JSHandle valueHandle = JSNApiHelper::ToJSHandle(value); return JSArray::FastSetPropertyByValue(thread, objectHandle, index, valueHandle); @@ -2447,6 +2790,7 @@ bool ArrayRef::SetValueAt(const EcmaVM *vm, Local obj, uint32_t inde Local Exception::name(const EcmaVM *vm, Local message) \ { \ CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); \ + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); \ ObjectFactory *factory = vm->GetFactory(); \ \ JSHandle messageValue(JSNApiHelper::ToJSHandle(message)); \ @@ -2470,6 +2814,7 @@ FunctionCallScope::~FunctionCallScope() vm_->DecreaseCallDepth(); if (vm_->IsTopLevelCallDepth()) { JSThread *thread = vm_->GetJSThread(); + ecmascript::ThreadManagedScope managedScope(vm_->GetJSThread()); thread->GetCurrentEcmaContext()->ExecutePromisePendingJob(); } } @@ -2510,6 +2855,7 @@ EcmaVM *JsiRuntimeCallInfo::GetVM() const PatchErrorCode JSNApi::LoadPatch(EcmaVM *vm, const std::string &patchFileName, const std::string &baseFileName) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, PatchErrorCode::INTERNAL_ERROR); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ecmascript::QuickFixManager *quickFixManager = vm->GetQuickFixManager(); return quickFixManager->LoadPatch(thread, patchFileName, baseFileName); } @@ -2519,6 +2865,7 @@ PatchErrorCode JSNApi::LoadPatch(EcmaVM *vm, const std::string &baseFileName, const void *baseBuffer, size_t baseSize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, PatchErrorCode::INTERNAL_ERROR); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ecmascript::QuickFixManager *quickFixManager = vm->GetQuickFixManager(); return quickFixManager->LoadPatch( thread, patchFileName, patchBuffer, patchSize, baseFileName, baseBuffer, baseSize); @@ -2527,6 +2874,7 @@ PatchErrorCode JSNApi::LoadPatch(EcmaVM *vm, PatchErrorCode JSNApi::UnloadPatch(EcmaVM *vm, const std::string &patchFileName) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, PatchErrorCode::INTERNAL_ERROR); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ecmascript::QuickFixManager *quickFixManager = vm->GetQuickFixManager(); return quickFixManager->UnloadPatch(thread, patchFileName); } @@ -2624,6 +2972,7 @@ bool JSNApi::InitForConcurrentThread(EcmaVM *vm, ConcurrentCallback cb, void *da bool JSNApi::InitForConcurrentFunction(EcmaVM *vm, Local function, void *taskInfo) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); [[maybe_unused]] LocalScope scope(vm); JSHandle funcVal = JSNApiHelper::ToJSHandle(function); JSHandle transFunc = JSHandle::Cast(funcVal); @@ -2639,6 +2988,7 @@ bool JSNApi::InitForConcurrentFunction(EcmaVM *vm, Local function, v void* JSNApi::GetCurrentTaskInfo(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, nullptr); + ecmascript::ThreadManagedScope managedScope(thread); JSTaggedType *current = const_cast(thread->GetCurrentFrame()); ecmascript::FrameIterator it(current, thread); for (; !it.Done(); it.Advance()) { @@ -2744,6 +3094,7 @@ void JSNApi::GetStackBeforeCallNapiSuccess([[maybe_unused]] EcmaVM *vm, { #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) JSThread *thread = vm->GetJSThread(); + ecmascript::ThreadManagedScope managedScope(thread); if (thread->GetIsProfiling()) { getStackBeforeCallNapiSuccess = vm->GetProfiler()->GetStackBeforeCallNapi(thread); } @@ -2754,6 +3105,7 @@ void JSNApi::GetStackAfterCallNapi([[maybe_unused]] EcmaVM *vm) { #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) JSThread *thread = vm->GetJSThread(); + ecmascript::ThreadManagedScope managedScope(thread); if (thread->GetIsProfiling()) { vm->GetProfiler()->GetStackAfterCallNapi(thread); } @@ -2839,57 +3191,38 @@ EcmaVM *JSNApi::CreateJSVM(const RuntimeOption &option) EcmaContext *JSNApi::CreateJSContext(EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); + ecmascript::ThreadManagedScope managedScope(thread); return EcmaContext::CreateAndInitialize(thread); } void JSNApi::SwitchCurrentContext(EcmaVM *vm, EcmaContext *context) { JSThread *thread = vm->GetJSThread(); + ecmascript::ThreadManagedScope managedScope(thread); thread->SwitchCurrentContext(context); } void JSNApi::DestroyJSContext(EcmaVM *vm, EcmaContext *context) { JSThread *thread = vm->GetJSThread(); + ecmascript::ThreadManagedScope managedScope(thread); EcmaContext::CheckAndDestroy(thread, context); } EcmaVM *JSNApi::CreateEcmaVM(const JSRuntimeOptions &options) { - { - LockHolder lock(*mutex); - vmCount_++; - if (!initialize_) { - ecmascript::Log::Initialize(options); - InitializeIcuData(options); - InitializeMemMapAllocator(); - InitializePGOProfiler(options); - initialize_ = true; - } - } - auto config = ecmascript::EcmaParamConfiguration(options.IsWorker(), - MemMapAllocator::GetInstance()->GetCapacity()); - LOG_ECMA(DEBUG) << " [NAPI]: CreateEcmaVM, isWorker = " << options.IsWorker() << ", vmCount = " << vmCount_; - MemMapAllocator::GetInstance()->IncreaseAndCheckReserved(config.GetMaxHeapSize()); - return EcmaVM::Create(options, config); + return EcmaVM::Create(options); } void JSNApi::DestroyJSVM(EcmaVM *ecmaVm) { - LockHolder lock(*mutex); - if (!initialize_) { + if (UNLIKELY(ecmaVm == nullptr)) { return; } + ecmaVm->GetJSThread()->ManagedCodeBegin(); auto &config = ecmaVm->GetEcmaParamConfiguration(); MemMapAllocator::GetInstance()->DecreaseReserved(config.GetMaxHeapSize()); EcmaVM::Destroy(ecmaVm); - vmCount_--; - if (vmCount_ <= 0) { - DestroyAnDataManager(); - DestroyMemMapAllocator(); - DestroyPGOProfiler(); - initialize_ = false; - } } void JSNApi::RegisterUncatchableErrorHandler(EcmaVM *ecmaVm, const UncatchableErrorHandler &handler) @@ -2900,6 +3233,7 @@ void JSNApi::RegisterUncatchableErrorHandler(EcmaVM *ecmaVm, const UncatchableEr void JSNApi::TriggerGC(const EcmaVM *vm, TRIGGER_GC_TYPE gcType) { CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); if (thread != nullptr && vm->IsInitialized()) { switch (gcType) { case TRIGGER_GC_TYPE::SEMI_GC: @@ -2920,6 +3254,7 @@ void JSNApi::TriggerGC(const EcmaVM *vm, TRIGGER_GC_TYPE gcType) void JSNApi::ThrowException(const EcmaVM *vm, Local error) { auto thread = vm->GetJSThread(); + ecmascript::ThreadManagedScope managedScope(thread); if (thread->HasPendingException()) { LOG_ECMA(ERROR) << "An exception has already occurred before, keep old exception here."; return; @@ -2930,6 +3265,7 @@ void JSNApi::ThrowException(const EcmaVM *vm, Local error) void JSNApi::PrintExceptionInfo(const EcmaVM *vm) { JSThread* thread = vm->GetJSThread(); + ecmascript::ThreadManagedScope managedScope(thread); [[maybe_unused]] ecmascript::EcmaHandleScope handleScope(thread); if (!HasPendingException(vm)) { @@ -3347,6 +3683,7 @@ void JSNApi::SetDeviceDisconnectCallback(EcmaVM *vm, DeviceDisconnectCallback cb void JSNApi::LoadAotFile(EcmaVM *vm, const std::string &moduleName) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); + ecmascript::ThreadManagedScope scope(thread); if (!ecmascript::AnFileDataManager::GetInstance()->IsEnable()) { return; } @@ -3368,6 +3705,7 @@ bool JSNApi::ExecuteInContext(EcmaVM *vm, const std::string &fileName, const std { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); LOG_ECMA(DEBUG) << "start to execute ark file in context: " << fileName; + ecmascript::ThreadManagedScope scope(thread); EcmaContext::MountContext(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteFromAbcFile(thread, fileName.c_str(), entry, needUpdate)) { if (thread->HasPendingException()) { @@ -3385,6 +3723,7 @@ bool JSNApi::Execute(EcmaVM *vm, const std::string &fileName, const std::string { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); LOG_ECMA(DEBUG) << "start to execute ark file: " << fileName; + ecmascript::ThreadManagedScope scope(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteFromAbcFile(thread, fileName.c_str(), entry, needUpdate)) { if (thread->HasPendingException()) { thread->GetCurrentEcmaContext()->HandleUncaughtException(); @@ -3402,6 +3741,7 @@ bool JSNApi::Execute(EcmaVM *vm, const uint8_t *data, int32_t size, const std::s { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); LOG_ECMA(DEBUG) << "start to execute ark buffer: " << filename; + ecmascript::ThreadManagedScope scope(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteFromBuffer(thread, data, size, entry, filename.c_str(), needUpdate)) { if (thread->HasPendingException()) { thread->GetCurrentEcmaContext()->HandleUncaughtException(); @@ -3419,6 +3759,7 @@ bool JSNApi::ExecuteModuleBuffer(EcmaVM *vm, const uint8_t *data, int32_t size, { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); LOG_ECMA(DEBUG) << "start to execute module buffer: " << filename; + ecmascript::ThreadManagedScope scope(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteModuleBuffer(thread, data, size, filename.c_str(), needUpdate)) { if (thread->HasPendingException()) { thread->GetCurrentEcmaContext()->HandleUncaughtException(); @@ -3438,6 +3779,7 @@ bool JSNApi::ExecuteSecure(EcmaVM *vm, uint8_t *data, int32_t size, const std::s LOG_ECMA(ERROR) << "Secure memory check failed, please execute in srcure memory."; return false; } + ecmascript::ThreadManagedScope scope(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteFromBufferSecure(thread, data, size, entry, filename.c_str(), needUpdate)) { if (thread->HasPendingException()) { @@ -3459,6 +3801,7 @@ bool JSNApi::ExecuteModuleBufferSecure(EcmaVM *vm, uint8_t* data, int32_t size, LOG_ECMA(ERROR) << "Secure memory check failed, please execute in srcure memory."; return false; } + ecmascript::ThreadManagedScope scope(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteModuleBufferSecure(thread, data, size, filename.c_str(), needUpdate)) { if (thread->HasPendingException()) { @@ -3472,6 +3815,7 @@ bool JSNApi::ExecuteModuleBufferSecure(EcmaVM *vm, uint8_t* data, int32_t size, void JSNApi::PreFork(EcmaVM *vm) { + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); vm->PreFork(); } @@ -3513,11 +3857,13 @@ bool JSNApi::DeleteWorker(EcmaVM *hostVm, EcmaVM *workerVm) Local JSNApi::GetUncaughtException(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToLocal(vm->GetEcmaUncaughtException()); } Local JSNApi::GetAndClearUncaughtException(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToLocal(vm->GetAndClearEcmaUncaughtException()); } @@ -3533,6 +3879,7 @@ bool JSNApi::IsExecutingPendingJob(const EcmaVM *vm) bool JSNApi::HasPendingJob(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return vm->GetAssociatedJSThread()->GetCurrentEcmaContext()->HasPendingJob(); } @@ -3543,6 +3890,7 @@ void JSNApi::EnableUserUncaughtErrorHandler(EcmaVM *vm) Local JSNApi::GetGlobalObject(const EcmaVM *vm) { + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle global(vm->GetJSThread(), globalEnv->GetGlobalObject()); return JSNApiHelper::ToLocal(global); @@ -3551,6 +3899,7 @@ Local JSNApi::GetGlobalObject(const EcmaVM *vm) void JSNApi::ExecutePendingJob(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EcmaVM::ConstCast(vm)->GetJSThread()->GetCurrentEcmaContext()->ExecutePromisePendingJob(); } @@ -3559,6 +3908,7 @@ uintptr_t JSNApi::GetHandleAddr(const EcmaVM *vm, uintptr_t localAddress) if (localAddress == 0) { return 0; } + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); CROSS_THREAD_CHECK(vm); JSTaggedType value = *(reinterpret_cast(localAddress)); return ecmascript::EcmaHandleScope::NewHandle(thread, value); @@ -3569,6 +3919,7 @@ uintptr_t JSNApi::GetGlobalHandleAddr(const EcmaVM *vm, uintptr_t localAddress) if (localAddress == 0) { return 0; } + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); CROSS_THREAD_CHECK(vm); JSTaggedType value = *(reinterpret_cast(localAddress)); return thread->NewGlobalHandle(value); @@ -3579,6 +3930,7 @@ uintptr_t JSNApi::SetWeak(const EcmaVM *vm, uintptr_t localAddress) if (localAddress == 0) { return 0; } + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); CROSS_THREAD_CHECK(vm); return thread->SetWeak(localAddress); } @@ -3589,6 +3941,7 @@ uintptr_t JSNApi::SetWeakCallback(const EcmaVM *vm, uintptr_t localAddress, void if (localAddress == 0) { return 0; } + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); CROSS_THREAD_CHECK(vm); return thread->SetWeak(localAddress, ref, freeGlobalCallBack, nativeFinalizeCallback); } @@ -3598,6 +3951,7 @@ uintptr_t JSNApi::ClearWeak(const EcmaVM *vm, uintptr_t localAddress) if (localAddress == 0) { return 0; } + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); if (JSTaggedValue(reinterpret_cast(localAddress)->GetObject()) .IsUndefined()) { LOG_ECMA(ERROR) << "The object of weak reference has been recycled!"; @@ -3612,6 +3966,7 @@ bool JSNApi::IsWeak(const EcmaVM *vm, uintptr_t localAddress) if (localAddress == 0) { return false; } + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); CROSS_THREAD_CHECK(vm); return thread->IsWeak(localAddress); } @@ -3621,6 +3976,7 @@ void JSNApi::DisposeGlobalHandleAddr(const EcmaVM *vm, uintptr_t addr) if (addr == 0 || !reinterpret_cast(addr)->IsUsing()) { return; } + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); CROSS_THREAD_CHECK(vm); thread->DisposeGlobalHandle(addr); } @@ -3629,6 +3985,7 @@ void *JSNApi::SerializeValue(const EcmaVM *vm, Local value, Local cloneList, bool defaultTransfer, bool defaultCloneShared) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, nullptr); + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); JSHandle arkValue = JSNApiHelper::ToJSHandle(value); JSHandle arkTransfer = JSNApiHelper::ToJSHandle(transfer); JSHandle arkCloneList = JSNApiHelper::ToJSHandle(cloneList); @@ -3660,6 +4017,7 @@ void *JSNApi::SerializeValue(const EcmaVM *vm, Local value, Local JSNApi::DeserializeValue(const EcmaVM *vm, void *recoder, void *hint) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); #if ECMASCRIPT_ENABLE_VALUE_SERIALIZER std::unique_ptr data(reinterpret_cast(recoder)); ecmascript::BaseDeserializer deserializer(thread, data.release(), hint); @@ -3743,6 +4101,7 @@ void JSNApi::SetNativePtrGetter(EcmaVM *vm, void* cb) void JSNApi::SetHostEnqueueJob(const EcmaVM *vm, Local cb) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); JSHandle fun = JSHandle::Cast(JSNApiHelper::ToJSHandle(cb)); JSHandle array = vm->GetFactory()->EmptyArray(); JSHandle job = thread->GetCurrentEcmaContext()->GetMicroJobQueue(); @@ -3752,6 +4111,7 @@ void JSNApi::SetHostEnqueueJob(const EcmaVM *vm, Local cb) bool JSNApi::ExecuteModuleFromBuffer(EcmaVM *vm, const void *data, int32_t size, const std::string &file) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); if (!ecmascript::JSPandaFileExecutor::ExecuteFromBuffer(thread, data, size, ENTRY_POINTER, file.c_str())) { std::cerr << "Cannot execute panda file from memory" << std::endl; return false; @@ -3762,6 +4122,7 @@ bool JSNApi::ExecuteModuleFromBuffer(EcmaVM *vm, const void *data, int32_t size, Local JSNApi::GetExportObject(EcmaVM *vm, const std::string &file, const std::string &key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); ecmascript::CString entry = file.c_str(); ecmascript::CString name = vm->GetAssetPath(); if (!vm->IsBundlePack()) { @@ -3796,6 +4157,7 @@ Local JSNApi::GetExportObjectFromBuffer(EcmaVM *vm, const std::string const std::string &key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); ecmascript::ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); JSHandle ecmaModule = moduleManager->HostGetImportedModule(file.c_str()); @@ -3815,6 +4177,7 @@ Local JSNApi::GetExportObjectFromBuffer(EcmaVM *vm, const std::string Local JSNApi::ExecuteNativeModule(EcmaVM *vm, const std::string &key) { + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); JSHandle exportObj = moduleManager->LoadNativeModule(thread, key); @@ -3824,6 +4187,7 @@ Local JSNApi::ExecuteNativeModule(EcmaVM *vm, const std::string &key) Local JSNApi::GetModuleNameSpaceFromFile(EcmaVM *vm, const std::string &file, const std::string &module_path) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); std::string recordNameStr; std::string abcFilePath; if (module_path.size() != 0) { @@ -3848,6 +4212,7 @@ Local JSNApi::GetModuleNameSpaceWithModuleInfo(EcmaVM *vm, const std: const std::string &module_path) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); ecmascript::CString moduleStr = ModulePathHelper::GetModuleNameWithPath(module_path.c_str()); ecmascript::CString srcPrefix = moduleStr + ModulePathHelper::PHYCICAL_FILE_PATH; std::string prefix = ConvertToStdString(srcPrefix); @@ -3862,51 +4227,10 @@ Local JSNApi::GetModuleNameSpaceWithModuleInfo(EcmaVM *vm, const std: return JSNApiHelper::ToLocal(nameSp); } - // Initialize IcuData Path -void JSNApi::InitializeIcuData(const JSRuntimeOptions &options) -{ - std::string icuPath = options.GetIcuDataPath(); - if (icuPath == "default") { -#if !WIN_OR_MAC_OR_IOS_PLATFORM && !defined(PANDA_TARGET_LINUX) - SetHwIcuDirectory(); -#endif - } else { - std::string absPath; - if (ecmascript::RealPath(icuPath, absPath)) { - u_setDataDirectory(absPath.c_str()); - } - } -} - -void JSNApi::InitializeMemMapAllocator() -{ - MemMapAllocator::GetInstance()->Initialize(ecmascript::DEFAULT_REGION_SIZE); -} - -void JSNApi::DestroyMemMapAllocator() -{ - MemMapAllocator::GetInstance()->Finalize(); -} - -void JSNApi::InitializePGOProfiler(const ecmascript::JSRuntimeOptions &options) -{ - ecmascript::pgo::PGOProfilerManager::GetInstance()->Initialize( - options.GetPGOProfilerPath(), options.GetPGOHotnessThreshold()); -} - -void JSNApi::DestroyPGOProfiler() -{ - ecmascript::pgo::PGOProfilerManager::GetInstance()->Destroy(); -} - -void JSNApi::DestroyAnDataManager() -{ - ecmascript::AnFileDataManager::GetInstance()->SafeDestroyAllData(); -} - // ---------------------------------- Promise ------------------------------------- Local PromiseRef::Catch(const EcmaVM *vm, Local handler) { + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); const GlobalEnvConstants *constants = thread->GlobalConstants(); @@ -3928,6 +4252,7 @@ Local PromiseRef::Catch(const EcmaVM *vm, Local handler Local PromiseRef::Finally(const EcmaVM *vm, Local handler) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle promise = JSNApiHelper::ToJSHandle(this); @@ -3948,6 +4273,7 @@ Local PromiseRef::Finally(const EcmaVM *vm, Local handl Local PromiseRef::Then(const EcmaVM *vm, Local handler) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle promise = JSNApiHelper::ToJSHandle(this); @@ -3968,6 +4294,7 @@ Local PromiseRef::Then(const EcmaVM *vm, Local handler) Local PromiseRef::Then(const EcmaVM *vm, Local onFulfilled, Local onRejected) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle promise = JSNApiHelper::ToJSHandle(this); @@ -3989,6 +4316,7 @@ Local PromiseRef::Then(const EcmaVM *vm, Local onFulfil Local PromiseRef::GetPromiseState(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); JSHandle promise(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(promise, ERROR); @@ -4013,6 +4341,7 @@ Local PromiseRef::GetPromiseState(const EcmaVM *vm) Local PromiseRef::GetPromiseResult(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); JSHandle promise(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(promise, ERROR); @@ -4022,6 +4351,7 @@ Local PromiseRef::GetPromiseResult(const EcmaVM *vm) Local ProxyRef::GetHandler(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); JSHandle jsProxy(JSNApiHelper::ToJSHandle(this)); return JSNApiHelper::ToLocal(JSHandle(thread, jsProxy->GetHandler())); } @@ -4029,6 +4359,7 @@ Local ProxyRef::GetHandler(const EcmaVM *vm) Local ProxyRef::GetTarget(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope scope(vm->GetJSThread()); JSHandle jsProxy(JSNApiHelper::ToJSHandle(this)); return JSNApiHelper::ToLocal(JSHandle(thread, jsProxy->GetTarget())); } @@ -4059,6 +4390,7 @@ int32_t SetRef::GetTotalElements() Local SetRef::GetValue(const EcmaVM *vm, int entry) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); JSHandle set(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(set, FATAL); return JSNApiHelper::ToLocal(JSHandle(thread, set->GetValue(entry))); @@ -4067,6 +4399,7 @@ Local SetRef::GetValue(const EcmaVM *vm, int entry) Local SetRef::New(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); ObjectFactory *factory = vm->GetJSThread()->GetEcmaVM()->GetFactory(); JSHandle env = vm->GetJSThread()->GetEcmaVM()->GetGlobalEnv(); JSHandle constructor = env->GetBuiltinsSetFunction(); @@ -4081,6 +4414,7 @@ Local SetRef::New(const EcmaVM *vm) void SetRef::Add(const EcmaVM *vm, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(thread); JSHandle set(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(set, ERROR); JSSet::Add(vm->GetJSThread(), set, JSNApiHelper::ToJSHandle(value)); @@ -4105,6 +4439,7 @@ int32_t WeakMapRef::GetTotalElements() Local WeakMapRef::GetKey(const EcmaVM *vm, int entry) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); JSHandle weakMap(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(weakMap, FATAL); JSTaggedValue key = weakMap->GetKey(entry); @@ -4122,6 +4457,7 @@ Local WeakMapRef::GetValue(const EcmaVM *vm, int entry) Local WeakMapRef::New(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); ObjectFactory *factory = vm->GetJSThread()->GetEcmaVM()->GetFactory(); JSHandle env = vm->GetJSThread()->GetEcmaVM()->GetGlobalEnv(); JSHandle constructor = env->GetBuiltinsWeakMapFunction(); @@ -4136,6 +4472,7 @@ Local WeakMapRef::New(const EcmaVM *vm) void WeakMapRef::Set(const EcmaVM *vm, const Local &key, const Local &value) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(thread); JSHandle weakMap(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(weakMap, FATAL); JSWeakMap::Set(vm->GetJSThread(), weakMap, JSNApiHelper::ToJSHandle(key), JSNApiHelper::ToJSHandle(value)); @@ -4145,6 +4482,7 @@ bool WeakMapRef::Has(const EcmaVM *vm, Local key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); DCHECK_SPECIAL_VALUE_WITH_RETURN(this, false); + ecmascript::ThreadManagedScope managedScope(thread); JSHandle weakMap(JSNApiHelper::ToJSHandle(this)); return weakMap->Has(thread, JSNApiHelper::ToJSTaggedValue(*key)); } @@ -4168,6 +4506,7 @@ int32_t WeakSetRef::GetTotalElements() Local WeakSetRef::GetValue(const EcmaVM *vm, int entry) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); JSHandle weakSet(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(weakSet, FATAL); JSTaggedValue value = weakSet->GetValue(entry); @@ -4177,6 +4516,7 @@ Local WeakSetRef::GetValue(const EcmaVM *vm, int entry) Local WeakSetRef::New(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); ObjectFactory *factory = vm->GetJSThread()->GetEcmaVM()->GetFactory(); JSHandle env = vm->GetJSThread()->GetEcmaVM()->GetGlobalEnv(); JSHandle constructor = env->GetBuiltinsSetFunction(); @@ -4191,6 +4531,7 @@ Local WeakSetRef::New(const EcmaVM *vm) void WeakSetRef::Add(const EcmaVM *vm, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(thread); JSHandle weakSet(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(weakSet, ERROR); JSWeakSet::Add(vm->GetJSThread(), weakSet, JSNApiHelper::ToJSHandle(value)); @@ -4210,11 +4551,13 @@ void TryCatch::Rethrow() Local TryCatch::GetAndClearException() { + ecmascript::ThreadManagedScope managedScope(ecmaVm_->GetJSThread()); return JSNApiHelper::ToLocal(ecmaVm_->GetAndClearEcmaUncaughtException()); } Local TryCatch::GetException() { + ecmascript::ThreadManagedScope managedScope(ecmaVm_->GetJSThread()); return JSNApiHelper::ToLocal(ecmaVm_->GetEcmaUncaughtException()); } diff --git a/ecmascript/napi/test/BUILD.gn b/ecmascript/napi/test/BUILD.gn index dbf81a4bd238c8e637556bd76b66297cabe10a0d..57c990ea790b8685ef20929184bbf16c3bd6764e 100644 --- a/ecmascript/napi/test/BUILD.gn +++ b/ecmascript/napi/test/BUILD.gn @@ -146,6 +146,28 @@ host_unittest_action("Jsnapi_004_Test") { deps += hiviewdfx_deps } +host_unittest_action("Jsnapi_Sendable_Test") { + module_out_path = module_output_path + + sources = [ "jsnapi_sendable_tests.cpp" ] + + configs = [ "../../../:ecma_test_config" ] + + deps = [ + "$ark_third_party_root/icu/icu4c:shared_icui18n", + "$ark_third_party_root/icu/icu4c:shared_icuuc", + "../../../:libark_jsruntime_test", + sdk_libc_secshared_dep, + ] + + foreach(file, test_js_files) { + deps += [ ":gen_${file}_abc" ] + } + + external_deps = hiviewdfx_ext_deps + deps += hiviewdfx_deps +} + host_unittest_action("FFIWorkLoadTest") { module_out_path = module_output_path @@ -199,6 +221,7 @@ group("unittest") { ":Jsnapi_002_Test", ":Jsnapi_003_Test", ":Jsnapi_004_Test", + ":Jsnapi_Sendable_Test", ] } @@ -209,6 +232,7 @@ group("host_unittest") { ":Jsnapi_002_TestAction", ":Jsnapi_003_TestAction", ":Jsnapi_004_TestAction", + ":Jsnapi_Sendable_TestAction", ] if (is_mac) { @@ -217,6 +241,7 @@ group("host_unittest") { ":Jsnapi_002_TestAction", ":Jsnapi_003_TestAction", ":Jsnapi_004_TestAction", + ":Jsnapi_Sendable_TestAction", ] } } diff --git a/ecmascript/napi/test/ffi_workload.cpp b/ecmascript/napi/test/ffi_workload.cpp index 4a06645b65546ed821a634bb8e70719a10269065..ff49a0a7730aad9cc4b6906124df25d7c85d5ed4 100644 --- a/ecmascript/napi/test/ffi_workload.cpp +++ b/ecmascript/napi/test/ffi_workload.cpp @@ -3588,56 +3588,6 @@ HWTEST_F_L0(JSNApiSplTest, JSNApi_SetHostEnqueueJob) TEST_TIME(JSNApi_SetHostEnqueueJob); } -HWTEST_F_L0(JSNApiSplTest, JSNApi_InitializeIcuData) -{ - LocalScope scope(vm_); - CalculateForTime(); - JSRuntimeOptions runtimeOptions; - gettimeofday(&g_beginTime, nullptr); - for (int i = 0; i < NUM_COUNT; i++) { - JSNApi::InitializeIcuData(runtimeOptions); - } - gettimeofday(&g_endTime, nullptr); - TEST_TIME(JSNApi_InitializeIcuData); -} - -HWTEST_F_L0(JSNApiSplTest, JSNApi_InitializePGOProfiler) -{ - LocalScope scope(vm_); - CalculateForTime(); - JSRuntimeOptions runtimeOptions; - gettimeofday(&g_beginTime, nullptr); - for (int i = 0; i < NUM_COUNT; i++) { - JSNApi::InitializePGOProfiler(runtimeOptions); - } - gettimeofday(&g_endTime, nullptr); - TEST_TIME(JSNApi_InitializePGOProfiler); -} - -HWTEST_F_L0(JSNApiSplTest, JSNApi_DestroyAnDataManager) -{ - LocalScope scope(vm_); - CalculateForTime(); - gettimeofday(&g_beginTime, nullptr); - for (int i = 0; i < NUM_COUNT; i++) { - JSNApi::DestroyAnDataManager(); - } - gettimeofday(&g_endTime, nullptr); - TEST_TIME(JSNApi_DestroyAnDataManager); -} - -HWTEST_F_L0(JSNApiSplTest, JSNApi_DestroyPGOProfiler) -{ - LocalScope scope(vm_); - CalculateForTime(); - gettimeofday(&g_beginTime, nullptr); - for (int i = 0; i < NUM_COUNT; i++) { - JSNApi::DestroyPGOProfiler(); - } - gettimeofday(&g_endTime, nullptr); - TEST_TIME(JSNApi_DestroyPGOProfiler); -} - HWTEST_F_L0(JSNApiSplTest, JSValueRef_IsMapIterator_True) { LocalScope scope(vm_); @@ -3905,7 +3855,7 @@ HWTEST_F_L0(JSNApiSplTest, JSValueRef_IsAsyncGeneratorFunction_True) CalculateForTime(); ObjectFactory *factory = vm_->GetFactory(); MethodLiteral *methodLiteral = nullptr; - JSHandle method = factory->NewMethod(methodLiteral); + JSHandle method = factory->NewSMethod(methodLiteral); JSHandle asyncGeneratorFunction = factory->NewJSAsyncGeneratorFunction(method); JSHandle asyncgefu = JSHandle::Cast(asyncGeneratorFunction); Local object = JSNApiHelper::ToLocal(asyncgefu); diff --git a/ecmascript/napi/test/jsnapi_first_tests.cpp b/ecmascript/napi/test/jsnapi_first_tests.cpp index 35f986a9c18a1930622b90978ad13fa53db80870..1116d60362ff5327de76f0bce36966071430477c 100644 --- a/ecmascript/napi/test/jsnapi_first_tests.cpp +++ b/ecmascript/napi/test/jsnapi_first_tests.cpp @@ -57,7 +57,9 @@ #include "ecmascript/tests/test_helper.h" #include "ecmascript/tagged_tree.h" #include "ecmascript/weak_vector.h" +#include "ecmascript/checkpoint/thread_state_transition.h" #include "gtest/gtest.h" +#include "jsnapi_expo.h" using namespace panda; using namespace panda::ecmascript; @@ -87,10 +89,12 @@ public: ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; thread_ = vm_->GetJSThread(); vm_->SetEnableForceGC(true); + thread_->ManagedCodeBegin(); } void TearDown() override { + thread_->ManagedCodeEnd(); vm_->SetEnableForceGC(false); JSNApi::DestroyJSVM(vm_); } @@ -1084,6 +1088,7 @@ HWTEST_F_L0(JSNApiTests, OOMError) HWTEST_F_L0(JSNApiTests, InheritPrototype_001) { + ecmascript::ThreadManagedScope managedScope(vm_->GetJSThread()); LocalScope scope(vm_); JSHandle env = vm_->GetGlobalEnv(); // new with Builtins::Set Prototype @@ -1147,6 +1152,7 @@ HWTEST_F_L0(JSNApiTests, InheritPrototype_001) HWTEST_F_L0(JSNApiTests, InheritPrototype_002) { + ecmascript::ThreadManagedScope managedScope(vm_->GetJSThread()); LocalScope scope(vm_); JSHandle env = vm_->GetGlobalEnv(); // new with Builtins::weakSet Prototype @@ -1181,6 +1187,7 @@ HWTEST_F_L0(JSNApiTests, InheritPrototype_002) HWTEST_F_L0(JSNApiTests, InheritPrototype_003) { + ecmascript::ThreadManagedScope managedScope(vm_->GetJSThread()); LocalScope scope(vm_); JSHandle env = vm_->GetGlobalEnv(); auto factory = vm_->GetFactory(); @@ -1220,6 +1227,7 @@ HWTEST_F_L0(JSNApiTests, InheritPrototype_003) HWTEST_F_L0(JSNApiTests, InheritPrototype_004) { + ecmascript::ThreadManagedScope managedScope(vm_->GetJSThread()); LocalScope scope(vm_); JSHandle env = vm_->GetGlobalEnv(); auto factory = vm_->GetFactory(); @@ -1291,13 +1299,14 @@ HWTEST_F_L0(JSNApiTests, ClassFunction) JSTaggedValue accessor = JSHandle(clsObj)->GetPropertyInlinedProps(JSFunction::CLASS_PROTOTYPE_INLINE_PROPERTY_INDEX); ASSERT_TRUE(accessor.IsInternalAccessor()); - + accessor = JSHandle(clsObj)->GetPropertyInlinedProps(JSFunction::LENGTH_INLINE_PROPERTY_INDEX); ASSERT_TRUE(!accessor.IsUndefinedOrNull()); } HWTEST_F_L0(JSNApiTests, WeakRefSecondPassCallback) { + ecmascript::ThreadManagedScope managedScope(vm_->GetJSThread()); LocalScope scope(vm_); Local object1 = ObjectRef::New(vm_); Global globalObject1(vm_, object1); @@ -1335,6 +1344,7 @@ HWTEST_F_L0(JSNApiTests, WeakRefSecondPassCallback) */ HWTEST_F_L0(JSNApiTests, TriggerGC_OLD_GC) { + ecmascript::ThreadManagedScope managedScope(vm_->GetJSThread()); vm_->SetEnableForceGC(false); auto globalEnv = vm_->GetGlobalEnv(); auto factory = vm_->GetFactory(); @@ -1370,13 +1380,17 @@ HWTEST_F_L0(JSNApiTests, TriggerGC_OLD_GC) */ HWTEST_F_L0(JSNApiTests, addWorker_DeleteWorker) { - JSRuntimeOptions option; - EcmaVM *workerVm = JSNApi::CreateEcmaVM(option); - JSNApi::AddWorker(vm_, workerVm); - bool hasDeleted = JSNApi::DeleteWorker(vm_, workerVm); - EXPECT_TRUE(hasDeleted); - - hasDeleted = JSNApi::DeleteWorker(vm_, nullptr); + std::thread t1([&]() { + JSRuntimeOptions option; + EcmaVM *workerVm = JSNApi::CreateEcmaVM(option); + JSNApi::AddWorker(vm_, workerVm); + bool hasDeleted = JSNApi::DeleteWorker(vm_, workerVm); + JSNApi::DestroyJSVM(workerVm); + EXPECT_TRUE(hasDeleted); + }); + t1.join(); + + bool hasDeleted = JSNApi::DeleteWorker(vm_, nullptr); EXPECT_FALSE(hasDeleted); } @@ -2036,12 +2050,15 @@ HWTEST_F_L0(JSNApiTests, FunctionRef_New_GetFunctionPrototype) HWTEST_F_L0(JSNApiTests, PrintExceptionInfo) { LocalScope scope(vm_); - RuntimeOption option; - option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR); - vm_ = JSNApi::CreateJSVM(option); - ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; - thread_ = vm_->GetJSThread(); - JSNApi::PrintExceptionInfo(vm_); + std::thread t1([&](){ + RuntimeOption option; + option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR); + auto *vm = JSNApi::CreateJSVM(option); + ASSERT_TRUE(vm != nullptr) << "Cannot create Runtime"; + JSNApi::PrintExceptionInfo(vm); + JSNApi::DestroyJSVM(vm); + }); + t1.join(); } /* diff --git a/ecmascript/napi/test/jsnapi_second_tests.cpp b/ecmascript/napi/test/jsnapi_second_tests.cpp index a41da19578238ce7ee84337e515535418780dc81..3a841ef6bb61b37e4782998fc172c44570972c91 100644 --- a/ecmascript/napi/test/jsnapi_second_tests.cpp +++ b/ecmascript/napi/test/jsnapi_second_tests.cpp @@ -17,6 +17,7 @@ #include "ecmascript/builtins/builtins.h" #include "ecmascript/builtins/builtins_function.h" #include "ecmascript/builtins/builtins_object.h" +#include "ecmascript/checkpoint/thread_state_transition.h" #include "ecmascript/compiler/aot_file/an_file_data_manager.h" #include "ecmascript/compiler/aot_file/aot_file_manager.h" #include "ecmascript/compiler/circuit_builder_helper.h" @@ -87,10 +88,12 @@ public: ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; thread_ = vm_->GetJSThread(); vm_->SetEnableForceGC(true); + thread_->ManagedCodeBegin(); } void TearDown() override { + thread_->ManagedCodeEnd(); vm_->SetEnableForceGC(false); JSNApi::DestroyJSVM(vm_); } @@ -216,6 +219,7 @@ HWTEST_F_L0(JSNApiTests, ObjectRef_Freeze) JSHandle env = vm_->GetGlobalEnv(); JSHandle set = env->GetBuiltinsSetFunction(); object->Freeze(vm_); + ecmascript::ThreadManagedScope managedScope(thread_); bool status = JSObject::SetIntegrityLevel(thread_, JSHandle::Cast(set), IntegrityLevel::FROZEN); ASSERT_TRUE(status); } @@ -237,6 +241,7 @@ HWTEST_F_L0(JSNApiTests, ObjectRef_Seal) JSHandle env = vm_->GetGlobalEnv(); JSHandle set = env->GetBuiltinsSetFunction(); object->Seal(vm_); // 尝试将对象封闭 + ecmascript::ThreadManagedScope managedScope(thread_); bool status = JSObject::SetIntegrityLevel(thread_, JSHandle::Cast(set), IntegrityLevel::SEALED); ASSERT_TRUE(status); } @@ -268,6 +273,7 @@ HWTEST_F_L0(JSNApiTests, ObjectRef_GetAllPropertyNames) */ HWTEST_F_L0(JSNApiTests, GetIndex) { + ecmascript::ThreadManagedScope managedScope(vm_->GetJSThread()); LocalScope scope(vm_); JSThread *thread = vm_->GetJSThread(); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); @@ -297,6 +303,7 @@ HWTEST_F_L0(JSNApiTests, GetKind_entries_values_keys) { LocalScope scope(vm_); JSThread *thread = vm_->GetJSThread(); + ecmascript::ThreadManagedScope managedScope(thread); std::string expectedResult = "entries"; std::string valuesResult = "values"; std::string keysResult = "keys"; @@ -336,6 +343,7 @@ HWTEST_F_L0(JSNApiTests, GetKind_entries_values_keys) */ HWTEST_F_L0(JSNApiTests, GetKind_001) { + ecmascript::ThreadManagedScope managedScope(vm_->GetJSThread()); LocalScope scope(vm_); JSThread *thread = vm_->GetJSThread(); std::string keysResult = "keys"; @@ -365,6 +373,7 @@ HWTEST_F_L0(JSNApiTests, GetKind_001) */ HWTEST_F_L0(JSNApiTests, GetKind_002) { + ecmascript::ThreadManagedScope managedScope(vm_->GetJSThread()); LocalScope scope(vm_); JSThread *thread = vm_->GetJSThread(); std::string valuesResult = "values"; @@ -394,6 +403,7 @@ HWTEST_F_L0(JSNApiTests, GetKind_002) */ HWTEST_F_L0(JSNApiTests, GetKind_003) { + ecmascript::ThreadManagedScope managedScope(vm_->GetJSThread()); LocalScope scope(vm_); JSThread *thread = vm_->GetJSThread(); std::string expectedResult = "entries"; diff --git a/ecmascript/napi/test/jsnapi_sendable_tests.cpp b/ecmascript/napi/test/jsnapi_sendable_tests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9bd599006183cff67677feadbbb10bb7ab0b70b0 --- /dev/null +++ b/ecmascript/napi/test/jsnapi_sendable_tests.cpp @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2024 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/napi/jsnapi_helper.h" +#include "ecmascript/tests/test_helper.h" +#include "gtest/gtest.h" + +// index 0 is name/constructor, index 1 is property to test. +static constexpr int INITIAL_PROPERTY_LENGTH = 2; + +using namespace panda::ecmascript; + +namespace panda::test { +class JSNApiTests : public testing::Test { + public: + static void SetUpTestCase() + { + GTEST_LOG_(INFO) << "SetUpTestCase"; + } + + static void TearDownTestCase() + { + GTEST_LOG_(INFO) << "TearDownCase"; + } + + void SetUp() override + { + RuntimeOption option; + option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR); + vm_ = JSNApi::CreateJSVM(option); + ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; + thread_ = vm_->GetJSThread(); + vm_->SetEnableForceGC(true); + thread_->ManagedCodeBegin(); + staticKey = StringRef::NewFromUtf8(vm_, "static"); + nonStaticKey = StringRef::NewFromUtf8(vm_, "nonStatic"); + instanceKey = StringRef::NewFromUtf8(vm_, "instance"); + getterSetterKey = StringRef::NewFromUtf8(vm_, "getterSetter"); + invalidKey = StringRef::NewFromUtf8(vm_, "invalid"); + } + + void TearDown() override + { + thread_->ManagedCodeEnd(); + vm_->SetEnableForceGC(false); + JSNApi::DestroyJSVM(vm_); + } + + template + void TestNumberRef(T val, TaggedType expected) + { + LocalScope scope(vm_); + Local obj = NumberRef::New(vm_, val); + ASSERT_TRUE(obj->IsNumber()); + JSTaggedType res = JSNApiHelper::ToJSTaggedValue(*obj).GetRawData(); + ASSERT_EQ(res, expected); + if constexpr (std::is_floating_point_v) { + if (std::isnan(val)) { + ASSERT_TRUE(std::isnan(obj->Value())); + } else { + ASSERT_EQ(obj->Value(), val); + } + } else if constexpr (sizeof(T) >= sizeof(int32_t)) { + ASSERT_EQ(obj->IntegerValue(vm_), val); + } else if constexpr (std::is_signed_v) { + ASSERT_EQ(obj->Int32Value(vm_), val); + } else { + ASSERT_EQ(obj->Uint32Value(vm_), val); + } + } + + TaggedType ConvertDouble(double val) + { + return base::bit_cast(val) + JSTaggedValue::DOUBLE_ENCODE_OFFSET; + } + + protected: + JSThread *thread_ = nullptr; + EcmaVM *vm_ = nullptr; + Local staticKey; + Local nonStaticKey; + Local instanceKey; + Local getterSetterKey; + Local invalidKey; +}; + +panda::JSValueRef FunctionCallback(JsiRuntimeCallInfo *info) +{ + EcmaVM *vm = info->GetVM(); + Local jsThisRef = info->GetThisRef(); + Local thisRef = jsThisRef->ToObject(vm); + return **thisRef; +} + +Local GetNewSendableClassFunction( + EcmaVM *vm, const char *instanceKey, const char *staticKey, const char *nonStaticKey, Local parent) +{ + Local instanceKeys = panda::ArrayRef::New(vm, 1); + Local instanceValues = panda::ArrayRef::New(vm, 1); + PropertyAttribute *instanceAttributes = new PropertyAttribute[1]; + // index 0 is name + Local staticKeys = panda::ArrayRef::New(vm, INITIAL_PROPERTY_LENGTH); + Local staticValues = panda::ArrayRef::New(vm, INITIAL_PROPERTY_LENGTH); + PropertyAttribute *staticAttributes = new PropertyAttribute[INITIAL_PROPERTY_LENGTH]; + // index 0 is constructor + Local nonStaticKeys = panda::ArrayRef::New(vm, INITIAL_PROPERTY_LENGTH); + Local nonStaticValues = panda::ArrayRef::New(vm, INITIAL_PROPERTY_LENGTH); + PropertyAttribute *nonStaticAttributes = new PropertyAttribute[INITIAL_PROPERTY_LENGTH]; + + Local instanceStr = StringRef::NewFromUtf8(vm, instanceKey); + instanceKeys->Set(vm, 0, instanceStr); + instanceValues->Set(vm, 0, instanceStr); + instanceAttributes[0] = PropertyAttribute(instanceStr, true, true, true); + + Local staticStr = StringRef::NewFromUtf8(vm, staticKey); + staticKeys->Set(vm, 1, staticStr); + staticValues->Set(vm, 1, staticStr); + staticAttributes[1] = PropertyAttribute(staticStr, true, true, true); + + Local nonStaticStr = StringRef::NewFromUtf8(vm, nonStaticKey); + nonStaticKeys->Set(vm, 1, nonStaticStr); + nonStaticValues->Set(vm, 1, nonStaticStr); + nonStaticAttributes[1] = PropertyAttribute(nonStaticStr, true, true, true); + + Local nameStr = StringRef::NewFromUtf8(vm, "name"); + Local constructor = + FunctionRef::NewSendableClassFunction(vm, FunctionCallback, nullptr, nullptr, nameStr, + {{instanceKeys, instanceValues, instanceAttributes}, + {staticKeys, staticValues, staticAttributes}, + {nonStaticKeys, nonStaticValues, nonStaticAttributes}}, + parent); + + return constructor; +} + +HWTEST_F_L0(JSNApiTests, NewSendableClassFunction) +{ + LocalScope scope(vm_); + Local constructor = + GetNewSendableClassFunction(vm_, "instance", "static", "nonStatic", FunctionRef::Null(vm_)); + + ASSERT_EQ("name", constructor->GetName(vm_)->ToString()); + ASSERT_TRUE(constructor->IsFunction()); + JSHandle jsConstructor = JSNApiHelper::ToJSHandle(constructor); + ASSERT_TRUE(jsConstructor->IsClassConstructor()); + + Local prototype = constructor->GetFunctionPrototype(vm_); + ASSERT_TRUE(prototype->IsObject()); + JSHandle jsPrototype = JSNApiHelper::ToJSHandle(prototype); + ASSERT_TRUE(jsPrototype->IsClassPrototype()); +} + +HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionProperties) +{ + LocalScope scope(vm_); + Local constructor = + GetNewSendableClassFunction(vm_, "instance", "static", "nonStatic", FunctionRef::Null(vm_)); + Local prototype = constructor->GetFunctionPrototype(vm_); + + ASSERT_EQ("static", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString()); + ASSERT_EQ("nonStatic", prototype->Get(vm_, nonStaticKey)->ToString(vm_)->ToString()); + ASSERT_EQ("undefined", constructor->Get(vm_, invalidKey)->ToString(vm_)->ToString()); + ASSERT_EQ("undefined", prototype->Get(vm_, invalidKey)->ToString(vm_)->ToString()); + + // set static property on constructor + constructor->Set(vm_, staticKey, StringRef::NewFromUtf8(vm_, "static0")); + ASSERT_EQ("static0", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString()); + + // set non static property on prototype + prototype->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic0")); + ASSERT_EQ("nonStatic0", prototype->Get(vm_, nonStaticKey)->ToString(vm_)->ToString()); + + // set invalid property on constructor + ASSERT_FALSE(vm_->GetJSThread()->HasPendingException()); + constructor->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid")); + ASSERT_TRUE(vm_->GetJSThread()->HasPendingException()); + JSNApi::GetAndClearUncaughtException(vm_); + ASSERT_EQ("undefined", constructor->Get(vm_, invalidKey)->ToString(vm_)->ToString()); + + // set invalid property on prototype + ASSERT_FALSE(vm_->GetJSThread()->HasPendingException()); + prototype->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid")); + ASSERT_TRUE(vm_->GetJSThread()->HasPendingException()); + JSNApi::GetAndClearUncaughtException(vm_); + ASSERT_EQ("undefined", prototype->Get(vm_, invalidKey)->ToString(vm_)->ToString()); +} + +HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionInstance) +{ + LocalScope scope(vm_); + Local constructor = + GetNewSendableClassFunction(vm_, "instance", "static", "nonStatic", FunctionRef::Null(vm_)); + Local argv[1] = {NumberRef::New(vm_, 0)}; + Local obj = constructor->Constructor(vm_, argv, 0); + Local obj0 = constructor->Constructor(vm_, argv, 0); + + ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(constructor))); + ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj0), JSNApiHelper::ToJSHandle(constructor))); + + // set instance property + ASSERT_EQ("undefined", obj->Get(vm_, instanceKey)->ToString(vm_)->ToString()); + ASSERT_EQ("undefined", obj0->Get(vm_, instanceKey)->ToString(vm_)->ToString()); + obj->Set(vm_, instanceKey, StringRef::NewFromUtf8(vm_, "instance")); + ASSERT_EQ("instance", obj->Get(vm_, instanceKey)->ToString(vm_)->ToString()); + ASSERT_EQ("undefined", obj0->Get(vm_, instanceKey)->ToString(vm_)->ToString()); + + // set non static property on prototype and get from instance + ASSERT_EQ("nonStatic", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString()); + ASSERT_EQ("nonStatic", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString()); + Local prototype = obj->GetPrototype(vm_); + prototype->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic0")); + ASSERT_EQ("nonStatic0", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString()); + ASSERT_EQ("nonStatic0", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString()); + + // set non static property on instance + ASSERT_FALSE(vm_->GetJSThread()->HasPendingException()); + obj->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic1")); + ASSERT_TRUE(vm_->GetJSThread()->HasPendingException()); + JSNApi::GetAndClearUncaughtException(vm_); + ASSERT_EQ("nonStatic0", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString()); + ASSERT_EQ("nonStatic0", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString()); + + // set invalid property on instance + ASSERT_EQ("undefined", obj->Get(vm_, invalidKey)->ToString(vm_)->ToString()); + ASSERT_FALSE(vm_->GetJSThread()->HasPendingException()); + obj->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid")); + ASSERT_TRUE(vm_->GetJSThread()->HasPendingException()); + JSNApi::GetAndClearUncaughtException(vm_); + ASSERT_EQ("undefined", obj->Get(vm_, invalidKey)->ToString(vm_)->ToString()); +} + +HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionInherit) +{ + LocalScope scope(vm_); + Local parent = + GetNewSendableClassFunction(vm_, "parentInstance", "parentStatic", "parentNonStatic", FunctionRef::Null(vm_)); + Local constructor = GetNewSendableClassFunction(vm_, "instance", "static", "nonStatic", parent); + Local argv[1] = {NumberRef::New(vm_, 0)}; + Local obj = constructor->Constructor(vm_, argv, 0); + Local obj0 = constructor->Constructor(vm_, argv, 0); + + ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(parent))); + ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj0), JSNApiHelper::ToJSHandle(parent))); + + // set parent instance property on instance + Local parentInstanceKey = StringRef::NewFromUtf8(vm_, "parentInstance"); + ASSERT_EQ("undefined", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString()); + ASSERT_FALSE(vm_->GetJSThread()->HasPendingException()); + obj->Set(vm_, parentInstanceKey, StringRef::NewFromUtf8(vm_, "parentInstance")); + ASSERT_TRUE(vm_->GetJSThread()->HasPendingException()); + JSNApi::GetAndClearUncaughtException(vm_); + ASSERT_EQ("undefined", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString()); + + // get parent static property from constructor + Local parentStaticKey = StringRef::NewFromUtf8(vm_, "parentStatic"); + ASSERT_EQ("parentStatic", constructor->Get(vm_, parentStaticKey)->ToString(vm_)->ToString()); + + // get parent non static property form instance + Local parentNonStaticKey = StringRef::NewFromUtf8(vm_, "parentNonStatic"); + ASSERT_EQ("parentNonStatic", obj->Get(vm_, parentNonStaticKey)->ToString(vm_)->ToString()); +} + +HWTEST_F_L0(JSNApiTests, NewSendable) +{ + LocalScope scope(vm_); + Local func = FunctionRef::NewSendable( + vm_, + [](JsiRuntimeCallInfo *runtimeInfo) -> JSValueRef { + EcmaVM *vm = runtimeInfo->GetVM(); + LocalScope scope(vm); + return **StringRef::NewFromUtf8(vm, "funcResult"); + }, + nullptr); + Local res = func->Call(vm_, JSValueRef::Undefined(vm_), nullptr, 0); + ASSERT_EQ("funcResult", res->ToString(vm_)->ToString()); +} + +HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionFunction) +{ + LocalScope scope(vm_); + + Local instanceKeys = panda::ArrayRef::New(vm_, 0); + Local instanceValues = panda::ArrayRef::New(vm_, 0); + PropertyAttribute *instanceAttributes = new PropertyAttribute[0]; + // index 0 is name + Local staticKeys = panda::ArrayRef::New(vm_, INITIAL_PROPERTY_LENGTH); + Local staticValues = panda::ArrayRef::New(vm_, INITIAL_PROPERTY_LENGTH); + PropertyAttribute *staticAttributes = new PropertyAttribute[INITIAL_PROPERTY_LENGTH]; + // index 0 is constructor + Local nonStaticKeys = panda::ArrayRef::New(vm_, 1); + Local nonStaticValues = panda::ArrayRef::New(vm_, 1); + PropertyAttribute *nonStaticAttributes = new PropertyAttribute[1]; + + Local func = FunctionRef::NewSendable( + vm_, + [](JsiRuntimeCallInfo *runtimeInfo) -> JSValueRef { + EcmaVM *vm = runtimeInfo->GetVM(); + LocalScope scope(vm); + return **StringRef::NewFromUtf8(vm, "funcResult"); + }, + nullptr); + staticKeys->Set(vm_, 1, staticKey); + staticValues->Set(vm_, 1, func); + staticAttributes[1] = PropertyAttribute(func, true, true, true); + + Local constructor = FunctionRef::NewSendableClassFunction( + vm_, FunctionCallback, nullptr, nullptr, StringRef::NewFromUtf8(vm_, "name"), + {{instanceKeys, instanceValues, instanceAttributes}, + {staticKeys, staticValues, staticAttributes}, + {nonStaticKeys, nonStaticValues, nonStaticAttributes}}, + FunctionRef::Null(vm_)); + + Local staticValue = constructor->Get(vm_, staticKey); + ASSERT_TRUE(staticValue->IsFunction()); + Local res = staticValue->Call(vm_, JSValueRef::Undefined(vm_), nullptr, 0); + ASSERT_EQ("funcResult", res->ToString(vm_)->ToString()); +} + +HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionGetterSetter) +{ + LocalScope scope(vm_); + + Local instanceKeys = panda::ArrayRef::New(vm_, 0); + Local instanceValues = panda::ArrayRef::New(vm_, 0); + PropertyAttribute *instanceAttributes = new PropertyAttribute[0]; + // index 0 is name + Local staticKeys = panda::ArrayRef::New(vm_, 3); + Local staticValues = panda::ArrayRef::New(vm_, 3); + PropertyAttribute *staticAttributes = new PropertyAttribute[3]; + // index 0 is constructor + Local nonStaticKeys = panda::ArrayRef::New(vm_, 1); + Local nonStaticValues = panda::ArrayRef::New(vm_, 1); + PropertyAttribute *nonStaticAttributes = new PropertyAttribute[1]; + + Local getterSetter = StringRef::NewFromUtf8(vm_, "getterSetter"); + staticKeys->Set(vm_, 1, getterSetter); + staticValues->Set(vm_, 1, getterSetter); + staticAttributes[1] = PropertyAttribute(getterSetter, true, true, true); + Local staticGetter = FunctionRef::NewSendable( + vm_, + [](JsiRuntimeCallInfo *info) -> JSValueRef { + Local value = info->GetThisRef(); + Local obj = value->ToObject(info->GetVM()); + Local temp = obj->Get(info->GetVM(), StringRef::NewFromUtf8(info->GetVM(), "getterSetter")); + return **temp->ToString(info->GetVM()); + }, + nullptr); + Local staticSetter = FunctionRef::NewSendable( + vm_, + [](JsiRuntimeCallInfo *info) -> JSValueRef { + Local arg = info->GetCallArgRef(0); + Local value = info->GetThisRef(); + Local obj = value->ToObject(info->GetVM()); + obj->Set(info->GetVM(), StringRef::NewFromUtf8(info->GetVM(), "getterSetter"), arg); + return **JSValueRef::Undefined(info->GetVM()); + }, + nullptr); + Local staticValue = panda::ObjectRef::CreateSendableAccessorData(vm_, staticGetter, staticSetter); + staticKeys->Set(vm_, 2, staticKey); + staticValues->Set(vm_, 2, staticValue); + staticAttributes[2] = PropertyAttribute(staticValue, true, true, true); + + Local constructor = FunctionRef::NewSendableClassFunction( + vm_, FunctionCallback, nullptr, nullptr, StringRef::NewFromUtf8(vm_, "name"), + {{instanceKeys, instanceValues, instanceAttributes}, + {staticKeys, staticValues, staticAttributes}, + {nonStaticKeys, nonStaticValues, nonStaticAttributes}}, + FunctionRef::Null(vm_)); + + ASSERT_EQ("getterSetter", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString()); + constructor->Set(vm_, staticKey, StringRef::NewFromUtf8(vm_, "getterSetter0")); + ASSERT_EQ("getterSetter0", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString()); +} + +} // namespace panda::test diff --git a/ecmascript/napi/test/jsnapi_third_tests.cpp b/ecmascript/napi/test/jsnapi_third_tests.cpp index 30823e0747b2f9a1e565bb665dd42557ee243a50..dbdbb4dc05ab2b48cc620182882d9211e7925c5d 100644 --- a/ecmascript/napi/test/jsnapi_third_tests.cpp +++ b/ecmascript/napi/test/jsnapi_third_tests.cpp @@ -17,6 +17,7 @@ #include "ecmascript/builtins/builtins.h" #include "ecmascript/builtins/builtins_function.h" #include "ecmascript/builtins/builtins_object.h" +#include "ecmascript/checkpoint/thread_state_transition.h" #include "ecmascript/compiler/aot_file/an_file_data_manager.h" #include "ecmascript/compiler/aot_file/aot_file_manager.h" #include "ecmascript/compiler/circuit_builder_helper.h" @@ -87,10 +88,12 @@ public: ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; thread_ = vm_->GetJSThread(); vm_->SetEnableForceGC(true); + thread_->ManagedCodeBegin(); } void TearDown() override { + thread_->ManagedCodeEnd(); vm_->SetEnableForceGC(false); JSNApi::DestroyJSVM(vm_); } @@ -356,14 +359,17 @@ HWTEST_F_L0(JSNApiTests, JSNApi_SwitchCurrentContext_DestroyJSContext) HWTEST_F_L0(JSNApiTests, JSNApi_CreateJSVM_DestroyJSVM) { LocalScope scope(vm_); - EcmaVM *vm1_ = nullptr; - RuntimeOption option; - option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR); - vm1_ = JSNApi::CreateJSVM(option); - ASSERT_TRUE(vm1_ != nullptr) << "Cannot create Runtime"; - vm1_->SetEnableForceGC(true); - vm1_->SetEnableForceGC(false); - JSNApi::DestroyJSVM(vm1_); + std::thread t1([&](){ + EcmaVM *vm1_ = nullptr; + RuntimeOption option; + option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR); + vm1_ = JSNApi::CreateJSVM(option); + ASSERT_TRUE(vm1_ != nullptr) << "Cannot create Runtime"; + vm1_->SetEnableForceGC(true); + vm1_->SetEnableForceGC(false); + JSNApi::DestroyJSVM(vm1_); + }); + t1.join(); } /** @@ -597,10 +603,16 @@ HWTEST_F_L0(JSNApiTests, Is32Arraytest) HWTEST_F_L0(JSNApiTests, SynchronizVMInfo) { LocalScope scope(vm_); - JSRuntimeOptions option; - EcmaVM *hostVM = JSNApi::CreateEcmaVM(option); - LocalScope scope2(hostVM); - JSNApi::SynchronizVMInfo(vm_, hostVM); + std::thread t1([&]() { + JSRuntimeOptions option; + EcmaVM *hostVM = JSNApi::CreateEcmaVM(option); + { + LocalScope scope2(hostVM); + JSNApi::SynchronizVMInfo(vm_, hostVM); + } + JSNApi::DestroyJSVM(hostVM); + }); + t1.join(); } /* @@ -724,6 +736,7 @@ HWTEST_F_L0(JSNApiTests, PreFork) HWTEST_F_L0(JSNApiTests, PostFork) { RuntimeOption option; + ecmascript::ThreadNativeScope nativeScope(vm_->GetJSThread()); LocalScope scope(vm_); JSNApi::PostFork(vm_, option); } @@ -1070,4 +1083,4 @@ HWTEST_F_L0(JSNApiTests, NewObjectWithNamedPropertiesDuplicate) EXPECT_TRUE(obj.GetTaggedValue() == JSTaggedValue::Undefined()); thread_->ClearException(); } -} // namespace panda::test \ No newline at end of file +} // namespace panda::test diff --git a/ecmascript/object_factory-inl.h b/ecmascript/object_factory-inl.h index b2246285101750c4a7ab976b680bd5db701c9965..a18394773f21181cc7e6ca39b633d229a3fed628 100644 --- a/ecmascript/object_factory-inl.h +++ b/ecmascript/object_factory-inl.h @@ -23,6 +23,7 @@ #include "ecmascript/lexical_env.h" #include "ecmascript/mem/heap-inl.h" #include "ecmascript/mem/barriers-inl.h" +#include "ecmascript/mem/space.h" #include "ecmascript/object_factory.h" #include "ecmascript/tagged_array-inl.h" @@ -31,9 +32,9 @@ EcmaString *ObjectFactory::AllocLineStringObjectNoGC(size_t size) { TaggedObject *object = nullptr; if (size > MAX_REGULAR_HEAP_OBJECT_SIZE) { - object = reinterpret_cast(heap_->GetHugeObjectSpace()->Allocate(size, thread_)); + object = reinterpret_cast(sHeap_->GetHugeObjectSpace()->Allocate(thread_, size)); } else { - object = reinterpret_cast(heap_->GetOldSpace()->Allocate(size, false)); + object = reinterpret_cast(sHeap_->GetOldSpace()->Allocate(thread_, size, false)); } object->SetClass(thread_, JSHClass::Cast(thread_->GlobalConstants()->GetLineStringClass().GetTaggedObject())); return EcmaString::Cast(object); @@ -41,44 +42,47 @@ EcmaString *ObjectFactory::AllocLineStringObjectNoGC(size_t size) EcmaString *ObjectFactory::AllocNonMovableLineStringObject(size_t size) { - NewObjectHook(); - return reinterpret_cast(heap_->AllocateNonMovableOrHugeObject( - JSHClass::Cast(thread_->GlobalConstants()->GetLineStringClass().GetTaggedObject()), size)); + NewSObjectHook(); + return reinterpret_cast(sHeap_->AllocateNonMovableOrHugeObject( + thread_, JSHClass::Cast(thread_->GlobalConstants()->GetLineStringClass().GetTaggedObject()), size)); } EcmaString *ObjectFactory::AllocLineStringObject(size_t size) { - NewObjectHook(); - return reinterpret_cast(heap_->AllocateYoungOrHugeObject( - JSHClass::Cast(thread_->GlobalConstants()->GetLineStringClass().GetTaggedObject()), size)); + NewSObjectHook(); + return reinterpret_cast(sHeap_->AllocateOldOrHugeObject( + thread_, JSHClass::Cast(thread_->GlobalConstants()->GetLineStringClass().GetTaggedObject()), size)); } EcmaString *ObjectFactory::AllocOldSpaceLineStringObject(size_t size) { - NewObjectHook(); - return reinterpret_cast(heap_->AllocateOldOrHugeObject( - JSHClass::Cast(thread_->GlobalConstants()->GetLineStringClass().GetTaggedObject()), size)); + NewSObjectHook(); + return reinterpret_cast(sHeap_->AllocateOldOrHugeObject( + thread_, JSHClass::Cast(thread_->GlobalConstants()->GetLineStringClass().GetTaggedObject()), size)); } EcmaString *ObjectFactory::AllocSlicedStringObject(MemSpaceType type) { - NewObjectHook(); + ASSERT(IsSMemSpace(type)); + NewSObjectHook(); return reinterpret_cast(AllocObjectWithSpaceType(SlicedString::SIZE, JSHClass::Cast(thread_->GlobalConstants()->GetSlicedStringClass().GetTaggedObject()), type)); } EcmaString *ObjectFactory::AllocConstantStringObject(MemSpaceType type) { - NewObjectHook(); + ASSERT(IsSMemSpace(type)); + NewSObjectHook(); return reinterpret_cast(AllocObjectWithSpaceType(ConstantString::SIZE, JSHClass::Cast(thread_->GlobalConstants()->GetConstantStringClass().GetTaggedObject()), type)); } EcmaString *ObjectFactory::AllocTreeStringObject() { - NewObjectHook(); - return reinterpret_cast(heap_->AllocateYoungOrHugeObject( - JSHClass::Cast(thread_->GlobalConstants()->GetTreeStringClass().GetTaggedObject()), TreeEcmaString::SIZE)); + NewSObjectHook(); + return reinterpret_cast(sHeap_->AllocateOldOrHugeObject( + thread_, JSHClass::Cast(thread_->GlobalConstants()->GetTreeStringClass().GetTaggedObject()), + TreeEcmaString::SIZE)); } JSHandle ObjectFactory::NewJSNativePointer(void *externalPointer, @@ -102,7 +106,7 @@ JSHandle ObjectFactory::NewJSNativePointer(void *externalPointe obj->SetData(data); obj->SetBindingSize(nativeBindingsize); obj->SetNativeFlag(flag); - + if (callBack != nullptr) { heap_->IncreaseNativeBindingSize(nativeBindingsize); vm_->PushToNativePointerList(static_cast(header)); @@ -151,6 +155,10 @@ TaggedObject *ObjectFactory::AllocObjectWithSpaceType(size_t size, JSHClass *cls return heap_->AllocateOldOrHugeObject(cls, size); case MemSpaceType::NON_MOVABLE: return heap_->AllocateNonMovableOrHugeObject(cls, size); + case MemSpaceType::SHARED_OLD_SPACE: + return sHeap_->AllocateOldOrHugeObject(thread_, cls, size); + case MemSpaceType::SHARED_NON_MOVABLE: + return sHeap_->AllocateNonMovableOrHugeObject(thread_, cls, size); default: LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index a29a3eb2c9d6a80daee50c683a0b6f3a25b67a71..a8f0b4d097465626aa884d2ee39ac84cc20bd5b0 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -14,6 +14,7 @@ */ #include "ecmascript/js_function_kind.h" +#include "ecmascript/mem/heap.h" #include "ecmascript/object_factory-inl.h" #include "ecmascript/accessor_data.h" @@ -115,6 +116,7 @@ #include "ecmascript/mem/space.h" #include "ecmascript/module/js_module_namespace.h" #include "ecmascript/module/js_module_source_text.h" +#include "ecmascript/module/js_shared_module.h" #include "ecmascript/object_factory.h" #include "ecmascript/record.h" #include "ecmascript/require/js_cjs_exports.h" @@ -156,15 +158,15 @@ using OOMError = builtins::BuiltinsOOMError; using ErrorType = base::ErrorType; using ErrorHelper = base::ErrorHelper; -ObjectFactory::ObjectFactory(JSThread *thread, Heap *heap) - : thread_(thread), vm_(thread->GetEcmaVM()), heap_(heap) {} +ObjectFactory::ObjectFactory(JSThread *thread, Heap *heap, SharedHeap *sHeap) + : thread_(thread), vm_(thread->GetEcmaVM()), heap_(heap), sHeap_(sHeap) {} JSHandle ObjectFactory::NewMethodForNativeFunction(const void *func, FunctionKind kind, kungfu::BuiltinsStubCSigns::ID builtinId, - MemSpaceType spaceType) + MemSpaceType methodSpaceType) { uint32_t numArgs = 2; // function object and this - auto method = NewMethod(nullptr, spaceType); + auto method = NewSMethod(nullptr, methodSpaceType); method->SetNativePointer(const_cast(func)); method->SetNativeBit(true); if (builtinId != kungfu::BuiltinsStubCSigns::INVALID) { @@ -556,7 +558,7 @@ JSHandle ObjectFactory::CloneProperties(const JSHandle newArray->Set(thread_, i, value); } else { JSHandle valueHandle(thread_, value); - JSHandle newFunc = CloneJSFuction(valueHandle); + JSHandle newFunc = CloneJSFunction(valueHandle); newFunc->SetLexicalEnv(thread_, env); newFunc->SetHomeObject(thread_, obj); newArray->Set(thread_, i, newFunc); @@ -565,7 +567,8 @@ JSHandle ObjectFactory::CloneProperties(const JSHandle return newArray; } -JSHandle ObjectFactory::CloneObjectLiteral(JSHandle object, const JSHandle &env, +JSHandle ObjectFactory::CloneObjectLiteral(JSHandle object, + const JSHandle &env, bool canShareHClass) { NewObjectHook(); @@ -593,7 +596,7 @@ JSHandle ObjectFactory::CloneObjectLiteral(JSHandle object, cloneObject->SetPropertyInlinedPropsWithRep(thread_, i, value); } else { JSHandle valueHandle(thread_, value); - JSHandle newFunc = CloneJSFuction(valueHandle); + JSHandle newFunc = CloneJSFunction(valueHandle); newFunc->SetLexicalEnv(thread_, env); newFunc->SetHomeObject(thread_, cloneObject); cloneObject->SetPropertyInlinedProps(thread_, i, newFunc.GetTaggedValue()); @@ -602,7 +605,7 @@ JSHandle ObjectFactory::CloneObjectLiteral(JSHandle object, return cloneObject; } -JSHandle ObjectFactory::CloneJSFuction(JSHandle func) +JSHandle ObjectFactory::CloneJSFunction(JSHandle func) { JSHandle jshclass(thread_, func->GetJSHClass()); JSHandle method(thread_, func->GetMethod()); @@ -611,11 +614,13 @@ JSHandle ObjectFactory::CloneJSFuction(JSHandle func) JSTaggedValue length = func->GetPropertyInlinedProps(JSFunction::LENGTH_INLINE_PROPERTY_INDEX); cloneFunc->SetPropertyInlinedProps(thread_, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, length); cloneFunc->SetLength(func->GetLength()); + cloneFunc->SetModule(thread_, func->GetModule()); return cloneFunc; } JSHandle ObjectFactory::CloneSFunction(JSHandle func) { + ASSERT(func.GetTaggedValue().IsJSSharedFunction()); JSHandle jshclass(thread_, func->GetJSHClass()); JSHandle method(thread_, func->GetMethod()); JSHandle cloneFunc = NewSFunctionByHClass(method, jshclass); @@ -623,6 +628,7 @@ JSHandle ObjectFactory::CloneSFunction(JSHandle func) JSTaggedValue length = func->GetPropertyInlinedProps(JSFunction::LENGTH_INLINE_PROPERTY_INDEX); cloneFunc->SetPropertyInlinedProps(thread_, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, length); cloneFunc->SetLength(func->GetLength()); + cloneFunc->SetModule(thread_, func->GetModule()); return cloneFunc; } @@ -650,7 +656,7 @@ JSHandle ObjectFactory::CloneClassCtor(JSHandle ctor, co cloneCtor->SetPropertyInlinedPropsWithRep(thread_, i, value); } else { JSHandle valueHandle(thread_, value); - JSHandle newFunc = CloneJSFuction(valueHandle); + JSHandle newFunc = CloneJSFunction(valueHandle); newFunc->SetLexicalEnv(thread_, lexenv); newFunc->SetHomeObject(thread_, cloneCtor); cloneCtor->SetPropertyInlinedProps(thread_, i, newFunc.GetTaggedValue()); @@ -955,14 +961,18 @@ JSHandle ObjectFactory::NewJSObjectByConstructor(const JSHandleGetObjectFunctionPrototype()); } - JSHandle obj = NewJSObjectWithInit(jshclass); - if (jshclass->IsJSSharedObject() && jshclass->IsDictionaryMode()) { - auto maybeDict = jshclass->GetLayout(); - if (maybeDict.IsDictionary()) { - auto dict = JSHandle(thread_, maybeDict); - auto properties = NewAndCopyNameDictionary(dict, dict->GetLength()); + JSHandle obj; + if (jshclass->IsJSSharedObject()) { + obj = NewSharedOldSpaceJSObject(jshclass); + if (jshclass->IsDictionaryMode()) { + auto fieldLayout = jshclass->GetLayout(); + ASSERT(fieldLayout.IsDictionary()); + auto dict = JSHandle(thread_, fieldLayout); + auto properties = NewAndCopySNameDictionary(dict, dict->GetLength()); obj->SetProperties(thread_, properties); } + } else { + obj = NewJSObjectWithInit(jshclass); } return obj; } @@ -987,14 +997,18 @@ JSHandle ObjectFactory::NewJSObjectByConstructor(const JSHandle obj = NewJSObjectWithInit(jshclass); - if (jshclass->IsJSSharedObject() && jshclass->IsDictionaryMode()) { - auto maybeDict = jshclass->GetLayout(); - if (maybeDict.IsDictionary()) { - auto dict = JSHandle(thread_, maybeDict); - auto properties = NewAndCopyNameDictionary(dict, dict->GetLength()); + JSHandle obj; + if (jshclass->IsJSSharedObject()) { + obj = NewSharedOldSpaceJSObject(jshclass); + if (jshclass->IsDictionaryMode()) { + auto fieldLayout = jshclass->GetLayout(); + ASSERT(fieldLayout.IsDictionary()); + auto dict = JSHandle(thread_, fieldLayout); + auto properties = NewAndCopySNameDictionary(dict, dict->GetLength()); obj->SetProperties(thread_, properties); } + } else { + obj = NewJSObjectWithInit(jshclass); } return obj; } @@ -1493,9 +1507,7 @@ FreeObject *ObjectFactory::FillFreeObject(uintptr_t address, size_t size, Remove // For huge object, the region of `object` might not be its 1st region. Use `hugeObjectHead` instead. Region *region = Region::ObjectAddressToRange(hugeObjectHead == 0 ? object : reinterpret_cast(hugeObjectHead)); - if (!region->InYoungSpace()) { - heap_->ClearSlotsRange(region, address, address + size); - } + heap_->ClearSlotsRange(region, address, address + size); } return object; } @@ -1545,25 +1557,11 @@ JSHandle ObjectFactory::OrdinaryNewJSObjectCreate(const JSHandle ObjectFactory::NewSFunction(const JSHandle &env, const void *nativeFunc, - FunctionKind kind, kungfu::BuiltinsStubCSigns::ID builtinId, MemSpaceType spaceType) -{ - JSHandle method = NewMethodForNativeFunction(nativeFunc, kind, builtinId, spaceType); - JSHandle hclass; - if (JSFunction::IsConstructorKind(kind)) { - hclass = JSHandle::Cast(env->GetSConstructorClass()); - } else { - hclass = JSHandle::Cast(env->GetSNormalFunctionClass()); - } - JSHandle sfunc = NewSFunctionByHClass(method, hclass); - return sfunc; -} - JSHandle ObjectFactory::NewJSFunction(const JSHandle &env, const void *nativeFunc, FunctionKind kind, kungfu::BuiltinsStubCSigns::ID builtinId, - MemSpaceType spaceType) + MemSpaceType methodSpaceType) { - JSHandle target = NewMethodForNativeFunction(nativeFunc, kind, builtinId, spaceType); + JSHandle target = NewMethodForNativeFunction(nativeFunc, kind, builtinId, methodSpaceType); return NewJSFunction(env, target); } @@ -1585,6 +1583,18 @@ JSHandle ObjectFactory::NewJSFunction(const JSHandle &env return NewJSFunctionByHClass(method, hclass); } +JSHandle ObjectFactory::NewSFunction(const JSHandle &env, + const void *nativeFunc, + FunctionKind kind, + kungfu::BuiltinsStubCSigns::ID builtinId, + MemSpaceType spaceType) +{ + JSHandle method = NewSMethodForNativeFunction(nativeFunc, kind, builtinId, spaceType); + JSHandle hclass = JSHandle::Cast(env->GetSFunctionClassWithoutProto()); + JSHandle sfunc = NewSFunctionByHClass(method, hclass); + return sfunc; +} + JSHandle ObjectFactory::CreateFunctionClass(FunctionKind kind, uint32_t size, JSType type, const JSHandle &prototype) { @@ -1738,22 +1748,6 @@ JSHandle ObjectFactory::CreateDefaultClassConstructorHClass(JSHClass * return defaultHclass; } -JSHandle ObjectFactory::NewSFunctionByHClass(const JSHandle &method, - const JSHandle &hclass) -{ - JSHandle function(NewOldSpaceJSObject(hclass)); - JSFunction::InitializeJSFunction(thread_, function, method->GetFunctionKind()); - function->SetMethod(thread_, method); - return function; -} - -JSHandle ObjectFactory::NewSFunctionByHClass(const void *func, const JSHandle &hclass, - FunctionKind kind) -{ - JSHandle method = NewMethodForNativeFunction(func, kind); - return NewSFunctionByHClass(method, hclass); -} - JSHandle ObjectFactory::NewJSFunctionByHClass(const JSHandle &method, const JSHandle &clazz, MemSpaceType type) @@ -1777,6 +1771,10 @@ JSHandle ObjectFactory::NewJSFunctionByHClass(const JSHandle clazz->SetExtensible(true); JSFunction::InitializeJSFunction(thread_, function, method->GetFunctionKind()); function->SetMethod(thread_, method); + if (method->IsAotWithCallField()) { + thread_->GetEcmaVM()->GetAOTFileManager()-> + SetAOTFuncEntry(method->GetJSPandaFile(), *function, *method); + } return function; } @@ -1792,18 +1790,8 @@ JSHandle ObjectFactory::NewJSFunctionByHClass(const void *func, cons return function; } -JSHandle ObjectFactory::NewMethod(const MethodLiteral *methodLiteral, MemSpaceType spaceType) +void ObjectFactory::InitializeMethod(const MethodLiteral *methodLiteral, JSHandle &method) { - NewObjectHook(); - TaggedObject *header = nullptr; - if (spaceType == NON_MOVABLE) { - header = heap_->AllocateNonMovableOrHugeObject( - JSHClass::Cast(thread_->GlobalConstants()->GetMethodClass().GetTaggedObject())); - } else { - header = heap_->AllocateOldOrHugeObject( - JSHClass::Cast(thread_->GlobalConstants()->GetMethodClass().GetTaggedObject())); - } - JSHandle method(thread_, header); if (methodLiteral != nullptr) { method->SetCallField(methodLiteral->GetCallField()); method->SetLiteralInfo(methodLiteral->GetLiteralInfo()); @@ -1817,15 +1805,27 @@ JSHandle ObjectFactory::NewMethod(const MethodLiteral *methodLiteral, Me } method->SetCodeEntryOrLiteral(reinterpret_cast(methodLiteral)); method->SetConstantPool(thread_, JSTaggedValue::Undefined()); - method->SetProfileTypeInfo(thread_, JSTaggedValue::Undefined()); - method->SetModule(thread_, JSTaggedValue::Undefined()); - method->SetMachineCode(thread_, JSTaggedValue::Undefined()); +} + +JSHandle ObjectFactory::NewMethod(const MethodLiteral *methodLiteral, MemSpaceType spaceType) +{ + NewObjectHook(); + TaggedObject *header = nullptr; + if (spaceType == NON_MOVABLE) { + header = heap_->AllocateNonMovableOrHugeObject( + JSHClass::Cast(thread_->GlobalConstants()->GetMethodClass().GetTaggedObject())); + } else { + header = heap_->AllocateOldOrHugeObject( + JSHClass::Cast(thread_->GlobalConstants()->GetMethodClass().GetTaggedObject())); + } + JSHandle method(thread_, header); + InitializeMethod(methodLiteral, method); return method; } JSHandle ObjectFactory::NewMethod(const JSPandaFile *jsPandaFile, MethodLiteral *methodLiteral, - JSHandle constpool, JSHandle module, - uint32_t entryIndex, bool needSetAotFlag, bool *canFastCall) + JSHandle constpool, uint32_t entryIndex, + bool needSetAotFlag, bool *canFastCall) { JSHandle method; if (jsPandaFile->IsNewVersion()) { @@ -1834,12 +1834,9 @@ JSHandle ObjectFactory::NewMethod(const JSPandaFile *jsPandaFile, Method method = NewMethod(methodLiteral); method->SetConstantPool(thread_, constpool); } - if (method->GetModule().IsUndefined()) { - method->SetModule(thread_, module); - } if (needSetAotFlag) { thread_->GetEcmaVM()->GetAOTFileManager()-> - SetAOTFuncEntry(jsPandaFile, *method, entryIndex, canFastCall); + SetAOTFuncEntry(jsPandaFile, nullptr, *method, entryIndex, canFastCall); } else { method->ClearAOTFlagsWhenInit(); } @@ -1893,7 +1890,7 @@ JSHandle ObjectFactory::NewJSBoundFunction(const JSHandleSetBoundTarget(thread_, target); bundleFunction->SetBoundThis(thread_, boundThis); bundleFunction->SetBoundArguments(thread_, args); - + if (target.GetTaggedValue().IsConstructor()) { bundleFunction->SetConstructor(true); } @@ -2371,28 +2368,6 @@ JSHandle ObjectFactory::NewJSRealm() return realm; } -JSHandle ObjectFactory::NewEmptyArray() -{ - NewObjectHook(); - auto header = heap_->AllocateReadOnlyOrHugeObject( - JSHClass::Cast(thread_->GlobalConstants()->GetArrayClass().GetTaggedObject()), TaggedArray::SIZE); - JSHandle array(thread_, header); - array->SetLength(0); - array->SetExtraLength(0); - return array; -} - -JSHandle ObjectFactory::NewEmptyMutantArray() -{ - NewObjectHook(); - auto header = heap_->AllocateReadOnlyOrHugeObject( - JSHClass::Cast(thread_->GlobalConstants()->GetMutantTaggedArrayClass().GetTaggedObject()), TaggedArray::SIZE); - JSHandle array(thread_, header); - array->SetLength(0); - array->SetExtraLength(0); - return array; -} - JSHandle ObjectFactory::NewTaggedArray(uint32_t length, JSTaggedValue initVal, bool nonMovable) { if (nonMovable) { @@ -2421,6 +2396,12 @@ JSHandle ObjectFactory::NewTaggedArray(uint32_t length, JSTaggedVal case MemSpaceType::NON_MOVABLE: header = heap_->AllocateNonMovableOrHugeObject(arrayClass, size); break; + case MemSpaceType::SHARED_OLD_SPACE: + header = sHeap_->AllocateOldOrHugeObject(thread_, arrayClass, size); + break; + case MemSpaceType::SHARED_NON_MOVABLE: + header = sHeap_->AllocateNonMovableOrHugeObject(thread_, arrayClass, size); + break; default: LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); @@ -2440,16 +2421,8 @@ JSHandle ObjectFactory::NewAndCopyTaggedArray(JSHandle if (newLength == 0) { return dstElements; } - if (dstElements->IsYoungAndNotMarking(thread_)) { - size_t size = oldLength * sizeof(JSTaggedType); - if (memcpy_s(reinterpret_cast(dstElements->GetData()), size, - reinterpret_cast(srcElements->GetData() + k), size) != EOK) { - LOG_FULL(FATAL) << "memcpy_s failed"; - } - } else { - for (uint32_t i = 0; i < oldLength; i++) { - dstElements->Set(thread_, i, srcElements->Get(i + k)); - } + for (uint32_t i = 0; i < oldLength; i++) { + dstElements->Set(thread_, i, srcElements->Get(i + k)); } for (uint32_t i = oldLength; i < newLength; i++) { dstElements->Set(thread_, i, JSTaggedValue::Hole()); @@ -2457,22 +2430,14 @@ JSHandle ObjectFactory::NewAndCopyTaggedArray(JSHandle return dstElements; } -JSHandle ObjectFactory::NewAndCopyNameDictionary(JSHandle &srcElements, uint32_t length) +JSHandle ObjectFactory::NewAndCopySNameDictionary(JSHandle &srcElements, uint32_t length) { - JSHandle dstElements = NewDictionaryArray(length); + JSHandle dstElements = NewSDictionaryArray(length); if (length == 0) { return dstElements; } - if (dstElements->IsYoungAndNotMarking(thread_)) { - size_t size = length * sizeof(JSTaggedType); - if (memcpy_s(reinterpret_cast(dstElements->GetData()), size, - reinterpret_cast(srcElements->GetData()), size) != EOK) { - LOG_FULL(FATAL) << "memcpy_s failed"; - } - } else { - for (uint32_t i = 0; i < length; i++) { - dstElements->Set(thread_, i, srcElements->Get(i)); - } + for (uint32_t i = 0; i < length; i++) { + dstElements->Set(thread_, i, srcElements->Get(i)); } return dstElements; } @@ -2507,16 +2472,9 @@ JSHandle ObjectFactory::NewAndCopyTaggedArrayByObject(JSHandleIsYoungAndNotMarking(thread_)) { - size_t size = oldLength * sizeof(JSTaggedType); - if (memcpy_s(reinterpret_cast(dstElements->GetData()), size, - reinterpret_cast(srcElements->GetData() + k), size) != EOK) { - LOG_FULL(FATAL) << "memcpy_s failed"; - } - } else { - for (uint32_t i = 0; i < oldLength; i++) { - dstElements->Set(thread_, i, ElementAccessor::Get(thisObjHandle, i + k)); - } + + for (uint32_t i = 0; i < oldLength; i++) { + dstElements->Set(thread_, i, ElementAccessor::Get(thisObjHandle, i + k)); } for (uint32_t i = oldLength; i < newLength; i++) { dstElements->Set(thread_, i, JSTaggedValue::Hole()); @@ -2535,19 +2493,11 @@ JSHandle ObjectFactory::NewAndCopyMutantTaggedArrayByObject(J if (newLength == 0) { return dstElements; } - if (dstElements->IsYoungAndNotMarking(thread_)) { - size_t size = oldLength * sizeof(JSTaggedType); - if (memcpy_s(reinterpret_cast(dstElements->GetData()), size, - reinterpret_cast(srcElements->GetData() + k), size) != EOK) { - LOG_FULL(FATAL) << "memcpy_s failed"; - } - } else { - for (uint32_t i = 0; i < oldLength; i++) { - ElementsKind kind = thisObjHandle->GetClass()->GetElementsKind(); - JSTaggedValue value = JSTaggedValue(ElementAccessor::ConvertTaggedValueWithElementsKind( - ElementAccessor::Get(thisObjHandle, i + k), kind)); - dstElements->Set(thread_, i, value); - } + for (uint32_t i = 0; i < oldLength; i++) { + ElementsKind kind = thisObjHandle->GetClass()->GetElementsKind(); + JSTaggedValue value = JSTaggedValue(ElementAccessor::ConvertTaggedValueWithElementsKind( + ElementAccessor::Get(thisObjHandle, i + k), kind)); + dstElements->Set(thread_, i, value); } for (uint32_t i = oldLength; i < newLength; i++) { ElementsKind kind = thisObjHandle->GetClass()->GetElementsKind(); @@ -3012,7 +2962,7 @@ JSHandle ObjectFactory::GetStringFromStringTable(const uint8_t *utf8 return GetEmptyString(); } auto stringTable = vm_->GetEcmaStringTable(); - return JSHandle(thread_, stringTable->GetOrInternString(utf8Data, utf8Len, canBeCompress)); + return JSHandle(thread_, stringTable->GetOrInternString(vm_, utf8Data, utf8Len, canBeCompress)); } JSHandle ObjectFactory::GetCompressedSubStringFromStringTable(const JSHandle &string, @@ -3023,7 +2973,7 @@ JSHandle ObjectFactory::GetCompressedSubStringFromStringTable(const return GetEmptyString(); } auto *stringTable = vm_->GetEcmaStringTable(); - return JSHandle(thread_, stringTable->GetOrInternCompressedSubString(string, offset, utf8Len)); + return JSHandle(thread_, stringTable->GetOrInternCompressedSubString(vm_, string, offset, utf8Len)); } JSHandle ObjectFactory::GetStringFromStringTableNonMovable(const uint8_t *utf8Data, uint32_t utf8Len) const @@ -3033,7 +2983,7 @@ JSHandle ObjectFactory::GetStringFromStringTableNonMovable(const uin return GetEmptyString(); } auto stringTable = vm_->GetEcmaStringTable(); - return JSHandle(thread_, stringTable->CreateAndInternStringNonMovable(utf8Data, utf8Len)); + return JSHandle(thread_, stringTable->CreateAndInternStringNonMovable(vm_, utf8Data, utf8Len)); } JSHandle ObjectFactory::GetStringFromStringTable(const uint16_t *utf16Data, uint32_t utf16Len, @@ -3044,7 +2994,7 @@ JSHandle ObjectFactory::GetStringFromStringTable(const uint16_t *utf return GetEmptyString(); } auto stringTable = vm_->GetEcmaStringTable(); - return JSHandle(thread_, stringTable->GetOrInternString(utf16Data, utf16Len, canBeCompress)); + return JSHandle(thread_, stringTable->GetOrInternString(vm_, utf16Data, utf16Len, canBeCompress)); } JSHandle ObjectFactory::GetStringFromStringTable(EcmaString *string) const @@ -3054,7 +3004,7 @@ JSHandle ObjectFactory::GetStringFromStringTable(EcmaString *string) return GetEmptyString(); } auto stringTable = vm_->GetEcmaStringTable(); - return JSHandle(thread_, stringTable->GetOrInternString(string)); + return JSHandle(thread_, stringTable->GetOrInternString(vm_, string)); } // NB! don't do special case for C0 80, it means '\u0000', so don't convert to UTF-8 @@ -3071,10 +3021,10 @@ EcmaString *ObjectFactory::GetRawStringFromStringTable(StringData sd, MemSpaceTy const uint8_t *mutf8Data = sd.data; if (canBeCompressed) { // This branch will use constant string, which has a pointer at the string in the pandafile. - return vm_->GetEcmaStringTable()->GetOrInternStringWithSpaceType(mutf8Data, utf16Len, true, type, + return vm_->GetEcmaStringTable()->GetOrInternStringWithSpaceType(vm_, mutf8Data, utf16Len, true, type, isConstantString, idOffset); } - return vm_->GetEcmaStringTable()->GetOrInternStringWithSpaceType(mutf8Data, utf16Len, type); + return vm_->GetEcmaStringTable()->GetOrInternStringWithSpaceType(vm_, mutf8Data, utf16Len, type); } JSHandle ObjectFactory::NewPropertyBox(const JSHandle &value) @@ -3140,7 +3090,7 @@ JSHandle ObjectFactory::NewBigInt(uint32_t length) NewObjectHook(); ASSERT(length > 0); size_t size = BigInt::ComputeSize(length); - auto header = heap_->AllocateYoungOrHugeObject( + auto header = sHeap_->AllocateNonMovableOrHugeObject(thread_, JSHClass::Cast(thread_->GlobalConstants()->GetBigIntClass().GetTaggedObject()), size); JSHandle bigint(thread_, header); bigint->SetLength(length); @@ -3526,7 +3476,7 @@ EcmaString *ObjectFactory::InternString(const JSHandle &key) } EcmaStringTable *stringTable = vm_->GetEcmaStringTable(); - return stringTable->GetOrInternString(str); + return stringTable->GetOrInternString(vm_, str); } JSHandle ObjectFactory::NewTransitionHandler() @@ -4086,7 +4036,7 @@ JSHandle ObjectFactory::GetStringFromStringTable(const JSHandle &secondString) { auto stringTable = vm_->GetEcmaStringTable(); - return JSHandle(thread_, stringTable->GetOrInternString(firstString, secondString)); + return JSHandle(thread_, stringTable->GetOrInternString(vm_, firstString, secondString)); } JSHandle ObjectFactory::NewJSAPIArrayList(uint32_t capacity) @@ -4478,6 +4428,7 @@ JSHandle ObjectFactory::NewSourceTextModule() obj->SetTypes(ModuleTypes::UNKNOWN); obj->SetIsNewBcVersion(false); obj->SetRegisterCounts(UINT16_MAX); + obj->SetSharedType(SharedTypes::UNSENDABLE_MODULE); return obj; } @@ -4711,29 +4662,19 @@ JSHandle ObjectFactory::NewJSFunction(const JSHandle &method LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); } + JSHandle jsfunc = NewJSFunctionByHClass(methodHandle, hclass); ASSERT_NO_ABRUPT_COMPLETION(thread_); return jsfunc; } -JSHandle ObjectFactory::NewSFunction(const JSHandle &methodHandle, - const JSHandle &homeObject) -{ - ASSERT(homeObject->IsECMAObject()); - JSHandle env = vm_->GetGlobalEnv(); - JSHandle hclass = JSHandle::Cast(env->GetSFunctionClassWithoutProto()); - JSHandle jsFunc = NewSFunctionByHClass(methodHandle, hclass); - jsFunc->SetHomeObject(thread_, homeObject); - ASSERT_NO_ABRUPT_COMPLETION(thread_); - return jsFunc; -} - JSHandle ObjectFactory::NewJSFunction(const JSHandle &methodHandle, const JSHandle &homeObject) { ASSERT(homeObject->IsECMAObject()); JSHandle env = vm_->GetGlobalEnv(); JSHandle hclass = JSHandle::Cast(env->GetFunctionClassWithoutProto()); + JSHandle jsFunc = NewJSFunctionByHClass(methodHandle, hclass); jsFunc->SetHomeObject(thread_, homeObject); ASSERT_NO_ABRUPT_COMPLETION(thread_); @@ -4934,43 +4875,9 @@ JSHandle ObjectFactory::CreateDictionaryJSObjectWithNamedProperti return JSHandle(object); } -JSHandle ObjectFactory::CreateSFunctionClassWithoutProto(uint32_t size, JSType type, - const JSHandle &prototype) -{ - const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); - JSHandle functionClass = NewEcmaHClass(size, type, prototype); - uint32_t fieldOrder = 0; - ASSERT(JSFunction::LENGTH_INLINE_PROPERTY_INDEX == fieldOrder); - JSHandle layoutInfoHandle = CreateLayoutInfo(JSFunction::LENGTH_OF_INLINE_PROPERTIES); - { - PropertyAttributes attributes = PropertyAttributes::DefaultAccessor(false, false, false); - attributes.SetIsInlinedProps(true); - attributes.SetRepresentation(Representation::TAGGED); - attributes.SetOffset(fieldOrder); - layoutInfoHandle->AddKey(thread_, fieldOrder, globalConst->GetLengthString(), attributes); - fieldOrder++; - } - - ASSERT(JSFunction::NAME_INLINE_PROPERTY_INDEX == fieldOrder); - { - PropertyAttributes attributes = PropertyAttributes::DefaultAccessor(false, false, false); - attributes.SetIsInlinedProps(true); - attributes.SetRepresentation(Representation::TAGGED); - attributes.SetOffset(fieldOrder); - layoutInfoHandle->AddKey(thread_, fieldOrder, - globalConst->GetHandledNameString().GetTaggedValue(), attributes); - fieldOrder++; - } - functionClass->SetLayout(thread_, layoutInfoHandle); - functionClass->SetNumberOfProps(fieldOrder); - functionClass->SetCallable(true); - functionClass->SetExtensible(false); - return functionClass; -} - void ObjectFactory::FillFreeMemoryRange(uintptr_t start, uintptr_t end) { - ASSERT(start < end); + ASSERT(start <= end); ASSERT(start % static_cast(MemAlignment::MEM_ALIGN_OBJECT) == 0); ASSERT(end % static_cast(MemAlignment::MEM_ALIGN_OBJECT) == 0); while (start < end) { diff --git a/ecmascript/object_factory.h b/ecmascript/object_factory.h index fdd20a61cc226a869943fe1a340185e3d66c706e..1db1da008db30788eedda8958fee49b7bf49636f 100644 --- a/ecmascript/object_factory.h +++ b/ecmascript/object_factory.h @@ -92,6 +92,7 @@ class JSLocale; class ResolvingFunctionsRecord; class EcmaVM; class Heap; +class SharedHeap; class ConstantPool; class Program; class LayoutInfo; @@ -151,6 +152,7 @@ class CjsRequire; class CjsExports; class ResolvedBinding; class ResolvedIndexBinding; +class ResolvedRecordBinding; class BigInt; class AsyncGeneratorRequest; class AsyncIteratorRecord; @@ -195,12 +197,12 @@ enum class GrowMode { KEEP, GROW }; class ObjectFactory { public: static constexpr JSTaggedType FREE_MEMMORY_ADDRESS_ZAM_VALUE = 0xDEADFACE; - ObjectFactory(JSThread *thread, Heap *heap); + ObjectFactory(JSThread *thread, Heap *heap, SharedHeap *sHeap); ~ObjectFactory() = default; JSHandle NewMethodForNativeFunction(const void *func, FunctionKind kind = FunctionKind::NORMAL_FUNCTION, kungfu::BuiltinsStubCSigns::ID builtinId = kungfu::BuiltinsStubCSigns::INVALID, - MemSpaceType spaceType = OLD_SPACE); + MemSpaceType methodSpaceType = SHARED_OLD_SPACE); JSHandle NewProfileTypeInfo(uint32_t length); JSHandle NewConstantPool(uint32_t capacity); @@ -229,11 +231,13 @@ public: JSHandle NewJSFunction(const JSHandle &env, const void *nativeFunc = nullptr, FunctionKind kind = FunctionKind::NORMAL_FUNCTION, kungfu::BuiltinsStubCSigns::ID builtinId = kungfu::BuiltinsStubCSigns::INVALID, - MemSpaceType spaceType = OLD_SPACE); - JSHandle NewSFunction(const JSHandle &env, const void *nativeFunc = nullptr, - FunctionKind kind = FunctionKind::NORMAL_FUNCTION, - kungfu::BuiltinsStubCSigns::ID builtinId = kungfu::BuiltinsStubCSigns::INVALID, - MemSpaceType spaceType = OLD_SPACE); + MemSpaceType methodSpaceType = SHARED_OLD_SPACE); + JSHandle NewSFunction(const JSHandle &env, + const void *nativeFunc = nullptr, + FunctionKind kind = FunctionKind::NORMAL_FUNCTION, + kungfu::BuiltinsStubCSigns::ID builtinId = kungfu::BuiltinsStubCSigns::INVALID, + MemSpaceType spaceType = SHARED_OLD_SPACE); + void InitializeMethod(const MethodLiteral *methodLiteral, JSHandle &method); // use for method JSHandle NewJSFunction(const JSHandle &env, const JSHandle &method); @@ -356,7 +360,7 @@ public: uint32_t oldLength, uint32_t k = 0); JSHandle NewAndCopyTaggedArray(JSHandle &srcElements, uint32_t newLength, uint32_t oldLength, uint32_t k = 0); - JSHandle NewAndCopyNameDictionary(JSHandle &srcElements, uint32_t length); + JSHandle NewAndCopySNameDictionary(JSHandle &srcElements, uint32_t length); JSHandle NewAndCopyTaggedArrayByObject(JSHandle thisObjHandle, uint32_t newLength, uint32_t oldLength, uint32_t k = 0); JSHandle NewAndCopyMutantTaggedArrayByObject(JSHandle thisObjHandle, @@ -476,7 +480,7 @@ public: bool canShareHClass = true); JSHandle CloneObjectLiteral(JSHandle object); JSHandle CloneArrayLiteral(JSHandle object); - JSHandle CloneJSFuction(JSHandle func); + JSHandle CloneJSFunction(JSHandle func); JSHandle CloneSFunction(JSHandle func); JSHandle CloneClassCtor(JSHandle ctor, const JSHandle &lexenv, bool canShareHClass); @@ -524,8 +528,8 @@ public: JSHandle NewMethod(const MethodLiteral *methodLiteral, MemSpaceType spaceType = OLD_SPACE); JSHandle NewMethod(const JSPandaFile *jsPandaFile, MethodLiteral *methodLiteral, - JSHandle constpool, JSHandle module, - uint32_t entryIndex, bool needSetAotFlag, bool *canFastCall = nullptr); + JSHandle constpool, uint32_t entryIndex, + bool needSetAotFlag, bool *canFastCall = nullptr); // used for creating jsobject by constructor JSHandle NewJSObjectByConstructor(const JSHandle &constructor, @@ -656,8 +660,8 @@ public: JSHandle NewResolvedBindingRecord(const JSHandle &module, const JSHandle &bindingName); JSHandle NewResolvedIndexBindingRecord(); - JSHandle NewResolvedIndexBindingRecord(const JSHandle &module, - int32_t index); + JSHandle NewResolvedIndexBindingRecord( + const JSHandle &module, int32_t index); JSHandle NewCellRecord(); JSHandle NewJSAsyncGeneratorFunction(const JSHandle &method); @@ -687,10 +691,117 @@ public: const PropertyDescriptor *attributes); JSHandle CreateJSObjectWithNamedProperties(size_t propertyCount, const char **keys, const Local *values); - // Fill the given free memory range with special zam value. void FillFreeMemoryRange(uintptr_t start, uintptr_t end); + // -----------------------------------shared object----------------------------------------- + JSHandle NewSharedOldSpaceJSObject(const JSHandle &jshclass); + + TaggedObject *NewSharedOldSpaceObject(const JSHandle &hclass); + + JSHandle NewSEcmaHClass(uint32_t size, JSType type, uint32_t inlinedProps); + + JSHandle NewSEcmaHClass(JSHClass *hclass, uint32_t size, JSType type, + uint32_t inlinedProps = JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS); + + JSHandle NewSEcmaHClass(uint32_t size, uint32_t inlinedProps, JSType type, + const JSHandle &prototype, const JSHandle &layout); + + JSHandle NewSEcmaHClassClass(JSHClass *hclass, uint32_t size, JSType type); + + JSHandle InitSClassClass(); + + JSHandle NewSEcmaReadOnlyHClass(JSHClass *hclass, uint32_t size, JSType type, + uint32_t inlinedProps = JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS); + JSHandle SharedEmptyArray() const; + + JSHandle NewSMethodForNativeFunction(const void *func, FunctionKind kind = FunctionKind::NORMAL_FUNCTION, + kungfu::BuiltinsStubCSigns::ID builtinId = + kungfu::BuiltinsStubCSigns::INVALID, + MemSpaceType spaceType = SHARED_OLD_SPACE); + + JSHandle NewSFunctionByHClass(const JSHandle &methodHandle, + const JSHandle &hclass); + JSHandle NewSFunctionByHClass(const void *func, const JSHandle &hclass, + FunctionKind kind, + kungfu::BuiltinsStubCSigns::ID builtinId = kungfu::BuiltinsStubCSigns::INVALID, + MemSpaceType spaceType = SHARED_OLD_SPACE); + + JSHandle NewSFunctionWithAccessor( + const void *func, + const JSHandle &hclass, + FunctionKind kind, + kungfu::BuiltinsStubCSigns::ID builtinId = kungfu::BuiltinsStubCSigns::INVALID, + MemSpaceType spaceType = SHARED_OLD_SPACE); + + JSHandle NewSMethod(const MethodLiteral *methodLiteral, MemSpaceType methodSpaceType = SHARED_OLD_SPACE); + + JSHandle NewSMethod(const JSPandaFile *jsPandaFile, + MethodLiteral *methodLiteral, + JSHandle constpool, + uint32_t entryIndex, + bool needSetAotFlag, + bool *canFastCall = nullptr); + + JSHandle NewSConstantPool(uint32_t capacity); + + JSHandle NewSAOTLiteralInfo(uint32_t length, JSTaggedValue initVal = JSTaggedValue::Hole()); + + JSHandle NewSCOWTaggedArray(uint32_t length, JSTaggedValue initVal = JSTaggedValue::Hole()); + + JSHandle NewSClassLiteral(); + + JSHandle NewSClassInfoExtractor(JSHandle method); + + JSHandle NewSOldSpaceTaggedArray(uint32_t length, JSTaggedValue initVal = JSTaggedValue::Hole()); + + JSHandle NewSTaggedArray(uint32_t length, JSTaggedValue initVal, MemSpaceType spaceType); + + JSHandle NewSAccessorData(); + + JSHandle NewSModule(); + + JSHandle NewSResolvedIndexBindingRecord(); + + JSHandle NewSResolvedIndexBindingRecord(const JSHandle &module, + int32_t index); + + JSHandle NewSResolvedBindingRecord(); + + JSHandle NewSResolvedBindingRecord(const JSHandle &module, + const JSHandle &bindingName); + + JSHandle NewSResolvedRecordBindingRecord(); + + JSHandle NewSResolvedRecordBindingRecord(const JSHandle &moduleRecord, + int32_t index); + + JSHandle CopyAndReSortSLayoutInfo(const JSHandle &old, int end, int capacity); + + JSHandle CreateSLayoutInfo(uint32_t properties); + + JSHandle NewSEmptyArray(); // only used for EcmaVM. + + JSHandle NewSEmptyMutantArray(); + + JSHandle PUBLIC_API NewSDictionaryArray(uint32_t length); + + JSHandle NewSTaggedArrayWithoutInit(uint32_t length); + + JSHandle CreateSFunctionClass(uint32_t size, JSType type, + const JSHandle &prototype, bool isAccessor = true); + + JSHandle NewSJSNativePointer(void *externalPointer, + const DeleteEntryPoint &callBack, + void *data = nullptr, + bool nonMovable = false, + size_t nativeBindingsize = 0, + NativeFlag flag = NativeFlag::NO_DIV); + + JSHandle NewSInternalAccessor(void *setter, void *getter); + + JSHandle NewSWellKnownSymbol(const JSHandle &name); + JSHandle NewSWellKnownSymbolWithChar(std::string_view description); private: friend class GlobalEnv; friend class GlobalEnvConstants; @@ -706,6 +817,7 @@ private: EcmaVM *vm_ {nullptr}; Heap *heap_ {nullptr}; + SharedHeap *sHeap_ {nullptr}; static constexpr uint32_t LENGTH_THRESHOLD = 50; static constexpr int MAX_LITERAL_HCLASS_CACHE_SIZE = 63; @@ -714,7 +826,7 @@ private: NO_MOVE_SEMANTIC(ObjectFactory); void NewObjectHook() const; - + void NewSObjectHook() const; // used for creating jshclass in GlobalEnv, EcmaVM JSHandle NewEcmaHClassClass(JSHClass *hclass, uint32_t size, JSType type); @@ -747,7 +859,8 @@ private: uint32_t utf8Len) const; JSHandle GetStringFromStringTableNonMovable(const uint8_t *utf8Data, uint32_t utf8Len) const; // For MUtf-8 string data - EcmaString* PUBLIC_API GetRawStringFromStringTable(StringData sd, MemSpaceType type = MemSpaceType::SEMI_SPACE, + EcmaString *PUBLIC_API GetRawStringFromStringTable(StringData sd, + MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE, bool isConstantString = false, uint32_t idOffset = 0) const; JSHandle GetStringFromStringTable(const uint16_t *utf16Data, uint32_t utf16Len, @@ -758,9 +871,6 @@ private: JSHandle GetStringFromStringTable(const JSHandle &firstString, const JSHandle &secondString); - JSHandle NewEmptyArray(); // only used for EcmaVM. - JSHandle NewEmptyMutantArray(); - JSHandle CreateJSArguments(const JSHandle &env); JSHandle CreateJSArrayInstanceClass(JSHandle proto, uint32_t inlinedProps = JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS); @@ -784,15 +894,6 @@ private: JSHandle NewMutantTaggedArrayWithoutInit(uint32_t length, MemSpaceType spaceType); - // For sharedobject - JSHandle NewSFunction(const JSHandle &methodHandle, - const JSHandle &homeObject); - JSHandle NewSFunctionByHClass(const void *func, const JSHandle &hclass, - FunctionKind kind); - JSHandle NewSFunctionByHClass(const JSHandle &methodHandle, - const JSHandle &hclass); - JSHandle CreateSFunctionClassWithoutProto(uint32_t size, JSType type, - const JSHandle &prototype); friend class Builtins; // create builtins object need hclass friend class JSFunction; // create prototype_or_hclass need hclass friend class JSHClass; // HC transition need hclass @@ -807,6 +908,7 @@ private: friend class ConstantPool; friend class EcmaContext; friend class kungfu::TSHClassGenerator; + friend class panda::FunctionRef; }; class ClassLinkerFactory { diff --git a/ecmascript/object_fast_operator-inl.h b/ecmascript/object_fast_operator-inl.h index 82cddbfb8ca2fdb60b523fc92d2c33b067271060..4e7c61794a18df726cae90d6db37c4ae5a2ae0ed 100644 --- a/ecmascript/object_fast_operator-inl.h +++ b/ecmascript/object_fast_operator-inl.h @@ -83,8 +83,8 @@ std::pair ObjectFastOperator::HasOwnProperty(JSThread *thre } if (!EcmaStringAccessor(key).IsInternString()) { - EcmaString *str = - thread->GetEcmaVM()->GetEcmaStringTable()->TryGetInternString(EcmaString::Cast(key.GetTaggedObject())); + JSHandle keyHandle(thread, key); + EcmaString *str = thread->GetEcmaVM()->GetEcmaStringTable()->TryGetInternString(thread, keyHandle); if (str == nullptr) { return std::make_pair(JSTaggedValue::Hole(), true); } @@ -247,7 +247,7 @@ JSTaggedValue ObjectFastOperator::SetPropertyByName(JSThread *thread, JSTaggedVa break; } if (holder.IsJSShared() && (sCheckMode == SCheckMode::CHECK)) { - if (!ClassHelper::MatchTrackType(attr.GetTrackType(), value)) { + if (!ClassHelper::MatchFieldType(attr.GetSharedFieldType(), value)) { THROW_TYPE_ERROR_AND_RETURN((thread), GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty), JSTaggedValue::Exception()); } @@ -283,7 +283,7 @@ JSTaggedValue ObjectFastOperator::SetPropertyByName(JSThread *thread, JSTaggedVa break; } if ((sCheckMode == SCheckMode::CHECK) && holder.IsJSShared()) { - if (!ClassHelper::MatchTrackType(attr.GetDictTrackType(), value)) { + if (!ClassHelper::MatchFieldType(attr.GetDictSharedFieldType(), value)) { THROW_TYPE_ERROR_AND_RETURN((thread), GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty), JSTaggedValue::Exception()); } diff --git a/ecmascript/object_operator.cpp b/ecmascript/object_operator.cpp index 12d05641a949f78340f169f806c7073a0a483d3b..9e908985f8838c9db8267c6ffc8ea44df0c93f26 100644 --- a/ecmascript/object_operator.cpp +++ b/ecmascript/object_operator.cpp @@ -401,11 +401,11 @@ bool ObjectOperator::IsDetectorName(JSHandle env, JSTaggedValue key) return (start <= addr) && (addr <= end); } -TrackType ObjectOperator::GetTrackType() const +SharedFieldType ObjectOperator::GetSharedFieldType() const { return JSObject::Cast(holder_->GetTaggedObject())->GetJSHClass()->IsDictionaryMode() - ? attributes_.GetDictTrackType() - : attributes_.GetTrackType(); + ? attributes_.GetDictSharedFieldType() + : attributes_.GetSharedFieldType(); } void ObjectOperator::ToPropertyDescriptor(PropertyDescriptor &desc) const @@ -419,7 +419,7 @@ void ObjectOperator::ToPropertyDescriptor(PropertyDescriptor &desc) const desc.SetWritable(IsWritable()); JSTaggedValue val = GetValue(); desc.SetValue(JSHandle(thread_, val)); - desc.SetTrackType(GetTrackType()); + desc.SetSharedFieldType(GetSharedFieldType()); } else { auto result = GetValue(); bool isPropertyBox = result.IsPropertyBox(); @@ -508,7 +508,7 @@ void ObjectOperator::LookupGlobal(const JSHandle &obj) return; } JSTaggedValue value(dict->GetBox(entry)); - uint32_t attr = dict->GetAttributes(entry).GetValue(); + auto attr = dict->GetAttributes(entry).GetValue(); SetFound(entry, value, attr, true); } @@ -537,7 +537,7 @@ void ObjectOperator::LookupPropertyInlinedProps(const JSHandle &obj) } JSTaggedValue value(dict->GetBox(entry)); - uint32_t attr = dict->GetAttributes(entry).GetValue(); + auto attr = dict->GetAttributes(entry).GetValue(); SetFound(entry, value, attr, true); return; } @@ -578,7 +578,7 @@ void ObjectOperator::LookupPropertyInlinedProps(const JSHandle &obj) } JSTaggedValue value = dict->GetValue(entry); - uint32_t attr = dict->GetAttributes(entry).GetValue(); + auto attr = dict->GetAttributes(entry).GetValue(); SetFound(entry, value, attr, false); } @@ -610,7 +610,7 @@ void ObjectOperator::TransitionForAttributeChanged(const JSHandle &rec JSHandle dict(JSObject::TransitionToDictionary(thread_, receiver)); index = static_cast(dict->FindEntry(key_.GetTaggedValue())); PropertyAttributes origin = dict->GetAttributes(index); - attr.SetDictTrackType(attr.GetTrackType()); + attr.SetDictSharedFieldType(attr.GetSharedFieldType()); attr.SetDictionaryOrder(origin.GetDictionaryOrder()); dict->SetAttributes(thread_, index, attr); } else { @@ -909,7 +909,7 @@ void ObjectOperator::DeleteElementInHolder() const } } -void ObjectOperator::SetFound(uint32_t index, JSTaggedValue value, uint32_t attr, bool mode, bool transition) +void ObjectOperator::SetFound(uint32_t index, JSTaggedValue value, uint64_t attr, bool mode, bool transition) { SetIndex(index); SetValue(value); @@ -918,7 +918,7 @@ void ObjectOperator::SetFound(uint32_t index, JSTaggedValue value, uint32_t attr SetAttr(attr); } -void ObjectOperator::UpdateFound(uint32_t index, uint32_t attr, bool mode, bool transition) +void ObjectOperator::UpdateFound(uint32_t index, uint64_t attr, bool mode, bool transition) { SetIndex(index); SetFastMode(mode); @@ -991,7 +991,7 @@ void ObjectOperator::LookupElementInlinedProps(const JSHandle &obj) return; } - uint32_t attr = dictionary->GetAttributes(entry).GetValue(); + auto attr = dictionary->GetAttributes(entry).GetValue(); SetFound(entry, dictionary->GetValue(entry), attr, false); } } diff --git a/ecmascript/object_operator.h b/ecmascript/object_operator.h index c1d79eb6881d5eab64725d6550ee273a34955362..93758a03952a939fa0163861d56667d19c8a7d4a 100644 --- a/ecmascript/object_operator.h +++ b/ecmascript/object_operator.h @@ -159,14 +159,14 @@ public: return attributes_; } - inline void SetAttr(uint32_t attr) + inline void SetAttr(uint64_t attr) { attributes_ = PropertyAttributes(attr); } inline void SetAttr(const PropertyAttributes &attr) { - attributes_ = PropertyAttributes(attr); + attributes_ = attr; } inline bool IsPrimitiveAttr() const @@ -275,7 +275,7 @@ public: } void ToPropertyDescriptor(PropertyDescriptor &desc) const; - TrackType GetTrackType() const; + SharedFieldType GetSharedFieldType() const; void LookupProperty(); void GlobalLookupProperty(); inline void ReLookupPropertyInReceiver() @@ -324,8 +324,8 @@ private: void StartGlobalLookUp(OperatorType type); void HandleKey(const JSHandle &key); uint32_t ComputeElementCapacity(uint32_t oldCapacity); - void SetFound(uint32_t index, JSTaggedValue value, uint32_t attr, bool mode, bool transition = false); - void UpdateFound(uint32_t index, uint32_t attr, bool mode, bool transition); + void SetFound(uint32_t index, JSTaggedValue value, uint64_t attr, bool mode, bool transition = false); + void UpdateFound(uint32_t index, uint64_t attr, bool mode, bool transition); void ResetState(); void ResetStateForAddProperty(); inline void LookupPropertyInHolder() diff --git a/ecmascript/ohos/tests/ohos_test.cpp b/ecmascript/ohos/tests/ohos_test.cpp index 1bfc25d2ea3a6cf41b4077552510f0c2ec7441db..15373165640d15eb0e3ec9ada4e53f50e1c60845 100644 --- a/ecmascript/ohos/tests/ohos_test.cpp +++ b/ecmascript/ohos/tests/ohos_test.cpp @@ -54,10 +54,12 @@ public: runtimeOptions_.SetCompilerExternalPkgJsonInfo(BuildOhosExternalPkgJson()); vm_ = JSNApi::CreateEcmaVM(runtimeOptions_); ASSERT(vm_ != nullptr); + vm_->GetJSThread()->ManagedCodeBegin(); } void TearDown() override { + vm_->GetJSThread()->ManagedCodeEnd(); ohos::EnableAotListHelper::GetInstance()->Clear(); JSNApi::DestroyJSVM(vm_); vm_ = nullptr; diff --git a/ecmascript/patch/patch_loader.cpp b/ecmascript/patch/patch_loader.cpp index bed6888f73e8e6959ba6d1b25d05ae4eb8da001a..d43753960ad1a454ae476a9147b61c040511bb6b 100644 --- a/ecmascript/patch/patch_loader.cpp +++ b/ecmascript/patch/patch_loader.cpp @@ -19,7 +19,9 @@ #include "ecmascript/jspandafile/js_pandafile_manager.h" #include "ecmascript/jspandafile/literal_data_extractor.h" #include "ecmascript/mem/c_string.h" +#include "ecmascript/module/js_shared_module.h" #include "ecmascript/napi/include/jsnapi.h" +#include "ecmascript/checkpoint/thread_state_transition.h" namespace panda::ecmascript { PatchErrorCode PatchLoader::LoadPatchInternal(JSThread *thread, const JSPandaFile *baseFile, @@ -64,7 +66,7 @@ PatchErrorCode PatchLoader::LoadPatchInternal(JSThread *thread, const JSPandaFil thread->GetCurrentEcmaContext()->ClearPatchModules(); // execute patch func_main_0 for hot reload, and patch_main_0 for hot patch. ExecuteFuncOrPatchMain(thread, patchFile, patchInfo); - ReplaceModuleOfMethod(thread, baseFile, patchInfo); + UpdateJSFunction(thread, patchInfo); vm->GetJsDebuggerManager()->GetHotReloadManager()->NotifyPatchLoaded(baseFile, patchFile); return PatchErrorCode::SUCCESS; @@ -73,6 +75,11 @@ PatchErrorCode PatchLoader::LoadPatchInternal(JSThread *thread, const JSPandaFil void PatchLoader::ExecuteFuncOrPatchMain( JSThread *thread, const JSPandaFile *jsPandaFile, const PatchInfo &patchInfo, bool loadPatch) { + bool needToFinishManagedCode = false; + if (thread->GetState() != ThreadState::RUNNING) { + needToFinishManagedCode = true; + thread->ManagedCodeBegin(); + } LOG_ECMA(DEBUG) << "execute main begin"; EcmaContext *context = thread->GetCurrentEcmaContext(); context->SetStageOfHotReload(StageOfHotReload::BEGIN_EXECUTE_PATCHMAIN); @@ -109,30 +116,8 @@ void PatchLoader::ExecuteFuncOrPatchMain( context->SetStageOfHotReload(StageOfHotReload::UNLOAD_END_EXECUTE_PATCHMAIN); } LOG_ECMA(DEBUG) << "execute main end"; -} - -void PatchLoader::ReplaceModuleOfMethod(JSThread *thread, const JSPandaFile *baseFile, PatchInfo &patchInfo) -{ - EcmaContext *context = thread->GetCurrentEcmaContext(); - auto baseConstpoolValues = context->FindConstpools(baseFile); - if (!baseConstpoolValues.has_value()) { - LOG_ECMA(ERROR) << "replace module :base constpool is empty"; - return; - } - - const auto &baseMethodInfo = patchInfo.baseMethodInfo; - for (const auto &item : baseMethodInfo) { - const auto &methodIndex = item.first; - ConstantPool *baseConstpool = ConstantPool::Cast( - (baseConstpoolValues.value().get()[methodIndex.constpoolNum]).GetTaggedObject()); - - Method *patchMethod = GetPatchMethod(thread, methodIndex, baseConstpool); - - JSHandle moduleRecord = context->FindPatchModule(patchMethod->GetRecordNameStr()); - patchMethod->SetModule(thread, moduleRecord.GetTaggedValue()); - LOG_ECMA(DEBUG) << "Replace base method module: " - << patchMethod->GetRecordNameStr() - << ":" << patchMethod->GetMethodName(); + if (needToFinishManagedCode) { + thread->ManagedCodeEnd(); } } @@ -165,16 +150,17 @@ PatchErrorCode PatchLoader::UnloadPatchInternal(JSThread *thread, const CString return PatchErrorCode::INTERNAL_ERROR; } + patchInfo.repalcedPatchMethods.clear(); for (const auto &item : baseMethodInfo) { const auto &methodIndex = item.first; - ConstantPool *baseConstpool = ConstantPool::Cast( - (baseConstpoolValues.value().get()[methodIndex.constpoolNum]).GetTaggedObject()); + JSTaggedValue baseConstpool = baseConstpoolValues.value().get()[methodIndex.constpoolNum]; Method *patchMethod = GetPatchMethod(thread, methodIndex, baseConstpool); MethodLiteral *baseMethodLiteral = item.second; - JSTaggedValue baseConstpoolValue = context->FindConstpool( - baseFile.get(), baseMethodLiteral->GetMethodId()); + EntityId baseMethodId = baseMethodLiteral->GetMethodId(); + JSTaggedValue baseConstpoolValue = context->FindConstpool(baseFile.get(), baseMethodId); + patchInfo.repalcedPatchMethods.emplace(baseMethodId, patchMethod->GetRecordNameStr()); ReplaceMethod(thread, patchMethod, baseMethodLiteral, baseConstpoolValue); LOG_ECMA(DEBUG) << "Replace base method: " << patchMethod->GetRecordNameStr() @@ -184,7 +170,7 @@ PatchErrorCode PatchLoader::UnloadPatchInternal(JSThread *thread, const CString context->ClearPatchModules(); // execute base func_main_0 for recover global object. ExecuteFuncOrPatchMain(thread, baseFile.get(), patchInfo, false); - ReplaceModuleOfMethod(thread, baseFile.get(), patchInfo); + UpdateJSFunction(thread, patchInfo); vm->GetJsDebuggerManager()->GetHotReloadManager()->NotifyPatchUnloaded(patchFile.get()); @@ -200,17 +186,26 @@ PatchErrorCode PatchLoader::UnloadPatchInternal(JSThread *thread, const CString } Method *PatchLoader::GetPatchMethod(JSThread *thread, - const BaseMethodIndex &methodIndex, const ConstantPool *baseConstpool) + const BaseMethodIndex &methodIndex, const JSTaggedValue constpoolVal) { uint32_t constpoolIndex = methodIndex.constpoolIndex; uint32_t literalIndex = methodIndex.literalIndex; Method *patchMethod = nullptr; + ConstantPool *baseConstpool = ConstantPool::Cast(constpoolVal.GetTaggedObject()); if (literalIndex == UINT32_MAX) { JSTaggedValue value = baseConstpool->GetObjectFromCache(constpoolIndex); ASSERT(value.IsMethod()); patchMethod = Method::Cast(value.GetTaggedObject()); } else { - ClassLiteral *classLiteral = ClassLiteral::Cast(baseConstpool->GetObjectFromCache(constpoolIndex)); + ClassLiteral *classLiteral; + if (baseConstpool->GetObjectFromCache(constpoolIndex).IsHole()) { + JSTaggedValue unsharedBaseConstpool = thread->GetCurrentEcmaContext()-> + FindUnsharedConstpool(constpoolVal); + classLiteral = ClassLiteral::Cast( + ConstantPool::Cast(unsharedBaseConstpool.GetTaggedObject())->GetObjectFromCache(constpoolIndex)); + } else { + classLiteral = ClassLiteral::Cast(baseConstpool->GetObjectFromCache(constpoolIndex)); + } TaggedArray *literalArray = TaggedArray::Cast(classLiteral->GetArray()); JSTaggedValue value = literalArray->Get(thread, literalIndex); ASSERT(value.IsJSFunctionBase()); @@ -249,10 +244,52 @@ void PatchLoader::ReplaceMethod(JSThread *thread, destMethod->SetCodeEntryOrLiteral(reinterpret_cast(srcMethodLiteral)); destMethod->SetNativePointerOrBytecodeArray(const_cast(srcMethodLiteral->GetNativePointer())); destMethod->SetConstantPool(thread, srcConstpool); - destMethod->SetProfileTypeInfo(thread, JSTaggedValue::Undefined()); destMethod->SetAotCodeBit(false); } +// Iterator heap to update module in JSFunction. +void PatchLoader::UpdateJSFunction(JSThread *thread, PatchInfo &patchInfo) +{ + auto &repalcedPatchMethods = patchInfo.repalcedPatchMethods; + const Heap *heap = thread->GetEcmaVM()->GetHeap(); + heap->GetSweeper()->EnsureAllTaskFinished(); + heap->IterateOverObjects([&repalcedPatchMethods, thread]([[maybe_unused]] TaggedObject *obj) { + JSFunction *function = nullptr; + if (JSTaggedValue(obj).IsJSFunction()) { + function = JSFunction::Cast(obj); + EntityId methodId = Method::Cast(function->GetMethod())->GetMethodId(); + if (repalcedPatchMethods.count(methodId) > 0) { + JSHandle moduleRecord = + thread->GetCurrentEcmaContext()->FindPatchModule(repalcedPatchMethods[methodId]); + function->SetModule(thread, moduleRecord.GetTaggedValue()); + function->SetProfileTypeInfo(thread, JSTaggedValue::Undefined()); + } + } + }); +} + +void PatchLoader::UpdateModuleForColdPatch(JSThread *thread, EntityId methodId, CString &recordName, bool hasModule) +{ + const Heap *heap = thread->GetEcmaVM()->GetHeap(); + heap->GetSweeper()->EnsureAllTaskFinished(); + heap->IterateOverObjects([methodId, &recordName, hasModule, thread]([[maybe_unused]] TaggedObject *obj) { + JSFunction *function = nullptr; + if (JSTaggedValue(obj).IsJSFunction()) { + function = JSFunction::Cast(obj); + EntityId methodIdLoop = Method::Cast(function->GetMethod())->GetMethodId(); + if (methodId == methodIdLoop) { + JSHandle moduleRecord = + thread->GetCurrentEcmaContext()->FindPatchModule(recordName); + if (hasModule) { + function->SetModule(thread, moduleRecord.GetTaggedValue()); + } else { + function->SetModule(thread, JSTaggedValue::Undefined()); + } + } + } + }); +} + void PatchLoader::FindAndReplaceSameMethod(JSThread *thread, const JSPandaFile *baseFile, const JSPandaFile *patchFile, PatchInfo &patchInfo, const CMap &baseClassInfo) @@ -283,44 +320,69 @@ void PatchLoader::FindAndReplaceSameMethod(JSThread *thread, const JSPandaFile * continue; } - JSTaggedValue patchConstpoolValue = context->FindConstpool(patchFile, - patchMethodLiteral->GetMethodId()); + EntityId patchMethodId = patchMethodLiteral->GetMethodId(); + JSTaggedValue patchConstpoolValue = context->FindConstpool(patchFile, patchMethodId); + patchInfo.repalcedPatchMethods.emplace(patchMethodId, baseMethod->GetRecordNameStr()); ReplaceMethod(thread, baseMethod, patchMethodLiteral, patchConstpoolValue); BaseMethodIndex indexs = {constpoolNum, constpoolIndex}; SaveBaseMethodInfo(patchInfo, baseFile, baseMethodId, indexs); } else if (constpoolValue.IsClassLiteral()) { // For class literal. - ClassLiteral *classLiteral = ClassLiteral::Cast(constpoolValue); - TaggedArray *literalArray = TaggedArray::Cast(classLiteral->GetArray()); - uint32_t literalLength = literalArray->GetLength(); - for (uint32_t literalIndex = 0; literalIndex < literalLength; literalIndex++) { - JSTaggedValue literalItem = literalArray->Get(thread, literalIndex); - if (!literalItem.IsJSFunctionBase()) { - continue; - } - - // Every record is the same in current class literal. - JSFunctionBase *func = JSFunctionBase::Cast(literalItem.GetTaggedObject()); - Method *baseMethod = Method::Cast(func->GetMethod().GetTaggedObject()); - EntityId baseMethodId = baseMethod->GetMethodId(); - MethodLiteral *patchMethodLiteral = - FindSameMethod(patchInfo, baseFile, baseMethodId, baseClassInfo); - if (patchMethodLiteral == nullptr) { - continue; - } - - JSTaggedValue patchConstpoolValue = context->FindConstpool(patchFile, - patchMethodLiteral->GetMethodId()); - ReplaceMethod(thread, baseMethod, patchMethodLiteral, patchConstpoolValue); + FindAndReplaceClassLiteral(thread, baseFile, patchFile, constpoolValue, patchInfo, + constpoolIndex, constpoolNum, baseClassInfo); + } + } - BaseMethodIndex indexs = {constpoolNum, constpoolIndex, literalIndex}; - SaveBaseMethodInfo(patchInfo, baseFile, baseMethodId, indexs); - } + JSTaggedValue unsharedConstpool = context->FindUnsharedConstpool(item.second); + ConstantPool *baseUnsharedConstpool = ConstantPool::Cast(unsharedConstpool.GetTaggedObject()); + const uint32_t len = baseUnsharedConstpool->GetCacheLength(); + for (uint32_t constpoolIndex = 0; constpoolIndex < len; constpoolIndex++) { + JSTaggedValue constpoolValue = baseUnsharedConstpool->GetObjectFromCache(constpoolIndex); + if (!constpoolValue.IsMethod() && !constpoolValue.IsClassLiteral()) { + continue; + } + if (constpoolValue.IsClassLiteral()) { + FindAndReplaceClassLiteral(thread, baseFile, patchFile, constpoolValue, patchInfo, + constpoolIndex, constpoolNum, baseClassInfo); } } } } +void PatchLoader::FindAndReplaceClassLiteral(JSThread *thread, const JSPandaFile *baseFile, + const JSPandaFile *patchFile, JSTaggedValue constpoolValue, + PatchInfo &patchInfo, uint32_t constpoolIndex, + uint32_t constpoolNum, const CMap &baseClassInfo) +{ + // For class literal. + ClassLiteral *classLiteral = ClassLiteral::Cast(constpoolValue); + TaggedArray *literalArray = TaggedArray::Cast(classLiteral->GetArray()); + uint32_t literalLength = literalArray->GetLength(); + for (uint32_t literalIndex = 0; literalIndex < literalLength; literalIndex++) { + JSTaggedValue literalItem = literalArray->Get(thread, literalIndex); + if (!literalItem.IsJSFunctionBase()) { + continue; + } + + // Every record is the same in current class literal. + JSFunctionBase *func = JSFunctionBase::Cast(literalItem.GetTaggedObject()); + Method *baseMethod = Method::Cast(func->GetMethod().GetTaggedObject()); + EntityId baseMethodId = baseMethod->GetMethodId(); + MethodLiteral *patchMethodLiteral = + FindSameMethod(patchInfo, baseFile, baseMethodId, baseClassInfo); + if (patchMethodLiteral == nullptr) { + continue; + } + + EntityId patchMethodId = patchMethodLiteral->GetMethodId(); + JSTaggedValue patchConstpoolValue = thread->GetCurrentEcmaContext()->FindConstpool(patchFile, patchMethodId); + patchInfo.repalcedPatchMethods.emplace(patchMethodId, baseMethod->GetRecordNameStr()); + ReplaceMethod(thread, baseMethod, patchMethodLiteral, patchConstpoolValue); + + BaseMethodIndex indexs = {constpoolNum, constpoolIndex, literalIndex}; + SaveBaseMethodInfo(patchInfo, baseFile, baseMethodId, indexs); + } +} MethodLiteral* PatchLoader::FindSameMethod(PatchInfo &patchInfo, const JSPandaFile *baseFile, EntityId baseMethodId, const CMap &baseClassInfo) diff --git a/ecmascript/patch/patch_loader.h b/ecmascript/patch/patch_loader.h index 7ef0f6fe42953d77c447a00bc3529df39567b6f1..5fbb8a28027577c396022eed00776e25f05c086a 100644 --- a/ecmascript/patch/patch_loader.h +++ b/ecmascript/patch/patch_loader.h @@ -79,6 +79,8 @@ struct PatchInfo { CVector> baseConstpools; // patch replaced recordNames. CUnorderedSet replacedRecordNames; + // patch replaced methods. + CUnorderedMap repalcedPatchMethods; }; enum class StageOfHotReload : int32_t { @@ -106,6 +108,9 @@ public: static void ExecuteFuncOrPatchMain( JSThread *thread, const JSPandaFile *jsPandaFile, const PatchInfo &patchInfo, bool loadPatch = true); static CMap CollectClassInfo(const JSPandaFile *jsPandaFile); + static void UpdateModuleForColdPatch( + JSThread *thread, EntityId methodId, CString &recordName, bool hasModule = true); + static void UpdateJSFunction(JSThread *thread, PatchInfo &patchInfo); private: static PatchInfo GeneratePatchInfo(const JSPandaFile *patchFile); @@ -126,7 +131,11 @@ private: static void ReplaceModuleOfMethod(JSThread *thread, const JSPandaFile *baseFile, PatchInfo &patchInfo); static Method *GetPatchMethod(JSThread *thread, - const BaseMethodIndex &methodIndex, const ConstantPool *baseConstpool); + const BaseMethodIndex &methodIndex, const JSTaggedValue baseConstpool); + static void FindAndReplaceClassLiteral(JSThread *thread, const JSPandaFile *baseFile, + const JSPandaFile *patchFile, JSTaggedValue constpoolValue, + PatchInfo &patchInfo, uint32_t constpoolIndex, + uint32_t constpoolNum, const CMap &baseClassInfo); }; } // namespace panda::ecmascript #endif // ECMASCRIPT_PATCH_PATCH_LOADER_H diff --git a/ecmascript/patch/quick_fix_manager.cpp b/ecmascript/patch/quick_fix_manager.cpp index d7a04319e136bd5cb44e9e0d538e0a3b7e35ec75..1d1292c788f977caf5d8b714c1b74ca3b72603ec 100644 --- a/ecmascript/patch/quick_fix_manager.cpp +++ b/ecmascript/patch/quick_fix_manager.cpp @@ -19,6 +19,8 @@ #include "ecmascript/jspandafile/js_pandafile_manager.h" #include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/mem/c_string.h" +#include "ecmascript/module/js_module_manager.h" +#include "ecmascript/module/js_shared_module.h" #include "ecmascript/napi/include/jsnapi.h" #include "ecmascript/object_factory.h" @@ -205,7 +207,8 @@ JSTaggedValue QuickFixManager::CheckAndGetPatch(JSThread *thread, const JSPandaF ASSERT(patchFile != nullptr); EcmaVM *vm = thread->GetEcmaVM(); - JSHandle method = vm->GetFactory()->NewMethod(patchMethodLiteral); + JSHandle method; + method = vm->GetFactory()->NewSMethod(patchMethodLiteral); JSHandle newConstpool = thread->GetCurrentEcmaContext()->FindOrCreateConstPool( patchFile.get(), patchMethodLiteral->GetMethodId()); method->SetConstantPool(thread, newConstpool); @@ -213,16 +216,17 @@ JSTaggedValue QuickFixManager::CheckAndGetPatch(JSThread *thread, const JSPandaF CString recordName = MethodLiteral::GetRecordName(baseFile, baseMethodId); EcmaContext *context = thread->GetCurrentEcmaContext(); JSHandle moduleRecord = context->FindPatchModule(recordName); + EntityId methodId = method->GetMethodId(); if (moduleRecord->IsHole()) { PatchLoader::ExecuteFuncOrPatchMain(thread, patchFile.get(), patchInfo); moduleRecord = context->FindPatchModule(recordName); if (moduleRecord->IsHole()) { LOG_ECMA(ERROR) << "cold patch: moduleRecord is still hole after regeneration"; - method->SetModule(thread, JSTaggedValue::Undefined()); + PatchLoader::UpdateModuleForColdPatch(thread, methodId, recordName, false); return method.GetTaggedValue(); } } - method->SetModule(thread, moduleRecord.GetTaggedValue()); + PatchLoader::UpdateModuleForColdPatch(thread, methodId, recordName); return method.GetTaggedValue(); } diff --git a/ecmascript/pgo_profiler/pgo_profiler.cpp b/ecmascript/pgo_profiler/pgo_profiler.cpp index e72d30ecf6e002a0b60fc071fe6269ab0d6caa08..5d4a26a16cfb0d356a4ee1c20e3e72af4fce3fed 100644 --- a/ecmascript/pgo_profiler/pgo_profiler.cpp +++ b/ecmascript/pgo_profiler/pgo_profiler.cpp @@ -141,6 +141,7 @@ void PGOProfiler::ProfileDefineGetterSetter( if (!methodValue.IsMethod()) { return; } + auto function = JSFunction::Cast(funcValue); WorkNode* workNode = reinterpret_cast(function->GetWorkNodePointer()); if (workNode != nullptr) { @@ -232,8 +233,7 @@ void PGOProfiler::UpdateTrackInfo(JSTaggedValue trackInfoVal) if (!object->GetClass()->IsJSFunction()) { return; } - auto method = JSFunction::Cast(object)->GetMethod(); - auto profileTypeInfoVal = Method::Cast(method)->GetProfileTypeInfo(); + auto profileTypeInfoVal = JSFunction::Cast(object)->GetProfileTypeInfo(); if (profileTypeInfoVal.IsUndefined()) { return; } @@ -398,7 +398,7 @@ void PGOProfiler::HandlePGOPreDump() if (!methodValue.IsMethod()) { return; } - JSTaggedValue recordNameValue = Method::Cast(methodValue)->GetRecordName(); + JSTaggedValue recordNameValue = func->GetRecordName(); if (!recordNameValue.IsString()) { return; } @@ -413,7 +413,7 @@ void PGOProfiler::HandlePGOPreDump() ProfileType recordType = GetRecordProfileType(abcId, recordName); recordInfos_->AddMethod(recordType, Method::Cast(methodValue), SampleMode::HOTNESS_MODE); - ProfileBytecode(abcId, recordName, methodValue); + ProfileBytecode(abcId, recordName, funcValue); }); } @@ -440,7 +440,7 @@ void PGOProfiler::HandlePGODump(bool force) current = PopFromProfileQueue(); continue; } - JSTaggedValue recordNameValue = Method::Cast(methodValue)->GetRecordName(); + JSTaggedValue recordNameValue = func->GetRecordName(); if (!recordNameValue.IsString()) { current = PopFromProfileQueue(); continue; @@ -458,7 +458,7 @@ void PGOProfiler::HandlePGODump(bool force) if (recordInfos_->AddMethod(recordType, Method::Cast(methodValue), SampleMode::HOTNESS_MODE)) { methodCount_++; } - ProfileBytecode(abcId, recordName, methodValue); + ProfileBytecode(abcId, recordName, value); current = PopFromProfileQueue(); } if (state_ == State::PAUSE) { @@ -515,10 +515,15 @@ bool PGOProfiler::PausePGODump() return false; } -void PGOProfiler::ProfileBytecode(ApEntityId abcId, const CString &recordName, JSTaggedValue value) +void PGOProfiler::ProfileBytecode(ApEntityId abcId, const CString &recordName, JSTaggedValue funcValue) { - Method *method = Method::Cast(value.GetTaggedObject()); - JSTaggedValue profileTypeInfoVal = method->GetProfileTypeInfo(); + JSFunction *function = JSFunction::Cast(funcValue); + if (function->GetClass()->IsJSSharedFunction() || + function->GetFunctionKind() == ecmascript::FunctionKind::CONCURRENT_FUNCTION) { + return; + } + Method *method = Method::Cast(function->GetMethod()); + JSTaggedValue profileTypeInfoVal = function->GetProfileTypeInfo(); ASSERT(!profileTypeInfoVal.IsUndefined()); auto profileTypeInfo = ProfileTypeInfo::Cast(profileTypeInfoVal.GetTaggedObject()); auto methodId = method->GetMethodId(); @@ -847,7 +852,9 @@ void PGOProfiler::DumpICByNameWithHandler(ApEntityId abcId, const CString &recor } else if (secondValue.IsPrototypeHandler()) { auto prototypeHandler = PrototypeHandler::Cast(secondValue.GetTaggedObject()); auto cellValue = prototypeHandler->GetProtoCell(); - ASSERT(cellValue.IsProtoChangeMarker()); + if (cellValue.IsUndefined()) { + return; + } ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject()); if (cell->GetHasChanged()) { return; @@ -894,7 +901,9 @@ void PGOProfiler::DumpICByNameWithHandler(ApEntityId abcId, const CString &recor } else if (secondValue.IsPrototypeHandler()) { auto prototypeHandler = PrototypeHandler::Cast(secondValue.GetTaggedObject()); auto cellValue = prototypeHandler->GetProtoCell(); - ASSERT(cellValue.IsProtoChangeMarker()); + if (cellValue.IsUndefined()) { + return; + } ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject()); if (cell->GetHasChanged()) { return; diff --git a/ecmascript/pgo_profiler/pgo_profiler.h b/ecmascript/pgo_profiler/pgo_profiler.h index eaad43d6b958653c9c76b830c7339661f5a57d6b..8d4b7f757e5069db7dd9bb3d7f1c401a148ffe3e 100644 --- a/ecmascript/pgo_profiler/pgo_profiler.h +++ b/ecmascript/pgo_profiler/pgo_profiler.h @@ -110,7 +110,7 @@ private: FORCE_SAVE_PAUSE, }; - void ProfileBytecode(ApEntityId abcId, const CString &recordName, JSTaggedValue value); + void ProfileBytecode(ApEntityId abcId, const CString &recordName, JSTaggedValue funcValue); bool PausePGODump(); void DumpICByName(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId, diff --git a/ecmascript/pgo_profiler/tests/pgo_profiler_test.cpp b/ecmascript/pgo_profiler/tests/pgo_profiler_test.cpp index 2009529a94cae134b052ca61a8dbbdb8c5997c0c..081b003bb49e6d99fb4a679b7a4888b74ff91525 100644 --- a/ecmascript/pgo_profiler/tests/pgo_profiler_test.cpp +++ b/ecmascript/pgo_profiler/tests/pgo_profiler_test.cpp @@ -22,6 +22,7 @@ #include #include "ecmascript/base/file_header.h" +#include "ecmascript/checkpoint/thread_state_transition.h" #include "ecmascript/elements.h" #include "ecmascript/log_wrapper.h" #include "ecmascript/object_factory.h" @@ -203,7 +204,7 @@ protected: } void CheckApMethodsInApFiles(const std::string &fileName, - std::unordered_map> &recordMethodList) + std::unordered_map> &recordMethodList) { std::vector methodLiterals {}; CreateJSPandaFile(fileName.c_str(), methodLiterals); @@ -213,7 +214,7 @@ protected: if (recordEntry == recordMethodList.end()) { continue; } - for (auto index = 0; index < recordEntry->second.size(); ++index) { + for (size_t index = 0; index < recordEntry->second.size(); ++index) { if (!(recordEntry->second.at(index) == methodLiteral->GetMethodId())) { continue; } @@ -243,17 +244,20 @@ HWTEST_F_L0(PGOProfilerTest, Sample) option.SetEnableProfile(true); option.SetProfileDir("ark-profiler/"); vm_ = JSNApi::CreateJSVM(option); - JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); + vm_->GetJSThread()->ManagedCodeBegin(); + JSHandle constPool = vm_->GetFactory()->NewSConstantPool(4); constPool->SetJSPandaFile(pf_.get()); uint32_t checksum = 304293; PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler.abc"); ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; - JSHandle method = vm_->GetFactory()->NewMethod(methodLiterals[0]); + JSHandle method = vm_->GetFactory()->NewSMethod(methodLiterals[0]); method->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); JSHandle recordName(vm_->GetFactory()->NewFromStdString("test")); - method->SetModule(vm_->GetJSThread(), recordName); + JSHandle func = vm_->GetFactory()->NewJSFunction(vm_->GetGlobalEnv(), method); + func->SetModule(vm_->GetJSThread(), recordName); vm_->GetPGOProfiler()->SetSaveTimestamp(std::chrono::system_clock::now()); + vm_->GetJSThread()->ManagedCodeEnd(); JSNApi::DestroyJSVM(vm_); // Loader PGOProfilerDecoder loader("ark-profiler/modules.ap", DECODER_THRESHOLD); @@ -280,23 +284,28 @@ HWTEST_F_L0(PGOProfilerTest, Sample1) option.SetEnableProfile(true); option.SetProfileDir("ark-profiler1/"); vm_ = JSNApi::CreateJSVM(option); - JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); + vm_->GetJSThread()->ManagedCodeBegin(); + JSHandle constPool = vm_->GetFactory()->NewSConstantPool(4); constPool->SetJSPandaFile(pf_.get()); uint32_t checksum = 304293; PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler1.abc"); ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; - JSHandle method = vm_->GetFactory()->NewMethod(methodLiterals[0]); - JSHandle method1 = vm_->GetFactory()->NewMethod(methodLiterals[1]); - JSHandle method2 = vm_->GetFactory()->NewMethod(methodLiterals[2]); + JSHandle method = vm_->GetFactory()->NewSMethod(methodLiterals[0]); + JSHandle method1 = vm_->GetFactory()->NewSMethod(methodLiterals[1]); + JSHandle method2 = vm_->GetFactory()->NewSMethod(methodLiterals[2]); method->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); method1->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); method2->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); + JSHandle func = vm_->GetFactory()->NewJSFunction(vm_->GetGlobalEnv(), method); + JSHandle func1 = vm_->GetFactory()->NewJSFunction(vm_->GetGlobalEnv(), method1); + JSHandle func2 = vm_->GetFactory()->NewJSFunction(vm_->GetGlobalEnv(), method2); JSHandle recordName(vm_->GetFactory()->NewFromStdString("test")); - method->SetModule(vm_->GetJSThread(), recordName); - method1->SetModule(vm_->GetJSThread(), recordName); - method2->SetModule(vm_->GetJSThread(), recordName); + func->SetModule(vm_->GetJSThread(), recordName); + func1->SetModule(vm_->GetJSThread(), recordName); + func2->SetModule(vm_->GetJSThread(), recordName); + vm_->GetJSThread()->ManagedCodeEnd(); JSNApi::DestroyJSVM(vm_); // Loader @@ -331,21 +340,25 @@ HWTEST_F_L0(PGOProfilerTest, Sample2) option.SetEnableProfile(true); option.SetProfileDir("ark-profiler2/"); vm_ = JSNApi::CreateJSVM(option); - JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); + vm_->GetJSThread()->ManagedCodeBegin(); + JSHandle constPool = vm_->GetFactory()->NewSConstantPool(4); constPool->SetJSPandaFile(pf_.get()); ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; uint32_t checksum = 304293; PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "ark-profiler2.abc"); - JSHandle method = vm_->GetFactory()->NewMethod(methodLiterals[0]); - JSHandle method1 = vm_->GetFactory()->NewMethod(methodLiterals[1]); + JSHandle method = vm_->GetFactory()->NewSMethod(methodLiterals[0]); + JSHandle method1 = vm_->GetFactory()->NewSMethod(methodLiterals[1]); method->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); method1->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); + JSHandle func = vm_->GetFactory()->NewJSFunction(vm_->GetGlobalEnv(), method); JSHandle recordName(vm_->GetFactory()->NewFromStdString("test")); - method->SetModule(vm_->GetJSThread(), recordName); + func->SetModule(vm_->GetJSThread(), recordName); + JSHandle func1 = vm_->GetFactory()->NewJSFunction(vm_->GetGlobalEnv(), method1); JSHandle recordName1(vm_->GetFactory()->NewFromStdString("test1")); - method1->SetModule(vm_->GetJSThread(), recordName1); + func1->SetModule(vm_->GetJSThread(), recordName1); + vm_->GetJSThread()->ManagedCodeEnd(); JSNApi::DestroyJSVM(vm_); // Loader @@ -383,18 +396,21 @@ HWTEST_F_L0(PGOProfilerTest, DisEnableSample) option.SetEnableProfile(false); option.SetProfileDir("ark-profiler3/"); vm_ = JSNApi::CreateJSVM(option); + vm_->GetJSThread()->ManagedCodeBegin(); JSPandaFileManager::GetInstance()->AddJSPandaFileVm(vm_, pf_); - JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); + JSHandle constPool = vm_->GetFactory()->NewSConstantPool(4); constPool->SetJSPandaFile(pf_.get()); uint32_t checksum = pf_->GetChecksum(); PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "sample_test.abc"); ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; - JSHandle method = vm_->GetFactory()->NewMethod(methodLiterals[0]); + JSHandle method = vm_->GetFactory()->NewSMethod(methodLiterals[0]); method->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); + JSHandle func = vm_->GetFactory()->NewJSFunction(vm_->GetGlobalEnv(), method); JSHandle recordName(vm_->GetFactory()->NewFromStdString("sample_test")); - method->SetModule(vm_->GetJSThread(), recordName); + func->SetModule(vm_->GetJSThread(), recordName); + vm_->GetJSThread()->ManagedCodeEnd(); JSNApi::DestroyJSVM(vm_); // Loader @@ -439,14 +455,17 @@ HWTEST_F_L0(PGOProfilerTest, PGOProfilerManagerSample) currentPath[PATH_MAX + 1] = '\0'; option.SetProfileDir(currentPath); vm_ = JSNApi::CreateJSVM(option); + vm_->GetJSThread()->ManagedCodeBegin(); uint32_t checksum = 304293; PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, ""); ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; // RecordName is hole MethodLiteral *methodLiteral = new MethodLiteral(EntityId(61)); - JSHandle method = vm_->GetFactory()->NewMethod(methodLiteral); - method->SetModule(vm_->GetJSThread(), JSTaggedValue::Hole()); + JSHandle method = vm_->GetFactory()->NewSMethod(methodLiteral); + JSHandle func = vm_->GetFactory()->NewJSFunction(vm_->GetGlobalEnv(), method); + func->SetModule(vm_->GetJSThread(), JSTaggedValue::Hole()); + vm_->GetJSThread()->ManagedCodeEnd(); JSNApi::DestroyJSVM(vm_); PGOProfilerDecoder loader("", DECODER_THRESHOLD); @@ -470,34 +489,48 @@ HWTEST_F_L0(PGOProfilerTest, PGOProfilerDoubleVM) // outDir is empty option.SetProfileDir("ark-profiler5/"); vm_ = JSNApi::CreateJSVM(option); + vm_->GetJSThread()->ManagedCodeBegin(); JSPandaFileManager::GetInstance()->AddJSPandaFileVm(vm_, pf_); - JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); + JSHandle constPool = vm_->GetFactory()->NewSConstantPool(4); constPool->SetJSPandaFile(pf_.get()); uint32_t checksum = 304293; PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "sample_test.abc"); ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; // worker vm read profile enable from PGOProfilerManager singleton option.SetEnableProfile(false); - auto vm2 = JSNApi::CreateJSVM(option); - JSHandle constPool2 = vm2->GetFactory()->NewConstantPool(4); - constPool2->SetJSPandaFile(pf_.get()); - PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "sample_test.abc"); - ASSERT_TRUE(vm2 != nullptr) << "Cannot create Runtime"; - JSHandle method = vm2->GetFactory()->NewMethod(methodLiterals[0]); - method->SetConstantPool(vm2->GetJSThread(), constPool2.GetTaggedValue()); + std::thread t1([&]() { + auto vm2 = JSNApi::CreateJSVM(option); + vm2->GetJSThread()->ManagedCodeBegin(); + JSHandle constPool2 = vm2->GetFactory()->NewSConstantPool(4); + constPool2->SetJSPandaFile(pf_.get()); + PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "sample_test.abc"); + ASSERT_TRUE(vm2 != nullptr) << "Cannot create Runtime"; + + JSHandle method = vm2->GetFactory()->NewSMethod(methodLiterals[0]); + method->SetConstantPool(vm2->GetJSThread(), constPool2.GetTaggedValue()); + JSHandle func = vm2->GetFactory()->NewJSFunction(vm_->GetGlobalEnv(), method); + JSHandle recordName(vm2->GetFactory()->NewFromStdString("sample_test")); + func->SetModule(vm2->GetJSThread(), recordName); + vm2->GetJSThread()->ManagedCodeEnd(); + JSNApi::DestroyJSVM(vm2); + }); + { + ThreadSuspensionScope scope(vm_->GetJSThread()); + t1.join(); + } JSHandle recordName(vm_->GetFactory()->NewFromStdString("sample_test")); - method->SetModule(vm2->GetJSThread(), recordName); - - JSHandle method1 = vm_->GetFactory()->NewMethod(methodLiterals[0]); - JSHandle method2 = vm_->GetFactory()->NewMethod(methodLiterals[1]); + JSHandle method1 = vm_->GetFactory()->NewSMethod(methodLiterals[0]); + JSHandle method2 = vm_->GetFactory()->NewSMethod(methodLiterals[1]); method1->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); method2->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); + JSHandle func1 = vm_->GetFactory()->NewJSFunction(vm_->GetGlobalEnv(), method1); + JSHandle func2 = vm_->GetFactory()->NewJSFunction(vm_->GetGlobalEnv(), method2); JSHandle recordName1(vm_->GetFactory()->NewFromStdString("sample_test")); - method1->SetModule(vm_->GetJSThread(), recordName); - method2->SetModule(vm_->GetJSThread(), recordName); + func1->SetModule(vm_->GetJSThread(), recordName); + func2->SetModule(vm_->GetJSThread(), recordName); - JSNApi::DestroyJSVM(vm2); + vm_->GetJSThread()->ManagedCodeEnd(); JSNApi::DestroyJSVM(vm_); PGOProfilerDecoder loader("ark-profiler5/profiler", DECODER_THRESHOLD); @@ -530,17 +563,20 @@ HWTEST_F_L0(PGOProfilerTest, PGOProfilerDecoderNoHotMethod) option.SetEnableProfile(true); option.SetProfileDir("ark-profiler8/"); vm_ = JSNApi::CreateJSVM(option); + vm_->GetJSThread()->ManagedCodeBegin(); JSPandaFileManager::GetInstance()->AddJSPandaFileVm(vm_, pf_); - JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); + JSHandle constPool = vm_->GetFactory()->NewSConstantPool(4); constPool->SetJSPandaFile(pf_.get()); uint32_t checksum = pf_->GetChecksum(); PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "sample_test.abc"); - JSHandle method = vm_->GetFactory()->NewMethod(methodLiterals[0]); + JSHandle method = vm_->GetFactory()->NewSMethod(methodLiterals[0]); method->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); + JSHandle func = vm_->GetFactory()->NewJSFunction(vm_->GetGlobalEnv(), method); JSHandle recordName(vm_->GetFactory()->NewFromStdString("sample_test")); - method->SetModule(vm_->GetJSThread(), recordName); + func->SetModule(vm_->GetJSThread(), recordName); + vm_->GetJSThread()->ManagedCodeEnd(); JSNApi::DestroyJSVM(vm_); PGOProfilerDecoder loader("ark-profiler8/modules.ap", DECODER_THRESHOLD); @@ -572,8 +608,9 @@ HWTEST_F_L0(PGOProfilerTest, PGOProfilerPostTask) option.SetEnableProfile(true); option.SetProfileDir("ark-profiler9/"); vm_ = JSNApi::CreateJSVM(option); + vm_->GetJSThread()->ManagedCodeBegin(); JSPandaFileManager::GetInstance()->AddJSPandaFileVm(vm_, pf_); - JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); + JSHandle constPool = vm_->GetFactory()->NewSConstantPool(4); constPool->SetJSPandaFile(pf_.get()); uint32_t checksum = 304293; PGOProfilerManager::GetInstance()->SetApGenMode(ApGenMode::OVERWRITE); @@ -581,11 +618,13 @@ HWTEST_F_L0(PGOProfilerTest, PGOProfilerPostTask) JSHandle recordName(vm_->GetFactory()->NewFromStdString("ark-profiler9.abc")); for (int i = 61; i < 91; i++) { - JSHandle method = vm_->GetFactory()->NewMethod(methodLiterals[i]); + JSHandle method = vm_->GetFactory()->NewSMethod(methodLiterals[i]); method->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); - method->SetModule(vm_->GetJSThread(), recordName); + JSHandle func = vm_->GetFactory()->NewJSFunction(vm_->GetGlobalEnv(), method); + func->SetModule(vm_->GetJSThread(), recordName); } + vm_->GetJSThread()->ManagedCodeEnd(); JSNApi::DestroyJSVM(vm_); PGOProfilerDecoder loader("ark-profiler9/modules.ap", DECODER_THRESHOLD); @@ -657,18 +696,21 @@ HWTEST_F_L0(PGOProfilerTest, FailResetProfilerInWorker) option.SetProfileDir("ark-profiler12/"); // PgoProfiler is disabled as default. vm_ = JSNApi::CreateJSVM(option); + vm_->GetJSThread()->ManagedCodeBegin(); JSPandaFileManager::GetInstance()->AddJSPandaFileVm(vm_, pf_); uint32_t checksum = pf_->GetChecksum(); PGOProfilerManager::GetInstance()->SamplePandaFileInfo(checksum, "sample_test.abc"); ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime"; - JSHandle method = vm_->GetFactory()->NewMethod(methodLiterals[0]); + JSHandle method = vm_->GetFactory()->NewSMethod(methodLiterals[0]); - JSHandle constPool = vm_->GetFactory()->NewConstantPool(4); + JSHandle constPool = vm_->GetFactory()->NewSConstantPool(4); constPool->SetJSPandaFile(pf_.get()); method->SetConstantPool(vm_->GetJSThread(), constPool.GetTaggedValue()); + JSHandle func = vm_->GetFactory()->NewJSFunction(vm_->GetGlobalEnv(), method); JSHandle recordName(vm_->GetFactory()->NewFromStdString("sample_test")); - method->SetModule(vm_->GetJSThread(), recordName); + func->SetModule(vm_->GetJSThread(), recordName); + vm_->GetJSThread()->ManagedCodeEnd(); JSNApi::DestroyJSVM(vm_); // Loader diff --git a/ecmascript/platform/map.h b/ecmascript/platform/map.h index f56cc444b0fc518f5e8eef3627b4c9a3fe686e72..4737ee238c4a28198b271b9561ecc01d86f6f285 100644 --- a/ecmascript/platform/map.h +++ b/ecmascript/platform/map.h @@ -92,6 +92,6 @@ void PageTag(void *mem, size_t size, PageTagType type, const std::string &spaceN void PageClearTag(void *mem, size_t size); const CString GetPageTagString(PageTagType type, const std::string &spaceName, const uint32_t threadId = 0); void PageProtect(void *mem, size_t size, int prot); -size_t PageSize(); +size_t PUBLIC_API PageSize(); } // namespace panda::ecmascript #endif // ECMASCRIPT_PLATFORM_MAP_H diff --git a/ecmascript/property_attributes.h b/ecmascript/property_attributes.h index aef86ddcc3d2f57289d2ec2f9d621cc0b01ab574..a57a38f362244796728802478db8831b3d1d0b4a 100644 --- a/ecmascript/property_attributes.h +++ b/ecmascript/property_attributes.h @@ -35,10 +35,16 @@ enum class TrackType : uint8_t { INT = 0x1ULL, DOUBLE = 0x1ULL << 1, NUMBER = INT | DOUBLE, - TAGGED = 0x1ULL << 2, - BOOLEAN = 5, - STRING = 6, - SENDABLE = 7 + TAGGED = 0x1ULL << 2 +}; + +enum class SharedFieldType : uint8_t { + NONE = 0, + NUMBER = 1, + STRING = 2, + BOOLEAN = 3, + SENDABLE = 4, + BIG_INT = 5, }; enum class PropertyBoxType { @@ -64,13 +70,14 @@ enum class PropertyBoxType { * -------------------------------- * Fast | OffsetField(bit 8...17) * | TrackTypeField(bit 18...20) - * | SortedIndexField(bit 21...30) - * | IsConstPropsField(bit 31) - * | IsNotHoleField(bit 32) + * | SharedFieldTypeField(bit 21...23) + * | SortedIndexField(bit 24...33) + * | IsConstPropsField(bit 34) + * | IsNotHoleField(bit 35) * ----------------------------- * Slow | PropertyBoxTypeField(bit 8...9) * | DictionaryOrderField(bit 10...29) - * | TrackTypeField(bit 30...32) + * | SharedFieldTypeField(bit 30...32) */ class PropertyAttributes { public: @@ -80,21 +87,24 @@ public: DEFAULT_NOEXCEPT_MOVE_SEMANTIC(PropertyAttributes); DEFAULT_COPY_SEMANTIC(PropertyAttributes); - explicit PropertyAttributes(uint32_t v) : value_(v) {} - explicit PropertyAttributes(int32_t v) : value_(static_cast(v)) {} - explicit PropertyAttributes(JSTaggedValue v) : value_(v.GetInt()) {} + explicit PropertyAttributes(uint64_t v) : value_(v) {} + explicit PropertyAttributes(JSTaggedValue v) : value_(JSTaggedValue::UnwrapToUint64(v)) {} explicit PropertyAttributes(const PropertyDescriptor &desc); static constexpr uint32_t DICTIONARY_ORDER_NUM = 20; static constexpr uint32_t OFFSET_BITFIELD_NUM = 10; static constexpr uint32_t REPRESENTATION_NUM = 2; static constexpr uint32_t TRACK_TYPE_NUM = 3; + static constexpr uint32_t FIELD_TYPE_NUM = 3; static constexpr uint32_t MAX_FAST_PROPS_CAPACITY = (1U << OFFSET_BITFIELD_NUM) - 1; static constexpr unsigned BITS_PER_BYTE = 8; - using PropertyMetaDataField = BitField; // 4: property metaData field occupies 4 bits - using AttributesField = BitField; // 4: attributes field occupies 4 bits - using DefaultAttributesField = BitField; // 3: default attributes field occupies 3 bits + static constexpr uint32_t MAX_BIT_SIZE = 48; + static constexpr int INITIAL_PROPERTY_INDEX = 0; + + using PropertyMetaDataField = BitField; // 4: property metaData field occupies 4 bits + using AttributesField = BitField; // 4: attributes field occupies 4 bits + using DefaultAttributesField = BitField; // 3: default attributes field occupies 3 bits using WritableField = BitField; // 1: writable field occupies 1 bits using EnumerableField = WritableField::NextFlag; using ConfigurableField = EnumerableField::NextFlag; @@ -113,14 +123,16 @@ public: using OffsetField = FastModeStartField::NextField; // 17 using TrackTypeField = OffsetField::NextField; // 20: 3 bits - static constexpr uint32_t NORMAL_ATTR_BITS = 20; - using NormalAttrField = BitField; - using SortedIndexField = TrackTypeField::NextField; // 30 - using IsConstPropsField = SortedIndexField::NextFlag; // 31 - using IsNotHoleField = IsConstPropsField::NextFlag; // 32 + // normal attr should include SharedFieldTypeField when set to layout + static constexpr uint32_t NORMAL_ATTR_BITS = 23; + using NormalAttrField = BitField; + using SharedFieldTypeField = TrackTypeField::NextField; // 23: 3 bits + using SortedIndexField = SharedFieldTypeField::NextField; // 33: 10 bits + using IsConstPropsField = SortedIndexField::NextFlag; // 34 + using IsNotHoleField = IsConstPropsField::NextFlag; // 35 using FastModeLastField = IsNotHoleField; static_assert( - FastModeLastField::START_BIT + FastModeLastField::SIZE <= sizeof(uint32_t) * BITS_PER_BYTE, "Invalid"); + FastModeLastField::START_BIT + FastModeLastField::SIZE <= MAX_BIT_SIZE, "Invalid"); // --------------------------------------------------------------------------------------------- // only for dictionary mode, include global @@ -129,15 +141,13 @@ public: static_assert(DictModeStartField::SIZE == CommonLastBitField::SIZE); using PropertyBoxTypeField = DictModeStartField::NextField; // 2: 2 bits, 8-9 using DictionaryOrderField = PropertyBoxTypeField::NextField; // 29 - using DictTrackTypeField = DictionaryOrderField::NextField; - using DictModeLastField = DictTrackTypeField; - static_assert( - DictModeLastField::START_BIT + DictModeLastField::SIZE <= sizeof(uint32_t) * BITS_PER_BYTE, "Invalid"); + using DictSharedFieldTypeField = DictionaryOrderField::NextField; + using DictModeLastField = DictSharedFieldTypeField; - static constexpr uint32_t BIT_SIZE = 28; - static constexpr int INITIAL_PROPERTY_INDEX = 0; + static_assert( + DictModeLastField::START_BIT + DictModeLastField::SIZE <= MAX_BIT_SIZE, "Invalid"); - inline int GetPropertyMetaData() const + inline int32_t GetPropertyMetaData() const { return PropertyMetaDataField::Get(value_); } @@ -149,24 +159,24 @@ public: static PropertyAttributes Default(bool w, bool e, bool c, bool isAccessor = false) { - uint32_t value = WritableField::Encode(w) | EnumerableField::Encode(e) | ConfigurableField::Encode(c) | + uint64_t value = WritableField::Encode(w) | EnumerableField::Encode(e) | ConfigurableField::Encode(c) | IsAccessorField::Encode(isAccessor); return PropertyAttributes(value); } static PropertyAttributes DefaultAccessor(bool w, bool e, bool c) { - uint32_t value = WritableField::Encode(w) | EnumerableField::Encode(e) | ConfigurableField::Encode(c) | + uint64_t value = WritableField::Encode(w) | EnumerableField::Encode(e) | ConfigurableField::Encode(c) | IsAccessorField::Encode(true); return PropertyAttributes(value); } inline void SetDefaultAttributes() { - AttributesField::Set(DefaultAttributesField::Mask(), &value_); + AttributesField::Set(DefaultAttributesField::Mask(), &value_); } - static inline int GetDefaultAttributes() + static inline int32_t GetDefaultAttributes() { return DefaultAttributesField::Mask(); } @@ -194,12 +204,12 @@ public: inline bool IsDefaultAttributes() const { - return AttributesField::Get(value_) == static_cast(DefaultAttributesField::Mask()); + return AttributesField::Get(value_) == static_cast(DefaultAttributesField::Mask()); } inline void SetNoneAttributes() { - AttributesField::Set(0U, &value_); + AttributesField::Set(0U, &value_); } inline bool IsNoneAttributes() const @@ -209,7 +219,7 @@ public: inline void SetWritable(bool flag) { - WritableField::Set(flag, &value_); + WritableField::Set(flag, &value_); } inline bool IsWritable() const { @@ -217,7 +227,7 @@ public: } inline void SetEnumerable(bool flag) { - EnumerableField::Set(flag, &value_); + EnumerableField::Set(flag, &value_); } inline bool IsEnumerable() const { @@ -225,7 +235,7 @@ public: } inline void SetConfigurable(bool flag) { - ConfigurableField::Set(flag, &value_); + ConfigurableField::Set(flag, &value_); } inline bool IsConfigurable() const { @@ -234,7 +244,7 @@ public: inline void SetIsAccessor(bool flag) { - IsAccessorField::Set(flag, &value_); + IsAccessorField::Set(flag, &value_); } inline bool IsAccessor() const @@ -244,7 +254,7 @@ public: inline void SetIsInlinedProps(bool flag) { - IsInlinedPropsField::Set(flag, &value_); + IsInlinedPropsField::Set(flag, &value_); } inline bool IsInlinedProps() const @@ -254,7 +264,7 @@ public: inline void SetIsConstProps(bool flag) { - IsConstPropsField::Set(flag, &value_); + IsConstPropsField::Set(flag, &value_); } inline bool IsConstProps() const @@ -264,7 +274,7 @@ public: inline void SetIsNotHole(bool flag) { - IsNotHoleField::Set(flag, &value_); + IsNotHoleField::Set(flag, &value_); } inline bool IsNotHole() const @@ -291,7 +301,7 @@ public: inline void SetRepresentation(Representation representation) { - RepresentationField::Set(representation, &value_); + RepresentationField::Set(representation, &value_); } inline Representation GetRepresentation() const @@ -306,22 +316,32 @@ public: inline void SetTrackType(TrackType type) { - TrackTypeField::Set(type, &value_); + TrackTypeField::Set(type, &value_); } - inline void SetDictTrackType(TrackType type) + inline SharedFieldType GetSharedFieldType() const { - DictTrackTypeField::Set(type, &value_); + return SharedFieldTypeField::Get(value_); } - inline TrackType GetDictTrackType() const + inline void SetSharedFieldType(SharedFieldType fieldType) { - return DictTrackTypeField::Get(value_); + SharedFieldTypeField::Set(fieldType, &value_); + } + + inline void SetDictSharedFieldType(SharedFieldType fieldType) + { + DictSharedFieldTypeField::Set(fieldType, &value_); + } + + inline SharedFieldType GetDictSharedFieldType() const + { + return DictSharedFieldTypeField::Get(value_); } inline void SetDictionaryOrder(uint32_t order) { - DictionaryOrderField::Set(order, &value_); + DictionaryOrderField::Set(order, &value_); } inline uint32_t GetDictionaryOrder() const { @@ -330,8 +350,9 @@ public: inline void SetOffset(uint32_t offset) { - OffsetField::Set(offset, &value_); + OffsetField::Set(offset, &value_); } + inline uint32_t GetOffset() const { return OffsetField::Get(value_); @@ -339,7 +360,7 @@ public: inline void SetSortedIndex(uint32_t sortedIndex) { - SortedIndexField::Set(sortedIndex, &value_); + SortedIndexField::Set(sortedIndex, &value_); } inline uint32_t GetSortedIndex() const { @@ -348,7 +369,7 @@ public: inline void SetNormalAttr(uint32_t normalAttr) { - NormalAttrField::Set(normalAttr, &value_); + NormalAttrField::Set(normalAttr, &value_); } inline uint32_t GetNormalAttr() const @@ -358,17 +379,17 @@ public: inline JSTaggedValue GetNormalTagged() const { - return JSTaggedValue(static_cast(GetNormalAttr())); + return JSTaggedValue::WrapUint64(GetNormalAttr()); } - inline uint32_t GetValue() const + inline uint64_t GetValue() const { return value_; } inline void SetBoxType(PropertyBoxType cellType) { - PropertyBoxTypeField::Set(cellType, &value_); + PropertyBoxTypeField::Set(cellType, &value_); } inline PropertyBoxType GetBoxType() const @@ -383,11 +404,11 @@ public: inline JSTaggedValue GetTaggedValue() const { - return JSTaggedValue(static_cast(value_)); + return JSTaggedValue::WrapUint64(value_); } private: - uint32_t value_{0}; + uint64_t value_{0}; }; } // namespace panda::ecmascript #endif // ECMASCRIPT_PROPERTY_ATTRIBUTES_H diff --git a/ecmascript/runtime.cpp b/ecmascript/runtime.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d5140e7ffe1c7c16e625c33bd24abeefb757fb3 --- /dev/null +++ b/ecmascript/runtime.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2024 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/runtime.h" +#include + +#include "ecmascript/compiler/aot_file/an_file_data_manager.h" +#include "ecmascript/ecma_vm.h" +#include "ecmascript/ecma_string_table.h" +#include "ecmascript/log_wrapper.h" +#include "ecmascript/mem/mem_map_allocator.h" +#include "ecmascript/module/js_module_manager.h" +#include "ecmascript/pgo_profiler/pgo_profiler_manager.h" +#include "ecmascript/checkpoint/thread_state_transition.h" +#include "jsnapi_expo.h" + +namespace panda::ecmascript { +using PGOProfilerManager = pgo::PGOProfilerManager; + +int32_t Runtime::vmCount_ = 0; +bool Runtime::firstVmCreated_ = false; +Mutex *Runtime::vmCreationLock_ = new Mutex(); +Runtime *Runtime::instance_ = nullptr; + +Runtime *Runtime::GetInstance() +{ + ASSERT(instance_ != nullptr); + return instance_; +} + +void Runtime::CreateIfFirstVm(const JSRuntimeOptions &options) +{ + LockHolder lock(*vmCreationLock_); + if (!firstVmCreated_) { + Log::Initialize(options); + EcmaVM::InitializeIcuData(options); + MemMapAllocator::GetInstance()->Initialize(ecmascript::DEFAULT_REGION_SIZE); + PGOProfilerManager::GetInstance()->Initialize(options.GetPGOProfilerPath(), + options.GetPGOHotnessThreshold()); + ASSERT(instance_ == nullptr); + instance_ = new Runtime(); + firstVmCreated_ = true; + } +} + +void Runtime::InitializeIfFirstVm(EcmaVM *vm) +{ + { + LockHolder lock(*vmCreationLock_); + if (++vmCount_ == 1) { + ThreadManagedScope managedScope(vm->GetAssociatedJSThread()); + PreInitialization(vm); + vm->Initialize(); + PostInitialization(vm); + } + } + if (!vm->IsInitialized()) { + ThreadManagedScope managedScope(vm->GetAssociatedJSThread()); + vm->Initialize(); + } +} + +void Runtime::PreInitialization(const EcmaVM *vm) +{ + mainThread_ = vm->GetAssociatedJSThread(); + nativeAreaAllocator_ = std::make_unique(); + heapRegionAllocator_ = std::make_unique(); + stringTable_ = std::make_unique(); + SharedHeap::GetInstance()->Initialize(nativeAreaAllocator_.get(), heapRegionAllocator_.get(), + const_cast(vm)->GetJSOptions()); +} + +void Runtime::PostInitialization(const EcmaVM *vm) +{ + // Use the main thread's globalconst after it has initialized, + // and copy shared parts to other thread's later. + globalConstants_ = mainThread_->GlobalConstants(); + globalEnv_ = vm->GetGlobalEnv().GetTaggedValue(); + SharedHeap::GetInstance()->PostInitialization(globalConstants_, const_cast(vm)->GetJSOptions()); + // [[todo::DaiHN]] need adding root iterate. + SharedModuleManager::GetInstance()->Initialize(vm); +} + +void Runtime::DestroyIfLastVm() +{ + LockHolder lock(*vmCreationLock_); + if (--vmCount_ <= 0) { + AnFileDataManager::GetInstance()->SafeDestroyAllData(); + MemMapAllocator::GetInstance()->Finalize(); + PGOProfilerManager::GetInstance()->Destroy(); + ASSERT(instance_ != nullptr); + delete instance_; + instance_ = nullptr; + firstVmCreated_ = false; + } +} + +void Runtime::RegisterThread(JSThread* newThread) +{ + LockHolder lock(threadsLock_); + threads_.emplace_back(newThread); + // send all current suspended requests to the new thread + for (uint32_t i = 0; i < suspendNewCount_; i++) { + newThread->SuspendThread(true); + } +} + +// Note: currently only called when thread is to be destroyed. +void Runtime::UnregisterThread(JSThread* thread) +{ + LockHolder lock(threadsLock_); + ASSERT(!thread->IsInRunningState()); + threads_.remove(thread); +} + +void Runtime::SuspendAll(JSThread *current) +{ + ASSERT(current != nullptr); + ASSERT(!current->IsInRunningState()); + ASSERT(!mutatorLock_.HasLock()); + SuspendAllThreadsImpl(current); + mutatorLock_.WriteLock(); +} + +void Runtime::ResumeAll(JSThread *current) +{ + ASSERT(current != nullptr); + ASSERT(!current->IsInRunningState()); + ASSERT(mutatorLock_.HasLock()); + mutatorLock_.Unlock(); + ResumeAllThreadsImpl(current); +} + +void Runtime::SuspendAllThreadsImpl(JSThread *current) +{ + LockHolder lock(threadsLock_); + suspendNewCount_++; + for (auto i : threads_) { + if (i != current) { + i->SuspendThread(true); + } + } +} + +void Runtime::ResumeAllThreadsImpl(JSThread *current) +{ + LockHolder lock(threadsLock_); + if (suspendNewCount_ > 0) { + suspendNewCount_--; + } + for (auto i : threads_) { + if (i != current) { + i->ResumeThread(true); + } + } +} + +void Runtime::IterateSerializeRoot(const RootVisitor &v) +{ + for (auto &it : serializeRootMap_) { + for (auto &rootObj : it.second) { + v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(&rootObj))); + } + } +} +} // namespace panda::ecmascript diff --git a/ecmascript/runtime.h b/ecmascript/runtime.h new file mode 100644 index 0000000000000000000000000000000000000000..2802d6dd3d6be687be160c00fa1b3585bcbf8ee1 --- /dev/null +++ b/ecmascript/runtime.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2024 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_RUNTIME_H +#define ECMASCRIPT_RUNTIME_H + +#include "ecmascript/ecma_string_table.h" +#include "ecmascript/global_env_constants.h" +#include "ecmascript/js_runtime_options.h" +#include "ecmascript/js_thread.h" +#include "ecmascript/platform/mutex.h" +#include "ecmascript/mem/heap.h" +#include "ecmascript/module/js_shared_module_manager.h" +#include "ecmascript/mutator_lock.h" + +#include "libpandabase/macros.h" + +#include +#include + +namespace panda::ecmascript { +class Runtime { +public: + static Runtime *GetInstance(); + + static void CreateIfFirstVm(const JSRuntimeOptions &options); + static void DestroyIfLastVm(); + void InitializeIfFirstVm(EcmaVM *vm); + + void RegisterThread(JSThread* newThread); + void UnregisterThread(JSThread* thread); + + void SuspendAll(JSThread *current); + void ResumeAll(JSThread *current); + void IterateSerializeRoot(const RootVisitor &v); + + MutatorLock *GetMutatorLock() + { + return &mutatorLock_; + } + + const MutatorLock *GetMutatorLock() const + { + return &mutatorLock_; + } + + template + void GCIterateThreadList(const Callback &cb) + { + LockHolder lock(threadsLock_); + for (auto thread : threads_) { + if (thread->ReadyForGCIterating()) { + cb(thread); + } + } + } + + inline const GlobalEnvConstants *GetGlobalEnvConstants() + { + return globalConstants_; + } + + JSTaggedValue GetGlobalEnv() const + { + return globalEnv_; + } + + inline EcmaStringTable *GetEcmaStringTable() const + { + return stringTable_.get(); + } + + uint32_t PushSerializationRoot([[maybe_unused]] JSThread *thread, std::vector &rootSet) + { + ASSERT(thread->IsInManagedState()); + LockHolder lock(serializeLock_); + uint32_t index = GetSerializeDataIndex(); + ASSERT(serializeRootMap_.find(index) == serializeRootMap_.end()); + serializeRootMap_.emplace(index, rootSet); + return index; + } + + void RemoveSerializationRoot([[maybe_unused]] JSThread *thread, uint32_t index) + { + ASSERT(thread->IsInManagedState()); + LockHolder lock(serializeLock_); + ASSERT(serializeRootMap_.find(index) != serializeRootMap_.end()); + serializeRootMap_.erase(index); + serializeDataIndexVector_.emplace_back(index); + } + +private: + Runtime() = default; + ~Runtime() = default; + void SuspendAllThreadsImpl(JSThread *current); + void ResumeAllThreadsImpl(JSThread *current); + + void PreInitialization(const EcmaVM *vm); + void PostInitialization(const EcmaVM *vm); + + uint32_t GetSerializeDataIndex() + { + if (!serializeDataIndexVector_.empty()) { + uint32_t index = serializeDataIndexVector_.back(); + serializeDataIndexVector_.pop_back(); + return index; + } + return ++serializeDataIndex_; + } + + Mutex threadsLock_; + Mutex serializeLock_; + std::list threads_; + uint32_t suspendNewCount_ {0}; + uint32_t serializeDataIndex_ {0}; + MutatorLock mutatorLock_; + + const GlobalEnvConstants *globalConstants_ {nullptr}; + JSTaggedValue globalEnv_ {JSTaggedValue::Hole()}; + JSThread *mainThread_ {nullptr}; + // for shared heap. + std::unique_ptr nativeAreaAllocator_; + std::unique_ptr heapRegionAllocator_; + // for stringTable. + std::unique_ptr stringTable_; + std::unordered_map> serializeRootMap_; + std::vector serializeDataIndexVector_; + + // Runtime instance and VMs creation. + static int32_t vmCount_; + static bool firstVmCreated_; + static Mutex *vmCreationLock_; + static Runtime *instance_; + + friend class EcmaVM; + friend class JSThread; + + NO_COPY_SEMANTIC(Runtime); + NO_MOVE_SEMANTIC(Runtime); +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_RUNTIME_H diff --git a/test/fuzztest/jsnapidestory_fuzzer/jsnapidestory_fuzzer.h b/ecmascript/runtime_lock.cpp similarity index 52% rename from test/fuzztest/jsnapidestory_fuzzer/jsnapidestory_fuzzer.h rename to ecmascript/runtime_lock.cpp index 9acb3718ca295e248547bf82a4d6c96b47c886fa..e92ea458ddb89a68107b7c3f87c237136ec1fb87 100644 --- a/test/fuzztest/jsnapidestory_fuzzer/jsnapidestory_fuzzer.h +++ b/ecmascript/runtime_lock.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2024 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 + * 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, @@ -13,9 +13,15 @@ * limitations under the License. */ -#ifndef JSNAPIDESTORY_FUZZER_H -#define JSNAPIDESTORY_FUZZER_H +#include "ecmascript/runtime_lock.h" +#include "ecmascript/checkpoint/thread_state_transition.h" +#include "ecmascript/js_thread.h" -#define FUZZ_PROJECT_NAME "jsnapidestory_fuzzer.h" - -#endif \ No newline at end of file +namespace panda::ecmascript { +RuntimeLockHolder::RuntimeLockHolder(JSThread *thread, Mutex &mtx) + : thread_(thread), mtx_(mtx) +{ + ThreadStateTransitionScope ts(thread_, ThreadState::WAIT); + mtx.Lock(); +} +} // namespace panda::ecmascript \ No newline at end of file diff --git a/ecmascript/runtime_lock.h b/ecmascript/runtime_lock.h new file mode 100644 index 0000000000000000000000000000000000000000..6fcdf5e150112299525fe18d5f118cbf6aadacfe --- /dev/null +++ b/ecmascript/runtime_lock.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 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_RUNTIME_LOCK_H +#define ECMASCRIPT_RUNTIME_LOCK_H + +#include "ecmascript/js_thread.h" +#include "ecmascript/platform/mutex.h" +namespace panda::ecmascript { +class RuntimeLockHolder { +public: + RuntimeLockHolder(JSThread *thread, Mutex &mtx); + + ~RuntimeLockHolder() + { + mtx_.Unlock(); + } + +private: + JSThread *thread_; + Mutex &mtx_; + + NO_COPY_SEMANTIC(RuntimeLockHolder); + NO_MOVE_SEMANTIC(RuntimeLockHolder); +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_RUNTIME_LOCK_H \ No newline at end of file diff --git a/ecmascript/serializer/base_deserializer.cpp b/ecmascript/serializer/base_deserializer.cpp index 5f37be3ea387f1a577cd66f9d65c0c80c600f2c6..2d1082e3b8c60d6cd53bdc34ba44c136f01fe3e1 100644 --- a/ecmascript/serializer/base_deserializer.cpp +++ b/ecmascript/serializer/base_deserializer.cpp @@ -23,6 +23,9 @@ #include "ecmascript/js_thread.h" #include "ecmascript/mem/mem.h" #include "ecmascript/mem/sparse_space.h" +#include "ecmascript/platform/mutex.h" +#include "ecmascript/runtime.h" +#include "ecmascript/runtime_lock.h" #include "ecmascript/shared_mm/shared_mm.h" namespace panda::ecmascript { @@ -31,7 +34,10 @@ namespace panda::ecmascript { (uint8_t)SerializedObjectSpace::OLD_SPACE: \ case (uint8_t)SerializedObjectSpace::NON_MOVABLE_SPACE: \ case (uint8_t)SerializedObjectSpace::MACHINE_CODE_SPACE: \ - case (uint8_t)SerializedObjectSpace::HUGE_SPACE + case (uint8_t)SerializedObjectSpace::HUGE_SPACE: \ + case (uint8_t)SerializedObjectSpace::SHARED_OLD_SPACE: \ + case (uint8_t)SerializedObjectSpace::SHARED_NON_MOVABLE_SPACE: \ + case (uint8_t)SerializedObjectSpace::SHARED_HUGE_SPACE JSHandle BaseDeserializer::ReadValue() { @@ -52,8 +58,8 @@ JSHandle BaseDeserializer::DeserializeJSTaggedValue() heap_->SetOnSerializeEvent(true); uint8_t encodeFlag = data_->ReadUint8(position_); - JSTaggedType result = 0U; - while (ReadSingleEncodeData(encodeFlag, ToUintPtr(&result), 0, true) == 0) { // 0: root object offset + JSHandle resHandle(thread_, JSTaggedValue::Undefined()); + while (ReadSingleEncodeData(encodeFlag, resHandle.GetAddress(), 0, true) == 0) { // 0: root object offset encodeFlag = data_->ReadUint8(position_); } // now new constpool here if newConstPoolInfos_ is not empty @@ -87,11 +93,11 @@ JSHandle BaseDeserializer::DeserializeJSTaggedValue() heap_->SetOnSerializeEvent(false); // If is on concurrent mark, mark push root object to stack for mark - if (JSTaggedValue(result).IsHeapObject() && thread_->IsConcurrentMarkingOrFinished()) { - Barriers::MarkAndPushForDeserialize(thread_, JSTaggedValue(result).GetHeapObject()); + if (resHandle->IsHeapObject() && thread_->IsConcurrentMarkingOrFinished()) { + Barriers::MarkAndPushForDeserialize(thread_, resHandle->GetHeapObject()); } - return JSHandle(thread_, JSTaggedValue(result)); + return resHandle; } uintptr_t BaseDeserializer::DeserializeTaggedObject(SerializedObjectSpace space) @@ -99,21 +105,7 @@ uintptr_t BaseDeserializer::DeserializeTaggedObject(SerializedObjectSpace space) size_t objSize = data_->ReadUint32(position_); uintptr_t res = RelocateObjectAddr(space, objSize); objectVector_.push_back(res); - size_t resIndex = objectVector_.size() - 1; DeserializeObjectField(res, res + objSize); - JSType type = reinterpret_cast(res)->GetClass()->GetObjectType(); - // String need remove duplicates if string table can find - if (type == JSType::LINE_STRING || type == JSType::CONSTANT_STRING) { - EcmaStringTable *stringTable = thread_->GetEcmaVM()->GetEcmaStringTable(); - EcmaString *str = stringTable->GetString(reinterpret_cast(res)); - if (str) { - res = ToUintPtr(str); - objectVector_[resIndex] = res; - } else { - EcmaStringAccessor(reinterpret_cast(res)).ClearInternString(); - stringTable->InternString(reinterpret_cast(res)); - } - } return res; } @@ -132,10 +124,8 @@ void BaseDeserializer::DeserializeConstPool(NewConstPoolInfo *info) JSPandaFile *jsPandaFile = info->jsPandaFile_; panda_file::File::EntityId methodId = info->methodId_; ObjectSlot slot = info->GetSlot(); - JSHandle constpool = ConstantPool::CreateConstPool(thread_->GetEcmaVM(), jsPandaFile, methodId); - panda_file::IndexAccessor indexAccessor(*jsPandaFile->GetPandaFile(), methodId); - int32_t index = static_cast(indexAccessor.GetHeaderIndex()); - thread_->GetCurrentEcmaContext()->AddConstpool(jsPandaFile, constpool.GetTaggedValue(), index); + EcmaContext *context = thread_->GetCurrentEcmaContext(); + JSHandle constpool = context->CreateConstpoolPair(jsPandaFile, methodId); slot.Update(constpool.GetTaggedType()); WriteBarrier(thread_, reinterpret_cast(info->GetObjAddr()), info->GetFieldOffset(), @@ -190,19 +180,10 @@ void BaseDeserializer::HandleNewObjectEncodeFlag(SerializedObjectSpace space, u void *bufferPointer = GetAndResetBufferPointer(); ConstantPool *constpool = GetAndResetConstantPool(); bool needNewConstPool = GetAndResetNeedNewConstPool(); - bool isErrorMsg = GetAndResetIsErrorMsg(); - bool functionInShared = GetAndResetFunctionInShared(); - // deserialize object here uintptr_t addr = DeserializeTaggedObject(space); // deserialize object epilogue - if (isErrorMsg) { - // defer new js error - jsErrorInfos_.back()->errorMsg_ = JSTaggedValue(static_cast(addr)); - return; - } - if (isTransferBuffer) { TransferArrayBufferAttach(addr); } else if (isSharedArrayBuffer) { @@ -216,9 +197,6 @@ void BaseDeserializer::HandleNewObjectEncodeFlag(SerializedObjectSpace space, u newConstPoolInfos_.back()->objAddr_ = addr; newConstPoolInfos_.back()->offset_ = Method::CONSTANT_POOL_OFFSET; } - if (functionInShared) { - concurrentFunctions_.push_back(reinterpret_cast(addr)); - } TaggedObject *object = reinterpret_cast(addr); if (object->GetClass()->IsJSNativePointer()) { JSNativePointer *nativePointer = reinterpret_cast(object); @@ -401,6 +379,7 @@ size_t BaseDeserializer::ReadSingleEncodeData(uint8_t encodeFlag, uintptr_t objA break; } case (uint8_t)EncodeFlag::JS_ERROR: { + slot.Update(JSTaggedValue::Undefined().GetRawData()); uint8_t type = data_->ReadUint8(position_); ASSERT(type >= static_cast(JSType::JS_ERROR_FIRST) && type <= static_cast(JSType::JS_ERROR_LAST)); @@ -412,9 +391,20 @@ size_t BaseDeserializer::ReadSingleEncodeData(uint8_t encodeFlag, uintptr_t objA } break; } - case (uint8_t)EncodeFlag::JS_FUNCTION_IN_SHARED: { - functionInShared_ = true; - handledFieldSize = 0; + case (uint8_t)EncodeFlag::SHARED_OBJECT: { + JSTaggedType value = data_->ReadJSTaggedType(position_); + objectVector_.push_back(value); + bool isErrorMsg = GetAndResetIsErrorMsg(); + if (isErrorMsg) { + // defer new js error + jsErrorInfos_.back()->errorMsg_ = JSTaggedValue(value); + break; + } + if (!isRoot) { + WriteBarrier(thread_, reinterpret_cast(objAddr), fieldOffset, + value); + } + UpdateMaybeWeak(slot, value, GetAndResetWeak()); break; } default: @@ -452,14 +442,41 @@ uintptr_t BaseDeserializer::RelocateObjectAddr(SerializedObjectSpace space, size ASSERT(machineCodeRegionIndex_ < regionVector_.size()); machineCodeSpaceBeginAddr_ = regionVector_[machineCodeRegionIndex_++]->GetBegin(); } - res = nonMovableSpaceBeginAddr_; - nonMovableSpaceBeginAddr_ += objSize; + res = machineCodeSpaceBeginAddr_; + machineCodeSpaceBeginAddr_ += objSize; break; } - default: + case SerializedObjectSpace::HUGE_SPACE: { // no gc for this allocate res = heap_->GetHugeObjectSpace()->Allocate(objSize, thread_); break; + } + case SerializedObjectSpace::SHARED_OLD_SPACE: { + if (sOldSpaceBeginAddr_ + objSize > AlignUp(sOldSpaceBeginAddr_, DEFAULT_REGION_SIZE)) { + ASSERT(sOldRegionIndex_ < regionVector_.size()); + sOldSpaceBeginAddr_ = regionVector_[sOldRegionIndex_++]->GetBegin(); + } + res = sOldSpaceBeginAddr_; + sOldSpaceBeginAddr_ += objSize; + break; + } + case SerializedObjectSpace::SHARED_NON_MOVABLE_SPACE: { + if (sNonMovableSpaceBeginAddr_ + objSize > AlignUp(sNonMovableSpaceBeginAddr_, DEFAULT_REGION_SIZE)) { + ASSERT(sNonMovableRegionIndex_ < regionVector_.size()); + sNonMovableSpaceBeginAddr_ = regionVector_[sNonMovableRegionIndex_++]->GetBegin(); + } + res = sNonMovableSpaceBeginAddr_; + sNonMovableSpaceBeginAddr_ += objSize; + break; + } + case SerializedObjectSpace::SHARED_HUGE_SPACE: { + // no gc for this allocate + res = sheap_->GetHugeObjectSpace()->Allocate(thread_, objSize); + break; + } + default: + LOG_ECMA(FATAL) << "this branch is unreachable"; + UNREACHABLE(); } return res; } @@ -555,6 +572,16 @@ void BaseDeserializer::AllocateToDifferentSpaces() heap_->GetMachineCodeSpace()->IncreaseLiveObjectSize(machineCodeSpaceSize); AllocateToMachineCodeSpace(machineCodeSpaceSize); } + size_t sOldSpaceSize = data_->GetSharedOldSpaceSize(); + if (sOldSpaceSize > 0) { + sheap_->GetOldSpace()->IncreaseLiveObjectSize(sOldSpaceSize); + AllocateToSharedOldSpace(sOldSpaceSize); + } + size_t sNonMovableSpaceSize = data_->GetSharedNonMovableSpaceSize(); + if (sNonMovableSpaceSize > 0) { + sheap_->GetNonMovableSpace()->IncreaseLiveObjectSize(sNonMovableSpaceSize); + AllocateToSharedNonMovableSpace(sNonMovableSpaceSize); + } } void BaseDeserializer::AllocateMultiRegion(SparseSpace *space, size_t spaceObjSize, size_t ®ionIndex) @@ -575,6 +602,32 @@ void BaseDeserializer::AllocateMultiRegion(SparseSpace *space, size_t spaceObjSi space->ResetTopPointer(space->GetCurrentRegion()->GetEnd() - lastRegionRemainSize); } +Region *BaseDeserializer::AllocateMultiSharedRegion(SharedSparseSpace *space, size_t spaceObjSize, size_t ®ionIndex) +{ + regionIndex = regionVector_.size(); + size_t regionAlignedSize = SerializeData::AlignUpRegionAvailableSize(spaceObjSize); + size_t regionNum = regionAlignedSize / Region::GetRegionAvailableSize(); + std::vector regionRemainSizeVector = data_->GetRegionRemainSizeVector(); + std::vector allocateRegions; + while (regionNum > 0) { + if (space->CommittedSizeExceed()) { + LOG_ECMA(FATAL) << "BaseDeserializer::OutOfMemory when deserialize"; + } + Region *region = space->AllocateDeserializeRegion(thread_); + if (regionNum == 1) { // 1: Last allocate region + size_t lastRegionRemainSize = regionAlignedSize - spaceObjSize; + region->SetHighWaterMark(region->GetEnd() - lastRegionRemainSize); + } else { + region->SetHighWaterMark(region->GetEnd() - regionRemainSizeVector[regionRemainSizeIndex_++]); + } + regionVector_.push_back(region); + allocateRegions.push_back(region); + regionNum--; + } + space->MergeDeserializeAllocateRegions(allocateRegions); + return allocateRegions.front(); +} + void BaseDeserializer::AllocateToOldSpace(size_t oldSpaceSize) { SparseSpace *space = heap_->GetOldSpace(); @@ -620,5 +673,29 @@ void BaseDeserializer::AllocateToMachineCodeSpace(size_t machineCodeSpaceSize) } } +void BaseDeserializer::AllocateToSharedOldSpace(size_t sOldSpaceSize) +{ + SharedSparseSpace *space = sheap_->GetOldSpace(); + uintptr_t object = space->AllocateNoGCAndExpand(thread_, sOldSpaceSize); + if (UNLIKELY(object == 0U)) { + Region *region = AllocateMultiSharedRegion(space, sOldSpaceSize, sOldRegionIndex_); + sOldSpaceBeginAddr_ = region->GetBegin(); + } else { + sOldSpaceBeginAddr_ = object; + } +} + +void BaseDeserializer::AllocateToSharedNonMovableSpace(size_t sNonMovableSpaceSize) +{ + SharedNonMovableSpace *space = sheap_->GetNonMovableSpace(); + uintptr_t object = space->AllocateNoGCAndExpand(thread_, sNonMovableSpaceSize); + if (UNLIKELY(object == 0U)) { + Region *region = AllocateMultiSharedRegion(space, sNonMovableSpaceSize, sNonMovableRegionIndex_); + sNonMovableSpaceBeginAddr_ = region->GetBegin(); + } else { + sNonMovableSpaceBeginAddr_ = object; + } +} + } // namespace panda::ecmascript diff --git a/ecmascript/serializer/base_deserializer.h b/ecmascript/serializer/base_deserializer.h index d89fb4e44e4bcb41866c7b8f160245727b9c88e8..8a6e0b74c1e8d075139fe6917294c456a4aaadf4 100644 --- a/ecmascript/serializer/base_deserializer.h +++ b/ecmascript/serializer/base_deserializer.h @@ -105,7 +105,10 @@ struct JSErrorInfo { class BaseDeserializer { public: explicit BaseDeserializer(JSThread *thread, SerializeData *data, void *hint = nullptr) - : thread_(thread), heap_(const_cast(thread->GetEcmaVM()->GetHeap())), data_(data), engine_(hint) {} + : thread_(thread), heap_(const_cast(thread->GetEcmaVM()->GetHeap())), data_(data), engine_(hint) + { + sheap_ = SharedHeap::GetInstance(); + } ~BaseDeserializer() { objectVector_.clear(); @@ -137,9 +140,12 @@ private: void AllocateToDifferentSpaces(); void AllocateMultiRegion(SparseSpace *space, size_t spaceObjSize, size_t ®ionIndex); + Region *AllocateMultiSharedRegion(SharedSparseSpace *space, size_t spaceObjSize, size_t ®ionIndex); void AllocateToOldSpace(size_t oldSpaceSize); void AllocateToNonMovableSpace(size_t nonMovableSpaceSize); void AllocateToMachineCodeSpace(size_t machineCodeSpaceSize); + void AllocateToSharedOldSpace(size_t sOldSpaceSize); + void AllocateToSharedNonMovableSpace(size_t sNonMovableSpaceSize); bool GetAndResetWeak() { @@ -223,16 +229,21 @@ private: private: JSThread *thread_; Heap *heap_; + SharedHeap *sheap_; SerializeData* data_; void *engine_; uintptr_t oldSpaceBeginAddr_ {0}; uintptr_t nonMovableSpaceBeginAddr_ {0}; uintptr_t machineCodeSpaceBeginAddr_ {0}; + uintptr_t sOldSpaceBeginAddr_ {0}; + uintptr_t sNonMovableSpaceBeginAddr_ {0}; CVector objectVector_; CVector regionVector_; size_t oldRegionIndex_ {0}; size_t nonMovableRegionIndex_ {0}; size_t machineCodeRegionIndex_ {0}; + size_t sOldRegionIndex_ {0}; + size_t sNonMovableRegionIndex_ {0}; size_t regionRemainSizeIndex_ {0}; bool isWeak_ {false}; bool isTransferArrayBuffer_ {false}; diff --git a/ecmascript/serializer/base_serializer-inl.h b/ecmascript/serializer/base_serializer-inl.h index ec784d2b189852d8688d5293cd2a64c1a7f2ab38..bbc95655ff9489147912f84f9578b3706301b72a 100644 --- a/ecmascript/serializer/base_serializer-inl.h +++ b/ecmascript/serializer/base_serializer-inl.h @@ -43,7 +43,7 @@ void BaseSerializer::SerializeObjectField(TaggedObject *object) } }; - objXRay_.VisitObjectBody(object, object->GetClass(), visitor); + ObjectXRay::VisitObjectBody(object, object->GetClass(), visitor); } template diff --git a/ecmascript/serializer/base_serializer.cpp b/ecmascript/serializer/base_serializer.cpp index 2ca32a9fe271db7b8bf2aa3fb046632c6346cfd2..3249094c0781c902c2439ccdb5fcefa9f820ce2d 100644 --- a/ecmascript/serializer/base_serializer.cpp +++ b/ecmascript/serializer/base_serializer.cpp @@ -36,6 +36,15 @@ SerializedObjectSpace BaseSerializer::GetSerializedObjectSpace(TaggedObject *obj if (region->InHugeObjectSpace()) { return SerializedObjectSpace::HUGE_SPACE; } + if (region->InSharedOldSpace()) { + return SerializedObjectSpace::SHARED_OLD_SPACE; + } + if (region->InSharedNonMovableSpace()) { + return SerializedObjectSpace::SHARED_NON_MOVABLE_SPACE; + } + if (region->InSharedHugeObjectSpace()) { + return SerializedObjectSpace::SHARED_HUGE_SPACE; + } LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); } @@ -87,6 +96,14 @@ bool BaseSerializer::SerializeRootObject(TaggedObject *object) return false; } +void BaseSerializer::SerializeSharedObject(TaggedObject *object) +{ + data_->WriteEncodeFlag(EncodeFlag::SHARED_OBJECT); + data_->WriteJSTaggedType(reinterpret_cast(object)); + referenceMap_.emplace(object, objectIndex_++); + sharedObjects_.emplace_back(object); +} + bool BaseSerializer::SerializeSpecialObjIndividually(JSType objectType, TaggedObject *root, ObjectSlot start, ObjectSlot end) { @@ -170,6 +187,22 @@ void BaseSerializer::SerializeSFunctionFieldIndividually(TaggedObject *root, Obj while (slot < end) { size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root); switch (fieldOffset) { + case JSFunction::MACHINECODE_OFFSET: + case JSFunction::PROFILE_TYPE_INFO_OFFSET: { + data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE); + data_->WriteJSTaggedValue(JSTaggedValue::Undefined()); + slot++; + break; + } + case JSFunction::ECMA_MODULE_OFFSET: { + // Module of shared function should write pointer directly when serialize + TaggedObject *module = JSFunction::Cast(root)->GetModule().GetTaggedObject(); + if (!SerializeReference(module)) { + SerializeSharedObject(module); + } + slot++; + break; + } case JSFunction::WORK_NODE_POINTER_OFFSET: { data_->WriteEncodeFlag(EncodeFlag::MULTI_RAW_DATA); data_->WriteUint32(sizeof(uintptr_t)); @@ -224,7 +257,10 @@ void BaseSerializer::SerializeAsyncFunctionFieldIndividually(TaggedObject *root, } case JSFunction::PROTO_OR_DYNCLASS_OFFSET: case JSFunction::LEXICAL_ENV_OFFSET: - case JSFunction::HOME_OBJECT_OFFSET: { + case JSFunction::MACHINECODE_OFFSET: + case JSFunction::PROFILE_TYPE_INFO_OFFSET: + case JSFunction::HOME_OBJECT_OFFSET: + case JSFunction::ECMA_MODULE_OFFSET: { data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE); data_->WriteJSTaggedValue(JSTaggedValue::Undefined()); slot++; @@ -253,9 +289,7 @@ void BaseSerializer::SerializeMethodFieldIndividually(TaggedObject *root, Object while (slot < end) { size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root); switch (fieldOffset) { - case Method::CONSTANT_POOL_OFFSET: - case Method::PROFILE_TYPE_INFO_OFFSET: - case Method::ECMA_MODULE_OFFSET: { + case Method::CONSTANT_POOL_OFFSET:{ data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE); data_->WriteJSTaggedValue(JSTaggedValue::Undefined()); slot++; diff --git a/ecmascript/serializer/base_serializer.h b/ecmascript/serializer/base_serializer.h index 9500e8cd58b6770b82c7bb4b410031e22a16708e..fe63e4ed8543eb238f2040bbc52aa3759914f41b 100644 --- a/ecmascript/serializer/base_serializer.h +++ b/ecmascript/serializer/base_serializer.h @@ -25,7 +25,7 @@ class Ecmavm; class JSThread; class BaseSerializer { public: - explicit BaseSerializer(JSThread *thread) : thread_(thread), vm_(thread->GetEcmaVM()), objXRay_(vm_) + explicit BaseSerializer(JSThread *thread) : thread_(thread), vm_(thread->GetEcmaVM()) { data_.reset(new SerializeData(thread)); } @@ -50,6 +50,7 @@ protected: void SerializeTaggedObject(TaggedObject *object); bool SerializeReference(TaggedObject *object); bool SerializeRootObject(TaggedObject *object); + void SerializeSharedObject(TaggedObject *object); template void SerializeObjectField(TaggedObject *object); bool SerializeSpecialObjIndividually(JSType objectType, TaggedObject *root, ObjectSlot start, ObjectSlot end); @@ -66,9 +67,9 @@ protected: protected: JSThread *thread_; EcmaVM *vm_; - ObjectXRay objXRay_; std::unique_ptr data_; CUnorderedMap referenceMap_; + std::vector sharedObjects_; size_t objectIndex_ {0}; static constexpr size_t PARENT_ENV_SLOT = sizeof(TaggedObject); static constexpr size_t SCOPE_INFO_SLOT = PARENT_ENV_SLOT * 2; // 2: the second object slot of lexical env diff --git a/ecmascript/serializer/serialize_data.h b/ecmascript/serializer/serialize_data.h index d06c182549d7ee0c39992d68a666db61e05785e5..b46628d51e95625b9c21b4b134970c8a3852c429 100644 --- a/ecmascript/serializer/serialize_data.h +++ b/ecmascript/serializer/serialize_data.h @@ -18,20 +18,25 @@ #include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/mem/dyn_chunk.h" +#include "ecmascript/runtime.h" #include "ecmascript/shared_mm/shared_mm.h" #include "ecmascript/snapshot/mem/snapshot_env.h" namespace panda::ecmascript { constexpr size_t INITIAL_CAPACITY = 64; constexpr int CAPACITY_INCREASE_RATE = 2; +constexpr uint32_t RESERVED_INDEX = 0; enum class EncodeFlag : uint8_t { - // 0x00~0x03 represent new object to different space: + // 0x00~0x06 represent new object to different space: // 0x00: old space // 0x01: non movable space // 0x02: machine code space // 0x03: huge space + // 0x04: shared old space + // 0x05: shared non movable space + // 0x06: shared huge space NEW_OBJECT = 0x00, - REFERENCE = 0x04, + REFERENCE = 0x07, WEAK, PRIMITIVE, MULTI_RAW_DATA, @@ -44,7 +49,7 @@ enum class EncodeFlag : uint8_t { NATIVE_BINDING_OBJECT, JS_ERROR, JS_REG_EXP, - JS_FUNCTION_IN_SHARED, + SHARED_OBJECT, LAST }; @@ -52,7 +57,10 @@ enum class SerializedObjectSpace : uint8_t { OLD_SPACE = 0, NON_MOVABLE_SPACE, MACHINE_CODE_SPACE, - HUGE_SPACE + HUGE_SPACE, + SHARED_OLD_SPACE, + SHARED_NON_MOVABLE_SPACE, + SHARED_HUGE_SPACE }; enum class SerializeType : uint8_t { @@ -71,6 +79,9 @@ public: DecreaseSharedArrayBufferReference(); } free(buffer_); + if (!incompleteData_ && dataIndex_ != RESERVED_INDEX) { + Runtime::GetInstance()->RemoveSerializationRoot(thread_, dataIndex_); + } } NO_COPY_SEMANTIC(SerializeData); NO_MOVE_SEMANTIC(SerializeData); @@ -286,6 +297,16 @@ public: return machineCodeSpaceSize_; } + size_t GetSharedOldSpaceSize() const + { + return sharedOldSpaceSize_; + } + + size_t GetSharedNonMovableSpaceSize() const + { + return sharedNonMovableSpaceSize_; + } + void CalculateSerializedObjectSize(SerializedObjectSpace space, size_t objectSize) { switch (space) { @@ -298,6 +319,12 @@ public: case SerializedObjectSpace::MACHINE_CODE_SPACE: AlignSpaceObjectSize(machineCodeSpaceSize_, objectSize); break; + case SerializedObjectSpace::SHARED_OLD_SPACE: + AlignSpaceObjectSize(sharedOldSpaceSize_, objectSize); + break; + case SerializedObjectSpace::SHARED_NON_MOVABLE_SPACE: + AlignSpaceObjectSize(sharedNonMovableSpaceSize_, objectSize); + break; default: break; } @@ -328,19 +355,32 @@ public: sharedArrayBufferSet_.insert(ptr); } + void SetDataIndex(uint32_t dataIndex) + { + dataIndex_ = dataIndex; + } + + uint32_t GetDataIndex() const + { + return dataIndex_; + } + private: static constexpr size_t U8_SIZE = 1; static constexpr size_t U16_SIZE = 2; static constexpr size_t U32_SIZE = 4; static constexpr size_t U64_SIZE = 8; JSThread *thread_; - uint8_t *buffer_ = nullptr; - uint64_t sizeLimit_ = 0; - size_t bufferSize_ = 0; - size_t bufferCapacity_ = 0; + uint32_t dataIndex_ {RESERVED_INDEX}; + uint8_t *buffer_ {nullptr}; + uint64_t sizeLimit_ {0}; + size_t bufferSize_ {0}; + size_t bufferCapacity_ {0}; size_t oldSpaceSize_ {0}; size_t nonMovableSpaceSize_ {0}; size_t machineCodeSpaceSize_ {0}; + size_t sharedOldSpaceSize_ {0}; + size_t sharedNonMovableSpaceSize_ {0}; bool incompleteData_ {false}; std::vector regionRemainSizeVector_; std::set sharedArrayBufferSet_; diff --git a/ecmascript/serializer/tests/serializer_test.cpp b/ecmascript/serializer/tests/serializer_test.cpp index 27c6e4d72e1d54956962fd5117b039a050973b25..d2aefe484ea9becfe9dff2c02a34a9fe39fabe7a 100644 --- a/ecmascript/serializer/tests/serializer_test.cpp +++ b/ecmascript/serializer/tests/serializer_test.cpp @@ -19,6 +19,7 @@ #include "libpandafile/class_data_accessor-inl.h" #include "ecmascript/builtins/builtins_arraybuffer.h" +#include "ecmascript/checkpoint/thread_state_transition.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" #include "ecmascript/js_array.h" @@ -60,9 +61,11 @@ public: EXPECT_TRUE(ecmaVm != nullptr) << "Cannot create Runtime"; thread = ecmaVm->GetJSThread(); scope = new EcmaHandleScope(thread); + thread->ManagedCodeBegin(); } void Destroy() { + thread->ManagedCodeEnd(); delete scope; scope = nullptr; ecmaVm->SetEnableForceGC(false); @@ -117,7 +120,7 @@ public: ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); EXPECT_FALSE(res.IsEmpty()); - EXPECT_TRUE(res->IsLineString()); + EXPECT_TRUE(res->IsTreeString()); Destroy(); } @@ -131,7 +134,7 @@ public: ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); EXPECT_FALSE(res.IsEmpty()); - EXPECT_TRUE(res->IsLineString()); + EXPECT_TRUE(res->IsSlicedString()); Destroy(); } @@ -168,7 +171,7 @@ public: JSHandle objValue = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); - + JSHandle retObj = JSHandle::Cast(objValue); EXPECT_FALSE(retObj.IsEmpty()); @@ -654,79 +657,6 @@ public: Destroy(); } - void SharedObjectTest1(SerializeData *data) - { - Init(); - BaseDeserializer deserializer(thread, data); - JSHandle res = deserializer.ReadValue(); - EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize SharedObject fail"; - EXPECT_TRUE(res->IsJSSharedObject()) << "[NotJSSharedObject] Deserialize SharedObject fail"; - JSHandle sObj = JSHandle::Cast(res); - - ObjectFactory *factory = ecmaVm->GetFactory(); - JSHandle key1(factory->NewFromASCII("number1")); - JSHandle key2(factory->NewFromASCII("boolean2")); - JSHandle key3(factory->NewFromASCII("string3")); - JSHandle key4(factory->NewFromASCII("funcA")); - JSHandle val1 = JSObject::GetProperty(thread, sObj, key1).GetRawValue(); - JSHandle val2 = JSObject::GetProperty(thread, sObj, key2).GetRawValue(); - JSHandle val3 = JSObject::GetProperty(thread, sObj, key3).GetRawValue(); - JSHandle val4 = JSObject::GetProperty(thread, sObj, key4).GetRawValue(); - EXPECT_TRUE(val4->IsJSSharedFunction()); - EXPECT_EQ(val1->GetInt(), 1024); // 1024 is the expected value - EXPECT_TRUE(val2->ToBoolean()); - JSHandle str3 = JSHandle(val3); - JSHandle strTest3 = factory->NewFromStdString("hello world!"); - EXPECT_TRUE(JSTaggedValue::StringCompare(*str3, *strTest3)); - Destroy(); - } - - void SharedObjectTest2(SerializeData *data) - { - Init(); - BaseDeserializer deserializer(thread, data); - JSHandle res = deserializer.ReadValue(); - EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize SharedObject fail"; - EXPECT_TRUE(res->IsJSSharedObject()) << "[NotJSSharedObject] Deserialize SharedObject fail"; - JSHandle sObj = JSHandle::Cast(res); - - ObjectFactory *factory = ecmaVm->GetFactory(); - JSHandle key1(factory->NewFromASCII("funcA")); - JSHandle key2(factory->NewFromASCII("funcB")); - JSHandle val1 = JSObject::GetProperty(thread, sObj, key1).GetRawValue(); - JSHandle val2 = JSObject::GetProperty(thread, sObj, key2).GetRawValue(); - EXPECT_TRUE(val1->IsJSSharedFunction()); - EXPECT_TRUE(val2->IsJSSharedFunction()); - EXPECT_TRUE(val1->IsCallable()); - JSHandle func1(val1); - EXPECT_FALSE(func1->GetProtoOrHClass().IsHole()); - EXPECT_TRUE(func1->GetLexicalEnv().IsTaggedArray()); - EXPECT_TRUE(func1->GetHomeObject().IsJSSharedObject()); - Destroy(); - } - - void SharedObjectTest3(SerializeData* data) - { - Init(); - BaseDeserializer deserializer(thread, data); - JSHandle res = deserializer.ReadValue(); - EXPECT_FALSE(res.IsEmpty()); - EXPECT_TRUE(res->IsJSSharedObject()) << "[NotJSSharedObject] Deserialize SharedObject fail"; - - JSHandle sObj = JSHandle::Cast(res); - JSHandle array = JSObject::GetOwnPropertyKeys(thread, sObj); - uint32_t length = array->GetLength(); - EXPECT_EQ(length, 10U); - for (uint32_t i = 0; i < length; i++) { - JSHandle key(thread, array->Get(i)); - JSHandle value = - JSObject::GetProperty(thread, JSHandle(sObj), key).GetValue(); - EXPECT_TRUE(value->GetTaggedObject()->GetClass()->IsJSObject()); - } - - Destroy(); - } - void SharedObjectTest4(SerializeData* data) { Init(); @@ -734,7 +664,7 @@ public: JSHandle res = deserializer.ReadValue(); EXPECT_FALSE(res.IsEmpty()); EXPECT_TRUE(res->IsJSSharedObject()) << "[NotJSSharedObject] Deserialize SharedObject fail"; - + JSHandle sObj = JSHandle::Cast(res); JSHandle array = JSObject::GetOwnPropertyKeys(thread, sObj); uint32_t length = array->GetLength(); @@ -875,6 +805,47 @@ public: Destroy(); } + void SerializeCloneListTest1(SerializeData *data) + { + Init(); + BaseDeserializer deserializer(thread, data); + JSHandle res = deserializer.ReadValue(); + ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); + ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); + + EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize CloneListTest1 fail"; + Region *region = Region::ObjectAddressToRange(res->GetTaggedObject()); + EXPECT_TRUE(region->InSharedHeap()); + JSType resType = res->GetTaggedObject()->GetClass()->GetObjectType(); + EXPECT_EQ(resType, JSType::JS_SHARED_OBJECT); + + ObjectFactory *factory = ecmaVm->GetFactory(); + JSHandle key(factory->NewFromASCII("str2str1")); + JSHandle shareObj = + JSObject::GetProperty(thread, JSHandle(res), key).GetValue(); + Region *region1 = Region::ObjectAddressToRange(shareObj->GetTaggedObject()); + EXPECT_TRUE(region1->InSharedHeap()); + Destroy(); + } + + void SerializeCloneListTest2(SerializeData *data) + { + Init(); + BaseDeserializer deserializer(thread, data); + JSHandle res = deserializer.ReadValue(); + ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); + ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); + + EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize CloneListTest2 fail"; + ObjectFactory *factory = ecmaVm->GetFactory(); + JSHandle key(factory->NewFromASCII("shareObj")); + JSHandle shareObj = + JSObject::GetProperty(thread, JSHandle(res), key).GetValue(); + Region *region = Region::ObjectAddressToRange(shareObj->GetTaggedObject()); + EXPECT_TRUE(region->InSharedHeap()); + Destroy(); + } + private: EcmaVM *ecmaVm = nullptr; EcmaHandleScope *scope = nullptr; @@ -920,6 +891,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSSpecialValue) JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSSpecialValueTest, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -936,6 +908,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeLineString) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::LineStringTest, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -956,6 +929,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeTreeString) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TreeStringTest, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -976,6 +950,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeSlicedString) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::SlicedStringTest, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1006,6 +981,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject1) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSPlainObjectTest1, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1036,6 +1012,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject2) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSPlainObjectTest2, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1062,6 +1039,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject3) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSPlainObjectTest3, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1086,6 +1064,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject4) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSPlainObjectTest4, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1140,13 +1119,13 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSError1) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSErrorTest1, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeJSError2) { -#ifdef NDEBUG ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); JSHandle key1(factory->NewFromASCII("error1")); @@ -1166,9 +1145,9 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSError2) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSErrorTest2, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; -#endif }; HWTEST_F_L0(JSSerializerTest, SerializeBigInt) @@ -1196,6 +1175,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeBigInt) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::BigIntTest, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1252,6 +1232,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeNativeBindingObject1) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::NativeBindingObjectTest1, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; } @@ -1286,6 +1267,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeNativeBindingObject2) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::NativeBindingObjectTest2, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; } @@ -1327,6 +1309,7 @@ HWTEST_F_L0(JSSerializerTest, TestSerializeJSSet) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSSetTest, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1355,6 +1338,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeDate) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSDateTest, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1390,6 +1374,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSMap) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSMapTest, jsDeserializerTest, data.release(), map); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1417,6 +1402,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSRegExp) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSRegexpTest, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1451,6 +1437,7 @@ HWTEST_F_L0(JSSerializerTest, TestSerializeJSArray) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSArrayTest, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1471,6 +1458,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeEcmaString1) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::EcmaStringTest1, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1489,6 +1477,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeEcmaString2) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::EcmaStringTest2, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1506,6 +1495,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeInt32_t) JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::Int32Test, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1522,6 +1512,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeDouble) JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::DoubleTest, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1570,6 +1561,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeObjectWithConcurrentFunction) JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::ObjectWithConcurrentFunctionTest, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1627,6 +1619,7 @@ HWTEST_F_L0(JSSerializerTest, TransferJSArrayBuffer1) jsDeserializerTest, data.release(), reinterpret_cast(buffer)); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; // test if detached @@ -1661,6 +1654,7 @@ HWTEST_F_L0(JSSerializerTest, TransferJSArrayBuffer2) jsDeserializerTest, data.release(), reinterpret_cast(buffer)); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; // test if detached @@ -1684,6 +1678,7 @@ HWTEST_F_L0(JSSerializerTest, TransferJSArrayBuffer3) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TransferJSArrayBufferTest3, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; // test if detached @@ -1737,6 +1732,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSArrayBufferShared2) std::string changeStr = "world hello"; std::thread t1(&JSDeserializerTest::JSSharedArrayBufferTest, jsDeserializerTest, data.release(), 12, changeStr.c_str()); + ThreadSuspensionScope scope(thread); t1.join(); EXPECT_TRUE(strcmp((char *)buffer, "world hello") == 0) << "Serialize JSArrayBuffer fail"; delete serializer; @@ -1765,22 +1761,25 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSArrayBufferShared3) std::string changeStr = "world hello"; std::thread t1(&JSDeserializerTest::JSSharedArrayBufferTest, jsDeserializerTest, data.get(), 12, changeStr.c_str()); - t1.join(); - EXPECT_TRUE(strcmp((char *)buffer, "world hello") == 0) << "Serialize JSArrayBuffer fail"; - changeStr = "world hella"; - JSDeserializerTest jsDeserializerTest1; - std::thread t2(&JSDeserializerTest::JSSharedArrayBufferTest, - jsDeserializerTest1, data.get(), 12, changeStr.c_str()); - t2.join(); - EXPECT_TRUE(strcmp((char *)buffer, "world hella") == 0) << "Serialize JSArrayBuffer fail"; - changeStr = "world hellb"; - JSDeserializerTest jsDeserializerTest2; - std::thread t3(&JSDeserializerTest::JSSharedArrayBufferTest, - jsDeserializerTest2, data.get(), 12, changeStr.c_str()); - t3.join(); - EXPECT_TRUE(strcmp((char *)buffer, "world hellb") == 0) << "Serialize JSArrayBuffer fail"; + { + ThreadSuspensionScope scope(thread); + t1.join(); + EXPECT_TRUE(strcmp((char *)buffer, "world hello") == 0) << "Serialize JSArrayBuffer fail"; + changeStr = "world hella"; + JSDeserializerTest jsDeserializerTest1; + std::thread t2(&JSDeserializerTest::JSSharedArrayBufferTest, + jsDeserializerTest1, data.get(), 12, changeStr.c_str()); + t2.join(); + EXPECT_TRUE(strcmp((char *)buffer, "world hella") == 0) << "Serialize JSArrayBuffer fail"; + changeStr = "world hellb"; + JSDeserializerTest jsDeserializerTest2; + std::thread t3(&JSDeserializerTest::JSSharedArrayBufferTest, + jsDeserializerTest2, data.get(), 12, changeStr.c_str()); + t3.join(); + EXPECT_TRUE(strcmp((char *)buffer, "world hellb") == 0) << "Serialize JSArrayBuffer fail"; + } delete serializer; - delete data.release(); + data.reset(); EXPECT_TRUE(JSHandle(jsArrayBuffer)->IsSharedArrayBuffer()); }; @@ -1826,6 +1825,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSTypedArray1) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TypedArrayTest1, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1862,119 +1862,112 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSTypedArray2) std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TypedArrayTest2, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; -HWTEST_F_L0(JSSerializerTest, SerializeSharedObject1) +JSHandle CreateEmptySObject(JSThread *thread) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); - JSHandle ctor = env->GetSObjectFunction(); - JSHandle sObj = - JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(ctor), ctor)); - JSHandle key1(factory->NewFromASCII("number1")); - JSHandle key2(factory->NewFromASCII("boolean2")); - JSHandle key3(factory->NewFromASCII("string3")); - JSHandle key4(factory->NewFromASCII("funcA")); - JSHandle key5(factory->NewFromASCII("funcB")); - JSHandle value1(thread, JSTaggedValue(1024)); - JSHandle value2(thread, JSTaggedValue::True()); - JSHandle value3(factory->NewFromStdString("hello world!")); - - // test func - JSHandle func1 = thread->GetEcmaVM()->GetFactory()->NewSFunction(env, nullptr, - FunctionKind::NORMAL_FUNCTION); - EXPECT_TRUE(*func1 != nullptr); - JSHandle value4(thread, func1.GetTaggedValue()); - EXPECT_TRUE(JSObject::SetProperty(thread, JSHandle(sObj), key1, value1)); - EXPECT_TRUE(JSObject::SetProperty(thread, JSHandle(sObj), key2, value2)); - EXPECT_TRUE(JSObject::SetProperty(thread, JSHandle(sObj), key3, value3)); - EXPECT_TRUE(JSObject::SetProperty(thread, JSHandle(sObj), key4, value4)); - ValueSerializer *serializer = new ValueSerializer(thread); - - // set value to array - JSHandle array = factory->NewJSArray(); - array->SetArrayLength(thread, 1); - JSArray::FastSetPropertyByValue(thread, JSHandle(array), 0, JSHandle(sObj)); - bool success = serializer->WriteValue(thread, JSHandle(sObj), - JSHandle(thread, JSTaggedValue::Undefined()), - JSHandle(array)); - EXPECT_TRUE(success) << "Serialize sObj fail"; - std::unique_ptr data = serializer->Release(); - JSDeserializerTest jsDeserializerTest; - std::thread t1(&JSDeserializerTest::SharedObjectTest1, jsDeserializerTest, data.release()); - t1.join(); - delete serializer; -}; + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + JSHandle nullHandle = globalConst->GetHandledNull(); + JSHandle emptyLayout = factory->CreateSLayoutInfo(0); + JSHandle hclass = factory->NewSEcmaHClass(JSSharedObject::SIZE, 0, JSType::JS_SHARED_OBJECT, nullHandle, + JSHandle(emptyLayout)); + return factory->NewSharedOldSpaceJSObject(hclass); +} -HWTEST_F_L0(JSSerializerTest, SerializeSharedObject2) +JSHandle CreateSObject(JSThread *thread) { - ObjectFactory *factory = ecmaVm->GetFactory(); - JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); - JSHandle ctor = env->GetSObjectFunction(); - JSHandle sObj = - JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(ctor), ctor)); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + JSHandle nullHandle = globalConst->GetHandledNull(); + + uint32_t index = 0; + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + uint32_t length = 4; + JSHandle layout = factory->CreateSLayoutInfo(length); + JSHandle key1(factory->NewFromASCII("str1")); JSHandle key2(factory->NewFromASCII("str2")); - for (int i = 0; i < 10; i++) { - JSHandle sObj1 = - JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(ctor), ctor)); - JSHandle key3(factory->NewFromASCII("str3")); - for (int j = 0; j < 10; j++) { - key3 = JSHandle(thread, EcmaStringAccessor::Concat(ecmaVm, key3, key1)); - JSObject::SetProperty(thread, JSHandle(sObj1), JSHandle(key3), - JSHandle(factory->NewEmptyJSObject())); - } - key2 = JSHandle(thread, EcmaStringAccessor::Concat(ecmaVm, key2, key1)); - EXPECT_TRUE(JSObject::SetProperty(thread, JSHandle(sObj), JSHandle(key2), - JSHandle(sObj1))); + + while (index < length) { + attributes.SetOffset(index); + attributes.SetIsAccessor(false); + key2 = JSHandle(thread, EcmaStringAccessor::Concat(thread->GetEcmaVM(), key2, key1)); + auto stringTable = thread->GetEcmaVM()->GetEcmaStringTable(); + stringTable->GetOrInternString(thread->GetEcmaVM(), *key2); + layout->AddKey(thread, index++, key2.GetTaggedValue(), attributes); } - ValueSerializer *serializer = new ValueSerializer(thread); - // set value to array + JSHandle hclass = factory->NewSEcmaHClass(JSSharedObject::SIZE, length, JSType::JS_SHARED_OBJECT, + nullHandle, JSHandle(layout)); + JSHandle object = factory->NewSharedOldSpaceJSObject(hclass); + uint32_t fieldIndex = 0; + while (fieldIndex < length) { + object->SetPropertyInlinedProps(thread, fieldIndex++, CreateEmptySObject(thread).GetTaggedValue()); + } + return object; +} + + +HWTEST_F_L0(JSSerializerTest, SerializeCloneListTest1) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle shareObj = CreateSObject(thread); + Region *region = Region::ObjectAddressToRange(*shareObj); + EXPECT_TRUE(region->InSharedHeap()); + + JSHandle key(factory->NewFromASCII("str2str1")); + JSHandle shareObj1 = + JSObject::GetProperty(thread, JSHandle(shareObj), JSHandle(key)).GetValue(); + Region *region1 = Region::ObjectAddressToRange(shareObj1->GetTaggedObject()); + EXPECT_TRUE(region1->InSharedHeap()); + JSHandle array = factory->NewJSArray(); - array->SetArrayLength(thread, 1); - JSArray::FastSetPropertyByValue(thread, JSHandle(array), 0, JSHandle(sObj)); - bool success = serializer->WriteValue(thread, JSHandle(sObj), + JSArray::FastSetPropertyByValue(thread, JSHandle(array), 0, JSHandle(shareObj)); + + ValueSerializer *serializer = new ValueSerializer(thread); + bool success = serializer->WriteValue(thread, JSHandle(shareObj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(array)); - EXPECT_TRUE(success) << "Serialize sObj fail"; + EXPECT_TRUE(success) << "SerializeCloneListTest1: Serialize shared obj fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; - std::thread t1(&JSDeserializerTest::SharedObjectTest3, jsDeserializerTest, data.release()); + std::thread t1(&JSDeserializerTest::SerializeCloneListTest1, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; -HWTEST_F_L0(JSSerializerTest, SerializeSharedObject3) +HWTEST_F_L0(JSSerializerTest, SerializeCloneListTest2) { - ObjectFactory *factory = ecmaVm->GetFactory(); - JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); - JSHandle ctor = env->GetSObjectFunction(); - JSHandle sObj = - JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(ctor), ctor)); - JSHandle key1(factory->NewFromASCII("str1")); - JSHandle key2(factory->NewFromASCII("str2")); - JSHandle value1(thread, JSTaggedValue(1)); - for (int i = 0; i < 512; i++) { - key2 = JSHandle(thread, EcmaStringAccessor::Concat(ecmaVm, key2, key1)); - EXPECT_TRUE(JSObject::SetProperty(thread, JSHandle(sObj), JSHandle(key2), - value1)); - } + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle rootObj = factory->NewEmptyJSObject(); + JSHandle shareObj = CreateSObject(thread); + JSHandle noShareObj = CreateSObject(thread); + + JSHandle key1(factory->NewFromASCII("shareObj")); + JSHandle key2(factory->NewFromASCII("noShareObj")); + + JSObject::SetProperty(thread, JSHandle(rootObj), key1, JSHandle(shareObj)); + JSObject::SetProperty(thread, JSHandle(rootObj), key2, JSHandle(noShareObj)); - ValueSerializer *serializer = new ValueSerializer(thread); - // set value to array JSHandle array = factory->NewJSArray(); - array->SetArrayLength(thread, 1); - JSArray::FastSetPropertyByValue(thread, JSHandle(array), 0, JSHandle(sObj)); - bool success = serializer->WriteValue(thread, JSHandle(sObj), + JSArray::FastSetPropertyByValue(thread, JSHandle(array), 0, JSHandle(shareObj)); + + ValueSerializer *serializer = new ValueSerializer(thread); + bool success = serializer->WriteValue(thread, JSHandle(rootObj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(array)); - EXPECT_TRUE(success) << "Serialize sObj fail"; + EXPECT_TRUE(success) << "SerializeCloneListTest2: Serialize shared obj fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; - std::thread t1(&JSDeserializerTest::SharedObjectTest4, jsDeserializerTest, data.release()); + std::thread t1(&JSDeserializerTest::SerializeCloneListTest2, jsDeserializerTest, data.release()); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; diff --git a/ecmascript/serializer/value_serializer.cpp b/ecmascript/serializer/value_serializer.cpp index 82d023270646a8b6c4c8d902ca4d95d40e87ac79..3dadb6a33b10690599100b7eaf5d25d327cf1c86 100644 --- a/ecmascript/serializer/value_serializer.cpp +++ b/ecmascript/serializer/value_serializer.cpp @@ -71,9 +71,8 @@ bool ValueSerializer::CheckObjectCanSerialize(TaggedObject *object, bool &findSh if (defaultCloneShared_ || cloneSharedSet_.find(ToUintPtr(object)) != cloneSharedSet_.end()) { findSharedObject = true; serializeSharedEvent_++; - return true; } - break; + return true; } default: break; @@ -110,6 +109,11 @@ bool ValueSerializer::WriteValue(JSThread *thread, data_->SetIncompleteData(true); return false; } + // Push share root object to runtime map + if (!sharedObjects_.empty()) { + uint32_t index = Runtime::GetInstance()->PushSerializationRoot(thread_, sharedObjects_); + data_->SetDataIndex(index); + } size_t maxSerializerSize = vm_->GetEcmaParamConfiguration().GetMaxJSSerializerSize(); if (data_->Size() > maxSerializerSize) { LOG_ECMA(ERROR) << "The serialization data size has exceed limit Size, current size is: " << data_->Size() @@ -135,6 +139,12 @@ void ValueSerializer::SerializeObjectImpl(TaggedObject *object, bool isWeak) if (SerializeReference(object) || SerializeRootObject(object)) { return; } + Region *region = Region::ObjectAddressToRange(object); + if (object->GetClass()->IsString() || object->GetClass()->IsMethod() || region->InSharedReadOnlySpace() || + (serializeSharedEvent_ == 0 && region->InSharedHeap())) { + SerializeSharedObject(object); + return; + } if (object->GetClass()->IsNativeBindingObject()) { SerializeNativeBindingObject(object); return; @@ -164,19 +174,9 @@ void ValueSerializer::SerializeObjectImpl(TaggedObject *object, bool isWeak) array->SetTrackInfo(thread_, JSTaggedValue::Undefined()); break; } - case JSType::TREE_STRING: - case JSType::SLICED_STRING: - object = EcmaStringAccessor::FlattenNoGC(vm_, EcmaString::Cast(object)); - break; case JSType::JS_REG_EXP: SerializeJSRegExpPrologue(reinterpret_cast(object)); break; - case JSType::JS_SHARED_FUNCTION: { - if (serializeSharedEvent_ > 0) { - data_->WriteEncodeFlag(EncodeFlag::JS_FUNCTION_IN_SHARED); - } - break; - } case JSType::JS_OBJECT: hashfield = Barriers::GetValue(object, JSObject::HASH_OFFSET); Barriers::SetPrimitive(object, JSObject::HASH_OFFSET, JSTaggedValue::VALUE_ZERO); @@ -221,9 +221,9 @@ void ValueSerializer::SerializeJSError(TaggedObject *object) JSHandle msg = JSObject::GetProperty(thread_, JSHandle(thread_, object), handleMsg).GetValue(); if (msg->IsString()) { - EcmaString *str = EcmaStringAccessor::FlattenNoGC(vm_, EcmaString::Cast(msg->GetTaggedObject())); data_->WriteUint8(1); // 1: msg is string - SerializeTaggedObject(str); + // string must be shared + SerializeSharedObject(msg->GetTaggedObject()); } else { data_->WriteUint8(0); // 0: msg is undefined } diff --git a/ecmascript/shared_object_factory.cpp b/ecmascript/shared_object_factory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a6f663191ee37f55846b45b2e2d027a54e8cafc --- /dev/null +++ b/ecmascript/shared_object_factory.cpp @@ -0,0 +1,593 @@ +/* + * Copyright (c) 2023 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/object_factory.h" + +#include "ecmascript/accessor_data.h" +#include "ecmascript/compiler/aot_file/aot_file_manager.h" +#include "ecmascript/ecma_context.h" +#include "ecmascript/global_env_constants-inl.h" +#include "ecmascript/js_function.h" +#include "ecmascript/jspandafile/program_object.h" +#include "ecmascript/layout_info-inl.h" +#include "ecmascript/mem/heap-inl.h" +#include "ecmascript/symbol_table.h" +#include "ecmascript/jspandafile/program_object.h" +#include "ecmascript/module/js_module_source_text.h" +#include "ecmascript/module/js_shared_module.h" + +namespace panda::ecmascript { +void ObjectFactory::NewSObjectHook() const +{ +#ifndef NDEBUG + static std::atomic count = 0; + static uint32_t frequency = vm_->GetJSOptions().GetForceSharedGCFrequency(); + if (frequency == 0 || !vm_->GetJSOptions().EnableForceGC() || !vm_->IsInitialized() || + !thread_->IsAllContextsInitialized()) { + return; + } + if (count++ % frequency == 0) { + sHeap_->CollectGarbage(thread_, TriggerGCType::SHARED_GC, GCReason::OTHER); + } +#endif +} + +JSHandle ObjectFactory::CreateSFunctionClass(uint32_t size, JSType type, + const JSHandle &prototype, bool isAccessor) +{ + const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); + uint32_t fieldOrder = 0; + ASSERT(JSFunction::LENGTH_INLINE_PROPERTY_INDEX == fieldOrder); + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsAccessor(isAccessor); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + JSHandle layoutInfoHandle = CreateSLayoutInfo(JSFunction::LENGTH_OF_INLINE_PROPERTIES); + { + attributes.SetOffset(fieldOrder); + layoutInfoHandle->AddKey(thread_, fieldOrder, globalConst->GetLengthString(), attributes); + fieldOrder++; + } + + ASSERT(JSFunction::NAME_INLINE_PROPERTY_INDEX == fieldOrder); + { + attributes.SetOffset(fieldOrder); + layoutInfoHandle->AddKey(thread_, fieldOrder, + globalConst->GetHandledNameString().GetTaggedValue(), attributes); + fieldOrder++; + } + JSHandle functionClass = NewSEcmaHClass(size, fieldOrder, type, prototype, + JSHandle(layoutInfoHandle)); + functionClass->SetCallable(true); + return functionClass; +} + +JSHandle ObjectFactory::NewSEcmaHClass(uint32_t size, JSType type, uint32_t inlinedProps) +{ + return NewSEcmaHClass(JSHClass::Cast(thread_->GlobalConstants()->GetHClassClass().GetTaggedObject()), + size, type, inlinedProps); +} + +JSHandle ObjectFactory::NewSEcmaHClass(JSHClass *hclass, uint32_t size, JSType type, uint32_t inlinedProps) +{ + NewSObjectHook(); + uint32_t classSize = JSHClass::SIZE; + auto *newClass = static_cast(sHeap_->AllocateNonMovableOrHugeObject(thread_, hclass, classSize)); + newClass->Initialize(thread_, size, type, inlinedProps, thread_->GlobalConstants()->GetHandledEmptySLayoutInfo()); + return JSHandle(thread_, newClass); +} + +// This function don't UpdateProtoClass +JSHandle ObjectFactory::NewSEcmaHClass(uint32_t size, uint32_t inlinedProps, JSType type, + const JSHandle &prototype, const JSHandle &layout) +{ + NewSObjectHook(); + uint32_t classSize = JSHClass::SIZE; + auto *newClass = static_cast(sHeap_->AllocateNonMovableOrHugeObject( + thread_, JSHClass::Cast(thread_->GlobalConstants()->GetHClassClass().GetTaggedObject()), classSize)); + newClass->Initialize(thread_, size, type, inlinedProps, layout); + JSHandle hclass(thread_, newClass); + if (prototype->IsJSObject()) { + prototype->GetTaggedObject()->GetClass()->SetIsPrototype(true); + } + hclass->SetProto(thread_, prototype.GetTaggedValue()); + hclass->SetExtensible(false); + hclass->SetNumberOfProps(inlinedProps); + return hclass; +} + +JSHandle ObjectFactory::NewSEcmaHClassClass(JSHClass *hclass, uint32_t size, JSType type) +{ + NewSObjectHook(); + uint32_t classSize = JSHClass::SIZE; + auto *newClass = static_cast(sHeap_->AllocateClassClass(hclass, classSize)); + newClass->Initialize(thread_, size, type, 0, thread_->GlobalConstants()->GetHandledEmptySLayoutInfo()); + return JSHandle(thread_, newClass); +} + +JSHandle ObjectFactory::NewSEcmaReadOnlyHClass(JSHClass *hclass, uint32_t size, JSType type, + uint32_t inlinedProps) +{ + NewSObjectHook(); + uint32_t classSize = JSHClass::SIZE; + auto *newClass = static_cast(sHeap_->AllocateReadOnlyOrHugeObject(thread_, hclass, classSize)); + newClass->Initialize(thread_, size, type, inlinedProps, thread_->GlobalConstants()->GetHandledEmptySLayoutInfo()); + return JSHandle(thread_, newClass); +} + +JSHandle ObjectFactory::InitSClassClass() +{ + JSHandle hClassHandle = NewSEcmaHClassClass(nullptr, JSHClass::SIZE, JSType::HCLASS); + JSHClass *hclass = reinterpret_cast(hClassHandle.GetTaggedValue().GetTaggedObject()); + hclass->SetClass(thread_, hclass); + return hClassHandle; +} + +JSHandle ObjectFactory::NewSAccessorData() +{ + NewSObjectHook(); + TaggedObject *header = sHeap_->AllocateOldOrHugeObject( + thread_, JSHClass::Cast(thread_->GlobalConstants()->GetAccessorDataClass().GetTaggedObject())); + JSHandle acc(thread_, AccessorData::Cast(header)); + acc->SetGetter(thread_, JSTaggedValue::Undefined()); + acc->SetSetter(thread_, JSTaggedValue::Undefined()); + return acc; +} + +JSHandle ObjectFactory::NewSMethod(const JSPandaFile *jsPandaFile, MethodLiteral *methodLiteral, + JSHandle constpool, uint32_t entryIndex, + bool needSetAotFlag, bool *canFastCall) +{ + JSHandle method; + if (jsPandaFile->IsNewVersion()) { + method = Method::Create(thread_, jsPandaFile, methodLiteral); + } else { + method = NewSMethod(methodLiteral); + method->SetConstantPool(thread_, constpool); + } + if (needSetAotFlag) { + auto aotFileManager = thread_->GetEcmaVM()->GetAOTFileManager(); + aotFileManager->SetAOTFuncEntry(jsPandaFile, nullptr, *method, entryIndex, canFastCall); + } else { + method->ClearAOTFlagsWhenInit(); + } + return method; +} + +JSHandle ObjectFactory::NewSMethod(const MethodLiteral *methodLiteral, MemSpaceType spaceType) +{ + ASSERT(spaceType == SHARED_NON_MOVABLE || spaceType == SHARED_OLD_SPACE); + NewSObjectHook(); + TaggedObject *header = nullptr; + if (spaceType == SHARED_NON_MOVABLE) { + header = sHeap_->AllocateNonMovableOrHugeObject(thread_, + JSHClass::Cast(thread_->GlobalConstants()->GetMethodClass().GetTaggedObject())); + } else { + header = sHeap_->AllocateOldOrHugeObject(thread_, + JSHClass::Cast(thread_->GlobalConstants()->GetMethodClass().GetTaggedObject())); + } + JSHandle method(thread_, header); + InitializeMethod(methodLiteral, method); + return method; +} + +JSHandle ObjectFactory::NewSMethodForNativeFunction(const void *func, FunctionKind kind, + kungfu::BuiltinsStubCSigns::ID builtinId, + MemSpaceType spaceType) +{ + uint32_t numArgs = 2; // function object and this + auto method = NewSMethod(nullptr, spaceType); + method->SetNativePointer(const_cast(func)); + method->SetNativeBit(true); + if (builtinId != kungfu::BuiltinsStubCSigns::INVALID) { + bool isFast = kungfu::BuiltinsStubCSigns::IsFastBuiltin(builtinId); + method->SetFastBuiltinBit(isFast); + method->SetBuiltinId(static_cast(builtinId)); + } + method->SetNumArgsWithCallField(numArgs); + method->SetFunctionKind(kind); + return method; +} + +JSHandle ObjectFactory::NewSFunctionByHClass(const JSHandle &method, + const JSHandle &hclass) +{ + JSHandle function(NewSharedOldSpaceJSObject(hclass)); + hclass->SetCallable(true); + JSFunction::InitializeSFunction(thread_, function, method->GetFunctionKind()); + function->SetMethod(thread_, method); + if (method->IsAotWithCallField()) { + thread_->GetEcmaVM()->GetAOTFileManager()-> + SetAOTFuncEntry(method->GetJSPandaFile(), *function, *method); + } + return function; +} + +// new function with name/length accessor +JSHandle ObjectFactory::NewSFunctionWithAccessor(const void *func, const JSHandle &hclass, + FunctionKind kind, kungfu::BuiltinsStubCSigns::ID builtinId, MemSpaceType spaceType) +{ + ASSERT(spaceType == SHARED_NON_MOVABLE || spaceType == SHARED_OLD_SPACE); + JSHandle method = NewSMethodForNativeFunction(func, kind, builtinId, spaceType); + return NewSFunctionByHClass(method, hclass); +} + +// new function without name/length accessor +JSHandle ObjectFactory::NewSFunctionByHClass(const void *func, const JSHandle &hclass, + FunctionKind kind, kungfu::BuiltinsStubCSigns::ID builtinId, MemSpaceType spaceType) +{ + ASSERT(spaceType == SHARED_NON_MOVABLE || spaceType == SHARED_OLD_SPACE); + JSHandle method = NewSMethodForNativeFunction(func, kind, builtinId, spaceType); + JSHandle function(NewSharedOldSpaceJSObject(hclass)); + hclass->SetCallable(true); + JSFunction::InitializeWithDefaultValue(thread_, function); + function->SetMethod(thread_, method); + return function; +} + +TaggedObject *ObjectFactory::NewSharedOldSpaceObject(const JSHandle &hclass) +{ + NewSObjectHook(); + TaggedObject *header = sHeap_->AllocateOldOrHugeObject(thread_, *hclass); + uint32_t inobjPropCount = hclass->GetInlinedProperties(); + if (inobjPropCount > 0) { + InitializeExtraProperties(hclass, header, inobjPropCount); + } + return header; +} + +JSHandle ObjectFactory::NewSharedOldSpaceJSObject(const JSHandle &jshclass) +{ + JSHandle obj(thread_, JSObject::Cast(NewSharedOldSpaceObject(jshclass))); + JSHandle emptyArray = SharedEmptyArray(); + obj->InitializeHash(); + obj->SetElements(thread_, emptyArray); + obj->SetProperties(thread_, emptyArray); + return obj; +} + +JSHandle ObjectFactory::SharedEmptyArray() const +{ + return JSHandle(thread_->GlobalConstants()->GetHandledEmptyArray()); +} + +JSHandle ObjectFactory::NewSTaggedArrayWithoutInit(uint32_t length) +{ + NewSObjectHook(); + size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), length); + auto arrayClass = JSHClass::Cast(thread_->GlobalConstants()->GetArrayClass().GetTaggedObject()); + TaggedObject *header = sHeap_->AllocateOldOrHugeObject(thread_, arrayClass, size); + JSHandle array(thread_, header); + array->SetLength(length); + return array; +} + +JSHandle ObjectFactory::CreateSLayoutInfo(uint32_t properties) +{ + uint32_t arrayLength = LayoutInfo::ComputeArrayLength(properties); + JSHandle layoutInfoHandle = JSHandle::Cast(NewSTaggedArrayWithoutInit(arrayLength)); + layoutInfoHandle->Initialize(thread_); + return layoutInfoHandle; +} + +JSHandle ObjectFactory::CopyAndReSortSLayoutInfo(const JSHandle &old, int end, int capacity) +{ + ASSERT(capacity >= end); + JSHandle newArr = CreateSLayoutInfo(capacity); + Span sp(old->GetProperties(), end); + for (int i = 0; i < end; i++) { + newArr->AddKey(thread_, i, sp[i].key_, PropertyAttributes(sp[i].attr_)); + } + return newArr; +} + +JSHandle ObjectFactory::NewSDictionaryArray(uint32_t length) +{ + NewSObjectHook(); + ASSERT(length > 0); + size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), length); + auto header = sHeap_->AllocateOldOrHugeObject( + thread_, JSHClass::Cast(thread_->GlobalConstants()->GetDictionaryClass().GetTaggedObject()), size); + JSHandle array(thread_, header); + array->InitializeWithSpecialValue(JSTaggedValue::Undefined(), length); + return array; +} + +JSHandle ObjectFactory::NewSEmptyArray() +{ + NewSObjectHook(); + auto header = sHeap_->AllocateReadOnlyOrHugeObject(thread_, + JSHClass::Cast(thread_->GlobalConstants()->GetArrayClass().GetTaggedObject()), TaggedArray::SIZE); + JSHandle array(thread_, header); + array->SetLength(0); + array->SetExtraLength(0); + return array; +} + +JSHandle ObjectFactory::NewSEmptyMutantArray() +{ + NewSObjectHook(); + auto header = sHeap_->AllocateReadOnlyOrHugeObject(thread_, + JSHClass::Cast(thread_->GlobalConstants()->GetMutantTaggedArrayClass().GetTaggedObject()), TaggedArray::SIZE); + JSHandle array(thread_, header); + array->SetLength(0); + array->SetExtraLength(0); + return array; +} + +JSHandle ObjectFactory::NewSJSNativePointer(void *externalPointer, + const DeleteEntryPoint &callBack, + void *data, + bool nonMovable, + size_t nativeBindingsize, + NativeFlag flag) +{ + NewSObjectHook(); + TaggedObject *header; + auto jsNativePointerClass = JSHClass::Cast(thread_->GlobalConstants()->GetJSNativePointerClass().GetTaggedObject()); + if (nonMovable) { + header = sHeap_->AllocateNonMovableOrHugeObject(thread_, jsNativePointerClass); + } else { + header = sHeap_->AllocateOldOrHugeObject(thread_, jsNativePointerClass); + } + JSHandle obj(thread_, header); + obj->SetExternalPointer(externalPointer); + obj->SetDeleter(callBack); + obj->SetData(data); + obj->SetBindingSize(nativeBindingsize); + obj->SetNativeFlag(flag); + + if (callBack != nullptr) { + vm_->PushToNativePointerList(static_cast(header)); + // In some cases, the size of JS/TS object is too small and the native binding size is too large. + // Check and try trigger concurrent mark here. + } + return obj; +} + +JSHandle ObjectFactory::NewSInternalAccessor(void *setter, void *getter) +{ + NewSObjectHook(); + TaggedObject *header = sHeap_->AllocateNonMovableOrHugeObject(thread_, + JSHClass::Cast(thread_->GlobalConstants()->GetInternalAccessorClass().GetTaggedObject())); + JSHandle obj(thread_, AccessorData::Cast(header)); + obj->SetGetter(thread_, JSTaggedValue::Undefined()); + obj->SetSetter(thread_, JSTaggedValue::Undefined()); + if (setter != nullptr) { + JSHandle setFunc = NewSJSNativePointer(setter, nullptr, nullptr, true); + obj->SetSetter(thread_, setFunc.GetTaggedValue()); + } + if (getter != nullptr) { + JSHandle getFunc = NewSJSNativePointer(getter, nullptr, nullptr, true); + obj->SetGetter(thread_, getFunc); + } + return obj; +} + +JSHandle ObjectFactory::NewSConstantPool(uint32_t capacity) +{ + NewSObjectHook(); + size_t size = ConstantPool::ComputeSize(capacity); + auto header = sHeap_->AllocateOldOrHugeObject( + thread_, JSHClass::Cast(sHeap_->GetGlobalConst()->GetConstantPoolClass().GetTaggedObject()), size); + JSHandle array(thread_, header); + array->InitializeWithSpecialValue(thread_, JSTaggedValue::Hole(), capacity); + return array; +} + +JSHandle ObjectFactory::NewSCOWTaggedArray(uint32_t length, JSTaggedValue initVal) +{ + NewSObjectHook(); + ASSERT(length > 0); + + size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), length); + auto header = sHeap_->AllocateNonMovableOrHugeObject( + thread_, JSHClass::Cast(sHeap_->GetGlobalConst()->GetCOWArrayClass().GetTaggedObject()), size); + JSHandle cowArray(thread_, header); + cowArray->InitializeWithSpecialValue(initVal, length); + return cowArray; +} + +JSHandle ObjectFactory::NewSClassLiteral() +{ + NewSObjectHook(); + TaggedObject *header = sHeap_->AllocateOldOrHugeObject( + thread_, JSHClass::Cast(sHeap_->GetGlobalConst()->GetClassLiteralClass().GetTaggedObject())); + JSHandle emptyArray = EmptyArray(); + + JSHandle classLiteral(thread_, header); + classLiteral->SetArray(thread_, emptyArray); + classLiteral->SetIsAOTUsed(false); + + return classLiteral; +} + +JSHandle ObjectFactory::NewSClassInfoExtractor( + JSHandle method) +{ + NewSObjectHook(); + TaggedObject *header = sHeap_->AllocateOldOrHugeObject( + thread_, JSHClass::Cast(sHeap_->GetGlobalConst()->GetClassInfoExtractorHClass().GetTaggedObject())); + JSHandle obj(thread_, header); + obj->ClearBitField(); + obj->SetConstructorMethod(thread_, method.GetTaggedValue()); + JSHandle emptyArray = EmptyArray(); + obj->SetNonStaticKeys(thread_, emptyArray, SKIP_BARRIER); + obj->SetNonStaticProperties(thread_, emptyArray, SKIP_BARRIER); + obj->SetNonStaticElements(thread_, emptyArray, SKIP_BARRIER); + obj->SetStaticKeys(thread_, emptyArray, SKIP_BARRIER); + obj->SetStaticProperties(thread_, emptyArray, SKIP_BARRIER); + obj->SetStaticElements(thread_, emptyArray, SKIP_BARRIER); + return obj; +} + +JSHandle ObjectFactory::NewSOldSpaceTaggedArray(uint32_t length, JSTaggedValue initVal) +{ + return NewSTaggedArray(length, initVal, MemSpaceType::SHARED_OLD_SPACE); +} + +JSHandle ObjectFactory::NewSTaggedArray(uint32_t length, JSTaggedValue initVal, MemSpaceType spaceType) +{ + NewSObjectHook(); + if (length == 0) { + return EmptyArray(); + } + + size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), length); + TaggedObject *header = nullptr; + JSHClass *arrayClass = JSHClass::Cast(thread_->GlobalConstants()->GetArrayClass().GetTaggedObject()); + switch (spaceType) { + case MemSpaceType::SHARED_OLD_SPACE: + header = sHeap_->AllocateOldOrHugeObject(thread_, arrayClass, size); + break; + case MemSpaceType::SHARED_NON_MOVABLE: + header = sHeap_->AllocateNonMovableOrHugeObject(thread_, arrayClass, size); + break; + default: + LOG_ECMA(FATAL) << "this branch is unreachable"; + UNREACHABLE(); + } + + JSHandle array(thread_, header); + array->InitializeWithSpecialValue(initVal, length); + return array; +} + +JSHandle ObjectFactory::NewSWellKnownSymbol(const JSHandle &name) +{ + NewSObjectHook(); + TaggedObject *header = sHeap_->AllocateNonMovableOrHugeObject( + thread_, JSHClass::Cast(thread_->GlobalConstants()->GetSymbolClass().GetTaggedObject())); + JSHandle obj(thread_, JSSymbol::Cast(header)); + obj->SetFlags(0); + obj->SetWellKnownSymbol(); + obj->SetDescription(thread_, name); + obj->SetHashField(SymbolTable::Hash(name.GetTaggedValue())); + return obj; +} + +JSHandle ObjectFactory::NewSWellKnownSymbolWithChar(std::string_view description) +{ + JSHandle string = NewFromUtf8(description); + return NewSWellKnownSymbol(JSHandle(string)); +} + +JSHandle ObjectFactory::NewSModule() +{ + NewObjectHook(); + TaggedObject *header = sHeap_->AllocateOldOrHugeObject(thread_, + JSHClass::Cast(thread_->GlobalConstants()->GetSourceTextModuleClass().GetTaggedObject())); + JSHandle obj(thread_, header); + JSTaggedValue undefinedValue = thread_->GlobalConstants()->GetUndefined(); + obj->SetEnvironment(thread_, undefinedValue); + obj->SetNamespace(thread_, undefinedValue); + obj->SetEcmaModuleFilename(thread_, undefinedValue); + obj->SetEcmaModuleRecordName(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); + // [[CycleRoot]]: For a module not in a cycle, this would be the module itself. + obj->SetCycleRoot(thread_, obj); + obj->SetTopLevelCapability(thread_, undefinedValue); + obj->SetAsyncParentModules(thread_, undefinedValue); + obj->SetHasTLA(false); + obj->SetAsyncEvaluatingOrdinal(SourceTextModule::NOT_ASYNC_EVALUATED); + obj->SetPendingAsyncDependencies(SourceTextModule::UNDEFINED_INDEX); + obj->SetDFSIndex(SourceTextModule::UNDEFINED_INDEX); + obj->SetDFSAncestorIndex(SourceTextModule::UNDEFINED_INDEX); + obj->SetEvaluationError(SourceTextModule::UNDEFINED_INDEX); + obj->SetStatus(ModuleStatus::UNINSTANTIATED); + obj->SetTypes(ModuleTypes::UNKNOWN); + obj->SetIsNewBcVersion(false); + obj->SetRegisterCounts(UINT16_MAX); + obj->SetSharedType(SharedTypes::UNSENDABLE_MODULE); + return obj; +} + +JSHandle ObjectFactory::NewSResolvedIndexBindingRecord() +{ + JSHandle undefinedValue = thread_->GlobalConstants()->GetHandledUndefined(); + JSHandle ecmaModule(undefinedValue); + int32_t index = 0; + return NewSResolvedIndexBindingRecord(ecmaModule, index); +} + +JSHandle ObjectFactory::NewSResolvedIndexBindingRecord(const JSHandle &module, + int32_t index) +{ + NewObjectHook(); + TaggedObject *header = sHeap_->AllocateOldOrHugeObject(thread_, + JSHClass::Cast(thread_->GlobalConstants()->GetResolvedIndexBindingClass().GetTaggedObject())); + JSHandle obj(thread_, header); + obj->SetModule(thread_, module); + obj->SetIndex(index); + return obj; +} + +JSHandle ObjectFactory::NewSResolvedBindingRecord() +{ + JSHandle undefinedValue = thread_->GlobalConstants()->GetHandledUndefined(); + JSHandle ecmaModule(undefinedValue); + JSHandle bindingName(undefinedValue); + return NewSResolvedBindingRecord(ecmaModule, bindingName); +} + +JSHandle ObjectFactory::NewSResolvedBindingRecord(const JSHandle &module, + const JSHandle &bindingName) +{ + NewObjectHook(); + TaggedObject *header = sHeap_->AllocateOldOrHugeObject(thread_, + JSHClass::Cast(thread_->GlobalConstants()->GetResolvedBindingClass().GetTaggedObject())); + JSHandle obj(thread_, header); + obj->SetModule(thread_, module); + obj->SetBindingName(thread_, bindingName); + return obj; +} + +JSHandle ObjectFactory::NewSResolvedRecordBindingRecord() +{ + JSHandle undefinedValue = thread_->GlobalConstants()->GetHandledUndefined(); + JSHandle ecmaModule(undefinedValue); + int32_t index = 0; + return NewSResolvedRecordBindingRecord(ecmaModule, index); +} + +JSHandle ObjectFactory::NewSResolvedRecordBindingRecord( + const JSHandle &moduleRecord, int32_t index) +{ + NewObjectHook(); + TaggedObject *header = sHeap_->AllocateOldOrHugeObject(thread_, + JSHClass::Cast(thread_->GlobalConstants()->GetResolvedRecordBindingClass().GetTaggedObject())); + JSHandle obj(thread_, header); + obj->SetModuleRecord(thread_, moduleRecord); + obj->SetIndex(index); + return obj; +} + +JSHandle ObjectFactory::NewSAOTLiteralInfo(uint32_t length, JSTaggedValue initVal) +{ + NewObjectHook(); + size_t size = AOTLiteralInfo::ComputeSize(length); + auto header = sHeap_->AllocateOldOrHugeObject(thread_, + JSHClass::Cast(sHeap_->GetGlobalConst()->GetAOTLiteralInfoClass().GetTaggedObject()), size); + + JSHandle aotLiteralInfo(thread_, header); + aotLiteralInfo->InitializeWithSpecialValue(initVal, length); + return aotLiteralInfo; +} +} // namespace panda::ecmascript diff --git a/ecmascript/snapshot/mem/snapshot_processor.cpp b/ecmascript/snapshot/mem/snapshot_processor.cpp index bab8f3b937fd4a27f38c732fb6c2891ec3f8380e..6026b3b92f252f178f17eadcb6c0a31a56c8f36a 100644 --- a/ecmascript/snapshot/mem/snapshot_processor.cpp +++ b/ecmascript/snapshot/mem/snapshot_processor.cpp @@ -103,6 +103,9 @@ #include "ecmascript/mem/space-inl.h" #include "ecmascript/mem/visitor.h" #include "ecmascript/object_factory.h" +#include "ecmascript/platform/mutex.h" +#include "ecmascript/runtime.h" +#include "ecmascript/runtime_lock.h" #include "ecmascript/snapshot/mem/snapshot_env.h" #ifdef ARK_SUPPORT_INTL #include "ecmascript/builtins/builtins_collator.h" @@ -1250,7 +1253,7 @@ void SnapshotProcessor::DeserializeSpaceObject(uintptr_t beginAddr, Space* space } for (size_t i = 0; i < numberOfRegions; i++) { Region *region = vm_->GetHeapRegionAllocator()->AllocateAlignedRegion( - space, DEFAULT_REGION_SIZE, vm_->GetAssociatedJSThread()); + space, DEFAULT_REGION_SIZE, vm_->GetAssociatedJSThread(), const_cast(vm_->GetHeap())); auto fileRegion = ToNativePtr(beginAddr + i * (DEFAULT_REGION_SIZE - GetMarkGCBitSetSize())); uintptr_t objectBeginAddr = ToUintPtr(fileRegion) + AlignUp(sizeof(Region), static_cast(MemAlignment::MEM_ALIGN_REGION)); @@ -1312,7 +1315,7 @@ void SnapshotProcessor::DeserializeHugeSpaceObject(uintptr_t beginAddr, HugeObje size_t objSize = SnapshotHelper::GetHugeObjectSize(snapshotData); size_t alignedHugeRegionSize = AlignUp(objSize + sizeof(Region), PANDA_POOL_ALIGNMENT_IN_BYTES); Region *region = vm_->GetHeapRegionAllocator()->AllocateAlignedRegion( - space, alignedHugeRegionSize, vm_->GetAssociatedJSThread()); + space, alignedHugeRegionSize, vm_->GetAssociatedJSThread(), const_cast(vm_->GetHeap())); // low 32 bits storage regionIndex size_t regionIndex = SnapshotHelper::GetHugeObjectRegionIndex(snapshotData); regionIndexMap_.emplace(regionIndex, region); @@ -1341,8 +1344,8 @@ void SnapshotProcessor::DeserializeString(uintptr_t stringBegin, uintptr_t strin { EcmaStringTable *stringTable = vm_->GetEcmaStringTable(); ASSERT(stringVector_.empty()); - auto oldSpace = const_cast(vm_->GetHeap())->GetOldSpace(); - auto hugeSpace = const_cast(vm_->GetHeap())->GetHugeObjectSpace(); + auto oldSpace = sHeap_->GetOldSpace(); + auto hugeSpace = sHeap_->GetHugeObjectSpace(); auto globalConst = const_cast(vm_->GetJSThread()->GlobalConstants()); auto lineStringClass = globalConst->GetLineStringClass(); auto constantStringClass = globalConst->GetConstantStringClass(); @@ -1363,28 +1366,31 @@ void SnapshotProcessor::DeserializeString(uintptr_t stringBegin, uintptr_t strin } size_t strSize = EcmaStringAccessor(str).ObjectSize(); strSize = AlignUp(strSize, static_cast(MemAlignment::MEM_ALIGN_OBJECT)); - auto strFromTable = stringTable->GetString(str); - if (strFromTable) { - stringVector_.emplace_back(ToUintPtr(strFromTable)); - } else { - uintptr_t newObj = 0; - if (UNLIKELY(strSize > MAX_REGULAR_HEAP_OBJECT_SIZE)) { - newObj = hugeSpace->Allocate(strSize, vm_->GetJSThread()); + { + RuntimeLockHolder locker(vm_->GetJSThread(), stringTable->mutex_); + auto strFromTable = stringTable->GetStringThreadUnsafe(str); + if (strFromTable) { + stringVector_.emplace_back(ToUintPtr(strFromTable)); } else { - newObj = oldSpace->Allocate(strSize, false); - } - if (newObj == 0) { - LOG_ECMA_MEM(FATAL) << "Snapshot Allocate OldLocalSpace OOM"; - UNREACHABLE(); - } - if (memcpy_s(ToVoidPtr(newObj), strSize, str, strSize) != EOK) { - LOG_FULL(FATAL) << "memcpy_s failed"; - UNREACHABLE(); + uintptr_t newObj = 0; + if (UNLIKELY(strSize > MAX_REGULAR_HEAP_OBJECT_SIZE)) { + newObj = hugeSpace->Allocate(vm_->GetJSThread(), strSize); + } else { + newObj = oldSpace->Allocate(vm_->GetJSThread(), strSize, false); + } + if (newObj == 0) { + LOG_ECMA_MEM(FATAL) << "Snapshot Allocate OldLocalSpace OOM"; + UNREACHABLE(); + } + if (memcpy_s(ToVoidPtr(newObj), strSize, str, strSize) != EOK) { + LOG_FULL(FATAL) << "memcpy_s failed"; + UNREACHABLE(); + } + str = reinterpret_cast(newObj); + EcmaStringAccessor(str).ClearInternString(); + stringTable->GetOrInternStringThreadUnsafe(vm_, str); + stringVector_.emplace_back(newObj); } - str = reinterpret_cast(newObj); - EcmaStringAccessor(str).ClearInternString(); - stringTable->GetOrInternString(str); - stringVector_.emplace_back(newObj); } stringBegin += strSize; } @@ -1495,7 +1501,7 @@ void SnapshotProcessor::SerializeObject(TaggedObject *objectHeader, CQueue(objectHeader, objectHeader->GetClass(), visitor); + ObjectXRay::VisitObjectBody(objectHeader, objectHeader->GetClass(), visitor); } bool SnapshotProcessor::VisitObjectBodyWithRep(TaggedObject *root, ObjectSlot slot, uintptr_t obj, int index, @@ -1581,7 +1587,7 @@ void SnapshotProcessor::RelocateSpaceObject(const JSPandaFile *jsPandaFile, Spac (JSType(objType) >= JSType::STRING_FIRST && JSType(objType) <= JSType::STRING_LAST)) { auto str = reinterpret_cast(begin); EcmaStringAccessor(str).ClearInternString(); - stringTable->InsertStringIfNotExist(str); + stringTable->InsertStringIfNotExistThreadUnsafe(str); if (JSType(objType) == JSType::CONSTANT_STRING) { auto constantStr = ConstantString::Cast(str); uint32_t id = constantStr->GetEntityIdU32(); @@ -1672,6 +1678,9 @@ void SnapshotProcessor::DeserializeTaggedField(uint64_t *value, TaggedObject *ro ASSERT((ToUintPtr(value) % static_cast(MemAlignment::MEM_ALIGN_OBJECT)) == 0); rootRegion->InsertOldToNewRSet((uintptr_t)value); } + if (!rootRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) { + rootRegion->AtomicInsertLocalToShareRSet((uintptr_t)value); + } *value = taggedObjectAddr; return; } @@ -1710,7 +1719,7 @@ void SnapshotProcessor::DeserializeField(TaggedObject *objectHeader) } }; - objXRay_.VisitObjectBody(objectHeader, objectHeader->GetClass(), visitor); + ObjectXRay::VisitObjectBody(objectHeader, objectHeader->GetClass(), visitor); } EncodeBit SnapshotProcessor::NativePointerToEncodeBit(void *nativePointer) @@ -1820,16 +1829,17 @@ uintptr_t SnapshotProcessor::GetNewObj(size_t objectSize, TaggedObject *objectHe return AllocateObjectToLocalSpace(snapshotLocalSpace_, objectSize); } auto region = Region::ObjectAddressToRange(objectHeader); - if (region->InYoungOrOldSpace()) { + if (region->InYoungOrOldSpace() || region->InSharedOldSpace()) { return AllocateObjectToLocalSpace(oldLocalSpace_, objectSize); } if (region->InMachineCodeSpace()) { return AllocateObjectToLocalSpace(machineCodeLocalSpace_, objectSize); } - if (region->InNonMovableSpace() || region->InReadOnlySpace()) { + if (region->InNonMovableSpace() || region->InReadOnlySpace() || + region->InSharedNonMovableSpace() || region->InSharedReadOnlySpace()) { return AllocateObjectToLocalSpace(nonMovableLocalSpace_, objectSize); } - if (region->InHugeObjectSpace()) { + if (region->InHugeObjectSpace() || region->InSharedHugeObjectSpace()) { return AllocateObjectToLocalSpace(hugeObjectLocalSpace_, objectSize); } return AllocateObjectToLocalSpace(snapshotLocalSpace_, objectSize); diff --git a/ecmascript/snapshot/mem/snapshot_processor.h b/ecmascript/snapshot/mem/snapshot_processor.h index beebc1d61463af4c2d0f1a5cd802bb7054aecd47..120aa6fe2daf9c93f430cb8b9f65cb7fba43a1b8 100644 --- a/ecmascript/snapshot/mem/snapshot_processor.h +++ b/ecmascript/snapshot/mem/snapshot_processor.h @@ -20,6 +20,7 @@ #include #include +#include "ecmascript/mem/heap.h" #include "ecmascript/snapshot/mem/encode_bit.h" #include "ecmascript/jspandafile/method_literal.h" #include "ecmascript/js_tagged_value.h" @@ -43,7 +44,7 @@ using ObjectEncode = std::pair; class SnapshotProcessor final { public: explicit SnapshotProcessor(EcmaVM *vm) - : vm_(vm), objXRay_(vm) {} + : vm_(vm), sHeap_(SharedHeap::GetInstance()) {} ~SnapshotProcessor(); void Initialize(); @@ -132,12 +133,12 @@ private: uintptr_t AllocateObjectToLocalSpace(Space *space, size_t objectSize); EcmaVM *vm_ {nullptr}; + SharedHeap* sHeap_ {nullptr}; LocalSpace *oldLocalSpace_ {nullptr}; LocalSpace *nonMovableLocalSpace_ {nullptr}; LocalSpace *machineCodeLocalSpace_ {nullptr}; SnapshotSpace *snapshotLocalSpace_ {nullptr}; HugeObjectSpace *hugeObjectLocalSpace_ {nullptr}; - ObjectXRay objXRay_; bool programSerialize_ {false}; bool builtinsSerialize_ {false}; bool builtinsDeserialize_ {false}; diff --git a/ecmascript/snapshot/tests/snapshot_test.cpp b/ecmascript/snapshot/tests/snapshot_test.cpp index 95db17d15dbd5fdfb30302bfb0c2aa6a90e39868..ef1dec4202c54b4a778b12ec6ffaacf19251e260 100644 --- a/ecmascript/snapshot/tests/snapshot_test.cpp +++ b/ecmascript/snapshot/tests/snapshot_test.cpp @@ -48,11 +48,13 @@ public: ecmaVm = JSNApi::CreateEcmaVM(options); ASSERT_TRUE(ecmaVm != nullptr) << "Cannot create EcmaVM"; thread = ecmaVm->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } void TearDown() override { + thread->ManagedCodeEnd(); delete scope; scope = nullptr; ecmaVm->SetEnableForceGC(false); @@ -79,15 +81,19 @@ public: // serialize in earlier version tag snapshotSerialize.Serialize(*array1, nullptr, fileName); - JSRuntimeOptions options; - EcmaVM *ecmaVm2 = JSNApi::CreateEcmaVM(options); - // deserialize with last version tag - SnapshotMock snapshotDeserialize(ecmaVm2); - snapshotDeserialize.SetLastVersion(deserializeVersion); - EXPECT_EQ(snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName), expected); - - ASSERT_EQ(const_cast(ecmaVm2->GetHeap())->GetHugeObjectSpace()->GetFirstRegion() != nullptr, expected); - JSNApi::DestroyJSVM(ecmaVm2); + std::thread t1([&]() { + JSRuntimeOptions options; + EcmaVM *ecmaVm2 = JSNApi::CreateEcmaVM(options); + // deserialize with last version tag + SnapshotMock snapshotDeserialize(ecmaVm2); + snapshotDeserialize.SetLastVersion(deserializeVersion); + EXPECT_EQ(snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName), expected); + + ASSERT_EQ(const_cast(ecmaVm2->GetHeap())->GetHugeObjectSpace()->GetFirstRegion() != nullptr, + expected); + JSNApi::DestroyJSVM(ecmaVm2); + }); + t1.join(); std::remove(fileName.c_str()); } @@ -243,32 +249,40 @@ HWTEST_F_L0(SnapshotTest, SerializeBuiltins) CString fileName = "builtins.snapshot"; std::remove(fileName.c_str()); // generate builtins.snapshot file - JSRuntimeOptions options1; - options1.SetArkProperties(ArkProperties::ENABLE_SNAPSHOT_SERIALIZE); - EcmaVM *ecmaVm1 = JSNApi::CreateEcmaVM(options1); - JSNApi::DestroyJSVM(ecmaVm1); + std::thread t1([]() { + JSRuntimeOptions options1; + options1.SetArkProperties(ArkProperties::ENABLE_SNAPSHOT_SERIALIZE); + EcmaVM *ecmaVm1 = JSNApi::CreateEcmaVM(options1); + JSNApi::DestroyJSVM(ecmaVm1); + }); + t1.join(); // create EcmaVM use builtins deserialzie - JSRuntimeOptions options2; - options2.SetArkProperties(ArkProperties::ENABLE_SNAPSHOT_DESERIALIZE); - EcmaVM *ecmaVm2 = JSNApi::CreateEcmaVM(options2); - EXPECT_TRUE(ecmaVm2->GetGlobalEnv()->GetClass()->GetObjectType() == JSType::GLOBAL_ENV); - auto globalConst = const_cast(ecmaVm2->GetJSThread()->GlobalConstants()); - size_t hclassEndIndex = static_cast(ConstantIndex::UNDEFINED_INDEX); - size_t hclassIndex = 0; - globalConst->VisitRangeSlot([&hclassIndex, &hclassEndIndex]([[maybe_unused]] Root type, - ObjectSlot start, ObjectSlot end) { - while (start < end) { - JSTaggedValue object(start.GetTaggedType()); - start++; - if (hclassIndex < hclassEndIndex) { - EXPECT_TRUE(object.IsJSHClass()); + std::thread t2([&]() { + JSRuntimeOptions options2; + options2.SetArkProperties(ArkProperties::ENABLE_SNAPSHOT_DESERIALIZE); + EcmaVM *ecmaVm2 = JSNApi::CreateEcmaVM(options2); + EXPECT_TRUE(ecmaVm2->GetGlobalEnv()->GetClass()->GetObjectType() == JSType::GLOBAL_ENV); + auto globalConst = const_cast(ecmaVm2->GetJSThread()->GlobalConstants()); + globalConst->VisitRangeSlot([]([[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end) { + size_t sharedBeginHclassIndex = static_cast(ConstantIndex::SHARED_HCLASS_BEGIN); + size_t sharedHclassEndIndex = static_cast(ConstantIndex::SHARED_HCLASS_END); + size_t hclassBeginIndex = static_cast(ConstantIndex::NON_SHARED_HCLASS_BEGIN); + size_t hclassEndIndex = static_cast(ConstantIndex::NON_SHARED_HCLASS_END); + size_t index = sharedBeginHclassIndex; + while (start < end) { + JSTaggedValue object(start.GetTaggedType()); + start++; + if ((index >= sharedBeginHclassIndex && index <= sharedHclassEndIndex) || + (index >= hclassBeginIndex && index <= hclassEndIndex)) { + EXPECT_TRUE(object.IsJSHClass()); + } + index++; } - hclassIndex++; - } + }); + JSNApi::DestroyJSVM(ecmaVm2); }); - JSNApi::DestroyJSVM(ecmaVm2); - + t2.join(); std::remove(fileName.c_str()); } diff --git a/ecmascript/stubs/runtime_stubs-inl.h b/ecmascript/stubs/runtime_stubs-inl.h index 96547d19ca9d456b912f8c043b7edd0cd887fd3b..7df024845a850aec32d8fbb864e4a63d2a8786ae 100644 --- a/ecmascript/stubs/runtime_stubs-inl.h +++ b/ecmascript/stubs/runtime_stubs-inl.h @@ -42,6 +42,7 @@ #include "ecmascript/module/js_module_manager.h" #include "ecmascript/module/js_module_source_text.h" #include "ecmascript/platform/file.h" +#include "ecmascript/runtime.h" #include "ecmascript/stackmap/llvm/llvm_stackmap_parser.h" #include "ecmascript/template_string.h" #include "ecmascript/ts_types/ts_manager.h" @@ -798,8 +799,8 @@ JSTaggedValue RuntimeStubs::RuntimeResolveClass(JSThread *thread, const JSHandle ASSERT(ctor.GetTaggedValue().IsClassConstructor()); FrameHandler frameHandler(thread); - Method *currentMethod = frameHandler.GetMethod(); - JSHandle ecmaModule(thread, currentMethod->GetModule()); + JSTaggedValue currentFunc = frameHandler.GetFunction(); + JSHandle ecmaModule(thread, JSFunction::Cast(currentFunc.GetTaggedObject())->GetModule()); RuntimeSetClassInheritanceRelationship(thread, JSHandle(ctor), base); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -812,7 +813,7 @@ JSTaggedValue RuntimeStubs::RuntimeResolveClass(JSThread *thread, const JSHandle if (LIKELY(value.IsJSFunction())) { JSFunction *func = JSFunction::Cast(value.GetTaggedObject()); func->SetLexicalEnv(thread, lexenv.GetTaggedValue()); - Method::Cast(func->GetMethod())->SetModule(thread, ecmaModule); + func->SetModule(thread, ecmaModule); } } @@ -878,21 +879,24 @@ JSTaggedValue RuntimeStubs::RuntimeCreateClassWithBuffer(JSThread *thread, CString entry = ModuleManager::GetRecordName(module.GetTaggedValue()); // For class constructor. - auto methodObj = ConstantPool::GetMethodFromCache( - thread, constpool.GetTaggedValue(), module.GetTaggedValue(), methodId); + auto methodObj = ConstantPool::GetMethodFromCache(thread, constpool.GetTaggedValue(), methodId); JSHandle method(thread, methodObj); JSHandle constpoolHandle = JSHandle::Cast(constpool); JSHandle cls; JSMutableHandle ihc(thread, JSTaggedValue::Undefined()); JSMutableHandle chc(thread, JSTaggedValue::Undefined()); - JSTaggedValue val = constpoolHandle->GetObjectFromCache(literalId); + JSHandle cp(thread, + thread->GetCurrentEcmaContext()->FindUnsharedConstpool(constpoolHandle.GetTaggedValue())); + JSTaggedValue val = cp->GetObjectFromCache(literalId); if (val.IsAOTLiteralInfo()) { JSHandle aotLiteralInfo(thread, val); ihc.Update(aotLiteralInfo->GetIhc()); chc.Update(aotLiteralInfo->GetChc()); } - auto literalObj = ConstantPool::GetClassLiteralFromCache(thread, constpoolHandle, literalId, entry); + + JSTaggedValue literalObj = ConstantPool::GetClassLiteralFromCache(thread, cp, literalId, entry); + JSHandle classLiteral(thread, literalObj); JSHandle arrayHandle(thread, classLiteral->GetArray()); JSHandle extractor = factory->NewClassInfoExtractor(method); @@ -912,6 +916,7 @@ JSTaggedValue RuntimeStubs::RuntimeCreateClassWithBuffer(JSThread *thread, RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); cls->SetLexicalEnv(thread, lexenv.GetTaggedValue()); + cls->SetModule(thread, module.GetTaggedValue()); RuntimeSetClassConstructorLength(thread, cls.GetTaggedValue(), length.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -931,8 +936,7 @@ JSTaggedValue RuntimeStubs::RuntimeCreateSharedClass(JSThread *thread, ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); CString entry = ModuleManager::GetRecordName(module.GetTaggedValue()); - auto methodObj = ConstantPool::GetMethodFromCache( - thread, constpool.GetTaggedValue(), module.GetTaggedValue(), methodId); + auto methodObj = ConstantPool::GetMethodFromCache(thread, constpool.GetTaggedValue(), methodId); JSHandle method(thread, methodObj); JSHandle constpoolHandle = JSHandle::Cast(constpool); @@ -951,6 +955,9 @@ JSTaggedValue RuntimeStubs::RuntimeCreateSharedClass(JSThread *thread, JSHandle staticFieldArray = SendableClassDefiner::ExtractStaticFieldTypeArray(thread, fieldTypeArray); JSHandle cls = SendableClassDefiner::DefineSendableClassFromExtractor(thread, extractor, staticFieldArray); + ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); + JSHandle sendableClsModule = moduleManager->GenerateSendableFuncModule(module); + cls->SetModule(thread, sendableClsModule.GetTaggedValue()); RuntimeSetClassConstructorLength(thread, cls.GetTaggedValue(), JSTaggedValue(length)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); RuntimeSetClassInheritanceRelationship(thread, JSHandle(cls), base, ClassKind::SENDABLE); @@ -1060,21 +1067,26 @@ JSTaggedValue RuntimeStubs::RuntimeSetClassConstructorLength(JSThread *thread, J return JSTaggedValue::Undefined(); } -JSTaggedValue RuntimeStubs::RuntimeNotifyInlineCache(JSThread *thread, const JSHandle &method, +JSTaggedValue RuntimeStubs::RuntimeNotifyInlineCache(JSThread *thread, const JSHandle &function, uint32_t icSlotSize) { if (icSlotSize == 0) { return JSTaggedValue::Undefined(); } ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - JSHandle profileTypeInfo = factory->NewProfileTypeInfo(icSlotSize); + JSHandle profileTypeInfo; + if (function->GetClass()->IsJSSharedFunction()) { + return JSTaggedValue::Undefined(); + } else { + profileTypeInfo = factory->NewProfileTypeInfo(icSlotSize); + } // overflow 8bit if (icSlotSize > ProfileTypeInfo::INVALID_SLOT_INDEX) { // set as mega profileTypeInfo->Set(thread, ProfileTypeInfo::INVALID_SLOT_INDEX, JSTaggedValue::Hole()); ASSERT(icSlotSize <= ProfileTypeInfo::MAX_SLOT_INDEX + 1); } - method->SetProfileTypeInfo(thread, profileTypeInfo.GetTaggedValue()); + function->SetProfileTypeInfo(thread, profileTypeInfo.GetTaggedValue()); return profileTypeInfo.GetTaggedValue(); } @@ -1274,6 +1286,11 @@ JSTaggedValue RuntimeStubs::RuntimeLdExternalModuleVar(JSThread *thread, int32_t return thread->GetCurrentEcmaContext()->GetModuleManager()->GetModuleValueOutter(index); } +JSTaggedValue RuntimeStubs::RuntimeLdSendableExternalModuleVar(JSThread *thread, int32_t index, JSTaggedValue jsFunc) +{ + return SharedModuleManager::GetInstance()->GetSendableModuleValue(thread, index, jsFunc); +} + JSTaggedValue RuntimeStubs::RuntimeLdExternalModuleVar(JSThread *thread, int32_t index, JSTaggedValue jsFunc) { return thread->GetCurrentEcmaContext()->GetModuleManager()->GetModuleValueOutter(index, jsFunc); @@ -1583,8 +1600,8 @@ JSTaggedValue RuntimeStubs::RuntimeDynamicImport(JSThread *thread, const JSHandl ObjectFactory *factory = ecmaVm->GetFactory(); // get current filename - Method *method = JSFunction::Cast(func->GetTaggedObject())->GetCallTarget(); - const JSPandaFile *jsPandaFile = method->GetJSPandaFile(); + JSFunction *function = JSFunction::Cast(func->GetTaggedObject()); + const JSPandaFile *jsPandaFile = function->GetCallTarget()->GetJSPandaFile(); CString currentfilename = jsPandaFile->GetJSPandaFileDesc(); JSMutableHandle dirPath(thread, thread->GlobalConstants()->GetUndefined()); @@ -1592,7 +1609,7 @@ JSTaggedValue RuntimeStubs::RuntimeDynamicImport(JSThread *thread, const JSHandl if (jsPandaFile->IsBundlePack()) { dirPath.Update(factory->NewFromUtf8(currentfilename).GetTaggedValue()); } else { - recordName.Update(method->GetRecordName()); + recordName.Update(function->GetRecordName()); dirPath.Update(factory->NewFromUtf8(currentfilename).GetTaggedValue()); } @@ -2104,11 +2121,13 @@ JSTaggedValue RuntimeStubs::RuntimeDefinefunc(JSThread *thread, const JSHandle ihc(thread, JSTaggedValue::Undefined()); JSTaggedValue val = constpoolHandle->GetObjectFromCache(methodId); if (val.IsAOTLiteralInfo()) { + JSTaggedValue unsharedCp = thread->GetCurrentEcmaContext()->FindUnsharedConstpool(constpool.GetTaggedValue()); + JSHandle unsharedCpHandle(thread, unsharedCp); + val = unsharedCpHandle->GetObjectFromCache(methodId); JSHandle aotLiteralInfo(thread, val); ihc.Update(aotLiteralInfo->GetIhc()); } - JSTaggedValue method = ConstantPool::GetMethodFromCache(thread, constpool.GetTaggedValue(), - module.GetTaggedValue(), methodId); + JSTaggedValue method = ConstantPool::GetMethodFromCache(thread, constpool.GetTaggedValue(), methodId); const JSHandle methodHandle(thread, method); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle result = factory->NewJSFunction(methodHandle); @@ -2117,6 +2136,7 @@ JSTaggedValue RuntimeStubs::RuntimeDefinefunc(JSThread *thread, const JSHandleSetLength(length); result->SetLexicalEnv(thread, envHandle.GetTaggedValue()); result->SetHomeObject(thread, homeObject.GetTaggedValue()); + result->SetModule(thread, module.GetTaggedValue()); return result.GetTaggedValue(); } @@ -2240,12 +2260,14 @@ JSTaggedValue RuntimeStubs::RuntimeCreateObjectWithExcludedKeys(JSThread *thread JSTaggedValue RuntimeStubs::RuntimeDefineMethod(JSThread *thread, const JSHandle &methodHandle, const JSHandle &homeObject, uint16_t length, - const JSHandle &env) + const JSHandle &env, + const JSHandle &module) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle func = factory->NewJSFunction(methodHandle, homeObject); func->SetLength(length); func->SetLexicalEnv(thread, env); + func->SetModule(thread, module); return func.GetTaggedValue(); } @@ -2996,7 +3018,11 @@ JSTaggedValue RuntimeStubs::RuntimeCreatePrivateProperty(JSThread *thread, JSTag handleLexicalEnv->SetProperties(thread, startIndex + i, symbol.GetTaggedValue()); } - JSTaggedValue literalObj = ConstantPool::GetClassLiteralFromCache(thread, handleConstpool, literalId, entry); + JSTaggedValue cp = thread->GetCurrentEcmaContext()-> + FindUnsharedConstpool(handleConstpool.GetTaggedValue()); + JSTaggedValue literalObj = ConstantPool::GetClassLiteralFromCache( + thread, JSHandle(thread, cp), literalId, entry); + JSHandle classLiteral(thread, literalObj); JSHandle literalBuffer(thread, classLiteral->GetArray()); uint32_t literalBufferLength = literalBuffer->GetLength(); @@ -3012,7 +3038,7 @@ JSTaggedValue RuntimeStubs::RuntimeCreatePrivateProperty(JSThread *thread, JSTag JSFunction *func = JSFunction::Cast(literalValue.GetTaggedObject()); func->SetLexicalEnv(thread, handleLexicalEnv.GetTaggedValue()); func->GetClass()->SetExtensible(false); - Method::Cast(func->GetMethod())->SetModule(thread, handleModule.GetTaggedValue()); + func->SetModule(thread, handleModule.GetTaggedValue()); } handleLexicalEnv->SetProperties(thread, startIndex + count + i, literalValue); } @@ -3153,11 +3179,11 @@ JSTaggedValue RuntimeStubs::ArrayNumberSort(JSThread *thread, JSHandle return thisObj.GetTaggedValue(); } -JSTaggedType RuntimeStubs::RuntimeTryGetInternString(uintptr_t argGlue, EcmaString *string) +JSTaggedType RuntimeStubs::RuntimeTryGetInternString(uintptr_t argGlue, const JSHandle &string) { auto thread = JSThread::GlueToJSThread(argGlue); EcmaString *str = - thread->GetEcmaVM()->GetEcmaStringTable()->TryGetInternString(string); + thread->GetEcmaVM()->GetEcmaStringTable()->TryGetInternString(thread, string); if (str == nullptr) { return JSTaggedValue::Hole().GetRawData(); } diff --git a/ecmascript/stubs/runtime_stubs.cpp b/ecmascript/stubs/runtime_stubs.cpp index f7bce0a24071433c6786129fb11d724b6346ee6c..b7a668be451f5fdc9d85ddd97645b64e249792e6 100644 --- a/ecmascript/stubs/runtime_stubs.cpp +++ b/ecmascript/stubs/runtime_stubs.cpp @@ -18,6 +18,7 @@ #include "ecmascript/js_tagged_value.h" #include "ecmascript/log.h" #include "ecmascript/log_wrapper.h" +#include "ecmascript/mem/heap.h" #include "ecmascript/stubs/runtime_stubs-inl.h" #include "ecmascript/accessor_data.h" #include "ecmascript/base/fast_json_stringifier.h" @@ -112,9 +113,9 @@ DEF_RUNTIME_STUBS(AddElementInternal) JSHandle receiver = GetHArg(argv, argc, 0); // 0: means the zeroth parameter JSTaggedValue argIndex = GetArg(argv, argc, 1); // 1: means the first parameter JSHandle value = GetHArg(argv, argc, 2); // 2: means the second parameter - JSTaggedValue argAttr = GetArg(argv, argc, 3); // 3: means the third parameter - auto attr = static_cast(argAttr.GetInt()); - auto result = JSObject::AddElementInternal(thread, receiver, argIndex.GetInt(), value, attr); + JSTaggedValue attr = GetArg(argv, argc, 3); // 3: means the third parameter + PropertyAttributes attrValue(attr); + auto result = JSObject::AddElementInternal(thread, receiver, argIndex.GetInt(), value, attrValue); return JSTaggedValue(result).GetRawData(); } @@ -162,6 +163,22 @@ DEF_RUNTIME_STUBS(AllocateInYoung) return JSTaggedValue(result).GetRawData(); } +DEF_RUNTIME_STUBS(AllocateInSOld) +{ + RUNTIME_STUBS_HEADER(AllocateInSOld); + JSTaggedValue allocateSize = GetArg(argv, argc, 0); // 0: means the zeroth parameter + auto size = static_cast(allocateSize.GetInt()); + auto sharedHeap = const_cast(SharedHeap::GetInstance()); + auto oldSpace = sharedHeap->GetOldSpace(); + ASSERT(size <= MAX_REGULAR_HEAP_OBJECT_SIZE); + auto result = reinterpret_cast(oldSpace->Allocate(thread, size)); + if (result == nullptr) { + result = sharedHeap->AllocateOldOrHugeObject(thread, size); + ASSERT(result != nullptr); + } + return JSTaggedValue(result).GetRawData(); +} + DEF_RUNTIME_STUBS(CallInternalGetter) { RUNTIME_STUBS_HEADER(CallInternalGetter); @@ -301,7 +318,7 @@ DEF_RUNTIME_STUBS(NameDictPutIfAbsent) JSTaggedValue attr = GetArg(argv, argc, 4); // 4: means the fourth parameter JSTaggedValue needTransToDict = GetArg(argv, argc, 5); // 5: means the fifth parameter - PropertyAttributes propAttr(attr.GetInt()); + PropertyAttributes propAttr(attr); if (needTransToDict.IsTrue()) { JSHandle objHandle(thread, JSTaggedValue(reinterpret_cast(receiver))); JSHandle dictHandle(JSObject::TransitionToDictionary(thread, objHandle)); @@ -325,7 +342,7 @@ DEF_RUNTIME_STUBS(NumberDictionaryPut) JSTaggedValue needTransToDict = GetArg(argv, argc, 5); // 5: means the fifth parameter JSHandle keyHandle(thread, key); - PropertyAttributes propAttr(attr.GetInt()); + PropertyAttributes propAttr(attr); JSHandle objHandle(thread, JSTaggedValue(reinterpret_cast(receiver))); if (needTransToDict.IsTrue()) { JSObject::ElementsToDictionary(thread, objHandle); @@ -483,7 +500,7 @@ DEF_RUNTIME_STUBS(UpdateLayOutAndAddTransition) JSHandle keyHandle = GetHArg(argv, argc, 2); // 2: means the second parameter JSTaggedValue attr = GetArg(argv, argc, 3); // 3: means the third parameter - PropertyAttributes attrValue(attr.GetInt()); + PropertyAttributes attrValue(attr); JSHClass::AddPropertyToNewHClass(thread, oldHClassHandle, newHClassHandle, keyHandle, attrValue); @@ -501,7 +518,7 @@ DEF_RUNTIME_STUBS(CopyAndUpdateObjLayout) JSTaggedValue attr = GetArg(argv, argc, 3); // 3: means the third parameter auto factory = thread->GetEcmaVM()->GetFactory(); - PropertyAttributes attrValue(attr.GetInt()); + PropertyAttributes attrValue(attr); // 1. Copy JSHandle oldLayout(thread, newHClassHandle->GetLayout()); @@ -800,7 +817,7 @@ DEF_RUNTIME_STUBS(RegularJSObjDeletePrototype) JSTaggedValue value = GetArg(argv, argc, 1); uint32_t index = 0; if (value.IsString()) { - auto string = reinterpret_cast(value.GetTaggedObject()); + auto string = JSHandle(thread, value); if (EcmaStringAccessor(string).ToElementIndex(&index)) { value = JSTaggedValue(index); } else if (!EcmaStringAccessor(string).IsInternString()) { @@ -1257,9 +1274,8 @@ DEF_RUNTIME_STUBS(GetMethodFromCache) RUNTIME_STUBS_HEADER(GetMethodFromCache); JSHandle constpool = GetHArg(argv, argc, 0); // 0: means the zeroth parameter JSTaggedValue index = GetArg(argv, argc, 1); // 1: means the first parameter - JSHandle module = GetHArg(argv, argc, 2); // 2: means the second parameter return ConstantPool::GetMethodFromCache( - thread, constpool.GetTaggedValue(), module.GetTaggedValue(), index.GetInt()).GetRawData(); + thread, constpool.GetTaggedValue(), index.GetInt()).GetRawData(); } DEF_RUNTIME_STUBS(GetStringFromCache) @@ -1277,8 +1293,9 @@ DEF_RUNTIME_STUBS(GetObjectLiteralFromCache) JSHandle constpool = GetHArg(argv, argc, 0); // 0: means the zeroth parameter JSTaggedValue index = GetArg(argv, argc, 1); // 1: means the first parameter JSHandle module = GetHArg(argv, argc, 2); // 2: means the second parameter + JSTaggedValue cp = thread->GetCurrentEcmaContext()->FindUnsharedConstpool(constpool.GetTaggedValue()); return ConstantPool::GetLiteralFromCache( - thread, constpool.GetTaggedValue(), index.GetInt(), module.GetTaggedValue()).GetRawData(); + thread, cp, index.GetInt(), module.GetTaggedValue()).GetRawData(); } DEF_RUNTIME_STUBS(GetArrayLiteralFromCache) @@ -1287,8 +1304,9 @@ DEF_RUNTIME_STUBS(GetArrayLiteralFromCache) JSHandle constpool = GetHArg(argv, argc, 0); // 0: means the zeroth parameter JSTaggedValue index = GetArg(argv, argc, 1); // 1: means the first parameter JSHandle module = GetHArg(argv, argc, 2); // 2: means the second parameter + JSTaggedValue cp = thread->GetCurrentEcmaContext()->FindUnsharedConstpool(constpool.GetTaggedValue()); return ConstantPool::GetLiteralFromCache( - thread, constpool.GetTaggedValue(), index.GetInt(), module.GetTaggedValue()).GetRawData(); + thread, cp, index.GetInt(), module.GetTaggedValue()).GetRawData(); } DEF_RUNTIME_STUBS(LdObjByIndex) @@ -1455,10 +1473,10 @@ DEF_RUNTIME_STUBS(UpdateHotnessCounter) JSHandle thisFunc = GetHArg(argv, argc, 0); // 0: means the zeroth parameter thread->CheckSafepoint(); JSHandle method(thread, thisFunc->GetMethod()); - auto profileTypeInfo = method->GetProfileTypeInfo(); + auto profileTypeInfo = thisFunc->GetProfileTypeInfo(); if (profileTypeInfo.IsUndefined()) { uint32_t slotSize = method->GetSlotSize(); - auto res = RuntimeNotifyInlineCache(thread, method, slotSize); + auto res = RuntimeNotifyInlineCache(thread, thisFunc, slotSize); return res.GetRawData(); } return profileTypeInfo.GetRawData(); @@ -1485,11 +1503,10 @@ DEF_RUNTIME_STUBS(UpdateHotnessCounterWithProf) RUNTIME_STUBS_HEADER(UpdateHotnessCounterWithProf); JSHandle thisFunc = GetHArg(argv, argc, 0); // 0: means the zeroth parameter thread->CheckSafepoint(); - JSHandle method(thread, thisFunc->GetMethod()); - auto profileTypeInfo = method->GetProfileTypeInfo(); + auto profileTypeInfo = thisFunc->GetProfileTypeInfo(); if (profileTypeInfo.IsUndefined()) { - uint32_t slotSize = method->GetSlotSize(); - auto res = RuntimeNotifyInlineCache(thread, method, slotSize); + uint32_t slotSize = thisFunc->GetCallTarget()->GetSlotSize(); + auto res = RuntimeNotifyInlineCache(thread, thisFunc, slotSize); return res.GetRawData(); } return profileTypeInfo.GetRawData(); @@ -1726,6 +1743,14 @@ DEF_RUNTIME_STUBS(LdExternalModuleVarByIndex) return RuntimeLdExternalModuleVar(thread, index.GetInt()).GetRawData(); } +DEF_RUNTIME_STUBS(LdSendableExternalModuleVarByIndex) +{ + RUNTIME_STUBS_HEADER(LdSendableExternalModuleVarByIndex); + JSTaggedValue index = GetArg(argv, argc, 0); // 0: means the zeroth parameter + JSTaggedValue jsFunc = GetArg(argv, argc, 1); // 1: means the first parameter + return RuntimeLdSendableExternalModuleVar(thread, index.GetInt(), jsFunc).GetRawData(); +} + DEF_RUNTIME_STUBS(LdLocalModuleVarByIndexOnJSFunc) { RUNTIME_STUBS_HEADER(LdLocalModuleVarByIndexOnJSFunc); @@ -2315,7 +2340,8 @@ DEF_RUNTIME_STUBS(DefineMethod) JSHandle homeObject = GetHArg(argv, argc, 1); // 1: means the first parameter uint16_t length = static_cast(GetArg(argv, argc, 2).GetInt()); // 2: means the second parameter JSHandle env = GetHArg(argv, argc, 3); // 3: means the third parameter - return RuntimeDefineMethod(thread, method, homeObject, length, env).GetRawData(); + JSHandle module = GetHArg(argv, argc, 4); // 4: means the fourth parameter + return RuntimeDefineMethod(thread, method, homeObject, length, env, module).GetRawData(); } DEF_RUNTIME_STUBS(CallSpread) @@ -2776,7 +2802,7 @@ DEF_RUNTIME_STUBS(InsertStringToTable) RUNTIME_STUBS_HEADER(InsertStringToTable); JSHandle str = GetHArg(argv, argc, 0); // 0: means the zeroth parameter return JSTaggedValue::Cast( - static_cast(thread->GetEcmaVM()->GetEcmaStringTable()->InsertStringToTable(str))); + static_cast(thread->GetEcmaVM()->GetEcmaStringTable()->InsertStringToTable(thread->GetEcmaVM(), str))); } DEF_RUNTIME_STUBS(SlowFlattenString) @@ -2786,9 +2812,10 @@ DEF_RUNTIME_STUBS(SlowFlattenString) return JSTaggedValue(EcmaStringAccessor::SlowFlatten(thread->GetEcmaVM(), str)).GetRawData(); } -JSTaggedType RuntimeStubs::TryToElementsIndexOrFindInStringTable(uintptr_t argGlue, JSTaggedType ecmaString) +DEF_RUNTIME_STUBS(TryToElementsIndexOrFindInStringTable) { - auto string = reinterpret_cast(ecmaString); + RUNTIME_STUBS_HEADER(TryToElementsIndexOrFindInStringTable); + JSHandle string = GetHArg(argv, argc, 0); // 0: means the zeroth parameter uint32_t index = 0; if (EcmaStringAccessor(string).ToElementIndex(&index)) { return JSTaggedValue(index).GetRawData(); @@ -2796,12 +2823,13 @@ JSTaggedType RuntimeStubs::TryToElementsIndexOrFindInStringTable(uintptr_t argGl if (!EcmaStringAccessor(string).IsInternString()) { return RuntimeTryGetInternString(argGlue, string); } - return ecmaString; + return string.GetTaggedValue().GetRawData(); } -JSTaggedType RuntimeStubs::TryGetInternString(uintptr_t argGlue, JSTaggedType ecmaString) +DEF_RUNTIME_STUBS(TryGetInternString) { - auto string = reinterpret_cast(ecmaString); + RUNTIME_STUBS_HEADER(TryGetInternString); + JSHandle string = GetHArg(argv, argc, 0); // 0: means the zeroth parameter return RuntimeTryGetInternString(argGlue, string); } @@ -2978,6 +3006,14 @@ void RuntimeStubs::InsertOldToNewRSet([[maybe_unused]] uintptr_t argGlue, return region->InsertOldToNewRSet(slotAddr); } +void RuntimeStubs::InsertLocalToShareRSet([[maybe_unused]] uintptr_t argGlue, + uintptr_t object, size_t offset) +{ + Region *region = Region::ObjectAddressToRange(object); + uintptr_t slotAddr = object + offset; + region->AtomicInsertLocalToShareRSet(slotAddr); +} + void RuntimeStubs::MarkingBarrier([[maybe_unused]] uintptr_t argGlue, uintptr_t object, size_t offset, TaggedObject *value) { @@ -3013,6 +3049,9 @@ void RuntimeStubs::StoreBarrier([[maybe_unused]] uintptr_t argGlue, ASSERT((slotAddr % static_cast(MemAlignment::MEM_ALIGN_OBJECT)) == 0); objectRegion->InsertOldToNewRSet(slotAddr); } + if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) { + objectRegion->AtomicInsertLocalToShareRSet(slotAddr); + } if (!thread->IsConcurrentMarkingOrFinished()) { return; } @@ -3114,9 +3153,11 @@ void RuntimeStubs::SaveFrameToContext(JSThread *thread, JSHandleSetRegsArray(thread, regsArray.GetTaggedValue()); JSTaggedValue function = frameHandler.GetFunction(); - Method *method = JSFunction::Cast(function.GetTaggedObject())->GetCallTarget(); + JSFunction* func = JSFunction::Cast(function.GetTaggedObject()); + Method *method = func->GetCallTarget(); if (method->IsAotWithCallField()) { method->ClearAOTStatusWhenDeopt(); + func->SetCodeEntry(reinterpret_cast(nullptr)); } context->SetMethod(thread, function); context->SetThis(thread, frameHandler.GetThis()); diff --git a/ecmascript/stubs/runtime_stubs.h b/ecmascript/stubs/runtime_stubs.h index ab43b82a4a235cbde4e45e1c14996a4eda6bc6ce..2c44a0f26ba8106fe95cb97424e8ec4cc43a36dc 100644 --- a/ecmascript/stubs/runtime_stubs.h +++ b/ecmascript/stubs/runtime_stubs.h @@ -110,6 +110,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co V(FatalPrintCustom) \ V(GetActualArgvNoGC) \ V(InsertOldToNewRSet) \ + V(InsertLocalToShareRSet) \ V(MarkingBarrier) \ V(StoreBarrier) \ V(DoubleToInt) \ @@ -136,8 +137,6 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co V(FloatFloor) \ V(FloatPow) \ V(FindElementWithCache) \ - V(TryToElementsIndexOrFindInStringTable) \ - V(TryGetInternString) \ V(CreateArrayFromList) \ V(StringsAreEquals) \ V(BigIntEquals) \ @@ -158,6 +157,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co #define RUNTIME_STUB_WITH_GC_LIST(V) \ V(AddElementInternal) \ V(AllocateInYoung) \ + V(AllocateInSOld) \ V(CallInternalGetter) \ V(CallInternalSetter) \ V(CallGetPrototype) \ @@ -278,6 +278,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co V(StModuleVar) \ V(LdLocalModuleVarByIndex) \ V(LdExternalModuleVarByIndex) \ + V(LdSendableExternalModuleVarByIndex) \ V(LdLocalModuleVarByIndexOnJSFunc) \ V(LdExternalModuleVarByIndexOnJSFunc) \ V(LdModuleVar) \ @@ -406,7 +407,9 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co V(FunctionDefineOwnProperty) \ V(AOTEnableProtoChangeMarker) \ V(HasProperty) \ - V(DumpObject) + V(DumpObject) \ + V(TryGetInternString) \ + V(TryToElementsIndexOrFindInStringTable) #define RUNTIME_STUB_LIST(V) \ RUNTIME_ASM_STUB_LIST(V) \ @@ -464,11 +467,10 @@ public: uintptr_t object, size_t offset, TaggedObject *value); static void StoreBarrier([[maybe_unused]] uintptr_t argGlue, uintptr_t object, size_t offset, TaggedObject *value); - static JSTaggedType TryToElementsIndexOrFindInStringTable(uintptr_t argGlue, JSTaggedType ecmaString); - static JSTaggedType TryGetInternString(uintptr_t argGlue, JSTaggedType ecmaString); static JSTaggedType CreateArrayFromList([[maybe_unused]] uintptr_t argGlue, int32_t argc, JSTaggedValue *argvPtr); static JSTaggedType GetActualArgvNoGC(uintptr_t argGlue); static void InsertOldToNewRSet([[maybe_unused]] uintptr_t argGlue, uintptr_t object, size_t offset); + static void InsertLocalToShareRSet([[maybe_unused]] uintptr_t argGlue, uintptr_t object, size_t offset); static int32_t DoubleToInt(double x, size_t bits); static JSTaggedType DoubleToLength(double x); static double FloatMod(double x, double y); @@ -616,7 +618,7 @@ private: ClassKind kind = ClassKind::NON_SENDABLE); static inline JSTaggedValue RuntimeSetClassConstructorLength(JSThread *thread, JSTaggedValue ctor, JSTaggedValue length); - static inline JSTaggedValue RuntimeNotifyInlineCache(JSThread *thread, const JSHandle &method, + static inline JSTaggedValue RuntimeNotifyInlineCache(JSThread *thread, const JSHandle &function, uint32_t icSlotSize); static inline JSTaggedValue RuntimeStOwnByValueWithNameSet(JSThread *thread, const JSHandle &obj, const JSHandle &key, @@ -642,6 +644,8 @@ private: static inline JSTaggedValue RuntimeLdLocalModuleVar(JSThread *thread, int32_t index, JSTaggedValue jsFunc); static inline JSTaggedValue RuntimeLdExternalModuleVar(JSThread *thread, int32_t index); + static inline JSTaggedValue RuntimeLdSendableExternalModuleVar(JSThread *thread, int32_t index, + JSTaggedValue jsFunc); static inline JSTaggedValue RuntimeLdExternalModuleVar(JSThread *thread, int32_t index, JSTaggedValue jsFunc); static inline JSTaggedValue RuntimeLdModuleVar(JSThread *thread, JSTaggedValue key, bool inner); @@ -755,7 +759,8 @@ private: uint16_t firstArgRegIdx); static inline JSTaggedValue RuntimeDefineMethod(JSThread *thread, const JSHandle &methodHandle, const JSHandle &homeObject, uint16_t length, - const JSHandle &env); + const JSHandle &env, + const JSHandle &module); static inline JSTaggedValue RuntimeCallSpread(JSThread *thread, const JSHandle &func, const JSHandle &obj, const JSHandle &array); @@ -846,7 +851,7 @@ private: static inline bool ShouldUseAOTHClass(const JSHandle &ihc, const JSHandle &chc, const JSHandle &classLiteral); - static inline JSTaggedType RuntimeTryGetInternString(uintptr_t argGlue, EcmaString *string); + static inline JSTaggedType RuntimeTryGetInternString(uintptr_t argGlue, const JSHandle &string); friend class SlowRuntimeStub; }; } // namespace panda::ecmascript diff --git a/ecmascript/tagged_array-inl.h b/ecmascript/tagged_array-inl.h index 6b3f1230680d97a19e1534fabcd0094c484ac269..bc3671d2ece4274ffa15302d574c1b6a7404570f 100644 --- a/ecmascript/tagged_array-inl.h +++ b/ecmascript/tagged_array-inl.h @@ -173,7 +173,7 @@ void TaggedArray::RemoveElementByIndex(const JSThread *thread, JSHandleIsYoungAndNotMarking(thread))) { + if (noNeedBarrier) { size_t taggedTypeSize = JSTaggedValue::TaggedTypeSize(); size_t offset = taggedTypeSize * index; auto *addr = reinterpret_cast(ToUintPtr(srcArray->GetData()) + offset); @@ -196,21 +196,10 @@ void TaggedArray::InsertElementByIndex(const JSThread *thread, JSHandleGetLength()); - if (srcArray->IsYoungAndNotMarking(thread)) { - size_t taggedTypeSize = JSTaggedValue::TaggedTypeSize(); - size_t offset = taggedTypeSize * effectiveLength; - auto *addr = reinterpret_cast(ToUintPtr(srcArray->GetData()) + offset); - while (effectiveLength != index && effectiveLength > 0) { - *addr = *(addr - 1); - addr--; - effectiveLength--; - } - } else { - while (effectiveLength != index && effectiveLength > 0) { - JSTaggedValue oldValue = srcArray->Get(effectiveLength - 1); - srcArray->Set(thread, effectiveLength, oldValue); - effectiveLength--; - } + while (effectiveLength != index && effectiveLength > 0) { + JSTaggedValue oldValue = srcArray->Get(effectiveLength - 1); + srcArray->Set(thread, effectiveLength, oldValue); + effectiveLength--; } srcArray->Set(thread, index, value.GetTaggedValue()); } @@ -220,16 +209,8 @@ void TaggedArray::CopyTaggedArrayElement(const JSThread *thread, JSHandleGetLength()); ASSERT(effectiveLength <= dstElements->GetLength()); - if (dstElements->IsYoungAndNotMarking(thread)) { - size_t size = effectiveLength * sizeof(JSTaggedType); - if (memcpy_s(reinterpret_cast(dstElements->GetData()), size, - reinterpret_cast(srcElements->GetData()), size) != EOK) { - LOG_FULL(FATAL) << "memcpy_s failed" << " size: " << size; - } - } else { - for (uint32_t i = 0; i < effectiveLength; i++) { - dstElements->Set(thread, i, srcElements->Get(i)); - } + for (uint32_t i = 0; i < effectiveLength; i++) { + dstElements->Set(thread, i, srcElements->Get(i)); } } diff --git a/ecmascript/tagged_dictionary.cpp b/ecmascript/tagged_dictionary.cpp index 86b55a7c3f5759c75839613425f54d995fa45e9f..4022d60245a37ae283d31e769afd8cd6d5e0c96b 100644 --- a/ecmascript/tagged_dictionary.cpp +++ b/ecmascript/tagged_dictionary.cpp @@ -193,10 +193,15 @@ JSHandle NameDictionary::Create(const JSThread *thread, int numb return OrderHashTableT::Create(thread, numberOfElements); } +JSHandle NameDictionary::CreateInSharedHeap(const JSThread *thread, int numberOfElements) +{ + return OrderHashTableT::Create(thread, numberOfElements, true); +} + PropertyAttributes NameDictionary::GetAttributes(int entry) const { int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX; - return PropertyAttributes(Get(index).GetInt()); + return PropertyAttributes(Get(index)); } void NameDictionary::SetAttributes(const JSThread *thread, int entry, const PropertyAttributes &metaData) @@ -372,7 +377,7 @@ JSHandle NumberDictionary::Create(const JSThread *thread, int PropertyAttributes NumberDictionary::GetAttributes(int entry) const { int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX; - return PropertyAttributes(Get(index).GetInt()); + return PropertyAttributes(Get(index)); } void NumberDictionary::SetAttributes(const JSThread *thread, int entry, const PropertyAttributes &metaData) diff --git a/ecmascript/tagged_dictionary.h b/ecmascript/tagged_dictionary.h index 1dac9ee36c4b423f8e2d190934e4e4a723f12b25..a6be1d6612dbafe73c8f4397133e93f5f875792e 100644 --- a/ecmascript/tagged_dictionary.h +++ b/ecmascript/tagged_dictionary.h @@ -47,7 +47,9 @@ public: static bool IsMatch(const uint8_t* str, int size, const JSTaggedValue &other); static JSHandle Create(const JSThread *thread, - int numberOfElements = OrderHashTableT::DEFAULT_ELEMENTS_NUMBER); + int numberOfElements = OrderHashTableT::DEFAULT_ELEMENTS_NUMBER); + static JSHandle CreateInSharedHeap(const JSThread *thread, + int numberOfElements = OrderHashTableT::DEFAULT_ELEMENTS_NUMBER); // Returns the property metaData for the property at entry. PropertyAttributes PUBLIC_API GetAttributes(int entry) const; void PUBLIC_API SetAttributes(const JSThread *thread, int entry, const PropertyAttributes &metaData); diff --git a/ecmascript/tagged_hash_table.h b/ecmascript/tagged_hash_table.h index 33e52656658b05844568e90d3bf884791a4f322f..d35a427fa0441638dc4a5310075ab7962634562b 100644 --- a/ecmascript/tagged_hash_table.h +++ b/ecmascript/tagged_hash_table.h @@ -69,7 +69,9 @@ public: int freeSize = table->Size() - table->EntriesCount() - numOfAddedElements; if (table->HoleEntriesCount() > freeSize / 2) { // 2: half int copyLength = Derived::GetEntryIndex(table->Size()); - JSHandle copyTable(thread->GetEcmaVM()->GetFactory()->NewDictionaryArray(copyLength)); + JSHandle copyTable = table.GetTaggedValue().IsInSharedHeap() ? + JSHandle(thread->GetEcmaVM()->GetFactory()->NewSDictionaryArray(copyLength)) : + JSHandle(thread->GetEcmaVM()->GetFactory()->NewDictionaryArray(copyLength)); copyTable->SetHashTableSize(thread, table->Size()); table->Rehash(thread, *copyTable); return copyTable; @@ -80,13 +82,15 @@ public: table->Size(), numOfAddedElements); newSize = std::max(newSize, MIN_SHRINK_SIZE); int length = Derived::GetEntryIndex(newSize); - JSHandle newTable(thread->GetEcmaVM()->GetFactory()->NewDictionaryArray(length)); + JSHandle newTable = table.GetTaggedValue().IsInSharedHeap() ? + JSHandle(thread->GetEcmaVM()->GetFactory()->NewSDictionaryArray(length)) : + JSHandle(thread->GetEcmaVM()->GetFactory()->NewDictionaryArray(length)); newTable->SetHashTableSize(thread, newSize); table->Rehash(thread, *newTable); return newTable; } - static JSHandle Create(const JSThread *thread, int entriesCount) + static JSHandle Create(const JSThread *thread, int entriesCount, bool inShareSpace = false) { ASSERT_PRINT((entriesCount > 0), "the size must be greater than zero"); auto size = static_cast(entriesCount); @@ -94,7 +98,9 @@ public: int length = Derived::GetEntryIndex(entriesCount); - JSHandle table(thread->GetEcmaVM()->GetFactory()->NewDictionaryArray(length)); + JSHandle table = inShareSpace ? + JSHandle(thread->GetEcmaVM()->GetFactory()->NewSDictionaryArray(length)) : + JSHandle(thread->GetEcmaVM()->GetFactory()->NewDictionaryArray(length)); table->SetEntriesCount(thread, 0); table->SetHoleEntriesCount(thread, 0); table->SetHashTableSize(thread, size); @@ -401,9 +407,10 @@ public: return newTable; } - static JSHandle Create(const JSThread *thread, int numberOfElements = DEFAULT_ELEMENTS_NUMBER) + static JSHandle Create(const JSThread *thread, int numberOfElements = DEFAULT_ELEMENTS_NUMBER, + bool inShareSpace = false) { - JSHandle dict = HashTableT::Create(thread, numberOfElements); + JSHandle dict = HashTableT::Create(thread, numberOfElements, inShareSpace); dict->SetNextEnumerationIndex(thread, PropertyAttributes::INITIAL_PROPERTY_INDEX); return dict; } @@ -443,7 +450,7 @@ public: PropertyAttributes attr(metaData); attr.SetDictionaryOrder(enumIndex); attr.SetRepresentation(Representation::TAGGED); - attr.SetDictTrackType(metaData.GetTrackType()); + attr.SetDictSharedFieldType(metaData.GetSharedFieldType()); int entry = table->FindEntry(key.GetTaggedValue()); if (entry != -1) { table->SetEntry(thread, entry, key.GetTaggedValue(), value.GetTaggedValue(), attr); diff --git a/ecmascript/tests/BUILD.gn b/ecmascript/tests/BUILD.gn index 74ed0ef5f55b54dd6c5d1abac8dfd7a8b61cdc93..f040903a9fba8af07c75c92aab59f33d92c1c68f 100644 --- a/ecmascript/tests/BUILD.gn +++ b/ecmascript/tests/BUILD.gn @@ -1332,6 +1332,33 @@ host_unittest_action("EcmaVm_047_Test") { deps += hiviewdfx_deps } +host_unittest_action("EcmaVm_048_Test") { + module_out_path = module_output_path + + sources = [ + # test file + "js_thread_state_test.cpp", + ] + + configs = [ + "../../:asm_interp_enable_config", + "../../:ecma_test_config", + "$ark_root/assembler:arkassembler_public_config", + "$ark_root/libpandafile:arkfile_public_config", + ] + + deps = [ + "$ark_third_party_root/icu/icu4c:shared_icui18n", + "$ark_third_party_root/icu/icu4c:shared_icuuc", + "../../:libark_jsruntime_test", + sdk_libc_secshared_dep, + ] + + # hiviewdfx libraries + external_deps = hiviewdfx_ext_deps + deps += hiviewdfx_deps +} + group("unittest") { testonly = true @@ -1384,6 +1411,7 @@ group("unittest") { ":EcmaVm_045_Test", ":EcmaVm_046_Test", ":EcmaVm_047_Test", + ":EcmaVm_048_Test", ] } @@ -1439,6 +1467,7 @@ group("host_unittest") { ":EcmaVm_045_TestAction", ":EcmaVm_046_TestAction", ":EcmaVm_047_TestAction", + ":EcmaVm_048_TestAction", ] if (is_mac) { @@ -1490,6 +1519,7 @@ group("host_unittest") { ":EcmaVm_045_TestAction", ":EcmaVm_046_TestAction", ":EcmaVm_047_TestAction", + ":EcmaVm_048_TestAction", ] } } diff --git a/ecmascript/tests/accessor_data_test.cpp b/ecmascript/tests/accessor_data_test.cpp index f6ac2cab5a57f6fa48e07ac6a0e7fe11f7327199..4cd46bb756917adb0b614186398f867a4c4105c6 100644 --- a/ecmascript/tests/accessor_data_test.cpp +++ b/ecmascript/tests/accessor_data_test.cpp @@ -178,7 +178,7 @@ HWTEST_F_L0(AccessorDataTest, CallInternalSet) JSFunction *func1 = globalEnv->GetObjectFunction().GetObject(); Method::Cast(func1->GetMethod().GetTaggedObject())->SetFunctionKind(FunctionKind::BASE_CONSTRUCTOR); JSHandle funcTagVal1 = - factory->CloneJSFuction(JSHandle(thread, func1)); + factory->CloneJSFunction(JSHandle(thread, func1)); // Call the CallInternalGet method to inspect prototype. JSHandle nullPrototypeHandle(thread, JSTaggedValue::Null()); diff --git a/ecmascript/tests/concurrent_marking_test.cpp b/ecmascript/tests/concurrent_marking_test.cpp index 897f558db55d2629bf31ebadc5188cfad1f6d130..612493cbad693305336af2132d7a0112ae39aa5c 100644 --- a/ecmascript/tests/concurrent_marking_test.cpp +++ b/ecmascript/tests/concurrent_marking_test.cpp @@ -43,6 +43,7 @@ public: instance = JSNApi::CreateEcmaVM(options); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); instance->SetEnableForceGC(false); auto heap = const_cast(thread->GetEcmaVM()->GetHeap()); diff --git a/ecmascript/tests/dump_test.cpp b/ecmascript/tests/dump_test.cpp index d14a91864a5f075c854a74807e6876f88f9b7573..74cf9add7f5a654ba9554f3eeb9e631823b9fa82 100644 --- a/ecmascript/tests/dump_test.cpp +++ b/ecmascript/tests/dump_test.cpp @@ -451,19 +451,19 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump) } case JSType::METHOD: { #ifdef PANDA_TARGET_64 - CHECK_DUMP_FIELDS(TaggedObject::TaggedObjectSize(), Method::SIZE, 9U); + CHECK_DUMP_FIELDS(TaggedObject::TaggedObjectSize(), Method::SIZE, 6U); #else - CHECK_DUMP_FIELDS(TaggedObject::TaggedObjectSize(), Method::SIZE, 8U); + CHECK_DUMP_FIELDS(TaggedObject::TaggedObjectSize(), Method::SIZE, 5U); #endif break; } case JSType::JS_FUNCTION_BASE: { - CHECK_DUMP_FIELDS(JSObject::SIZE, JSFunctionBase::SIZE, 2U); + CHECK_DUMP_FIELDS(JSObject::SIZE, JSFunctionBase::SIZE, 3U); break; } case JSType::JS_FUNCTION: case JSType::JS_SHARED_FUNCTION: { - CHECK_DUMP_FIELDS(JSFunctionBase::SIZE, JSFunction::SIZE, 4U); + CHECK_DUMP_FIELDS(JSFunctionBase::SIZE, JSFunction::SIZE, 7U); JSHandle jsFunc = globalEnv->GetFunctionFunction(); DUMP_FOR_HANDLE(jsFunc); break; @@ -493,7 +493,7 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump) break; } case JSType::JS_ASYNC_MODULE_FULFILLED_FUNCTION: { - CHECK_DUMP_FIELDS(JSFunction::SIZE, JSAsyncModuleFulfilledFunction::SIZE, 1U); + CHECK_DUMP_FIELDS(JSFunction::SIZE, JSAsyncModuleFulfilledFunction::SIZE, 0U); JSHandle moduleFulfilledClass = JSHandle::Cast(globalEnv->GetAsyncModuleFulfilledFunctionClass()); JSHandle moduleFulfilledFunc = factory->NewJSObjectWithInit(moduleFulfilledClass); @@ -501,7 +501,7 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump) break; } case JSType::JS_ASYNC_MODULE_REJECTED_FUNCTION: { - CHECK_DUMP_FIELDS(JSFunction::SIZE, JSAsyncModuleRejectedFunction::SIZE, 1U); + CHECK_DUMP_FIELDS(JSFunction::SIZE, JSAsyncModuleRejectedFunction::SIZE, 0U); JSHandle moduleRejectedClass = JSHandle::Cast(globalEnv->GetAsyncModuleRejectedFunctionClass()); JSHandle moduleRejectedFunc = factory->NewJSObjectWithInit(moduleRejectedClass); @@ -1376,6 +1376,12 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump) DUMP_FOR_HANDLE(resolvedBinding); break; } + case JSType::RESOLVEDRECORDBINDING_RECORD: { + CHECK_DUMP_FIELDS(Record::SIZE, ResolvedRecordBinding::SIZE, 2U); + JSHandle recordBinding = factory->NewSResolvedRecordBindingRecord(); + DUMP_FOR_HANDLE(recordBinding); + break; + } case JSType::JS_MODULE_NAMESPACE: { CHECK_DUMP_FIELDS(JSObject::SIZE, ModuleNamespace::SIZE, 3U); JSHandle moduleNamespace = factory->NewModuleNamespace(); diff --git a/ecmascript/tests/ecma_string_table_test.cpp b/ecmascript/tests/ecma_string_table_test.cpp index 65f4260443b41b1b721042cde6198ee0914bc057..08b4b5f6b59fb7a31b361f5a099c872739fdce28 100644 --- a/ecmascript/tests/ecma_string_table_test.cpp +++ b/ecmascript/tests/ecma_string_table_test.cpp @@ -59,7 +59,7 @@ HWTEST_F_L0(EcmaStringTableTest, InternEmptyString) JSHandle emptyEcmaStrHandle(thread, EcmaStringAccessor::CreateEmptyString(thread->GetEcmaVM())); EXPECT_TRUE(!EcmaStringAccessor(emptyEcmaStrHandle).IsInternString()); - table->InternEmptyString(*emptyEcmaStrHandle); + table->InternEmptyString(thread, *emptyEcmaStrHandle); EXPECT_TRUE(EcmaStringAccessor(emptyEcmaStrHandle).IsInternString()); } @@ -79,7 +79,7 @@ HWTEST_F_L0(EcmaStringTableTest, GetOrInternString_utf8Data) EcmaString *ecmaStrCreatePtr = EcmaStringAccessor::CreateFromUtf8(vm, utf8Data, sizeof(utf8Data), true); EXPECT_TRUE(!EcmaStringAccessor(ecmaStrCreatePtr).IsInternString()); - EcmaString *ecmaStrGetPtr = table->GetOrInternString(utf8Data, sizeof(utf8Data), true); + EcmaString *ecmaStrGetPtr = table->GetOrInternString(vm, utf8Data, sizeof(utf8Data), true); EXPECT_STREQ(EcmaStringAccessor(ecmaStrGetPtr).ToCString().c_str(), "hello"); EXPECT_TRUE(EcmaStringAccessor(ecmaStrGetPtr).IsInternString()); } @@ -101,7 +101,7 @@ HWTEST_F_L0(EcmaStringTableTest, GetOrInternString_utf16Data) EcmaStringAccessor::CreateFromUtf16(vm, utf16Data, sizeof(utf16Data) / sizeof(uint16_t), false); EXPECT_TRUE(!EcmaStringAccessor(ecmaStrCreatePtr).IsInternString()); - EcmaString *ecmaStrGetPtr = table->GetOrInternString(utf16Data, sizeof(utf16Data) / sizeof(uint16_t), false); + EcmaString *ecmaStrGetPtr = table->GetOrInternString(vm, utf16Data, sizeof(utf16Data) / sizeof(uint16_t), false); EXPECT_STREQ(EcmaStringAccessor(ecmaStrGetPtr).ToCString().c_str(), "编码解码"); EXPECT_TRUE(EcmaStringAccessor(ecmaStrGetPtr).IsInternString()); } @@ -122,7 +122,7 @@ HWTEST_F_L0(EcmaStringTableTest, GetOrInternString_EcmaString) JSHandle ecmaStrCreateHandle = factory->NewFromASCII("hello world"); EXPECT_TRUE(EcmaStringAccessor(ecmaStrCreateHandle).IsInternString()); - EcmaString *ecmaStrGetPtr = table->GetOrInternString(*ecmaStrCreateHandle); + EcmaString *ecmaStrGetPtr = table->GetOrInternString(vm, *ecmaStrCreateHandle); EXPECT_STREQ(EcmaStringAccessor(ecmaStrGetPtr).ToCString().c_str(), "hello world"); EXPECT_TRUE(EcmaStringAccessor(ecmaStrGetPtr).IsInternString()); } @@ -136,6 +136,6 @@ HWTEST_F_L0(EcmaStringTableTest, GetOrInternString_EcmaString) */ HWTEST_F_L0(EcmaStringTableTest, GetOrInternString_CheckStringTable) { - EXPECT_TRUE(thread->GetEcmaVM()->GetEcmaStringTable()->CheckStringTableValidity()); + EXPECT_TRUE(thread->GetEcmaVM()->GetEcmaStringTable()->CheckStringTableValidity(thread)); } } // namespace panda::test diff --git a/ecmascript/tests/ecma_vm_test.cpp b/ecmascript/tests/ecma_vm_test.cpp index b43c335c0d0669b86e77eb5d0f652a39931aa385..dada7f4f38b39a4e17e863dcbc91466f80f5a2dd 100644 --- a/ecmascript/tests/ecma_vm_test.cpp +++ b/ecmascript/tests/ecma_vm_test.cpp @@ -52,27 +52,30 @@ HWTEST_F_L0(EcmaVMTest, CreateEcmaVMInTwoWays) options.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR); EcmaVM *ecmaVm1 = JSNApi::CreateJSVM(options); - JSRuntimeOptions options2; - options2.SetEnableArkTools(false); - options2.SetEnableForceGC(false); - options2.SetForceFullGC(false); - options2.SetArkProperties(ArkProperties::GC_STATS_PRINT); - // A non-production gc strategy. Prohibit stw-gc 10 times. - EcmaVM *ecmaVm2 = JSNApi::CreateEcmaVM(options2); + std::thread t1([&]() { + JSRuntimeOptions options2; + options2.SetEnableArkTools(false); + options2.SetEnableForceGC(false); + options2.SetForceFullGC(false); + options2.SetArkProperties(ArkProperties::GC_STATS_PRINT); + // A non-production gc strategy. Prohibit stw-gc 10 times. + EcmaVM *ecmaVm2 = JSNApi::CreateEcmaVM(options2); - EXPECT_TRUE(ecmaVm1 != ecmaVm2); + EXPECT_TRUE(ecmaVm1 != ecmaVm2); - JSRuntimeOptions options1Out = ecmaVm1->GetJSOptions(); - JSRuntimeOptions options2Out = ecmaVm2->GetJSOptions(); + JSRuntimeOptions options1Out = ecmaVm1->GetJSOptions(); + JSRuntimeOptions options2Out = ecmaVm2->GetJSOptions(); - EXPECT_TRUE(&options1Out != &options2Out); + EXPECT_TRUE(&options1Out != &options2Out); - EXPECT_TRUE(options1Out.EnableArkTools() != options2Out.EnableArkTools()); - EXPECT_TRUE(options1Out.EnableForceGC() != options2Out.EnableForceGC()); - EXPECT_TRUE(options1Out.ForceFullGC() != options2Out.ForceFullGC()); - EXPECT_TRUE(options1Out.GetArkProperties() != options2Out.GetArkProperties()); + EXPECT_TRUE(options1Out.EnableArkTools() != options2Out.EnableArkTools()); + EXPECT_TRUE(options1Out.EnableForceGC() != options2Out.EnableForceGC()); + EXPECT_TRUE(options1Out.ForceFullGC() != options2Out.ForceFullGC()); + EXPECT_TRUE(options1Out.GetArkProperties() != options2Out.GetArkProperties()); - JSNApi::DestroyJSVM(ecmaVm2); + JSNApi::DestroyJSVM(ecmaVm2); + }); + t1.join(); JSNApi::DestroyJSVM(ecmaVm1); } } // namespace panda::ecmascript diff --git a/ecmascript/tests/gc_first_test.cpp b/ecmascript/tests/gc_first_test.cpp index 6c63fe6097c52f016fa58844d8dcdc1a75d967a9..07169c6e26e99a9378e6609195b4bb328c421e16 100644 --- a/ecmascript/tests/gc_first_test.cpp +++ b/ecmascript/tests/gc_first_test.cpp @@ -14,6 +14,7 @@ */ #include "ecmascript/builtins/builtins_ark_tools.h" +#include "ecmascript/checkpoint/thread_state_transition.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/mem/full_gc.h" #include "ecmascript/object_factory-inl.h" @@ -45,6 +46,7 @@ public: instance = JSNApi::CreateEcmaVM(options); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); auto heap = const_cast(thread->GetEcmaVM()->GetHeap()); heap->GetConcurrentMarker()->EnableConcurrentMarking(EnableConcurrentMarkType::ENABLE); @@ -214,4 +216,36 @@ HWTEST_F_L0(GCTest, NativeBindingCheckGCTest) newNativeSize = heap->GetNativeBindingSize(); EXPECT_EQ(newNativeSize - oldNativeSize, 0UL); } + +HWTEST_F_L0(GCTest, SharedGC) +{ + constexpr size_t ALLOCATE_COUNT = 100; + constexpr size_t ALLOCATE_SIZE = 512; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + auto sHeap = SharedHeap::GetInstance(); + sHeap->CollectGarbage(thread, TriggerGCType::SHARED_GC, GCReason::OTHER); + auto oldSizebase = sHeap->GetOldSpace()->GetHeapObjectSize(); + { + [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread); + for (int i = 0; i < ALLOCATE_COUNT; i++) { + factory->NewSOldSpaceTaggedArray(ALLOCATE_SIZE, JSTaggedValue::Undefined()); + } + } + size_t oldSizeBefore = sHeap->GetOldSpace()->GetHeapObjectSize(); + EXPECT_TRUE(oldSizeBefore > oldSizebase); + sHeap->CollectGarbage(thread, TriggerGCType::SHARED_GC, GCReason::OTHER); + auto oldSizeAfter = sHeap->GetOldSpace()->GetHeapObjectSize(); + EXPECT_TRUE(oldSizeBefore > oldSizeAfter); + EXPECT_EQ(oldSizebase, oldSizeAfter); +} + +HWTEST_F_L0(GCTest, SharedGCSuspendAll) +{ + EXPECT_TRUE(thread->IsInRunningState()); + { + SuspendAllScope suspendScope(thread); + EXPECT_TRUE(!thread->IsInRunningState()); + } + EXPECT_TRUE(thread->IsInRunningState()); +} } // namespace panda::test diff --git a/ecmascript/tests/gc_second_test.cpp b/ecmascript/tests/gc_second_test.cpp index 3002a2563c307c921f77376b8025d78e3bf8024c..1e32a70834e8494f44c62b4e3c8b7378db605fb0 100644 --- a/ecmascript/tests/gc_second_test.cpp +++ b/ecmascript/tests/gc_second_test.cpp @@ -45,6 +45,7 @@ public: instance = JSNApi::CreateEcmaVM(options); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); auto heap = const_cast(thread->GetEcmaVM()->GetHeap()); heap->GetConcurrentMarker()->EnableConcurrentMarking(EnableConcurrentMarkType::ENABLE); diff --git a/ecmascript/tests/gc_third_test.cpp b/ecmascript/tests/gc_third_test.cpp index 90c676878594b728c6b75b6ec2196d6372488c91..dfe904964c3911d203fc18e5ae7bd49e75caedb1 100644 --- a/ecmascript/tests/gc_third_test.cpp +++ b/ecmascript/tests/gc_third_test.cpp @@ -45,6 +45,7 @@ public: instance = JSNApi::CreateEcmaVM(options); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); auto heap = const_cast(thread->GetEcmaVM()->GetHeap()); heap->GetConcurrentMarker()->EnableConcurrentMarking(EnableConcurrentMarkType::ENABLE); diff --git a/ecmascript/tests/glue_regs_test.cpp b/ecmascript/tests/glue_regs_test.cpp index 5c266d3162f945185c9e43041671a12217488f85..2b8fa59c2d98f15ed3d641c5378b833122cf659b 100644 --- a/ecmascript/tests/glue_regs_test.cpp +++ b/ecmascript/tests/glue_regs_test.cpp @@ -103,7 +103,7 @@ HWTEST_F_L0(GlueRegsTest, ConstantAccessorTest) EXPECT_TRUE(!Name##value.IsNull()); \ JSHandle Name##handledValue = globalConst->GetHandled##Name(); \ EXPECT_TRUE(!Name##handledValue->IsNull()); - GLOBAL_ENV_CONSTANT_ACCESSOR(CONSTANT_ACCESSOR_ITERATOR) + SHARED_GLOBAL_ENV_CONSTANT_ACCESSOR(CONSTANT_ACCESSOR_ITERATOR) #undef CONSTANT_ACCESSOR_ITERATOR } } // namespace panda::test \ No newline at end of file diff --git a/ecmascript/tests/handle_leak_test.cpp b/ecmascript/tests/handle_leak_test.cpp index 471edd4c3a13b281e11baf588e352a0f66ab5994..1c682b9621174abe0c708273887f8c1b4290cbc2 100644 --- a/ecmascript/tests/handle_leak_test.cpp +++ b/ecmascript/tests/handle_leak_test.cpp @@ -53,6 +53,7 @@ public: instance = JSNApi::CreateEcmaVM(options); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/tests/incremental_marking_test.cpp b/ecmascript/tests/incremental_marking_test.cpp index f32ecdf42565ab4ca7a3874be3f1d97b39554dcc..b87e402190e708c819a40c426f5224d3d5176a05 100644 --- a/ecmascript/tests/incremental_marking_test.cpp +++ b/ecmascript/tests/incremental_marking_test.cpp @@ -43,6 +43,7 @@ public: instance = JSNApi::CreateEcmaVM(options); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); instance->SetEnableForceGC(false); } diff --git a/ecmascript/tests/js_collator_test.cpp b/ecmascript/tests/js_collator_test.cpp index ea6442cdd90316c22482803077505073f062094a..0119ed81cfb86c8ce37b6a3106fab9c695d2e315 100644 --- a/ecmascript/tests/js_collator_test.cpp +++ b/ecmascript/tests/js_collator_test.cpp @@ -44,6 +44,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/tests/js_date_time_format_first_test.cpp b/ecmascript/tests/js_date_time_format_first_test.cpp index dc36fb24d3740582eddd3673e8e3f96b00a7749a..27c533b691998ebc566b578715bf4cf8be265260 100644 --- a/ecmascript/tests/js_date_time_format_first_test.cpp +++ b/ecmascript/tests/js_date_time_format_first_test.cpp @@ -51,6 +51,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/tests/js_date_time_format_second_test.cpp b/ecmascript/tests/js_date_time_format_second_test.cpp index cab149ed8c78948550e10dcbe25ed1014fd948d6..98417b9695ca1b1d23e15622b82bc6ef1b2f45cf 100644 --- a/ecmascript/tests/js_date_time_format_second_test.cpp +++ b/ecmascript/tests/js_date_time_format_second_test.cpp @@ -51,6 +51,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/tests/js_displaynames_test.cpp b/ecmascript/tests/js_displaynames_test.cpp index 2ef5f5e58f18c25768f865d6c41a0746bf6d7c5a..3f7feb03be383cfea5e19d7c97c2cc49ad293eb2 100644 --- a/ecmascript/tests/js_displaynames_test.cpp +++ b/ecmascript/tests/js_displaynames_test.cpp @@ -46,6 +46,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/tests/js_handle_test.cpp b/ecmascript/tests/js_handle_test.cpp index dad8b658abd8484c01a4e177ffa28ff9c888f94f..0f38887a2411cb834a28e91f6b8095b4b623c872 100644 --- a/ecmascript/tests/js_handle_test.cpp +++ b/ecmascript/tests/js_handle_test.cpp @@ -183,7 +183,8 @@ HWTEST_F_L0(JSHandleTest, NewWeakGlobalHandle) EXPECT_TRUE(thread->IsWeak(globalString)); } // trigger GC - thread->GetEcmaVM()->CollectGarbage(TriggerGCType::FULL_GC); + SharedHeap::GetInstance()->CollectGarbage(instance->GetJSThread(), ecmascript::TriggerGCType::SHARED_GC, + GCReason::OTHER); // check weak reference JSTaggedType result = *reinterpret_cast(globalString); diff --git a/ecmascript/tests/js_hclass_test.cpp b/ecmascript/tests/js_hclass_test.cpp index feeb45872c3ba91002e599be3b5b9d798be1f967..6d29850c4f63cc03d271c52df38223d7f59bed29 100644 --- a/ecmascript/tests/js_hclass_test.cpp +++ b/ecmascript/tests/js_hclass_test.cpp @@ -86,7 +86,7 @@ HWTEST_F_L0(JSHClassTest, SizeFromJSHClass) objectSize = objectClass->SizeFromJSHClass(*objectClass); EXPECT_EQ(objectSize, 40U); #endif - EcmaString *string = factory->AllocLineStringObject(EcmaString::SIZE); + EcmaString *string = EcmaStringAccessor::CreateEmptyString(vm); objectSize = string->GetClass()->SizeFromJSHClass(string); EXPECT_EQ(objectSize, 16U); string = factory->AllocTreeStringObject(); diff --git a/ecmascript/tests/js_list_format_test.cpp b/ecmascript/tests/js_list_format_test.cpp index c4c3e1b2208be676fadc4dde1cfe3e5649837d70..4d879285c7d330b20ff633307b257c5c32a5abb0 100644 --- a/ecmascript/tests/js_list_format_test.cpp +++ b/ecmascript/tests/js_list_format_test.cpp @@ -48,6 +48,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/tests/js_locale_test.cpp b/ecmascript/tests/js_locale_test.cpp index 4fca00040dc31110c52a18b06e64aa6a324ed758..3e33aa6e7496928e3e2686be9106630b1813109a 100644 --- a/ecmascript/tests/js_locale_test.cpp +++ b/ecmascript/tests/js_locale_test.cpp @@ -48,6 +48,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/tests/js_number_format_test.cpp b/ecmascript/tests/js_number_format_test.cpp index a35f0de4e59f04f83a5ec510daefa8d2b0fd2c53..6a16a5423a0990105256d2ebed4e2b869d8b8db6 100644 --- a/ecmascript/tests/js_number_format_test.cpp +++ b/ecmascript/tests/js_number_format_test.cpp @@ -45,6 +45,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/tests/js_plural_rules_test.cpp b/ecmascript/tests/js_plural_rules_test.cpp index b6e04cce1f66eb34ed4ff11f12f2ee8f6fd689f3..709032648f8ba5b01778f1a35fc073fd95bd30a2 100644 --- a/ecmascript/tests/js_plural_rules_test.cpp +++ b/ecmascript/tests/js_plural_rules_test.cpp @@ -47,6 +47,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/tests/js_relative_time_format_test.cpp b/ecmascript/tests/js_relative_time_format_test.cpp index 23174d72762045af58931c15bbacb2b60c12dd18..1ed57032b00a612144e85e05d3a9d7a09547a36c 100644 --- a/ecmascript/tests/js_relative_time_format_test.cpp +++ b/ecmascript/tests/js_relative_time_format_test.cpp @@ -48,6 +48,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/tests/js_serializer_test.cpp b/ecmascript/tests/js_serializer_test.cpp index 5cf9e94403711a2eab3ab811a7dbf6ff9bb89a4c..a35e0c883222c88b0dfab8cd11514778a83245de 100644 --- a/ecmascript/tests/js_serializer_test.cpp +++ b/ecmascript/tests/js_serializer_test.cpp @@ -21,6 +21,7 @@ #include "libpandafile/class_data_accessor-inl.h" #include "ecmascript/builtins/builtins_arraybuffer.h" +#include "ecmascript/checkpoint/thread_state_transition.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" #include "ecmascript/js_array.h" @@ -55,9 +56,11 @@ public: EXPECT_TRUE(ecmaVm != nullptr) << "Cannot create Runtime"; thread = ecmaVm->GetJSThread(); scope = new EcmaHandleScope(thread); + thread->ManagedCodeBegin(); } void Destroy() { + thread->ManagedCodeEnd(); delete scope; scope = nullptr; ecmaVm->SetEnableForceGC(false); @@ -750,8 +753,8 @@ public: EXPECT_FALSE(method->IsNativeWithCallField()); JSHandle constpool(thread, method->GetConstantPool()); - EXPECT_EQ(constpool->GetLength(), 6U); - EXPECT_EQ(constpool->GetCacheLength(), 4U); + EXPECT_EQ(constpool->GetLength(), 8U); + EXPECT_EQ(constpool->GetCacheLength(), 6U); const JSPandaFile *jsPandaFile = constpool->GetJSPandaFile(); EXPECT_TRUE(jsPandaFile != nullptr); const CString &desc = jsPandaFile->GetJSPandaFileDesc(); @@ -1033,6 +1036,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSSpecialValue) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSSpecialValueTest, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1078,6 +1082,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject1) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSPlainObjectTest1, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1126,6 +1131,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject2) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSPlainObjectTest2, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1166,6 +1172,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject3) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSPlainObjectTest3, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; } @@ -1243,6 +1250,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeNativeBindingObject1) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::NativeBindingObjectTest1, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; } @@ -1281,6 +1289,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeNativeBindingObject2) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::NativeBindingObjectTest2, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; } @@ -1323,6 +1332,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeNativeBindingObject3) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::NativeBindingObjectTest3, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; } @@ -1357,6 +1367,7 @@ HWTEST_F_L0(JSSerializerTest, TestSerializeDescription) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::DescriptionTest, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1395,6 +1406,7 @@ HWTEST_F_L0(JSSerializerTest, TestSerializeJSSet) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSSetTest, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1427,6 +1439,7 @@ HWTEST_F_L0(JSSerializerTest, TestSerializeJSArray) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSArrayTest, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1463,6 +1476,7 @@ HWTEST_F_L0(JSSerializerTest, TestObjectsPropertyReference) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::ObjectsPropertyReferenceTest, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1477,6 +1491,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeEcmaString1) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::EcmaStringTest1, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1494,6 +1509,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeEcmaString2) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::EcmaStringTest2, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1507,6 +1523,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeEcmaString3) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::EcmaStringTest3, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1522,6 +1539,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeEcmaString4) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::EcmaStringTest4, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1538,6 +1556,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeInt32_t) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::Int32Test, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1553,6 +1572,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeDouble) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::DoubleTest, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1578,6 +1598,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeDate) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSDateTest, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1611,6 +1632,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSMap) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSMapTest, jsDeserializerTest, data, map); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1645,6 +1667,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSArrayBuffer) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSArrayBufferTest, jsDeserializerTest, data, jsArrayBuffer, 10, nullptr); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1668,6 +1691,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSArrayBufferShared) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSArrayBufferTest, jsDeserializerTest, data, jsArrayBuffer, 12, nullptr); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; delete[] msgBuffer; @@ -1693,6 +1717,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSArrayBufferShared2) std::string changeStr = "world hello"; std::thread t1(&JSDeserializerTest::JSSharedArrayBufferTest, jsDeserializerTest, data, jsArrayBuffer, 12, changeStr.c_str()); + ThreadSuspensionScope scope(thread); t1.join(); EXPECT_TRUE(strcmp((char *)Buffer, "world hello") == 0) << "Serialize JSArrayBuffer fail"; delete serializer; @@ -1717,7 +1742,10 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSArrayBufferShared3) JSDeserializerTest jsDeserializerTest; std::string changeStr = "aaaaaaaaaa"; std::thread t1(&JSDeserializerTest::JSSharedArrayBufferTest1, jsDeserializerTest, data, 5, changeStr.c_str()); - t1.join(); + { + ThreadSuspensionScope scope(thread); + t1.join(); + } EXPECT_TRUE(strcmp((char *)Buffer, "aaaaa world") == 0) << "Serialize JSArrayBuffer fail"; JSSerializer *serializer2 = new JSSerializer(thread); bool success2 = serializer2->SerializeJSTaggedValue(JSHandle::Cast(jsArrayBuffer)); @@ -1726,6 +1754,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSArrayBufferShared3) JSDeserializerTest jsDeserializerTest2; std::string changeStr2 = "bbbbbbbbbbb"; std::thread t2(&JSDeserializerTest::JSSharedArrayBufferTest1, jsDeserializerTest2, data2, 6, changeStr2.c_str()); + ThreadSuspensionScope scope(thread); t2.join(); EXPECT_TRUE(strcmp((char *)Buffer, "bbbbbbworld") == 0) << "Serialize JSArrayBuffer fail"; delete serializer; @@ -1753,6 +1782,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSRegExp) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSRegexpTest, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1796,6 +1826,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSTypedArray1) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TypedArrayTest1, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1829,6 +1860,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSTypedArray2) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TypedArrayTest2, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1850,6 +1882,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeTaggedArray) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TaggedArrayTest, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1892,6 +1925,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeMethod1) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::MethodTest, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1909,12 +1943,12 @@ HWTEST_F_L0(JSSerializerTest, SerializeMethod2) uint32_t methodOffset = 0; std::shared_ptr pf = CreateJSPandaFile(source, fileName, &methodOffset); MethodLiteral *methodLiteral = new MethodLiteral(EntityId(methodOffset)); - JSHandle method = factory->NewMethod(methodLiteral); + JSHandle method = factory->NewSMethod(methodLiteral); EXPECT_TRUE(method.GetTaggedValue().IsMethod()); JSPandaFileManager::GetInstance()->AddJSPandaFileVm(thread->GetEcmaVM(), pf); EXPECT_TRUE(pf != nullptr); - JSHandle constPool = factory->NewConstantPool(4); + JSHandle constPool = factory->NewSConstantPool(4); constPool->SetJSPandaFile(pf.get()); EXPECT_TRUE(constPool.GetTaggedValue().IsConstantPool()); method->SetConstantPool(thread, constPool.GetTaggedValue()); @@ -1925,6 +1959,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeMethod2) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::MethodTest1, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1946,12 +1981,12 @@ HWTEST_F_L0(JSSerializerTest, SerializeAOTMethod) methodLiteral->SetIsFastCall(true); pf->SetMethodLiteralToMap(methodLiteral); - JSHandle method = factory->NewMethod(methodLiteral); + JSHandle method = factory->NewSMethod(methodLiteral); EXPECT_TRUE(method.GetTaggedValue().IsMethod()); JSPandaFileManager::GetInstance()->AddJSPandaFileVm(thread->GetEcmaVM(), pf); EXPECT_TRUE(pf != nullptr); - JSHandle constPool = factory->NewConstantPool(4); + JSHandle constPool = factory->NewSConstantPool(4); constPool->SetJSPandaFile(pf.get()); EXPECT_TRUE(constPool.GetTaggedValue().IsConstantPool()); method->SetConstantPool(thread, constPool.GetTaggedValue()); @@ -1965,6 +2000,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeAOTMethod) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::AOTMethodTest, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -1984,6 +2020,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeConcurrentFunction) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::ConcurrentFunctionTest, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -2041,6 +2078,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeBigInt) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::BigIntTest, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; } @@ -2076,6 +2114,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeObjectWithConcurrentFunction) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::ObjectWithConcurrentFunctionTest, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; @@ -2149,6 +2188,7 @@ HWTEST_F_L0(JSSerializerTest, TransferJSArrayBuffer1) jsDeserializerTest, data, reinterpret_cast(buffer)); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; // test if detached @@ -2179,6 +2219,7 @@ HWTEST_F_L0(JSSerializerTest, TransferJSArrayBuffer2) JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TransferJSArrayBufferTest2, jsDeserializerTest, data, reinterpret_cast(buffer)); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; // test if detached @@ -2200,6 +2241,7 @@ HWTEST_F_L0(JSSerializerTest, TransferJSArrayBuffer3) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TransferJSArrayBufferTest3, jsDeserializerTest, data); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; // test if detached @@ -2231,6 +2273,7 @@ HWTEST_F_L0(JSSerializerTest, TransferJSArrayBuffer4) JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TransferJSArrayBufferTest4, jsDeserializerTest, data, reinterpret_cast(buffer)); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; // test if detached @@ -2269,6 +2312,7 @@ HWTEST_F_L0(JSSerializerTest, TransferJSArrayBufferInTypedArray) std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TransferJSArrayBufferTest5, jsDeserializerTest, data, buffer); + ThreadSuspensionScope scope(thread); t1.join(); delete serializer; // test if detached diff --git a/ecmascript/tests/js_thread_state_test.cpp b/ecmascript/tests/js_thread_state_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..80c778e03511f9e34e96af73f48e4b760bcb510e --- /dev/null +++ b/ecmascript/tests/js_thread_state_test.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2024 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_vm.h" +#include "ecmascript/global_env.h" +#include "ecmascript/js_handle.h" +#include "ecmascript/js_runtime_options.h" +#include "ecmascript/log.h" +#include "ecmascript/tests/test_helper.h" +#include "ecmascript/checkpoint/thread_state_transition.h" + +#include +#include +using namespace panda::ecmascript; + +namespace panda::test { + +class StateTransitioningTest : public testing::Test { +public: + static void SetUpTestCase() + { + GTEST_LOG_(INFO) << "SetUpTestCase"; + } + + static void TearDownTestCase() + { + GTEST_LOG_(INFO) << "TearDownCase"; + } + + void SetUp() override + { + TestHelper::CreateEcmaVMWithScope(instance, thread, scope); + } + + void InitializeLogger() + { + panda::ecmascript::JSRuntimeOptions runtimeOptions; + runtimeOptions.SetLogLevel("error"); + ecmascript::Log::Initialize(runtimeOptions); + } + + void TearDown() override + { + TestHelper::DestroyEcmaVMWithScope(instance, scope); + } + + static void NewVMThreadEntry(EcmaVM *newVm, + bool nativeState, + std::atomic *isTestEnded, + std::atomic *activeThreadCount) + { + panda::RuntimeOption postOption; + JSNApi::PostFork(newVm, postOption); + { + ThreadManagedScope managedScope(JSThread::GetCurrent()); + activeThreadCount->fetch_add(1); + if (nativeState) { + ThreadNativeScope nativeScope(JSThread::GetCurrent()); + while (!isTestEnded->load()) {} + } else { + while (!isTestEnded->load()) { + JSThread::GetCurrent()->CheckSafepoint(); + } + } + } + JSNApi::DestroyJSVM(newVm); + activeThreadCount->fetch_sub(1); + } + + void CreateNewVMInSeparateThread(bool nativeState) + { + std::thread t1([&]() { + RuntimeOption options; + EcmaVM *newVm = JSNApi::CreateJSVM(options); + vms.push_back(newVm); + { + ThreadManagedScope managedScope(newVm->GetJSThread()); + JSNApi::PreFork(newVm); + } + size_t oldCount = activeThreadCount; + // This case isn't a really fork which causes JSThread::GetCurrentThread() equals nullptr in worker_thread. + // So reset the threadState as CREATED to skip the check. + newVm->GetAssociatedJSThread()->UpdateState(ThreadState::CREATED); + std::thread *worker_thread = new std::thread(StateTransitioningTest::NewVMThreadEntry, newVm, nativeState, + &isTestEnded, &activeThreadCount); + threads.push_back(worker_thread); + while (activeThreadCount == oldCount) { + } + }); + t1.join(); + } + + void DestroyAllVMs() + { + isTestEnded = true; + while (activeThreadCount != 0) {} + for (auto i: threads) { + i->join(); + delete(i); + } + } + + std::list vms; + std::list threads; + std::atomic activeThreadCount {0}; + std::atomic isTestEnded {false}; + JSThread *thread {nullptr}; + EcmaVM *instance {nullptr}; + ecmascript::EcmaHandleScope *scope {nullptr}; +}; + +HWTEST_F_L0(StateTransitioningTest, ChangeStateTest) +{ + ASSERT(Runtime::GetInstance()->GetMutatorLock()->HasLock()); + { + ThreadNativeScope nativeScope(thread); + ASSERT(!Runtime::GetInstance()->GetMutatorLock()->HasLock()); + } + { + ThreadNativeScope nativeScope(thread); + ASSERT(!Runtime::GetInstance()->GetMutatorLock()->HasLock()); + { + ThreadManagedScope managedScope(thread); + ASSERT(Runtime::GetInstance()->GetMutatorLock()->HasLock()); + } + } +} + +HWTEST_F_L0(StateTransitioningTest, SuspendAllManagedTest) +{ + CreateNewVMInSeparateThread(false); + { + SuspendAllScope suspendScope(JSThread::GetCurrent()); + } + DestroyAllVMs(); +} + +HWTEST_F_L0(StateTransitioningTest, SuspendAllNativeTest) +{ + CreateNewVMInSeparateThread(true); + { + SuspendAllScope suspendScope(JSThread::GetCurrent()); + } + DestroyAllVMs(); +} +} // namespace panda::test diff --git a/ecmascript/tests/locale_helper_test.cpp b/ecmascript/tests/locale_helper_test.cpp index 694fc00b4cbd95a952acfcd8d47c4f9055b9f3a7..8cf4f59202e485381d3e5ff50625a0e7feb3a793 100644 --- a/ecmascript/tests/locale_helper_test.cpp +++ b/ecmascript/tests/locale_helper_test.cpp @@ -48,6 +48,7 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + thread->ManagedCodeBegin(); scope = new EcmaHandleScope(thread); } diff --git a/ecmascript/tests/read_only_space_test.cpp b/ecmascript/tests/read_only_space_test.cpp index 2b4e42707ed5bba096bc4be681bc881866e87459..8dca54218b38bca3d6a06e6149b3db6c0734b95a 100644 --- a/ecmascript/tests/read_only_space_test.cpp +++ b/ecmascript/tests/read_only_space_test.cpp @@ -125,12 +125,12 @@ HWTEST_F_L0(ReadOnlySpaceTest, CompactHeapBeforeForkTest) JSHandle obj = factory->NewEmptyJSObject(); auto *regionBefore = Region::ObjectAddressToRange(string.GetObject()); auto *objRegionBefore = Region::ObjectAddressToRange(obj.GetObject()); - EXPECT_FALSE(regionBefore->InReadOnlySpace()); + EXPECT_TRUE(regionBefore->InSharedHeap()); EXPECT_FALSE(objRegionBefore->InReadOnlySpace()); heap->CompactHeapBeforeFork(); auto *regionAfter = Region::ObjectAddressToRange(string.GetObject()); auto *objRegionAfter = Region::ObjectAddressToRange(obj.GetObject()); - EXPECT_TRUE(regionAfter->InReadOnlySpace()); + EXPECT_TRUE(regionAfter->InSharedHeap()); EXPECT_FALSE(objRegionAfter->InReadOnlySpace()); } @@ -162,7 +162,7 @@ HWTEST_F_L0(ReadOnlySpaceTest, ForkTest) // test gc in child process heap->CollectGarbage(TriggerGCType::OLD_GC); auto *region = Region::ObjectAddressToRange(string.GetObject()); - EXPECT_TRUE(region->InReadOnlySpace()); + EXPECT_TRUE(region->InSharedHeap()); } } } // namespace panda::test diff --git a/ecmascript/tests/tagged_dictionary_test.cpp b/ecmascript/tests/tagged_dictionary_test.cpp index 61c774f5557e3ce7a22dc6fb6a8a2e342f4adc70..7584b26dd5f7efe2b1ef643d05652b0d0a485221 100644 --- a/ecmascript/tests/tagged_dictionary_test.cpp +++ b/ecmascript/tests/tagged_dictionary_test.cpp @@ -169,7 +169,8 @@ HWTEST_F_L0(TaggedDictionaryTest, NameDictionary_ShrinkCapacity) for (int i = 0; i < 10; i++) { keyArray[5] = '0' + static_cast(i); keyArray[6] = 0; - JSHandle key(thread, stringTable->GetOrInternString(keyArray, utf::Mutf8Size(keyArray), true)); + JSHandle key(thread, + stringTable->GetOrInternString(instance, keyArray, utf::Mutf8Size(keyArray), true)); JSHandle value(thread, JSTaggedValue(i)); PropertyAttributes metaData; // test insert() @@ -179,8 +180,8 @@ HWTEST_F_L0(TaggedDictionaryTest, NameDictionary_ShrinkCapacity) keyArray[5] = '2'; keyArray[6] = 0; - JSHandle arrayHandle(thread, - stringTable->GetOrInternString(keyArray, utf::Mutf8Size(keyArray), true)); + JSHandle arrayHandle( + thread, stringTable->GetOrInternString(instance, keyArray, utf::Mutf8Size(keyArray), true)); int entry = dictHandle->FindEntry(arrayHandle.GetTaggedValue()); EXPECT_NE(entry, -1); diff --git a/ecmascript/tests/test_helper.h b/ecmascript/tests/test_helper.h index 171f82701c7609e853d3b6a592f4ba250e60693f..c463be5ccc6d8592445f87e87d33135157279cd4 100644 --- a/ecmascript/tests/test_helper.h +++ b/ecmascript/tests/test_helper.h @@ -22,6 +22,7 @@ #include "ecmascript/ecma_vm.h" #include "ecmascript/js_function.h" #include "ecmascript/js_handle.h" +#include "ecmascript/js_thread.h" #include "ecmascript/mem/mem_common.h" #include "ecmascript/napi/include/jsnapi.h" #include "ecmascript/object_factory-inl.h" @@ -102,7 +103,7 @@ public: // If you want to call once create, you can refer to BuiltinsMathTest for detail. static void CreateEcmaVMWithScope(EcmaVM *&instance, JSThread *&thread, EcmaHandleScope *&scope, - bool tryLoadStubFile = false, bool useCInterpreter = false) + bool tryLoadStubFile = false, bool useCInterpreter = false, bool startManagedCode = true) { JSRuntimeOptions options; options.SetEnableForceGC(true); @@ -116,11 +117,17 @@ public: instance->SetEnableForceGC(true); ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM"; thread = instance->GetJSThread(); + if (startManagedCode) { + thread->ManagedCodeBegin(); + } scope = new EcmaHandleScope(thread); } - static inline void DestroyEcmaVMWithScope(EcmaVM *instance, EcmaHandleScope *scope) + static inline void DestroyEcmaVMWithScope(EcmaVM *instance, EcmaHandleScope *scope, bool exitManagedCode = true) { + if (exitManagedCode) { + instance->GetJSThread()->ManagedCodeEnd(); + } delete scope; scope = nullptr; instance->SetEnableForceGC(false); diff --git a/ecmascript/ts_types/ts_type_parser.cpp b/ecmascript/ts_types/ts_type_parser.cpp index 422ee7c8703fbffcfaf7c8786c8e9a1f371efd3b..28f6df37f0fc86c80509c84e21fe63db8fdc4822 100644 --- a/ecmascript/ts_types/ts_type_parser.cpp +++ b/ecmascript/ts_types/ts_type_parser.cpp @@ -880,8 +880,10 @@ JSHandle TSTypeParser::ParseNonImportPGOType(GlobalTSTypeRef gt, JSHandle TSTypeParser::ParseObjectPGOType(GlobalTSTypeRef gt, PGOInfo &info) { JSHandle constpoolHandle(tsManager_->GetConstantPool()); + JSTaggedValue unsharedConstpool = thread_->GetCurrentEcmaContext()-> + FindUnsharedConstpool(constpoolHandle.GetTaggedValue()); JSTaggedValue obj = ConstantPool::GetLiteralFromCache( - thread_, constpoolHandle.GetTaggedValue(), info.cpIdx, info.recordName); + thread_, unsharedConstpool, info.cpIdx, info.recordName); JSHandle objHandle(thread_, obj); JSHandle oldHClass(thread_, objHandle->GetClass()); diff --git a/libark_jsruntime.map b/libark_jsruntime.map index f941727d802fdf49bad34c95437471f6b3394bf1..a69869df4f79dd4cf1bcca2259f0d8b7ba665668 100644 --- a/libark_jsruntime.map +++ b/libark_jsruntime.map @@ -104,7 +104,7 @@ panda::ecmascript::AnFileInfo::Save*; panda::ecmascript::Barriers::Update*; panda::ecmascript::BigInt::SameValue*; - panda::ecmascript::ClassHelper::MatchTrackType*; + panda::ecmascript::ClassHelper::MatchFieldType*; panda::ecmascript::ConvertToStdString*; panda::ecmascript::ConvertToString*; panda::ecmascript::Deoptimizier::ComputeShift*; @@ -114,6 +114,7 @@ panda::ecmascript::DynChunk::EmitChar*; panda::ecmascript::EcmaContext::FindConstpool*; panda::ecmascript::EcmaContext::FindOrCreateConstPool*; + panda::ecmascript::EcmaContext::FindUnsharedConstpool*; panda::ecmascript::EcmaContext::SetTSManager*; panda::ecmascript::EcmaString::ComputeHashcode*; panda::ecmascript::EcmaString::GetUtf16DataFlat*; @@ -169,6 +170,7 @@ panda::ecmascript::JSPandaFile::GetRecordNameWithBundlePack*; panda::ecmascript::JSProxy::IsArray*; panda::ecmascript::JSTaggedValue::IsJSCOWArray*; + panda::ecmascript::JSTaggedValue::IsInSharedHeap*; panda::ecmascript::JSTaggedValue::SetProperty*; panda::ecmascript::JSTaggedValue::ToString*; panda::ecmascript::JSTypedArray::FastSetPropertyByIndex*; @@ -206,6 +208,7 @@ panda::ecmascript::ObjectFactory::NewCompressedUtf8*; panda::ecmascript::ObjectFactory::NewDictionaryArray*; panda::ecmascript::ObjectFactory::NewEcmaHClass*; + panda::ecmascript::ObjectFactory::NewSDictionaryArray*; panda::ecmascript::ObjectFactory::NewFromASCII*; panda::ecmascript::ObjectFactory::NewFromUtf16*; panda::ecmascript::ObjectFactory::NewFromUtf8*; @@ -217,6 +220,7 @@ panda::ecmascript::ObjectOperator::UpdateDetector*; panda::ecmascript::PageMap*; panda::ecmascript::PageUnmap*; + panda::ecmascript::PageSize*; panda::ecmascript::RealPath*; panda::ecmascript::SetDirModeAsDefault*; panda::ecmascript::SetFileModeAsDefault*; diff --git a/test/fuzztest/BUILD.gn b/test/fuzztest/BUILD.gn index b7d410d1a9007eb00ab24754ee4ac54c142e436d..8406cc8edee6becbd41066e15de2d1a367cc35a2 100644 --- a/test/fuzztest/BUILD.gn +++ b/test/fuzztest/BUILD.gn @@ -243,7 +243,6 @@ group("fuzztest") { "jsnapicontext_fuzzer:fuzztest", "jsnapideleteserializationdata_fuzzer:fuzztest", "jsnapideserializevalue_fuzzer:fuzztest", - "jsnapidestory_fuzzer:fuzztest", "jsnapiexception_fuzzer:fuzztest", "jsnapiexceptions_fuzzer:fuzztest", "jsnapiexecute_fuzzer:fuzztest", @@ -251,7 +250,6 @@ group("fuzztest") { "jsnapifork_fuzzer:fuzztest", "jsnapihaspendingexception_fuzzer:fuzztest", "jsnapiinformation_fuzzer:fuzztest", - "jsnapiinitialize_fuzzer:fuzztest", "jsnapiisarrayiterator_fuzzer:fuzztest", "jsnapiisbundle_fuzzer:fuzztest", "jsnapiisconstructor_fuzzer:fuzztest", diff --git a/test/fuzztest/jsnapidestory_fuzzer/BUILD.gn b/test/fuzztest/jsnapidestory_fuzzer/BUILD.gn deleted file mode 100644 index fab98a2b7eff3919dcc6c1332813e30d3053cbb7..0000000000000000000000000000000000000000 --- a/test/fuzztest/jsnapidestory_fuzzer/BUILD.gn +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (c) 2023 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. - -#####################################hydra-fuzz############################### -import("//arkcompiler/ets_runtime/js_runtime_config.gni") -import("//arkcompiler/ets_runtime/test/test_helper.gni") -import("//build/config/features.gni") -import("//build/ohos.gni") - -####################################fuzztest################################## -ohos_fuzztest("JSNApiDestoryFuzzTest") { - module_out_path = ets_runtime_output_path - - fuzz_config_file = "$js_root/test/fuzztest/jsnapidestory_fuzzer" - - sources = [ "jsnapidestory_fuzzer.cpp" ] - - configs = [ "$js_root:ecma_test_config" ] - - deps = [ - "$js_root:libark_jsruntime", - sdk_libc_secshared_dep, - ] - - # hiviewdfx libraries - external_deps = hiviewdfx_ext_deps - deps += hiviewdfx_deps -} - -group("fuzztest") { - testonly = true - deps = [] - deps += [ ":JSNApiDestoryFuzzTest" ] -} diff --git a/test/fuzztest/jsnapidestory_fuzzer/jsnapidestory_fuzzer.cpp b/test/fuzztest/jsnapidestory_fuzzer/jsnapidestory_fuzzer.cpp deleted file mode 100644 index 9d74eba9c96af36efde63a7ba70b88d681d9d743..0000000000000000000000000000000000000000 --- a/test/fuzztest/jsnapidestory_fuzzer/jsnapidestory_fuzzer.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2023 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 "jsnapidestory_fuzzer.h" -#include "ecmascript/base/string_helper.h" -#include "ecmascript/napi/include/jsnapi.h" -#include "ecmascript/napi/include/dfx_jsnapi.h" - -using namespace panda; -using namespace panda::ecmascript; - -namespace OHOS { -void JSNApiDestoryAnDataManagerFuzzTest([[maybe_unused]]const uint8_t *data, size_t size) -{ - RuntimeOption option; - option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR); - EcmaVM *vm = JSNApi::CreateJSVM(option); - if (size <= 0) { - return; - } - JSRuntimeOptions runtimeOptions; - JSNApi::InitializeIcuData(runtimeOptions); - JSNApi::DestroyAnDataManager(); - JSNApi::DestroyJSVM(vm); -} - -void JSNApiDestroyPGOProfilerFuzzTest([[maybe_unused]]const uint8_t *data, size_t size) -{ - RuntimeOption option; - option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR); - EcmaVM *vm = JSNApi::CreateJSVM(option); - if (size <= 0) { - return; - } - JSRuntimeOptions runtimeOptions; - JSNApi::InitializePGOProfiler(runtimeOptions); - JSNApi::DestroyPGOProfiler(); - JSNApi::DestroyJSVM(vm); -} -} - -// Fuzzer entry point. -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) -{ - // Run your code on data. - OHOS::JSNApiDestoryAnDataManagerFuzzTest(data, size); - OHOS::JSNApiDestroyPGOProfilerFuzzTest(data, size); - return 0; -} \ No newline at end of file diff --git a/test/fuzztest/jsnapidestory_fuzzer/project.xml b/test/fuzztest/jsnapidestory_fuzzer/project.xml deleted file mode 100644 index b34b12ca9c8a2169da9bdf0f2867fcec717e4eea..0000000000000000000000000000000000000000 --- a/test/fuzztest/jsnapidestory_fuzzer/project.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - 1000 - - 300 - - 5120 - - diff --git a/test/fuzztest/jsnapiinitialize_fuzzer/BUILD.gn b/test/fuzztest/jsnapiinitialize_fuzzer/BUILD.gn deleted file mode 100644 index 861b06c9485832ee8971b62aff70e51c5ca1cd13..0000000000000000000000000000000000000000 --- a/test/fuzztest/jsnapiinitialize_fuzzer/BUILD.gn +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (c) 2023 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. - -#####################################hydra-fuzz############################### -import("//arkcompiler/ets_runtime/js_runtime_config.gni") -import("//arkcompiler/ets_runtime/test/test_helper.gni") -import("//build/config/features.gni") -import("//build/ohos.gni") - -####################################fuzztest################################## -ohos_fuzztest("JSNApiInitializeFuzzTest") { - module_out_path = ets_runtime_output_path - - fuzz_config_file = "$js_root/test/fuzztest/jsnapiinitialize_fuzzer" - - sources = [ "jsnapiinitialize_fuzzer.cpp" ] - - configs = [ "$js_root:ecma_test_config" ] - - deps = [ - "$js_root:libark_jsruntime", - sdk_libc_secshared_dep, - ] - - # hiviewdfx libraries - external_deps = hiviewdfx_ext_deps - deps += hiviewdfx_deps -} - -group("fuzztest") { - testonly = true - deps = [] - deps += [ ":JSNApiInitializeFuzzTest" ] -} diff --git a/test/fuzztest/jsnapiinitialize_fuzzer/jsnapiinitialize_fuzzer.cpp b/test/fuzztest/jsnapiinitialize_fuzzer/jsnapiinitialize_fuzzer.cpp deleted file mode 100644 index 256b27be05233a3632037090ae2f5176c477900e..0000000000000000000000000000000000000000 --- a/test/fuzztest/jsnapiinitialize_fuzzer/jsnapiinitialize_fuzzer.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2023 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 "jsnapiinitialize_fuzzer.h" -#include "ecmascript/base/string_helper.h" -#include "ecmascript/napi/include/dfx_jsnapi.h" -#include "ecmascript/napi/include/jsnapi.h" - -using namespace panda; -using namespace panda::ecmascript; - -namespace OHOS { -void JSNApiInitializeIcuDataFuzzTest([[maybe_unused]]const uint8_t *data, size_t size) -{ - RuntimeOption option; - option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR); - EcmaVM *vm = JSNApi::CreateJSVM(option); - if (size <= 0) { - return; - } - JSRuntimeOptions runtimeOptions; - JSNApi::InitializeIcuData(runtimeOptions); - JSNApi::DestroyJSVM(vm); -} - -void JSNApiInitializePGOProfilerFuzzTest([[maybe_unused]]const uint8_t *data, size_t size) -{ - RuntimeOption option; - option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR); - EcmaVM *vm = JSNApi::CreateJSVM(option); - if (size <= 0) { - return; - } - JSRuntimeOptions runtimeOptions; - JSNApi::InitializePGOProfiler(runtimeOptions); - JSNApi::DestroyJSVM(vm); -} -} - -// Fuzzer entry point. -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) -{ - // Run your code on data. - OHOS::JSNApiInitializeIcuDataFuzzTest(data, size); - OHOS::JSNApiInitializePGOProfilerFuzzTest(data, size); - return 0; -} \ No newline at end of file diff --git a/test/fuzztest/jsnapiinitialize_fuzzer/project.xml b/test/fuzztest/jsnapiinitialize_fuzzer/project.xml deleted file mode 100644 index 4fdbc407f205680885fa42663163b5c987f123a6..0000000000000000000000000000000000000000 --- a/test/fuzztest/jsnapiinitialize_fuzzer/project.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - 1000 - - 300 - - 4096 - - diff --git a/test/fuzztest/jsvaluerefisasync_fuzzer/jsvaluerefisasync_fuzzer.cpp b/test/fuzztest/jsvaluerefisasync_fuzzer/jsvaluerefisasync_fuzzer.cpp index f0c15de5b47680fd8f512db99ebc5ae7ebc54eb0..b027ee75e71491021d9039829950018b667fc388 100644 --- a/test/fuzztest/jsvaluerefisasync_fuzzer/jsvaluerefisasync_fuzzer.cpp +++ b/test/fuzztest/jsvaluerefisasync_fuzzer/jsvaluerefisasync_fuzzer.cpp @@ -37,7 +37,7 @@ namespace OHOS { ptr = const_cast(data); ObjectFactory *factory = vm->GetFactory(); MethodLiteral *methodLiteral = nullptr; - JSHandle method = factory->NewMethod(methodLiteral); + JSHandle method = factory->NewSMethod(methodLiteral); JSHandle asyncGeneratorFunction = factory->NewJSAsyncGeneratorFunction(method); JSHandle asyncgefu = JSHandle::Cast(asyncGeneratorFunction); Local object = JSNApiHelper::ToLocal(asyncgefu); @@ -75,7 +75,7 @@ namespace OHOS { ptr = const_cast(data); ObjectFactory *factory = vm->GetFactory(); MethodLiteral *methodLiteral = nullptr; - JSHandle method = factory->NewMethod(methodLiteral); + JSHandle method = factory->NewSMethod(methodLiteral); JSHandle asyncGeneratorFunction = factory->NewJSAsyncGeneratorFunction(method); JSHandle asyncgefu = JSHandle::Cast(asyncGeneratorFunction); Local object = JSNApiHelper::ToLocal(asyncgefu); diff --git a/test/moduletest/BUILD.gn b/test/moduletest/BUILD.gn index f298899980f68d5c2ac22366ebd8f5c3a29541fe..57898da7c78c13e358d5968432534614bcda4c18 100644 --- a/test/moduletest/BUILD.gn +++ b/test/moduletest/BUILD.gn @@ -169,6 +169,8 @@ group("ark_js_moduletest") { "sharedcheck", "definesendableclass", "sendablecontext", + "sendableclassuseimport", + "sharedic", ] deps = [] @@ -347,6 +349,8 @@ group("ark_asm_test") { "sharedcheck", "definesendableclass", "sendablecontext", + "sendableclassuseimport", + "sharedic", ] deps = [] @@ -502,6 +506,8 @@ group("ark_asm_single_step_test") { "sharedcheck", "definesendableclass", "sendablecontext", + "sendableclassuseimport", + "sharedic", ] deps = [] diff --git a/test/moduletest/sendableclassuseimport/BUILD.gn b/test/moduletest/sendableclassuseimport/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..3f923e128c94f2c881d402a85e03cd97c6a6baf2 --- /dev/null +++ b/test/moduletest/sendableclassuseimport/BUILD.gn @@ -0,0 +1,22 @@ +# Copyright (c) 2023 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. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_moduletest_action("sendableclassuseimport") { + deps = [] + entry_point = "--entry-point=sendableclassuseimport" + is_merge = true + src_postfix = "ts" + is_merge_abc = true +} diff --git a/test/fuzztest/jsnapiinitialize_fuzzer/corpus/init b/test/moduletest/sendableclassuseimport/expect_output.txt similarity index 66% rename from test/fuzztest/jsnapiinitialize_fuzzer/corpus/init rename to test/moduletest/sendableclassuseimport/expect_output.txt index 69c5791762c2df3d7e43cb066be9cd8b56f80621..d790f6f02672db14ab7d1383c22ca61af1cfc14a 100644 --- a/test/fuzztest/jsnapiinitialize_fuzzer/corpus/init +++ b/test/moduletest/sendableclassuseimport/expect_output.txt @@ -1,9 +1,9 @@ -# Copyright (c) 2023 Huawei Device Co., Ltd. +# Copyright (c) 2024 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 +# 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, @@ -11,4 +11,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -FUZZ \ No newline at end of file +(This is strA!) +testOneLevelContext +(This is strA!)(This is strB!) +testImportFunction +foo():(This is strA!) +testImportFunction +ClassB: foo():(This is strB!)foo2 diff --git a/test/moduletest/sendableclassuseimport/func.ts b/test/moduletest/sendableclassuseimport/func.ts new file mode 100644 index 0000000000000000000000000000000000000000..cbc111307a53e9ab16c72248de895dff5c4de4bb --- /dev/null +++ b/test/moduletest/sendableclassuseimport/func.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 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. + */ + +/* + * @tc.name:sendableclassuseimport + * @tc.desc:test sendableclassuseimport + * @tc.type: FUNC + * @tc.require: issue#I91CQ6 + */ +export class Test1 { + value1:string; + constructor(value1:string) { + this.value1 = value1; + } + foo(): string { + return "foo():" + this.value1; + } +} + +export function foo2(a1 : Test1, a2 : string) :string { + return a1.foo() + a2; +} \ No newline at end of file diff --git a/test/moduletest/sendableclassuseimport/sendableclassuseimport.ts b/test/moduletest/sendableclassuseimport/sendableclassuseimport.ts new file mode 100644 index 0000000000000000000000000000000000000000..f087461cacd8882905304a8ae87b68441842b8e1 --- /dev/null +++ b/test/moduletest/sendableclassuseimport/sendableclassuseimport.ts @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024 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. + */ + +/* + * @tc.name:sendableclassuseimport + * @tc.desc:test sendableclassuseimport + * @tc.type: FUNC + * @tc.require: issue#I91CQ6 + */ + +// @ts-nocheck +declare function print(str: any): string; + +import {Test1, foo2} from "./func" +import {strA, strB} from "./string" + +class SendableClassA { + static staticField: string = strA; + constructor() { + "use sendable"; + } + + testZeroLevelContext() { + print(SendableClassA.staticField); + } + + testOneLevelContext() { + let x: number = 0; + (()=>{ + print("testOneLevelContext"); + print(SendableClassA.staticField + strB); + })(); + } + testImportFunction() { + let x: number = 0; + (()=>{ + print("testImportFunction"); + let tA = new Test1(strA); + print(tA.foo()); + })(); + } +} + +let sObj = new SendableClassA; +sObj.testZeroLevelContext(); +sObj.testOneLevelContext(); +sObj.testImportFunction(); + +class SendableClassB extends SendableClassA { + classBStr:string; + constructor(classBStr:string) { + "use sendable"; + super(); + this.classBStr = classBStr; + } + + testImportFunction() { + print("testImportFunction"); + let tB = new Test1(strB); + let foo2Str = foo2(tB, "foo2") + print(this.classBStr + foo2Str); + } +} + +let sObjb = new SendableClassB("ClassB: "); +sObjb.testImportFunction() diff --git a/test/moduletest/sendableclassuseimport/sendableclassuseimport.txt b/test/moduletest/sendableclassuseimport/sendableclassuseimport.txt new file mode 100644 index 0000000000000000000000000000000000000000..bb6a7e06744e9e07e7b4106db6541b05f20e39cc --- /dev/null +++ b/test/moduletest/sendableclassuseimport/sendableclassuseimport.txt @@ -0,0 +1,3 @@ +sendableclassuseimport.ts;sendableclassuseimport;esm;sendableclassuseimport.ts;xxsendableclassuseimportxx +func.ts;func;esm;func.ts;xxfuncxx +string.ts;string;esm;string.ts;xxstringxx \ No newline at end of file diff --git a/test/fuzztest/jsnapiinitialize_fuzzer/jsnapiinitialize_fuzzer.h b/test/moduletest/sendableclassuseimport/string.ts similarity index 61% rename from test/fuzztest/jsnapiinitialize_fuzzer/jsnapiinitialize_fuzzer.h rename to test/moduletest/sendableclassuseimport/string.ts index b98714d227e46f1a508d7ac28c227e13cd597775..7218ddbfd291ce51802786be7cc0d73e4b53417a 100644 --- a/test/fuzztest/jsnapiinitialize_fuzzer/jsnapiinitialize_fuzzer.h +++ b/test/moduletest/sendableclassuseimport/string.ts @@ -1,10 +1,10 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2024 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 + * 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, @@ -13,9 +13,12 @@ * limitations under the License. */ -#ifndef JSNAPIINITIALIZE_FUZZER_H -#define JSNAPIINITIALIZE_FUZZER_H - -#define FUZZ_PROJECT_NAME "jsnapiinitialize_fuzzer.h" +/* + * @tc.name:sendableclassuseimport + * @tc.desc:test sendableclassuseimport + * @tc.type: FUNC + * @tc.require: issue#I91CQ6 + */ -#endif \ No newline at end of file +export var strA : string = "(This is strA!)"; +export var strB : string = "(This is strB!)"; \ No newline at end of file diff --git a/test/moduletest/sharedic/BUILD.gn b/test/moduletest/sharedic/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..dad25ffb51ff4bc32c6a4932bb4139fdef4d198b --- /dev/null +++ b/test/moduletest/sharedic/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright (c) 2023 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. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_moduletest_action("sharedic") { + deps = [] + entry_point = "--entry-point=sharedic" + is_module = true + is_merge = true + src_dir = "$js_root/test/sharedtest/sharedic" + src_postfix = "ts" +} diff --git a/test/resource/js_runtime/ohos_test.xml b/test/resource/js_runtime/ohos_test.xml index 8e1a6d0ff65db33ce20278e10c72e2b6b9707d6b..75beb00b7b3295436e2da0d452d62399955a8d4e 100755 --- a/test/resource/js_runtime/ohos_test.xml +++ b/test/resource/js_runtime/ohos_test.xml @@ -707,6 +707,11 @@