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 "frameworks/bridge/js_frontend/engine/jsi/ark_js_value.h"
17 
18 // NOLINTNEXTLINE(readability-identifier-naming)
19 namespace OHOS::Ace::Framework {
ToInt32(shared_ptr<JsRuntime> runtime)20 int32_t ArkJSValue::ToInt32(shared_ptr<JsRuntime> runtime)
21 {
22     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
23     const EcmaVM* vm = pandaRuntime->GetEcmaVm();
24     LocalScope scope(vm);
25     if (CheckException(pandaRuntime)) {
26         LOGE("ArkJSValue::ToInt32 occurs exception, return 0 directly");
27         return 0;
28     }
29     return value_->Int32Value(vm);
30 }
31 
ToDouble(shared_ptr<JsRuntime> runtime)32 double ArkJSValue::ToDouble(shared_ptr<JsRuntime> runtime)
33 {
34     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
35     const EcmaVM* vm = pandaRuntime->GetEcmaVm();
36     LocalScope scope(vm);
37     if (CheckException(pandaRuntime)) {
38         LOGE("ArkJSValue::ToDouble occurs exception, return 0 directly");
39         return 0;
40     }
41     Local<NumberRef> number = value_->ToNumber(vm);
42     if (!CheckException(pandaRuntime, number)) {
43         return number->Value();
44     }
45     LOGE("ArkJSValue::ToDouble occurs exception, return 0 directly");
46     return 0;
47 }
48 
ToString(shared_ptr<JsRuntime> runtime)49 std::string ArkJSValue::ToString(shared_ptr<JsRuntime> runtime)
50 {
51     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
52     const EcmaVM* vm = pandaRuntime->GetEcmaVm();
53     LocalScope scope(vm);
54     if (CheckException(pandaRuntime)) {
55         LOGE("ArkJSValue::ToString occurs exception, return empty string directly");
56         return "";
57     }
58     Local<StringRef> string = value_->ToString(vm);
59     if (!CheckException(pandaRuntime, string)) {
60         return string->ToString(vm);
61     }
62     LOGE("ArkJSValue::ToString occurs exception, return empty string directly");
63     return "";
64 }
65 
ToBoolean(shared_ptr<JsRuntime> runtime)66 bool ArkJSValue::ToBoolean(shared_ptr<JsRuntime> runtime)
67 {
68     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
69     LocalScope scope(pandaRuntime->GetEcmaVm());
70     if (!CheckException(pandaRuntime)) {
71         return value_->BooleaValue(pandaRuntime->GetEcmaVm());
72     }
73     LOGE("ArkJSValue::ToBoolean occurs exception, return false directly");
74     return false;
75 }
76 
77 bool ArkJSValue::IsUndefined([[maybe_unused]] shared_ptr<JsRuntime> runtime)
78 {
79     return !value_.IsEmpty() && value_->IsUndefined();
80 }
81 
82 bool ArkJSValue::IsNull([[maybe_unused]] shared_ptr<JsRuntime> runtime)
83 {
84     return !value_.IsEmpty() && value_->IsNull();
85 }
86 
87 bool ArkJSValue::IsBoolean([[maybe_unused]] shared_ptr<JsRuntime> runtime)
88 {
89     return !value_.IsEmpty() && value_->IsBoolean();
90 }
91 
92 bool ArkJSValue::IsInt32([[maybe_unused]] shared_ptr<JsRuntime> runtime)
93 {
94     return !value_.IsEmpty() && value_->IsInt();
95 }
96 
97 bool ArkJSValue::WithinInt32([[maybe_unused]] shared_ptr<JsRuntime> runtime)
98 {
99     return !value_.IsEmpty() && value_->WithinInt32();
100 }
101 
102 bool ArkJSValue::IsString([[maybe_unused]] shared_ptr<JsRuntime> runtime)
103 {
104     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
105     return !value_.IsEmpty() && value_->IsString(pandaRuntime->GetEcmaVm());
106 }
107 
108 bool ArkJSValue::IsNumber([[maybe_unused]] shared_ptr<JsRuntime> runtime)
109 {
110     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
111     return !value_.IsEmpty() && value_->IsNumber();
112 }
113 
114 bool ArkJSValue::IsObject([[maybe_unused]] shared_ptr<JsRuntime> runtime)
115 {
116     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
117     return !value_.IsEmpty() && value_->IsObject(pandaRuntime->GetEcmaVm());
118 }
119 
120 bool ArkJSValue::IsArray([[maybe_unused]] shared_ptr<JsRuntime> runtime)
121 {
122     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
123     return !value_.IsEmpty() && value_->IsArray(pandaRuntime->GetEcmaVm());
124 }
125 
126 bool ArkJSValue::IsFunction([[maybe_unused]] shared_ptr<JsRuntime> runtime)
127 {
128     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
129     return !value_.IsEmpty() && value_->IsFunction(pandaRuntime->GetEcmaVm());
130 }
131 
132 // NOLINTNEXTLINE(performance-unnecessary-value-param)
133 bool ArkJSValue::IsException([[maybe_unused]] shared_ptr<JsRuntime> runtime)
134 {
135     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
136     return value_.IsEmpty() || pandaRuntime->HasPendingException();
137 }
138 
Call(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,std::vector<shared_ptr<JsValue>> argv,int32_t argc)139 shared_ptr<JsValue> ArkJSValue::Call(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
140                                      std::vector<shared_ptr<JsValue>> argv, int32_t argc)
141 {
142     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
143     const EcmaVM* vm = pandaRuntime->GetEcmaVm();
144     JSExecutionScope executionScope(vm);
145     LocalScope scope(vm);
146     panda::TryCatch trycatch(vm);
147     if (!IsFunction(pandaRuntime)) {
148         return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
149     }
150     std::vector<Local<JSValueRef>> arguments;
151     arguments.reserve(argc);
152     for (const shared_ptr<JsValue> &arg : argv) {
153         arguments.emplace_back(std::static_pointer_cast<ArkJSValue>(arg)->GetValue(pandaRuntime));
154     }
155     Local<JSValueRef> thisValue = std::static_pointer_cast<ArkJSValue>(thisObj)->GetValue(pandaRuntime);
156     Local<FunctionRef> function(GetValue(pandaRuntime));
157     Local<JSValueRef> result = function->Call(vm, thisValue, arguments.data(), argc);
158     bool hasCaught = trycatch.HasCaught();
159     pandaRuntime->HandleUncaughtException(trycatch);
160     if (hasCaught) {
161         result = JSValueRef::Undefined(vm);
162     }
163     return std::make_shared<ArkJSValue>(pandaRuntime, result);
164 }
165 
GetPropertyNames(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> & propName,int32_t & len)166 bool ArkJSValue::GetPropertyNames(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> &propName, int32_t &len)
167 {
168     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
169     const EcmaVM* vm = pandaRuntime->GetEcmaVm();
170     LocalScope scope(vm);
171     if (CheckException(pandaRuntime)) {
172         LOGE("ArkJSValue::GetPropertyNames occurs exception, return false directly");
173         return false;
174     }
175     Local<ObjectRef> obj = value_->ToObject(vm);
176     if (CheckException(pandaRuntime, obj)) {
177         LOGE("ArkJSValue::GetPropertyNames occurs exception, return false directly");
178         return false;
179     }
180     Local<ArrayRef> names = obj->GetOwnPropertyNames(vm);
181     len = static_cast<int32_t>(names->Length(vm));
182     if (!propName) {
183         propName = std::make_shared<ArkJSValue>(pandaRuntime, names);
184     } else {
185         std::static_pointer_cast<ArkJSValue>(propName)->SetValue(pandaRuntime, names);
186     }
187     return true;
188 }
189 
GetEnumerablePropertyNames(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> & propName,int32_t & len)190 bool ArkJSValue::GetEnumerablePropertyNames(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> &propName, int32_t &len)
191 {
192     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
193     const EcmaVM* vm = pandaRuntime->GetEcmaVm();
194     LocalScope scope(vm);
195     if (CheckException(pandaRuntime)) {
196         LOGE("ArkJSValue::GetEnumerablePropertyNames occurs exception, return false directly");
197         return false;
198     }
199     Local<ObjectRef> obj = value_->ToObject(vm);
200     if (CheckException(pandaRuntime, obj)) {
201         LOGE("ArkJSValue::GetEnumerablePropertyNames occurs exception, return false directly");
202         return false;
203     }
204     Local<ArrayRef> names = obj->GetOwnEnumerablePropertyNames(vm);
205     len = static_cast<int32_t>(names->Length(vm));
206     if (!propName) {
207         propName = std::make_shared<ArkJSValue>(pandaRuntime, names);
208     } else {
209         std::static_pointer_cast<ArkJSValue>(propName)->SetValue(pandaRuntime, names);
210     }
211     return true;
212 }
213 
GetProperty(shared_ptr<JsRuntime> runtime,int32_t idx)214 shared_ptr<JsValue> ArkJSValue::GetProperty(shared_ptr<JsRuntime> runtime, int32_t idx)
215 {
216     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
217     const EcmaVM* vm = pandaRuntime->GetEcmaVm();
218     LocalScope scope(vm);
219     if (CheckException(pandaRuntime)) {
220         LOGE("ArkJSValue::GetProperty occurs exception, return undefined directly");
221         return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
222     }
223     Local<ObjectRef> obj = value_->ToObject(vm);
224     if (CheckException(pandaRuntime, obj)) {
225         LOGE("ArkJSValue::GetProperty occurs exception, return undefined directly");
226         return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
227     }
228     Local<JSValueRef> property = obj->Get(vm, idx);
229     if (CheckException(pandaRuntime, property)) {
230         LOGE("ArkJSValue::GetProperty occurs exception, return undefined directly");
231         return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
232     }
233     return std::make_shared<ArkJSValue>(pandaRuntime, property);
234 }
235 
GetProperty(shared_ptr<JsRuntime> runtime,const std::string & name)236 shared_ptr<JsValue> ArkJSValue::GetProperty(shared_ptr<JsRuntime> runtime, const std::string &name)
237 {
238     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
239     LocalScope scope(pandaRuntime->GetEcmaVm());
240     shared_ptr<JsValue> key = pandaRuntime->NewString(name);
241     return GetProperty(runtime, key);
242 }
243 
GetProperty(shared_ptr<JsRuntime> runtime,const shared_ptr<JsValue> & name)244 shared_ptr<JsValue> ArkJSValue::GetProperty(shared_ptr<JsRuntime> runtime, const shared_ptr<JsValue> &name)
245 {
246     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
247     const EcmaVM* vm = pandaRuntime->GetEcmaVm();
248     LocalScope scope(vm);
249     if (CheckException(pandaRuntime)) {
250         LOGE("ArkJSValue::GetProperty occurs exception, return undefined directly");
251         return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
252     }
253     Local<ObjectRef> obj = value_->ToObject(vm);
254     if (CheckException(pandaRuntime, obj)) {
255         LOGE("ArkJSValue::GetProperty occurs exception, return undefined directly");
256         return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
257     }
258     Local<JSValueRef> key = std::static_pointer_cast<ArkJSValue>(name)->GetValue(pandaRuntime);
259     Local<JSValueRef> property = obj->Get(vm, key);
260     if (CheckException(pandaRuntime, property)) {
261         LOGE("ArkJSValue::GetProperty occurs exception, return undefined directly");
262         return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
263     }
264     return std::make_shared<ArkJSValue>(pandaRuntime, property);
265 }
266 
SetProperty(shared_ptr<JsRuntime> runtime,const std::string & name,const shared_ptr<JsValue> & value)267 bool ArkJSValue::SetProperty(shared_ptr<JsRuntime> runtime, const std::string &name, const shared_ptr<JsValue> &value)
268 {
269     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
270     LocalScope scope(pandaRuntime->GetEcmaVm());
271     shared_ptr<JsValue> key = pandaRuntime->NewString(name);
272     return SetProperty(runtime, key, value);
273 }
274 
SetProperty(shared_ptr<JsRuntime> runtime,const shared_ptr<JsValue> & name,const shared_ptr<JsValue> & value)275 bool ArkJSValue::SetProperty(shared_ptr<JsRuntime> runtime, const shared_ptr<JsValue> &name,
276                              const shared_ptr<JsValue> &value)
277 {
278     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
279     const EcmaVM* vm = pandaRuntime->GetEcmaVm();
280     LocalScope scope(vm);
281     if (CheckException(pandaRuntime)) {
282         LOGE("ArkJSValue::SetProperty occurs exception, return false directly");
283         return false;
284     }
285     Local<ObjectRef> obj = value_->ToObject(vm);
286     if (CheckException(pandaRuntime, obj)) {
287         LOGE("ArkJSValue::SetProperty occurs exception, return false directly");
288         return false;
289     }
290     Local<JSValueRef> key = std::static_pointer_cast<ArkJSValue>(name)->GetValue(pandaRuntime);
291     Local<JSValueRef> value_ref = std::static_pointer_cast<ArkJSValue>(value)->GetValue(pandaRuntime);
292     return obj->Set(vm, key, value_ref);
293 }
294 
SetAccessorProperty(shared_ptr<JsRuntime> runtime,const std::string & name,const shared_ptr<JsValue> & getter,const shared_ptr<JsValue> & setter)295 bool ArkJSValue::SetAccessorProperty(shared_ptr<JsRuntime> runtime, const std::string &name,
296                                      const shared_ptr<JsValue> &getter, const shared_ptr<JsValue> &setter)
297 {
298     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
299     LocalScope scope(pandaRuntime->GetEcmaVm());
300     shared_ptr<JsValue> key = pandaRuntime->NewString(name);
301     return SetAccessorProperty(runtime, key, getter, setter);
302 }
303 
SetAccessorProperty(shared_ptr<JsRuntime> runtime,const shared_ptr<JsValue> & name,const shared_ptr<JsValue> & getter,const shared_ptr<JsValue> & setter)304 bool ArkJSValue::SetAccessorProperty(shared_ptr<JsRuntime> runtime, const shared_ptr<JsValue> &name,
305                                      const shared_ptr<JsValue> &getter, const shared_ptr<JsValue> &setter)
306 {
307     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
308     const EcmaVM* vm = pandaRuntime->GetEcmaVm();
309     LocalScope scope(vm);
310     if (CheckException(pandaRuntime)) {
311         LOGE("ArkJSValue::SetAccessorProperty occurs exception, return false directly");
312         return false;
313     }
314     Local<ObjectRef> obj = value_->ToObject(vm);
315     if (CheckException(pandaRuntime, obj)) {
316         LOGE("ArkJSValue::SetAccessorProperty occurs exception, return false directly");
317         return false;
318     }
319     Local<JSValueRef> key = std::static_pointer_cast<ArkJSValue>(name)->GetValue(pandaRuntime);
320     Local<JSValueRef> getterValue = std::static_pointer_cast<ArkJSValue>(getter)->GetValue(pandaRuntime);
321     Local<JSValueRef> setterValue = std::static_pointer_cast<ArkJSValue>(setter)->GetValue(pandaRuntime);
322     return obj->SetAccessorProperty(vm, key, getterValue, setterValue);
323 }
324 
HasProperty(shared_ptr<JsRuntime> runtime,const std::string & name)325 bool ArkJSValue::HasProperty(shared_ptr<JsRuntime> runtime, const std::string &name)
326 {
327     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
328     LocalScope scope(pandaRuntime->GetEcmaVm());
329     shared_ptr<JsValue> key = pandaRuntime->NewString(name);
330     return HasProperty(runtime, key);
331 }
332 
HasProperty(shared_ptr<JsRuntime> runtime,const shared_ptr<JsValue> & name)333 bool ArkJSValue::HasProperty(shared_ptr<JsRuntime> runtime, const shared_ptr<JsValue> &name)
334 {
335     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
336     const EcmaVM* vm = pandaRuntime->GetEcmaVm();
337     LocalScope scope(vm);
338     if (CheckException(pandaRuntime)) {
339         LOGE("ArkJSValue::HasProperty occurs exception, return false directly");
340         return false;
341     }
342     Local<ObjectRef> obj = value_->ToObject(vm);
343     if (CheckException(pandaRuntime, obj)) {
344         LOGE("ArkJSValue::HasProperty occurs exception, return false directly");
345         return false;
346     }
347     Local<JSValueRef> key = std::static_pointer_cast<ArkJSValue>(name)->GetValue(pandaRuntime);
348     bool hasProperty = obj->Has(vm, key);
349     if (CheckException(pandaRuntime)) {
350         LOGE("ArkJSValue::HasProperty occurs exception, return false directly");
351         return false;
352     }
353     return hasProperty;
354 }
355 
GetArrayLength(shared_ptr<JsRuntime> runtime)356 int32_t ArkJSValue::GetArrayLength(shared_ptr<JsRuntime> runtime)
357 {
358     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
359     const EcmaVM* vm = pandaRuntime->GetEcmaVm();
360     LocalScope scope(vm);
361     if (CheckException(pandaRuntime)) {
362         LOGE("ArkJSValue::GetArrayLength occurs exception, return -1 directly");
363         return -1;
364     }
365     Local<ArrayRef> array(GetValue(pandaRuntime));
366     return array->Length(vm);
367 }
368 
GetElement(shared_ptr<JsRuntime> runtime,int32_t idx)369 shared_ptr<JsValue> ArkJSValue::GetElement(shared_ptr<JsRuntime> runtime, int32_t idx)
370 {
371     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
372     const EcmaVM* vm = pandaRuntime->GetEcmaVm();
373     LocalScope scope(vm);
374     if (CheckException(pandaRuntime)) {
375         LOGE("ArkJSValue::GetElement occurs exception, return undefined directly");
376         return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
377     }
378     Local<ArrayRef> obj(GetValue(pandaRuntime));
379     if (CheckException(pandaRuntime, obj)) {
380         LOGE("ArkJSValue::GetElement occurs exception, return undefined directly");
381         return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
382     }
383     Local<JSValueRef> property = obj->Get(vm, idx);
384     if (CheckException(pandaRuntime, property)) {
385         LOGE("ArkJSValue::GetElement occurs exception, return undefined directly");
386         return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
387     }
388     return std::make_shared<ArkJSValue>(pandaRuntime, property);
389 }
390 
GetJsonString(const shared_ptr<JsRuntime> & runtime)391 std::string ArkJSValue::GetJsonString(const shared_ptr<JsRuntime>& runtime)
392 {
393     shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
394     const EcmaVM* vm = pandaRuntime->GetEcmaVm();
395     LocalScope scope(vm);
396     auto stringify = panda::JSON::Stringify(vm, GetValue(pandaRuntime));
397     if (CheckException(pandaRuntime, stringify)) {
398         LOGE("ArkJSValue::GetJsonString occurs exception, return empty string directly");
399         return "";
400     }
401     auto valueStr = panda::Local<panda::StringRef>(stringify);
402     if (CheckException(pandaRuntime, valueStr)) {
403         LOGE("ArkJSValue::GetJsonString occurs exception, return empty string directly");
404         return "";
405     }
406     return valueStr->ToString(pandaRuntime->GetEcmaVm());
407 }
408 
CheckException(const shared_ptr<ArkJSRuntime> & runtime) const409 bool ArkJSValue::CheckException(const shared_ptr<ArkJSRuntime> &runtime) const
410 {
411     return value_.IsEmpty() || runtime->HasPendingException();
412 }
413 
CheckException(const shared_ptr<ArkJSRuntime> & runtime,const Local<JSValueRef> & value) const414 bool ArkJSValue::CheckException(const shared_ptr<ArkJSRuntime> &runtime, const Local<JSValueRef> &value) const
415 {
416     return value.IsEmpty() || runtime->HasPendingException();
417 }
418 }  // namespace OHOS::Ace::Framework
419