/* * 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 "native_sendable.h" #include "ark_native_engine.h" #include "native_engine/native_utils.h" using panda::ObjectRef; using panda::StringRef; using panda::SymbolRef; FunctionRef::SendablePropertiesInfos NativeSendable::CreateSendablePropertiesInfos( napi_env env, const NapiPropertyDescriptor* properties, size_t propertiesLength) { FunctionRef::SendablePropertiesInfos infos; for (size_t i = 0; i < propertiesLength; ++i) { if (properties[i].attributes & NATIVE_STATIC) { InitSendablePropertiesInfo(env, infos.staticPropertiesInfo, properties[i]); } else if (properties[i].attributes & NATIVE_INSTANCE) { InitSendablePropertiesInfo(env, infos.instancePropertiesInfo, properties[i]); } else if (properties[i].attributes & NATIVE_INSTANCE_OBJECT) { InitSendablePropertiesInfo(env, infos.instancePropertiesInfo, properties[i], FunctionRef::SendableType::OBJECT); } else if (properties[i].attributes & NATIVE_INSTANCE_GENERIC) { InitSendablePropertiesInfo(env, infos.instancePropertiesInfo, properties[i], FunctionRef::SendableType::GENERIC); } else { InitSendablePropertiesInfo(env, infos.nonStaticPropertiesInfo, properties[i]); } } return infos; } void NativeSendable::InitSendablePropertiesInfo(napi_env env, FunctionRef::SendablePropertiesInfo& info, NapiPropertyDescriptor propertyDescriptor, FunctionRef::SendableType type) { auto engine = reinterpret_cast(env); auto vm = engine->GetEcmaVm(); bool writable = (propertyDescriptor.attributes & NATIVE_WRITABLE) != 0; bool enumable = (propertyDescriptor.attributes & NATIVE_ENUMERABLE) != 0; bool configable = (propertyDescriptor.attributes & NATIVE_CONFIGURABLE) != 0; Local key; if (propertyDescriptor.utf8name == nullptr) { key = LocalValueFromJsValue(propertyDescriptor.name); } else { key = StringRef::NewFromUtf8(vm, propertyDescriptor.utf8name); } info.keys.push_back(key); if (propertyDescriptor.getter != nullptr || propertyDescriptor.setter != nullptr) { Local localGetter = JSValueRef::Undefined(vm); Local localSetter = JSValueRef::Undefined(vm); if (propertyDescriptor.getter != nullptr) { localGetter = NapiNativeCreateSendableFunction(env, "getter", propertyDescriptor.getter, propertyDescriptor.data); } if (propertyDescriptor.setter != nullptr) { localSetter = NapiNativeCreateSendableFunction(env, "setter", propertyDescriptor.setter, propertyDescriptor.data); } Local val = ObjectRef::CreateSendableAccessorData(vm, localGetter, localSetter); info.types.push_back(FunctionRef::SendableType::OBJECT); info.attributes.push_back(PropertyAttribute(val, false, enumable, configable)); } else if (propertyDescriptor.method != nullptr) { std::string fullName; if (propertyDescriptor.utf8name != nullptr) { fullName += propertyDescriptor.utf8name; } else { fullName += key->IsString(vm) ? Local(key)->ToString(vm) : Local(key)->GetDescription(vm)->ToString(vm); } Local func = NapiNativeCreateSendableFunction(env, fullName.c_str(), propertyDescriptor.method, propertyDescriptor.data); info.types.push_back(FunctionRef::SendableType::OBJECT); info.attributes.push_back(PropertyAttribute(func, writable, enumable, configable)); } else { Local val = LocalValueFromJsValue(propertyDescriptor.value); info.types.push_back(type); info.attributes.push_back(PropertyAttribute(val, writable, enumable, configable)); } } Local NativeSendable::NapiNativeCreateSendableFunction(napi_env env, const char* name, NapiNativeCallback cb, void* value) { auto engine = reinterpret_cast(env); auto vm = const_cast(engine->GetEcmaVm()); NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance(); if (funcInfo == nullptr) { HILOG_ERROR("funcInfo is nullptr"); return JSValueRef::Undefined(vm); } funcInfo->callback = cb; funcInfo->data = value; Local fn = FunctionRef::NewSendable( vm, ArkNativeFunctionCallBack, [](void* env, void* externalPointer, void* data) { auto info = reinterpret_cast(data); if (info != nullptr) { delete info; } }, reinterpret_cast(funcInfo), true); return fn; } void NativeSendable::NapiDefineSendabledProperty(napi_env env, Local& obj, NapiPropertyDescriptor& propertyDescriptor, Local& propertyName, bool& result) { auto engine = reinterpret_cast(env); auto vm = engine->GetEcmaVm(); bool enumable = (propertyDescriptor.attributes & NATIVE_ENUMERABLE) != 0; bool configable = (propertyDescriptor.attributes & NATIVE_CONFIGURABLE) != 0; if (propertyDescriptor.getter != nullptr || propertyDescriptor.setter != nullptr) { Local localGetter = JSValueRef::Undefined(vm); Local localSetter = JSValueRef::Undefined(vm); if (propertyDescriptor.getter != nullptr) { localGetter = NapiNativeCreateSendableFunction(env, "getter", propertyDescriptor.getter, propertyDescriptor.data); } if (propertyDescriptor.setter != nullptr) { localSetter = NapiNativeCreateSendableFunction(env, "setter", propertyDescriptor.setter, propertyDescriptor.data); } PropertyAttribute attr(JSValueRef::Undefined(vm), false, enumable, configable); // note(lzl): SetSendableAccessorProperty? result = obj->SetAccessorProperty(vm, propertyName, localGetter, localSetter, attr); } else if (propertyDescriptor.method != nullptr) { std::string fullName; if (propertyDescriptor.utf8name != nullptr) { fullName += propertyDescriptor.utf8name; } else { fullName += propertyName->IsString(vm) ? Local(propertyName)->ToString(vm) : Local(propertyName)->GetDescription(vm)->ToString(vm); } Local func = NapiNativeCreateSendableFunction(env, fullName.c_str(), propertyDescriptor.method, propertyDescriptor.data); result = obj->Set(vm, propertyName, func); } else { Local val = LocalValueFromJsValue(propertyDescriptor.value); result = obj->Set(vm, propertyName, val); } }