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 if (!IsFunction(pandaRuntime)) {
146 return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
147 }
148 std::vector<Local<JSValueRef>> arguments;
149 arguments.reserve(argc);
150 for (const shared_ptr<JsValue> &arg : argv) {
151 arguments.emplace_back(std::static_pointer_cast<ArkJSValue>(arg)->GetValue(pandaRuntime));
152 }
153 Local<JSValueRef> thisValue = std::static_pointer_cast<ArkJSValue>(thisObj)->GetValue(pandaRuntime);
154 Local<FunctionRef> function(GetValue(pandaRuntime));
155 Local<JSValueRef> result = function->Call(vm, thisValue, arguments.data(), argc);
156 Local<ObjectRef> exception = JSNApi::GetUncaughtException(vm);
157 pandaRuntime->HandleUncaughtException();
158 if (!exception.IsEmpty() && !exception->IsHole()) {
159 result = JSValueRef::Undefined(vm);
160 }
161 return std::make_shared<ArkJSValue>(pandaRuntime, result);
162 }
163
GetPropertyNames(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> & propName,int32_t & len)164 bool ArkJSValue::GetPropertyNames(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> &propName, int32_t &len)
165 {
166 shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
167 const EcmaVM* vm = pandaRuntime->GetEcmaVm();
168 LocalScope scope(vm);
169 if (CheckException(pandaRuntime)) {
170 LOGE("ArkJSValue::GetPropertyNames occurs exception, return false directly");
171 return false;
172 }
173 Local<ObjectRef> obj = value_->ToObject(vm);
174 if (CheckException(pandaRuntime, obj)) {
175 LOGE("ArkJSValue::GetPropertyNames occurs exception, return false directly");
176 return false;
177 }
178 Local<ArrayRef> names = obj->GetOwnPropertyNames(vm);
179 len = names->Length(vm);
180 if (!propName) {
181 propName = std::make_shared<ArkJSValue>(pandaRuntime, names);
182 } else {
183 std::static_pointer_cast<ArkJSValue>(propName)->SetValue(pandaRuntime, names);
184 }
185 return true;
186 }
187
GetEnumerablePropertyNames(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> & propName,int32_t & len)188 bool ArkJSValue::GetEnumerablePropertyNames(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> &propName, int32_t &len)
189 {
190 shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
191 const EcmaVM* vm = pandaRuntime->GetEcmaVm();
192 LocalScope scope(vm);
193 if (CheckException(pandaRuntime)) {
194 LOGE("ArkJSValue::GetEnumerablePropertyNames occurs exception, return false directly");
195 return false;
196 }
197 Local<ObjectRef> obj = value_->ToObject(vm);
198 if (CheckException(pandaRuntime, obj)) {
199 LOGE("ArkJSValue::GetEnumerablePropertyNames occurs exception, return false directly");
200 return false;
201 }
202 Local<ArrayRef> names = obj->GetOwnEnumerablePropertyNames(vm);
203 len = names->Length(vm);
204 if (!propName) {
205 propName = std::make_shared<ArkJSValue>(pandaRuntime, names);
206 } else {
207 std::static_pointer_cast<ArkJSValue>(propName)->SetValue(pandaRuntime, names);
208 }
209 return true;
210 }
211
GetProperty(shared_ptr<JsRuntime> runtime,int32_t idx)212 shared_ptr<JsValue> ArkJSValue::GetProperty(shared_ptr<JsRuntime> runtime, int32_t idx)
213 {
214 shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
215 const EcmaVM* vm = pandaRuntime->GetEcmaVm();
216 LocalScope scope(vm);
217 if (CheckException(pandaRuntime)) {
218 LOGE("ArkJSValue::GetProperty occurs exception, return undefined directly");
219 return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
220 }
221 Local<ObjectRef> obj = value_->ToObject(vm);
222 if (CheckException(pandaRuntime, obj)) {
223 LOGE("ArkJSValue::GetProperty occurs exception, return undefined directly");
224 return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
225 }
226 Local<JSValueRef> property = obj->Get(vm, idx);
227 if (CheckException(pandaRuntime, property)) {
228 LOGE("ArkJSValue::GetProperty occurs exception, return undefined directly");
229 return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
230 }
231 return std::make_shared<ArkJSValue>(pandaRuntime, property);
232 }
233
GetProperty(shared_ptr<JsRuntime> runtime,const std::string & name)234 shared_ptr<JsValue> ArkJSValue::GetProperty(shared_ptr<JsRuntime> runtime, const std::string &name)
235 {
236 shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
237 LocalScope scope(pandaRuntime->GetEcmaVm());
238 shared_ptr<JsValue> key = pandaRuntime->NewString(name);
239 return GetProperty(runtime, key);
240 }
241
GetProperty(shared_ptr<JsRuntime> runtime,const shared_ptr<JsValue> & name)242 shared_ptr<JsValue> ArkJSValue::GetProperty(shared_ptr<JsRuntime> runtime, const shared_ptr<JsValue> &name)
243 {
244 shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
245 const EcmaVM* vm = pandaRuntime->GetEcmaVm();
246 LocalScope scope(vm);
247 if (CheckException(pandaRuntime)) {
248 LOGE("ArkJSValue::GetProperty occurs exception, return undefined directly");
249 return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
250 }
251 Local<ObjectRef> obj = value_->ToObject(vm);
252 if (CheckException(pandaRuntime, obj)) {
253 LOGE("ArkJSValue::GetProperty occurs exception, return undefined directly");
254 return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
255 }
256 Local<JSValueRef> key = std::static_pointer_cast<ArkJSValue>(name)->GetValue(pandaRuntime);
257 Local<JSValueRef> property = obj->Get(vm, key);
258 if (CheckException(pandaRuntime, property)) {
259 LOGE("ArkJSValue::GetProperty occurs exception, return undefined directly");
260 return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
261 }
262 return std::make_shared<ArkJSValue>(pandaRuntime, property);
263 }
264
SetProperty(shared_ptr<JsRuntime> runtime,const std::string & name,const shared_ptr<JsValue> & value)265 bool ArkJSValue::SetProperty(shared_ptr<JsRuntime> runtime, const std::string &name, const shared_ptr<JsValue> &value)
266 {
267 shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
268 LocalScope scope(pandaRuntime->GetEcmaVm());
269 shared_ptr<JsValue> key = pandaRuntime->NewString(name);
270 return SetProperty(runtime, key, value);
271 }
272
SetProperty(shared_ptr<JsRuntime> runtime,const shared_ptr<JsValue> & name,const shared_ptr<JsValue> & value)273 bool ArkJSValue::SetProperty(shared_ptr<JsRuntime> runtime, const shared_ptr<JsValue> &name,
274 const shared_ptr<JsValue> &value)
275 {
276 shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
277 const EcmaVM* vm = pandaRuntime->GetEcmaVm();
278 LocalScope scope(vm);
279 if (CheckException(pandaRuntime)) {
280 LOGE("ArkJSValue::SetProperty occurs exception, return false directly");
281 return false;
282 }
283 Local<ObjectRef> obj = value_->ToObject(vm);
284 if (CheckException(pandaRuntime, obj)) {
285 LOGE("ArkJSValue::SetProperty occurs exception, return false directly");
286 return false;
287 }
288 Local<JSValueRef> key = std::static_pointer_cast<ArkJSValue>(name)->GetValue(pandaRuntime);
289 Local<JSValueRef> value_ref = std::static_pointer_cast<ArkJSValue>(value)->GetValue(pandaRuntime);
290 return obj->Set(vm, key, value_ref);
291 }
292
SetAccessorProperty(shared_ptr<JsRuntime> runtime,const std::string & name,const shared_ptr<JsValue> & getter,const shared_ptr<JsValue> & setter)293 bool ArkJSValue::SetAccessorProperty(shared_ptr<JsRuntime> runtime, const std::string &name,
294 const shared_ptr<JsValue> &getter, const shared_ptr<JsValue> &setter)
295 {
296 shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
297 LocalScope scope(pandaRuntime->GetEcmaVm());
298 shared_ptr<JsValue> key = pandaRuntime->NewString(name);
299 return SetAccessorProperty(runtime, key, getter, setter);
300 }
301
SetAccessorProperty(shared_ptr<JsRuntime> runtime,const shared_ptr<JsValue> & name,const shared_ptr<JsValue> & getter,const shared_ptr<JsValue> & setter)302 bool ArkJSValue::SetAccessorProperty(shared_ptr<JsRuntime> runtime, const shared_ptr<JsValue> &name,
303 const shared_ptr<JsValue> &getter, const shared_ptr<JsValue> &setter)
304 {
305 shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
306 const EcmaVM* vm = pandaRuntime->GetEcmaVm();
307 LocalScope scope(vm);
308 if (CheckException(pandaRuntime)) {
309 LOGE("ArkJSValue::SetAccessorProperty occurs exception, return false directly");
310 return false;
311 }
312 Local<ObjectRef> obj = value_->ToObject(vm);
313 if (CheckException(pandaRuntime, obj)) {
314 LOGE("ArkJSValue::SetAccessorProperty occurs exception, return false directly");
315 return false;
316 }
317 Local<JSValueRef> key = std::static_pointer_cast<ArkJSValue>(name)->GetValue(pandaRuntime);
318 Local<JSValueRef> getterValue = std::static_pointer_cast<ArkJSValue>(getter)->GetValue(pandaRuntime);
319 Local<JSValueRef> setterValue = std::static_pointer_cast<ArkJSValue>(setter)->GetValue(pandaRuntime);
320 return obj->SetAccessorProperty(vm, key, getterValue, setterValue);
321 }
322
HasProperty(shared_ptr<JsRuntime> runtime,const std::string & name)323 bool ArkJSValue::HasProperty(shared_ptr<JsRuntime> runtime, const std::string &name)
324 {
325 shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
326 LocalScope scope(pandaRuntime->GetEcmaVm());
327 shared_ptr<JsValue> key = pandaRuntime->NewString(name);
328 return HasProperty(runtime, key);
329 }
330
HasProperty(shared_ptr<JsRuntime> runtime,const shared_ptr<JsValue> & name)331 bool ArkJSValue::HasProperty(shared_ptr<JsRuntime> runtime, const shared_ptr<JsValue> &name)
332 {
333 shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
334 const EcmaVM* vm = pandaRuntime->GetEcmaVm();
335 LocalScope scope(vm);
336 if (CheckException(pandaRuntime)) {
337 LOGE("ArkJSValue::HasProperty occurs exception, return false directly");
338 return false;
339 }
340 Local<ObjectRef> obj = value_->ToObject(vm);
341 if (CheckException(pandaRuntime, obj)) {
342 LOGE("ArkJSValue::HasProperty occurs exception, return false directly");
343 return false;
344 }
345 Local<JSValueRef> key = std::static_pointer_cast<ArkJSValue>(name)->GetValue(pandaRuntime);
346 bool hasProperty = obj->Has(vm, key);
347 if (CheckException(pandaRuntime)) {
348 LOGE("ArkJSValue::HasProperty occurs exception, return false directly");
349 return false;
350 }
351 return hasProperty;
352 }
353
GetArrayLength(shared_ptr<JsRuntime> runtime)354 int32_t ArkJSValue::GetArrayLength(shared_ptr<JsRuntime> runtime)
355 {
356 shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
357 const EcmaVM* vm = pandaRuntime->GetEcmaVm();
358 LocalScope scope(vm);
359 if (CheckException(pandaRuntime)) {
360 LOGE("ArkJSValue::GetArrayLength occurs exception, return -1 directly");
361 return -1;
362 }
363 Local<ArrayRef> array(GetValue(pandaRuntime));
364 return array->Length(vm);
365 }
366
GetElement(shared_ptr<JsRuntime> runtime,int32_t idx)367 shared_ptr<JsValue> ArkJSValue::GetElement(shared_ptr<JsRuntime> runtime, int32_t idx)
368 {
369 shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
370 const EcmaVM* vm = pandaRuntime->GetEcmaVm();
371 LocalScope scope(vm);
372 if (CheckException(pandaRuntime)) {
373 LOGE("ArkJSValue::GetElement occurs exception, return undefined directly");
374 return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
375 }
376 Local<ArrayRef> obj(GetValue(pandaRuntime));
377 if (CheckException(pandaRuntime, obj)) {
378 LOGE("ArkJSValue::GetElement occurs exception, return undefined directly");
379 return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
380 }
381 Local<JSValueRef> property = obj->Get(vm, idx);
382 if (CheckException(pandaRuntime, property)) {
383 LOGE("ArkJSValue::GetElement occurs exception, return undefined directly");
384 return std::make_shared<ArkJSValue>(pandaRuntime, JSValueRef::Undefined(vm));
385 }
386 return std::make_shared<ArkJSValue>(pandaRuntime, property);
387 }
388
GetJsonString(const shared_ptr<JsRuntime> & runtime)389 std::string ArkJSValue::GetJsonString(const shared_ptr<JsRuntime>& runtime)
390 {
391 shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
392 const EcmaVM* vm = pandaRuntime->GetEcmaVm();
393 LocalScope scope(vm);
394 auto stringify = panda::JSON::Stringify(vm, GetValue(pandaRuntime));
395 if (CheckException(pandaRuntime, stringify)) {
396 LOGE("ArkJSValue::GetJsonString occurs exception, return empty string directly");
397 return "";
398 }
399 auto valueStr = panda::Local<panda::StringRef>(stringify);
400 if (CheckException(pandaRuntime, valueStr)) {
401 LOGE("ArkJSValue::GetJsonString occurs exception, return empty string directly");
402 return "";
403 }
404 return valueStr->ToString();
405 }
406
CheckException(const shared_ptr<ArkJSRuntime> & runtime) const407 bool ArkJSValue::CheckException(const shared_ptr<ArkJSRuntime> &runtime) const
408 {
409 return value_.IsEmpty() || runtime->HasPendingException();
410 }
411
CheckException(const shared_ptr<ArkJSRuntime> & runtime,const Local<JSValueRef> & value) const412 bool ArkJSValue::CheckException(const shared_ptr<ArkJSRuntime> &runtime, const Local<JSValueRef> &value) const
413 {
414 return value.IsEmpty() || runtime->HasPendingException();
415 }
416 } // namespace OHOS::Ace::Framework