From 6c47d106b7101ac6fa2e781a0e47664e1ac42714 Mon Sep 17 00:00:00 2001 From: Roman Sannikov Date: Wed, 19 Oct 2022 21:33:33 +0300 Subject: [PATCH 1/4] Add alloc_obj intrinsic Signed-off-by: Roman Sannikov --- runtime/builtins.cpp | 1 + runtime/builtins/builtins_global.cpp | 17 +++++++++++++++++ runtime/builtins/builtins_global.h | 1 + runtime/runtime_call_id.h | 1 + tests/runtime/common/startGc.js | 2 +- 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/runtime/builtins.cpp b/runtime/builtins.cpp index 5294de92e..e5f52859f 100644 --- a/runtime/builtins.cpp +++ b/runtime/builtins.cpp @@ -346,6 +346,7 @@ void Builtins::InitializeGlobalObject(const JSHandle &env, const JSHa SetFunction(env, globalObject, "gc", Global::GCEntrypoint, 0); SetFunction(env, globalObject, "startGC", Global::SpecifiedGCEntrypoint, 1); SetFunction(env, globalObject, "waitForFinishGC", Global::WaitForFinishGC, 1); + SetFunction(env, globalObject, "allocateObject", Global::AllocateObject, 1); SetFunction(env, globalObject, "markObject", Global::MarkObject, 1); SetFunction(env, globalObject, "getMarkQueue", Global::GetMarkQueue, 0); SetFunction(env, globalObject, "clearMarkQueue", Global::ClearMarkQueue, 0); diff --git a/runtime/builtins/builtins_global.cpp b/runtime/builtins/builtins_global.cpp index 8e7d235f5..f2a091746 100644 --- a/runtime/builtins/builtins_global.cpp +++ b/runtime/builtins/builtins_global.cpp @@ -26,6 +26,7 @@ #include "plugins/ecmascript/runtime/interpreter/slow_runtime_helper.h" #include "plugins/ecmascript/runtime/js_invoker.h" #include "plugins/ecmascript/runtime/js_eval.h" +#include "plugins/ecmascript/runtime/free_object.h" #include "plugins/ecmascript/runtime/tagged_array-inl.h" #include "include/thread_scopes.h" @@ -793,6 +794,22 @@ JSTaggedValue BuiltinsGlobal::WaitForFinishGC(EcmaRuntimeCallInfo *msg) return JSTaggedValue::Undefined(); } +JSTaggedValue BuiltinsGlobal::AllocateObject(EcmaRuntimeCallInfo *msg) +{ + JSThread *thread = msg->GetThread(); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + ASSERT(thread != nullptr); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + BUILTINS_API_TRACE(thread, Global, AllocateObject); + + uint32_t sizeInBytes = (uint32_t)JSTaggedValue::ToNumber(thread, GetCallArg(msg, 0)).GetNumber(); + + auto newClass = factory->NewEcmaDynClass(nullptr, JSObject::SIZE, JSType::JS_OBJECT); + JSHandle object = factory->NewJSObject(newClass); + + return object.GetTaggedValue(); +} + JSTaggedValue BuiltinsGlobal::MarkObject(EcmaRuntimeCallInfo *msg) { JSThread *thread = msg->GetThread(); diff --git a/runtime/builtins/builtins_global.h b/runtime/builtins/builtins_global.h index 534ea064a..1d71ace46 100644 --- a/runtime/builtins/builtins_global.h +++ b/runtime/builtins/builtins_global.h @@ -50,6 +50,7 @@ public: static JSTaggedValue GCEntrypoint(EcmaRuntimeCallInfo *msg); static JSTaggedValue SpecifiedGCEntrypoint(EcmaRuntimeCallInfo *msg); static JSTaggedValue WaitForFinishGC(EcmaRuntimeCallInfo *msg); + static JSTaggedValue AllocateObject(EcmaRuntimeCallInfo *msg); static JSTaggedValue MarkObject(EcmaRuntimeCallInfo *msg); static JSTaggedValue GetMarkQueue(EcmaRuntimeCallInfo *msg); static JSTaggedValue ClearMarkQueue(EcmaRuntimeCallInfo *msg); diff --git a/runtime/runtime_call_id.h b/runtime/runtime_call_id.h index 454fabd6f..88f1e7ffa 100644 --- a/runtime/runtime_call_id.h +++ b/runtime/runtime_call_id.h @@ -331,6 +331,7 @@ namespace panda::ecmascript { V(Global, MarkObject) \ V(Global, GetMarkQueue) \ V(Global, ClearMarkQueue) \ + V(Global, AllocateObject) \ V(Global, NewobjDynrange) \ V(Global, CallJsBoundFunction) \ V(Global, CallJsProxy) \ diff --git a/tests/runtime/common/startGc.js b/tests/runtime/common/startGc.js index 8056796dd..f47f7be3b 100644 --- a/tests/runtime/common/startGc.js +++ b/tests/runtime/common/startGc.js @@ -52,7 +52,7 @@ function makeTenuredCollectible() // So we need to fill it up by moving more objects to this region. // When the region gets filled GC allocates a new region and the old region // can be collected. - let tmp = allocLargeObject(); + let tmp = allocateObject(1024 * 60); startGC("young"); } -- Gitee From 433939a7d04813275729a3909d1a053f57d4513b Mon Sep 17 00:00:00 2001 From: Roman Sannikov Date: Sat, 22 Oct 2022 12:40:10 +0300 Subject: [PATCH 2/4] Change allocating a JS_OBJECT to allocating a FreeObject with changable size Signed-off-by: Roman Sannikov --- runtime/builtins/builtins_global.cpp | 9 ++++++--- runtime/free_object.h | 4 ++++ runtime/object_factory.cpp | 6 ++++++ runtime/object_factory.h | 2 ++ tests/runtime/common/startGc.js | 5 ++--- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/runtime/builtins/builtins_global.cpp b/runtime/builtins/builtins_global.cpp index f2a091746..da8913c87 100644 --- a/runtime/builtins/builtins_global.cpp +++ b/runtime/builtins/builtins_global.cpp @@ -802,10 +802,13 @@ JSTaggedValue BuiltinsGlobal::AllocateObject(EcmaRuntimeCallInfo *msg) [[maybe_unused]] EcmaHandleScope handleScope(thread); BUILTINS_API_TRACE(thread, Global, AllocateObject); - uint32_t sizeInBytes = (uint32_t)JSTaggedValue::ToNumber(thread, GetCallArg(msg, 0)).GetNumber(); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + uint32_t sizeInBytes = JSTaggedValue::ToNumber(thread, GetCallArg(msg, 0)).GetNumber(); - auto newClass = factory->NewEcmaDynClass(nullptr, JSObject::SIZE, JSType::JS_OBJECT); - JSHandle object = factory->NewJSObject(newClass); + JSHandle newClass = + factory->NewEcmaDynClass(JSHClass::Cast(globalConst->GetHClassClass().GetTaggedObject()), + sizeInBytes, JSType::FREE_OBJECT_WITH_ONE_FIELD); + JSHandle object = factory->NewFreeObject(newClass); return object.GetTaggedValue(); } diff --git a/runtime/free_object.h b/runtime/free_object.h index c38456d22..b5ab7e1b0 100644 --- a/runtime/free_object.h +++ b/runtime/free_object.h @@ -29,6 +29,10 @@ public: { return reinterpret_cast(object); } + static FreeObject *Cast(TaggedObject *object) + { + return reinterpret_cast(object); + } static FreeObject *FillFreeObject(EcmaVM *vm, uintptr_t address, size_t size); inline bool IsEmpty() const diff --git a/runtime/object_factory.cpp b/runtime/object_factory.cpp index 4d822f553..6a358faa4 100644 --- a/runtime/object_factory.cpp +++ b/runtime/object_factory.cpp @@ -325,6 +325,12 @@ JSHandle ObjectFactory::NewJSObject(const JSHandle &jshclass return obj; } +JSHandle ObjectFactory::NewFreeObject(const JSHandle &jshclass) +{ + JSHandle obj(thread_, FreeObject::Cast(NewDynObject(jshclass))); + return obj; +} + JSHandle ObjectFactory::CloneProperties(const JSHandle &old) { uint32_t new_length = old->GetLength(); diff --git a/runtime/object_factory.h b/runtime/object_factory.h index 5490ac660..a7171f59e 100644 --- a/runtime/object_factory.h +++ b/runtime/object_factory.h @@ -385,6 +385,8 @@ public: // used for creating Function JSHandle NewJSObject(const JSHandle &jshclass); + JSHandle NewFreeObject(const JSHandle &jshclass); + // used for creating jshclass in GlobalEnv, EcmaVM template inline JSHandle CreateDynClass(JSHClass *hclass, JSType type, uint32_t flags = 0, diff --git a/tests/runtime/common/startGc.js b/tests/runtime/common/startGc.js index f47f7be3b..99cfd8f80 100644 --- a/tests/runtime/common/startGc.js +++ b/tests/runtime/common/startGc.js @@ -33,8 +33,7 @@ function allocLargeObject() { // Only length setter does this. let big = new Array(); for (let i = 0; i < 60; ++i) { - let a = new Array(); - a.length = 1024; + let a = allocateObject(1024) if (i % 2 == 0) { big[i] = a; } @@ -52,7 +51,7 @@ function makeTenuredCollectible() // So we need to fill it up by moving more objects to this region. // When the region gets filled GC allocates a new region and the old region // can be collected. - let tmp = allocateObject(1024 * 60); + let tmp = allocLargeObject(); startGC("young"); } -- Gitee From dedabdaa25b50cc449f545c99a8cddf097ce533d Mon Sep 17 00:00:00 2001 From: Roman Sannikov Date: Sun, 23 Oct 2022 23:43:26 +0300 Subject: [PATCH 3/4] Added a check for the size Changed JSObject to FreeObject Signed-off-by: Roman Sannikov --- runtime/builtins/builtins_global.cpp | 15 +++++++++++---- runtime/object_factory.cpp | 4 ++-- runtime/object_factory.h | 2 +- tests/runtime/common/startGc.js | 2 +- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/runtime/builtins/builtins_global.cpp b/runtime/builtins/builtins_global.cpp index da8913c87..b276e2c28 100644 --- a/runtime/builtins/builtins_global.cpp +++ b/runtime/builtins/builtins_global.cpp @@ -803,12 +803,19 @@ JSTaggedValue BuiltinsGlobal::AllocateObject(EcmaRuntimeCallInfo *msg) BUILTINS_API_TRACE(thread, Global, AllocateObject); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); - uint32_t sizeInBytes = JSTaggedValue::ToNumber(thread, GetCallArg(msg, 0)).GetNumber(); + int64_t sizeInBytes = JSTaggedValue::ToNumber(thread, GetCallArg(msg, 0)).GetNumber(); + sizeInBytes -= sizeInBytes % 8; + + if (sizeInBytes <= 0) { + JSHandle err = + thread->GetEcmaVM()->GetFactory()->GetJSError(ErrorType::TYPE_ERROR, "The value must be >= 8"); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, err.GetTaggedValue(), JSTaggedValue::Exception()); + } JSHandle newClass = - factory->NewEcmaDynClass(JSHClass::Cast(globalConst->GetHClassClass().GetTaggedObject()), - sizeInBytes, JSType::FREE_OBJECT_WITH_ONE_FIELD); - JSHandle object = factory->NewFreeObject(newClass); + factory->NewEcmaDynClass(JSHClass::Cast(globalConst->GetHClassClass().GetTaggedObject()), sizeInBytes, + JSType::FREE_OBJECT_WITH_NONE_FIELD); + JSHandle object = factory->NewFreeObject(newClass); return object.GetTaggedValue(); } diff --git a/runtime/object_factory.cpp b/runtime/object_factory.cpp index 6a358faa4..476564e33 100644 --- a/runtime/object_factory.cpp +++ b/runtime/object_factory.cpp @@ -325,9 +325,9 @@ JSHandle ObjectFactory::NewJSObject(const JSHandle &jshclass return obj; } -JSHandle ObjectFactory::NewFreeObject(const JSHandle &jshclass) +JSHandle ObjectFactory::NewFreeObject(const JSHandle &jshclass) { - JSHandle obj(thread_, FreeObject::Cast(NewDynObject(jshclass))); + JSHandle obj(thread_, FreeObject::Cast(NewDynObject(jshclass))); return obj; } diff --git a/runtime/object_factory.h b/runtime/object_factory.h index a7171f59e..093470e62 100644 --- a/runtime/object_factory.h +++ b/runtime/object_factory.h @@ -385,7 +385,7 @@ public: // used for creating Function JSHandle NewJSObject(const JSHandle &jshclass); - JSHandle NewFreeObject(const JSHandle &jshclass); + JSHandle NewFreeObject(const JSHandle &jshclass); // used for creating jshclass in GlobalEnv, EcmaVM template diff --git a/tests/runtime/common/startGc.js b/tests/runtime/common/startGc.js index 99cfd8f80..d61fdb45e 100644 --- a/tests/runtime/common/startGc.js +++ b/tests/runtime/common/startGc.js @@ -33,7 +33,7 @@ function allocLargeObject() { // Only length setter does this. let big = new Array(); for (let i = 0; i < 60; ++i) { - let a = allocateObject(1024) + let a = allocateObject(1024 * 8); if (i % 2 == 0) { big[i] = a; } -- Gitee From 56bc293929ed0ff4b7cd675966fac48af62ad640 Mon Sep 17 00:00:00 2001 From: Artem Udovichenko Date: Fri, 28 Oct 2022 10:48:12 +0300 Subject: [PATCH 4/4] Use JSArray to fill space Change-Id: I41af8f934950d7d9d455aecaaaabaaeb9568c4c6 --- runtime/builtins/builtins_global.cpp | 18 ++++++++++-------- runtime/object_factory.cpp | 3 +++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/runtime/builtins/builtins_global.cpp b/runtime/builtins/builtins_global.cpp index b276e2c28..520489b91 100644 --- a/runtime/builtins/builtins_global.cpp +++ b/runtime/builtins/builtins_global.cpp @@ -26,8 +26,8 @@ #include "plugins/ecmascript/runtime/interpreter/slow_runtime_helper.h" #include "plugins/ecmascript/runtime/js_invoker.h" #include "plugins/ecmascript/runtime/js_eval.h" -#include "plugins/ecmascript/runtime/free_object.h" #include "plugins/ecmascript/runtime/tagged_array-inl.h" +#include "plugins/ecmascript/runtime/js_array.h" #include "include/thread_scopes.h" namespace panda::ecmascript::builtins { @@ -802,7 +802,6 @@ JSTaggedValue BuiltinsGlobal::AllocateObject(EcmaRuntimeCallInfo *msg) [[maybe_unused]] EcmaHandleScope handleScope(thread); BUILTINS_API_TRACE(thread, Global, AllocateObject); - const GlobalEnvConstants *globalConst = thread->GlobalConstants(); int64_t sizeInBytes = JSTaggedValue::ToNumber(thread, GetCallArg(msg, 0)).GetNumber(); sizeInBytes -= sizeInBytes % 8; @@ -812,12 +811,15 @@ JSTaggedValue BuiltinsGlobal::AllocateObject(EcmaRuntimeCallInfo *msg) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, err.GetTaggedValue(), JSTaggedValue::Exception()); } - JSHandle newClass = - factory->NewEcmaDynClass(JSHClass::Cast(globalConst->GetHClassClass().GetTaggedObject()), sizeInBytes, - JSType::FREE_OBJECT_WITH_NONE_FIELD); - JSHandle object = factory->NewFreeObject(newClass); - - return object.GetTaggedValue(); + uint32_t numElements = sizeInBytes / sizeof(TaggedType); + JSHandle array = factory->NewJSArray(); + JSHandle elements = factory->NewTaggedArray(numElements); + if (elements.IsEmpty()) { + return JSTaggedValue::Exception(); + } + array->SetElements(thread, elements); + array->SetArrayLength(thread, numElements); + return array.GetTaggedValue(); } JSTaggedValue BuiltinsGlobal::MarkObject(EcmaRuntimeCallInfo *msg) diff --git a/runtime/object_factory.cpp b/runtime/object_factory.cpp index 476564e33..36a46c7cb 100644 --- a/runtime/object_factory.cpp +++ b/runtime/object_factory.cpp @@ -1650,6 +1650,9 @@ JSHandle ObjectFactory::NewTaggedArrayImpl(uint32_t length, JSTagge ASSERT(!init_val.IsHeapObject()); size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), length); auto header = heap_helper_.AllocateYoungGenerationOrHugeObject(weak ? weak_array_class_ : array_class_, size); + if (UNLIKELY(header == nullptr)) { + return JSHandle(); + } JSHandle array(thread_, header); // TODO(audovichenko): Remove this suppression when CSA gets recognize primitive TaggedValue (issue #I5QOJX) // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader) -- Gitee