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
21 using panda::ObjectRef;
22 using panda::StringRef;
23 using panda::SymbolRef;
24
CreateSendablePropertiesInfos(napi_env env,const NapiPropertyDescriptor * properties,size_t propertiesLength)25 FunctionRef::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
InitSendablePropertiesInfo(napi_env env,FunctionRef::SendablePropertiesInfo & info,NapiPropertyDescriptor propertyDescriptor,FunctionRef::SendableType type)51 void 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
NapiNativeCreateSendableFunction(napi_env env,const char * name,NapiNativeCallback cb,void * value)107 Local<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
NapiDefineSendabledProperty(napi_env env,Local<ObjectRef> & obj,NapiPropertyDescriptor & propertyDescriptor,Local<JSValueRef> & propertyName,bool & result)134 void 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