• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "quickjs_native_object.h"
17 #include "native_engine/native_engine.h"
18 #include "native_engine/native_property.h"
19 #include "quickjs_headers.h"
20 #include "quickjs_native_array.h"
21 #include "quickjs_native_big_int.h"
22 #include "quickjs_native_engine.h"
23 #include "quickjs_native_function.h"
24 #include "quickjs_native_string.h"
25 #include "utils/log.h"
26 
QuickJSNativeObject(QuickJSNativeEngine * engine)27 QuickJSNativeObject::QuickJSNativeObject(QuickJSNativeEngine* engine)
28     : QuickJSNativeObject(engine, JS_NewObject(engine->GetContext()))
29 {
30 }
31 
QuickJSNativeObject(QuickJSNativeEngine * engine,JSValue value)32 QuickJSNativeObject::QuickJSNativeObject(QuickJSNativeEngine* engine, JSValue value) : QuickJSNativeValue(engine, value)
33 {
34 }
35 
~QuickJSNativeObject()36 QuickJSNativeObject::~QuickJSNativeObject() {}
37 
SetNativePointer(void * pointer,NativeFinalize cb,void * hint)38 void QuickJSNativeObject::SetNativePointer(void* pointer, NativeFinalize cb, void* hint)
39 {
40     NativeObjectInfo* info = (NativeObjectInfo*)JS_GetNativePointer(engine_->GetContext(), value_);
41     if (info == nullptr) {
42         info = new NativeObjectInfo();
43         if (info != nullptr) {
44             info->callback = cb;
45             info->engine = engine_;
46             info->nativeObject = pointer;
47             info->hint = hint;
48         }
49         JS_SetNativePointer(
50             engine_->GetContext(), value_, info,
51             [](JSContext* context, void* data, void* hint) {
52                 auto info = reinterpret_cast<NativeObjectInfo*>(data);
53                 if (info) {
54                     info->callback(info->engine, info->nativeObject, info->hint);
55                     delete info;
56                 }
57             },
58             hint);
59     } else if (pointer == nullptr) {
60         JS_SetNativePointer(engine_->GetContext(), value_, nullptr, nullptr, nullptr);
61         delete info;
62     }
63 }
64 
GetNativePointer()65 void* QuickJSNativeObject::GetNativePointer()
66 {
67     NativeObjectInfo* info = (NativeObjectInfo*)JS_GetNativePointer(engine_->GetContext(), value_);
68     return info ? info->nativeObject : nullptr;
69 }
70 
AddFinalizer(void * pointer,NativeFinalize cb,void * hint)71 void QuickJSNativeObject::AddFinalizer(void* pointer, NativeFinalize cb, void* hint)
72 {
73     NativeObjectInfo* info = (NativeObjectInfo*)JS_GetNativePointer(engine_->GetContext(), value_);
74     if (info == nullptr) {
75         info = new NativeObjectInfo();
76         if (info != nullptr) {
77             info->callback = cb;
78             info->engine = engine_;
79             info->nativeObject = pointer;
80             info->hint = hint;
81         }
82     }
83     if (info == nullptr) {
84         return;
85     }
86 
87     JS_AddFinalizer(
88         engine_->GetContext(), value_, info,
89         [](JSContext* context, void* data, void* hint) {
90             auto info = reinterpret_cast<NativeObjectInfo*>(data);
91             if (info) {
92                 info->callback(info->engine, info->nativeObject, info->hint);
93                 delete info;
94             }
95         },
96         hint);
97 }
98 
GetInterface(int interfaceId)99 void* QuickJSNativeObject::GetInterface(int interfaceId)
100 {
101     return (NativeObject::INTERFACE_ID == interfaceId) ? (NativeObject*)this : nullptr;
102 }
103 
GetPropertyNames()104 NativeValue* QuickJSNativeObject::GetPropertyNames()
105 {
106     JSPropertyEnum* tab = nullptr;
107     uint32_t len = 0;
108 
109     JS_GetOwnPropertyNames(engine_->GetContext(), &tab, &len, value_, JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY);
110 
111     QuickJSNativeArray* propertyNames = new QuickJSNativeArray(engine_, (uint32_t)0);
112     if (propertyNames == nullptr) {
113         HILOG_ERROR("create property names failed");
114         return nullptr;
115     }
116 
117     for (uint32_t i = 0; i < len; i++) {
118         QuickJSNativeString* name = new QuickJSNativeString(engine_, tab[i].atom);
119         propertyNames->SetElement(i, name);
120     }
121 
122     return propertyNames;
123 }
124 
GetPrototype()125 NativeValue* QuickJSNativeObject::GetPrototype()
126 {
127     JSValue value = JS_GetPrototype(engine_->GetContext(), value_);
128     return new QuickJSNativeObject(engine_, value);
129 }
130 
DefineProperty(NativePropertyDescriptor propertyDescriptor)131 bool QuickJSNativeObject::DefineProperty(NativePropertyDescriptor propertyDescriptor)
132 {
133     JSAtom jKey = JS_NewAtom(engine_->GetContext(), propertyDescriptor.utf8name);
134 
135     bool result = false;
136 
137     if (propertyDescriptor.value) {
138         result = JS_DefinePropertyValue(engine_->GetContext(), value_, jKey,
139             JS_DupValue(engine_->GetContext(), *propertyDescriptor.value), JS_PROP_C_W_E);
140     } else if (propertyDescriptor.method) {
141         NativeValue* function = new QuickJSNativeFunction(engine_, propertyDescriptor.utf8name,
142                                                           propertyDescriptor.method, propertyDescriptor.data);
143         if (function != nullptr) {
144             result = JS_DefinePropertyValue(engine_->GetContext(), value_, jKey,
145                                             JS_DupValue(engine_->GetContext(), *function),
146                                             JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
147         }
148     } else if (propertyDescriptor.getter || propertyDescriptor.setter) {
149         NativeValue* getter =
150             new QuickJSNativeFunction(engine_, nullptr, propertyDescriptor.getter, propertyDescriptor.data);
151         NativeValue* setter =
152             new QuickJSNativeFunction(engine_, nullptr, propertyDescriptor.setter, propertyDescriptor.data);
153         if (getter != nullptr && setter != nullptr) {
154             result = JS_DefinePropertyGetSet(engine_->GetContext(), value_, jKey,
155                                              JS_DupValue(engine_->GetContext(), *getter),
156                                              JS_DupValue(engine_->GetContext(), *setter),
157                                              JS_PROP_C_W_E);
158         }
159     }
160 
161     JS_FreeAtom(engine_->GetContext(), jKey);
162 
163     return result;
164 }
165 
SetProperty(NativeValue * key,NativeValue * value)166 bool QuickJSNativeObject::SetProperty(NativeValue* key, NativeValue* value)
167 {
168     bool result = false;
169     JSAtom jKey = JS_ValueToAtom(engine_->GetContext(), *key);
170     result = JS_SetProperty(engine_->GetContext(), value_, jKey, JS_DupValue(engine_->GetContext(), *value));
171     JS_FreeAtom(engine_->GetContext(), jKey);
172 
173     return result;
174 }
175 
GetProperty(NativeValue * key)176 NativeValue* QuickJSNativeObject::GetProperty(NativeValue* key)
177 {
178     JSValue value = JS_UNDEFINED;
179     JSAtom atomKey = JS_ValueToAtom(engine_->GetContext(), *key);
180     value = JS_GetProperty(engine_->GetContext(), value_, atomKey);
181     JS_FreeAtom(engine_->GetContext(), atomKey);
182     return QuickJSNativeEngine::JSValueToNativeValue(engine_, value);
183 }
184 
HasProperty(NativeValue * key)185 bool QuickJSNativeObject::HasProperty(NativeValue* key)
186 {
187     bool result = false;
188     JSAtom jKey = JS_ValueToAtom(engine_->GetContext(), *key);
189     result = JS_HasProperty(engine_->GetContext(), value_, jKey);
190     JS_FreeAtom(engine_->GetContext(), jKey);
191     return result;
192 }
193 
DeleteProperty(NativeValue * key)194 bool QuickJSNativeObject::DeleteProperty(NativeValue* key)
195 {
196     bool result = false;
197     JSAtom jKey = JS_ValueToAtom(engine_->GetContext(), *key);
198     result = JS_DeleteProperty(engine_->GetContext(), value_, jKey, JS_PROP_THROW);
199     JS_FreeAtom(engine_->GetContext(), jKey);
200     return result;
201 }
202 
SetProperty(const char * name,NativeValue * value)203 bool QuickJSNativeObject::SetProperty(const char* name, NativeValue* value)
204 {
205     return JS_SetPropertyStr(engine_->GetContext(), value_, name, JS_DupValue(engine_->GetContext(), *value));
206 }
207 
GetProperty(const char * name)208 NativeValue* QuickJSNativeObject::GetProperty(const char* name)
209 {
210     JSValue value = JS_UNDEFINED;
211     value = JS_GetPropertyStr(engine_->GetContext(), value_, name);
212     return QuickJSNativeEngine::JSValueToNativeValue(engine_, value);
213 }
214 
HasProperty(const char * name)215 bool QuickJSNativeObject::HasProperty(const char* name)
216 {
217     bool result = false;
218     JSAtom key = JS_NewAtom(engine_->GetContext(), name);
219     result = JS_HasProperty(engine_->GetContext(), value_, key);
220     JS_FreeAtom(engine_->GetContext(), key);
221     return result;
222 }
223 
DeleteProperty(const char * name)224 bool QuickJSNativeObject::DeleteProperty(const char* name)
225 {
226     bool result = false;
227     JSAtom key = JS_NewAtom(engine_->GetContext(), name);
228     result = JS_DeleteProperty(engine_->GetContext(), value_, key, JS_PROP_THROW);
229     JS_FreeAtom(engine_->GetContext(), key);
230     return result;
231 }
232 
SetPrivateProperty(const char * name,NativeValue * value)233 bool QuickJSNativeObject::SetPrivateProperty(const char* name, NativeValue* value)
234 {
235     bool result = false;
236     JSAtom key = JS_NewAtom(engine_->GetContext(), name);
237     result = JS_SetPropertyInternal(engine_->GetContext(), value_, key, JS_DupValue(engine_->GetContext(), *value),
238                                     JS_PROP_C_W_E | JS_PROP_THROW);
239     JS_FreeAtom(engine_->GetContext(), key);
240     return result;
241 }
242 
GetPrivateProperty(const char * name)243 NativeValue* QuickJSNativeObject::GetPrivateProperty(const char* name)
244 {
245     JSValue result = JS_UNDEFINED;
246     JSAtom key = JS_NewAtom(engine_->GetContext(), name);
247     result = JS_GetPropertyInternal(engine_->GetContext(), value_, key, value_, false);
248     JS_FreeAtom(engine_->GetContext(), key);
249     return QuickJSNativeEngine::JSValueToNativeValue(engine_, result);
250 }
251 
HasPrivateProperty(const char * name)252 bool QuickJSNativeObject::HasPrivateProperty(const char* name)
253 {
254     bool result = false;
255     JSAtom key = JS_NewAtom(engine_->GetContext(), name);
256     result = JS_HasProperty(engine_->GetContext(), value_, key);
257     JS_FreeAtom(engine_->GetContext(), key);
258     return result;
259 }
260 
DeletePrivateProperty(const char * name)261 bool QuickJSNativeObject::DeletePrivateProperty(const char* name)
262 {
263     bool result = false;
264     JSAtom key = JS_NewAtom(engine_->GetContext(), name);
265     result = JS_DeleteProperty(engine_->GetContext(), value_, key, JS_PROP_C_W_E | JS_PROP_THROW);
266     JS_FreeAtom(engine_->GetContext(), key);
267     return result;
268 }
269 
GetAllPropertyNames(napi_key_collection_mode keyMode,napi_key_filter keyFilter,napi_key_conversion keyConversion)270 NativeValue* QuickJSNativeObject::GetAllPropertyNames(
271     napi_key_collection_mode keyMode, napi_key_filter keyFilter, napi_key_conversion keyConversion)
272 {
273     auto getPower = JS_PROP_CONFIGURABLE;
274     if (keyFilter == napi_key_all_properties) {
275         getPower = getPower | JS_PROP_GETSET | JS_PROP_WRITABLE | JS_PROP_ENUMERABLE | JS_PROP_CONFIGURABLE;
276     } else {
277         if (keyFilter == napi_key_writable) {
278             getPower = getPower | JS_PROP_WRITABLE | JS_PROP_GETSET;
279         }
280 
281         if (keyFilter == napi_key_enumerable) {
282             getPower = getPower | JS_PROP_ENUMERABLE;
283         }
284 
285         if (keyFilter == napi_key_configurable) {
286             getPower = getPower | JS_PROP_CONFIGURABLE;
287         }
288     }
289 
290     JSPropertyEnum* tab = nullptr;
291     uint32_t len = 0;
292 
293     JS_GetOwnPropertyNames(engine_->GetContext(), &tab, &len, value_, getPower);
294 
295     QuickJSNativeArray* propertyNames = new QuickJSNativeArray(engine_, len);
296     if (propertyNames == nullptr) {
297         HILOG_ERROR("create property names failed");
298         return nullptr;
299     }
300 
301     for (uint32_t i = 0; i < len; i++) {
302         QuickJSNativeString* name = new QuickJSNativeString(engine_, tab[i].atom);
303         propertyNames->SetElement(i, name);
304     }
305 
306     return propertyNames;
307 }
308 
AssociateTypeTag(NapiTypeTag * typeTag)309 bool QuickJSNativeObject::AssociateTypeTag(NapiTypeTag* typeTag)
310 {
311     const char name_lower[] = "ACENAPI_LOWER";
312     const char name_upper[] = "ACENAPI_UPPER";
313     bool result = false;
314     bool hasPribate = false;
315     hasPribate = HasPrivateProperty(name_lower);
316     if (!hasPribate) {
317         JSValue valueLower = JS_NewInt64(engine_->GetContext(), (uint64_t)(typeTag->lower));
318         JSValue valueUpper = JS_NewInt64(engine_->GetContext(), (uint64_t)(typeTag->upper));
319 
320         JSAtom keyLower = JS_NewAtom(engine_->GetContext(), name_lower);
321         result = JS_SetPropertyInternal(engine_->GetContext(), value_, keyLower,
322             JS_DupValue(engine_->GetContext(), valueLower), JS_PROP_C_W_E | JS_PROP_THROW);
323         JS_FreeAtom(engine_->GetContext(), keyLower);
324 
325         JSAtom keyUpper = JS_NewAtom(engine_->GetContext(), name_upper);
326         result = result && JS_SetPropertyInternal(engine_->GetContext(), value_, keyUpper,
327             JS_DupValue(engine_->GetContext(), valueUpper), JS_PROP_C_W_E | JS_PROP_THROW);
328         JS_FreeAtom(engine_->GetContext(), keyUpper);
329 
330         JS_FreeValue(engine_->GetContext(), valueLower);
331         JS_FreeValue(engine_->GetContext(), valueUpper);
332     }
333     return result;
334 }
335 
CheckTypeTag(NapiTypeTag * typeTag)336 bool QuickJSNativeObject::CheckTypeTag(NapiTypeTag* typeTag)
337 {
338     const char name_lower[] = "ACENAPI_LOWER";
339     const char name_upper[] = "ACENAPI_UPPER";
340     bool result = false;
341     result = HasPrivateProperty(name_lower);
342     if (result) {
343         JSValue valueLower = JS_UNDEFINED;
344         JSAtom key = JS_NewAtom(engine_->GetContext(), name_lower);
345         valueLower = JS_GetPropertyInternal(engine_->GetContext(), value_, key, value_, false);
346         JS_FreeAtom(engine_->GetContext(), key);
347 
348         JSValue valueUpper = JS_UNDEFINED;
349         key = JS_NewAtom(engine_->GetContext(), name_upper);
350         valueUpper = JS_GetPropertyInternal(engine_->GetContext(), value_, key, value_, false);
351         JS_FreeAtom(engine_->GetContext(), key);
352 
353         int64_t bigintLower = 0;
354         int64_t bigintUpper = 0;
355         JS_ToInt64(engine_->GetContext(), &bigintLower, valueLower);
356         JS_ToInt64(engine_->GetContext(), &bigintUpper, valueUpper);
357 
358         if (((uint64_t)bigintLower != typeTag->lower) || ((uint64_t)bigintUpper != typeTag->upper)) {
359             result = false;
360         }
361     }
362     return result;
363 }
364 
Freeze()365 void QuickJSNativeObject::Freeze()
366 {
367     JS_Freeze(engine_->GetContext(), value_);
368 }
369 
Seal()370 void QuickJSNativeObject::Seal()
371 {
372     JS_Seal(engine_->GetContext(), value_);
373 }