/* * Copyright (c) 2021 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 "ark_native_object.h" #include "ark_headers.h" #include "ark_native_array.h" #include "ark_native_external.h" #include "ark_native_function.h" #include "ark_native_reference.h" #include "ark_native_string.h" #include "native_engine/native_property.h" #include "utils/log.h" using panda::ObjectRef; using panda::StringRef; using panda::NativePointerRef; using panda::ArrayRef; using panda::PropertyAttribute; ArkNativeObject::ArkNativeObject(ArkNativeEngine* engine) : ArkNativeObject(engine, JSValueRef::Undefined(engine->GetEcmaVm())) { auto vm = engine->GetEcmaVm(); LocalScope scope(vm); Local object = ObjectRef::New(vm); value_ = Global(vm, object); } ArkNativeObject::ArkNativeObject(ArkNativeEngine* engine, Local value) : ArkNativeValue(engine, value) {} void* ArkNativeObject::DetachFuncCallback(void* engine, void* object, void* hint, void* detachData) { if (detachData == nullptr || (engine == nullptr || object ==nullptr)) { HILOG_ERROR("DetachFuncCallback params has nullptr"); return nullptr; } DetachCallback detach = reinterpret_cast(detachData); void* detachVal = detach(reinterpret_cast(engine), object, hint); return detachVal; } Local ArkNativeObject::AttachFuncCallback(void* engine, void* buffer, void* hint, void* attachData) { panda::EscapeLocalScope scope(reinterpret_cast(engine)->GetEcmaVm()); if (attachData == nullptr || (engine == nullptr || buffer ==nullptr)) { HILOG_ERROR("AttachFuncCallback params has nullptr"); } AttachCallback attach = reinterpret_cast(attachData); NativeValue* attachVal = attach(reinterpret_cast(engine), buffer, hint); Global result = *attachVal; return scope.Escape(result.ToLocal(reinterpret_cast(engine)->GetEcmaVm())); } ArkNativeObject::~ArkNativeObject() {} bool ArkNativeObject::ConvertToNativeBindingObject( void* engine, DetachCallback detachData, AttachCallback attachData, void *object, void *hint) { if (detachData == nullptr || (attachData == nullptr || object == nullptr)) { HILOG_ERROR("ConvertToNativeBindingObject params has nullptr"); return false; } auto vm = reinterpret_cast(engine)->GetEcmaVm(); Global obj = value_; bool res = obj->Set(vm, reinterpret_cast(DetachFuncCallback), reinterpret_cast(AttachFuncCallback)); this->SetNativeBindingPointer( engine, object, hint, reinterpret_cast(detachData), reinterpret_cast(attachData)); return res; } void* ArkNativeObject::GetInterface(int interfaceId) { return (NativeObject::INTERFACE_ID == interfaceId) ? (NativeObject*)this : nullptr; } void ArkNativeObject::SetNativePointer(void* pointer, NativeFinalize cb, void* hint, NativeReference** reference, size_t nativeBindingSize) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global value = value_; Local key = StringRef::GetNapiWrapperString(vm); if (pointer == nullptr && value->Has(vm, key)) { Local wrapper = value->Get(vm, key); auto ref = reinterpret_cast(wrapper->GetNativePointerField(0)); // Try to remove native pointer from ArrayDataList ASSERT(nativeBindingSize == 0); wrapper->SetNativePointerField(0, nullptr, nullptr, nullptr, nativeBindingSize); value->Delete(vm, key); delete ref; } else { Local object = ObjectRef::New(vm); ArkNativeReference* ref = nullptr; if (reference != nullptr) { ref = new ArkNativeReference(engine_, this, 1, false, cb, pointer, hint); *reference = ref; } else { ref = new ArkNativeReference(engine_, this, 0, true, cb, pointer, hint); } object->SetNativePointerFieldCount(1); object->SetNativePointerField(0, ref, nullptr, nullptr, nativeBindingSize); PropertyAttribute attr(object, true, false, true); value->DefineProperty(vm, key, attr); } } void* ArkNativeObject::GetNativePointer() { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global value = value_; Local key = StringRef::GetNapiWrapperString(vm); Local val = value->Get(vm, key); void* result = nullptr; if (val->IsObject()) { Local ext(val); auto ref = reinterpret_cast(ext->GetNativePointerField(0)); result = ref != nullptr ? ref->GetData() : nullptr; } return result; } void ArkNativeObject::SetNativeBindingPointer( void *enginePointer, void *objPointer, void *hint, void *detachData, void *attachData) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global value = value_; Local object = Local(value.ToLocal(vm)); object->SetNativePointerFieldCount(5); // 5 : NativeEngine, NativeObject, hint, detachData, attachData object->SetNativePointerField(0, enginePointer, nullptr, nullptr); object->SetNativePointerField(1, objPointer, nullptr, nullptr); object->SetNativePointerField(2, hint, nullptr, nullptr); // 2 : hint object->SetNativePointerField(3, detachData, nullptr, nullptr); // 3 : detachData object->SetNativePointerField(4, attachData, nullptr, nullptr); // 4 : attachData } void* ArkNativeObject::GetNativeBindingPointer(uint32_t index) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global value = value_; uint32_t paramCount = static_cast(value->GetNativePointerFieldCount()); if (index >= paramCount) { HILOG_ERROR("index more than nativebindingpointer count"); return nullptr; } return value->GetNativePointerField(index); } NativeValue* ArkNativeObject::GetPropertyNames() { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global val = value_; Local arrayVal = val->GetOwnPropertyNames(vm); NativeChunk& chunk = engine_->GetNativeChunk(); return chunk.New(engine_, arrayVal); } NativeValue* ArkNativeObject::GetEnumerablePropertyNames() { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global val = value_; Local arrayVal = val->GetOwnEnumerablePropertyNames(vm); NativeChunk& chunk = engine_->GetNativeChunk(); return chunk.New(engine_, arrayVal); } NativeValue* ArkNativeObject::GetPrototype() { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global obj = value_; Local val = obj->GetPrototype(vm); return ArkNativeEngine::ArkValueToNativeValue(engine_, val); } bool ArkNativeObject::DefineProperty(NativePropertyDescriptor propertyDescriptor) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global obj = value_; bool result = false; Local propertyName = StringRef::NewFromUtf8(vm, propertyDescriptor.utf8name); bool writable = (propertyDescriptor.attributes & NATIVE_WRITABLE) != 0; bool enumable = (propertyDescriptor.attributes & NATIVE_ENUMERABLE) != 0; bool configable = (propertyDescriptor.attributes & NATIVE_CONFIGURABLE) != 0; NativeScopeManager* scopeManager = engine_->GetScopeManager(); if (scopeManager == nullptr) { HILOG_ERROR("scope manager is null"); return false; } NativeScope* nativeScope = scopeManager->Open(); std::string fullName(""); #ifdef ENABLE_HITRACE fullName += GetModuleName(); #endif NativeChunk& chunk = engine_->GetNativeChunk(); if (propertyDescriptor.getter != nullptr || propertyDescriptor.setter != nullptr) { Local localGetter = JSValueRef::Undefined(vm); Local localSetter = JSValueRef::Undefined(vm); if (propertyDescriptor.getter != nullptr) { fullName += "getter"; NativeValue* getter = chunk.New( engine_, fullName.c_str(), 0, propertyDescriptor.getter, propertyDescriptor.data); Global globalGetter = *getter; localGetter = globalGetter.ToLocal(vm); } if (propertyDescriptor.setter != nullptr) { fullName += "setter"; NativeValue* setter = chunk.New( engine_, fullName.c_str(), 0, propertyDescriptor.setter, propertyDescriptor.data); Global globalSetter = *setter; localSetter = globalSetter.ToLocal(vm); } PropertyAttribute attr(JSValueRef::Undefined(engine_->GetEcmaVm()), false, enumable, configable); result = obj->SetAccessorProperty(vm, propertyName, localGetter, localSetter, attr); } else if (propertyDescriptor.method != nullptr) { fullName += propertyDescriptor.utf8name; NativeValue* cb = chunk.New(engine_, fullName.c_str(), 0, propertyDescriptor.method, propertyDescriptor.data); Global globalCb = *cb; PropertyAttribute attr(globalCb.ToLocal(vm), writable, enumable, configable); result = obj->DefineProperty(vm, propertyName, attr); } else { Global value = *(propertyDescriptor.value); PropertyAttribute attr(value.ToLocal(vm), writable, enumable, configable); result = obj->DefineProperty(vm, propertyName, attr); } Local excep = panda::JSNApi::GetUncaughtException(vm); if (!excep.IsNull()) { HILOG_ERROR("ArkNativeObject::DefineProperty occur Exception"); panda::JSNApi::GetAndClearUncaughtException(vm); } scopeManager->Close(nativeScope); return result; } bool ArkNativeObject::SetProperty(NativeValue* key, NativeValue* value) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global obj = value_; Global k = *key; Global val = *value; return obj->Set(vm, k.ToLocal(vm), val.ToLocal(vm)); } NativeValue* ArkNativeObject::GetProperty(NativeValue* key) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global k = *key; Global obj = value_; Local val = obj->Get(vm, k.ToLocal(vm)); return ArkNativeEngine::ArkValueToNativeValue(engine_, val); } bool ArkNativeObject::HasProperty(NativeValue* key) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global obj = value_; Global k = *key; return obj->Has(vm, k.ToLocal(vm)); } bool ArkNativeObject::DeleteProperty(NativeValue* key) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global k = *key; Global obj = value_; return obj->Delete(vm, k.ToLocal(vm)); } bool ArkNativeObject::SetProperty(const char* name, NativeValue* value) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global obj = value_; Local key = StringRef::NewFromUtf8(vm, name); Global val = *value; return obj->Set(vm, key, val.ToLocal(vm)); } NativeValue* ArkNativeObject::GetProperty(const char* name) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Local key = StringRef::NewFromUtf8(vm, name); Global obj = value_; Local val = obj->Get(vm, key); return ArkNativeEngine::ArkValueToNativeValue(engine_, val); } NativeValue* ArkNativeObject::GetOwnProperty(const char* name) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Local key = StringRef::NewFromUtf8(vm, name); Global obj = value_; PropertyAttribute property; obj->GetOwnProperty(vm, key, property); return ArkNativeEngine::ArkValueToNativeValue(engine_, property.GetValue(vm)); } bool ArkNativeObject::HasProperty(const char* name) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Local key = StringRef::NewFromUtf8(vm, name); Global obj = value_; return obj->Has(vm, key); } bool ArkNativeObject::DeleteProperty(const char* name) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Local key = StringRef::NewFromUtf8(vm, name); Global obj = value_; return obj->Delete(vm, key); } bool ArkNativeObject::SetPrivateProperty(const char* name, NativeValue* value) { return false; } NativeValue* ArkNativeObject::GetPrivateProperty(const char* name) { return nullptr; } bool ArkNativeObject::HasPrivateProperty(const char* name) { return false; } bool ArkNativeObject::DeletePrivateProperty(const char* name) { return false; } NativeValue* ArkNativeObject::GetAllPropertyNames( napi_key_collection_mode keyMode, napi_key_filter keyFilter, napi_key_conversion keyConversion) { uint32_t filter = NATIVE_DEFAULT; if (keyFilter & napi_key_writable) { filter = static_cast(filter | NATIVE_WRITABLE); } if (keyFilter & napi_key_enumerable) { filter = static_cast(filter | NATIVE_ENUMERABLE); } if (keyFilter & napi_key_configurable) { filter = static_cast(filter | NATIVE_CONFIGURABLE); } if (keyFilter & napi_key_skip_strings) { filter = static_cast(filter | NATIVE_KEY_SKIP_STRINGS); } if (keyFilter & napi_key_skip_symbols) { filter = static_cast(filter | NATIVE_KEY_SKIP_SYMBOLS); } switch (keyMode) { case napi_key_include_prototypes: filter = static_cast(filter | NATIVE_KEY_INCLUDE_PROTOTYPES); break; case napi_key_own_only: filter = static_cast(filter | NATIVE_KEY_OWN_ONLY); break; default: return nullptr; } switch (keyConversion) { case napi_key_keep_numbers: filter = static_cast(filter | NATIVE_KEY_KEEP_NUMBERS); break; case napi_key_numbers_to_strings: filter = static_cast(filter | NATIVE_KEY_NUMBERS_TO_STRINGS); break; default: return nullptr; } auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global val = value_; Local arrayVal = val->GetAllPropertyNames(vm, filter); NativeChunk& chunk = engine_->GetNativeChunk(); return chunk.New(engine_, arrayVal); } bool ArkNativeObject::AssociateTypeTag(NapiTypeTag* typeTag) { const char name[] = "ACENAPI_TYPETAG"; bool result = false; bool hasPribate = false; hasPribate = HasProperty(name); if (!hasPribate) { auto resultValue = engine_->CreateBigWords( 0, 2, reinterpret_cast(typeTag)); // 2: Indicates that the number of elements is 2 result = this->SetProperty(name, resultValue); } return result; } bool ArkNativeObject::CheckTypeTag(NapiTypeTag* typeTag) { const char name[] = "ACENAPI_TYPETAG"; bool result = false; result = this->HasProperty(name); if (result) { auto resultValue = this->GetProperty(name); Global object = *resultValue; if (object->IsBigInt()) { int sign; size_t size = 2; // 2: Indicates that the number of elements is 2 NapiTypeTag tag; auto nativeBigint = reinterpret_cast(resultValue->GetInterface(NativeBigint::INTERFACE_ID)); nativeBigint->GetWordsArray(&sign, &size, reinterpret_cast(&tag)); if (sign == 0 && ((size == 1) || (size == 2))) { // 2: Indicates that the number of elements is 2 result = (tag.lower == typeTag->lower && tag.upper == typeTag->upper); } } } return result; } void ArkNativeObject::SetModuleName(std::string moduleName) { NativeChunk& chunk = engine_->GetNativeChunk(); NativeValue* moduleValue = chunk.New(engine_, moduleName.c_str(), moduleName.size()); this->SetProperty(ArkNativeObject::PANDA_MODULE_NAME, moduleValue); } std::string ArkNativeObject::GetModuleName() { std::string moduleName(""); auto nativeModuleName = this->GetProperty(ArkNativeObject::PANDA_MODULE_NAME); if (nativeModuleName != nullptr && nativeModuleName->TypeOf() == NATIVE_STRING) { auto nativeString = reinterpret_cast(nativeModuleName->GetInterface(NativeString::INTERFACE_ID)); char arrayName[PANDA_MODULE_NAME_LEN] = {0}; size_t len = 0; nativeString->GetCString(arrayName, PANDA_MODULE_NAME_LEN, &len); moduleName += arrayName; moduleName += "."; } return moduleName; } void ArkNativeObject::AddFinalizer(void* pointer, NativeFinalize cb, void* hint) {} void ArkNativeObject::Freeze() { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global obj = value_; obj->Freeze(vm); } void ArkNativeObject::Seal() { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global obj = value_; obj->Seal(vm); } bool ArkNativeObject::SetElement(uint32_t index, NativeValue* value) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global obj = value_; Global val = *value; return obj->Set(vm, index, val.ToLocal(vm)); } NativeValue* ArkNativeObject::GetElement(uint32_t index) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global obj = value_; auto val = obj->Get(vm, index); return ArkNativeEngine::ArkValueToNativeValue(engine_, val); } bool ArkNativeObject::HasElement(uint32_t index) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global obj = value_; return obj->Has(vm, index); } bool ArkNativeObject::DeleteElement(uint32_t index) { auto vm = engine_->GetEcmaVm(); LocalScope scope(vm); Global obj = value_; return obj->Delete(vm, index); }