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