1/* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "native_sendable.h" 17 18#include "ark_native_engine.h" 19#include "native_engine/native_utils.h" 20 21using panda::ObjectRef; 22using panda::StringRef; 23using panda::SymbolRef; 24 25FunctionRef::SendablePropertiesInfos NativeSendable::CreateSendablePropertiesInfos( 26 napi_env env, 27 const NapiPropertyDescriptor* properties, 28 size_t propertiesLength) 29{ 30 FunctionRef::SendablePropertiesInfos infos; 31 32 for (size_t i = 0; i < propertiesLength; ++i) { 33 if (properties[i].attributes & NATIVE_STATIC) { 34 InitSendablePropertiesInfo(env, infos.staticPropertiesInfo, properties[i]); 35 } else if (properties[i].attributes & NATIVE_INSTANCE) { 36 InitSendablePropertiesInfo(env, infos.instancePropertiesInfo, properties[i]); 37 } else if (properties[i].attributes & NATIVE_INSTANCE_OBJECT) { 38 InitSendablePropertiesInfo(env, infos.instancePropertiesInfo, properties[i], 39 FunctionRef::SendableType::OBJECT); 40 } else if (properties[i].attributes & NATIVE_INSTANCE_GENERIC) { 41 InitSendablePropertiesInfo(env, infos.instancePropertiesInfo, properties[i], 42 FunctionRef::SendableType::GENERIC); 43 } else { 44 InitSendablePropertiesInfo(env, infos.nonStaticPropertiesInfo, properties[i]); 45 } 46 } 47 48 return infos; 49} 50 51void NativeSendable::InitSendablePropertiesInfo(napi_env env, 52 FunctionRef::SendablePropertiesInfo& info, 53 NapiPropertyDescriptor propertyDescriptor, 54 FunctionRef::SendableType type) 55{ 56 auto engine = reinterpret_cast<NativeEngine*>(env); 57 auto vm = engine->GetEcmaVm(); 58 59 bool writable = (propertyDescriptor.attributes & NATIVE_WRITABLE) != 0; 60 bool enumable = (propertyDescriptor.attributes & NATIVE_ENUMERABLE) != 0; 61 bool configable = (propertyDescriptor.attributes & NATIVE_CONFIGURABLE) != 0; 62 63 Local<StringRef> key; 64 if (propertyDescriptor.utf8name == nullptr) { 65 key = LocalValueFromJsValue(propertyDescriptor.name); 66 } else { 67 key = StringRef::NewFromUtf8(vm, propertyDescriptor.utf8name); 68 } 69 info.keys.push_back(key); 70 71 if (propertyDescriptor.getter != nullptr || propertyDescriptor.setter != nullptr) { 72 Local<JSValueRef> localGetter = JSValueRef::Undefined(vm); 73 Local<JSValueRef> localSetter = JSValueRef::Undefined(vm); 74 75 if (propertyDescriptor.getter != nullptr) { 76 localGetter = 77 NapiNativeCreateSendableFunction(env, "getter", propertyDescriptor.getter, propertyDescriptor.data); 78 } 79 if (propertyDescriptor.setter != nullptr) { 80 localSetter = 81 NapiNativeCreateSendableFunction(env, "setter", propertyDescriptor.setter, propertyDescriptor.data); 82 } 83 84 Local<JSValueRef> val = ObjectRef::CreateSendableAccessorData(vm, localGetter, localSetter); 85 info.types.push_back(FunctionRef::SendableType::OBJECT); 86 info.attributes.push_back(PropertyAttribute(val, false, enumable, configable)); 87 } else if (propertyDescriptor.method != nullptr) { 88 std::string fullName; 89 if (propertyDescriptor.utf8name != nullptr) { 90 fullName += propertyDescriptor.utf8name; 91 } else { 92 fullName += key->IsString(vm) ? Local<StringRef>(key)->ToString(vm) 93 : Local<SymbolRef>(key)->GetDescription(vm)->ToString(vm); 94 } 95 96 Local<JSValueRef> func = 97 NapiNativeCreateSendableFunction(env, fullName.c_str(), propertyDescriptor.method, propertyDescriptor.data); 98 info.types.push_back(FunctionRef::SendableType::OBJECT); 99 info.attributes.push_back(PropertyAttribute(func, writable, enumable, configable)); 100 } else { 101 Local<JSValueRef> val = LocalValueFromJsValue(propertyDescriptor.value); 102 info.types.push_back(type); 103 info.attributes.push_back(PropertyAttribute(val, writable, enumable, configable)); 104 } 105} 106 107Local<JSValueRef> NativeSendable::NapiNativeCreateSendableFunction(napi_env env, 108 const char* name, 109 NapiNativeCallback cb, 110 void* value) 111{ 112 auto engine = reinterpret_cast<NativeEngine*>(env); 113 auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm()); 114 NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance(); 115 if (funcInfo == nullptr) { 116 HILOG_ERROR("funcInfo is nullptr"); 117 return JSValueRef::Undefined(vm); 118 } 119 funcInfo->callback = cb; 120 funcInfo->data = value; 121 122 Local<FunctionRef> fn = FunctionRef::NewSendable( 123 vm, ArkNativeFunctionCallBack, 124 [](void* env, void* externalPointer, void* data) { 125 auto info = reinterpret_cast<NapiFunctionInfo*>(data); 126 if (info != nullptr) { 127 delete info; 128 } 129 }, 130 reinterpret_cast<void*>(funcInfo), true); 131 return fn; 132} 133 134void NativeSendable::NapiDefineSendabledProperty(napi_env env, 135 Local<ObjectRef>& obj, 136 NapiPropertyDescriptor& propertyDescriptor, 137 Local<JSValueRef>& propertyName, 138 bool& result) 139{ 140 auto engine = reinterpret_cast<NativeEngine*>(env); 141 auto vm = engine->GetEcmaVm(); 142 143 bool enumable = (propertyDescriptor.attributes & NATIVE_ENUMERABLE) != 0; 144 bool configable = (propertyDescriptor.attributes & NATIVE_CONFIGURABLE) != 0; 145 146 if (propertyDescriptor.getter != nullptr || propertyDescriptor.setter != nullptr) { 147 Local<JSValueRef> localGetter = JSValueRef::Undefined(vm); 148 Local<JSValueRef> localSetter = JSValueRef::Undefined(vm); 149 150 if (propertyDescriptor.getter != nullptr) { 151 localGetter = 152 NapiNativeCreateSendableFunction(env, "getter", propertyDescriptor.getter, propertyDescriptor.data); 153 } 154 if (propertyDescriptor.setter != nullptr) { 155 localSetter = 156 NapiNativeCreateSendableFunction(env, "setter", propertyDescriptor.setter, propertyDescriptor.data); 157 } 158 159 PropertyAttribute attr(JSValueRef::Undefined(vm), false, enumable, configable); 160 // note(lzl): SetSendableAccessorProperty? 161 result = obj->SetAccessorProperty(vm, propertyName, localGetter, localSetter, attr); 162 } else if (propertyDescriptor.method != nullptr) { 163 std::string fullName; 164 if (propertyDescriptor.utf8name != nullptr) { 165 fullName += propertyDescriptor.utf8name; 166 } else { 167 fullName += propertyName->IsString(vm) ? Local<StringRef>(propertyName)->ToString(vm) 168 : Local<SymbolRef>(propertyName)->GetDescription(vm)->ToString(vm); 169 } 170 171 Local<JSValueRef> func = 172 NapiNativeCreateSendableFunction(env, fullName.c_str(), propertyDescriptor.method, propertyDescriptor.data); 173 result = obj->Set(vm, propertyName, func); 174 } else { 175 Local<JSValueRef> val = LocalValueFromJsValue(propertyDescriptor.value); 176 result = obj->Set(vm, propertyName, val); 177 } 178} 179