From b4dc845e496939877c6ba419a4a32b08c1e92769 Mon Sep 17 00:00:00 2001 From: Malinin Andrey Date: Thu, 11 May 2023 10:50:16 +0300 Subject: [PATCH 1/2] [GC] Support native reason collection Signed-off-by: Malinin Andrey --- runtime/object_factory.cpp | 29 +++++++++++++------ tests/runtime/common/gc/CMakeLists.txt | 1 + .../common/gc/registerNativeAllocation.js | 23 +++++++++++++++ 3 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 tests/runtime/common/gc/registerNativeAllocation.js diff --git a/runtime/object_factory.cpp b/runtime/object_factory.cpp index f69a6eede..1123e6916 100644 --- a/runtime/object_factory.cpp +++ b/runtime/object_factory.cpp @@ -81,9 +81,16 @@ namespace panda::ecmascript { using ErrorType = base::ErrorType; using ErrorHelper = base::ErrorHelper; -static void PandaFreeBufferFunc([[maybe_unused]] void *buffer, [[maybe_unused]] void *data) +static void PandaFreeBufferFunc(void *buffer, void *data) { - Runtime::GetCurrent()->GetInternalAllocator()->Free(buffer); + auto *thread = Thread::GetCurrent(); + // Need to check if thread is available because + // we can enter here after the runtime started termination + if (thread == nullptr) { + Runtime::GetCurrent()->GetInternalAllocator()->Free(buffer); + return; + } + thread->GetVM()->GetHeapManager()->FreeAndRegisterNative(buffer, reinterpret_cast(data)); } ObjectFactory::ObjectFactory(JSThread *thread) @@ -188,11 +195,12 @@ void ObjectFactory::NewJSArrayBufferData(const JSHandle &array, i if (length == 0) { return; } + auto size = length * sizeof(uint8_t); JSTaggedValue data = array->GetArrayBufferData(); if (data != JSTaggedValue::Undefined()) { auto *pointer = JSNativePointer::Cast(data.GetTaggedObject()); - auto new_data = Runtime::GetCurrent()->GetInternalAllocator()->Alloc(length * sizeof(uint8_t)); + auto *new_data = vm_->GetHeapManager()->AllocAndRegisterNative(size); if (memset_s(new_data, length, 0, length) != EOK) { LOG_ECMA(FATAL) << "memset_s failed"; UNREACHABLE(); @@ -201,12 +209,13 @@ void ObjectFactory::NewJSArrayBufferData(const JSHandle &array, i return; } - auto new_data = Runtime::GetCurrent()->GetInternalAllocator()->Alloc(length * sizeof(uint8_t)); + auto *new_data = vm_->GetHeapManager()->AllocAndRegisterNative(size); if (memset_s(new_data, length, 0, length) != EOK) { LOG_ECMA(FATAL) << "memset_s failed"; UNREACHABLE(); } - JSHandle pointer = NewJSNativePointer(new_data, PandaFreeBufferFunc); + JSHandle pointer = + NewJSNativePointer(new_data, PandaFreeBufferFunc, reinterpret_cast(size)); array->SetArrayBufferData(thread_, pointer.GetTaggedValue()); vm_->PushToArrayDataList(*pointer); } @@ -220,12 +229,13 @@ JSHandle ObjectFactory::NewJSArrayBuffer(int32_t length) JSHandle array_buffer(NewJSObjectByConstructor(constructor, new_target)); array_buffer->SetArrayBufferByteLength(thread_, JSTaggedValue(length)); if (length > 0) { - auto new_data = Runtime::GetCurrent()->GetInternalAllocator()->Alloc(length); + auto *new_data = vm_->GetHeapManager()->AllocAndRegisterNative(length); if (memset_s(new_data, length, 0, length) != EOK) { LOG_ECMA(FATAL) << "memset_s failed"; UNREACHABLE(); } - JSHandle pointer = NewJSNativePointer(new_data, PandaFreeBufferFunc); + JSHandle pointer = + NewJSNativePointer(new_data, PandaFreeBufferFunc, reinterpret_cast(length)); array_buffer->SetArrayBufferData(thread_, pointer.GetTaggedValue()); array_buffer->SetShared(thread_, JSTaggedValue::False()); vm_->PushToArrayDataList(*pointer); @@ -281,7 +291,7 @@ void ObjectFactory::NewJSRegExpByteCodeData(const JSHandle ®exp, vo return; } - auto new_buffer = Runtime::GetCurrent()->GetInternalAllocator()->Alloc(size); + auto *new_buffer = vm_->GetHeapManager()->AllocAndRegisterNative(size); if (memcpy_s(new_buffer, size, buffer, size) != EOK) { LOG_ECMA(FATAL) << "memcpy_s failed"; UNREACHABLE(); @@ -292,7 +302,8 @@ void ObjectFactory::NewJSRegExpByteCodeData(const JSHandle ®exp, vo native->ResetExternalPointer(new_buffer); return; } - JSHandle pointer = NewJSNativePointer(new_buffer, PandaFreeBufferFunc); + JSHandle pointer = + NewJSNativePointer(new_buffer, PandaFreeBufferFunc, reinterpret_cast(size)); regexp->SetByteCodeBuffer(thread_, pointer.GetTaggedValue()); regexp->SetLength(thread_, JSTaggedValue(static_cast(size))); diff --git a/tests/runtime/common/gc/CMakeLists.txt b/tests/runtime/common/gc/CMakeLists.txt index d6903cef4..9372bd27f 100644 --- a/tests/runtime/common/gc/CMakeLists.txt +++ b/tests/runtime/common/gc/CMakeLists.txt @@ -139,6 +139,7 @@ panda_add_ecma_gc_test(FILE spaceTypeTest.js OPTIONS "--gc-type=g1-gc" "--run-gc panda_add_ecma_gc_test(FILE concurrent.js OPTIONS "--gc-type=g1-gc" "--gc-trigger-type=debug-never") panda_add_ecma_gc_test(FILE hclass_changing_during_concurrent.js OPTIONS "--gc-type=g1-gc" "--gc-trigger-type=debug-never" "--heap-verifier=fail_on_verification:post") panda_add_ecma_gc_test(FILE pinObject.js OPTIONS "--gc-type=g1-gc" "--gc-trigger-type=debug-never") +panda_add_ecma_gc_test(FILE registerNativeAllocation.js OPTIONS "--gc-trigger-type=debug-never") panda_add_ecma_gc_test(FILE copylexenvDynTest.js OPTIONS "--gc-type=g1-gc" "--gc-trigger-type=debug-never" "--gc-use-nth-alloc-trigger=true" "--heap-verifier=fail_on_verification:pre:into:post") panda_add_ecma_gc_test(FILE hclass_collected_before_object.js OPTIONS "--gc-type=g1-gc" "--gc-trigger-type=debug-never" "--g1-track-freed-objects=true") panda_add_ecma_gc_test(FILE write_prebarrier_primitive_value.js OPTIONS "--gc-type=g1-gc" "--gc-trigger-type=debug-never" "--g1-track-freed-objects=true") diff --git a/tests/runtime/common/gc/registerNativeAllocation.js b/tests/runtime/common/gc/registerNativeAllocation.js new file mode 100644 index 000000000..b32821515 --- /dev/null +++ b/tests/runtime/common/gc/registerNativeAllocation.js @@ -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. + */ + +/** + * Test that GC::RegisterNativeAllocation works well with ArrayBuffer. + */ + +// Allocating ArrayBuffers in a loop in order to try to exhaust the memory in internal space +for (var i = 0; i < 3000; i++) { + new ArrayBuffer(2048 * 2048); +} -- Gitee From eeb5bdfec42dd9cd1e922e0985694b9f9d0a0dc2 Mon Sep 17 00:00:00 2001 From: Malinin Andrey Date: Fri, 14 Jul 2023 13:13:16 +0300 Subject: [PATCH 2/2] Making AllocAndRegisterNative a template method Signed-off-by: Malinin Andrey --- runtime/object_factory.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/runtime/object_factory.cpp b/runtime/object_factory.cpp index 1123e6916..2a8f9baac 100644 --- a/runtime/object_factory.cpp +++ b/runtime/object_factory.cpp @@ -200,7 +200,7 @@ void ObjectFactory::NewJSArrayBufferData(const JSHandle &array, i JSTaggedValue data = array->GetArrayBufferData(); if (data != JSTaggedValue::Undefined()) { auto *pointer = JSNativePointer::Cast(data.GetTaggedObject()); - auto *new_data = vm_->GetHeapManager()->AllocAndRegisterNative(size); + auto *new_data = vm_->GetHeapManager()->AllocAndRegisterNative(size); if (memset_s(new_data, length, 0, length) != EOK) { LOG_ECMA(FATAL) << "memset_s failed"; UNREACHABLE(); @@ -209,7 +209,7 @@ void ObjectFactory::NewJSArrayBufferData(const JSHandle &array, i return; } - auto *new_data = vm_->GetHeapManager()->AllocAndRegisterNative(size); + auto *new_data = vm_->GetHeapManager()->AllocAndRegisterNative(size); if (memset_s(new_data, length, 0, length) != EOK) { LOG_ECMA(FATAL) << "memset_s failed"; UNREACHABLE(); @@ -229,7 +229,7 @@ JSHandle ObjectFactory::NewJSArrayBuffer(int32_t length) JSHandle array_buffer(NewJSObjectByConstructor(constructor, new_target)); array_buffer->SetArrayBufferByteLength(thread_, JSTaggedValue(length)); if (length > 0) { - auto *new_data = vm_->GetHeapManager()->AllocAndRegisterNative(length); + auto *new_data = vm_->GetHeapManager()->AllocAndRegisterNative(length); if (memset_s(new_data, length, 0, length) != EOK) { LOG_ECMA(FATAL) << "memset_s failed"; UNREACHABLE(); @@ -291,7 +291,7 @@ void ObjectFactory::NewJSRegExpByteCodeData(const JSHandle ®exp, vo return; } - auto *new_buffer = vm_->GetHeapManager()->AllocAndRegisterNative(size); + auto *new_buffer = vm_->GetHeapManager()->AllocAndRegisterNative(size); if (memcpy_s(new_buffer, size, buffer, size) != EOK) { LOG_ECMA(FATAL) << "memcpy_s failed"; UNREACHABLE(); -- Gitee