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