From 9f034b1314fdb851070f5a2253b1099c9eed1d84 Mon Sep 17 00:00:00 2001 From: xiongluo Date: Thu, 19 Sep 2024 18:49:45 +0800 Subject: [PATCH] enable shared full gc Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IAMN77?from=project-issue Signed-off-by: xiongluo Change-Id: I26a07b167f0d799d8f73f3b2fdbc78adbe16157a --- BUILD.gn | 1 + ecmascript/base/typed_array_helper.cpp | 2 +- ecmascript/builtins/builtins_ark_tools.cpp | 3 +- ecmascript/builtins/builtins_shared_array.cpp | 58 +-- ecmascript/builtins/builtins_shared_map.cpp | 14 +- ecmascript/builtins/builtins_shared_set.cpp | 10 +- .../builtins/builtins_shared_typedarray.cpp | 63 +-- .../builtins/tests/builtins_string_test.cpp | 14 +- ecmascript/common.h | 2 + .../compiler/new_object_stub_builder.cpp | 79 ++-- ecmascript/compiler/new_object_stub_builder.h | 10 +- ecmascript/daemon/daemon_thread.h | 2 +- ecmascript/ecma_context.cpp | 3 + ecmascript/ecma_context.h | 6 + ecmascript/ecma_string.cpp | 11 +- ecmascript/ecma_string.h | 2 +- ecmascript/ecma_vm.cpp | 11 +- ecmascript/ecma_vm.h | 4 +- ecmascript/jit/jit.h | 20 +- ecmascript/js_api/js_api_bitvector.cpp | 22 +- .../js_api/js_api_bitvector_iterator.cpp | 2 +- ecmascript/js_function.cpp | 16 +- ecmascript/js_function.h | 2 +- ecmascript/js_thread.cpp | 7 + ecmascript/js_thread.h | 1 + ecmascript/jspandafile/program_object.h | 2 +- ecmascript/mem/gc_stats.cpp | 6 +- ecmascript/mem/heap-inl.h | 53 ++- ecmascript/mem/heap.cpp | 207 +++++++-- ecmascript/mem/heap.h | 56 ++- ecmascript/mem/mem.h | 1 + ecmascript/mem/parallel_marker-inl.h | 1 - ecmascript/mem/region.h | 17 +- .../shared_heap/shared_concurrent_marker.cpp | 7 +- .../shared_heap/shared_concurrent_sweeper.cpp | 46 +- .../shared_heap/shared_concurrent_sweeper.h | 5 +- ecmascript/mem/shared_heap/shared_full_gc.cpp | 184 ++++++++ ecmascript/mem/shared_heap/shared_full_gc.h | 56 +++ ecmascript/mem/shared_heap/shared_gc.cpp | 11 +- .../mem/shared_heap/shared_gc_marker-inl.h | 166 +++++-- .../mem/shared_heap/shared_gc_marker.cpp | 88 +++- ecmascript/mem/shared_heap/shared_gc_marker.h | 84 +++- ecmascript/mem/shared_heap/shared_space.cpp | 146 ++++-- ecmascript/mem/shared_heap/shared_space.h | 62 ++- ecmascript/mem/space-inl.h | 5 + ecmascript/mem/space.cpp | 2 +- ecmascript/mem/space.h | 17 +- ecmascript/mem/tlab_allocator-inl.h | 36 ++ ecmascript/mem/tlab_allocator.h | 34 +- ecmascript/mem/verification.cpp | 27 ++ ecmascript/mem/work_manager.cpp | 27 +- ecmascript/mem/work_manager.h | 32 +- ecmascript/napi/jsnapi.cpp | 20 +- ecmascript/napi/jsnapi_expo.cpp | 438 ++++++++++++------ ecmascript/object_factory-inl.h | 2 +- ecmascript/object_factory.h | 2 + ecmascript/runtime.cpp | 3 + ecmascript/runtime.h | 16 +- ecmascript/runtime_lock.cpp | 4 + ecmascript/serializer/base_deserializer.cpp | 40 +- ecmascript/serializer/base_deserializer.h | 13 +- ecmascript/serializer/base_serializer.cpp | 5 +- ecmascript/serializer/base_serializer.h | 2 +- .../serializer/tests/serializer_test.cpp | 143 +----- ecmascript/serializer/value_serializer.cpp | 14 +- ecmascript/shared_object_factory.cpp | 26 +- .../shared_objects/concurrent_api_scope.h | 25 +- ecmascript/shared_objects/js_shared_array.cpp | 8 +- .../js_shared_array_iterator.cpp | 6 +- ecmascript/shared_objects/js_shared_map.cpp | 40 +- ecmascript/shared_objects/js_shared_map.h | 10 +- .../shared_objects/js_shared_map_iterator.cpp | 2 +- ecmascript/shared_objects/js_shared_set.cpp | 26 +- ecmascript/shared_objects/js_shared_set.h | 6 +- .../shared_objects/js_shared_set_iterator.cpp | 2 +- .../snapshot/mem/snapshot_processor.cpp | 4 +- ecmascript/taskpool/taskpool.h | 8 + ecmascript/tests/gc_first_test.cpp | 72 ++- ecmascript/tests/js_verification_test.cpp | 23 +- libark_jsruntime.map | 2 + 80 files changed, 1969 insertions(+), 736 deletions(-) create mode 100644 ecmascript/mem/shared_heap/shared_full_gc.cpp create mode 100644 ecmascript/mem/shared_heap/shared_full_gc.h diff --git a/BUILD.gn b/BUILD.gn index 2c7c0fbaee..4c4409f88b 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -839,6 +839,7 @@ ecma_source = [ "ecmascript/mem/shared_heap/shared_concurrent_marker.cpp", "ecmascript/mem/shared_heap/shared_concurrent_sweeper.cpp", "ecmascript/mem/shared_heap/shared_gc.cpp", + "ecmascript/mem/shared_heap/shared_full_gc.cpp", "ecmascript/mem/shared_heap/shared_gc_marker.cpp", "ecmascript/mem/shared_heap/shared_space.cpp", "ecmascript/mem/stw_young_gc.cpp", diff --git a/ecmascript/base/typed_array_helper.cpp b/ecmascript/base/typed_array_helper.cpp index e82fd0ec90..1fd90fb864 100644 --- a/ecmascript/base/typed_array_helper.cpp +++ b/ecmascript/base/typed_array_helper.cpp @@ -624,7 +624,7 @@ JSTaggedValue TypedArrayHelper::CreateSharedFromTypedArray(EcmaRuntimeCallInfo * if (allocateResult == JSTaggedValue::Exception()) { return allocateResult; } - JSTaggedValue checkResult = CheckBufferAndType(buffer, thread, obj, srcArray); + JSTaggedValue checkResult = CheckBufferAndType(srcData.GetTaggedValue(), thread, obj, srcArray); if (checkResult == JSTaggedValue::Exception()) { return checkResult; } diff --git a/ecmascript/builtins/builtins_ark_tools.cpp b/ecmascript/builtins/builtins_ark_tools.cpp index 640c275e5c..40c9a25c9f 100644 --- a/ecmascript/builtins/builtins_ark_tools.cpp +++ b/ecmascript/builtins/builtins_ark_tools.cpp @@ -217,7 +217,8 @@ JSTaggedValue BuiltinsArkTools::ForceFullGC(EcmaRuntimeCallInfo *info) auto heap = const_cast(info->GetThread()->GetEcmaVM()->GetHeap()); heap->CollectGarbage( TriggerGCType::FULL_GC, GCReason::EXTERNAL_TRIGGER); - SharedHeap::GetInstance()->CollectGarbage(info->GetThread()); + SharedHeap::GetInstance()->CollectGarbage( + info->GetThread()); heap->GetHeapPrepare(); return JSTaggedValue::True(); } diff --git a/ecmascript/builtins/builtins_shared_array.cpp b/ecmascript/builtins/builtins_shared_array.cpp index c0593271ac..da028cee7d 100644 --- a/ecmascript/builtins/builtins_shared_array.cpp +++ b/ecmascript/builtins/builtins_shared_array.cpp @@ -414,7 +414,7 @@ JSTaggedValue BuiltinsSharedArray::Concat(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle thisObjVal(thisObjHandle); @@ -529,7 +529,7 @@ JSTaggedValue BuiltinsSharedArray::Entries(EcmaRuntimeCallInfo *argv) // 1. Let O be ToObject(this value). // 2. ReturnIfAbrupt(O). JSHandle self = JSTaggedValue::ToObject(thread, GetThis(argv)); - [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 3. Return CreateArrayIterator(O, "key+value"). JSHandle iter(factory->NewJSSharedArrayIterator(self, IterationKind::KEY_AND_VALUE)); @@ -551,8 +551,7 @@ JSTaggedValue BuiltinsSharedArray::Fill(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisObjVal); - [[maybe_unused]] ConcurrentApiScope scope( - thread, thisObjHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisObjVal); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (thisObjVal->IsJSSharedArray()) { bool isDictionary = thisObjHandle->GetJSHClass()->IsDictionaryElement(); @@ -702,7 +701,7 @@ JSTaggedValue BuiltinsSharedArray::Filter(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); // 2. ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle thisObjVal(thisObjHandle); @@ -773,7 +772,7 @@ JSTaggedValue BuiltinsSharedArray::Find(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); // 2. ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle thisObjVal(thisObjHandle); @@ -840,7 +839,7 @@ JSTaggedValue BuiltinsSharedArray::FindIndex(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); // 2. ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle thisObjVal(thisObjHandle); @@ -915,7 +914,7 @@ JSTaggedValue BuiltinsSharedArray::ForEach(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); // 2. ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle thisObjVal(thisObjHandle); @@ -1059,7 +1058,7 @@ JSTaggedValue BuiltinsSharedArray::IndexOf(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The indexOf method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSTaggedValue opResult; if (thisHandle->IsStableJSArray(thread)) { @@ -1082,7 +1081,7 @@ JSTaggedValue BuiltinsSharedArray::Join(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The join method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); auto opResult = BuiltinsArray::Join(argv); return opResult; @@ -1099,7 +1098,7 @@ JSTaggedValue BuiltinsSharedArray::Keys(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The keys method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); auto opResult = BuiltinsArray::Keys(argv); return opResult; @@ -1191,7 +1190,7 @@ JSTaggedValue BuiltinsSharedArray::Map(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); // 2. ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle thisObjVal(thisObjHandle); @@ -1287,8 +1286,7 @@ JSTaggedValue BuiltinsSharedArray::Pop(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - [[maybe_unused]] ConcurrentApiScope scope( - thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSTaggedValue opResult = PopInner(argv, thisHandle, thisObjHandle); @@ -1360,8 +1358,7 @@ JSTaggedValue BuiltinsSharedArray::Push(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The push method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope( - thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (thisHandle->IsStableJSArray(thread)) { auto opResult = JSStableArray::Push(JSHandle::Cast(thisHandle), argv); @@ -1462,7 +1459,7 @@ JSTaggedValue BuiltinsSharedArray::Reduce(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); // 2. ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle thisObjVal(thisObjHandle); @@ -1541,8 +1538,7 @@ JSTaggedValue BuiltinsSharedArray::Shift(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - [[maybe_unused]] ConcurrentApiScope scope( - thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); // 2. ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (thisHandle->IsStableJSArray(thread) && JSObject::IsArrayLengthWritable(thread, thisObjHandle)) { @@ -1636,7 +1632,7 @@ JSTaggedValue BuiltinsSharedArray::Slice(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); // 2. ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle thisObjVal(thisObjHandle); @@ -1770,8 +1766,7 @@ JSTaggedValue BuiltinsSharedArray::Sort(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - [[maybe_unused]] ConcurrentApiScope scope( - thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // Array sort @@ -1801,7 +1796,7 @@ JSTaggedValue BuiltinsSharedArray::Splice(EcmaRuntimeCallInfo *argv) } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); [[maybe_unused]] ConcurrentApiScope scope( - thread, thisHandle.GetTaggedValue().GetTaggedObject()); + thread, thisHandle); // 2. ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle thisObjVal(thisObjHandle); @@ -2016,7 +2011,7 @@ JSTaggedValue BuiltinsSharedArray::ToString(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); // 2. ReturnIfAbrupt(array). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle thisObjVal(thisObjHandle); @@ -2064,8 +2059,7 @@ JSTaggedValue BuiltinsSharedArray::Unshift(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - [[maybe_unused]] ConcurrentApiScope scope( - thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); // 2. ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle thisObjVal(thisObjHandle); @@ -2164,7 +2158,7 @@ JSTaggedValue BuiltinsSharedArray::Values(EcmaRuntimeCallInfo *argv) // 1. Let O be ToObject(this value). // 2. ReturnIfAbrupt(O). JSHandle self = JSTaggedValue::ToObject(thread, GetThis(argv)); - [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 3. Return CreateArrayIterator(O, "value"). JSHandle iter(factory->NewJSSharedArrayIterator(self, IterationKind::VALUE)); @@ -2247,7 +2241,7 @@ JSTaggedValue BuiltinsSharedArray::Includes(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); uint32_t argc = argv->GetArgsNumber(); @@ -2322,7 +2316,7 @@ JSTaggedValue BuiltinsSharedArray::At(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The at method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (thisHandle->IsStableJSArray(thread)) { auto opResult = JSStableArray::At(JSHandle::Cast(thisHandle), argv); @@ -2383,8 +2377,7 @@ JSTaggedValue BuiltinsSharedArray::ShrinkTo(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - [[maybe_unused]] ConcurrentApiScope scope( - thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); JSHandle newLengthValue = GetCallArg(argv, 0); if (!newLengthValue->IsNumber()) { auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length."); @@ -2423,8 +2416,7 @@ JSTaggedValue BuiltinsSharedArray::ExtendTo(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); - [[maybe_unused]] ConcurrentApiScope scope( - thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); JSHandle newLengthValue = GetCallArg(argv, 0); if (!newLengthValue->IsNumber()) { auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length."); diff --git a/ecmascript/builtins/builtins_shared_map.cpp b/ecmascript/builtins/builtins_shared_map.cpp index 4a1eea3b82..6b299c01cd 100644 --- a/ecmascript/builtins/builtins_shared_map.cpp +++ b/ecmascript/builtins/builtins_shared_map.cpp @@ -131,9 +131,9 @@ JSTaggedValue BuiltinsSharedMap::Has(EcmaRuntimeCallInfo *argv) "The has method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - JSSharedMap *jsMap = JSSharedMap::Cast(self.GetTaggedValue().GetTaggedObject()); + JSHandle map(self); JSHandle key = GetCallArg(argv, 0); - bool flag = jsMap->Has(thread, key.GetTaggedValue()); + bool flag = JSSharedMap::Has(thread, map, key.GetTaggedValue()); return GetTaggedBoolean(flag); } @@ -148,9 +148,9 @@ JSTaggedValue BuiltinsSharedMap::Get(EcmaRuntimeCallInfo *argv) "The get method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - JSSharedMap *jsMap = JSSharedMap::Cast(self.GetTaggedValue().GetTaggedObject()); + JSHandle map(self); JSHandle key = GetCallArg(argv, 0); - JSTaggedValue value = jsMap->Get(thread, key.GetTaggedValue()); + JSTaggedValue value = JSSharedMap::Get(thread, map, key.GetTaggedValue()); return value; } @@ -165,7 +165,7 @@ JSTaggedValue BuiltinsSharedMap::ForEach(EcmaRuntimeCallInfo *argv) "The forEach method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, self.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, self); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); JSHandle map(self); JSHandle func(GetCallArg(argv, 0)); @@ -210,8 +210,8 @@ JSTaggedValue BuiltinsSharedMap::GetSize(EcmaRuntimeCallInfo *argv) if (!self->IsJSSharedMap()) { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not SharedMap", JSTaggedValue::Exception()); } - JSSharedMap *jsMap = JSSharedMap::Cast(self.GetTaggedValue().GetTaggedObject()); - uint32_t size = jsMap->GetSize(thread); + JSHandle map(self); + uint32_t size = JSSharedMap::GetSize(thread, map); return JSTaggedValue(size); } diff --git a/ecmascript/builtins/builtins_shared_set.cpp b/ecmascript/builtins/builtins_shared_set.cpp index 04541e9983..9587cd5065 100755 --- a/ecmascript/builtins/builtins_shared_set.cpp +++ b/ecmascript/builtins/builtins_shared_set.cpp @@ -172,9 +172,9 @@ JSTaggedValue BuiltinsSharedSet::Has(EcmaRuntimeCallInfo *argv) "The has method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - JSSharedSet* jsSet = JSSharedSet::Cast(self.GetTaggedValue().GetTaggedObject()); + JSHandle set(self); JSHandle value = GetCallArg(argv, 0); - bool flag = jsSet->Has(thread, value.GetTaggedValue()); + bool flag = JSSharedSet::Has(thread, set, value.GetTaggedValue()); return GetTaggedBoolean(flag); } @@ -189,7 +189,7 @@ JSTaggedValue BuiltinsSharedSet::ForEach(EcmaRuntimeCallInfo *argv) "The forEach method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, self.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, self); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); JSHandle set(self); @@ -233,8 +233,8 @@ JSTaggedValue BuiltinsSharedSet::GetSize(EcmaRuntimeCallInfo *argv) if (!self->IsJSSharedSet()) { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not SharedSet", JSTaggedValue::Exception()); } - JSSharedSet* jsSet = JSSharedSet::Cast(self.GetTaggedValue().GetTaggedObject()); - uint32_t size = jsSet->GetSize(thread); + JSHandle set(self); + uint32_t size = JSSharedSet::GetSize(thread, set); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue(0)); return JSTaggedValue(size); } diff --git a/ecmascript/builtins/builtins_shared_typedarray.cpp b/ecmascript/builtins/builtins_shared_typedarray.cpp index 4b33d257d2..cc8fbcd108 100755 --- a/ecmascript/builtins/builtins_shared_typedarray.cpp +++ b/ecmascript/builtins/builtins_shared_typedarray.cpp @@ -450,8 +450,7 @@ JSTaggedValue BuiltinsSharedTypedArray::CopyWithin(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The copyWithin method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope( - thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); return BuiltinsArray::CopyWithin(argv); } @@ -493,8 +492,7 @@ JSTaggedValue BuiltinsSharedTypedArray::Every(EcmaRuntimeCallInfo *argv) JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); // 2. ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - [[maybe_unused]] ConcurrentApiScope scope(thread, - thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); JSHandle thisObjVal(thisObjHandle); // 3. Let len be ToLength(Get(O, "length")). @@ -559,8 +557,7 @@ JSTaggedValue BuiltinsSharedTypedArray::Fill(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The fill method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope( - thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); return BuiltinsArray::Fill(argv); } @@ -590,8 +587,7 @@ JSTaggedValue BuiltinsSharedTypedArray::Filter(EcmaRuntimeCallInfo *argv) if (!callbackFnHandle->IsCallable()) { THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, - thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. JSHandle thisArgHandle = GetCallArg(argv, 1); @@ -665,8 +661,7 @@ JSTaggedValue BuiltinsSharedTypedArray::Find(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The find method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, - thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); return BuiltinsArray::Find(argv); } @@ -680,8 +675,7 @@ JSTaggedValue BuiltinsSharedTypedArray::FindIndex(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The findIndex method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, - thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); return BuiltinsArray::FindIndex(argv); } @@ -701,8 +695,7 @@ JSTaggedValue BuiltinsSharedTypedArray::ForEach(EcmaRuntimeCallInfo *argv) JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); // 2. ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - [[maybe_unused]] ConcurrentApiScope scope(thread, - thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); JSHandle thisObjVal(thisObjHandle); // 3. Let len be ToLength(Get(O, "length")). @@ -761,8 +754,7 @@ JSTaggedValue BuiltinsSharedTypedArray::IndexOf(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The indexOf method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, - thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); return BuiltinsArray::IndexOf(argv); } @@ -778,8 +770,7 @@ JSTaggedValue BuiltinsSharedTypedArray::Join(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The join method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, - thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); uint32_t length = JSHandle::Cast(thisHandle)->GetArrayLength(); JSHandle sepHandle = GetCallArg(argv, 0); @@ -934,8 +925,7 @@ JSTaggedValue BuiltinsSharedTypedArray::Map(EcmaRuntimeCallInfo *argv) } // 3. ReturnIfAbrupt(valid). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - [[maybe_unused]] ConcurrentApiScope scope(thread, - thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); JSHandle thisObj(thisHandle); // 4. Let len be the value of O’s [[ArrayLength]] internal slot. @@ -1000,8 +990,7 @@ JSTaggedValue BuiltinsSharedTypedArray::Reduce(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The reduce method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, - thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); return BuiltinsArray::Reduce(argv); } @@ -1021,8 +1010,7 @@ JSTaggedValue BuiltinsSharedTypedArray::Reverse(EcmaRuntimeCallInfo *argv) JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); // 2. ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - [[maybe_unused]] ConcurrentApiScope scope( - thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); JSHandle thisObjVal(thisObjHandle); // 3. Let len be O.[[ArrayLength]] @@ -1087,8 +1075,7 @@ JSTaggedValue BuiltinsSharedTypedArray::Set(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The set method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope( - thread, target.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, target); // 5. Assert: target has a [[ViewedArrayBuffer]] internal slot. // 6. Let targetOffset be ToInteger (offset). @@ -1343,8 +1330,7 @@ JSTaggedValue BuiltinsSharedTypedArray::Slice(EcmaRuntimeCallInfo *argv) // 3. ReturnIfAbrupt(valid). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - [[maybe_unused]] ConcurrentApiScope scope(thread, - thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); JSHandle thisObj(thisHandle); // 4. Let len be the value of O’s [[ArrayLength]] internal slot. @@ -1476,8 +1462,7 @@ JSTaggedValue BuiltinsSharedTypedArray::Some(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The some method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, - thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); return BuiltinsArray::Some(argv); } @@ -1497,8 +1482,7 @@ JSTaggedValue BuiltinsSharedTypedArray::Sort(EcmaRuntimeCallInfo *argv) JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - [[maybe_unused]] ConcurrentApiScope scope( - thread, thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); JSHandle thisObjVal(thisObjHandle); JSHandle buffer; @@ -1573,8 +1557,7 @@ JSTaggedValue BuiltinsSharedTypedArray::Subarray(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The subarray method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, - thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); // 4. Assert: O has a [[ViewedArrayBuffer]] internal slot. // 6. Let srcLength be the value of O’s [[ArrayLength]] internal slot. @@ -1654,8 +1637,7 @@ JSTaggedValue BuiltinsSharedTypedArray::ToLocaleString(EcmaRuntimeCallInfo *argv auto error = ContainerError::BindError(thread, "The toLocaleString method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, - thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); return BuiltinsArray::ToLocaleString(argv); } @@ -1669,8 +1651,7 @@ JSTaggedValue BuiltinsSharedTypedArray::ToString(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The toString method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, - thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); return BuiltinsArray::ToString(argv); } @@ -1737,8 +1718,7 @@ JSTaggedValue BuiltinsSharedTypedArray::At(EcmaRuntimeCallInfo *argv) JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); // ReturnIfAbrupt(O). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - [[maybe_unused]] ConcurrentApiScope scope(thread, - thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); // 3. Let len be O.[[ArrayLength]]. uint32_t len = JSHandle::Cast(thisObjHandle)->GetArrayLength(); @@ -1774,8 +1754,7 @@ JSTaggedValue BuiltinsSharedTypedArray::Includes(EcmaRuntimeCallInfo *argv) auto error = ContainerError::BindError(thread, "The includes method cannot be bound."); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } - [[maybe_unused]] ConcurrentApiScope scope(thread, - thisHandle.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle); return BuiltinsArray::Includes(argv); } } // namespace panda::ecmascript::builtins diff --git a/ecmascript/builtins/tests/builtins_string_test.cpp b/ecmascript/builtins/tests/builtins_string_test.cpp index 1c630f8e40..f7aca51ef3 100644 --- a/ecmascript/builtins/tests/builtins_string_test.cpp +++ b/ecmascript/builtins/tests/builtins_string_test.cpp @@ -944,7 +944,7 @@ HWTEST_F_L0(BuiltinsStringTest, Replace) JSHandle replaceStr1 = factory->NewFromASCII("abc$$"); JSHandle expected1 = factory->NewFromASCII("Twas the night before abc$..."); - + args[0] = searchStr.GetTaggedValue(); args[1] = replaceStr1.GetTaggedValue(); auto result1 = StringAlgorithm(thread, thisStr.GetTaggedValue(), args, 8, AlgorithmType::REPLACE); @@ -954,7 +954,7 @@ HWTEST_F_L0(BuiltinsStringTest, Replace) JSHandle replaceStr2 = factory->NewFromASCII("abc$$dd"); JSHandle expected2 = factory->NewFromASCII("Twas the night before abc$dd..."); - + args[0] = searchStr.GetTaggedValue(); args[1] = replaceStr2.GetTaggedValue(); auto result2 = StringAlgorithm(thread, thisStr.GetTaggedValue(), args, 8, AlgorithmType::REPLACE); @@ -964,7 +964,7 @@ HWTEST_F_L0(BuiltinsStringTest, Replace) JSHandle replaceStr3 = factory->NewFromASCII("abc$&dd"); JSHandle expected3 = factory->NewFromASCII("Twas the night before abcXmasdd..."); - + args[0] = searchStr.GetTaggedValue(); args[1] = replaceStr3.GetTaggedValue(); auto result3 = StringAlgorithm(thread, thisStr.GetTaggedValue(), args, 8, AlgorithmType::REPLACE); @@ -975,7 +975,7 @@ HWTEST_F_L0(BuiltinsStringTest, Replace) JSHandle replaceStr4 = factory->NewFromASCII("abc$`dd"); JSHandle expected4 = factory->NewFromASCII("Twas the night before abcTwas the night before dd..."); - + args[0] = searchStr.GetTaggedValue(); args[1] = replaceStr4.GetTaggedValue(); auto result4 = StringAlgorithm(thread, thisStr.GetTaggedValue(), args, 8, AlgorithmType::REPLACE); @@ -1001,7 +1001,7 @@ HWTEST_F_L0(BuiltinsStringTest, Replace2) JSHandle replaceStr2 = factory->NewFromASCII("abc$`dd$\'$ff"); JSHandle expected2 = factory->NewFromASCII("Twas the night before abcTwas the night before dd...$ff..."); - + args[0] = searchStr.GetTaggedValue(); args[1] = replaceStr2.GetTaggedValue(); auto result2 = StringAlgorithm(thread, thisStr.GetTaggedValue(), args, 8, AlgorithmType::REPLACE); @@ -1013,7 +1013,7 @@ HWTEST_F_L0(BuiltinsStringTest, Replace2) JSHandle replaceStr3 = factory->NewFromASCII("abc$`dd$\'$"); JSHandle expected3 = factory->NewFromASCII("Twas the night before abcTwas the night before dd...$..."); - + args[0] = searchStr.GetTaggedValue(); args[1] = replaceStr3.GetTaggedValue(); auto result3 = StringAlgorithm(thread, thisStr.GetTaggedValue(), args, 8, AlgorithmType::REPLACE); @@ -1024,7 +1024,7 @@ HWTEST_F_L0(BuiltinsStringTest, Replace2) JSHandle replaceStr4 = factory->NewFromASCII("abc$`dd$$"); JSHandle expected4 = factory->NewFromASCII("Twas the night before abcTwas the night before dd$..."); - + args[0] = searchStr.GetTaggedValue(); args[1] = replaceStr4.GetTaggedValue(); auto result4 = StringAlgorithm(thread, thisStr.GetTaggedValue(), args, 8, AlgorithmType::REPLACE); diff --git a/ecmascript/common.h b/ecmascript/common.h index 083cee779e..589285cfed 100644 --- a/ecmascript/common.h +++ b/ecmascript/common.h @@ -40,6 +40,8 @@ enum TriggerGCType { // GC is expected to compress objects into appspawn space; APPSPAWN_FULL_GC, SHARED_GC, + SHARED_FULL_GC, + APPSPAWN_SHARED_FULL_GC, GC_TYPE_LAST }; diff --git a/ecmascript/compiler/new_object_stub_builder.cpp b/ecmascript/compiler/new_object_stub_builder.cpp index 462a109797..a8f67d02fd 100644 --- a/ecmascript/compiler/new_object_stub_builder.cpp +++ b/ecmascript/compiler/new_object_stub_builder.cpp @@ -106,7 +106,7 @@ GateRef NewObjectStubBuilder::NewJSArrayWithSize(GateRef hclass, GateRef size) return result; } -void NewObjectStubBuilder::NewJSObject(Variable *result, Label *exit, GateRef hclass, MemoryAttribute mAttr) +void NewObjectStubBuilder::NewJSObject(Variable *result, Label *exit, GateRef hclass) { auto env = GetEnvironment(); @@ -117,11 +117,7 @@ void NewObjectStubBuilder::NewJSObject(Variable *result, Label *exit, GateRef hc AllocateInYoung(result, &hasPendingException, &noException, hclass); Bind(&noException); { - if (mAttr.Value() == MemoryAttribute::NoBarrier().Value()) { - StoreHClassWithoutBarrier(glue_, result->ReadVariable(), hclass); - } else { - StoreHClass(glue_, result->ReadVariable(), hclass); - } + StoreHClass(glue_, result->ReadVariable(), hclass); DEFVARIABLE(initValue, VariableType::JS_ANY(), Undefined()); Label isTS(env); Label initialize(env); @@ -136,7 +132,8 @@ void NewObjectStubBuilder::NewJSObject(Variable *result, Label *exit, GateRef hc Bind(&initialize); Label afterInitialize(env); InitializeWithSpeicalValue(&afterInitialize, - result->ReadVariable(), *initValue, Int32(JSObject::SIZE), ChangeIntPtrToInt32(size_), mAttr); + result->ReadVariable(), *initValue, Int32(JSObject::SIZE), ChangeIntPtrToInt32(size_), + MemoryAttribute::NoBarrier()); Bind(&afterInitialize); auto emptyArray = GetGlobalConstantValue( VariableType::JS_POINTER(), glue_, ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX); @@ -153,7 +150,7 @@ void NewObjectStubBuilder::NewJSObject(Variable *result, Label *exit, GateRef hc } } -void NewObjectStubBuilder::NewSObject(Variable *result, Label *exit, GateRef hclass, MemoryAttribute mAttr) +void NewObjectStubBuilder::NewSObject(Variable *result, Label *exit, GateRef hclass) { auto env = GetEnvironment(); @@ -162,11 +159,7 @@ void NewObjectStubBuilder::NewSObject(Variable *result, Label *exit, GateRef hcl AllocateInSOld(result, &afterAllocate, hclass); Bind(&afterAllocate); { - if (mAttr.Value() == MemoryAttribute::NoBarrier().Value()) { - StoreHClassWithoutBarrier(glue_, result->ReadVariable(), hclass); - } else { - StoreHClass(glue_, result->ReadVariable(), hclass); - } + StoreHClass(glue_, result->ReadVariable(), hclass); DEFVARIABLE(initValue, VariableType::JS_ANY(), Undefined()); Label isTS(env); Label initialize(env); @@ -181,7 +174,8 @@ void NewObjectStubBuilder::NewSObject(Variable *result, Label *exit, GateRef hcl Bind(&initialize); Label afterInitialize(env); InitializeWithSpeicalValue(&afterInitialize, - result->ReadVariable(), *initValue, Int32(JSObject::SIZE), ChangeIntPtrToInt32(size_), mAttr); + result->ReadVariable(), *initValue, Int32(JSObject::SIZE), ChangeIntPtrToInt32(size_), + MemoryAttribute::NoBarrier()); Bind(&afterInitialize); auto emptyArray = GetGlobalConstantValue( VariableType::JS_POINTER(), glue_, ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX); @@ -274,7 +268,8 @@ void NewObjectStubBuilder::NewJSObject(Variable *result, Label *exit, GateRef hc DEFVARIABLE(initValue, VariableType::JS_ANY(), Undefined()); Label afterInitialize(env); InitializeWithSpeicalValue(&afterInitialize, - result->ReadVariable(), *initValue, Int32(JSObject::SIZE), ChangeIntPtrToInt32(size_)); + result->ReadVariable(), *initValue, Int32(JSObject::SIZE), ChangeIntPtrToInt32(size_), + MemoryAttribute::NoBarrier()); Bind(&afterInitialize); auto emptyArray = GetGlobalConstantValue( VariableType::JS_POINTER(), glue_, ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX); @@ -286,7 +281,7 @@ void NewObjectStubBuilder::NewJSObject(Variable *result, Label *exit, GateRef hc Jump(exit); } -GateRef NewObjectStubBuilder::NewJSObject(GateRef glue, GateRef hclass, MemoryAttribute mAttr) +GateRef NewObjectStubBuilder::NewJSObject(GateRef glue, GateRef hclass) { auto env = GetEnvironment(); Label entry(env); @@ -295,7 +290,7 @@ GateRef NewObjectStubBuilder::NewJSObject(GateRef glue, GateRef hclass, MemoryAt DEFVARIABLE(result, VariableType::JS_ANY(), Undefined()); SetGlue(glue); - NewJSObject(&result, &exit, hclass, mAttr); + NewJSObject(&result, &exit, hclass); Bind(&exit); auto ret = *result; @@ -303,7 +298,7 @@ GateRef NewObjectStubBuilder::NewJSObject(GateRef glue, GateRef hclass, MemoryAt return ret; } -GateRef NewObjectStubBuilder::NewSObject(GateRef glue, GateRef hclass, MemoryAttribute mAttr) +GateRef NewObjectStubBuilder::NewSObject(GateRef glue, GateRef hclass) { auto env = GetEnvironment(); Label entry(env); @@ -312,7 +307,7 @@ GateRef NewObjectStubBuilder::NewSObject(GateRef glue, GateRef hclass, MemoryAtt DEFVARIABLE(result, VariableType::JS_ANY(), Undefined()); SetGlue(glue); - NewSObject(&result, &exit, hclass, mAttr); + NewSObject(&result, &exit, hclass); Bind(&exit); auto ret = *result; @@ -843,8 +838,6 @@ GateRef NewObjectStubBuilder::NewJSFunction(GateRef glue, GateRef constpool, Gat Bind(&afterAOTLiteral); GateRef method = GetMethodFromConstPool(glue, constpool, index); DEFVARIABLE(hclass, VariableType::JS_ANY(), Undefined()); - bool knownKind = JSFunction::IsNormalFunctionAndCanSkipWbWhenInitialization(targetKind); - Label isSendableFunc(env); Label isNotSendableFunc(env); Label afterSendableFunc(env); @@ -852,7 +845,7 @@ GateRef NewObjectStubBuilder::NewJSFunction(GateRef glue, GateRef constpool, Gat Bind(&isSendableFunc); { hclass = LoadSHClassFromMethod(glue, method); - result = NewSObject(glue, *hclass, knownKind ? MemoryAttribute::NoBarrier() : MemoryAttribute::Default()); + result = NewSObject(glue, *hclass); GateRef kind = GetFuncKind(method); InitializeSFunction(glue, *result, kind, targetKind); Jump(&afterSendableFunc); @@ -860,7 +853,7 @@ GateRef NewObjectStubBuilder::NewJSFunction(GateRef glue, GateRef constpool, Gat Bind(&isNotSendableFunc); { hclass = LoadHClassFromMethod(glue, method); - result = NewJSObject(glue, *hclass, knownKind ? MemoryAttribute::NoBarrier() : MemoryAttribute::Default()); + result = NewJSObject(glue, *hclass); SetExtensibleToBitfield(glue, *hclass, true); GateRef kind = GetFuncKind(method); InitializeJSFunction(glue, *result, kind, targetKind); @@ -868,7 +861,7 @@ GateRef NewObjectStubBuilder::NewJSFunction(GateRef glue, GateRef constpool, Gat } Bind(&afterSendableFunc); SetCallableToBitfield(glue, *hclass, true); - SetMethodToFunction(glue, *result, method, knownKind ? MemoryAttribute::NoBarrier() : MemoryAttribute::Default()); + SetMethodToFunction(glue, *result, method); SetCompiledCodeFlagToFunction(glue, *result, Int32(0)); SetMachineCodeToFunction(glue, *result, Undefined(), MemoryAttribute::NoBarrier()); @@ -924,27 +917,21 @@ void NewObjectStubBuilder::NewJSFunction(GateRef glue, GateRef jsFunc, GateRef i } Bind(¬Exception); { - bool knownKind = JSFunction::IsNormalFunctionAndCanSkipWbWhenInitialization(targetKind); GateRef module = GetModuleFromFunction(jsFunc); SetLengthToFunction(glue_, result->ReadVariable(), length); BRANCH(IsSendableFunction(GetMethodFromFunction(result->ReadVariable())), &isSendableFunc, &isNotSendableFunc); Bind(&isSendableFunc); { GateRef smodule = CallRuntime(glue, RTSTUB_ID(GetSharedModule), { module }); - SetSendableEnvToModule(glue, smodule, GetSendableEnvFromModule(module), - knownKind ? MemoryAttribute::NoBarrier() : MemoryAttribute::Default()); - SetModuleToFunction(glue, result->ReadVariable(), smodule, - knownKind ? MemoryAttribute::NoBarrier() : MemoryAttribute::Default()); + SetSendableEnvToModule(glue, smodule, GetSendableEnvFromModule(module)); + SetModuleToFunction(glue, result->ReadVariable(), smodule); Jump(&afterSendableFunc); } Bind(&isNotSendableFunc); { - SetLexicalEnvToFunction(glue_, result->ReadVariable(), lexEnv, - knownKind ? MemoryAttribute::NoBarrier() : MemoryAttribute::Default()); - SetModuleToFunction(glue_, result->ReadVariable(), module, - knownKind ? MemoryAttribute::NoBarrier() : MemoryAttribute::Default()); - SetHomeObjectToFunction(glue_, result->ReadVariable(), GetHomeObjectFromFunction(jsFunc), - knownKind ? MemoryAttribute::NoBarrier() : MemoryAttribute::Default()); + SetLexicalEnvToFunction(glue_, result->ReadVariable(), lexEnv); + SetModuleToFunction(glue_, result->ReadVariable(), module); + SetHomeObjectToFunction(glue_, result->ReadVariable(), GetHomeObjectFromFunction(jsFunc)); #if ECMASCRIPT_ENABLE_IC SetProfileTypeInfoCellToFunction(jsFunc, result->ReadVariable(), slotId); #endif @@ -1007,13 +994,11 @@ void NewObjectStubBuilder::InitializeSFunction(GateRef glue, GateRef func, GateR auto funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, ConstantIndex::FUNCTION_NAME_ACCESSOR); SetPropertyInlinedProps(glue, func, hclass, funcAccessor, Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX), - VariableType::JS_ANY(), - MemoryAttribute::NoBarrier()); + VariableType::JS_ANY(), MemoryAttribute::NoBarrier()); funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, ConstantIndex::FUNCTION_LENGTH_ACCESSOR); SetPropertyInlinedProps(glue, func, hclass, funcAccessor, Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX), - VariableType::JS_ANY(), - MemoryAttribute::NoBarrier()); + VariableType::JS_ANY(), MemoryAttribute::NoBarrier()); Jump(&exit); } } else { @@ -1109,13 +1094,11 @@ void NewObjectStubBuilder::InitializeJSFunction(GateRef glue, GateRef func, Gate auto funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, ConstantIndex::FUNCTION_NAME_ACCESSOR); SetPropertyInlinedProps(glue, func, hclass, funcAccessor, Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX), - VariableType::JS_ANY(), - MemoryAttribute::NoBarrier()); + VariableType::JS_ANY(), MemoryAttribute::NoBarrier()); funcAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, ConstantIndex::FUNCTION_LENGTH_ACCESSOR); SetPropertyInlinedProps(glue, func, hclass, funcAccessor, Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX), - VariableType::JS_ANY(), - MemoryAttribute::NoBarrier()); + VariableType::JS_ANY(), MemoryAttribute::NoBarrier()); Jump(&exit); } } else { @@ -1206,11 +1189,13 @@ GateRef NewObjectStubBuilder::NewJSBoundFunction(GateRef glue, GateRef target, G GateRef nameAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, ConstantIndex::FUNCTION_NAME_ACCESSOR); SetPropertyInlinedProps(glue, *result, hclass, nameAccessor, - Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX)); + Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX), VariableType::JS_ANY(), + MemoryAttribute::NoBarrier()); GateRef lengthAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, ConstantIndex::FUNCTION_LENGTH_ACCESSOR); SetPropertyInlinedProps(glue, *result, hclass, lengthAccessor, - Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX)); + Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX), VariableType::JS_ANY(), + MemoryAttribute::NoBarrier()); SetJSObjectTaggedField(glue, *result, JSBoundFunction::BOUND_TARGET_OFFSET, target); SetJSObjectTaggedField(glue, *result, JSBoundFunction::BOUND_THIS_OFFSET, boundThis); SetJSObjectTaggedField(glue, *result, JSBoundFunction::BOUND_ARGUMENTS_OFFSET, args); @@ -1396,7 +1381,7 @@ void NewObjectStubBuilder::NewJSArrayLiteral(Variable *result, Label *exit, Regi Bind(&initializeArray); Store(VariableType::JS_POINTER(), glue_, result->ReadVariable(), IntPtr(0), hclass); InitializeWithSpeicalValue(&afterInitialize, result->ReadVariable(), Undefined(), Int32(JSArray::SIZE), - TruncInt64ToInt32(size_)); + TruncInt64ToInt32(size_), MemoryAttribute::NoBarrier()); Bind(&afterInitialize); GateRef hashOffset = IntPtr(ECMAObject::HASH_OFFSET); Store(VariableType::INT64(), glue_, result->ReadVariable(), hashOffset, Int64(JSTaggedValue(0).GetRawData())); @@ -1423,7 +1408,7 @@ void NewObjectStubBuilder::NewJSArrayLiteral(Variable *result, Label *exit, Regi auto accessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::ARRAY_LENGTH_ACCESSOR); SetPropertyInlinedProps(glue_, result->ReadVariable(), hclass, accessor, - Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX), VariableType::JS_POINTER()); + Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX), VariableType::JS_POINTER(), MemoryAttribute::NoBarrier()); Jump(exit); } diff --git a/ecmascript/compiler/new_object_stub_builder.h b/ecmascript/compiler/new_object_stub_builder.h index c1a047343a..0408b65b07 100644 --- a/ecmascript/compiler/new_object_stub_builder.h +++ b/ecmascript/compiler/new_object_stub_builder.h @@ -52,12 +52,10 @@ public: void NewLexicalEnv(Variable *result, Label *exit, GateRef numSlots, GateRef parent); void NewJSObject(Variable *result, Label *exit, GateRef hclass, GateRef size); - void NewJSObject(Variable *result, Label *exit, GateRef hclass, - MemoryAttribute mAttr = MemoryAttribute::Default()); - void NewSObject(Variable *result, Label *exit, GateRef hclass, - MemoryAttribute mAttr = MemoryAttribute::Default()); - GateRef NewJSObject(GateRef glue, GateRef hclass, MemoryAttribute mAttr = MemoryAttribute::Default()); - GateRef NewSObject(GateRef glue, GateRef hclass, MemoryAttribute mAttr = MemoryAttribute::Default()); + void NewJSObject(Variable *result, Label *exit, GateRef hclass); + void NewSObject(Variable *result, Label *exit, GateRef hclass); + GateRef NewJSObject(GateRef glue, GateRef hclass); + GateRef NewSObject(GateRef glue, GateRef hclass); GateRef NewJSProxy(GateRef glue, GateRef target, GateRef handler); GateRef NewJSArray(GateRef glue, GateRef hclass); GateRef NewTaggedArray(GateRef glue, GateRef len); diff --git a/ecmascript/daemon/daemon_thread.h b/ecmascript/daemon/daemon_thread.h index a37bb5b662..8f6eb00b8f 100644 --- a/ecmascript/daemon/daemon_thread.h +++ b/ecmascript/daemon/daemon_thread.h @@ -32,7 +32,7 @@ static constexpr uint32_t DAEMON_THREAD_INDEX = 0; class DaemonThread : public JSThread { public: static void CreateNewInstance(); - static DaemonThread *GetInstance(); + static DaemonThread *PUBLIC_API GetInstance(); static void DestroyInstance(); using ThreadId = uint32_t; diff --git a/ecmascript/ecma_context.cpp b/ecmascript/ecma_context.cpp index 0b25e35b49..9fc5e729af 100644 --- a/ecmascript/ecma_context.cpp +++ b/ecmascript/ecma_context.cpp @@ -959,6 +959,9 @@ void EcmaContext::Iterate(const RootVisitor &v, const RootRangeVisitor &rv) if (propertiesCache_ != nullptr) { propertiesCache_->Clear(); } + if (regExpParserCache_ != nullptr) { + regExpParserCache_->Clear(); + } if (!vm_->GetJSOptions().EnableGlobalLeakCheck() && currentHandleStorageIndex_ != -1) { // IterateHandle when disableGlobalLeakCheck. int32_t nid = currentHandleStorageIndex_; diff --git a/ecmascript/ecma_context.h b/ecmascript/ecma_context.h index 26a7700a8c..9a4f72db05 100644 --- a/ecmascript/ecma_context.h +++ b/ecmascript/ecma_context.h @@ -629,6 +629,12 @@ public: { return hasKeptObjects_; } + + void ClearCachedConstantPool() + { + cachedSharedConstpools_.clear(); + } + private: void CJSExecution(JSHandle &func, JSHandle &thisArg, const JSPandaFile *jsPandaFile, std::string_view entryPoint); diff --git a/ecmascript/ecma_string.cpp b/ecmascript/ecma_string.cpp index ff30141264..43a8bf1c8a 100755 --- a/ecmascript/ecma_string.cpp +++ b/ecmascript/ecma_string.cpp @@ -1015,7 +1015,7 @@ EcmaString *EcmaString::ToLower(const EcmaVM *vm, const JSHandle &sr std::string res = base::StringHelper::ToLower(u16str); return *(factory->NewFromStdString(res)); } else { - return ConvertUtf8ToLowerOrUpper(vm, src, true, srcFlat); + return ConvertUtf8ToLowerOrUpper(vm, src, true); } } @@ -1037,7 +1037,7 @@ EcmaString *EcmaString::TryToLower(const EcmaVM *vm, const JSHandle if (upperIndex == srcLength) { return *src; } - return ConvertUtf8ToLowerOrUpper(vm, src, true, srcFlat, upperIndex); + return ConvertUtf8ToLowerOrUpper(vm, src, true, upperIndex); } /* static */ @@ -1058,17 +1058,18 @@ EcmaString *EcmaString::TryToUpper(const EcmaVM *vm, const JSHandle if (lowerIndex == srcLength) { return *src; } - return ConvertUtf8ToLowerOrUpper(vm, src, false, srcFlat, lowerIndex); + return ConvertUtf8ToLowerOrUpper(vm, src, false, lowerIndex); } /* static */ EcmaString *EcmaString::ConvertUtf8ToLowerOrUpper(const EcmaVM *vm, const JSHandle &src, - bool toLower, FlatStringInfo &srcFlat, uint32_t startIndex) + bool toLower, uint32_t startIndex) { const char start = toLower ? 'A' : 'a'; const char end = toLower ? 'Z' : 'z'; uint32_t srcLength = src->GetLength(); JSHandle newString(vm->GetJSThread(), CreateLineString(vm, srcLength, true)); + auto srcFlat = FlattenAllString(vm, src); Span data(srcFlat.GetDataUtf8Writable(), srcLength); auto newStringPtr = newString->GetDataUtf8Writable(); if (startIndex > 0) { @@ -1098,7 +1099,7 @@ EcmaString *EcmaString::ToUpper(const EcmaVM *vm, const JSHandle &sr std::string res = base::StringHelper::ToUpper(u16str); return *(factory->NewFromStdString(res)); } else { - return ConvertUtf8ToLowerOrUpper(vm, src, false, srcFlat); + return ConvertUtf8ToLowerOrUpper(vm, src, false); } } diff --git a/ecmascript/ecma_string.h b/ecmascript/ecma_string.h index 97636a7244..89de29e85e 100755 --- a/ecmascript/ecma_string.h +++ b/ecmascript/ecma_string.h @@ -750,7 +750,7 @@ private: static EcmaString *TryToUpper(const EcmaVM *vm, const JSHandle &src); static EcmaString *ConvertUtf8ToLowerOrUpper(const EcmaVM *vm, const JSHandle &src, - bool toLower, FlatStringInfo &srcFlat, uint32_t startIndex = 0); + bool toLower, uint32_t startIndex = 0); }; // The LineEcmaString abstract class captures sequential string values, only LineEcmaString can store chars data diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp index 104db7e5bb..f60d6e3029 100644 --- a/ecmascript/ecma_vm.cpp +++ b/ecmascript/ecma_vm.cpp @@ -161,7 +161,10 @@ void EcmaVM::PreFork() heap_->GetReadOnlySpace()->SetReadOnly(); heap_->DisableParallelGC(); SetPostForked(false); - SharedHeap::GetInstance()->DisableParallelGC(thread_); + + auto sHeap = SharedHeap::GetInstance(); + sHeap->CompactHeapBeforeFork(thread_); + sHeap->DisableParallelGC(thread_); } void EcmaVM::PostFork() @@ -593,6 +596,9 @@ void EcmaVM::ProcessSharedNativeDelete(const WeakRootVisitor &visitor) std::make_pair(object->GetDeleter(), std::make_pair(object->GetExternalPointer(), object->GetData()))); sharedIter = sharedNativePointerList_.erase(sharedIter); } else { + if (fwd != reinterpret_cast(object)) { + *sharedIter = reinterpret_cast(fwd); + } ++sharedIter; } } @@ -600,9 +606,6 @@ void EcmaVM::ProcessSharedNativeDelete(const WeakRootVisitor &visitor) void EcmaVM::ProcessReferences(const WeakRootVisitor &visitor) { - if (thread_->GetCurrentEcmaContext()->GetRegExpParserCache() != nullptr) { - thread_->GetCurrentEcmaContext()->GetRegExpParserCache()->Clear(); - } // process native ref should be limited to OldGC or FullGC only if (!heap_->IsGeneralYoungGC()) { heap_->ResetNativeBindingSize(); diff --git a/ecmascript/ecma_vm.h b/ecmascript/ecma_vm.h index 64469ebe24..2bf834e5ca 100644 --- a/ecmascript/ecma_vm.h +++ b/ecmascript/ecma_vm.h @@ -195,13 +195,13 @@ public: return const_cast(vm); } - void CheckThread() const + void PUBLIC_API CheckThread() const { // Exclude GC thread if (thread_ == nullptr) { LOG_FULL(FATAL) << "Fatal: ecma_vm has been destructed! vm address is: " << this; } - if (!Taskpool::GetCurrentTaskpool()->IsInThreadPool(std::this_thread::get_id()) && + if (!Taskpool::GetCurrentTaskpool()->IsDaemonThreadOrInThreadPool(std::this_thread::get_id()) && thread_->GetThreadId() != JSThread::GetCurrentThreadId() && !thread_->IsCrossThreadExecutionEnable()) { LOG_FULL(FATAL) << "Fatal: ecma_vm cannot run in multi-thread!" << " thread:" << thread_->GetThreadId() diff --git a/ecmascript/jit/jit.h b/ecmascript/jit/jit.h index e719015f86..b6148fdd8f 100644 --- a/ecmascript/jit/jit.h +++ b/ecmascript/jit/jit.h @@ -193,18 +193,28 @@ public: { ASSERT(!thread->IsJitThread()); if (Jit::GetInstance()->IsEnableFastJit() || Jit::GetInstance()->IsEnableBaselineJit()) { - Clock::time_point start = Clock::now(); - thread_->GetJitLock()->Lock(); - Jit::GetInstance()->GetJitDfx()->SetLockHoldingTime( - std::chrono::duration_cast(Clock::now() - start).count()); + LockJit(thread_); locked_ = true; } } + static void LockJit(JSThread *thread) + { + Clock::time_point start = Clock::now(); + thread->GetJitLock()->Lock(); + Jit::GetInstance()->GetJitDfx()->SetLockHoldingTime( + std::chrono::duration_cast(Clock::now() - start).count()); + } + + static void UnlockJit(JSThread *thread) + { + thread->GetJitLock()->Unlock(); + } + ~JitGCLockHolder() { if (locked_) { - thread_->GetJitLock()->Unlock(); + UnlockJit(thread_); locked_ = false; } } diff --git a/ecmascript/js_api/js_api_bitvector.cpp b/ecmascript/js_api/js_api_bitvector.cpp index 52a866e928..5548bef22f 100644 --- a/ecmascript/js_api/js_api_bitvector.cpp +++ b/ecmascript/js_api/js_api_bitvector.cpp @@ -33,7 +33,7 @@ bool JSAPIBitVector::Push( JSThread* thread, const JSHandle& bitVector, const JSHandle& value) { [[maybe_unused]] ConcurrentApiScope scope(thread, - bitVector.GetTaggedValue().GetTaggedObject()); + JSHandle::Cast(bitVector)); uint32_t length = bitVector->GetLength(); JSHandle np(thread, bitVector->GetNativePointer()); auto elements = reinterpret_cast>*>(np->GetExternalPointer()); @@ -53,7 +53,7 @@ bool JSAPIBitVector::Push( JSTaggedValue JSAPIBitVector::Pop(JSThread* thread, const JSHandle& bitVector) { [[maybe_unused]] ConcurrentApiScope scope(thread, - bitVector.GetTaggedValue().GetTaggedObject()); + JSHandle::Cast(bitVector)); uint32_t lastIndex = bitVector->GetLength() - 1; if (lastIndex < 0) { return JSTaggedValue::Undefined(); @@ -164,7 +164,7 @@ JSTaggedValue JSAPIBitVector::SetBitsByRange(JSThread* thread, const JSHandle& value, const JSHandle& start, const JSHandle& end) { [[maybe_unused]] ConcurrentApiScope scope(thread, - bitVector.GetTaggedValue().GetTaggedObject()); + JSHandle::Cast(bitVector)); int32_t startIndex = JSTaggedValue::ToInt32(thread, start); int32_t endIndex = JSTaggedValue::ToInt32(thread, end); int32_t length = bitVector->GetLength(); @@ -196,7 +196,7 @@ JSTaggedValue JSAPIBitVector::GetBitsByRange(JSThread* thread, const JSHandle& start, const JSHandle& end) { [[maybe_unused]] ConcurrentApiScope scope(thread, - bitVector.GetTaggedValue().GetTaggedObject()); + JSHandle::Cast(bitVector)); int32_t startIndex = JSTaggedValue::ToInt32(thread, start); int32_t endIndex = JSTaggedValue::ToInt32(thread, end); int32_t length = bitVector->GetLength(); @@ -238,7 +238,7 @@ JSTaggedValue JSAPIBitVector::SetAllBits( JSThread* thread, const JSHandle& bitVector, const JSHandle& value) { [[maybe_unused]] ConcurrentApiScope scope(thread, - bitVector.GetTaggedValue().GetTaggedObject()); + JSHandle::Cast(bitVector)); JSHandle np(thread, bitVector->GetNativePointer()); auto elements = reinterpret_cast>*>(np->GetExternalPointer()); int size = static_cast(elements->size()); @@ -257,7 +257,7 @@ JSTaggedValue JSAPIBitVector::SetAllBits( JSTaggedValue JSAPIBitVector::GetBitCountByRange(JSThread* thread, const JSHandle& bitVector, const JSHandle& value, const JSHandle& start, const JSHandle& end) { - [[maybe_unused]] ConcurrentApiScope scope(thread, bitVector.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, JSHandle::Cast(bitVector)); int32_t startIndex = JSTaggedValue::ToInt32(thread, start); int32_t endIndex = JSTaggedValue::ToInt32(thread, end); int32_t length = bitVector->GetLength(); @@ -294,7 +294,7 @@ JSTaggedValue JSAPIBitVector::GetBitCountByRange(JSThread* thread, const JSHandl int JSAPIBitVector::GetIndexOf(JSThread* thread, const JSHandle& bitVector, const JSHandle& value, const JSHandle& start, const JSHandle& end) { - [[maybe_unused]] ConcurrentApiScope scope(thread, bitVector.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, JSHandle::Cast(bitVector)); int32_t startIndex = JSTaggedValue::ToInt32(thread, start); int32_t endIndex = JSTaggedValue::ToInt32(thread, end); int32_t length = bitVector->GetLength(); @@ -330,7 +330,7 @@ int JSAPIBitVector::GetIndexOf(JSThread* thread, const JSHandle& int JSAPIBitVector::GetLastIndexOf(JSThread* thread, const JSHandle& bitVector, const JSHandle& value, const JSHandle& start, const JSHandle& end) { - [[maybe_unused]] ConcurrentApiScope scope(thread, bitVector.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, JSHandle::Cast(bitVector)); int32_t startIndex = JSTaggedValue::ToInt32(thread, start); int32_t endIndex = JSTaggedValue::ToInt32(thread, end); int32_t length = bitVector->GetLength(); @@ -366,7 +366,7 @@ int JSAPIBitVector::GetLastIndexOf(JSThread* thread, const JSHandle& bitVector, int index) { [[maybe_unused]] ConcurrentApiScope scope(thread, - bitVector.GetTaggedValue().GetTaggedObject()); + JSHandle::Cast(bitVector)); if (index >= bitVector->GetLength()) { std::ostringstream oss; oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (bitVector->GetLength() - 1) @@ -389,7 +389,7 @@ JSTaggedValue JSAPIBitVector::FlipBitsByRange(JSThread* thread, const JSHandle& start, const JSHandle& end) { [[maybe_unused]] ConcurrentApiScope scope(thread, - bitVector.GetTaggedValue().GetTaggedObject()); + JSHandle::Cast(bitVector)); int32_t startIndex = JSTaggedValue::ToInt32(thread, start); int32_t endIndex = JSTaggedValue::ToInt32(thread, end); int32_t length = bitVector->GetLength(); @@ -428,7 +428,7 @@ void JSAPIBitVector::Resize(JSThread* thread, const JSHandle& bi THROW_NEW_ERROR_AND_RETURN(thread, error); } [[maybe_unused]] ConcurrentApiScope scope(thread, - bitVector.GetTaggedValue().GetTaggedObject()); + JSHandle::Cast(bitVector)); int length = bitVector->GetLength(); uint32_t elementsLength = ((length - 1) / BIT_SET_LENGTH) + 1; uint32_t newElementsLength = ((newSize - 1) / BIT_SET_LENGTH) + 1; diff --git a/ecmascript/js_api/js_api_bitvector_iterator.cpp b/ecmascript/js_api/js_api_bitvector_iterator.cpp index 7f982ee3a1..40a3effd0b 100644 --- a/ecmascript/js_api/js_api_bitvector_iterator.cpp +++ b/ecmascript/js_api/js_api_bitvector_iterator.cpp @@ -47,7 +47,7 @@ JSTaggedValue JSAPIBitVectorIterator::Next(EcmaRuntimeCallInfo* argv) // If a has a [[TypedBitVectorName]] internal slot, then // Let len be the value of O’s [[BitVectorLength]] internal slot. ASSERT(bitVector->IsJSAPIBitVector()); - [[maybe_unused]] ConcurrentApiScope scope(thread, bitVector.GetTaggedValue().GetTaggedObject()); + [[maybe_unused]] ConcurrentApiScope scope(thread, bitVector); const uint32_t length = static_cast(JSHandle::Cast(bitVector)->GetSize()); // If index >= len, then if (index >= length) { diff --git a/ecmascript/js_function.cpp b/ecmascript/js_function.cpp index 438040b3fa..3030e856bd 100644 --- a/ecmascript/js_function.cpp +++ b/ecmascript/js_function.cpp @@ -1113,12 +1113,12 @@ JSTaggedValue JSFunction::GetNativeFunctionExtraInfo() const return JSTaggedValue::Undefined(); } -void JSFunction::InitializeForConcurrentFunction(JSThread *thread) +void JSFunction::InitializeForConcurrentFunction(JSThread *thread, JSHandle &func) { - JSHandle method(thread, this->GetMethod()); - JSTaggedValue sendableEnv = JSTaggedValue::Undefined(); - if (this->IsSharedFunction() && !this->GetModule().IsUndefined()) { - sendableEnv = SourceTextModule::Cast(this->GetModule())->GetSendableEnv(); + JSHandle method(thread, func->GetMethod()); + JSMutableHandle sendableEnv(thread, JSTaggedValue::Undefined()); + if (func->IsSharedFunction() && !func->GetModule().IsUndefined()) { + sendableEnv.Update(SourceTextModule::Cast(func->GetModule())->GetSendableEnv()); } const JSPandaFile *jsPandaFile = method->GetJSPandaFile(); if (jsPandaFile == nullptr) { @@ -1155,12 +1155,12 @@ void JSFunction::InitializeForConcurrentFunction(JSThread *thread) JSHandle module = JSHandle::Cast(moduleRecord); module->SetStatus(ecmascript::ModuleStatus::INSTANTIATED); ecmascript::SourceTextModule::EvaluateForConcurrent(thread, module, method); - if (this->IsSharedFunction()) { + if (func->IsSharedFunction()) { JSHandle sendableClassRecord = moduleManager->GenerateSendableFuncModule(moduleRecord); SourceTextModule::Cast(sendableClassRecord.GetTaggedValue())->SetSendableEnv(thread, sendableEnv); - this->SetModule(thread, sendableClassRecord); + func->SetModule(thread, sendableClassRecord); } else { - this->SetModule(thread, moduleRecord); + func->SetModule(thread, moduleRecord); } // for debugger, to notify the script loaded and parsed which the concurrent function is in diff --git a/ecmascript/js_function.h b/ecmascript/js_function.h index d838f27c4c..73477c0ab5 100644 --- a/ecmascript/js_function.h +++ b/ecmascript/js_function.h @@ -334,7 +334,7 @@ public: void SetJitCompiledFuncEntry(JSThread *thread, JSHandle &machineCode, bool isFastCall); - void InitializeForConcurrentFunction(JSThread *thread); + static void InitializeForConcurrentFunction(JSThread *thread, JSHandle &func); bool IsSendableOrConcurrentFunction() const; bool IsSharedFunction() const; diff --git a/ecmascript/js_thread.cpp b/ecmascript/js_thread.cpp index 95a57c6faa..686583e154 100644 --- a/ecmascript/js_thread.cpp +++ b/ecmascript/js_thread.cpp @@ -1048,6 +1048,13 @@ bool JSThread::EraseContext(EcmaContext *context) return false; } +void JSThread::ClearContextCachedConstantPool() +{ + for (EcmaContext *context : contexts_) { + context->ClearCachedConstantPool(); + } +} + PropertiesCache *JSThread::GetPropertiesCache() const { return glueData_.currentContext_->GetPropertiesCache(); diff --git a/ecmascript/js_thread.h b/ecmascript/js_thread.h index eaef1831ad..89bb51571f 100644 --- a/ecmascript/js_thread.h +++ b/ecmascript/js_thread.h @@ -1309,6 +1309,7 @@ public: bool IsPropertyCacheCleared() const; bool EraseContext(EcmaContext *context); + void ClearContextCachedConstantPool(); const GlobalEnvConstants *GetFirstGlobalConst() const; bool IsAllContextsInitialized() const; diff --git a/ecmascript/jspandafile/program_object.h b/ecmascript/jspandafile/program_object.h index afa2691565..909643431c 100644 --- a/ecmascript/jspandafile/program_object.h +++ b/ecmascript/jspandafile/program_object.h @@ -524,7 +524,7 @@ public: JSHandle method = factory->NewSMethod( jsPandaFile, methodLiteral, constpoolHandle, entryIndex, isLoadedAOT && hasEntryIndex); - CASSetObjectToCache(thread, constpool, index, method.GetTaggedValue()); + CASSetObjectToCache(thread, constpoolHandle.GetTaggedValue(), index, method.GetTaggedValue()); return method.GetTaggedValue(); } diff --git a/ecmascript/mem/gc_stats.cpp b/ecmascript/mem/gc_stats.cpp index 0418c9db68..73a0ed9fbb 100644 --- a/ecmascript/mem/gc_stats.cpp +++ b/ecmascript/mem/gc_stats.cpp @@ -753,7 +753,11 @@ void SharedGCStats::PrintGCMemoryStatistic() << "SharedHugeObjectSpace used:" << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetHugeObjectSpace()->GetHeapObjectSize())) << "KB" << " committed:" - << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetHugeObjectSpace()->GetCommittedSize())) << "KB\n"; + << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetHugeObjectSpace()->GetCommittedSize())) << "KB\n" + << "SharedAppSpawnSpace used:" + << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetAppSpawnSpace()->GetHeapObjectSize())) << "KB" + << " committed:" + << STATS_DATA_FORMAT(sizeToKB(sHeap_->GetAppSpawnSpace()->GetCommittedSize())) << "KB"; LOG_GC(INFO) << STATS_DESCRIPTION_FORMAT("Anno memory usage size:") << STATS_DATA_FORMAT(sizeToMB(heapRegionAllocator->GetAnnoMemoryUsage())) << "MB\n" diff --git a/ecmascript/mem/heap-inl.h b/ecmascript/mem/heap-inl.h index 098f284777..93573d812d 100644 --- a/ecmascript/mem/heap-inl.h +++ b/ecmascript/mem/heap-inl.h @@ -78,6 +78,7 @@ void SharedHeap::EnumerateOldSpaceRegions(const Callback &cb) const sOldSpace_->EnumerateRegions(cb); sNonMovableSpace_->EnumerateRegions(cb); sHugeObjectSpace_->EnumerateRegions(cb); + sAppSpawnSpace_->EnumerateRegions(cb); } template @@ -94,6 +95,7 @@ void SharedHeap::IterateOverObjects(const Callback &cb) const sOldSpace_->IterateOverObjects(cb); sNonMovableSpace_->IterateOverObjects(cb); sHugeObjectSpace_->IterateOverObjects(cb); + sAppSpawnSpace_->IterateOverMarkedObjects(cb); } template @@ -275,6 +277,11 @@ bool Heap::InHeapProfiler() #endif } +void SharedHeap::MergeToOldSpaceSync(SharedLocalSpace *localSpace) +{ + sOldSpace_->Merge(localSpace); +} + TaggedObject *Heap::TryAllocateYoungGeneration(JSHClass *hclass, size_t size) { size = AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT)); @@ -606,6 +613,17 @@ void Heap::SwapOldSpace() #endif } +void SharedHeap::SwapOldSpace() +{ + sCompressSpace_->SetInitialCapacity(sOldSpace_->GetInitialCapacity()); + auto *oldSpace = sCompressSpace_; + sCompressSpace_ = sOldSpace_; + sOldSpace_ = oldSpace; +#ifdef ECMASCRIPT_SUPPORT_HEAPSAMPLING + sOldSpace_->SwapAllocationCounter(sCompressSpace_); +#endif +} + void Heap::ReclaimRegions(TriggerGCType gcType) { activeSemiSpace_->EnumerateRegionsWithRecord([] (Region *region) { @@ -756,12 +774,14 @@ void SharedHeap::CollectGarbageFinish(bool inDaemon) // so do not need lock. smartGCStats_.forceGC_ = false; } + localFullMarkTriggered_ = false; // Record alive object size after shared gc NotifyHeapAliveSizeAfterGC(GetHeapObjectSize()); // Adjust shared gc trigger threshold AdjustGlobalSpaceAllocLimit(); GetEcmaGCStats()->RecordStatisticAfterGC(); GetEcmaGCStats()->PrintGCStatistic(); + ProcessAllGCListeners(); } TaggedObject *SharedHeap::AllocateNonMovableOrHugeObject(JSThread *thread, JSHClass *hclass) @@ -828,7 +848,7 @@ TaggedObject *SharedHeap::AllocateOldOrHugeObject(JSThread *thread, JSHClass *hc TaggedObject *object = thread->IsJitThread() ? nullptr : const_cast(thread->GetEcmaVM()->GetHeap())->AllocateSharedOldSpaceFromTlab(thread, size); if (object == nullptr) { - object = reinterpret_cast(sOldSpace_->Allocate(thread, size)); + object = AllocateInSOldSpace(thread, size); CHECK_SOBJ_AND_THROW_OOM_ERROR(thread, object, size, sOldSpace_, "SharedHeap::AllocateOldOrHugeObject"); object->SetClass(thread, hclass); TryTriggerConcurrentMarking(thread); @@ -850,13 +870,38 @@ TaggedObject *SharedHeap::AllocateOldOrHugeObject(JSThread *thread, size_t size) TaggedObject *object = thread->IsJitThread() ? nullptr : const_cast(thread->GetEcmaVM()->GetHeap())->AllocateSharedOldSpaceFromTlab(thread, size); if (object == nullptr) { - object = reinterpret_cast(sOldSpace_->Allocate(thread, size)); + object = AllocateInSOldSpace(thread, size); CHECK_SOBJ_AND_THROW_OOM_ERROR(thread, object, size, sOldSpace_, "SharedHeap::AllocateOldOrHugeObject"); TryTriggerConcurrentMarking(thread); } return object; } +TaggedObject *SharedHeap::AllocateInSOldSpace(JSThread *thread, size_t size) +{ + // jit thread no heap + bool allowGC = !thread->IsJitThread(); + if (allowGC) { + auto localHeap = const_cast(thread->GetEcmaVM()->GetHeap()); + localHeap->TryTriggerFullMarkBySharedSize(size); + } + TaggedObject *object = reinterpret_cast(sOldSpace_->TryAllocateAndExpand(thread, size, false)); + // Check whether it is necessary to trigger Shared GC before expanding to avoid OOM risk. + if (object == nullptr) { + if (allowGC) { + CheckAndTriggerSharedGC(thread); + } + object = reinterpret_cast(sOldSpace_->TryAllocateAndExpand(thread, size, true)); + if (object == nullptr) { + if (allowGC) { + CollectGarbage(thread); + } + object = reinterpret_cast(sOldSpace_->TryAllocateAndExpand(thread, size, true)); + } + } + return object; +} + TaggedObject *SharedHeap::AllocateHugeObject(JSThread *thread, JSHClass *hclass, size_t size) { auto object = AllocateHugeObject(thread, size); @@ -919,7 +964,7 @@ TaggedObject *SharedHeap::AllocateSOldTlab(JSThread *thread, size_t size) if (sOldSpace_->GetCommittedSize() > sOldSpace_->GetInitialCapacity() / 2) { // 2: half object = reinterpret_cast(sOldSpace_->AllocateNoGCAndExpand(thread, size)); } else { - object = reinterpret_cast(sOldSpace_->Allocate(thread, size)); + object = AllocateInSOldSpace(thread, size); } return object; } @@ -951,7 +996,7 @@ void SharedHeap::TriggerConcurrentMarking(JSThread *thread) template void SharedHeap::CollectGarbage(JSThread *thread) { - ASSERT(gcType == TriggerGCType::SHARED_GC); + ASSERT(gcType == TriggerGCType::SHARED_GC || gcType == TriggerGCType::SHARED_FULL_GC); #ifndef NDEBUG ASSERT(!thread->HasLaunchedSuspendAll()); #endif diff --git a/ecmascript/mem/heap.cpp b/ecmascript/mem/heap.cpp index ae39e3ed71..d4fe9c863b 100644 --- a/ecmascript/mem/heap.cpp +++ b/ecmascript/mem/heap.cpp @@ -20,6 +20,10 @@ #include "ecmascript/base/block_hook_scope.h" #include "ecmascript/checkpoint/thread_state_transition.h" +#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) +#include "ecmascript/dfx/cpu_profiler/cpu_profiler.h" +#endif +#include "ecmascript/daemon/daemon_thread.h" #include "ecmascript/ecma_string_table.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/free_object.h" @@ -40,6 +44,7 @@ #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/shared_heap/shared_full_gc.h" #include "ecmascript/mem/shared_heap/shared_concurrent_marker.h" #include "ecmascript/mem/stw_young_gc.h" #include "ecmascript/mem/verification.h" @@ -102,17 +107,31 @@ void SharedHeap::DestroyInstance() void SharedHeap::ForceCollectGarbageWithoutDaemonThread(TriggerGCType gcType, GCReason gcReason, JSThread *thread) { - ASSERT(gcType == TriggerGCType::SHARED_GC); ASSERT(!dThread_->IsRunning()); SuspendAllScope scope(thread); + SharedGCScope sharedGCScope; // SharedGCScope should be after SuspendAllScope. RecursionScope recurScope(this, HeapType::SHARED_HEAP); GetEcmaGCStats()->RecordStatisticBeforeGC(gcType, gcReason); if (UNLIKELY(ShouldVerifyHeap())) { // pre gc heap verify LOG_ECMA(DEBUG) << "pre gc shared heap verify"; + sharedGCMarker_->MergeBackAndResetRSetWorkListHandler(); SharedHeapVerification(this, VerifyKind::VERIFY_PRE_SHARED_GC).VerifyAll(); } - sharedGC_->RunPhases(); + switch (gcType) { + case TriggerGCType::SHARED_GC: { + sharedGC_->RunPhases(); + break; + } + case TriggerGCType::SHARED_FULL_GC: { + sharedFullGC_->RunPhases(); + break; + } + default: + LOG_ECMA(FATAL) << "this branch is unreachable"; + UNREACHABLE(); + break; + } if (UNLIKELY(ShouldVerifyHeap())) { // pre gc heap verify LOG_ECMA(DEBUG) << "after gc shared heap verify"; @@ -197,8 +216,10 @@ void SharedHeap::Initialize(NativeAreaAllocator *nativeAreaAllocator, HeapRegion TRIGGER_SHARED_CONCURRENT_MARKING_OBJECT_LIMIT_RATE); sOldSpace_ = new SharedOldSpace(this, oldSpaceCapacity, oldSpaceCapacity); + sCompressSpace_ = new SharedOldSpace(this, oldSpaceCapacity, oldSpaceCapacity); sReadOnlySpace_ = new SharedReadOnlySpace(this, readOnlySpaceCapacity, readOnlySpaceCapacity); sHugeObjectSpace_ = new SharedHugeObjectSpace(this, heapRegionAllocator_, oldSpaceCapacity, oldSpaceCapacity); + sAppSpawnSpace_ = new SharedAppSpawnSpace(this, oldSpaceCapacity); growingFactor_ = config_.GetSharedHeapLimitGrowingFactor(); growingStep_ = config_.GetSharedHeapLimitGrowingStep(); incNativeSizeTriggerSharedCM_= config_.GetStepNativeSizeInc(); @@ -217,6 +238,11 @@ void SharedHeap::Destroy() delete sOldSpace_; sOldSpace_ = nullptr; } + if (sCompressSpace_ != nullptr) { + sCompressSpace_->Reset(); + delete sCompressSpace_; + sCompressSpace_ = nullptr; + } if (sNonMovableSpace_ != nullptr) { sNonMovableSpace_->Reset(); delete sNonMovableSpace_; @@ -233,10 +259,19 @@ void SharedHeap::Destroy() delete sReadOnlySpace_; sReadOnlySpace_ = nullptr; } + if (sAppSpawnSpace_ != nullptr) { + sAppSpawnSpace_->Reset(); + delete sAppSpawnSpace_; + sAppSpawnSpace_ = nullptr; + } if (sharedGC_ != nullptr) { delete sharedGC_; sharedGC_ = nullptr; } + if (sharedFullGC_ != nullptr) { + delete sharedFullGC_; + sharedFullGC_ = nullptr; + } nativeAreaAllocator_ = nullptr; heapRegionAllocator_ = nullptr; @@ -253,7 +288,10 @@ void SharedHeap::Destroy() delete sharedGCMarker_; sharedGCMarker_ = nullptr; } - + if (sharedGCMovableMarker_ != nullptr) { + delete sharedGCMovableMarker_; + sharedGCMovableMarker_ = nullptr; + } dThread_ = nullptr; } @@ -264,31 +302,43 @@ void SharedHeap::PostInitialization(const GlobalEnvConstants *globalEnvConstants maxMarkTaskCount_ = totalThreadNum - 1; sWorkManager_ = new SharedGCWorkManager(this, totalThreadNum + 1); sharedGCMarker_ = new SharedGCMarker(sWorkManager_); + sharedGCMovableMarker_ = new SharedGCMovableMarker(sWorkManager_, this); sConcurrentMarker_ = new SharedConcurrentMarker(option.EnableSharedConcurrentMark() ? EnableConcurrentMarkType::ENABLE : EnableConcurrentMarkType::CONFIG_DISABLE); sSweeper_ = new SharedConcurrentSweeper(this, option.EnableConcurrentSweep() ? EnableConcurrentSweepType::ENABLE : EnableConcurrentSweepType::CONFIG_DISABLE); sharedGC_ = new SharedGC(this); + sharedFullGC_ = new SharedFullGC(this); } -void SharedHeap::PostGCMarkingTask() +void SharedHeap::PostGCMarkingTask(SharedParallelMarkPhase sharedTaskPhase) { IncreaseTaskCount(); - Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique(dThread_->GetThreadId(), this)); + Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique(dThread_->GetThreadId(), + this, sharedTaskPhase)); } 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); + switch (taskPhase_) { + case SharedParallelMarkPhase::SHARED_MARK_TASK: + sHeap_->GetSharedGCMarker()->ProcessMarkStack(threadIndex); + break; + case SharedParallelMarkPhase::SHARED_COMPRESS_TASK: + sHeap_->GetSharedGCMovableMarker()->ProcessMarkStack(threadIndex); + break; + default: + break; + } sHeap_->ReduceTaskCount(); return true; } bool SharedHeap::AsyncClearTask::Run([[maybe_unused]] uint32_t threadIndex) { - sHeap_->ReclaimRegions(); + sHeap_->ReclaimRegions(gcType_); return true; } @@ -324,21 +374,37 @@ void SharedHeap::WaitGCFinishedAfterAllJSThreadEliminated() void SharedHeap::DaemonCollectGarbage([[maybe_unused]]TriggerGCType gcType, [[maybe_unused]]GCReason gcReason) { RecursionScope recurScope(this, HeapType::SHARED_HEAP); - ASSERT(gcType == TriggerGCType::SHARED_GC); + ASSERT(gcType == TriggerGCType::SHARED_GC || gcType == TriggerGCType::SHARED_FULL_GC); ASSERT(JSThread::GetCurrent() == dThread_); { ThreadManagedScope runningScope(dThread_); SuspendAllScope scope(dThread_); + SharedGCScope sharedGCScope; // SharedGCScope should be after SuspendAllScope. gcType_ = gcType; GetEcmaGCStats()->RecordStatisticBeforeGC(gcType, gcReason); if (UNLIKELY(ShouldVerifyHeap())) { // pre gc heap verify LOG_ECMA(DEBUG) << "pre gc shared heap verify"; + sharedGCMarker_->MergeBackAndResetRSetWorkListHandler(); SharedHeapVerification(this, VerifyKind::VERIFY_PRE_SHARED_GC).VerifyAll(); } - sharedGC_->RunPhases(); + switch (gcType) { + case TriggerGCType::SHARED_GC: { + sharedGC_->RunPhases(); + break; + } + case TriggerGCType::SHARED_FULL_GC: { + sharedFullGC_->RunPhases(); + break; + } + default: + LOG_ECMA(FATAL) << "this branch is unreachable"; + UNREACHABLE(); + break; + } + if (UNLIKELY(ShouldVerifyHeap())) { - // pre gc heap verify + // after gc heap verify LOG_ECMA(DEBUG) << "after gc shared heap verify"; SharedHeapVerification(this, VerifyKind::VERIFY_POST_SHARED_GC).VerifyAll(); } @@ -382,6 +448,34 @@ void SharedHeap::Prepare(bool inTriggerGCThread) WaitClearTaskFinished(); } +SharedHeap::SharedGCScope::SharedGCScope() +{ + Runtime::GetInstance()->GCIterateThreadList([](JSThread *thread) { + std::shared_ptr pgoProfiler = thread->GetEcmaVM()->GetPGOProfiler(); + if (pgoProfiler != nullptr) { + pgoProfiler->SuspendByGC(); + } +#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) + thread->SetGcState(true); +#endif + }); +} + +SharedHeap::SharedGCScope::~SharedGCScope() +{ + Runtime::GetInstance()->GCIterateThreadList([](JSThread *thread) { + ASSERT(!thread->IsInRunningState()); + const_cast(thread->GetEcmaVM()->GetHeap())->ProcessGCListeners(); + std::shared_ptr pgoProfiler = thread->GetEcmaVM()->GetPGOProfiler(); + if (pgoProfiler != nullptr) { + pgoProfiler->ResumeByGC(); + } +#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) + thread->SetGcState(false); +#endif + }); +} + void SharedHeap::PrepareRecordRegionsForReclaim() { sOldSpace_->SetRecordRegion(); @@ -389,23 +483,25 @@ void SharedHeap::PrepareRecordRegionsForReclaim() sHugeObjectSpace_->SetRecordRegion(); } -void SharedHeap::Reclaim() +void SharedHeap::Reclaim(TriggerGCType gcType) { PrepareRecordRegionsForReclaim(); sHugeObjectSpace_->ReclaimHugeRegion(); + if (parallelGC_) { clearTaskFinished_ = false; Taskpool::GetCurrentTaskpool()->PostTask( - std::make_unique(dThread_->GetThreadId(), this)); + std::make_unique(dThread_->GetThreadId(), this, gcType)); } else { - ReclaimRegions(); + ReclaimRegions(gcType); } } -void SharedHeap::ReclaimRegions() +void SharedHeap::ReclaimRegions(TriggerGCType gcType) { - sOldSpace_->ReclaimRegions(); - sNonMovableSpace_->ReclaimRegions(); + if (gcType == TriggerGCType::SHARED_FULL_GC) { + sCompressSpace_->Reset(); + } sSweeper_->WaitAllTaskFinished(); EnumerateOldSpaceRegionsWithRecord([] (Region *region) { region->ClearMarkGCBitset(); @@ -449,24 +545,24 @@ void SharedHeap::UpdateWorkManager(SharedGCWorkManager *sWorkManager) { sConcurrentMarker_->ResetWorkManager(sWorkManager); sharedGCMarker_->ResetWorkManager(sWorkManager); + sharedGCMovableMarker_->ResetWorkManager(sWorkManager); sharedGC_->ResetWorkManager(sWorkManager); + sharedFullGC_->ResetWorkManager(sWorkManager); } -void SharedHeap::TryTriggerLocalConcurrentMarking(JSThread *thread) +void SharedHeap::TryTriggerLocalConcurrentMarking() { if (localFullMarkTriggered_) { return; } - { - SuspendAllScope scope(thread); - if (!localFullMarkTriggered_) { - localFullMarkTriggered_ = true; - Runtime::GetInstance()->GCIterateThreadList([](JSThread *thread) { - ASSERT(!thread->IsInRunningState()); - thread->SetFullMarkRequest(); - }); - } + if (reinterpret_cast*>(&localFullMarkTriggered_)->exchange(true, std::memory_order_relaxed) + != false) { + return; } + ASSERT(localFullMarkTriggered_ == true); + Runtime::GetInstance()->GCIterateThreadList([](JSThread *thread) { + thread->SetFullMarkRequest(); + }); } size_t SharedHeap::VerifyHeapObjects(VerifyKind verifyKind) const @@ -484,6 +580,10 @@ size_t SharedHeap::VerifyHeapObjects(VerifyKind verifyKind) const VerifyObjectVisitor verifier(this, &failCount, verifyKind); sHugeObjectSpace_->IterateOverObjects(verifier); } + { + VerifyObjectVisitor verifier(this, &failCount, verifyKind); + sAppSpawnSpace_->IterateOverMarkedObjects(verifier); + } return failCount; } @@ -499,6 +599,50 @@ bool SharedHeap::NeedStopCollection() return false; } +void SharedHeap::CompactHeapBeforeFork(JSThread *thread) +{ + ThreadManagedScope managedScope(thread); + WaitGCFinished(thread); + sharedFullGC_->SetForAppSpawn(true); + CollectGarbage(thread); + sharedFullGC_->SetForAppSpawn(false); +} + +void SharedHeap::MoveOldSpaceToAppspawn() +{ + auto committedSize = sOldSpace_->GetCommittedSize(); + sAppSpawnSpace_->SetInitialCapacity(committedSize); + sAppSpawnSpace_->SetMaximumCapacity(committedSize); + sOldSpace_->SetInitialCapacity(sOldSpace_->GetInitialCapacity() - committedSize); + sOldSpace_->SetMaximumCapacity(sOldSpace_->GetMaximumCapacity() - committedSize); +#ifdef ECMASCRIPT_SUPPORT_HEAPSAMPLING + sAppSpawnSpace_->SwapAllocationCounter(sOldSpace_); +#endif + auto threadId = Runtime::GetInstance()->GetMainThread()->GetThreadId(); + sOldSpace_->EnumerateRegions([&](Region *region) { + region->SetRegionSpaceFlag(RegionSpaceFlag::IN_SHARED_APPSPAWN_SPACE); + PageTag(region, region->GetCapacity(), PageTagType::HEAP, region->GetSpaceTypeName(), threadId); + sAppSpawnSpace_->AddRegion(region); + sAppSpawnSpace_->IncreaseLiveObjectSize(region->AliveObject()); + }); + sOldSpace_->GetRegionList().Clear(); + sOldSpace_->Reset(); +} + +void SharedHeap::ReclaimForAppSpawn() +{ + sSweeper_->WaitAllTaskFinished(); + sHugeObjectSpace_->ReclaimHugeRegion(); + sCompressSpace_->Reset(); + MoveOldSpaceToAppspawn(); + auto cb = [] (Region *region) { + region->ClearMarkGCBitset(); + region->ResetAliveObject(); + }; + sNonMovableSpace_->EnumerateRegions(cb); + sHugeObjectSpace_->EnumerateRegions(cb); +} + void SharedHeap::DumpHeapSnapshotBeforeOOM([[maybe_unused]]bool isFullGC, [[maybe_unused]]JSThread *thread) { #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) @@ -953,6 +1097,7 @@ void Heap::CollectGarbage(TriggerGCType gcType, GCReason reason) if (UNLIKELY(ShouldVerifyHeap())) { // pre gc heap verify LOG_ECMA(DEBUG) << "pre gc heap verify"; + ProcessSharedGCRSetWorkList(); Verification(this, VerifyKind::VERIFY_PRE_GC).VerifyAll(); } @@ -1922,7 +2067,7 @@ void Heap::ChangeGCParams(bool inBackground) if (sHeap_->GetHeapObjectSize() - sHeap_->GetHeapAliveSizeAfterGC() > BACKGROUND_GROW_LIMIT && sHeap_->GetCommittedSize() >= MIN_BACKGROUNG_GC_LIMIT && doubleOne * sHeap_->GetHeapObjectSize() / sHeap_->GetCommittedSize() <= MIN_OBJECT_SURVIVAL_RATE) { - sHeap_->CollectGarbage(thread_); + sHeap_->CollectGarbage(thread_); } if (GetMemGrowingType() != MemGrowingType::PRESSURE) { SetMemGrowingType(MemGrowingType::CONSERVATIVE); @@ -2418,6 +2563,14 @@ void Heap::ProcessGCListeners() } } +void SharedHeap::ProcessAllGCListeners() +{ + Runtime::GetInstance()->GCIterateThreadList([](JSThread *thread) { + ASSERT(!thread->IsInRunningState()); + const_cast(thread->GetEcmaVM()->GetHeap())->ProcessGCListeners(); + }); +} + #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) && defined(PANDA_TARGET_OHOS) && defined(ENABLE_HISYSEVENT) uint64_t Heap::GetCurrentTickMillseconds() { diff --git a/ecmascript/mem/heap.h b/ecmascript/mem/heap.h index 86e83b0ea4..13746a5489 100644 --- a/ecmascript/mem/heap.h +++ b/ecmascript/mem/heap.h @@ -53,7 +53,10 @@ class RSetWorkListHandler; class SharedConcurrentMarker; class SharedConcurrentSweeper; class SharedGC; +class SharedGCMarkerBase; class SharedGCMarker; +class SharedFullGC; +class SharedGCMovableMarker; class STWYoungGC; class ThreadLocalAllocationBuffer; class IdleGCTrigger; @@ -110,6 +113,7 @@ enum class VerifyKind { VERIFY_POST_SHARED_GC, VERIFY_SHARED_GC_MARK, VERIFY_SHARED_GC_SWEEP, + VERIFY_END, }; class BaseHeap { @@ -392,8 +396,8 @@ public: class ParallelMarkTask : public Task { public: - ParallelMarkTask(int32_t id, SharedHeap *heap) - : Task(id), sHeap_(heap) {}; + ParallelMarkTask(int32_t id, SharedHeap *heap, SharedParallelMarkPhase taskPhase) + : Task(id), sHeap_(heap), taskPhase_(taskPhase) {}; ~ParallelMarkTask() override = default; bool Run(uint32_t threadIndex) override; @@ -402,12 +406,13 @@ public: private: SharedHeap *sHeap_ {nullptr}; + SharedParallelMarkPhase taskPhase_; }; class AsyncClearTask : public Task { public: - AsyncClearTask(int32_t id, SharedHeap *heap) - : Task(id), sHeap_(heap) {} + AsyncClearTask(int32_t id, SharedHeap *heap, TriggerGCType type) + : Task(id), sHeap_(heap), gcType_(type) {} ~AsyncClearTask() override = default; bool Run(uint32_t threadIndex) override; @@ -415,6 +420,7 @@ public: NO_MOVE_SEMANTIC(AsyncClearTask); private: SharedHeap *sHeap_; + TriggerGCType gcType_; }; bool IsMarking() const override { @@ -483,7 +489,7 @@ public: bool CheckHugeAndTriggerSharedGC(JSThread *thread, size_t size); - void TryTriggerLocalConcurrentMarking(JSThread *currentThread); + void TryTriggerLocalConcurrentMarking(); // Called when all vm is destroyed, and try to destroy daemon thread. void WaitAllTasksFinishedAfterAllJSThreadEliminated(); @@ -557,6 +563,11 @@ public: return sReadOnlySpace_; } + SharedAppSpawnSpace *GetAppSpawnSpace() const + { + return sAppSpawnSpace_; + } + void SetForceGC(bool forceGC) { LockHolder lock(smartGCStats_.sensitiveStatusMutex_); @@ -678,8 +689,10 @@ public: } void Prepare(bool inTriggerGCThread); - void Reclaim(); - void PostGCMarkingTask(); + void Reclaim(TriggerGCType gcType); + void PostGCMarkingTask(SharedParallelMarkPhase sharedTaskPhase); + void CompactHeapBeforeFork(JSThread *thread); + void ReclaimForAppSpawn(); SharedGCWorkManager *GetWorkManager() const { @@ -691,6 +704,12 @@ public: return sharedGCMarker_; } + SharedGCMovableMarker *GetSharedGCMovableMarker() const + { + return sharedGCMovableMarker_; + } + inline void SwapOldSpace(); + void PrepareRecordRegionsForReclaim(); template @@ -730,15 +749,26 @@ public: size_t VerifyHeapObjects(VerifyKind verifyKind) const; + inline void MergeToOldSpaceSync(SharedLocalSpace *localSpace); + void DumpHeapSnapshotBeforeOOM(bool isFullGC, JSThread *thread); + + class SharedGCScope { + public: + SharedGCScope(); + ~SharedGCScope(); + }; + private: - + void ProcessAllGCListeners(); inline void CollectGarbageFinish(bool inDaemon); + + void MoveOldSpaceToAppspawn(); - void ReclaimRegions(); + void ReclaimRegions(TriggerGCType type); void ForceCollectGarbageWithoutDaemonThread(TriggerGCType gcType, GCReason gcReason, JSThread *thread); - + inline TaggedObject *AllocateInSOldSpace(JSThread *thread, size_t size); struct SharedHeapSmartGCStats { /** * For SmartGC. @@ -775,14 +805,18 @@ private: DaemonThread *dThread_ {nullptr}; const GlobalEnvConstants *globalEnvConstants_ {nullptr}; SharedOldSpace *sOldSpace_ {nullptr}; + SharedOldSpace *sCompressSpace_ {nullptr}; SharedNonMovableSpace *sNonMovableSpace_ {nullptr}; SharedReadOnlySpace *sReadOnlySpace_ {nullptr}; SharedHugeObjectSpace *sHugeObjectSpace_ {nullptr}; + SharedAppSpawnSpace *sAppSpawnSpace_ {nullptr}; SharedGCWorkManager *sWorkManager_ {nullptr}; SharedConcurrentMarker *sConcurrentMarker_ {nullptr}; SharedConcurrentSweeper *sSweeper_ {nullptr}; SharedGC *sharedGC_ {nullptr}; + SharedFullGC *sharedFullGC_ {nullptr}; SharedGCMarker *sharedGCMarker_ {nullptr}; + SharedGCMovableMarker *sharedGCMovableMarker_ {nullptr}; size_t growingFactor_ {0}; size_t growingStep_ {0}; size_t incNativeSizeTriggerSharedCM_ {0}; @@ -1435,6 +1469,7 @@ public: PUBLIC_API GCListenerId AddGCListener(FinishGCListener listener, void *data); PUBLIC_API void RemoveGCListener(GCListenerId listenerId); + void ProcessGCListeners(); private: inline TaggedObject *AllocateHugeObject(size_t size); @@ -1456,7 +1491,6 @@ private: void PrepareRecordRegionsForReclaim(); inline void ReclaimRegions(TriggerGCType gcType); inline size_t CalculateCommittedCacheSize(); - void ProcessGCListeners(); #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) && defined(PANDA_TARGET_OHOS) && defined(ENABLE_HISYSEVENT) uint64_t GetCurrentTickMillseconds(); void ThresholdReachedDump(); diff --git a/ecmascript/mem/mem.h b/ecmascript/mem/mem.h index 5b86afa5cc..c2f2644493 100644 --- a/ecmascript/mem/mem.h +++ b/ecmascript/mem/mem.h @@ -97,6 +97,7 @@ static constexpr size_t IDLE_SPACE_SIZE_MIN_INC_STEP_FULL = 1_MB; using TaggedType = uint64_t; static constexpr uint32_t TAGGED_TYPE_SIZE = sizeof(TaggedType); static constexpr uint32_t TAGGED_TYPE_SIZE_LOG = base::MathHelper::GetIntLog2(TAGGED_TYPE_SIZE); +constexpr size_t HEAD_SIZE = TaggedObject::TaggedObjectSize(); template constexpr inline bool IsAligned(T value, size_t alignment) diff --git a/ecmascript/mem/parallel_marker-inl.h b/ecmascript/mem/parallel_marker-inl.h index 113f039543..ab58effe0d 100644 --- a/ecmascript/mem/parallel_marker-inl.h +++ b/ecmascript/mem/parallel_marker-inl.h @@ -25,7 +25,6 @@ #include "ecmascript/mem/tlab_allocator-inl.h" namespace panda::ecmascript { -constexpr size_t HEAD_SIZE = TaggedObject::TaggedObjectSize(); template ARK_INLINE bool NonMovableMarker::VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, diff --git a/ecmascript/mem/region.h b/ecmascript/mem/region.h index b531351877..7d40c26d51 100644 --- a/ecmascript/mem/region.h +++ b/ecmascript/mem/region.h @@ -51,8 +51,10 @@ enum RegionSpaceFlag { IN_HUGE_MACHINE_CODE_SPACE = 0x11, IN_SHARED_NON_MOVABLE = 0x12, IN_SHARED_OLD_SPACE = 0x13, - IN_SHARED_HUGE_OBJECT_SPACE = 0x14, - IN_SHARED_READ_ONLY_SPACE = 0x15, + IN_SHARED_APPSPAWN_SPACE = 0X14, + IN_SHARED_HUGE_OBJECT_SPACE = 0x15, + IN_SHARED_READ_ONLY_SPACE = 0x16, + VALID_SPACE_MASK = 0xFF, GENERAL_YOUNG_BEGIN = IN_EDEN_SPACE, @@ -135,6 +137,8 @@ static inline std::string ToSpaceTypeName(uint8_t space) return "shared read only space"; case RegionSpaceFlag::IN_SHARED_HUGE_OBJECT_SPACE: return "shared huge object space"; + case RegionSpaceFlag::IN_SHARED_APPSPAWN_SPACE: + return "shared appspawn space"; default: return "invalid space"; } @@ -356,6 +360,10 @@ public: uint8_t GetRegionSpaceFlag(); + void SetRegionSpaceFlag(RegionSpaceFlag flag) + { + packedData_.flags_.spaceFlag_ = flag; + } bool InEdenSpace() const { return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_EDEN_SPACE; @@ -439,6 +447,11 @@ public: return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_SHARED_READ_ONLY_SPACE; } + bool InSharedAppSpawnSpace() const + { + return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_SHARED_APPSPAWN_SPACE; + } + bool InAppSpawnSpace() const { return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_APPSPAWN_SPACE; diff --git a/ecmascript/mem/shared_heap/shared_concurrent_marker.cpp b/ecmascript/mem/shared_heap/shared_concurrent_marker.cpp index 193386648c..3441dcf63f 100644 --- a/ecmascript/mem/shared_heap/shared_concurrent_marker.cpp +++ b/ecmascript/mem/shared_heap/shared_concurrent_marker.cpp @@ -64,10 +64,10 @@ void SharedConcurrentMarker::Mark(TriggerGCType gcType, GCReason gcReason) ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedConcurrentMarker::Mark"); CHECK_DAEMON_THREAD(); // TODO: support shared runtime state - InitializeMarking(); if (UNLIKELY(sHeap_->ShouldVerifyHeap())) { SharedHeapVerification(sHeap_, VerifyKind::VERIFY_PRE_SHARED_GC).VerifyAll(); } + InitializeMarking(); } // Daemon thread do not need to post task to GC_Thread ASSERT(!dThread_->IsInRunningState()); @@ -127,11 +127,14 @@ void SharedConcurrentMarker::InitializeMarking() dThread_->SetSharedMarkStatus(SharedMarkStatus::CONCURRENT_MARKING_OR_FINISHED); sHeapObjectSize_ = sHeap_->GetHeapObjectSize(); + sHeap_->GetAppSpawnSpace()->EnumerateRegions([](Region *current) { + current->ClearMarkGCBitset(); + }); sHeap_->EnumerateOldSpaceRegions([](Region *current) { ASSERT(current->InSharedSweepableSpace()); current->ResetAliveObject(); }); - sWorkManager_->Initialize(); + sWorkManager_->Initialize(TriggerGCType::SHARED_GC, SharedParallelMarkPhase::SHARED_MARK_TASK); sHeap_->GetSharedGCMarker()->MarkRoots(DAEMON_THREAD_INDEX, SharedMarkType::CONCURRENT_MARK_INITIAL_MARK); } diff --git a/ecmascript/mem/shared_heap/shared_concurrent_sweeper.cpp b/ecmascript/mem/shared_heap/shared_concurrent_sweeper.cpp index ef5735c491..41f2065268 100644 --- a/ecmascript/mem/shared_heap/shared_concurrent_sweeper.cpp +++ b/ecmascript/mem/shared_heap/shared_concurrent_sweeper.cpp @@ -27,30 +27,40 @@ SharedConcurrentSweeper::SharedConcurrentSweeper(SharedHeap *heap, EnableConcurr { } -void SharedConcurrentSweeper::PostTask() +void SharedConcurrentSweeper::PostTask(bool isFullGC) { auto tid = DaemonThread::GetInstance()->GetThreadId(); if (ConcurrentSweepEnabled()) { - Taskpool::GetCurrentTaskpool()->PostTask( - std::make_unique(tid, this, SHARED_OLD_SPACE)); + if (!isFullGC) { + 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() +void SharedConcurrentSweeper::Sweep(bool isFullGC) { + isFullGC_ = isFullGC; if (ConcurrentSweepEnabled()) { // Add all region to region list. Ensure all task finish - sHeap_->GetOldSpace()->PrepareSweeping(); + if (!isFullGC_) { + sHeap_->GetOldSpace()->PrepareSweeping(); + for (int spaceIndex = 0; spaceIndex < SHARED_SWEEPING_SPACE_NUM; spaceIndex++) { + remainingTaskNum_[spaceIndex] = SHARED_SWEEPING_SPACE_NUM; + } + } else { + remainingTaskNum_[0] = 0; // No need sweep shared old space in FullGC. + remainingTaskNum_[1] = 1; // Need sweep nonmovable space in FullGC. + } 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(); + if (!isFullGC_) { + sHeap_->GetOldSpace()->Sweep(); + } sHeap_->GetNonMovableSpace()->Sweep(); } sHeap_->GetHugeObjectSpace()->Sweep(); @@ -72,7 +82,8 @@ void SharedConcurrentSweeper::WaitAllTaskFinished() if (!isSweeping_) { return; } - for (int spaceIndex = 0; spaceIndex < SHARED_SWEEPING_SPACE_NUM; spaceIndex++) { + int spaceIndex = isFullGC_ ? 1 : 0; + for (; spaceIndex < SHARED_SWEEPING_SPACE_NUM; spaceIndex++) { if (remainingTaskNum_[spaceIndex] > 0) { LockHolder holder(mutexs_[spaceIndex]); while (remainingTaskNum_[spaceIndex] > 0) { @@ -88,7 +99,8 @@ void SharedConcurrentSweeper::EnsureAllTaskFinished() if (!isSweeping_) { return; } - for (int spaceIndex = 0; spaceIndex < SHARED_SWEEPING_SPACE_NUM; spaceIndex++) { + int spaceIndex = isFullGC_ ? 1 : 0; + for (; spaceIndex < SHARED_SWEEPING_SPACE_NUM; spaceIndex++) { int type = spaceIndex + SHARED_SWEEPING_SPACE_BEGIN; WaitingTaskFinish(static_cast(type)); } @@ -127,7 +139,9 @@ void SharedConcurrentSweeper::WaitingTaskFinish(MemSpaceType type) void SharedConcurrentSweeper::TryFillSweptRegion() { - sHeap_->GetOldSpace()->TryFillSweptRegion(); + if (!isFullGC_) { + sHeap_->GetOldSpace()->TryFillSweptRegion(); + } sHeap_->GetNonMovableSpace()->TryFillSweptRegion(); } @@ -135,10 +149,14 @@ bool SharedConcurrentSweeper::SweeperTask::Run([[maybe_unused]] uint32_t threadI { if (type_ == SHARED_NON_MOVABLE) { sweeper_->AsyncSweepSpace(SHARED_NON_MOVABLE, false); - sweeper_->AsyncSweepSpace(SHARED_OLD_SPACE, false); + if (!sweeper_->isFullGC_) { + sweeper_->AsyncSweepSpace(SHARED_OLD_SPACE, false); + } } else { ASSERT(type_ == SHARED_OLD_SPACE); - sweeper_->AsyncSweepSpace(SHARED_OLD_SPACE, false); + if (!sweeper_->isFullGC_) { + sweeper_->AsyncSweepSpace(SHARED_OLD_SPACE, false); + } sweeper_->AsyncSweepSpace(SHARED_NON_MOVABLE, false); } diff --git a/ecmascript/mem/shared_heap/shared_concurrent_sweeper.h b/ecmascript/mem/shared_heap/shared_concurrent_sweeper.h index 3e12f1ac81..206197aaa4 100644 --- a/ecmascript/mem/shared_heap/shared_concurrent_sweeper.h +++ b/ecmascript/mem/shared_heap/shared_concurrent_sweeper.h @@ -29,8 +29,8 @@ public: NO_COPY_SEMANTIC(SharedConcurrentSweeper); NO_MOVE_SEMANTIC(SharedConcurrentSweeper); - void PostTask(); - void Sweep(); + void PostTask(bool isFullGC); + void Sweep(bool isFullGC); void WaitAllTaskFinished(); // Help to finish sweeping task. It can be called through js thread @@ -100,6 +100,7 @@ private: SharedHeap *sHeap_; EnableConcurrentSweepType enableType_ {EnableConcurrentSweepType::CONFIG_DISABLE}; bool isSweeping_ {false}; + bool isFullGC_ {false}; }; } // namespace panda::ecmascript #endif // ECMASCRIPT_MEM_SHARED_HEAP_SHARED_CONCURRENT_SWEEPER_H diff --git a/ecmascript/mem/shared_heap/shared_full_gc.cpp b/ecmascript/mem/shared_heap/shared_full_gc.cpp new file mode 100644 index 0000000000..8e6772b358 --- /dev/null +++ b/ecmascript/mem/shared_heap/shared_full_gc.cpp @@ -0,0 +1,184 @@ +/* + * 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_full_gc.h" + +#include "ecmascript/checkpoint/thread_state_transition.h" +#include "ecmascript/ecma_string_table.h" +#include "ecmascript/ecma_vm.h" +#include "ecmascript/mem/barriers-inl.h" +#include "ecmascript/mem/gc_stats.h" +#include "ecmascript/mem/mark_stack.h" +#include "ecmascript/mem/mem.h" +#include "ecmascript/mem/object_xray.h" +#include "ecmascript/mem/shared_heap/shared_concurrent_marker.h" +#include "ecmascript/mem/shared_heap/shared_concurrent_sweeper.h" +#include "ecmascript/mem/shared_heap/shared_gc_marker-inl.h" +#include "ecmascript/mem/slots.h" +#include "ecmascript/mem/space-inl.h" +#include "ecmascript/mem/verification.h" +#include "ecmascript/mem/visitor.h" +#include "ecmascript/runtime.h" + +namespace panda::ecmascript { +void SharedFullGC::RunPhases() +{ + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedFullGC::RunPhases" + + std::to_string(static_cast(sHeap_->GetEcmaGCStats()->GetGCReason())) + + ";Sensitive" + std::to_string(static_cast(sHeap_->GetSensitiveStatus())) + + ";IsInBackground" + std::to_string(sHeap_->IsInBackground()) + + ";Startup" + std::to_string(sHeap_->OnStartupEvent()) + + ";Old" + std::to_string(sHeap_->GetOldSpace()->GetCommittedSize()) + + ";huge" + std::to_string(sHeap_->GetHugeObjectSpace()->GetCommittedSize()) + + ";NonMov" + std::to_string(sHeap_->GetNonMovableSpace()->GetCommittedSize()) + + ";TotCommit" + std::to_string(sHeap_->GetCommittedSize())); + TRACE_GC(GCStats::Scope::ScopeId::TotalGC, sHeap_->GetEcmaGCStats()); + Initialize(); + Mark(); + Sweep(); + Finish(); +} + +void SharedFullGC::Initialize() +{ + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedFullGC::Initialize"); + TRACE_GC(GCStats::Scope::ScopeId::Initialize, sHeap_->GetEcmaGCStats()); + sHeap_->Prepare(true); + if (UNLIKELY(sHeap_->CheckOngoingConcurrentMarking())) { + // Concurrent shared mark should always trigger shared gc without moving. + sHeap_->GetConcurrentMarker()->Reset(true); + } + sHeap_->GetAppSpawnSpace()->EnumerateRegions([](Region *current) { + current->ClearMarkGCBitset(); + }); + sHeap_->EnumerateOldSpaceRegions([](Region *current) { + ASSERT(current->InSharedSweepableSpace()); + current->ResetAliveObject(); + }); + sWorkManager_->Initialize(TriggerGCType::SHARED_FULL_GC, SharedParallelMarkPhase::SHARED_COMPRESS_TASK); +} + +void SharedFullGC::Mark() +{ + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedFullGC::Mark"); + TRACE_GC(GCStats::Scope::ScopeId::Mark, sHeap_->GetEcmaGCStats()); + SharedGCMovableMarker *marker = sHeap_->GetSharedGCMovableMarker(); + + marker->MarkRoots(DAEMON_THREAD_INDEX, SharedMarkType::NOT_CONCURRENT_MARK, VMRootVisitType::UPDATE_ROOT); + marker->DoMark(DAEMON_THREAD_INDEX); + marker->MergeBackAndResetRSetWorkListHandler(); + sHeap_->WaitRunningTaskFinished(); +} + +void SharedFullGC::Sweep() +{ + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedFullGC::Sweep"); + TRACE_GC(GCStats::Scope::ScopeId::Sweep, sHeap_->GetEcmaGCStats()); + UpdateRecordWeakReference(); + WeakRootVisitor gcUpdateWeak = [](TaggedObject *header) { + Region *objectRegion = Region::ObjectAddressToRange(header); + if (!objectRegion) { + LOG_GC(ERROR) << "SharedFullGC updateWeakReference: region is nullptr, header is " << header; + return reinterpret_cast(ToUintPtr(nullptr)); + } + if (objectRegion->InSharedOldSpace()) { + MarkWord markWord(header); + if (markWord.IsForwardingAddress()) { + return markWord.ToForwardingAddress(); + } + return reinterpret_cast(ToUintPtr(nullptr)); + } + if (!objectRegion->InSharedSweepableSpace() || objectRegion->Test(header)) { + return header; + } + return reinterpret_cast(ToUintPtr(nullptr)); + }; + auto stringTableCleaner = Runtime::GetInstance()->GetEcmaStringTable()->GetCleaner(); + stringTableCleaner->PostSweepWeakRefTask(gcUpdateWeak); + Runtime::GetInstance()->ProcessNativeDeleteInSharedGC(gcUpdateWeak); + + Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) { + ASSERT(!thread->IsInRunningState()); + thread->IterateWeakEcmaGlobalStorage(gcUpdateWeak, GCKind::SHARED_GC); + thread->GetEcmaVM()->ProcessSharedNativeDelete(gcUpdateWeak); + const_cast(thread->GetEcmaVM()->GetHeap())->ResetTlab(); + thread->ClearContextCachedConstantPool(); + }); + + stringTableCleaner->JoinAndWaitSweepWeakRefTask(gcUpdateWeak); + sHeap_->GetSweeper()->Sweep(true); + sHeap_->GetSweeper()->PostTask(true); +} + +void SharedFullGC::Finish() +{ + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedFullGC::Finish"); + TRACE_GC(GCStats::Scope::ScopeId::Finish, sHeap_->GetEcmaGCStats()); + sHeap_->SwapOldSpace(); + sWorkManager_->Finish(); + if (!isAppspawn_) { + sHeap_->Reclaim(TriggerGCType::SHARED_FULL_GC); + } else { + sHeap_->ReclaimForAppSpawn(); + } + + sHeap_->GetSweeper()->TryFillSweptRegion(); +} + +void SharedFullGC::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()); + ASSERT(value.IsWeak()); + auto header = value.GetTaggedWeakRef(); + Region *objectRegion = Region::ObjectAddressToRange(header); + if (!objectRegion->InSharedOldSpace()) { + if (!objectRegion->Test(header)) { + slot.Clear(); + } + } else { + MarkWord markWord(header); + if (markWord.IsForwardingAddress()) { + TaggedObject *dst = markWord.ToForwardingAddress(); + auto weakRef = JSTaggedValue(JSTaggedValue(dst).CreateAndGetWeakRef()).GetRawTaggedObject(); + slot.Update(weakRef); + } else { + slot.Clear(); + } + } + } + } +} + +bool SharedFullGC::HasEvacuated(Region *region) +{ + auto marker = reinterpret_cast(sHeap_->GetSharedGCMovableMarker()); + return marker->NeedEvacuate(region); +} + +void SharedFullGC::ResetWorkManager(SharedGCWorkManager *sWorkManager) +{ + sWorkManager_ = sWorkManager; +} +} // namespace panda::ecmascript diff --git a/ecmascript/mem/shared_heap/shared_full_gc.h b/ecmascript/mem/shared_heap/shared_full_gc.h new file mode 100644 index 0000000000..257ad45dd0 --- /dev/null +++ b/ecmascript/mem/shared_heap/shared_full_gc.h @@ -0,0 +1,56 @@ +/* + * 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_FULL_GC_H +#define ECMASCRIPT_MEM_SHARED_HEAP_SHARED_FULL_GC_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 SharedFullGC : public GarbageCollector { +public: + explicit SharedFullGC(SharedHeap *heap) : sHeap_(heap), sWorkManager_(heap->GetWorkManager()) {} + ~SharedFullGC() override = default; + NO_COPY_SEMANTIC(SharedFullGC); + NO_MOVE_SEMANTIC(SharedFullGC); + + void RunPhases() override; + void ResetWorkManager(SharedGCWorkManager *workManager); + void SetForAppSpawn(bool flag) + { + isAppspawn_ = flag; + } +protected: + void Initialize() override; + void Mark() override; + void Sweep() override; + void Finish() override; + +private: + void UpdateRecordWeakReference(); + bool HasEvacuated(Region *region); + + SharedHeap *sHeap_ {nullptr}; + SharedGCWorkManager *sWorkManager_ {nullptr}; + bool isAppspawn_ {false}; +}; +} // namespace panda::ecmascript + +#endif // ECMASCRIPT_MEM_SHARED_HEAP_SHARED_FULL_GC_H diff --git a/ecmascript/mem/shared_heap/shared_gc.cpp b/ecmascript/mem/shared_heap/shared_gc.cpp index 2692e48899..0dffd4f45d 100644 --- a/ecmascript/mem/shared_heap/shared_gc.cpp +++ b/ecmascript/mem/shared_heap/shared_gc.cpp @@ -70,11 +70,14 @@ void SharedGC::Initialize() TRACE_GC(GCStats::Scope::ScopeId::Initialize, sHeap_->GetEcmaGCStats()); if (!markingInProgress_) { sHeap_->Prepare(true); + sHeap_->GetAppSpawnSpace()->EnumerateRegions([](Region *current) { + current->ClearMarkGCBitset(); + }); sHeap_->EnumerateOldSpaceRegions([](Region *current) { ASSERT(current->InSharedSweepableSpace()); current->ResetAliveObject(); }); - sWorkManager_->Initialize(); + sWorkManager_->Initialize(TriggerGCType::SHARED_GC, SharedParallelMarkPhase::SHARED_MARK_TASK); } } void SharedGC::Mark() @@ -120,15 +123,15 @@ void SharedGC::Sweep() }); stringTableCleaner->JoinAndWaitSweepWeakRefTask(gcUpdateWeak); - sHeap_->GetSweeper()->Sweep(); - sHeap_->GetSweeper()->PostTask(); + sHeap_->GetSweeper()->Sweep(false); + sHeap_->GetSweeper()->PostTask(false); } void SharedGC::Finish() { ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGC::Finish"); TRACE_GC(GCStats::Scope::ScopeId::Finish, sHeap_->GetEcmaGCStats()); - sHeap_->Reclaim(); + sHeap_->Reclaim(TriggerGCType::SHARED_GC); if (markingInProgress_) { sHeap_->GetConcurrentMarker()->Reset(false); } else { diff --git a/ecmascript/mem/shared_heap/shared_gc_marker-inl.h b/ecmascript/mem/shared_heap/shared_gc_marker-inl.h index 31e4aaf7a2..893f5492d7 100644 --- a/ecmascript/mem/shared_heap/shared_gc_marker-inl.h +++ b/ecmascript/mem/shared_heap/shared_gc_marker-inl.h @@ -21,18 +21,20 @@ #include "ecmascript/js_hclass-inl.h" #include "ecmascript/mem/heap-inl.h" #include "ecmascript/mem/region-inl.h" +#include "ecmascript/mem/tlab_allocator-inl.h" namespace panda::ecmascript { -inline void SharedGCMarker::MarkObject(uint32_t threadId, TaggedObject *object) +inline void SharedGCMarker::MarkObject(uint32_t threadId, TaggedObject *object, [[maybe_unused]] ObjectSlot &slot) { Region *objectRegion = Region::ObjectAddressToRange(object); ASSERT(objectRegion->InSharedHeap()); if (!objectRegion->InSharedReadOnlySpace() && objectRegion->AtomicMark(object)) { + ASSERT(objectRegion->InSharedSweepableSpace()); sWorkManager_->Push(threadId, object); } } -inline void SharedGCMarker::MarkObjectFromJSThread(WorkNode *&localBuffer, TaggedObject *object) +inline void SharedGCMarkerBase::MarkObjectFromJSThread(WorkNode *&localBuffer, TaggedObject *object) { Region *objectRegion = Region::ObjectAddressToRange(object); ASSERT(objectRegion->InSharedHeap()); @@ -46,30 +48,30 @@ inline void SharedGCMarker::MarkValue(uint32_t threadId, ObjectSlot &slot) JSTaggedValue value(slot.GetTaggedType()); if (value.IsInSharedSweepableSpace()) { if (!value.IsWeakForHeapObject()) { - MarkObject(threadId, value.GetTaggedObject()); + MarkObject(threadId, value.GetTaggedObject(), slot); } else { RecordWeakReference(threadId, reinterpret_cast(slot.SlotAddress())); } } } -inline void SharedGCMarker::HandleRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot) +inline void SharedGCMarkerBase::HandleRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot) { JSTaggedValue value(slot.GetTaggedType()); if (value.IsInSharedSweepableSpace()) { - MarkObject(threadId, value.GetTaggedObject()); + MarkObject(threadId, value.GetTaggedObject(), slot); } } -inline void SharedGCMarker::HandleLocalRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot) +inline void SharedGCMarkerBase::HandleLocalRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot) { JSTaggedValue value(slot.GetTaggedType()); if (value.IsInSharedSweepableSpace()) { - MarkObject(threadId, value.GetTaggedObject()); + MarkObject(threadId, value.GetTaggedObject(), slot); } } -inline void SharedGCMarker::HandleLocalRangeRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot start, +inline void SharedGCMarkerBase::HandleLocalRangeRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end) { for (ObjectSlot slot = start; slot < end; slot++) { @@ -78,21 +80,29 @@ inline void SharedGCMarker::HandleLocalRangeRoots(uint32_t threadId, [[maybe_unu if (value.IsWeakForHeapObject()) { LOG_ECMA_MEM(FATAL) << "Weak Reference in SharedGCMarker roots"; } - MarkObject(threadId, value.GetTaggedObject()); + MarkObject(threadId, value.GetTaggedObject(), slot); } } } -inline void SharedGCMarker::HandleLocalDerivedRoots([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base, - [[maybe_unused]] ObjectSlot derived, - [[maybe_unused]] uintptr_t baseOldObject) +void SharedGCMarker::HandleLocalDerivedRoots([[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 } +void SharedGCMovableMarker::HandleLocalDerivedRoots([[maybe_unused]] Root type, ObjectSlot base, + ObjectSlot derived, uintptr_t baseOldObject) +{ + if (JSTaggedValue(base.GetTaggedType()).IsHeapObject()) { + derived.Update(base.GetTaggedType() + derived.GetTaggedType() - baseOldObject); + } +} + template -ARK_INLINE bool SharedGCMarker::VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, - Callback callback) +ARK_INLINE bool SharedGCMarkerBase::VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, + Callback callback) { auto hclass = root->SynchronizedGetClass(); int index = 0; @@ -109,28 +119,30 @@ ARK_INLINE bool SharedGCMarker::VisitBodyInObj(TaggedObject *root, ObjectSlot st return true; } -inline void SharedGCMarker::RecordWeakReference(uint32_t threadId, JSTaggedType *slot) +inline void SharedGCMarkerBase::RecordWeakReference(uint32_t threadId, JSTaggedType *slot) { sWorkManager_->PushWeakReference(threadId, slot); } -inline void SharedGCMarker::RecordObject(JSTaggedValue value, uint32_t threadId, void *mem) +inline void SharedGCMarkerBase::RecordObject(JSTaggedValue value, uint32_t threadId, void *mem) { if (value.IsWeakForHeapObject()) { RecordWeakReference(threadId, reinterpret_cast(mem)); } else { - MarkObject(threadId, value.GetTaggedObject()); + ObjectSlot slot(ToUintPtr(mem)); + MarkObject(threadId, value.GetTaggedObject(), slot); } } template -inline bool SharedGCMarker::GetVisitor(JSTaggedValue value, uint32_t threadId, void *mem) +inline bool SharedGCMarkerBase::GetVisitor(JSTaggedValue value, uint32_t threadId, void *mem) { if (value.IsInSharedSweepableSpace()) { if constexpr (markType == SharedMarkType::CONCURRENT_MARK_INITIAL_MARK) { // For now if record weak references from local to share in marking root, the slots // may be invalid due to LocalGC, so just mark them as strong-reference. - MarkObject(threadId, value.GetHeapObject()); + ObjectSlot slot(ToUintPtr(mem)); + MarkObject(threadId, value.GetHeapObject(), slot); } else { static_assert(markType == SharedMarkType::NOT_CONCURRENT_MARK); RecordObject(value, threadId, mem); @@ -141,19 +153,18 @@ inline bool SharedGCMarker::GetVisitor(JSTaggedValue value, uint32_t threadId, v } template -inline auto SharedGCMarker::GenerateRSetVisitor(uint32_t threadId) +inline auto SharedGCMarkerBase::GenerateRSetVisitor(uint32_t threadId) { auto visitor = [this, threadId](void *mem) -> bool { ObjectSlot slot(ToUintPtr(mem)); JSTaggedValue value(slot.GetTaggedType()); - return GetVisitor(value, threadId, mem); }; return visitor; } template -inline void SharedGCMarker::ProcessVisitorOfDoMark(uint32_t threadId) +inline void SharedGCMarkerBase::ProcessVisitorOfDoMark(uint32_t threadId) { auto rSetVisitor = GenerateRSetVisitor(threadId); auto visitor = [rSetVisitor](Region *region, RememberedSet *rSet) { @@ -166,7 +177,7 @@ inline void SharedGCMarker::ProcessVisitorOfDoMark(uint32_t threadId) } template -inline void SharedGCMarker::DoMark(uint32_t threadId) +inline void SharedGCMarkerBase::DoMark(uint32_t threadId) { if constexpr (markType != SharedMarkType::CONCURRENT_MARK_REMARK) { ProcessVisitorOfDoMark(threadId); @@ -174,7 +185,7 @@ inline void SharedGCMarker::DoMark(uint32_t threadId) ProcessMarkStack(threadId); } -inline bool SharedGCMarker::MarkObjectOfProcessVisitor(void *mem, WorkNode *&localBuffer) +inline bool SharedGCMarkerBase::MarkObjectOfProcessVisitor(void *mem, WorkNode *&localBuffer) { ObjectSlot slot(ToUintPtr(mem)); JSTaggedValue value(slot.GetTaggedType()); @@ -189,7 +200,7 @@ inline bool SharedGCMarker::MarkObjectOfProcessVisitor(void *mem, WorkNode *&loc return false; } -inline void SharedGCMarker::ProcessVisitor(RSetWorkListHandler *handler) +inline void SharedGCMarkerBase::ProcessVisitor(RSetWorkListHandler *handler) { WorkNode *&localBuffer = handler->GetHeap()->GetMarkingObjectLocalBuffer(); auto rSetVisitor = [this, &localBuffer](void *mem) -> bool { @@ -201,7 +212,7 @@ inline void SharedGCMarker::ProcessVisitor(RSetWorkListHandler *handler) handler->ProcessAll(visitor); } -inline void SharedGCMarker::ProcessThenMergeBackRSetFromBoundJSThread(RSetWorkListHandler *handler) +inline void SharedGCMarkerBase::ProcessThenMergeBackRSetFromBoundJSThread(RSetWorkListHandler *handler) { ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarker::ProcessRSet"); ASSERT(JSThread::GetCurrent() == handler->GetHeap()->GetEcmaVM()->GetJSThread()); @@ -209,5 +220,108 @@ inline void SharedGCMarker::ProcessThenMergeBackRSetFromBoundJSThread(RSetWorkLi ProcessVisitor(handler); handler->WaitFinishedThenMergeBack(); } + +void SharedGCMovableMarker::MarkObject(uint32_t threadId, TaggedObject *object, ObjectSlot &slot) +{ + Region *objectRegion = Region::ObjectAddressToRange(object); + ASSERT(objectRegion->InSharedHeap()); + if (!NeedEvacuate(objectRegion)) { + if (!objectRegion->InSharedReadOnlySpace() && objectRegion->AtomicMark(object)) { + auto hclass = object->GetClass(); + auto size = hclass->SizeFromJSHClass(object); + objectRegion->IncreaseAliveObject(size); + sWorkManager_->Push(threadId, object); + } + return; + } + + MarkWord markWord(object); + if (markWord.IsForwardingAddress()) { + TaggedObject *dst = markWord.ToForwardingAddress(); + slot.Update(dst); + return; + } + return EvacuateObject(threadId, object, markWord, slot); +} + +void SharedGCMovableMarker::MarkValue(uint32_t threadId, ObjectSlot &slot) +{ + JSTaggedValue value(slot.GetTaggedType()); + if (value.IsInSharedSweepableSpace()) { + if (!value.IsWeakForHeapObject()) { + MarkObject(threadId, value.GetTaggedObject(), slot); + } else { + RecordWeakReference(threadId, reinterpret_cast(slot.SlotAddress())); + } + } +} + +bool SharedGCMovableMarker::NeedEvacuate(Region *region) +{ + return region->InSharedOldSpace(); +} + +void SharedGCMovableMarker::EvacuateObject(uint32_t threadId, TaggedObject *object, + const MarkWord &markWord, ObjectSlot slot) +{ + JSHClass *klass = markWord.GetJSHClass(); + size_t size = klass->SizeFromJSHClass(object); + uintptr_t forwardAddress = AllocateForwardAddress(threadId, size); + RawCopyObject(ToUintPtr(object), forwardAddress, size, markWord); + + auto oldValue = markWord.GetValue(); + auto result = Barriers::AtomicSetPrimitive(object, 0, oldValue, + MarkWord::FromForwardingAddress(forwardAddress)); + if (result == oldValue) { + UpdateForwardAddressIfSuccess(threadId, klass, forwardAddress, size, slot); + return; + } + UpdateForwardAddressIfFailed(object, forwardAddress, size, slot); +} + +uintptr_t SharedGCMovableMarker::AllocateDstSpace(uint32_t threadId, size_t size) +{ + uintptr_t forwardAddress = 0; + forwardAddress = sWorkManager_->GetTlabAllocator(threadId)->Allocate(size, SHARED_COMPRESS_SPACE); + if (UNLIKELY(forwardAddress == 0)) { + LOG_ECMA_MEM(FATAL) << "EvacuateObject alloc failed: " + << " size: " << size; + UNREACHABLE(); + } + return forwardAddress; +} + +inline void SharedGCMovableMarker::RawCopyObject(uintptr_t fromAddress, uintptr_t toAddress, size_t size, + const MarkWord &markWord) +{ + if (memcpy_s(ToVoidPtr(toAddress + HEAD_SIZE), size - HEAD_SIZE, ToVoidPtr(fromAddress + HEAD_SIZE), + size - HEAD_SIZE) != EOK) { + LOG_FULL(FATAL) << "memcpy_s failed"; + } + *reinterpret_cast(toAddress) = markWord.GetValue(); +} + +void SharedGCMovableMarker::UpdateForwardAddressIfSuccess(uint32_t threadId, JSHClass *klass, uintptr_t toAddress, + size_t size, ObjectSlot slot) +{ + sWorkManager_->IncreaseAliveSize(threadId, size); + if (klass->HasReferenceField()) { + sWorkManager_->Push(threadId, reinterpret_cast(toAddress)); + } + slot.Update(reinterpret_cast(toAddress)); +} + +void SharedGCMovableMarker::UpdateForwardAddressIfFailed(TaggedObject *object, uintptr_t toAddress, size_t size, + ObjectSlot slot) +{ + FreeObject::FillFreeObject(sHeap_, toAddress, size); + TaggedObject *dst = MarkWord(object).ToForwardingAddress(); + slot.Update(dst); +} + +uintptr_t SharedGCMovableMarker::AllocateForwardAddress(uint32_t threadId, size_t size) +{ + return AllocateDstSpace(threadId, size); +} } // 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 index 97636dc763..cf12ed0416 100644 --- a/ecmascript/mem/shared_heap/shared_gc_marker.cpp +++ b/ecmascript/mem/shared_heap/shared_gc_marker.cpp @@ -22,9 +22,9 @@ #include "ecmascript/runtime.h" namespace panda::ecmascript { -void SharedGCMarker::MarkRoots(uint32_t threadId, SharedMarkType markType) +void SharedGCMarkerBase::MarkRoots(uint32_t threadId, SharedMarkType markType, VMRootVisitType type) { - ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarker::MarkRoots"); + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarkerBase::MarkRoots"); MarkSerializeRoots(threadId); MarkSharedModule(threadId); MarkStringCache(threadId); @@ -38,16 +38,17 @@ void SharedGCMarker::MarkRoots(uint32_t threadId, SharedMarkType markType) runtime->GCIterateThreadList([&](JSThread *thread) { ASSERT(!thread->IsInRunningState()); auto vm = thread->GetEcmaVM(); - MarkLocalVMRoots(threadId, vm, markType); + MarkLocalVMRoots(threadId, vm, markType, type); if (markType != SharedMarkType::CONCURRENT_MARK_REMARK) { CollectLocalVMRSet(vm); } }); } -void SharedGCMarker::MarkLocalVMRoots(uint32_t threadId, EcmaVM *localVm, SharedMarkType markType) +void SharedGCMarkerBase::MarkLocalVMRoots(uint32_t threadId, EcmaVM *localVm, SharedMarkType markType, + VMRootVisitType type) { - ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarker::MarkLocalVMRoots"); + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarkerBase::MarkLocalVMRoots"); Heap *heap = const_cast(localVm->GetHeap()); if (markType != SharedMarkType::CONCURRENT_MARK_REMARK) { heap->GetSweeper()->EnsureAllTaskFinished(); @@ -61,38 +62,38 @@ void SharedGCMarker::MarkLocalVMRoots(uint32_t threadId, EcmaVM *localVm, Shared }, [this](Root type, ObjectSlot base, ObjectSlot derived, uintptr_t baseOldObject) { this->HandleLocalDerivedRoots(type, base, derived, baseOldObject); - }, VMRootVisitType::MARK); + }, type); heap->ProcessSharedGCMarkingLocalBuffer(); } -void SharedGCMarker::CollectLocalVMRSet(EcmaVM *localVm) +void SharedGCMarkerBase::CollectLocalVMRSet(EcmaVM *localVm) { - ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarker::CollectLocalVMRSet"); + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarkerBase::CollectLocalVMRSet"); Heap *heap = const_cast(localVm->GetHeap()); RSetWorkListHandler *handler = new RSetWorkListHandler(heap); heap->SetRSetWorkListHandler(handler); rSetHandlers_.emplace_back(handler); } -void SharedGCMarker::MarkSerializeRoots(uint32_t threadId) +void SharedGCMarkerBase::MarkSerializeRoots(uint32_t threadId) { - ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarker::MarkSerializeRoots"); + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarkerBase::MarkSerializeRoots"); auto callback = [this, threadId](Root type, ObjectSlot slot) {this->HandleRoots(threadId, type, slot);}; Runtime::GetInstance()->IterateSerializeRoot(callback); } -void SharedGCMarker::MarkStringCache(uint32_t threadId) +void SharedGCMarkerBase::MarkStringCache(uint32_t threadId) { - ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarker::MarkStringCache"); + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarkerBase::MarkStringCache"); auto cacheStringCallback = [this, threadId](Root type, ObjectSlot start, ObjectSlot end) { this->HandleLocalRangeRoots(threadId, type, start, end); }; Runtime::GetInstance()->IterateCachedStringRoot(cacheStringCallback); } -void SharedGCMarker::MarkSharedModule(uint32_t threadId) +void SharedGCMarkerBase::MarkSharedModule(uint32_t threadId) { - ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarker::MarkSharedModule"); + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarkerBase::MarkSharedModule"); auto visitor = [this, threadId](Root type, ObjectSlot slot) {this->HandleRoots(threadId, type, slot);}; SharedModuleManager::GetInstance()->Iterate(visitor); } @@ -139,12 +140,58 @@ void SharedGCMarker::ProcessMarkStack(uint32_t threadId) Region *region = Region::ObjectAddressToRange(obj); ASSERT(region->InSharedSweepableSpace()); region->IncreaseAliveObjectSafe(size); - MarkObject(threadId, hclass); + ObjectSlot objectSlot(ToUintPtr(obj)); + MarkObject(threadId, hclass, objectSlot); ObjectXRay::VisitObjectBody(obj, hclass, visitor); } } -void SharedGCMarker::MergeBackAndResetRSetWorkListHandler() +void SharedGCMovableMarker::ProcessMarkStack(uint32_t threadId) +{ +#ifndef NDEBUG + DaemonThread *dThread = DaemonThread::GetInstance(); + if (UNLIKELY(!dThread->IsRunning())) { + // This DAEMON_THREAD_INDEX not means in daemon thread, but the daemon thread is terminated, and + // SharedGC is directly running in the current js thread, this maybe happen only AppSpawn + // trigger GC after PreFork (which is not expected), and at this time ParallelGC is disabled + ASSERT(threadId == DAEMON_THREAD_INDEX); + } else { + if (os::thread::GetCurrentThreadId() != dThread->GetThreadId()) { + ASSERT(threadId != 0); + } else { + ASSERT(threadId == 0); + } + } +#endif + auto cb = [&](ObjectSlot slot) { + MarkValue(threadId, slot); + }; + EcmaObjectRangeVisitor 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(); + [[maybe_unused]] Region *region = Region::ObjectAddressToRange(obj); + ObjectSlot objectSlot(ToUintPtr(obj)); + MarkObject(threadId, hclass, objectSlot); + ObjectXRay::VisitObjectBody(obj, hclass, visitor); + } +} + +void SharedGCMarkerBase::MergeBackAndResetRSetWorkListHandler() { for (RSetWorkListHandler *handler : rSetHandlers_) { handler->MergeBack(); @@ -153,8 +200,15 @@ void SharedGCMarker::MergeBackAndResetRSetWorkListHandler() rSetHandlers_.clear(); } -void SharedGCMarker::ResetWorkManager(SharedGCWorkManager *workManager) +void SharedGCMarkerBase::ResetWorkManager(SharedGCWorkManager *workManager) { sWorkManager_ = workManager; } + +SharedGCMarker::SharedGCMarker(SharedGCWorkManager *workManger) + : SharedGCMarkerBase(workManger) {} + +SharedGCMovableMarker::SharedGCMovableMarker(SharedGCWorkManager *workManger, SharedHeap *sHeap) + : SharedGCMarkerBase(workManger), sHeap_(sHeap) {} + } // 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 index 561fedf493..39358d471c 100644 --- a/ecmascript/mem/shared_heap/shared_gc_marker.h +++ b/ecmascript/mem/shared_heap/shared_gc_marker.h @@ -25,6 +25,8 @@ namespace panda::ecmascript { class Region; class TaggedObject; class SharedGCMarker; +class JSHClass; +enum class Root; enum class SharedMarkType : uint8_t { NOT_CONCURRENT_MARK, @@ -32,32 +34,28 @@ enum class SharedMarkType : uint8_t { CONCURRENT_MARK_REMARK, }; -class SharedGCMarker { +class SharedGCMarkerBase { public: - explicit SharedGCMarker(SharedGCWorkManager *workManger) : sWorkManager_(workManger) {} - ~SharedGCMarker() = default; + explicit SharedGCMarkerBase(SharedGCWorkManager *workManger) : sWorkManager_(workManger) {} + virtual ~SharedGCMarkerBase() = default; void ResetWorkManager(SharedGCWorkManager *workManager); - void MarkRoots(uint32_t threadId, SharedMarkType markType); - void MarkLocalVMRoots(uint32_t threadId, EcmaVM *localVm, SharedMarkType markType); + void MarkRoots(uint32_t threadId, SharedMarkType markType, VMRootVisitType type = VMRootVisitType::MARK); + void MarkLocalVMRoots(uint32_t threadId, EcmaVM *localVm, SharedMarkType markType, + VMRootVisitType type = VMRootVisitType::MARK); void CollectLocalVMRSet(EcmaVM *localVm); void MarkStringCache(uint32_t threadId); void MarkSerializeRoots(uint32_t threadId); void MarkSharedModule(uint32_t threadId); - void ProcessMarkStack(uint32_t threadId); inline void ProcessThenMergeBackRSetFromBoundJSThread(RSetWorkListHandler *handler); template inline void DoMark(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 HandleLocalRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot); inline void HandleLocalRangeRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end); - inline void HandleLocalDerivedRoots(Root type, ObjectSlot base, ObjectSlot derived, - uintptr_t baseOldObject); inline void RecordWeakReference(uint32_t threadId, JSTaggedType *ref); void MergeBackAndResetRSetWorkListHandler(); template @@ -65,16 +63,78 @@ public: inline void ProcessVisitor(RSetWorkListHandler *handler); inline bool MarkObjectOfProcessVisitor(void *mem, WorkNode *&localBuffer); -private: inline void MarkObjectFromJSThread(WorkNode *&localBuffer, TaggedObject *object); + + virtual inline void MarkValue([[maybe_unused]] uint32_t threadId, [[maybe_unused]] ObjectSlot &slot) + { + LOG_GC(FATAL) << " can not call this method"; + } + + virtual inline void MarkObject([[maybe_unused]] uint32_t threadId, [[maybe_unused]] TaggedObject *object, + [[maybe_unused]] ObjectSlot &slot) + { + LOG_GC(FATAL) << " can not call this method"; + } + + virtual inline void HandleLocalDerivedRoots([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base, + [[maybe_unused]] ObjectSlot derived, + [[maybe_unused]] uintptr_t baseOldObject) + { + LOG_GC(FATAL) << " can not call this method"; + } + virtual void ProcessMarkStack([[maybe_unused]] uint32_t threadId) + { + LOG_GC(FATAL) << " can not call this method"; + } + +protected: + SharedGCWorkManager *sWorkManager_ {nullptr}; + +private: template inline auto GenerateRSetVisitor(uint32_t threadId); inline void RecordObject(JSTaggedValue value, uint32_t threadId, void *mem); template inline bool GetVisitor(JSTaggedValue value, uint32_t threadId, void *mem); - SharedGCWorkManager *sWorkManager_ {nullptr}; std::vector rSetHandlers_; }; + +class SharedGCMarker : public SharedGCMarkerBase { +public: + explicit SharedGCMarker(SharedGCWorkManager *workManger); + ~SharedGCMarker() override = default; + void ProcessMarkStack(uint32_t threadId) override; + +protected: + inline void MarkValue(uint32_t threadId, ObjectSlot &slot) override; + inline void MarkObject(uint32_t threadId, TaggedObject *object, ObjectSlot &slot) override; + inline void HandleLocalDerivedRoots(Root type, ObjectSlot base, ObjectSlot derived, + uintptr_t baseOldObject) override; +}; + +class SharedGCMovableMarker : public SharedGCMarkerBase { +public: + explicit SharedGCMovableMarker(SharedGCWorkManager *workManger, SharedHeap *sHeap); + ~SharedGCMovableMarker() override = default; + inline bool NeedEvacuate(Region *region); + void ProcessMarkStack(uint32_t threadId) override; + +protected: + inline void HandleLocalDerivedRoots(Root type, ObjectSlot base, ObjectSlot derived, + uintptr_t baseOldObject) override; + inline void MarkValue(uint32_t threadId, ObjectSlot &slot) override; + inline void MarkObject(uint32_t threadId, TaggedObject *object, ObjectSlot &slot) override; + inline uintptr_t AllocateForwardAddress(uint32_t threadId, size_t size); + inline void EvacuateObject(uint32_t threadId, TaggedObject *object, const MarkWord &markWord, ObjectSlot slot); + inline uintptr_t AllocateDstSpace(uint32_t threadId, size_t size); + inline void RawCopyObject(uintptr_t fromAddress, uintptr_t toAddress, size_t size, const MarkWord &markWord); + inline void UpdateForwardAddressIfSuccess(uint32_t threadId, JSHClass *klass, uintptr_t toAddress, size_t size, + ObjectSlot slot); + inline void UpdateForwardAddressIfFailed(TaggedObject *object, uintptr_t toAddress, size_t size, ObjectSlot slot); + +private: + SharedHeap *sHeap_; +}; } // 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 index ac9bc6ac85..5bc1cf0025 100644 --- a/ecmascript/mem/shared_heap/shared_space.cpp +++ b/ecmascript/mem/shared_heap/shared_space.cpp @@ -68,7 +68,8 @@ uintptr_t SharedSparseSpace::Allocate(JSThread *thread, size_t size, bool allowG UNREACHABLE(); } #endif - thread->CheckSafepointIfSuspended(); + // Shared old space cannot use this allocate func. Shared full gc may happen in trigger and thread state update. + // Shared old space pointer might change by shared full gc. // jit thread no heap allowGC = allowGC && (!thread->IsJitThread()); if (allowGC) { @@ -95,6 +96,21 @@ uintptr_t SharedSparseSpace::Allocate(JSThread *thread, size_t size, bool allowG return object; } +uintptr_t SharedSparseSpace::TryAllocateAndExpand(JSThread *thread, size_t size, bool expand) +{ + uintptr_t object = TryAllocate(thread, size); + CHECK_SOBJECT_AND_INC_OBJ_SIZE(size); + if (sweepState_ == SweepState::SWEEPING) { + object = AllocateAfterSweepingCompleted(thread, size); + CHECK_SOBJECT_AND_INC_OBJ_SIZE(size); + } + if (expand) { + object = AllocateWithExpand(thread, size); + CHECK_SOBJECT_AND_INC_OBJ_SIZE(size); + } + return object; +} + uintptr_t SharedSparseSpace::AllocateNoGCAndExpand(JSThread *thread, size_t size) { #if ECMASCRIPT_ENABLE_THREAD_STATE_CHECK @@ -112,17 +128,17 @@ uintptr_t SharedSparseSpace::AllocateNoGCAndExpand(JSThread *thread, size_t size return object; } -uintptr_t SharedSparseSpace::TryAllocate(JSThread *thread, size_t size) +uintptr_t SharedSparseSpace::TryAllocate([[maybe_unused]] JSThread *thread, size_t size) { - RuntimeLockHolder lock(thread, allocateLock_); + LockHolder lock(allocateLock_); return allocator_->Allocate(size); } uintptr_t SharedSparseSpace::AllocateWithExpand(JSThread *thread, size_t size) { - RuntimeLockHolder lock(thread, allocateLock_); + LockHolder lock(allocateLock_); // In order to avoid expand twice by different threads, try allocate first. - CheckAndTriggerLocalFullMark(thread); + CheckAndTriggerLocalFullMark(); auto object = allocator_->Allocate(size); if (object == 0 && Expand(thread)) { object = allocator_->Allocate(size); @@ -165,9 +181,9 @@ void SharedSparseSpace::MergeDeserializeAllocateRegions(const std::vectorAllocate(size); } @@ -182,29 +198,10 @@ uintptr_t SharedSparseSpace::AllocateAfterSweepingCompleted(JSThread *thread, si return allocator_->Allocate(size); } -void SharedSparseSpace::ReclaimRegions() -{ - EnumerateReclaimRegions([this](Region *region) { - region->DeleteCrossRegionRSet(); - region->DeleteOldToNewRSet(); - region->DeleteLocalToShareRSet(); - region->DeleteSweepingOldToNewRSet(); - region->DeleteSweepingLocalToShareRSet(); - region->DestroyFreeObjectSets(); - heapRegionAllocator_->FreeRegion(region, 0); - }); - reclaimRegionList_.clear(); -} - void SharedSparseSpace::PrepareSweeping() { liveObjectSize_ = 0; EnumerateRegions([this](Region *current) { - if (current->AliveObject() == 0) { - RemoveRegion(current); - reclaimRegionList_.emplace(current); - return; - } IncreaseLiveObjectSize(current->AliveObject()); current->ResetWasted(); AddSweepingRegion(current); @@ -319,6 +316,11 @@ void SharedSparseSpace::FreeRegion(Region *current, bool isMain) } } +void SharedSparseSpace::DetachFreeObjectSet(Region *region) +{ + allocator_->DetachFreeObjectSet(region); +} + 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. @@ -379,13 +381,28 @@ void SharedSparseSpace::InvokeAllocationInspector(Address object, size_t size, s allocationCounter_.AdvanceAllocationInspector(alignedSize); } -void SharedSparseSpace::CheckAndTriggerLocalFullMark(JSThread *thread) +void SharedSparseSpace::CheckAndTriggerLocalFullMark() { if (liveObjectSize_ >= triggerLocalFullMarkLimit_) { - sHeap_->TryTriggerLocalConcurrentMarking(thread); + sHeap_->TryTriggerLocalConcurrentMarking(); } } +SharedAppSpawnSpace::SharedAppSpawnSpace(SharedHeap *heap, size_t initialCapacity) + : SharedSparseSpace(heap, MemSpaceType::SHARED_APPSPAWN_SPACE, initialCapacity, initialCapacity) +{ +} + +void SharedAppSpawnSpace::IterateOverMarkedObjects(const std::function &visitor) const +{ + EnumerateRegions([&](Region *current) { + current->IterateAllMarkedBits([&](void *mem) { + ASSERT(current->InRange(ToUintPtr(mem))); + visitor(reinterpret_cast(mem)); + }); + }); +} + SharedNonMovableSpace::SharedNonMovableSpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity) : SharedSparseSpace(heap, MemSpaceType::SHARED_NON_MOVABLE, initialCapacity, maximumCapacity) { @@ -396,6 +413,77 @@ SharedOldSpace::SharedOldSpace(SharedHeap *heap, size_t initialCapacity, size_t { } +void SharedOldSpace::Merge(SharedLocalSpace *localSpace) +{ + localSpace->FreeBumpPoint(); + LockHolder lock(lock_); + size_t oldCommittedSize = committedSize_; + localSpace->EnumerateRegions([&](Region *region) { + localSpace->DetachFreeObjectSet(region); + localSpace->RemoveRegion(region); + localSpace->DecreaseLiveObjectSize(region->AliveObject()); + AddRegion(region); + IncreaseLiveObjectSize(region->AliveObject()); + allocator_->CollectFreeObjectSet(region); + }); + size_t hugeSpaceCommitSize = sHeap_->GetHugeObjectSpace()->GetCommittedSize(); + if (committedSize_ + hugeSpaceCommitSize > GetOverShootMaximumCapacity()) { + LOG_ECMA_MEM(ERROR) << "Merge::Committed size " << committedSize_ << " of old space is too big. "; + if (sHeap_->CanThrowOOMError()) { + sHeap_->ShouldThrowOOMError(true); + } + IncreaseMergeSize(committedSize_ - oldCommittedSize); + // if throw OOM, temporarily increase space size to avoid vm crash + IncreaseOutOfMemoryOvershootSize(committedSize_ + hugeSpaceCommitSize - GetOverShootMaximumCapacity()); + } + + localSpace->GetRegionList().Clear(); + allocator_->IncreaseAllocatedSize(localSpace->GetTotalAllocatedSize()); +} + +SharedLocalSpace::SharedLocalSpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity) + : SharedSparseSpace(heap, MemSpaceType::SHARED_LOCAL_SPACE, initialCapacity, maximumCapacity) {} + +bool SharedLocalSpace::AddRegionToList(Region *region) +{ + if (committedSize_ >= maximumCapacity_) { + LOG_ECMA_MEM(FATAL) << "AddRegionTotList::Committed size " << committedSize_ << " of local space is too big."; + return false; + } + AddRegion(region); + allocator_->CollectFreeObjectSet(region); + IncreaseLiveObjectSize(region->AliveObject()); + return true; +} + +void SharedLocalSpace::FreeBumpPoint() +{ + allocator_->FreeBumpPoint(); +} + +void SharedLocalSpace::Stop() +{ + Region *currentRegion = GetCurrentRegion(); + if (currentRegion != nullptr) { + currentRegion->SetHighWaterMark(currentRegion->GetBegin() + currentRegion->AliveObject()); + } +} + +uintptr_t SharedLocalSpace::Allocate(size_t size, bool isExpand) +{ + auto object = allocator_->Allocate(size); + if (object == 0) { + // Shared Full GC will compress all regions and cannot recognize all threads' region. + if (isExpand && Expand(Runtime::GetInstance()->GetMainThread())) { + object = allocator_->Allocate(size); + } + } + if (object != 0) { + Region::ObjectAddressToRange(object)->IncreaseAliveObject(size); + } + return object; +} + SharedReadOnlySpace::SharedReadOnlySpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity) : Space( heap, heap->GetHeapRegionAllocator(), MemSpaceType::SHARED_READ_ONLY_SPACE, initialCapacity, maximumCapacity) @@ -536,7 +624,7 @@ void SharedHugeObjectSpace::InvokeAllocationInspector(Address object, size_t obj void SharedHugeObjectSpace::CheckAndTriggerLocalFullMark(JSThread *thread, size_t size) { if (committedSize_ >= triggerLocalFullMarkLimit_) { - reinterpret_cast(heap_)->TryTriggerLocalConcurrentMarking(thread); + reinterpret_cast(heap_)->TryTriggerLocalConcurrentMarking(); } else { auto localHeap = const_cast(thread->GetEcmaVM()->GetHeap()); if (!thread->IsJitThread()) { diff --git a/ecmascript/mem/shared_heap/shared_space.h b/ecmascript/mem/shared_heap/shared_space.h index 627e6e89a6..436db1cda9 100644 --- a/ecmascript/mem/shared_heap/shared_space.h +++ b/ecmascript/mem/shared_heap/shared_space.h @@ -42,6 +42,7 @@ namespace panda::ecmascript { #endif class SharedHeap; +class SharedLocalSpace; class SharedSparseSpace : public Space { public: @@ -58,6 +59,7 @@ public: uintptr_t AllocateWithoutGC(JSThread *thread, size_t size); uintptr_t Allocate(JSThread *thread, size_t size, bool allowGC = true); + uintptr_t TryAllocateAndExpand(JSThread *thread, size_t size, bool expand); // For work deserialize void ResetTopPointer(uintptr_t top); @@ -104,46 +106,46 @@ public: return committedSize_ >= maximumCapacity_ + outOfMemoryOvershootSize_; } - void CheckAndTriggerLocalFullMark(JSThread *thread); + void CheckAndTriggerLocalFullMark(); size_t GetTotalAllocatedSize() const; void InvokeAllocationInspector(Address object, size_t size, size_t alignedSize); - template - void EnumerateReclaimRegions(const Callback &cb) const - { - for (Region *current : reclaimRegionList_) { - if (current != nullptr) { - cb(current); - } - } - } + void DetachFreeObjectSet(Region *region); - void ReclaimRegions(); protected: + bool Expand(JSThread *thread); FreeListAllocator *allocator_; SweepState sweepState_ = SweepState::NO_SWEEP; + SharedHeap *sHeap_ {nullptr}; private: static constexpr double LIVE_OBJECT_SIZE_RATIO = 0.8; uintptr_t AllocateWithExpand(JSThread *thread, size_t size); uintptr_t TryAllocate(JSThread *thread, size_t size); - bool Expand(JSThread *thread); // For sweeping uintptr_t AllocateAfterSweepingCompleted(JSThread *thread, size_t size); Mutex lock_; Mutex allocateLock_; - SharedHeap *sHeap_ {nullptr}; std::vector sweepingList_; std::vector sweptList_; - std::set reclaimRegionList_; size_t liveObjectSize_ {0}; size_t triggerLocalFullMarkLimit_ {0}; }; +class SharedAppSpawnSpace : public SharedSparseSpace { +public: + SharedAppSpawnSpace(SharedHeap *heap, size_t initialCapacity); + ~SharedAppSpawnSpace() override = default; + NO_COPY_SEMANTIC(SharedAppSpawnSpace); + NO_MOVE_SEMANTIC(SharedAppSpawnSpace); + + void IterateOverMarkedObjects(const std::function &visitor) const; +}; + class SharedNonMovableSpace : public SharedSparseSpace { public: SharedNonMovableSpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity); @@ -156,8 +158,40 @@ class SharedOldSpace : public SharedSparseSpace { public: SharedOldSpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity); ~SharedOldSpace() override = default; + size_t GetMergeSize() const + { + return mergeSize_; + } + + void IncreaseMergeSize(size_t size) + { + mergeSize_ += size; + } + + void ResetMergeSize() + { + mergeSize_ = 0; + } + + void Merge(SharedLocalSpace *localSpace); NO_COPY_SEMANTIC(SharedOldSpace); NO_MOVE_SEMANTIC(SharedOldSpace); + Mutex lock_; + size_t mergeSize_ {0}; +}; + +class SharedLocalSpace : public SharedSparseSpace { +public: + SharedLocalSpace() = delete; + SharedLocalSpace(SharedHeap *heap, size_t initialCapacity, size_t maximumCapacity); + ~SharedLocalSpace() override = default; + NO_COPY_SEMANTIC(SharedLocalSpace); + NO_MOVE_SEMANTIC(SharedLocalSpace); + + uintptr_t Allocate(size_t size, bool isExpand = true); + bool AddRegionToList(Region *region); + void FreeBumpPoint(); + void Stop(); }; class SharedReadOnlySpace : public Space { diff --git a/ecmascript/mem/space-inl.h b/ecmascript/mem/space-inl.h index 8aedc12b8a..7f1d3db7aa 100644 --- a/ecmascript/mem/space-inl.h +++ b/ecmascript/mem/space-inl.h @@ -99,10 +99,15 @@ RegionSpaceFlag Space::GetRegionFlag() const case MemSpaceType::APPSPAWN_SPACE: flags = RegionSpaceFlag::IN_APPSPAWN_SPACE; break; + case MemSpaceType::SHARED_APPSPAWN_SPACE: + flags = RegionSpaceFlag::IN_SHARED_APPSPAWN_SPACE; + break; case MemSpaceType::SHARED_NON_MOVABLE: flags = RegionSpaceFlag::IN_SHARED_NON_MOVABLE; break; case MemSpaceType::SHARED_OLD_SPACE: + case MemSpaceType::SHARED_LOCAL_SPACE: + case MemSpaceType::SHARED_COMPRESS_SPACE: flags = RegionSpaceFlag::IN_SHARED_OLD_SPACE; break; case MemSpaceType::SHARED_READ_ONLY_SPACE: diff --git a/ecmascript/mem/space.cpp b/ecmascript/mem/space.cpp index 1fc328a90f..b0e09ad247 100644 --- a/ecmascript/mem/space.cpp +++ b/ecmascript/mem/space.cpp @@ -79,7 +79,7 @@ void Space::ClearAndFreeRegion(Region *region, size_t cachedSize) if (spaceType_ == MemSpaceType::OLD_SPACE || spaceType_ == MemSpaceType::NON_MOVABLE || spaceType_ == MemSpaceType::MACHINE_CODE_SPACE || spaceType_ == MemSpaceType::LOCAL_SPACE || spaceType_ == MemSpaceType::APPSPAWN_SPACE || spaceType_ == MemSpaceType::SHARED_NON_MOVABLE || - spaceType_ == MemSpaceType::SHARED_OLD_SPACE) { + spaceType_ == MemSpaceType::SHARED_OLD_SPACE || spaceType_ == MemSpaceType::SHARED_LOCAL_SPACE) { region->DestroyFreeObjectSets(); } // regions of EdenSpace are allocated in EdenSpace constructor and fixed, not allocate by heapRegionAllocator_ diff --git a/ecmascript/mem/space.h b/ecmascript/mem/space.h index f4fdb4a487..bd70c26e42 100644 --- a/ecmascript/mem/space.h +++ b/ecmascript/mem/space.h @@ -40,18 +40,21 @@ enum MemSpaceType { READ_ONLY_SPACE, APPSPAWN_SPACE, HUGE_MACHINE_CODE_SPACE, - SHARED_NON_MOVABLE, SHARED_OLD_SPACE, + SHARED_NON_MOVABLE, SHARED_READ_ONLY_SPACE, SHARED_HUGE_OBJECT_SPACE, + SHARED_LOCAL_SPACE, + SHARED_COMPRESS_SPACE, + SHARED_APPSPAWN_SPACE, SPACE_TYPE_LAST, // Count of different types - SHARED_BEGIN = SHARED_NON_MOVABLE, + SHARED_BEGIN = SHARED_OLD_SPACE, 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_BEGIN = SHARED_OLD_SPACE, + SHARED_SWEEPING_SPACE_END = SHARED_NON_MOVABLE, SHARED_SWEEPING_SPACE_NUM = SHARED_SWEEPING_SPACE_END - SHARED_SWEEPING_SPACE_BEGIN + 1, }; @@ -105,6 +108,12 @@ static inline std::string ToSpaceTypeName(MemSpaceType type) return "shared read only space"; case SHARED_HUGE_OBJECT_SPACE: return "shared huge object space"; + case SHARED_COMPRESS_SPACE: + return "compress space"; + case SHARED_LOCAL_SPACE: + return "shared local space"; + case SHARED_APPSPAWN_SPACE: + return "shared appspawn space"; default: return "unknown space"; } diff --git a/ecmascript/mem/tlab_allocator-inl.h b/ecmascript/mem/tlab_allocator-inl.h index 0e75c47157..c2ce94980a 100644 --- a/ecmascript/mem/tlab_allocator-inl.h +++ b/ecmascript/mem/tlab_allocator-inl.h @@ -139,5 +139,41 @@ bool TlabAllocator::ExpandCompressFromOld(size_t size) } return false; } + +SharedTlabAllocator::SharedTlabAllocator(SharedHeap *sHeap) + : sHeap_(sHeap) +{ + size_t maxOldSpaceCapacity = sHeap->GetOldSpace()->GetMaximumCapacity(); + sLocalSpace_ = new SharedLocalSpace(sHeap, maxOldSpaceCapacity, maxOldSpaceCapacity); +} + +inline void SharedTlabAllocator::Finalize() +{ + sHeap_->MergeToOldSpaceSync(sLocalSpace_); +} + +uintptr_t SharedTlabAllocator::Allocate(size_t size, MemSpaceType space) +{ + uintptr_t result = 0; + switch (space) { + case SHARED_COMPRESS_SPACE: + result = AllocateInCompressSpace(size); + break; + default: + LOG_ECMA(FATAL) << "this branch is unreachable"; + UNREACHABLE(); + } + return result; +} + +uintptr_t SharedTlabAllocator::AllocateInCompressSpace(size_t size) +{ + ASSERT(AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT)) == size); + size = AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT)); + uintptr_t result = sLocalSpace_->Allocate(size, true); + ASSERT(result != 0); + return result; +} + } // namespace panda::ecmascript #endif // ECMASCRIPT_MEM_TLAB_ALLOCATOR_INL_H diff --git a/ecmascript/mem/tlab_allocator.h b/ecmascript/mem/tlab_allocator.h index 3c0b6ec467..77f4445720 100644 --- a/ecmascript/mem/tlab_allocator.h +++ b/ecmascript/mem/tlab_allocator.h @@ -21,7 +21,15 @@ namespace panda::ecmascript { class Heap; -class TlabAllocator { +class TlabAllocatorBase { +public: + TlabAllocatorBase() = default; + ~TlabAllocatorBase() = default; + NO_COPY_SEMANTIC(TlabAllocatorBase); + NO_MOVE_SEMANTIC(TlabAllocatorBase); +}; + +class TlabAllocator : public TlabAllocatorBase { public: TlabAllocator() = delete; inline explicit TlabAllocator(Heap *heap); @@ -53,6 +61,30 @@ private: LocalSpace *localSpace_; }; + +class SharedTlabAllocator : public TlabAllocatorBase { +public: + SharedTlabAllocator() = delete; + inline explicit SharedTlabAllocator(SharedHeap *sHeap); + ~SharedTlabAllocator() + { + delete sLocalSpace_; + } + + NO_COPY_SEMANTIC(SharedTlabAllocator); + NO_MOVE_SEMANTIC(SharedTlabAllocator); + + inline void Finalize(); + + inline uintptr_t Allocate(size_t size, MemSpaceType space); + +private: + inline uintptr_t AllocateInCompressSpace(size_t size); + inline bool ExpandCompressFromOld(size_t size); + + SharedHeap *sHeap_; + SharedLocalSpace *sLocalSpace_; +}; } // namespace panda::ecmascript #endif // ECMASCRIPT_MEM_TLAB_ALLOCATOR_H diff --git a/ecmascript/mem/verification.cpp b/ecmascript/mem/verification.cpp index f3d95f55e2..b9c01712ca 100644 --- a/ecmascript/mem/verification.cpp +++ b/ecmascript/mem/verification.cpp @@ -790,6 +790,14 @@ size_t SharedHeapVerification::VerifyRoot() const []([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base, [[maybe_unused]] ObjectSlot derived, [[maybe_unused]] uintptr_t baseOldObject) { }; + RootVisitor serializeVisitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot slot) { + JSTaggedValue value(slot.GetTaggedType()); + if (!sHeap_->IsAlive(value.GetTaggedObject())) { + LOG_ECMA(ERROR) << "Serialize Heap verify detected a dead object. " << value.GetTaggedObject(); + ++failCount; + } + }; + Runtime::GetInstance()->IterateSerializeRoot(serializeVisitor); Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) { ASSERT(!thread->IsInRunningState()); auto vm = thread->GetEcmaVM(); @@ -813,6 +821,25 @@ size_t SharedHeapVerification::VerifyHeap() const if (failCount > 0) { LOG_GC(ERROR) << "SharedHeap VerifyHeap detects deadObject count is " << failCount; } + VerifyKind localVerifyKind = VerifyKind::VERIFY_END; + if (verifyKind_ == VerifyKind::VERIFY_PRE_SHARED_GC) { + localVerifyKind = VerifyKind::VERIFY_PRE_GC; + } else if (verifyKind_ == VerifyKind::VERIFY_POST_SHARED_GC) { + localVerifyKind = VerifyKind::VERIFY_POST_GC; + } + + Runtime::GetInstance()->GCIterateThreadList([&, localVerifyKind](JSThread *thread) { + ASSERT(!thread->IsInRunningState()); + auto vm = thread->GetEcmaVM(); + auto localHeap = const_cast(vm->GetHeap()); + localHeap->GetSweeper()->EnsureAllTaskFinished(); + if (localVerifyKind != VerifyKind::VERIFY_END) { + Verification(localHeap, localVerifyKind).VerifyAll(); + } + if (failCount > 0) { + LOG_GC(ERROR) << "SharedHeap VerifyRoot detects deadObject in local heap count is " << failCount; + } + }); return failCount; } diff --git a/ecmascript/mem/work_manager.cpp b/ecmascript/mem/work_manager.cpp index bb3c565000..d7ea7852b7 100644 --- a/ecmascript/mem/work_manager.cpp +++ b/ecmascript/mem/work_manager.cpp @@ -154,6 +154,11 @@ void WorkManager::Finish(size_t &aliveSize, size_t &promotedSize) for (uint32_t i = 0; i < threadNum_; i++) { WorkNodeHolder &holder = works_.at(i); promotedSize += holder.promotedSize_; + if (holder.allocator_ != nullptr) { + holder.allocator_->Finalize(); + delete holder.allocator_; + holder.allocator_ = nullptr; + } } initialized_.store(false, std::memory_order_release); } @@ -183,7 +188,7 @@ void WorkManager::Initialize(TriggerGCType gcType, ParallelGCTaskPhase taskPhase SharedGCWorkManager::SharedGCWorkManager(SharedHeap *heap, uint32_t threadNum) : WorkManagerBase(heap->GetNativeAreaAllocator()), sHeap_(heap), threadNum_(threadNum), - continuousQueue_ { nullptr } + continuousQueue_ { nullptr }, sharedTaskPhase_(SHARED_UNDEFINED_TASK) { for (uint32_t i = 0; i < threadNum_; i++) { continuousQueue_.at(i) = new ProcessQueue(); @@ -200,8 +205,9 @@ SharedGCWorkManager::~SharedGCWorkManager() } } -void SharedGCWorkManager::Initialize() +void SharedGCWorkManager::Initialize(TriggerGCType gcType, SharedParallelMarkPhase taskPhase) { + sharedTaskPhase_ = taskPhase; InitializeBase(); for (uint32_t i = 0; i < threadNum_; i++) { SharedGCWorkNodeHolder &holder = works_.at(i); @@ -209,6 +215,9 @@ void SharedGCWorkManager::Initialize() holder.outNode_ = AllocateWorkNode(); holder.weakQueue_ = new ProcessQueue(); holder.weakQueue_->BeginMarking(continuousQueue_.at(i)); + if (gcType == TriggerGCType::SHARED_FULL_GC) { + holder.allocator_ = new SharedTlabAllocator(sHeap_); + } } if (initialized_.load(std::memory_order_acquire)) { LOG_ECMA(FATAL) << "this branch is unreachable"; @@ -217,8 +226,9 @@ void SharedGCWorkManager::Initialize() initialized_.store(true, std::memory_order_release); } -void SharedGCWorkManager::Finish() +size_t SharedGCWorkManager::Finish() { + size_t aliveSize = 0; for (uint32_t i = 0; i < threadNum_; i++) { SharedGCWorkNodeHolder &holder = works_.at(i); if (holder.weakQueue_ != nullptr) { @@ -226,9 +236,16 @@ void SharedGCWorkManager::Finish() delete holder.weakQueue_; holder.weakQueue_ = nullptr; } + aliveSize += holder.aliveSize_; + if (holder.allocator_ != nullptr) { + holder.allocator_->Finalize(); + delete holder.allocator_; + holder.allocator_ = nullptr; + } } FinishBase(); initialized_.store(false, std::memory_order_release); + return aliveSize; } bool SharedGCWorkManager::Push(uint32_t threadId, TaggedObject *object) @@ -263,7 +280,7 @@ void SharedGCWorkManager::PushWorkNodeToGlobal(uint32_t threadId, bool postTask) workStack_.Push(inNode); inNode = AllocateWorkNode(); if (postTask && sHeap_->IsParallelGCEnabled() && sHeap_->CheckCanDistributeTask()) { - sHeap_->PostGCMarkingTask(); + sHeap_->PostGCMarkingTask(sharedTaskPhase_); } } } @@ -274,7 +291,7 @@ void SharedGCWorkManager::PushLocalBufferToGlobal(WorkNode *&node, bool postTask ASSERT(!node->IsEmpty()); workStack_.Push(node); if (postTask && sHeap_->IsParallelGCEnabled() && sHeap_->CheckCanDistributeTask()) { - sHeap_->PostGCMarkingTask(); + sHeap_->PostGCMarkingTask(sharedTaskPhase_); } node = nullptr; } diff --git a/ecmascript/mem/work_manager.h b/ecmascript/mem/work_manager.h index 015069499b..2fed3d807f 100644 --- a/ecmascript/mem/work_manager.h +++ b/ecmascript/mem/work_manager.h @@ -32,6 +32,7 @@ class SharedHeap; class Stack; class SemiSpaceCollector; class TlabAllocator; +class SharedTlabAllocator; class Region; class WorkSpaceChunk; @@ -47,6 +48,13 @@ enum ParallelGCTaskPhase { TASK_LAST // Count of different Task phase }; +enum SharedParallelMarkPhase { + SHARED_MARK_TASK, + SHARED_COMPRESS_TASK, + SHARED_UNDEFINED_TASK, + SHARED_TASK_LAST // Count of different Task phase +}; + class WorkNode { public: explicit WorkNode(Stack *stack) : next_(nullptr), stack_(stack) {} @@ -157,6 +165,11 @@ public: } WorkNode *AllocateWorkNode(); + virtual size_t Finish() + { + LOG_ECMA(FATAL) << " WorkManagerBase Finish"; + return 0; + } Mutex mtx_; private: @@ -177,7 +190,7 @@ public: ~WorkManager() override; void Initialize(TriggerGCType gcType, ParallelGCTaskPhase taskPhase); - size_t Finish(); + size_t Finish() override; void Finish(size_t &aliveSize, size_t &promotedSize); bool Push(uint32_t threadId, TaggedObject *object); @@ -253,6 +266,8 @@ struct SharedGCWorkNodeHolder { WorkNode *inNode_ {nullptr}; WorkNode *outNode_ {nullptr}; ProcessQueue *weakQueue_ {nullptr}; + SharedTlabAllocator *allocator_ {nullptr}; + size_t aliveSize_ = 0; }; class SharedGCWorkManager : public WorkManagerBase { @@ -260,8 +275,18 @@ public: SharedGCWorkManager(SharedHeap *heap, uint32_t threadNum); ~SharedGCWorkManager() override; - void Initialize(); - void Finish(); + void Initialize(TriggerGCType gcType, SharedParallelMarkPhase taskPhase); + size_t Finish() override; + + inline SharedTlabAllocator *GetTlabAllocator(uint32_t threadId) const + { + return works_.at(threadId).allocator_; + } + + inline void IncreaseAliveSize(uint32_t threadId, size_t size) + { + works_.at(threadId).aliveSize_ += size; + } bool Push(uint32_t threadId, TaggedObject *object); bool PushToLocalMarkingBuffer(WorkNode *&markingBuffer, TaggedObject *object); @@ -301,6 +326,7 @@ private: std::array *, MAX_TASKPOOL_THREAD_NUM + 1> continuousQueue_; GlobalWorkStack workStack_; std::atomic initialized_ {false}; + SharedParallelMarkPhase sharedTaskPhase_; }; } // namespace panda::ecmascript #endif // ECMASCRIPT_MEM_WORK_MANAGER_H diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index 4279da149f..ae47f8b5fd 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -301,6 +301,7 @@ Local RegExpRef::GetOriginalSource(const EcmaVM *vm) std::string RegExpRef::GetOriginalFlags([[maybe_unused]] const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, ""); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle regExp(JSNApiHelper::ToJSHandle(this)); JSTaggedValue regExpFlags = regExp->GetOriginalFlags(); uint32_t regExpFlagsInt = static_cast(regExpFlags.GetInt()); @@ -330,6 +331,7 @@ std::string RegExpRef::GetOriginalFlags([[maybe_unused]] const EcmaVM *vm) Local RegExpRef::IsGlobal(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle regExp(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(regExp, FATAL); JSTaggedValue flags = regExp->GetOriginalFlags(); @@ -341,6 +343,7 @@ Local RegExpRef::IsGlobal(const EcmaVM *vm) Local RegExpRef::IsIgnoreCase(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle regExp(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(regExp, FATAL); JSTaggedValue flags = regExp->GetOriginalFlags(); @@ -352,6 +355,7 @@ Local RegExpRef::IsIgnoreCase(const EcmaVM *vm) Local RegExpRef::IsMultiline(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle regExp(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(regExp, FATAL); JSTaggedValue flags = regExp->GetOriginalFlags(); @@ -363,6 +367,7 @@ Local RegExpRef::IsMultiline(const EcmaVM *vm) Local RegExpRef::IsDotAll(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle regExp(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(regExp, FATAL); JSTaggedValue flags = regExp->GetOriginalFlags(); @@ -374,6 +379,7 @@ Local RegExpRef::IsDotAll(const EcmaVM *vm) Local RegExpRef::IsUtf16(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle regExp(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(regExp, FATAL); JSTaggedValue flags = regExp->GetOriginalFlags(); @@ -385,6 +391,7 @@ Local RegExpRef::IsUtf16(const EcmaVM *vm) Local RegExpRef::IsStick(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle regExp(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(regExp, FATAL); JSTaggedValue flags = regExp->GetOriginalFlags(); @@ -395,6 +402,7 @@ Local RegExpRef::IsStick(const EcmaVM *vm) bool GeneratorFunctionRef::IsGenerator(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); // Omit exception check because ark calls here may not // cause side effect even pending exception exists. return IsGeneratorFunction(vm); @@ -403,6 +411,7 @@ bool GeneratorFunctionRef::IsGenerator(const EcmaVM *vm) Local GeneratorObjectRef::GetGeneratorState(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle jsGenerator(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(jsGenerator, FATAL); if (jsGenerator->GetGeneratorState() == JSGeneratorState::COMPLETED) { @@ -414,7 +423,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); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle jsGenerator(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(jsGenerator, FATAL); JSHandle generatorContext(thread, jsGenerator->GetGeneratorContext()); @@ -425,7 +434,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); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle jsGenerator(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(jsGenerator, FATAL); JSHandle generatorContext(thread, jsGenerator->GetGeneratorContext()); @@ -436,7 +445,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); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); #ifdef ARK_SUPPORT_INTL JSHandle jsCollator(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(jsCollator, FATAL); @@ -451,7 +460,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); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); #ifdef ARK_SUPPORT_INTL JSHandle jsDateTimeFormat(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(jsDateTimeFormat, FATAL); @@ -466,7 +475,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); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); #ifdef ARK_SUPPORT_INTL JSHandle jsNumberFormat(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(jsNumberFormat, FATAL); @@ -483,6 +492,7 @@ JSTaggedValue Callback::RegisterCallback(ecmascript::EcmaRuntimeCallInfo *ecmaRu { // Constructor JSThread *thread = ecmaRuntimeCallInfo->GetThread(); + ecmascript::ThreadManagedScope managedScope(thread); JSHandle constructor = BuiltinsBase::GetConstructor(ecmaRuntimeCallInfo); if (!constructor->IsJSFunction()) { return JSTaggedValue::False(); diff --git a/ecmascript/napi/jsnapi_expo.cpp b/ecmascript/napi/jsnapi_expo.cpp index b4a26f3283..bc5f2a92ae 100644 --- a/ecmascript/napi/jsnapi_expo.cpp +++ b/ecmascript/napi/jsnapi_expo.cpp @@ -262,6 +262,7 @@ Local JSValueRef::ToObject(const EcmaVM *vm) Local JSValueRef::ToEcmaObject(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->IsECMAObject()) { @@ -275,10 +276,10 @@ Local JSValueRef::ToEcmaObject(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()) { - ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); obj = JSHandle(JSTaggedValue::ToString(thread, obj)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); } @@ -288,14 +289,16 @@ 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()); // The function just get handle' value, and will not read and write js object. Don't need to switch state. JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); return JSNApiHelper::ToLocal(obj); } -bool JSValueRef::BooleaValue([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::BooleaValue(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).ToBoolean(); } @@ -320,13 +323,13 @@ int64_t JSValueRef::IntegerValue(const EcmaVM *vm) uint32_t JSValueRef::Uint32Value(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle tagged = JSNApiHelper::ToJSHandle(this); uint32_t number = 0; if (!tagged->IsECMAObject()) { number = JSTaggedValue::ToUint32(thread, tagged); } else { // EcmaObject may call [Symbol.toPrimitive]. - ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); number = JSTaggedValue::ToUint32(thread, tagged); } RETURN_VALUE_IF_ABRUPT(thread, 0); @@ -336,13 +339,13 @@ uint32_t JSValueRef::Uint32Value(const EcmaVM *vm) int32_t JSValueRef::Int32Value(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle tagged = JSNApiHelper::ToJSHandle(this); int32_t number = 0; if (!tagged->IsECMAObject()) { number = JSTaggedValue::ToInt32(thread, tagged); } else { // EcmaObject may call [Symbol.toPrimitive]. - ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); number = JSTaggedValue::ToInt32(thread, tagged); } RETURN_VALUE_IF_ABRUPT(thread, 0); @@ -511,8 +514,9 @@ bool JSValueRef::IsNumber() return JSNApiHelper::ToJSTaggedValue(this).IsNumber(); } -bool JSValueRef::IsBigInt([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsBigInt(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsBigInt(); } @@ -531,485 +535,577 @@ bool JSValueRef::IsBoolean() return JSNApiHelper::ToJSTaggedValue(this).IsBoolean(); } -bool JSValueRef::IsString([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsString(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsString(); } -bool JSValueRef::IsSymbol([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsSymbol(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsSymbol(); } -bool JSValueRef::IsObject([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsObject(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsECMAObject(); } -bool JSValueRef::IsArray([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsArray(const EcmaVM *vm) { CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsArray(thread); } -bool JSValueRef::IsJSArray([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSArray(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSArray(); } -bool JSValueRef::IsConstructor([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsConstructor(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedValue value = JSNApiHelper::ToJSTaggedValue(this); return value.IsHeapObject() && value.IsConstructor(); } -bool JSValueRef::IsFunction([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsFunction(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedValue value = JSNApiHelper::ToJSTaggedValue(this); return value.IsCallable(); } -bool JSValueRef::IsJSFunction([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSFunction(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedValue value = JSNApiHelper::ToJSTaggedValue(this); return value.IsJSFunction(); } -bool JSValueRef::IsProxy([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsProxy(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSProxy(); } -bool JSValueRef::IsPromise([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsPromise(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSPromise(); } -bool JSValueRef::IsDataView([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsDataView(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsDataView(); } -bool JSValueRef::IsTypedArray([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsTypedArray(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsTypedArray(); } -bool JSValueRef::IsNativePointer([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsNativePointer(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSNativePointer(); } -bool JSValueRef::IsDate([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsDate(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsDate(); } -bool JSValueRef::IsError([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsError(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSError(); } -bool JSValueRef::IsMap([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsMap(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSMap(); } -bool JSValueRef::IsSet([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsSet(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSet(); } -bool JSValueRef::IsWeakRef([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsWeakRef(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSWeakRef(); } -bool JSValueRef::IsWeakMap([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsWeakMap(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSWeakMap(); } -bool JSValueRef::IsWeakSet([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsWeakSet(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSWeakSet(); } -bool JSValueRef::IsRegExp([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsRegExp(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSRegExp(); } -bool JSValueRef::IsArrayIterator([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsArrayIterator(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSArrayIterator(); } -bool JSValueRef::IsStringIterator([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsStringIterator(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsStringIterator(); } -bool JSValueRef::IsSetIterator([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsSetIterator(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSetIterator(); } -bool JSValueRef::IsMapIterator([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsMapIterator(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSMapIterator(); } -bool JSValueRef::IsArrayBuffer([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsArrayBuffer(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsArrayBuffer(); } -bool JSValueRef::IsBuffer([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsBuffer(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsArrayBuffer(); } -bool JSValueRef::IsUint8Array([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsUint8Array(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSUint8Array(); } -bool JSValueRef::IsInt8Array([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsInt8Array(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSInt8Array(); } -bool JSValueRef::IsUint8ClampedArray([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsUint8ClampedArray(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSUint8ClampedArray(); } -bool JSValueRef::IsInt16Array([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsInt16Array(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSInt16Array(); } -bool JSValueRef::IsUint16Array([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsUint16Array(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSUint16Array(); } -bool JSValueRef::IsInt32Array([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsInt32Array(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSInt32Array(); } -bool JSValueRef::IsUint32Array([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsUint32Array(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSUint32Array(); } -bool JSValueRef::IsFloat32Array([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsFloat32Array(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSFloat32Array(); } -bool JSValueRef::IsFloat64Array([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsFloat64Array(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSFloat64Array(); } -bool JSValueRef::IsBigInt64Array([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsBigInt64Array(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSBigInt64Array(); } -bool JSValueRef::IsBigUint64Array([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsBigUint64Array(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSBigUint64Array(); } -bool JSValueRef::IsJSSharedInt8Array([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSSharedInt8Array(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedInt8Array(); } bool JSValueRef::IsJSSharedUint8Array([[maybe_unused]]const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedUint8Array(); } bool JSValueRef::IsJSSharedUint8ClampedArray([[maybe_unused]]const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedUint8ClampedArray(); } -bool JSValueRef::IsJSSharedInt16Array([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSSharedInt16Array(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedInt16Array(); } -bool JSValueRef::IsJSSharedUint16Array([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSSharedUint16Array(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedUint16Array(); } -bool JSValueRef::IsJSSharedInt32Array([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSSharedInt32Array(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedInt32Array(); } -bool JSValueRef::IsJSSharedFloat32Array([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSSharedFloat32Array(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedFloat32Array(); } -bool JSValueRef::IsJSSharedUint32Array([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSSharedUint32Array(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedUint32Array(); } -bool JSValueRef::IsJSPrimitiveRef([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSPrimitiveRef(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSPrimitiveRef(); } -bool JSValueRef::IsJSPrimitiveNumber([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSPrimitiveNumber(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, FATAL); return JSPrimitiveRef::Cast(obj->GetTaggedObject())->IsNumber(); } -bool JSValueRef::IsJSPrimitiveInt([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSPrimitiveInt(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, FATAL); return JSPrimitiveRef::Cast(obj->GetTaggedObject())->IsInt(); } -bool JSValueRef::IsJSPrimitiveBoolean([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSPrimitiveBoolean(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, FATAL); return JSPrimitiveRef::Cast(obj->GetTaggedObject())->IsBoolean(); } -bool JSValueRef::IsJSPrimitiveString([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSPrimitiveString(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, FATAL); return JSPrimitiveRef::Cast(obj->GetTaggedObject())->IsString(); } -bool JSValueRef::IsJSPrimitiveSymbol([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSPrimitiveSymbol(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, FATAL); return JSPrimitiveRef::Cast(obj->GetTaggedObject())->IsSymbol(); } -bool JSValueRef::IsGeneratorObject([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsGeneratorObject(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsGeneratorObject(); } -bool JSValueRef::IsModuleNamespaceObject([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsModuleNamespaceObject(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsModuleNamespace(); } -bool JSValueRef::IsNativeModuleFailureInfoObject([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsNativeModuleFailureInfoObject(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsNativeModuleFailureInfo(); } -bool JSValueRef::IsSharedArrayBuffer([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsSharedArrayBuffer(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsSharedArrayBuffer(); } -bool JSValueRef::IsSendableArrayBuffer([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsSendableArrayBuffer(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsSendableArrayBuffer(); } -bool JSValueRef::IsJSLocale([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSLocale(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSLocale(); } -bool JSValueRef::IsJSDateTimeFormat([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSDateTimeFormat(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSDateTimeFormat(); } -bool JSValueRef::IsJSRelativeTimeFormat([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSRelativeTimeFormat(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSRelativeTimeFormat(); } -bool JSValueRef::IsJSIntl([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSIntl(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSIntl(); } -bool JSValueRef::IsJSNumberFormat([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSNumberFormat(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSNumberFormat(); } -bool JSValueRef::IsJSCollator([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSCollator(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSCollator(); } -bool JSValueRef::IsJSPluralRules([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSPluralRules(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSPluralRules(); } -bool JSValueRef::IsJSListFormat([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSListFormat(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSListFormat(); } -bool JSValueRef::IsAsyncGeneratorObject([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsAsyncGeneratorObject(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsAsyncGeneratorObject(); } -bool JSValueRef::IsAsyncFunction([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsAsyncFunction(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAsyncFunction(); } -bool JSValueRef::IsConcurrentFunction([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsConcurrentFunction(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle funcVal = JSNApiHelper::ToJSHandle(this); JSHandle transFunc = JSHandle::Cast(funcVal); return transFunc->GetFunctionKind() == ecmascript::FunctionKind::CONCURRENT_FUNCTION; } -bool JSValueRef::IsArgumentsObject([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsArgumentsObject(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsArguments(); } -bool JSValueRef::IsGeneratorFunction([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsGeneratorFunction(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsGeneratorFunction(); } -bool JSValueRef::IsAsyncGeneratorFunction([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsAsyncGeneratorFunction(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsAsyncGeneratorFunction(); } -bool JSValueRef::IsArrayList([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsArrayList(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIArrayList(); } -bool JSValueRef::IsDeque([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsDeque(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIDeque(); } -bool JSValueRef::IsHashMap([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsHashMap(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIHashMap(); } -bool JSValueRef::IsHashSet([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsHashSet(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIHashSet(); } -bool JSValueRef::IsLightWeightMap([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsLightWeightMap(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPILightWeightMap(); } -bool JSValueRef::IsLightWeightSet([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsLightWeightSet(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPILightWeightSet(); } -bool JSValueRef::IsLinkedList([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsLinkedList(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPILinkedList(); } -bool JSValueRef::IsLinkedListIterator([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsLinkedListIterator(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPILinkedListIterator(); } -bool JSValueRef::IsList([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsList(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIList(); } -bool JSValueRef::IsPlainArray([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsPlainArray(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIPlainArray(); } -bool JSValueRef::IsQueue([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsQueue(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIQueue(); } -bool JSValueRef::IsStack([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsStack(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIStack(); } -bool JSValueRef::IsTreeMap([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsTreeMap(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPITreeMap(); } -bool JSValueRef::IsTreeSet([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsTreeSet(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPITreeSet(); } -bool JSValueRef::IsVector([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsVector(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIVector(); } -bool JSValueRef::IsSendableObject([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsSendableObject(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return IsJSShared(vm) && IsObject(vm); } -bool JSValueRef::IsJSShared([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsJSShared(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSShared(); } -bool JSValueRef::IsSharedArray([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsSharedArray(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedArray(); } -bool JSValueRef::IsSharedTypedArray([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsSharedTypedArray(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsSharedTypedArray(); } -bool JSValueRef::IsSharedSet([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsSharedSet(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedSet(); } -bool JSValueRef::IsSharedMap([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsSharedMap(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedMap(); } -bool JSValueRef::IsSharedMapIterator([[maybe_unused]] const EcmaVM *vm) +bool JSValueRef::IsSharedMapIterator(const EcmaVM *vm) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedMapIterator(); } @@ -1020,8 +1116,8 @@ bool JSValueRef::IsHeapObject() void *JSValueRef::GetNativePointerValue(const EcmaVM* vm, bool &isNativePointer) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); if (IsJSShared(vm)) { - ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return GetNativePointerValueImpl(vm, isNativePointer); } else { return GetNativePointerValueImpl(vm, isNativePointer); @@ -1031,6 +1127,7 @@ void *JSValueRef::GetNativePointerValue(const EcmaVM* vm, bool &isNativePointer) // private void *JSValueRef::GetNativePointerValueImpl(const EcmaVM* vm, bool &isNativePointer) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); if (!IsNativePointer(vm)) { isNativePointer = false; return nullptr; @@ -1041,8 +1138,9 @@ void *JSValueRef::GetNativePointerValueImpl(const EcmaVM* vm, bool &isNativePoin return JSHandle(nativePointer)->GetExternalPointer(); } -bool JSValueRef::IsDetachedArraybuffer([[maybe_unused]] const EcmaVM *vm, bool &isArrayBuffer) +bool JSValueRef::IsDetachedArraybuffer(const EcmaVM *vm, bool &isArrayBuffer) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); // arraybuffer is not shared. Do not need to switch state if (!IsArrayBuffer(vm)) { isArrayBuffer = false; @@ -1055,6 +1153,7 @@ bool JSValueRef::IsDetachedArraybuffer([[maybe_unused]] const EcmaVM *vm, bool & void JSValueRef::DetachedArraybuffer(const EcmaVM *vm, bool &isArrayBuffer) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); if (IsArrayBuffer(vm)) { JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); if (arrayBuffer->IsDetach()) { @@ -1081,6 +1180,7 @@ void JSValueRef::GetDataViewInfo(const EcmaVM *vm, JSValueRef **arrayBuffer, size_t *byteOffset) { + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); if (!IsDataView(vm)) { isDataView = false; return; @@ -1093,7 +1193,6 @@ void JSValueRef::GetDataViewInfo(const EcmaVM *vm, } if (data || arrayBuffer) { JSThread* thread = vm->GetJSThread(); - ecmascript::ThreadManagedScope managedScope(thread); JSHandle retArrayBuffer(thread, dataView->GetViewedArrayBuffer()); if (data) { JSTaggedValue bufferData = retArrayBuffer->GetArrayBufferData(); @@ -1302,16 +1401,18 @@ Local MapRef::New(const EcmaVM *vm) return JSNApiHelper::ToLocal(mapTag); } -int32_t MapRef::GetSize([[maybe_unused]] const EcmaVM *vm) +int32_t MapRef::GetSize(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); return map->GetSize(); } -int32_t MapRef::GetTotalElements([[maybe_unused]] const EcmaVM *vm) +int32_t MapRef::GetTotalElements(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); return static_cast((map->GetSize())) + LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())->NumberOfDeletedElements(); @@ -1390,8 +1491,8 @@ Local SendableMapRef::Get(const EcmaVM *vm, Local key) CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); JSHandle map(JSNApiHelper::ToJSHandle(this)); - return JSNApiHelper::ToLocal( - JSHandle(thread, map->Get(thread, JSNApiHelper::ToJSTaggedValue(*key)))); + return JSNApiHelper::ToLocal(JSHandle(thread, + ecmascript::JSSharedMap::Get(thread, map, JSNApiHelper::ToJSTaggedValue(*key)))); } Local SendableMapRef::Get(const EcmaVM *vm, const char *utf8) @@ -1401,7 +1502,7 @@ Local SendableMapRef::Get(const EcmaVM *vm, const char *utf8) JSHandle map(JSNApiHelper::ToJSHandle(this)); ObjectFactory *factory = vm->GetFactory(); JSHandle key(factory->NewFromUtf8(utf8)); - auto result = JSHandle(thread, map->Get(thread, key.GetTaggedValue())); + auto result = JSHandle(thread, ecmascript::JSSharedMap::Get(thread, map, key.GetTaggedValue())); return JSNApiHelper::ToLocal(result); } @@ -1428,7 +1529,7 @@ bool SendableMapRef::Has(const EcmaVM *vm, Local key) CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(thread); JSHandle map(JSNApiHelper::ToJSHandle(this)); - bool result = map->Has(thread, JSNApiHelper::ToJSTaggedValue(*key)); + bool result = ecmascript::JSSharedMap::Has(thread, map, JSNApiHelper::ToJSTaggedValue(*key)); return result; } @@ -1439,7 +1540,7 @@ bool SendableMapRef::Has(const EcmaVM *vm, const char *utf8) JSHandle map(JSNApiHelper::ToJSHandle(this)); ObjectFactory *factory = vm->GetFactory(); JSHandle key(factory->NewFromUtf8(utf8)); - bool result = map->Has(thread, key.GetTaggedValue()); + bool result = ecmascript::JSSharedMap::Has(thread, map, key.GetTaggedValue()); return result; } @@ -1465,15 +1566,16 @@ uint32_t SendableMapRef::GetSize(const EcmaVM *vm) DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); - return map->GetSize(thread); + return ecmascript::JSSharedMap::GetSize(thread, map); } uint32_t SendableMapRef::GetTotalElements(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); - return static_cast((map->GetSize(thread))) + + return static_cast(ecmascript::JSSharedMap::GetSize(thread, map)) + LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())->NumberOfDeletedElements(); } @@ -1483,7 +1585,8 @@ Local SendableMapRef::GetKey(const EcmaVM *vm, int entry) ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(map, FATAL); - return JSNApiHelper::ToLocal(JSHandle(thread, map->GetKey(thread, entry))); + return JSNApiHelper::ToLocal(JSHandle(thread, + ecmascript::JSSharedMap::GetKey(thread, map, entry))); } Local SendableMapRef::GetValue(const EcmaVM *vm, int entry) @@ -1492,7 +1595,8 @@ Local SendableMapRef::GetValue(const EcmaVM *vm, int entry) ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(map, FATAL); - return JSNApiHelper::ToLocal(JSHandle(thread, map->GetValue(thread, entry))); + return JSNApiHelper::ToLocal(JSHandle(thread, + ecmascript::JSSharedMap::GetValue(thread, map, entry))); } Local SendableMapRef::GetEntries(const EcmaVM *vm) @@ -1553,7 +1657,7 @@ uint32_t SendableSetRef::GetSize(const EcmaVM *vm) DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle set(JSNApiHelper::ToJSHandle(this)); - return set->GetSize(thread); + return ecmascript::JSSharedSet::GetSize(thread, set); } uint32_t SendableSetRef::GetTotalElements(const EcmaVM *vm) @@ -1562,7 +1666,7 @@ uint32_t SendableSetRef::GetTotalElements(const EcmaVM *vm) DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle set(JSNApiHelper::ToJSHandle(this)); - return static_cast(set->GetSize(thread)) + + return static_cast(ecmascript::JSSharedSet::GetSize(thread, set)) + LinkedHashSet::Cast(set->GetLinkedSet().GetTaggedObject())->NumberOfDeletedElements(); } @@ -1573,7 +1677,7 @@ Local SendableSetRef::GetValue(const EcmaVM *vm, int entry) JSHandle set(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(set, FATAL); return JSNApiHelper::ToLocal( - JSHandle(thread, set->GetValue(thread, entry))); + JSHandle(thread, ecmascript::JSSharedSet::GetValue(thread, set, entry))); } void SendableSetRef::Add(const EcmaVM *vm, Local value) @@ -1596,6 +1700,7 @@ int32_t MapIteratorRef::GetIndex() Local MapIteratorRef::GetKind(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle jsMapIter(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(jsMapIter, FATAL); IterationKind iterKind = jsMapIter->GetIterationKind(); @@ -1632,6 +1737,7 @@ Local MapIteratorRef::New(const EcmaVM *vm, Local map) ecmascript::EcmaRuntimeCallInfo *MapIteratorRef::GetEcmaRuntimeCallInfo(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, nullptr); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle jsMapIter(JSNApiHelper::ToJSHandle(this)); JSHandle linkedHashMap(vm->GetJSThread(), jsMapIter->GetIteratedMap()); uint32_t size = linkedHashMap->GetLength(); @@ -1682,6 +1788,7 @@ int32_t SetIteratorRef::GetIndex() Local SetIteratorRef::GetKind(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle jsSetIter(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(jsSetIter, FATAL); IterationKind iterKind = jsSetIter->GetIterationKind(); @@ -1718,6 +1825,7 @@ Local SetIteratorRef::New(const EcmaVM *vm, Local set) ecmascript::EcmaRuntimeCallInfo *SetIteratorRef::GetEcmaRuntimeCallInfo(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, nullptr); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle jsSetIter(JSNApiHelper::ToJSHandle(this)); JSHandle linkedHashSet(vm->GetJSThread(), jsSetIter->GetIteratedSet()); uint32_t size = linkedHashSet->GetLength(); @@ -1730,6 +1838,7 @@ ecmascript::EcmaRuntimeCallInfo *SetIteratorRef::GetEcmaRuntimeCallInfo(const Ec Local SetIteratorRef::Next(const EcmaVM *vm, ecmascript::EcmaRuntimeCallInfo *ecmaRuntimeCallInfo) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle nextTagValResult(vm->GetJSThread(), JSSetIterator::Next(ecmaRuntimeCallInfo)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); JSHandle iteratorVal(vm->GetJSThread(), @@ -1782,16 +1891,18 @@ Local BufferRef::New( return JSNApiHelper::ToLocal(JSHandle(arrayBuffer)); } -int32_t BufferRef::ByteLength([[maybe_unused]] const EcmaVM *vm) +int32_t BufferRef::ByteLength(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); return arrayBuffer->GetArrayBufferByteLength(); } -void *BufferRef::GetBuffer([[maybe_unused]] const EcmaVM *vm) +void *BufferRef::GetBuffer(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, nullptr); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); JSTaggedValue bufferData = arrayBuffer->GetArrayBufferData(); if (!bufferData.IsJSNativePointer()) { @@ -1803,6 +1914,7 @@ void *BufferRef::GetBuffer([[maybe_unused]] const EcmaVM *vm) JSTaggedValue BufferRef::BufferToStringCallback(ecmascript::EcmaRuntimeCallInfo *ecmaRuntimeCallInfo) { JSThread *thread = ecmaRuntimeCallInfo->GetThread(); + ecmascript::ThreadManagedScope managedScope(thread); [[maybe_unused]] LocalScope scope(thread->GetEcmaVM()); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle arrayBuff = ecmaRuntimeCallInfo->GetThis(); @@ -2063,21 +2175,24 @@ Local StringRef::NewFromUtf16(const EcmaVM *vm, const char16_t *utf16 return JSNApiHelper::ToLocal(current); } -std::string StringRef::ToString([[maybe_unused]] const EcmaVM *vm) +std::string StringRef::ToString(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, ""); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return EcmaStringAccessor(JSNApiHelper::ToJSTaggedValue(this)).ToStdString(); } -std::string StringRef::DebuggerToString([[maybe_unused]] const EcmaVM *vm) +std::string StringRef::DebuggerToString(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, ""); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return EcmaStringAccessor(JSNApiHelper::ToJSTaggedValue(this)).DebuggerToStdString(); } -uint32_t StringRef::Length([[maybe_unused]] const EcmaVM *vm) +uint32_t StringRef::Length(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return EcmaStringAccessor(JSNApiHelper::ToJSTaggedValue(this)).GetLength(); } @@ -2089,23 +2204,26 @@ int32_t StringRef::Utf8Length(const EcmaVM *vm, bool isGetBufferSize) return EcmaStringAccessor(EcmaStringAccessor::Flatten(vm, strHandle)).GetUtf8Length(isGetBufferSize); } -int StringRef::WriteUtf8([[maybe_unused]] const EcmaVM *vm, char *buffer, int length, bool isWriteBuffer) +int StringRef::WriteUtf8(const EcmaVM *vm, char *buffer, int length, bool isWriteBuffer) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return EcmaStringAccessor(JSNApiHelper::ToJSTaggedValue(this)) .WriteToFlatUtf8(reinterpret_cast(buffer), length, isWriteBuffer); } -int StringRef::WriteUtf16([[maybe_unused]] const EcmaVM *vm, char16_t *buffer, int length) +int StringRef::WriteUtf16(const EcmaVM *vm, char16_t *buffer, int length) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return EcmaStringAccessor(JSNApiHelper::ToJSTaggedValue(this)) .WriteToUtf16(reinterpret_cast(buffer), length); } -int StringRef::WriteLatin1([[maybe_unused]] const EcmaVM *vm, char *buffer, int length) +int StringRef::WriteLatin1(const EcmaVM *vm, char *buffer, int length) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return EcmaStringAccessor(JSNApiHelper::ToJSTaggedValue(this)) .WriteToOneByte(reinterpret_cast(buffer), length); } @@ -2201,9 +2319,10 @@ void BigIntRef::BigIntToUint64(const EcmaVM *vm, uint64_t *value, bool *lossless BigInt::BigIntToUint64(thread, bigintVal, value, lossless); } -void BigIntRef::GetWordsArray([[maybe_unused]] const EcmaVM *vm, bool* signBit, size_t wordCount, uint64_t* words) +void BigIntRef::GetWordsArray(const EcmaVM *vm, bool* signBit, size_t wordCount, uint64_t* words) { DCHECK_SPECIAL_VALUE(this); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle bigintVal(JSNApiHelper::ToJSHandle(this)); uint32_t len = bigintVal->GetLength(); uint32_t count = 0; @@ -2222,9 +2341,10 @@ void BigIntRef::GetWordsArray([[maybe_unused]] const EcmaVM *vm, bool* signBit, *signBit = bigintVal->GetSign(); } -uint32_t BigIntRef::GetWordsArraySize([[maybe_unused]] const EcmaVM *vm) +uint32_t BigIntRef::GetWordsArraySize(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle bigintVal(JSNApiHelper::ToJSHandle(this)); uint32_t len = bigintVal->GetLength(); return len % 2 != 0 ? len / 2 + 1 : len / 2; // 2 : len is odd or even @@ -2842,20 +2962,22 @@ void ObjectRef::SetNativePointerFieldCount(const EcmaVM *vm, int32_t count) object->SetNativePointerFieldCount(thread, count); } -int32_t ObjectRef::GetNativePointerFieldCount([[maybe_unused]] const EcmaVM *vm) +int32_t ObjectRef::GetNativePointerFieldCount(const EcmaVM *vm) { // ObjectRef::New may return special value if exception occurs. // So we need do special value check before use it. DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); return object->GetNativePointerFieldCount(); } -void *ObjectRef::GetNativePointerField([[maybe_unused]] const EcmaVM *vm, int32_t index) +void *ObjectRef::GetNativePointerField(const EcmaVM *vm, int32_t index) { // ObjectRef::New may return special value if exception occurs. // So we need do special value check before use it. DCHECK_SPECIAL_VALUE_WITH_RETURN(this, nullptr); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); return object->GetNativePointerField(index); } @@ -2955,7 +3077,7 @@ Local ArrayBufferRef::New( return JSNApiHelper::ToLocal(JSHandle(arrayBuffer)); } -int32_t ArrayBufferRef::ByteLength([[maybe_unused]] const EcmaVM *vm) +int32_t ArrayBufferRef::ByteLength(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); @@ -2964,9 +3086,10 @@ int32_t ArrayBufferRef::ByteLength([[maybe_unused]] const EcmaVM *vm) return arrayBuffer->GetArrayBufferByteLength(); } -void *ArrayBufferRef::GetBuffer([[maybe_unused]] const EcmaVM *vm) +void *ArrayBufferRef::GetBuffer(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, nullptr); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); JSTaggedValue bufferData = arrayBuffer->GetArrayBufferData(); if (!bufferData.IsJSNativePointer()) { @@ -2978,14 +3101,16 @@ void *ArrayBufferRef::GetBuffer([[maybe_unused]] const EcmaVM *vm) void ArrayBufferRef::Detach(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); // arraybuffer is not shared. Do not need to switch state JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); arrayBuffer->Detach(thread); } -bool ArrayBufferRef::IsDetach([[maybe_unused]] const EcmaVM *vm) +bool ArrayBufferRef::IsDetach(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); return arrayBuffer->IsDetach(); } @@ -3010,7 +3135,7 @@ Local SendableArrayBufferRef::New( return JSNApiHelper::ToLocal(JSHandle(arrayBuffer)); } -int32_t SendableArrayBufferRef::ByteLength([[maybe_unused]] const EcmaVM *vm) +int32_t SendableArrayBufferRef::ByteLength(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); @@ -3027,16 +3152,18 @@ void SendableArrayBufferRef::Detach(const EcmaVM *vm) arrayBuffer->Detach(thread); } -bool SendableArrayBufferRef::IsDetach([[maybe_unused]] const EcmaVM *vm) +bool SendableArrayBufferRef::IsDetach(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, false); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); return arrayBuffer->IsDetach(); } -void *SendableArrayBufferRef::GetBuffer([[maybe_unused]] const EcmaVM *vm) +void *SendableArrayBufferRef::GetBuffer(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, nullptr); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); JSTaggedValue bufferData = arrayBuffer->GetArrayBufferData(); if (!bufferData.IsJSNativePointer()) { @@ -3073,9 +3200,10 @@ Local DateRef::ToString(const EcmaVM *vm) return JSNApiHelper::ToLocal(dateStrHandle); } -double DateRef::GetTime([[maybe_unused]] const EcmaVM *vm) +double DateRef::GetTime(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0.0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle date(JSNApiHelper::ToJSHandle(this)); if (!date->IsDate()) { LOG_ECMA(ERROR) << "Not a Date Object"; @@ -3084,25 +3212,28 @@ double DateRef::GetTime([[maybe_unused]] const EcmaVM *vm) } // ---------------------------------- TypedArray ----------------------------------- -uint32_t TypedArrayRef::ByteLength([[maybe_unused]] const EcmaVM *vm) +uint32_t TypedArrayRef::ByteLength(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(typedArray, FATAL); return typedArray->GetByteLength(); } -uint32_t TypedArrayRef::ByteOffset([[maybe_unused]] const EcmaVM *vm) +uint32_t TypedArrayRef::ByteOffset(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(typedArray, FATAL); return typedArray->GetByteOffset(); } -uint32_t TypedArrayRef::ArrayLength([[maybe_unused]] const EcmaVM *vm) +uint32_t TypedArrayRef::ArrayLength(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(typedArray, FATAL); return typedArray->GetArrayLength(); @@ -3118,25 +3249,28 @@ Local TypedArrayRef::GetArrayBuffer(const EcmaVM *vm) return JSNApiHelper::ToLocal(arrayBuffer); } -uint32_t SendableTypedArrayRef::ByteLength([[maybe_unused]] const EcmaVM *vm) +uint32_t SendableTypedArrayRef::ByteLength(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(typedArray, FATAL); return typedArray->GetByteLength(); } -uint32_t SendableTypedArrayRef::ByteOffset([[maybe_unused]] const EcmaVM *vm) +uint32_t SendableTypedArrayRef::ByteOffset(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(typedArray, FATAL); return typedArray->GetByteOffset(); } -uint32_t SendableTypedArrayRef::ArrayLength([[maybe_unused]] const EcmaVM *vm) +uint32_t SendableTypedArrayRef::ArrayLength(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(typedArray, FATAL); return typedArray->GetArrayLength(); @@ -3227,6 +3361,7 @@ Local FunctionRef::NewConcurrent(EcmaVM *vm, InternalFunctionCallba static void InitClassFunction(EcmaVM *vm, JSHandle &func, bool callNapi) { CROSS_THREAD_CHECK(vm); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle env = vm->GetGlobalEnv(); auto globalConst = thread->GlobalConstants(); JSHandle accessor = globalConst->GetHandledFunctionPrototypeAccessor(); @@ -3630,7 +3765,7 @@ Local ArrayRef::New(const EcmaVM *vm, uint32_t length) return JSNApiHelper::ToLocal(array); } -uint32_t ArrayRef::Length([[maybe_unused]] const EcmaVM *vm) +uint32_t ArrayRef::Length(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); return JSArray::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject())->GetArrayLength(); @@ -3672,9 +3807,10 @@ Local SendableArrayRef::New(const EcmaVM *vm, uint32_t length) return JSNApiHelper::ToLocal(array); } -uint32_t SendableArrayRef::Length([[maybe_unused]] const EcmaVM *vm) +uint32_t SendableArrayRef::Length(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return ecmascript::JSSharedArray::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject())->GetArrayLength(); } @@ -3794,6 +3930,7 @@ JsiFastNativeScope::~JsiFastNativeScope() // ------------------------------------ JsiRuntimeCallInfo ----------------------------------------------- void *JsiRuntimeCallInfo::GetData() { + ecmascript::ThreadManagedScope managedScope(thread_); JSHandle constructor = BuiltinsBase::GetConstructor(reinterpret_cast(this)); if (!constructor->IsJSFunction()) { return nullptr; @@ -5818,16 +5955,18 @@ bool ProxyRef::IsRevoked() } // ---------------------------------- SetRef -------------------------------------- -int32_t SetRef::GetSize([[maybe_unused]] const EcmaVM *vm) +int32_t SetRef::GetSize(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle set(JSNApiHelper::ToJSHandle(this)); return set->GetSize(); } -int32_t SetRef::GetTotalElements([[maybe_unused]] const EcmaVM *vm) +int32_t SetRef::GetTotalElements(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle set(JSNApiHelper::ToJSHandle(this)); return static_cast(set->GetSize()) + LinkedHashSet::Cast(set->GetLinkedSet().GetTaggedObject())->NumberOfDeletedElements(); @@ -5867,16 +6006,18 @@ void SetRef::Add(const EcmaVM *vm, Local value) } // ---------------------------------- WeakMapRef -------------------------------------- -int32_t WeakMapRef::GetSize([[maybe_unused]] const EcmaVM *vm) +int32_t WeakMapRef::GetSize(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle weakMap(JSNApiHelper::ToJSHandle(this)); return weakMap->GetSize(); } -int32_t WeakMapRef::GetTotalElements([[maybe_unused]] const EcmaVM *vm) +int32_t WeakMapRef::GetTotalElements(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle weakMap(JSNApiHelper::ToJSHandle(this)); return weakMap->GetSize() + LinkedHashMap::Cast(weakMap->GetLinkedMap().GetTaggedObject())->NumberOfDeletedElements(); @@ -5934,16 +6075,18 @@ bool WeakMapRef::Has(const EcmaVM *vm, Local key) } // ---------------------------------- WeakSetRef -------------------------------------- -int32_t WeakSetRef::GetSize([[maybe_unused]] const EcmaVM *vm) +int32_t WeakSetRef::GetSize(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle weakSet(JSNApiHelper::ToJSHandle(this)); return weakSet->GetSize(); } -int32_t WeakSetRef::GetTotalElements([[maybe_unused]] const EcmaVM *vm) +int32_t WeakSetRef::GetTotalElements(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle weakSet(JSNApiHelper::ToJSHandle(this)); return weakSet->GetSize() + LinkedHashSet::Cast(weakSet->GetLinkedSet().GetTaggedObject())->NumberOfDeletedElements(); @@ -6038,6 +6181,7 @@ Local ExternalStringCache::GetCachedString(const EcmaVM *vm, uint32_t auto instance = ecmascript::Runtime::GetInstance(); ASSERT(instance != nullptr); + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle str = instance->GetCachedString(vm->GetJSThread(), propertyIndex); return JSNApiHelper::ToLocal(JSHandle(str)); } @@ -6046,7 +6190,7 @@ bool ExternalStringCache::HasCachedString([[maybe_unused]] const EcmaVM *vm, uin { auto instance = ecmascript::Runtime::GetInstance(); ASSERT(instance != nullptr); - + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return instance->HasCachedString(propertyIndex); } } // namespace panda diff --git a/ecmascript/object_factory-inl.h b/ecmascript/object_factory-inl.h index 013dd448f4..d4cedcec80 100644 --- a/ecmascript/object_factory-inl.h +++ b/ecmascript/object_factory-inl.h @@ -34,7 +34,7 @@ EcmaString *ObjectFactory::AllocLineStringObjectNoGC(size_t size) if (size > MAX_REGULAR_HEAP_OBJECT_SIZE) { object = reinterpret_cast(sHeap_->GetHugeObjectSpace()->Allocate(thread_, size)); } else { - object = reinterpret_cast(sHeap_->GetOldSpace()->Allocate(thread_, size, false)); + object = reinterpret_cast(sHeap_->GetOldSpace()->TryAllocateAndExpand(thread_, size, true)); } ASSERT(object != nullptr); object->SetClass(thread_, JSHClass::Cast(thread_->GlobalConstants()->GetLineStringClass().GetTaggedObject())); diff --git a/ecmascript/object_factory.h b/ecmascript/object_factory.h index ba3280616f..db4a15b95c 100644 --- a/ecmascript/object_factory.h +++ b/ecmascript/object_factory.h @@ -873,6 +873,8 @@ public: size_t nativeBindingsize = 0, NativeFlag flag = NativeFlag::NO_DIV); + JSHandle NewSReadOnlyJSNativePointer(void *externalPointer); + JSHandle NewSInternalAccessor(void *setter, void *getter); JSHandle NewSWellKnownSymbol(const JSHandle &name); diff --git a/ecmascript/runtime.cpp b/ecmascript/runtime.cpp index 4d94c584f2..a84000d2b2 100644 --- a/ecmascript/runtime.cpp +++ b/ecmascript/runtime.cpp @@ -334,6 +334,9 @@ void Runtime::ProcessNativeDeleteInSharedGC(const WeakRootVisitor &visitor) freeSharedConstpoolIndex_.insert(constpoolIndex); continue; } + if (fwd != reinterpret_cast(obj)) { + constpoolIter->second = JSTaggedValue(fwd); + } } ++constpoolIter; } diff --git a/ecmascript/runtime.h b/ecmascript/runtime.h index 13a42bcfbc..31a8003d30 100644 --- a/ecmascript/runtime.h +++ b/ecmascript/runtime.h @@ -98,7 +98,19 @@ public: return stringTable_.get(); } - uint32_t PushSerializationRoot([[maybe_unused]] JSThread *thread, std::vector &rootSet) + inline std::pair GetSerializeRootMapValue([[maybe_unused]] JSThread *thread, + uint32_t dataIndex) + { + ASSERT(thread->IsInManagedState()); + LockHolder lock(serializeLock_); + auto iter = serializeRootMap_.find(dataIndex); + if (iter == serializeRootMap_.end()) { + return std::make_pair(nullptr, 0); + } + return std::make_pair(iter->second.data(), iter->second.size()); + } + + uint32_t PushSerializationRoot([[maybe_unused]] JSThread *thread, std::vector &rootSet) { ASSERT(thread->IsInManagedState()); LockHolder lock(serializeLock_); @@ -251,7 +263,7 @@ private: std::unique_ptr heapRegionAllocator_; // for stringTable. std::unique_ptr stringTable_; - std::unordered_map> serializeRootMap_; + std::unordered_map> serializeRootMap_; std::vector serializeDataIndexVector_; // Shared constantpool cache diff --git a/ecmascript/runtime_lock.cpp b/ecmascript/runtime_lock.cpp index 3aa156d3ca..b24f7343b7 100644 --- a/ecmascript/runtime_lock.cpp +++ b/ecmascript/runtime_lock.cpp @@ -16,6 +16,7 @@ #include "ecmascript/runtime_lock.h" #include "ecmascript/checkpoint/thread_state_transition.h" #include "ecmascript/js_thread.h" +#include "ecmascript/mem/heap-inl.h" namespace panda::ecmascript { RuntimeLockHolder::RuntimeLockHolder(JSThread *thread, Mutex &mtx) @@ -24,6 +25,9 @@ RuntimeLockHolder::RuntimeLockHolder(JSThread *thread, Mutex &mtx) if (mtx_.TryLock()) { return; } +#ifndef NDEBUG + SharedHeap::GetInstance()->CollectGarbage(thread_); +#endif ThreadStateTransitionScope ts(thread_); mtx.Lock(); } diff --git a/ecmascript/serializer/base_deserializer.cpp b/ecmascript/serializer/base_deserializer.cpp index 24492fdd45..45ccfea366 100644 --- a/ecmascript/serializer/base_deserializer.cpp +++ b/ecmascript/serializer/base_deserializer.cpp @@ -41,6 +41,24 @@ namespace panda::ecmascript { case (uint8_t)SerializedObjectSpace::SHARED_NON_MOVABLE_SPACE: \ case (uint8_t)SerializedObjectSpace::SHARED_HUGE_SPACE +BaseDeserializer::BaseDeserializer(JSThread *thread, SerializeData *data, void *hint) + : thread_(thread), heap_(const_cast(thread->GetEcmaVM()->GetHeap())), data_(data), engine_(hint) +{ + sheap_ = SharedHeap::GetInstance(); + uint32_t index = data_->GetDataIndex(); + if (index != 0) { + std::pair dataVectorPair = Runtime::GetInstance()->GetSerializeRootMapValue(thread_, + index); + if (dataVectorPair.first == nullptr) { + LOG_ECMA(FATAL) << "Unknown serializer root index: " << index; + UNREACHABLE(); + } + // ValueVector is the pointer to the data from serialize vector and must be const. + valueVector_ = dataVectorPair.first; + vectorSize_ = dataVectorPair.second; + } +} + JSHandle BaseDeserializer::ReadValue() { ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "Deserialize dataSize: " + std::to_string(data_->Size())); @@ -67,7 +85,7 @@ JSHandle BaseDeserializer::DeserializeJSTaggedValue() // initialize concurrent func here for (auto func : concurrentFunctions_) { - func->InitializeForConcurrentFunction(thread_); + JSFunction::InitializeForConcurrentFunction(thread_, func); } concurrentFunctions_.clear(); @@ -95,7 +113,7 @@ uintptr_t BaseDeserializer::DeserializeTaggedObject(SerializedObjectSpace space) { size_t objSize = data_->ReadUint32(position_); uintptr_t res = RelocateObjectAddr(space, objSize); - objectVector_.push_back(res); + objectVector_.push_back(static_cast(res)); DeserializeObjectField(res, res + objSize); return res; } @@ -182,7 +200,8 @@ void BaseDeserializer::HandleNewObjectEncodeFlag(SerializedObjectSpace space, u FunctionKind funcKind = func->GetFunctionKind(); if (funcKind == FunctionKind::CONCURRENT_FUNCTION || object->GetClass()->IsJSSharedFunction()) { // defer initialize concurrent function - concurrentFunctions_.push_back(reinterpret_cast(object)); + JSHandle funcHandle(thread_, func); + concurrentFunctions_.push_back(funcHandle); } func->SetRawProfileTypeInfo(thread_, thread_->GlobalConstants()->GetEmptyProfileTypeInfoCell(), SKIP_BARRIER); func->SetWorkNodePointer(reinterpret_cast(nullptr)); @@ -250,10 +269,10 @@ size_t BaseDeserializer::ReadSingleEncodeData(uint8_t encodeFlag, uintptr_t objA } case (uint8_t)EncodeFlag::REFERENCE: { uint32_t valueIndex = data_->ReadUint32(position_); - uintptr_t valueAddr = objectVector_[valueIndex]; + JSTaggedType valueAddr = objectVector_[valueIndex]; UpdateMaybeWeak(slot, valueAddr, GetAndResetWeak()); WriteBarrier(thread_, reinterpret_cast(objAddr), fieldOffset, - static_cast(valueAddr)); + valueAddr); break; } case (uint8_t)EncodeFlag::WEAK: { @@ -340,7 +359,16 @@ size_t BaseDeserializer::ReadSingleEncodeData(uint8_t encodeFlag, uintptr_t objA break; } case (uint8_t)EncodeFlag::SHARED_OBJECT: { - JSTaggedType value = data_->ReadJSTaggedType(position_); + uint32_t index = data_->ReadUint32(position_); + if (UNLIKELY(valueVector_ == nullptr)) { + LOG_ECMA(FATAL) << "Deserializer valueVector is nullptr."; + UNREACHABLE(); + } + if (UNLIKELY(index >= vectorSize_)) { + LOG_ECMA(FATAL) << "Shared object index invalid, index: " << index << " vectorSize: " << vectorSize_; + UNREACHABLE(); + } + JSTaggedType value = valueVector_[index]; objectVector_.push_back(value); bool isErrorMsg = GetAndResetIsErrorMsg(); if (isErrorMsg) { diff --git a/ecmascript/serializer/base_deserializer.h b/ecmascript/serializer/base_deserializer.h index ce16e30754..261efccc7e 100644 --- a/ecmascript/serializer/base_deserializer.h +++ b/ecmascript/serializer/base_deserializer.h @@ -78,11 +78,8 @@ 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) - { - sheap_ = SharedHeap::GetInstance(); - } + explicit BaseDeserializer(JSThread *thread, SerializeData *data, void *hint = nullptr); + ~BaseDeserializer() { objectVector_.clear(); @@ -225,7 +222,9 @@ private: uintptr_t machineCodeSpaceBeginAddr_ {0}; uintptr_t sOldSpaceBeginAddr_ {0}; uintptr_t sNonMovableSpaceBeginAddr_ {0}; - CVector objectVector_; + JSTaggedType const *valueVector_ {nullptr}; + size_t vectorSize_ {0}; + CVector objectVector_; CVector regionVector_; size_t oldRegionIndex_ {0}; size_t nonMovableRegionIndex_ {0}; @@ -241,7 +240,7 @@ private: bool functionInShared_ {false}; CVector nativeBindingInfos_; CVector jsErrorInfos_; - CVector concurrentFunctions_; + CVector> concurrentFunctions_; size_t position_ {0}; }; } diff --git a/ecmascript/serializer/base_serializer.cpp b/ecmascript/serializer/base_serializer.cpp index 1cc36e93b4..7c3da6334d 100644 --- a/ecmascript/serializer/base_serializer.cpp +++ b/ecmascript/serializer/base_serializer.cpp @@ -39,6 +39,7 @@ SerializedObjectSpace BaseSerializer::GetSerializedObjectSpace(TaggedObject *obj return SerializedObjectSpace::MACHINE_CODE_SPACE; case RegionSpaceFlag::IN_HUGE_OBJECT_SPACE: return SerializedObjectSpace::HUGE_SPACE; + case RegionSpaceFlag::IN_SHARED_APPSPAWN_SPACE: case RegionSpaceFlag::IN_SHARED_OLD_SPACE: return SerializedObjectSpace::SHARED_OLD_SPACE; case RegionSpaceFlag::IN_SHARED_NON_MOVABLE: @@ -101,9 +102,9 @@ bool BaseSerializer::SerializeRootObject(TaggedObject *object) void BaseSerializer::SerializeSharedObject(TaggedObject *object) { data_->WriteEncodeFlag(EncodeFlag::SHARED_OBJECT); - data_->WriteJSTaggedType(reinterpret_cast(object)); + data_->WriteUint32(sharedObjects_.size()); referenceMap_.emplace(object, objectIndex_++); - sharedObjects_.emplace_back(object); + sharedObjects_.emplace_back(static_cast(ToUintPtr(object))); } bool BaseSerializer::SerializeSpecialObjIndividually(JSType objectType, TaggedObject *root, diff --git a/ecmascript/serializer/base_serializer.h b/ecmascript/serializer/base_serializer.h index 8593750989..c0112a9818 100644 --- a/ecmascript/serializer/base_serializer.h +++ b/ecmascript/serializer/base_serializer.h @@ -70,7 +70,7 @@ protected: EcmaVM *vm_; std::unique_ptr data_; CUnorderedMap referenceMap_; - std::vector sharedObjects_; + 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/tests/serializer_test.cpp b/ecmascript/serializer/tests/serializer_test.cpp index 7a7f87ec64..0aea4dae1c 100644 --- a/ecmascript/serializer/tests/serializer_test.cpp +++ b/ecmascript/serializer/tests/serializer_test.cpp @@ -569,7 +569,7 @@ public: EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSSharedSet failed"; EXPECT_TRUE(res->IsJSSharedSet()) << "[NotJSSharedSet] Deserialize JSSharedSet failed"; JSHandle jsSet = JSHandle::Cast(res); - auto size = jsSet->GetSize(thread); + auto size = JSSharedSet::GetSize(thread, jsSet); EXPECT_TRUE(size == INITIALIZE_SIZE); JSSharedSet::Clear(thread, jsSet); Destroy(); @@ -584,10 +584,10 @@ public: EXPECT_TRUE(res->IsJSSharedSet()) << "[NotJSSharedSet] Deserialize JSSharedSet failed"; JSHandle jsSet = JSHandle::Cast(res); - auto size = jsSet->GetSize(thread); + auto size = JSSharedSet::GetSize(thread, jsSet); EXPECT_TRUE(size == INITIALIZE_SIZE); for (int32_t i = 0; i < size; i++) { - EXPECT_TRUE(jsSet->Has(thread, JSTaggedValue(i))); + EXPECT_TRUE(JSSharedSet::Has(thread, jsSet, JSTaggedValue(i))); } JSSharedSet::Add(thread, jsSet, JSHandle(thread, JSTaggedValue(INITIALIZE_SIZE))); bool result = JSSharedSet::Delete(thread, jsSet, JSHandle(thread, JSTaggedValue(0))); @@ -604,29 +604,9 @@ public: EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSSharedSet fail"; EXPECT_TRUE(res->IsJSSharedSet()) << "[NotJSSharedSet] Deserialize JSSharedSet fail"; JSHandle jsSet = JSHandle::Cast(res); - EXPECT_TRUE(jsSet->GetSize(thread) == INITIALIZE_SIZE); + EXPECT_TRUE(JSSharedSet::GetSize(thread, jsSet) == INITIALIZE_SIZE); for (int i = 0; i < INITIALIZE_SIZE; i++) { - EXPECT_TRUE(jsSet->Has(thread, JSTaggedValue(i))); - } - Destroy(); - } - - void JSSharedSetMultiThreadTest2(SerializeData *data, std::pair range, - std::atomic &pendingExceptions) - { - EXPECT_TRUE(data != nullptr); - Init(); - BaseDeserializer deserializer(thread, data); - JSHandle res = deserializer.ReadValue(); - EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSSharedSet fail"; - EXPECT_TRUE(res->IsJSSharedSet()) << "[NotJSSharedSet] Deserialize JSSharedSet fail"; - JSHandle jsSet = JSHandle::Cast(res); - for (int32_t i = range.first; i < range.second; i++) { - JSSharedSet::Add(thread, jsSet, JSHandle(thread, JSTaggedValue(i))); - if (thread->HasPendingException()) { - pendingExceptions++; - break; - } + EXPECT_TRUE(JSSharedSet::Has(thread, jsSet, JSTaggedValue(i))); } Destroy(); } @@ -639,7 +619,7 @@ public: EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSSharedMap failed"; EXPECT_TRUE(res->IsJSSharedMap()) << "[NotJSSharedMap] Deserialize JSSharedMap failed"; JSHandle jsMap = JSHandle::Cast(res); - auto size = jsMap->GetSize(thread); + auto size = JSSharedMap::GetSize(thread, jsMap); EXPECT_TRUE(size == INITIALIZE_SIZE); JSSharedMap::Clear(thread, jsMap); Destroy(); @@ -654,10 +634,10 @@ public: EXPECT_TRUE(res->IsJSSharedMap()) << "[NotJSSharedMap] Deserialize JSSharedMap failed"; JSHandle jsMap = JSHandle::Cast(res); - auto size = jsMap->GetSize(thread); + auto size = JSSharedMap::GetSize(thread, jsMap); EXPECT_TRUE(size == INITIALIZE_SIZE); for (int32_t i = 0; i < size; i++) { - EXPECT_TRUE(jsMap->Has(thread, JSTaggedValue(i))); + EXPECT_TRUE(JSSharedMap::Has(thread, jsMap, JSTaggedValue(i))); } JSSharedMap::Set(thread, jsMap, JSHandle(thread, JSTaggedValue(INITIALIZE_SIZE)), JSHandle(thread, JSTaggedValue(INITIALIZE_SIZE))); @@ -666,27 +646,6 @@ public: Destroy(); } - void JSSharedMapMultiThreadTest(SerializeData *data, std::pair range, - std::atomic &pendingExceptions) - { - EXPECT_TRUE(data != nullptr); - Init(); - BaseDeserializer deserializer(thread, data); - JSHandle res = deserializer.ReadValue(); - EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSSharedMap fail"; - EXPECT_TRUE(res->IsJSSharedMap()) << "[NotJSSharedMap] Deserialize JSSharedMap fail"; - JSHandle jsMap = JSHandle::Cast(res); - for (int32_t i = range.first; i < range.second; i++) { - JSSharedMap::Set(thread, jsMap, JSHandle(thread, JSTaggedValue(i)), - JSHandle(thread, JSTaggedValue(i))); - if (thread->HasPendingException()) { - pendingExceptions++; - break; - } - } - Destroy(); - } - void JSRegexpTest(SerializeData *data) { Init(); @@ -1430,7 +1389,6 @@ HWTEST_F_L0(JSSerializerTest, SerializeNativeBindingObject2) delete serializer; } - HWTEST_F_L0(JSSerializerTest, TestSerializeJSSet) { ObjectFactory *factory = ecmaVm->GetFactory(); @@ -2116,7 +2074,8 @@ JSHandle CreateSObject(JSThread *thread) JSHandle object = factory->NewSharedOldSpaceJSObject(hclass); uint32_t fieldIndex = 0; while (fieldIndex < length) { - object->SetPropertyInlinedProps(thread, fieldIndex++, CreateEmptySObject(thread).GetTaggedValue()); + JSHandle emptyObject = CreateEmptySObject(thread); + object->SetPropertyInlinedProps(thread, fieldIndex++, emptyObject.GetTaggedValue()); } return object; } @@ -2230,26 +2189,26 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSSharedSetBasic1) jsDeserializerTest, data.get()); ThreadSuspensionScope scope(thread); t1.join(); - EXPECT_TRUE(jsSet->GetSize(thread) == 0); + EXPECT_TRUE(JSSharedSet::GetSize(thread, jsSet) == 0); } { for (int i = 0; i < INITIALIZE_SIZE; i++) { JSSharedSet::Add(thread, jsSet, JSHandle(thread, JSTaggedValue(i))); } - EXPECT_TRUE(!jsSet->Has(thread, JSTaggedValue(INITIALIZE_SIZE))); + EXPECT_TRUE(!JSSharedSet::Has(thread, jsSet, JSTaggedValue(INITIALIZE_SIZE))); JSDeserializerTest jsDeserializerTest; // The Deserializer thread will add and delete a element std::thread t1(&JSDeserializerTest::JSSharedSetBasicTest2, jsDeserializerTest, data.get()); ThreadSuspensionScope scope(thread); t1.join(); - EXPECT_TRUE(!jsSet->Has(thread, JSTaggedValue(0))); - EXPECT_TRUE(jsSet->Has(thread, JSTaggedValue(INITIALIZE_SIZE))); + EXPECT_TRUE(!JSSharedSet::Has(thread, jsSet, JSTaggedValue(0))); + EXPECT_TRUE(JSSharedSet::Has(thread, jsSet, JSTaggedValue(INITIALIZE_SIZE))); } delete serializer; }; -HWTEST_F_L0(JSSerializerTest, SerializeMultiThreadJSSharedSet1) +HWTEST_F_L0(JSSerializerTest, SerializeMultiThreadJSSharedSet) { JSHandle jsSet = CreateSSet(thread); ValueSerializer *serializer = new ValueSerializer(thread); @@ -2276,38 +2235,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeMultiThreadJSSharedSet1) delete serializer; }; -HWTEST_F_L0(JSSerializerTest, SerializeMultiThreadJSSharedSet2) -{ - JSHandle jsSet = CreateSSet(thread); - ValueSerializer *serializer = new ValueSerializer(thread); - bool success = serializer->WriteValue(thread, JSHandle(jsSet), - JSHandle(thread, JSTaggedValue::Undefined()), - JSHandle(thread, JSTaggedValue::Undefined())); - EXPECT_TRUE(success) << "Serialize JSSharedSet fail"; - std::unique_ptr data = serializer->Release(); - constexpr uint32_t maxNumDeserialziers = 10; - std::atomic pendingExceptions = 0; - JSDeserializerTest jsDeserializerTests[maxNumDeserialziers]; - std::thread threads[maxNumDeserialziers]; - for (int32_t i = 0; i < maxNumDeserialziers; i++) { - threads[i] = std::thread(&JSDeserializerTest::JSSharedSetMultiThreadTest2, - jsDeserializerTests[i], data.get(), - std::make_pair(i * maxNumDeserialziers, (i + 1) * maxNumDeserialziers), - std::ref(pendingExceptions)); - } - ThreadSuspensionScope scope(thread); - for (int i = 0; i < maxNumDeserialziers; i++) { - threads[i].join(); - } - if (pendingExceptions != 0) { - EXPECT_TRUE(jsSet->GetSize(thread) != maxNumDeserialziers * maxNumDeserialziers); - } else { - EXPECT_TRUE(jsSet->GetSize(thread) == maxNumDeserialziers * maxNumDeserialziers); - } - delete serializer; -}; - -HWTEST_F_L0(JSSerializerTest, SerializeJSSharedMapBasic1) +HWTEST_F_L0(JSSerializerTest, SerializeJSSharedMapBasic) { JSHandle jsMap = CreateSMap(thread); ValueSerializer *serializer = new ValueSerializer(thread); @@ -2327,53 +2255,22 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSSharedMapBasic1) jsDeserializerTest, data.get()); ThreadSuspensionScope scope(thread); t1.join(); - EXPECT_TRUE(jsMap->GetSize(thread) == 0); + EXPECT_TRUE(JSSharedMap::GetSize(thread, jsMap) == 0); } { for (int i = 0; i < INITIALIZE_SIZE; i++) { JSSharedMap::Set(thread, jsMap, JSHandle(thread, JSTaggedValue(i)), JSHandle(thread, JSTaggedValue(i))); } - EXPECT_TRUE(!jsMap->Has(thread, JSTaggedValue(INITIALIZE_SIZE))); + EXPECT_TRUE(!JSSharedMap::Has(thread, jsMap, JSTaggedValue(INITIALIZE_SIZE))); JSDeserializerTest jsDeserializerTest; // The Deserializer thread will add and delete a element std::thread t1(&JSDeserializerTest::JSSharedMapBasicTest2, jsDeserializerTest, data.get()); ThreadSuspensionScope scope(thread); t1.join(); - EXPECT_TRUE(!jsMap->Has(thread, JSTaggedValue(0))); - EXPECT_TRUE(jsMap->Has(thread, JSTaggedValue(INITIALIZE_SIZE))); - } - delete serializer; -}; - -HWTEST_F_L0(JSSerializerTest, SerializeMultiThreadJSSharedMap) -{ - JSHandle jsMap = CreateSMap(thread); - ValueSerializer *serializer = new ValueSerializer(thread); - bool success = serializer->WriteValue(thread, JSHandle(jsMap), - JSHandle(thread, JSTaggedValue::Undefined()), - JSHandle(thread, JSTaggedValue::Undefined())); - EXPECT_TRUE(success) << "Serialize JSSharedMap fail"; - std::unique_ptr data = serializer->Release(); - constexpr uint32_t maxNumDeserialziers = 10; - std::atomic pendingExceptions = 0; - JSDeserializerTest jsDeserializerTests[maxNumDeserialziers]; - std::thread threads[maxNumDeserialziers]; - for (int32_t i = 0; i < maxNumDeserialziers; i++) { - threads[i] = std::thread(&JSDeserializerTest::JSSharedMapMultiThreadTest, - jsDeserializerTests[i], data.get(), - std::make_pair(i * maxNumDeserialziers, (i + 1) * maxNumDeserialziers), - std::ref(pendingExceptions)); - } - ThreadSuspensionScope scope(thread); - for (int i = 0; i < maxNumDeserialziers; i++) { - threads[i].join(); - } - if (pendingExceptions != 0) { - EXPECT_TRUE(jsMap->GetSize(thread) != maxNumDeserialziers * maxNumDeserialziers); - } else { - EXPECT_TRUE(jsMap->GetSize(thread) == maxNumDeserialziers * maxNumDeserialziers); + EXPECT_TRUE(!JSSharedMap::Has(thread, jsMap, JSTaggedValue(0))); + EXPECT_TRUE(JSSharedMap::Has(thread, jsMap, JSTaggedValue(INITIALIZE_SIZE))); } delete serializer; }; diff --git a/ecmascript/serializer/value_serializer.cpp b/ecmascript/serializer/value_serializer.cpp index 1cc827d658..073cb2da13 100644 --- a/ecmascript/serializer/value_serializer.cpp +++ b/ecmascript/serializer/value_serializer.cpp @@ -120,6 +120,12 @@ bool ValueSerializer::WriteValue(JSThread *thread, return false; } SerializeJSTaggedValue(value.GetTaggedValue()); + // ThreadNativeScope may trigger moving gc, so PushSerializationRoot must do before native state. + // Push share root object to runtime map + uint32_t index = data_->GetDataIndex(); + if (!sharedObjects_.empty()) { + index = Runtime::GetInstance()->PushSerializationRoot(thread_, sharedObjects_); + } { ThreadNativeScope nativeScope(thread); for (auto &entry : detachCallbackInfo_) { @@ -128,7 +134,7 @@ bool ValueSerializer::WriteValue(JSThread *thread, if (detachNative == nullptr || entry.first < 0) { LOG_ECMA(ERROR) << "ValueSerialize: SerializeNativeBindingObject detachNative == nullptr"; notSupport_ = true; - return false; + break; } void *buffer = detachNative(info->env, info->nativeValue, info->hint, info->detachData); data_->EmitU64(reinterpret_cast(buffer), static_cast(entry.first)); @@ -137,11 +143,13 @@ bool ValueSerializer::WriteValue(JSThread *thread, if (notSupport_) { LOG_ECMA(ERROR) << "ValueSerialize: serialize data is incomplete"; data_->SetIncompleteData(true); + if (!sharedObjects_.empty()) { + // If notSupport, serializeRoot should be removed. + Runtime::GetInstance()->RemoveSerializationRoot(thread_, index); + } 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(); diff --git a/ecmascript/shared_object_factory.cpp b/ecmascript/shared_object_factory.cpp index 2c55619295..2b353c1b1b 100644 --- a/ecmascript/shared_object_factory.cpp +++ b/ecmascript/shared_object_factory.cpp @@ -52,6 +52,10 @@ void ObjectFactory::NewSObjectHook() const } else { sHeap_->TriggerConcurrentMarking(thread_); } + if (!ecmascript::AnFileDataManager::GetInstance()->IsEnable()) { + sHeap_->WaitGCFinished(thread_); + sHeap_->CollectGarbage(thread_); + } } #endif } @@ -539,20 +543,36 @@ JSHandle ObjectFactory::NewSJSNativePointer(void *externalPoint return obj; } +JSHandle ObjectFactory::NewSReadOnlyJSNativePointer(void* externalPointer) +{ + NewSObjectHook(); + auto jsNativePointerClass = + JSHClass::Cast(thread_->GlobalConstants()->GetSJSNativePointerClass().GetTaggedObject()); + jsNativePointerClass->SetIsJSShared(true); + TaggedObject* header = sHeap_->AllocateReadOnlyOrHugeObject(thread_, jsNativePointerClass); + JSHandle obj(thread_, header); + obj->SetExternalPointer(externalPointer); + obj->SetDeleter(nullptr); + obj->SetData(nullptr); + obj->SetBindingSize(0); + obj->SetNativeFlag(NativeFlag::NO_DIV); + return obj; +} + JSHandle ObjectFactory::NewSInternalAccessor(void *setter, void *getter) { NewSObjectHook(); - TaggedObject *header = sHeap_->AllocateNonMovableOrHugeObject(thread_, + TaggedObject *header = sHeap_->AllocateReadOnlyOrHugeObject(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); + JSHandle setFunc = NewSReadOnlyJSNativePointer(setter); obj->SetSetter(thread_, setFunc.GetTaggedValue()); } if (getter != nullptr) { - JSHandle getFunc = NewSJSNativePointer(getter, nullptr, nullptr, true); + JSHandle getFunc = NewSReadOnlyJSNativePointer(getter); obj->SetGetter(thread_, getFunc); } return obj; diff --git a/ecmascript/shared_objects/concurrent_api_scope.h b/ecmascript/shared_objects/concurrent_api_scope.h index 618390d6bf..cd5dfe390a 100644 --- a/ecmascript/shared_objects/concurrent_api_scope.h +++ b/ecmascript/shared_objects/concurrent_api_scope.h @@ -31,8 +31,8 @@ enum class ModType : uint8_t { template class ConcurrentApiScope final { public: - ConcurrentApiScope(JSThread *thread, const TaggedObject *obj, SCheckMode mode = SCheckMode::CHECK) - : thread_(thread), obj_(obj), checkMode_(mode) + ConcurrentApiScope(JSThread *thread, const JSHandle &objHandle, SCheckMode mode = SCheckMode::CHECK) + : thread_(thread), objHandle_(objHandle), checkMode_(mode) { if (checkMode_ == SCheckMode::SKIP) { return; @@ -64,7 +64,8 @@ private: inline uint32_t GetModRecord() { return reinterpret_cast *>( - ToUintPtr(obj_) + Container::MOD_RECORD_OFFSET)->load(std::memory_order_acquire); + ToUintPtr(objHandle_->GetTaggedObject()) + + Container::MOD_RECORD_OFFSET)->load(std::memory_order_acquire); } inline void CanWrite() @@ -72,8 +73,8 @@ private: // Set to ModType::WRITE, expect no writer and readers constexpr uint32_t expectedModRecord = 0; constexpr uint32_t desiredModRecord = WRITE_MOD_MASK; - uint32_t ret = Barriers::AtomicSetPrimitive(const_cast(obj_), Container::MOD_RECORD_OFFSET, - expectedModRecord, desiredModRecord); + uint32_t ret = Barriers::AtomicSetPrimitive(objHandle_->GetTaggedObject(), + Container::MOD_RECORD_OFFSET, expectedModRecord, desiredModRecord); if (ret != expectedModRecord) { auto error = containers::ContainerError::BusinessError( thread_, containers::ErrorFlag::CONCURRENT_MODIFICATION_ERROR, "Concurrent modification exception"); @@ -85,8 +86,8 @@ private: { constexpr uint32_t expectedModRecord = WRITE_MOD_MASK; constexpr uint32_t desiredModRecord = 0u; - uint32_t ret = Barriers::AtomicSetPrimitive(const_cast(obj_), Container::MOD_RECORD_OFFSET, - expectedModRecord, desiredModRecord); + uint32_t ret = Barriers::AtomicSetPrimitive(objHandle_->GetTaggedObject(), + Container::MOD_RECORD_OFFSET, expectedModRecord, desiredModRecord); if (ret != expectedModRecord) { auto error = containers::ContainerError::BusinessError( thread_, containers::ErrorFlag::CONCURRENT_MODIFICATION_ERROR, "Concurrent modification exception"); @@ -106,8 +107,8 @@ private: } // Increase readers by 1 desiredModRecord_ = expectModRecord_ + 1; - auto ret = Barriers::AtomicSetPrimitive(const_cast(obj_), Container::MOD_RECORD_OFFSET, - expectModRecord_, desiredModRecord_); + auto ret = Barriers::AtomicSetPrimitive(objHandle_->GetTaggedObject(), + Container::MOD_RECORD_OFFSET, expectModRecord_, desiredModRecord_); if (ret == expectModRecord_) { break; } @@ -118,8 +119,8 @@ private: { std::swap(expectModRecord_, desiredModRecord_); while (true) { - auto ret = Barriers::AtomicSetPrimitive(const_cast(obj_), Container::MOD_RECORD_OFFSET, - expectModRecord_, desiredModRecord_); + auto ret = Barriers::AtomicSetPrimitive(objHandle_->GetTaggedObject(), + Container::MOD_RECORD_OFFSET, expectModRecord_, desiredModRecord_); if (ret == expectModRecord_) { break; } @@ -136,7 +137,7 @@ private: } JSThread *thread_ {nullptr}; - const TaggedObject *obj_ {nullptr}; + JSHandle objHandle_; SCheckMode checkMode_ { SCheckMode::CHECK }; // For readers uint32_t expectModRecord_ {0}; diff --git a/ecmascript/shared_objects/js_shared_array.cpp b/ecmascript/shared_objects/js_shared_array.cpp index 408e4253c0..bf47a02e21 100644 --- a/ecmascript/shared_objects/js_shared_array.cpp +++ b/ecmascript/shared_objects/js_shared_array.cpp @@ -36,7 +36,7 @@ using base::ArrayHelper; JSTaggedValue JSSharedArray::LengthGetter([[maybe_unused]] JSThread *thread, const JSHandle &self, SCheckMode checkMode) { - [[maybe_unused]] ConcurrentApiScope scope(thread, self.GetTaggedValue().GetTaggedObject(), + [[maybe_unused]] ConcurrentApiScope scope(thread, JSHandle::Cast(self), checkMode); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); return JSTaggedValue(JSSharedArray::Cast(*self)->GetLength()); @@ -459,7 +459,7 @@ OperationResult JSSharedArray::GetProperty(JSThread *thread, const JSHandle &key, SCheckMode sCheckMode) { // Add Concurrent check for shared array - [[maybe_unused]] ConcurrentApiScope scope(thread, obj.GetTaggedValue().GetTaggedObject(), + [[maybe_unused]] ConcurrentApiScope scope(thread, obj, sCheckMode); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false))); @@ -478,7 +478,7 @@ bool JSSharedArray::SetProperty(JSThread *thread, const JSHandle { // Concurrent check for shared array [[maybe_unused]] ConcurrentApiScope scope( - thread, obj.GetTaggedValue().GetTaggedObject(), sCheckMode); + thread, obj, sCheckMode); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); // 2 ~ 4 findProperty in Receiver, Obj and its parents ObjectOperator op(thread, obj, key); @@ -497,7 +497,7 @@ bool JSSharedArray::SetProperty(JSThread *thread, const JSHandle { // Concurrent check for shared array [[maybe_unused]] ConcurrentApiScope scope( - thread, obj.GetTaggedValue().GetTaggedObject(), sCheckMode); + thread, obj, sCheckMode); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); // 2 ~ 4 findProperty in Receiver, Obj and its parents ObjectOperator op(thread, obj, index); diff --git a/ecmascript/shared_objects/js_shared_array_iterator.cpp b/ecmascript/shared_objects/js_shared_array_iterator.cpp index 8fee58a394..4db7f8c933 100644 --- a/ecmascript/shared_objects/js_shared_array_iterator.cpp +++ b/ecmascript/shared_objects/js_shared_array_iterator.cpp @@ -48,13 +48,11 @@ JSTaggedValue JSSharedArrayIterator::Next(EcmaRuntimeCallInfo *argv) JSHandle iter(thisObj); JSHandle array(thread, iter->GetIteratedArray()); if (array->IsJSSharedArray()) { - JSHandle iteratedArray(thread, iter->GetIteratedArray()); - [[maybe_unused]] ConcurrentApiScope scope(thread, *iteratedArray); + [[maybe_unused]] ConcurrentApiScope scope(thread, array); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); return NextInternal(thread, iter, array); } else if (array->IsSharedTypedArray()) { - JSHandle iteratedArray(thread, iter->GetIteratedArray()); - [[maybe_unused]] ConcurrentApiScope scope(thread, *iteratedArray); + [[maybe_unused]] ConcurrentApiScope scope(thread, array); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); return NextInternal(thread, iter, array); } diff --git a/ecmascript/shared_objects/js_shared_map.cpp b/ecmascript/shared_objects/js_shared_map.cpp index 7567747a3c..8ef48371d0 100644 --- a/ecmascript/shared_objects/js_shared_map.cpp +++ b/ecmascript/shared_objects/js_shared_map.cpp @@ -30,7 +30,7 @@ void JSSharedMap::Set(JSThread *thread, const JSHandle &map, THROW_NEW_ERROR_AND_RETURN(thread, error); } [[maybe_unused]] ConcurrentApiScope scope(thread, - map.GetTaggedValue().GetTaggedObject()); + JSHandle::Cast(map)); RETURN_IF_ABRUPT_COMPLETION(thread); JSHandle mapHandle(thread, LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())); @@ -41,7 +41,7 @@ void JSSharedMap::Set(JSThread *thread, const JSHandle &map, bool JSSharedMap::Delete(JSThread *thread, const JSHandle &map, const JSHandle &key) { [[maybe_unused]] ConcurrentApiScope scope(thread, - map.GetTaggedValue().GetTaggedObject()); + JSHandle::Cast(map)); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); JSHandle mapHandle(thread, LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())); int entry = mapHandle->FindElement(thread, key.GetTaggedValue()); @@ -55,47 +55,47 @@ bool JSSharedMap::Delete(JSThread *thread, const JSHandle &map, con void JSSharedMap::Clear(JSThread *thread, const JSHandle &map) { [[maybe_unused]] ConcurrentApiScope scope(thread, - map.GetTaggedValue().GetTaggedObject()); + JSHandle::Cast(map)); RETURN_IF_ABRUPT_COMPLETION(thread); JSHandle mapHandle(thread, LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())); JSHandle newMap = LinkedHashMap::Clear(thread, mapHandle); map->SetLinkedMap(thread, newMap); } -bool JSSharedMap::Has(JSThread *thread, JSTaggedValue key) const +bool JSSharedMap::Has(JSThread *thread, const JSHandle &map, JSTaggedValue key) { - [[maybe_unused]] ConcurrentApiScope scope(thread, reinterpret_cast(this)); + [[maybe_unused]] ConcurrentApiScope scope(thread, JSHandle::Cast(map)); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); - return LinkedHashMap::Cast(GetLinkedMap().GetTaggedObject())->Has(thread, key); + return LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())->Has(thread, key); } -JSTaggedValue JSSharedMap::Get(JSThread *thread, JSTaggedValue key) const +JSTaggedValue JSSharedMap::Get(JSThread *thread, const JSHandle &map, JSTaggedValue key) { - [[maybe_unused]] ConcurrentApiScope scope(thread, reinterpret_cast(this)); + [[maybe_unused]] ConcurrentApiScope scope(thread, JSHandle::Cast(map)); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Undefined()); - return LinkedHashMap::Cast(GetLinkedMap().GetTaggedObject())->Get(thread, key); + return LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())->Get(thread, key); } -uint32_t JSSharedMap::GetSize(JSThread *thread) const +uint32_t JSSharedMap::GetSize(JSThread *thread, const JSHandle &map) { - [[maybe_unused]] ConcurrentApiScope scope(thread, reinterpret_cast(this)); + [[maybe_unused]] ConcurrentApiScope scope(thread, JSHandle::Cast(map)); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0); - return LinkedHashMap::Cast(GetLinkedMap().GetTaggedObject())->NumberOfElements(); + return LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())->NumberOfElements(); } -JSTaggedValue JSSharedMap::GetKey(JSThread *thread, uint32_t entry) const +JSTaggedValue JSSharedMap::GetKey(JSThread *thread, const JSHandle &map, uint32_t entry) { - [[maybe_unused]] ConcurrentApiScope scope(thread, reinterpret_cast(this)); - ASSERT_PRINT(entry >= 0 && entry < GetSize(thread), "entry must be non-negative integer less than capacity"); + [[maybe_unused]] ConcurrentApiScope scope(thread, JSHandle::Cast(map)); + ASSERT_PRINT(entry >= 0 && entry < GetSize(thread, map), "entry must be non-negative integer less than capacity"); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Undefined()); - return LinkedHashMap::Cast(GetLinkedMap().GetTaggedObject())->GetKey(entry); + return LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())->GetKey(entry); } -JSTaggedValue JSSharedMap::GetValue(JSThread *thread, uint32_t entry) const +JSTaggedValue JSSharedMap::GetValue(JSThread *thread, const JSHandle &map, uint32_t entry) { - [[maybe_unused]] ConcurrentApiScope scope(thread, reinterpret_cast(this)); - ASSERT_PRINT(entry >= 0 && entry < GetSize(thread), "entry must be non-negative integer less than capacity"); + [[maybe_unused]] ConcurrentApiScope scope(thread, JSHandle::Cast(map)); + ASSERT_PRINT(entry >= 0 && entry < GetSize(thread, map), "entry must be non-negative integer less than capacity"); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Undefined()); - return LinkedHashMap::Cast(GetLinkedMap().GetTaggedObject())->GetValue(entry); + return LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())->GetValue(entry); } } // namespace panda::ecmascript diff --git a/ecmascript/shared_objects/js_shared_map.h b/ecmascript/shared_objects/js_shared_map.h index fef19cf947..9b218c8a7f 100644 --- a/ecmascript/shared_objects/js_shared_map.h +++ b/ecmascript/shared_objects/js_shared_map.h @@ -30,15 +30,15 @@ public: const JSHandle &value); static void Clear(JSThread *thread, const JSHandle &map); - bool Has(JSThread *thread, JSTaggedValue key) const; + static bool Has(JSThread *thread, const JSHandle &map, JSTaggedValue key); - JSTaggedValue Get(JSThread *thread, JSTaggedValue key) const; + static JSTaggedValue Get(JSThread *thread, const JSHandle &map, JSTaggedValue key); - uint32_t GetSize(JSThread *thread) const; + static uint32_t GetSize(JSThread *thread, const JSHandle &map); - JSTaggedValue GetKey(JSThread *thread, uint32_t entry) const; + static JSTaggedValue GetKey(JSThread *thread, const JSHandle &map, uint32_t entry); - JSTaggedValue GetValue(JSThread *thread, uint32_t entry) const; + static JSTaggedValue GetValue(JSThread *thread, const JSHandle &map, uint32_t entry); static constexpr size_t LINKED_MAP_OFFSET = JSObject::SIZE; ACCESSORS(LinkedMap, LINKED_MAP_OFFSET, MOD_RECORD_OFFSET) diff --git a/ecmascript/shared_objects/js_shared_map_iterator.cpp b/ecmascript/shared_objects/js_shared_map_iterator.cpp index 0d3d85a49c..5eee069382 100644 --- a/ecmascript/shared_objects/js_shared_map_iterator.cpp +++ b/ecmascript/shared_objects/js_shared_map_iterator.cpp @@ -45,7 +45,7 @@ JSTaggedValue JSSharedMapIterator::NextInternal(JSThread *thread, JSHandle iteratedMap(thread, iter->GetIteratedMap()); - [[maybe_unused]] ConcurrentApiScope scope(thread, *iteratedMap); + [[maybe_unused]] ConcurrentApiScope scope(thread, JSHandle::Cast(iteratedMap)); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); JSHandle map(thread, iteratedMap->GetLinkedMap()); diff --git a/ecmascript/shared_objects/js_shared_set.cpp b/ecmascript/shared_objects/js_shared_set.cpp index 68c74a790f..722ca4b16b 100755 --- a/ecmascript/shared_objects/js_shared_set.cpp +++ b/ecmascript/shared_objects/js_shared_set.cpp @@ -29,7 +29,7 @@ void JSSharedSet::Add(JSThread *thread, const JSHandle &set, const THROW_NEW_ERROR_AND_RETURN(thread, error); } [[maybe_unused]] ConcurrentApiScope scope(thread, - set.GetTaggedValue().GetTaggedObject()); + JSHandle::Cast(set)); RETURN_IF_ABRUPT_COMPLETION(thread); JSHandle setHandle(thread, LinkedHashSet::Cast(set->GetLinkedSet().GetTaggedObject())); @@ -40,7 +40,7 @@ void JSSharedSet::Add(JSThread *thread, const JSHandle &set, const bool JSSharedSet::Delete(JSThread *thread, const JSHandle &set, const JSHandle &value) { [[maybe_unused]] ConcurrentApiScope scope(thread, - set.GetTaggedValue().GetTaggedObject()); + JSHandle::Cast(set)); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); JSHandle setHandle(thread, LinkedHashSet::Cast(set->GetLinkedSet().GetTaggedObject())); int entry = setHandle->FindElement(thread, value.GetTaggedValue()); @@ -54,33 +54,33 @@ bool JSSharedSet::Delete(JSThread *thread, const JSHandle &set, con void JSSharedSet::Clear(JSThread *thread, const JSHandle &set) { [[maybe_unused]] ConcurrentApiScope scope(thread, - set.GetTaggedValue().GetTaggedObject()); + JSHandle::Cast(set)); RETURN_IF_ABRUPT_COMPLETION(thread); JSHandle setHandle(thread, LinkedHashSet::Cast(set->GetLinkedSet().GetTaggedObject())); JSHandle newSet = LinkedHashSet::Clear(thread, setHandle); set->SetLinkedSet(thread, newSet); } -bool JSSharedSet::Has(JSThread *thread, JSTaggedValue value) const +bool JSSharedSet::Has(JSThread *thread, const JSHandle &set, JSTaggedValue value) { - [[maybe_unused]] ConcurrentApiScope scope(thread, reinterpret_cast(this)); + [[maybe_unused]] ConcurrentApiScope scope(thread, JSHandle::Cast(set)); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); - return LinkedHashSet::Cast(GetLinkedSet().GetTaggedObject())->Has(thread, value); + return LinkedHashSet::Cast(set->GetLinkedSet().GetTaggedObject())->Has(thread, value); } -uint32_t JSSharedSet::GetSize(JSThread *thread) const +uint32_t JSSharedSet::GetSize(JSThread *thread, const JSHandle &set) { - [[maybe_unused]] ConcurrentApiScope scope(thread, reinterpret_cast(this)); + [[maybe_unused]] ConcurrentApiScope scope(thread, JSHandle::Cast(set)); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0); - return LinkedHashSet::Cast(GetLinkedSet().GetTaggedObject())->NumberOfElements(); + return LinkedHashSet::Cast(set->GetLinkedSet().GetTaggedObject())->NumberOfElements(); } -JSTaggedValue JSSharedSet::GetValue(JSThread *thread, int entry) const +JSTaggedValue JSSharedSet::GetValue(JSThread *thread, const JSHandle &set, int entry) { - [[maybe_unused]] ConcurrentApiScope scope(thread, reinterpret_cast(this)); - ASSERT_PRINT(entry >= 0 && static_cast(entry) < GetSize(thread), + [[maybe_unused]] ConcurrentApiScope scope(thread, JSHandle::Cast(set)); + ASSERT_PRINT(entry >= 0 && static_cast(entry) < GetSize(thread, set), "entry must be non-negative integer less than capacity"); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Undefined()); - return LinkedHashSet::Cast(GetLinkedSet().GetTaggedObject())->GetValue(entry); + return LinkedHashSet::Cast(set->GetLinkedSet().GetTaggedObject())->GetValue(entry); } } // namespace panda::ecmascript diff --git a/ecmascript/shared_objects/js_shared_set.h b/ecmascript/shared_objects/js_shared_set.h index 5fbd70bc0e..2972d54355 100755 --- a/ecmascript/shared_objects/js_shared_set.h +++ b/ecmascript/shared_objects/js_shared_set.h @@ -30,11 +30,11 @@ public: static void Clear(JSThread *thread, const JSHandle &set); - bool Has(JSThread *thread, JSTaggedValue value) const; + static bool Has(JSThread *thread, const JSHandle &set, JSTaggedValue value); - uint32_t GetSize(JSThread *thread) const; + static uint32_t GetSize(JSThread *thread, const JSHandle &set); - JSTaggedValue GetValue(JSThread *thread, int entry) const; + static JSTaggedValue GetValue(JSThread *thread, const JSHandle &set, int entry); static constexpr size_t LINKED_SET_OFFSET = JSObject::SIZE; ACCESSORS_SYNCHRONIZED(LinkedSet, LINKED_SET_OFFSET, MOD_RECORD_OFFSET) diff --git a/ecmascript/shared_objects/js_shared_set_iterator.cpp b/ecmascript/shared_objects/js_shared_set_iterator.cpp index 8780e6967e..a614d8717e 100755 --- a/ecmascript/shared_objects/js_shared_set_iterator.cpp +++ b/ecmascript/shared_objects/js_shared_set_iterator.cpp @@ -45,7 +45,7 @@ JSTaggedValue JSSharedSetIterator::NextInternal(JSThread *thread, JSHandle iteratedSet(thread, iter->GetIteratedSet()); - [[maybe_unused]] ConcurrentApiScope scope(thread, *iteratedSet); + [[maybe_unused]] ConcurrentApiScope scope(thread, JSHandle::Cast(iteratedSet)); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); JSHandle set(thread, iteratedSet->GetLinkedSet()); diff --git a/ecmascript/snapshot/mem/snapshot_processor.cpp b/ecmascript/snapshot/mem/snapshot_processor.cpp index 7653f4203a..372a3ba2b4 100644 --- a/ecmascript/snapshot/mem/snapshot_processor.cpp +++ b/ecmascript/snapshot/mem/snapshot_processor.cpp @@ -1338,12 +1338,12 @@ void SnapshotProcessor::DeserializeString(uintptr_t stringBegin, uintptr_t strin EcmaStringTable *stringTable = vm_->GetEcmaStringTable(); JSThread *thread = vm_->GetJSThread(); ASSERT(deserializeStringVector_.empty()); - auto oldSpace = sHeap_->GetOldSpace(); auto hugeSpace = sHeap_->GetHugeObjectSpace(); auto globalConst = const_cast(thread->GlobalConstants()); auto lineStringClass = globalConst->GetLineStringClass(); auto constantStringClass = globalConst->GetConstantStringClass(); while (stringBegin < stringEnd) { + // str is from snapshot file, which is in native heap. EcmaString *str = reinterpret_cast(stringBegin); int index = JSTaggedValue(*(reinterpret_cast(str))).GetInt(); if (index == 1) { @@ -1376,7 +1376,7 @@ void SnapshotProcessor::DeserializeString(uintptr_t stringBegin, uintptr_t strin if (UNLIKELY(strSize > MAX_REGULAR_HEAP_OBJECT_SIZE)) { newObj = hugeSpace->Allocate(thread, strSize); } else { - newObj = oldSpace->Allocate(thread, strSize, false); + newObj = sHeap_->GetOldSpace()->TryAllocateAndExpand(thread, strSize, true); } if (newObj == 0) { LOG_ECMA_MEM(FATAL) << "Snapshot Allocate OldSharedSpace OOM"; diff --git a/ecmascript/taskpool/taskpool.h b/ecmascript/taskpool/taskpool.h index b235abc39b..ae7adbe17e 100644 --- a/ecmascript/taskpool/taskpool.h +++ b/ecmascript/taskpool/taskpool.h @@ -21,6 +21,7 @@ #include "ecmascript/common.h" #include "ecmascript/taskpool/runner.h" #include "ecmascript/platform/mutex.h" +#include "ecmascript/daemon/daemon_thread.h" namespace panda::ecmascript { class PUBLIC_API Taskpool { @@ -63,6 +64,13 @@ public: return runner_->IsInThreadPool(id); } + bool PUBLIC_API IsDaemonThreadOrInThreadPool(std::thread::id id) const + { + DaemonThread *dThread = DaemonThread::GetInstance(); + return IsInThreadPool(id) || (dThread != nullptr + && dThread->GetThreadId() == JSThread::GetCurrentThreadId()); + } + void SetThreadPriority(PriorityMode mode) { runner_->SetQosPriority(mode); diff --git a/ecmascript/tests/gc_first_test.cpp b/ecmascript/tests/gc_first_test.cpp index 618177638f..fd636d76f6 100644 --- a/ecmascript/tests/gc_first_test.cpp +++ b/ecmascript/tests/gc_first_test.cpp @@ -174,6 +174,7 @@ HWTEST_F_L0(GCTest, NativeBindingCheckGCTest) HWTEST_F_L0(GCTest, SharedGC) { +#ifdef NDEBUG constexpr size_t ALLOCATE_COUNT = 100; constexpr size_t ALLOCATE_SIZE = 512; ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); @@ -189,7 +190,57 @@ HWTEST_F_L0(GCTest, SharedGC) size_t oldSizeBefore = sHeap->GetOldSpace()->GetHeapObjectSize(); EXPECT_TRUE(oldSizeBefore > oldSizebase); sHeap->CollectGarbage(thread); - sHeap->CollectGarbage(thread); + auto oldSizeAfter = sHeap->GetOldSpace()->GetHeapObjectSize(); + EXPECT_TRUE(oldSizeBefore > oldSizeAfter); + EXPECT_EQ(oldSizebase, oldSizeAfter); +#endif +} + +HWTEST_F_L0(GCTest, SharedFullGC) +{ + constexpr size_t ALLOCATE_COUNT = 100; + constexpr size_t ALLOCATE_SIZE = 512; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + auto sHeap = SharedHeap::GetInstance(); + sHeap->CollectGarbage(thread); + auto oldSizebase = sHeap->GetOldSpace()->GetHeapObjectSize(); + EXPECT_TRUE(oldSizebase > 0); + { + [[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); + EXPECT_TRUE(oldSizeBefore > TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), ALLOCATE_SIZE)); + sHeap->CollectGarbage(thread); + auto oldSizeAfter = sHeap->GetOldSpace()->GetHeapObjectSize(); + EXPECT_TRUE(oldSizeBefore > oldSizeAfter); +} + +HWTEST_F_L0(GCTest, SharedFullGCInAppspawn) +{ + constexpr size_t ALLOCATE_COUNT = 10; + constexpr size_t ALLOCATE_SIZE = 512; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + auto sHeap = SharedHeap::GetInstance(); + sHeap->CompactHeapBeforeFork(thread); + EXPECT_TRUE(sHeap->GetOldSpace()->GetHeapObjectSize() == 0); + 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); + sHeap->GetAppSpawnSpace()->IterateOverMarkedObjects([](TaggedObject *object) { + Region *objectRegion = Region::ObjectAddressToRange(object); + EXPECT_TRUE(objectRegion->InSharedAppSpawnSpace()); + }); auto oldSizeAfter = sHeap->GetOldSpace()->GetHeapObjectSize(); EXPECT_TRUE(oldSizeBefore > oldSizeAfter); EXPECT_EQ(oldSizebase, oldSizeAfter); @@ -204,4 +255,23 @@ HWTEST_F_L0(GCTest, SharedGCSuspendAll) } EXPECT_TRUE(thread->IsInRunningState()); } + +HWTEST_F_L0(GCTest, SerializeGCCheck) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + { + [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread); + JSHandle key1(factory->NewFromASCII("error1")); + JSHandle key2(factory->NewFromASCII("error2")); + JSHandle msg(factory->NewFromASCII("this is error")); + std::vector stringVec; + stringVec.push_back(reinterpret_cast(key1.GetTaggedValue().GetTaggedObject())); + stringVec.push_back(reinterpret_cast(key2.GetTaggedValue().GetTaggedObject())); + stringVec.push_back(reinterpret_cast(msg.GetTaggedValue().GetTaggedObject())); + Runtime::GetInstance()->PushSerializationRoot(thread, stringVec); + } + auto sHeap = SharedHeap::GetInstance(); + sHeap->CollectGarbage(thread); +}; + } // namespace panda::test diff --git a/ecmascript/tests/js_verification_test.cpp b/ecmascript/tests/js_verification_test.cpp index 66f43e6bcb..7153b809ec 100644 --- a/ecmascript/tests/js_verification_test.cpp +++ b/ecmascript/tests/js_verification_test.cpp @@ -81,4 +81,25 @@ HWTEST_F_L0(JSVerificationTest, VerifyHeapObjects) VerifyObjectVisitor objVerifier(heap, &failCount); const_cast(heap->GetNewSpace())->IterateOverObjects(objVerifier); // newspace reference the old space } -} // namespace panda::test + +HWTEST_F_L0(JSVerificationTest, NoBarrierInternalAccessor) +{ + auto ecmaVm = thread->GetEcmaVM(); + auto heap = const_cast(ecmaVm->GetHeap()); + auto objectFactory = ecmaVm->GetFactory(); + EXPECT_EQ(heap->VerifyHeapObjects(), 0U); + size_t failCount = 0; + { + EcmaHandleScope handleScope(thread); + auto newArray = objectFactory->NewTaggedArray(5, JSTaggedValue::Undefined(), MemSpaceType::SEMI_SPACE); + newArray->Set(thread, 0, thread->GlobalConstants()->GetFunctionNameAccessor()); + newArray->Set(thread, 1, thread->GlobalConstants()->GetFunctionPrototypeAccessor()); + newArray->Set(thread, 2, thread->GlobalConstants()->GetFunctionLengthAccessor()); + newArray->Set(thread, 3, thread->GlobalConstants()->GetArrayLengthAccessor()); + newArray->Set(thread, 4, thread->GlobalConstants()->GetSharedArrayLengthAccessor()); + VerifyObjectVisitor(heap, &failCount, VerifyKind::VERIFY_MARK_YOUNG)( + newArray.GetTaggedValue().GetTaggedObject()); + } + EXPECT_EQ(failCount, 0U); +} +} // namespace panda::test diff --git a/libark_jsruntime.map b/libark_jsruntime.map index 96b97179ae..1f949dad94 100644 --- a/libark_jsruntime.map +++ b/libark_jsruntime.map @@ -134,6 +134,7 @@ panda::ecmascript::ClassHelper::MatchFieldType*; panda::ecmascript::ConvertToStdString*; panda::ecmascript::ConvertToString*; + panda::ecmascript::DaemonThread::GetInstance*; panda::ecmascript::Deoptimizier::ComputeShift*; panda::ecmascript::Deoptimizier::DisplayItems*; panda::ecmascript::Deoptimizier::EncodeDeoptVregIndex*; @@ -156,6 +157,7 @@ panda::ecmascript::EcmaStringAccessor::CreateLineString*; panda::ecmascript::EcmaStringAccessor::EcmaStringAccessor*; panda::ecmascript::EcmaStringAccessor::ToStdString*; + panda::ecmascript::EcmaVM::CheckThread*; panda::ecmascript::EcmaVM::GetGlobalEnv*; panda::ecmascript::EcmaVM::IsEnableElementsKind*; panda::ecmascript::EcmaVM::IsEnablePGOProfiler*;