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