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 using PropertyAttribute = panda::PropertyAttribute;
25
CreateSendablePropertiesInfos(napi_env env,const NapiPropertyDescriptor * properties,size_t propertiesLength)26 FunctionRef::SendablePropertiesInfos NativeSendable::CreateSendablePropertiesInfos(
27 napi_env env,
28 const NapiPropertyDescriptor* properties,
29 size_t propertiesLength)
30 {
31 FunctionRef::SendablePropertiesInfos infos;
32
33 for (size_t i = 0; i < propertiesLength; ++i) {
34 if (properties[i].attributes & NATIVE_STATIC) {
35 InitSendablePropertiesInfo(env, infos.staticPropertiesInfo, properties[i]);
36 } else if (properties[i].attributes & NATIVE_INSTANCE) {
37 InitSendablePropertiesInfo(env, infos.instancePropertiesInfo, properties[i]);
38 } else if (properties[i].attributes & NATIVE_INSTANCE_OBJECT) {
39 InitSendablePropertiesInfo(env, infos.instancePropertiesInfo, properties[i],
40 FunctionRef::SendableType::OBJECT);
41 } else if (properties[i].attributes & NATIVE_INSTANCE_GENERIC) {
42 InitSendablePropertiesInfo(env, infos.instancePropertiesInfo, properties[i],
43 FunctionRef::SendableType::GENERIC);
44 } else {
45 InitSendablePropertiesInfo(env, infos.nonStaticPropertiesInfo, properties[i]);
46 }
47 }
48
49 return infos;
50 }
51
InitSendablePropertiesInfo(napi_env env,FunctionRef::SendablePropertiesInfo & info,NapiPropertyDescriptor propertyDescriptor,FunctionRef::SendableType type)52 void NativeSendable::InitSendablePropertiesInfo(napi_env env,
53 FunctionRef::SendablePropertiesInfo& info,
54 NapiPropertyDescriptor propertyDescriptor,
55 FunctionRef::SendableType type)
56 {
57 auto engine = reinterpret_cast<NativeEngine*>(env);
58 auto vm = engine->GetEcmaVm();
59
60 bool writable = (propertyDescriptor.attributes & NATIVE_WRITABLE) != 0;
61 bool enumable = (propertyDescriptor.attributes & NATIVE_ENUMERABLE) != 0;
62 bool configable = (propertyDescriptor.attributes & NATIVE_CONFIGURABLE) != 0;
63
64 Local<StringRef> key;
65 if (propertyDescriptor.utf8name == nullptr) {
66 key = LocalValueFromJsValue(propertyDescriptor.name);
67 } else {
68 key = StringRef::NewFromUtf8(vm, propertyDescriptor.utf8name);
69 }
70 info.keys.push_back(key);
71
72 if (propertyDescriptor.getter != nullptr || propertyDescriptor.setter != nullptr) {
73 Local<JSValueRef> localGetter = JSValueRef::Undefined(vm);
74 Local<JSValueRef> localSetter = JSValueRef::Undefined(vm);
75
76 if (propertyDescriptor.getter != nullptr) {
77 localGetter =
78 NapiNativeCreateSendableFunction(env, "getter", propertyDescriptor.getter, propertyDescriptor.data);
79 }
80 if (propertyDescriptor.setter != nullptr) {
81 localSetter =
82 NapiNativeCreateSendableFunction(env, "setter", propertyDescriptor.setter, propertyDescriptor.data);
83 }
84
85 Local<JSValueRef> val = ObjectRef::CreateSendableAccessorData(vm, localGetter, localSetter);
86 info.types.push_back(FunctionRef::SendableType::OBJECT);
87 info.attributes.push_back(PropertyAttribute(val, false, enumable, configable));
88 } else if (propertyDescriptor.method != nullptr) {
89 std::string fullName;
90 if (propertyDescriptor.utf8name != nullptr) {
91 fullName += propertyDescriptor.utf8name;
92 } else {
93 fullName += key->IsString(vm) ? Local<StringRef>(key)->ToString(vm)
94 : Local<SymbolRef>(key)->GetDescription(vm)->ToString(vm);
95 }
96
97 Local<JSValueRef> func =
98 NapiNativeCreateSendableFunction(env, fullName.c_str(), propertyDescriptor.method, propertyDescriptor.data);
99 info.types.push_back(FunctionRef::SendableType::OBJECT);
100 info.attributes.push_back(PropertyAttribute(func, writable, enumable, configable));
101 } else {
102 Local<JSValueRef> val = LocalValueFromJsValue(propertyDescriptor.value);
103 info.types.push_back(type);
104 info.attributes.push_back(PropertyAttribute(val, writable, enumable, configable));
105 }
106 }
107
NapiNativeCreateSendableFunction(napi_env env,const char * name,NapiNativeCallback cb,void * value)108 Local<JSValueRef> NativeSendable::NapiNativeCreateSendableFunction(napi_env env,
109 const char* name,
110 NapiNativeCallback cb,
111 void* value)
112 {
113 auto engine = reinterpret_cast<NativeEngine*>(env);
114 auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
115 NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
116 if (funcInfo == nullptr) {
117 HILOG_ERROR("funcInfo is nullptr");
118 return JSValueRef::Undefined(vm);
119 }
120 funcInfo->callback = cb;
121 funcInfo->data = value;
122 funcInfo->isSendable = true;
123
124 Local<FunctionRef> fn = FunctionRef::NewSendable(vm, ArkNativeFunctionCallBack, CommonDeleter,
125 reinterpret_cast<void*>(funcInfo), true);
126 return fn;
127 }
128
NapiDefineSendabledProperty(napi_env env,Local<ObjectRef> & obj,NapiPropertyDescriptor & propertyDescriptor,Local<JSValueRef> & propertyName,bool & result)129 void NativeSendable::NapiDefineSendabledProperty(napi_env env,
130 Local<ObjectRef>& obj,
131 NapiPropertyDescriptor& propertyDescriptor,
132 Local<JSValueRef>& propertyName,
133 bool& result)
134 {
135 auto engine = reinterpret_cast<NativeEngine*>(env);
136 auto vm = engine->GetEcmaVm();
137
138 bool enumable = (propertyDescriptor.attributes & NATIVE_ENUMERABLE) != 0;
139 bool configable = (propertyDescriptor.attributes & NATIVE_CONFIGURABLE) != 0;
140
141 if (propertyDescriptor.getter != nullptr || propertyDescriptor.setter != nullptr) {
142 Local<JSValueRef> localGetter = JSValueRef::Undefined(vm);
143 Local<JSValueRef> localSetter = JSValueRef::Undefined(vm);
144
145 if (propertyDescriptor.getter != nullptr) {
146 localGetter =
147 NapiNativeCreateSendableFunction(env, "getter", propertyDescriptor.getter, propertyDescriptor.data);
148 }
149 if (propertyDescriptor.setter != nullptr) {
150 localSetter =
151 NapiNativeCreateSendableFunction(env, "setter", propertyDescriptor.setter, propertyDescriptor.data);
152 }
153
154 PropertyAttribute attr(JSValueRef::Undefined(vm), false, enumable, configable);
155 // note(lzl): SetSendableAccessorProperty?
156 result = obj->SetAccessorProperty(vm, propertyName, localGetter, localSetter, attr);
157 } else if (propertyDescriptor.method != nullptr) {
158 std::string fullName;
159 if (propertyDescriptor.utf8name != nullptr) {
160 fullName += propertyDescriptor.utf8name;
161 } else {
162 fullName += propertyName->IsString(vm) ? Local<StringRef>(propertyName)->ToString(vm)
163 : Local<SymbolRef>(propertyName)->GetDescription(vm)->ToString(vm);
164 }
165
166 Local<JSValueRef> func =
167 NapiNativeCreateSendableFunction(env, fullName.c_str(), propertyDescriptor.method, propertyDescriptor.data);
168 result = obj->Set(vm, propertyName, func);
169 } else {
170 Local<JSValueRef> val = LocalValueFromJsValue(propertyDescriptor.value);
171 result = obj->Set(vm, propertyName, val);
172 }
173 }
174