From e5063261bb13340873176d1ea499f85ce4cdb966 Mon Sep 17 00:00:00 2001 From: wengchangcheng Date: Tue, 14 Jan 2025 23:36:47 +0800 Subject: [PATCH] Add interface for NativeBinding Object 1. Add detacherFinalizer in NativeBindingInfo 2. Add GetNativeBindingPointer interface Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IBHTUS Signed-off-by: wengchangcheng Change-Id: Ib917227ac037d904a6964f46dddb86329f43437c --- ecmascript/napi/include/jsnapi_expo.h | 4 +++ ecmascript/napi/jsnapi_expo.cpp | 30 ++++++++++++++++++-- ecmascript/napi/test/jsnapi_first_tests.cpp | 6 ++++ ecmascript/serializer/base_deserializer.cpp | 10 +++---- ecmascript/serializer/base_deserializer.h | 10 +++---- ecmascript/serializer/serialize_data.h | 31 +++++++++++++++++++-- ecmascript/serializer/value_serializer.cpp | 3 ++ 7 files changed, 80 insertions(+), 14 deletions(-) diff --git a/ecmascript/napi/include/jsnapi_expo.h b/ecmascript/napi/include/jsnapi_expo.h index 269e986fd7..446179028b 100644 --- a/ecmascript/napi/include/jsnapi_expo.h +++ b/ecmascript/napi/include/jsnapi_expo.h @@ -542,6 +542,7 @@ public: bool IsString(const EcmaVM *vm); bool IsSymbol(const EcmaVM *vm); bool IsObject(const EcmaVM *vm); + bool IsNativeBindingObject(const EcmaVM *vm); bool IsArray(const EcmaVM *vm); bool IsJSArray(const EcmaVM *vm); bool IsConstructor(const EcmaVM *vm); @@ -831,6 +832,7 @@ public: Local getter, Local setter); bool ConvertToNativeBindingObject(const EcmaVM *vm, Local value); + Local GetNativeBindingPointer(const EcmaVM *vm); bool Set(const EcmaVM *vm, Local key, Local value); bool Set(const EcmaVM *vm, const char *utf8, Local value); bool Set(const EcmaVM *vm, uint32_t key, Local value); @@ -1563,6 +1565,8 @@ public: void *detachFunc = nullptr; void *detachData = nullptr; void *hint = nullptr; + void *detachedFinalizer = nullptr; + void *detachedHint = nullptr; }; // JSVM diff --git a/ecmascript/napi/jsnapi_expo.cpp b/ecmascript/napi/jsnapi_expo.cpp index f14fd36625..f01a8adcca 100644 --- a/ecmascript/napi/jsnapi_expo.cpp +++ b/ecmascript/napi/jsnapi_expo.cpp @@ -536,6 +536,17 @@ bool JSValueRef::IsObject(const EcmaVM *vm) return JSNApiHelper::ToJSTaggedValue(this).IsECMAObject(); } +bool JSValueRef::IsNativeBindingObject(const EcmaVM *vm) +{ + ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); + JSTaggedValue object = JSNApiHelper::ToJSTaggedValue(this); + if (!object.IsECMAObject()) { + return false; + } + + return object.GetTaggedObject()->GetClass()->IsNativeBindingObject(); +} + bool JSValueRef::IsArray(const EcmaVM *vm) { CROSS_THREAD_CHECK(vm); @@ -2643,13 +2654,28 @@ bool ObjectRef::ConvertToNativeBindingObject(const EcmaVM *vm, Local env = vm->GetGlobalEnv(); JSHandle keyValue = env->GetNativeBindingSymbol(); - JSHandle valueValue = JSNApiHelper::ToJSHandle(value); - bool result = JSTaggedValue::SetProperty(thread, object, keyValue, valueValue); + auto key = JSNApiHelper::ToLocal(keyValue); + PropertyAttribute attr(Local(value), true, false, false); + bool result = DefineProperty(vm, key, attr); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); object->GetTaggedObject()->GetClass()->SetIsNativeBindingObject(true); return result; } +Local ObjectRef::GetNativeBindingPointer(const EcmaVM *vm) +{ + CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); + ecmascript::ThreadManagedScope managedScope(thread); + EscapeLocalScope scope(vm); + JSHandle object = JSNApiHelper::ToJSHandle(this); + LOG_IF_SPECIAL(object, ERROR); + JSHandle env = vm->GetGlobalEnv(); + JSHandle keyValue = env->GetNativeBindingSymbol(); + OperationResult ret = JSTaggedValue::GetProperty(thread, object, keyValue); + RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); + return scope.Escape(JSNApiHelper::ToLocal(ret.GetValue())); +} + bool ObjectRef::Set(const EcmaVM *vm, Local key, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); diff --git a/ecmascript/napi/test/jsnapi_first_tests.cpp b/ecmascript/napi/test/jsnapi_first_tests.cpp index e6183887be..dedfecf4fb 100644 --- a/ecmascript/napi/test/jsnapi_first_tests.cpp +++ b/ecmascript/napi/test/jsnapi_first_tests.cpp @@ -518,8 +518,14 @@ HWTEST_F_L0(JSNApiTests, CreateNativeObject) }, nullptr, nativeBindingSize); Local object = ObjectRef::New(vm_); + ASSERT_FALSE(object->IsNativeBindingObject(vm_)); bool result = object->ConvertToNativeBindingObject(vm_, nativeInfo); ASSERT_TRUE(result); + ASSERT_TRUE(object->IsNativeBindingObject(vm_)); + Local nativeInfo1 = object->GetNativeBindingPointer(vm_); + auto info1 = static_cast(nativeInfo1->Value()); + ASSERT_EQ(info, info1); + Local key = StringRef::NewFromUtf8(vm_, "TestKey"); Local value = ObjectRef::New(vm_); PropertyAttribute attribute(value, true, true, true); diff --git a/ecmascript/serializer/base_deserializer.cpp b/ecmascript/serializer/base_deserializer.cpp index 75b01c99fc..65b535d8ff 100644 --- a/ecmascript/serializer/base_deserializer.cpp +++ b/ecmascript/serializer/base_deserializer.cpp @@ -79,11 +79,11 @@ JSHandle BaseDeserializer::DeserializeJSTaggedValue() concurrentFunctions_.clear(); // new native binding object here - for (auto nativeBindingInfo : nativeBindingInfos_) { + for (auto nativeBindingInfo : nativeBindingAttachInfos_) { DeserializeNativeBindingObject(nativeBindingInfo); delete nativeBindingInfo; } - nativeBindingInfos_.clear(); + nativeBindingAttachInfos_.clear(); // new js error here for (auto jsErrorInfo : jsErrorInfos_) { @@ -116,7 +116,7 @@ void BaseDeserializer::DeserializeObjectField(uintptr_t start, uintptr_t end) } } -void BaseDeserializer::DeserializeNativeBindingObject(NativeBindingInfo *info) +void BaseDeserializer::DeserializeNativeBindingObject(NativeBindingAttachInfo *info) { [[maybe_unused]] EcmaHandleScope scope(thread_); AttachFunc af = info->af_; @@ -332,8 +332,8 @@ size_t BaseDeserializer::ReadSingleEncodeData(uint8_t encodeFlag, uintptr_t objA void *hint = reinterpret_cast(data_->ReadJSTaggedType(position_)); void *attachData = reinterpret_cast(data_->ReadJSTaggedType(position_)); // defer new native binding object until deserialize finish - nativeBindingInfos_.push_back(new NativeBindingInfo(af, bufferPointer, hint, attachData, - objAddr, fieldOffset, isRoot)); + nativeBindingAttachInfos_.push_back(new NativeBindingAttachInfo(af, bufferPointer, hint, attachData, + objAddr, fieldOffset, isRoot)); break; } case (uint8_t)EncodeFlag::JS_ERROR: { diff --git a/ecmascript/serializer/base_deserializer.h b/ecmascript/serializer/base_deserializer.h index 56a88fb14f..d93bafefae 100644 --- a/ecmascript/serializer/base_deserializer.h +++ b/ecmascript/serializer/base_deserializer.h @@ -21,7 +21,7 @@ namespace panda::ecmascript { class Heap; class JSThread; -struct NativeBindingInfo { +struct NativeBindingAttachInfo { AttachFunc af_ {nullptr}; void *bufferPointer_ {nullptr}; void *hint_ = {nullptr}; @@ -30,8 +30,8 @@ struct NativeBindingInfo { size_t offset_ {0U}; bool root_ {false}; - NativeBindingInfo(AttachFunc af, void *bufferPointer, void *hint, void *attachData, - uintptr_t objAddr, size_t offset, bool root) : af_(af), bufferPointer_(bufferPointer), + NativeBindingAttachInfo(AttachFunc af, void *bufferPointer, void *hint, void *attachData, + uintptr_t objAddr, size_t offset, bool root) : af_(af), bufferPointer_(bufferPointer), hint_(hint), attachData_(attachData), objAddr_(objAddr), offset_(offset), root_(root) {} uintptr_t GetObjAddr() const @@ -94,7 +94,7 @@ public: private: JSHandle DeserializeJSTaggedValue(); uintptr_t DeserializeTaggedObject(SerializedObjectSpace space); - void DeserializeNativeBindingObject(NativeBindingInfo *info); + void DeserializeNativeBindingObject(NativeBindingAttachInfo *info); void DeserializeJSError(JSErrorInfo *info); uintptr_t RelocateObjectAddr(SerializedObjectSpace space, size_t objSize); JSTaggedType RelocateObjectProtoAddr(uint8_t objectType); @@ -238,7 +238,7 @@ private: bool isErrorMsg_ {false}; void *bufferPointer_ {nullptr}; bool functionInShared_ {false}; - CVector nativeBindingInfos_; + CVector nativeBindingAttachInfos_; CVector jsErrorInfos_; CVector> concurrentFunctions_; size_t position_ {0}; diff --git a/ecmascript/serializer/serialize_data.h b/ecmascript/serializer/serialize_data.h index d2ed8f4ef4..d311dd8a98 100644 --- a/ecmascript/serializer/serialize_data.h +++ b/ecmascript/serializer/serialize_data.h @@ -31,6 +31,18 @@ constexpr uint32_t RESERVED_INDEX = 0; typedef void* (*DetachFunc)(void *enginePointer, void *objPointer, void *hint, void *detachData); typedef Local (*AttachFunc)(void *enginePointer, void *buffer, void *hint, void *attachData); +typedef void (*DetachFinalizer)(void *detachedObject, void *finalizerHint); + +struct NativeBindingDetachInfo { + DetachFinalizer detachedFinalizer = nullptr; + void *detachedObject = nullptr; + void *detachedHint = nullptr; + + NativeBindingDetachInfo(void *df, void *dObj, void *hint) + : detachedFinalizer(reinterpret_cast(df)), detachedObject(dObj), detachedHint(hint) + { + } +}; enum class EncodeFlag : uint8_t { // 0x00~0x06 represent new object to different space: @@ -84,6 +96,14 @@ public: if (sharedArrayBufferSet_.size() > 0) { DecreaseSharedArrayBufferReference(); } + for (const auto &info: nativeBindingDetachInfos_) { + auto finalizer = reinterpret_cast(info->detachedFinalizer); + if (finalizer != nullptr) { + finalizer(info->detachedObject, info->detachedHint); + } + delete info; + } + nativeBindingDetachInfos_.clear(); free(buffer_); if (!incompleteData_ && dataIndex_ != RESERVED_INDEX) { Runtime::GetInstance()->RemoveSerializationRoot(thread_, dataIndex_); @@ -387,6 +407,12 @@ public: return dataIndex_; } + void AddNativeBindingDetachInfo(panda::JSNApi::NativeBindingInfo *info, void *dObj) + { + auto *detachInfo = new NativeBindingDetachInfo(info->detachedFinalizer, dObj, info->detachedHint); + nativeBindingDetachInfos_.insert(detachInfo); + } + private: static constexpr size_t U8_SIZE = 1; static constexpr size_t U16_SIZE = 2; @@ -404,8 +430,9 @@ private: size_t sharedOldSpaceSize_ {0}; size_t sharedNonMovableSpaceSize_ {0}; bool incompleteData_ {false}; - std::vector regionRemainSizeVector_; - std::set sharedArrayBufferSet_; + std::vector regionRemainSizeVector_ {}; + std::set sharedArrayBufferSet_ {}; + std::set nativeBindingDetachInfos_ {}; }; } diff --git a/ecmascript/serializer/value_serializer.cpp b/ecmascript/serializer/value_serializer.cpp index 24821c81e3..ca778d7c4f 100644 --- a/ecmascript/serializer/value_serializer.cpp +++ b/ecmascript/serializer/value_serializer.cpp @@ -134,6 +134,9 @@ bool ValueSerializer::WriteValue(JSThread *thread, break; } void *buffer = detachNative(info->env, info->nativeValue, info->hint, info->detachData); + if (info->detachedFinalizer != nullptr) { + data_->AddNativeBindingDetachInfo(info, buffer); + } data_->EmitU64(reinterpret_cast(buffer), static_cast(entry.first)); } } -- Gitee