1 /*
2 * Copyright (c) 2021 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 "jerryscript_native_object.h"
17
18 #include "jerryscript-ext/handler.h"
19 #include "jerryscript_native_array.h"
20 #include "jerryscript_native_function.h"
21 #include "utils/log.h"
22
23 struct JerryScriptNativeObjectInfo {
24 NativeEngine* engine = nullptr;
25 NativeFinalize cb = nullptr;
26 void* data = nullptr;
27 void* hint = nullptr;
28 };
29
30 namespace {
31 jerry_object_native_info_t g_freeCallback = {
__anon1921375f0202() 32 .free_cb = [](void* nativePointer) -> void {
33 auto info = (JerryScriptNativeObjectInfo*)nativePointer;
34 if (info != nullptr) {
35 info->cb(info->engine, info->data, info->hint);
36 delete info;
37 }
38 },
39 };
40 } // namespace
41
JerryScriptNativeObject(JerryScriptNativeEngine * engine)42 JerryScriptNativeObject::JerryScriptNativeObject(JerryScriptNativeEngine* engine)
43 : JerryScriptNativeObject(engine, jerry_create_object())
44 {
45 }
46
JerryScriptNativeObject(JerryScriptNativeEngine * engine,jerry_value_t value)47 JerryScriptNativeObject::JerryScriptNativeObject(JerryScriptNativeEngine* engine, jerry_value_t value)
48 : JerryScriptNativeValue(engine, value)
49 {
50 }
51
~JerryScriptNativeObject()52 JerryScriptNativeObject::~JerryScriptNativeObject() {}
53
SetNativePointer(void * pointer,NativeFinalize cb,void * hint)54 void JerryScriptNativeObject::SetNativePointer(void* pointer, NativeFinalize cb, void* hint)
55 {
56 if (pointer == nullptr) {
57 jerry_delete_object_native_pointer(value_, &g_freeCallback);
58 return;
59 }
60
61 JerryScriptNativeObjectInfo* info = new JerryScriptNativeObjectInfo {
62 .engine = engine_,
63 .cb = cb,
64 .data = pointer,
65 .hint = hint,
66 };
67
68 jerry_set_object_native_pointer(value_, info, &g_freeCallback);
69 }
70
GetNativePointer()71 void* JerryScriptNativeObject::GetNativePointer()
72 {
73 JerryScriptNativeObjectInfo* info = nullptr;
74 jerry_get_object_native_pointer(value_, (void**)&info, &g_freeCallback);
75 if (info != nullptr) {
76 return info->data;
77 } else {
78 return nullptr;
79 }
80 }
81
AddFinalizer(void * pointer,NativeFinalize cb,void * hint)82 void JerryScriptNativeObject::AddFinalizer(void* pointer, NativeFinalize cb, void* hint)
83 {
84 if (pointer == nullptr) {
85 jerry_delete_object_native_pointer(value_, &g_freeCallback);
86 return;
87 }
88
89 JerryScriptNativeObjectInfo* info = new JerryScriptNativeObjectInfo {
90 .engine = engine_,
91 .cb = cb,
92 .data = pointer,
93 .hint = hint,
94 };
95
96 jerry_set_object_native_pointer(value_, info, &g_freeCallback);
97 }
98
GetInterface(int interfaceId)99 void* JerryScriptNativeObject::GetInterface(int interfaceId)
100 {
101 return (NativeObject::INTERFACE_ID == interfaceId) ? (NativeObject*)this : nullptr;
102 }
103
GetPropertyNames()104 NativeValue* JerryScriptNativeObject::GetPropertyNames()
105 {
106 return new JerryScriptNativeArray(engine_, jerry_get_object_keys(value_));
107 }
108
GetPrototype()109 NativeValue* JerryScriptNativeObject::GetPrototype()
110 {
111 return JerryScriptNativeEngine::JerryValueToNativeValue(engine_, jerry_get_prototype(value_));
112 }
113
DefineProperty(NativePropertyDescriptor propertyDescriptor)114 bool JerryScriptNativeObject::DefineProperty(NativePropertyDescriptor propertyDescriptor)
115 {
116 jerry_value_t propName = jerry_create_string_from_utf8((const unsigned char*)propertyDescriptor.utf8name);
117 jerry_property_descriptor_t prop = { 0 };
118
119 jerry_init_property_descriptor_fields(&prop);
120
121 prop.is_writable_defined = propertyDescriptor.attributes & NATIVE_WRITABLE;
122 prop.is_writable = propertyDescriptor.attributes & NATIVE_WRITABLE;
123
124 prop.is_enumerable_defined = propertyDescriptor.attributes & NATIVE_ENUMERABLE;
125 prop.is_enumerable = propertyDescriptor.attributes & NATIVE_ENUMERABLE;
126
127 prop.is_configurable_defined = propertyDescriptor.attributes & NATIVE_CONFIGURABLE;
128 prop.is_configurable = propertyDescriptor.attributes & NATIVE_CONFIGURABLE;
129
130 if (propertyDescriptor.value != nullptr) {
131 prop.value = *propertyDescriptor.value;
132 prop.is_value_defined = true;
133 }
134
135 if (propertyDescriptor.method != nullptr) {
136 prop.value = *(new JerryScriptNativeFunction(
137 engine_, propertyDescriptor.utf8name, propertyDescriptor.method, propertyDescriptor.data));
138 prop.is_value_defined = true;
139 }
140
141 if (propertyDescriptor.getter != nullptr) {
142 prop.getter =
143 *(new JerryScriptNativeFunction(engine_, "getter", propertyDescriptor.getter, propertyDescriptor.data));
144 prop.is_get_defined = true;
145 prop.is_writable_defined = true;
146 }
147 if (propertyDescriptor.setter != nullptr) {
148 prop.setter =
149 *(new JerryScriptNativeFunction(engine_, "setter", propertyDescriptor.setter, propertyDescriptor.data));
150 prop.is_set_defined = true;
151 prop.is_writable_defined = true;
152 }
153
154 jerry_value_t returnValue = jerry_define_own_property(value_, propName, &prop);
155 jerry_release_value(returnValue);
156 jerry_release_value(propName);
157
158 return true;
159 }
160
SetProperty(NativeValue * key,NativeValue * value)161 bool JerryScriptNativeObject::SetProperty(NativeValue* key, NativeValue* value)
162 {
163 jerry_value_t returnValue = jerry_set_property(value_, *key, *value);
164 jerry_release_value(returnValue);
165 return true;
166 }
167
GetProperty(NativeValue * key)168 NativeValue* JerryScriptNativeObject::GetProperty(NativeValue* key)
169 {
170 jerry_value_t returnValue = jerry_get_property(value_, *key);
171 return JerryScriptNativeEngine::JerryValueToNativeValue(engine_, returnValue);
172 }
173
HasProperty(NativeValue * key)174 bool JerryScriptNativeObject::HasProperty(NativeValue* key)
175 {
176 jerry_value_t returnValue = jerry_has_property(value_, *key);
177 bool result = jerry_value_to_boolean(returnValue);
178 jerry_release_value(returnValue);
179 return result;
180 }
181
DeleteProperty(NativeValue * key)182 bool JerryScriptNativeObject::DeleteProperty(NativeValue* key)
183 {
184 return jerry_delete_property(value_, *key);
185 }
186
SetProperty(const char * name,NativeValue * value)187 bool JerryScriptNativeObject::SetProperty(const char* name, NativeValue* value)
188 {
189 jerry_value_t returnValue = jerryx_set_property_str(value_, name, *value);
190 jerry_release_value(returnValue);
191 return true;
192 }
193
GetProperty(const char * name)194 NativeValue* JerryScriptNativeObject::GetProperty(const char* name)
195 {
196 jerry_value_t returnValue = jerryx_get_property_str(value_, name);
197 return JerryScriptNativeEngine::JerryValueToNativeValue(engine_, returnValue);
198 }
199
HasProperty(const char * name)200 bool JerryScriptNativeObject::HasProperty(const char* name)
201 {
202 bool result = jerryx_has_property_str(value_, name);
203 return result;
204 }
205
DeleteProperty(const char * name)206 bool JerryScriptNativeObject::DeleteProperty(const char* name)
207 {
208 jerry_value_t key = jerry_create_string_from_utf8((const unsigned char*)name);
209 bool result = jerry_delete_property(value_, key);
210 jerry_release_value(key);
211 return result;
212 }
213
SetPrivateProperty(const char * name,NativeValue * value)214 bool JerryScriptNativeObject::SetPrivateProperty(const char* name, NativeValue* value)
215 {
216 bool result = false;
217 jerry_value_t key = jerry_create_string_from_utf8((const unsigned char*)name);
218 result = jerry_set_property(value_, key, *value);
219 jerry_release_value(key);
220 return result;
221 }
222
GetPrivateProperty(const char * name)223 NativeValue* JerryScriptNativeObject::GetPrivateProperty(const char* name)
224 {
225 jerry_value_t result = 0;
226 jerry_value_t key = jerry_create_string_from_utf8((const unsigned char*)name);
227 result = jerry_get_property(value_, key);
228 jerry_release_value(key);
229 return JerryScriptNativeEngine::JerryValueToNativeValue(engine_, result);
230 }
231
HasPrivateProperty(const char * name)232 bool JerryScriptNativeObject::HasPrivateProperty(const char* name)
233 {
234 jerry_value_t key = jerry_create_string_from_utf8((const unsigned char*)name);
235 jerry_value_t returnValue = jerry_has_property(value_, key);
236 bool result = jerry_value_to_boolean(returnValue);
237 jerry_release_value(returnValue);
238 jerry_release_value(key);
239 return result;
240 }
241
DeletePrivateProperty(const char * name)242 bool JerryScriptNativeObject::DeletePrivateProperty(const char* name)
243 {
244 bool result = false;
245 jerry_value_t key = jerry_create_string_from_utf8((const unsigned char*)name);
246 result = jerry_delete_property(value_, key);
247 jerry_release_value(key);
248 return result;
249 }
250
Freeze()251 void JerryScriptNativeObject::Freeze()
252 {
253 jerry_freeze(value_);
254 }
255
Seal()256 void JerryScriptNativeObject::Seal()
257 {
258 jerry_seal(value_);
259 }
260
GetAllPropertyNames(napi_key_collection_mode keyMode,napi_key_filter keyFilter,napi_key_conversion keyConversion)261 NativeValue* JerryScriptNativeObject::GetAllPropertyNames(
262 napi_key_collection_mode keyMode, napi_key_filter keyFilter, napi_key_conversion keyConversion)
263 {
264 #if JERRY_API_MINOR_VERSION > 3 // jerryscript2.3: 3, jerryscript2.4: 4
265 jerry_property_filter_t filter = JERRY_PROPERTY_FILTER_ALL;
266
267 if (keyFilter & napi_key_writable) {
268 filter = static_cast<jerry_property_filter_t>(filter | JERRY_PROPERTY_FILTER_EXLCUDE_NON_WRITABLE);
269 }
270 if (keyFilter & napi_key_enumerable) {
271 filter = static_cast<jerry_property_filter_t>(filter | JERRY_PROPERTY_FILTER_EXLCUDE_NON_ENUMERABLE);
272 }
273 if (keyFilter & napi_key_configurable) {
274 filter = static_cast<jerry_property_filter_t>(filter | JERRY_PROPERTY_FILTER_EXLCUDE_NON_CONFIGURABLE);
275 }
276 if (keyFilter & napi_key_skip_strings) {
277 filter = static_cast<jerry_property_filter_t>(filter | JERRY_PROPERTY_FILTER_EXLCUDE_STRINGS);
278 }
279 if (keyFilter & napi_key_skip_symbols) {
280 filter = static_cast<jerry_property_filter_t>(filter | JERRY_PROPERTY_FILTER_EXLCUDE_SYMBOLS);
281 }
282
283 switch (keyConversion) {
284 case napi_key_keep_numbers:
285 filter = static_cast<jerry_property_filter_t>(filter | JERRY_PROPERTY_FILTER_EXLCUDE_INTEGER_INDICES);
286 break;
287 case napi_key_numbers_to_strings:
288 filter = static_cast<jerry_property_filter_t>(filter | JERRY_PROPERTY_FILTER_INTEGER_INDICES_AS_NUMBER);
289 break;
290 default:
291 break;
292 }
293
294 jerry_value_t result = jerry_object_get_property_names(value_, filter);
295
296 return JerryScriptNativeEngine::JerryValueToNativeValue(engine_, result);
297 #else
298 return nullptr;
299 #endif
300 }
301
AssociateTypeTag(NapiTypeTag * typeTag)302 bool JerryScriptNativeObject::AssociateTypeTag(NapiTypeTag* typeTag)
303 {
304 #if JERRY_API_MINOR_VERSION > 3 // jerryscript2.3: 3, jerryscript2.4: 4
305 const char name[] = "ACENAPI_TYPETAG";
306 bool result = false;
307 bool hasPribate = false;
308 hasPribate = HasPrivateProperty(name);
309 if (!hasPribate) {
310 jerry_value_t key = jerry_create_string_from_utf8((const unsigned char*)name);
311 uint32_t size = 2;
312 jerry_value_t value = jerry_create_bigint((uint64_t*)typeTag, size, false);
313
314 result = jerry_set_property(value_, key, value);
315 jerry_release_value(key);
316 }
317 return result;
318 #else
319 return true;
320 #endif
321 }
322
CheckTypeTag(NapiTypeTag * typeTag)323 bool JerryScriptNativeObject::CheckTypeTag(NapiTypeTag* typeTag)
324 {
325 #if JERRY_API_MINOR_VERSION > 3 // jerryscript2.3: 3, jerryscript2.4: 4
326 const char name[] = "ACENAPI_TYPETAG";
327 bool result = false;
328 result = HasPrivateProperty(name);
329 if (result) {
330 jerry_value_t key = jerry_create_string_from_utf8((const unsigned char*)name);
331 jerry_value_t value = jerry_get_property(value_, key);
332 jerry_release_value(key);
333
334 NapiTypeTag typeTagOut;
335 uint32_t size = 2;
336 bool sign = false;
337
338 jerry_get_bigint_digits(value, (uint64_t*)(&typeTagOut), size, &sign);
339
340 if ((typeTagOut.lower != typeTag->lower) || (typeTagOut.upper != typeTag->upper)) {
341 result = false;
342 }
343 }
344 return result;
345 #else
346 return true;
347 #endif
348 }