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 "frameworks/bridge/js_frontend/engine/jsi/ark_js_runtime.h"
17
18 #include "ecmascript/napi/include/dfx_jsnapi.h"
19
20 #include "frameworks/base/log/log_wrapper.h"
21 #include "frameworks/base/utils/system_properties.h"
22 #include "frameworks/bridge/common/utils/utils.h"
23 #include "frameworks/bridge/js_frontend/engine/jsi/ark_js_value.h"
24 #include "frameworks/core/common/connect_server_manager.h"
25
26 // NOLINTNEXTLINE(readability-identifier-naming)
27 namespace OHOS::Ace::Framework {
28 // NOLINTNEXTLINE(readability-identifier-naming)
29 static constexpr auto PANDA_MAIN_FUNCTION = "_GLOBAL::func_main_0";
30 #if !defined(PREVIEW)
31 constexpr int32_t FORMAT_JSON = 1;
32 #endif
33
FunctionCallback(panda::JsiRuntimeCallInfo * info)34 Local<JSValueRef> FunctionCallback(panda::JsiRuntimeCallInfo* info)
35 {
36 auto package = reinterpret_cast<PandaFunctionData*>(info->GetData());
37 if (package == nullptr) {
38 return JSValueRef::Undefined(info->GetVM());
39 }
40 return package->Callback(info);
41 }
42
FunctionDeleter(void * nativePointer,void * data)43 void FunctionDeleter(void *nativePointer, void *data)
44 {
45 auto info = reinterpret_cast<PandaFunctionData*>(data);
46 if (info != nullptr) {
47 delete info;
48 }
49 }
50
Initialize(const std::string & libraryPath,bool isDebugMode,int32_t instanceId)51 bool ArkJSRuntime::Initialize(const std::string& libraryPath, bool isDebugMode, int32_t instanceId)
52 {
53 RuntimeOption option;
54 option.SetGcType(RuntimeOption::GC_TYPE::GEN_GC);
55 #ifdef OHOS_PLATFORM
56 option.SetArkProperties(SystemProperties::GetArkProperties());
57 option.SetArkBundleName(SystemProperties::GetArkBundleName());
58 option.SetGcThreadNum(SystemProperties::GetGcThreadNum());
59 option.SetLongPauseTime(SystemProperties::GetLongPauseTime());
60 option.SetEnableAsmInterpreter(SystemProperties::GetAsmInterpreterEnabled());
61 option.SetAsmOpcodeDisableRange(SystemProperties::GetAsmOpcodeDisableRange());
62 LOGI("Initialize ark properties = %{public}d, bundlename = %{public}s", SystemProperties::GetArkProperties(),
63 SystemProperties::GetArkBundleName().c_str());
64 #endif
65 const int64_t poolSize = 0x10000000; // 256M
66 option.SetGcPoolSize(poolSize);
67 option.SetLogLevel(RuntimeOption::LOG_LEVEL::INFO);
68 option.SetLogBufPrint(print_);
69 option.SetDebuggerLibraryPath(libraryPath);
70 libPath_ = libraryPath;
71 isDebugMode_ = isDebugMode;
72 instanceId_ = instanceId;
73
74 vm_ = JSNApi::CreateJSVM(option);
75 return vm_ != nullptr;
76 }
77
InitializeFromExistVM(EcmaVM * vm)78 bool ArkJSRuntime::InitializeFromExistVM(EcmaVM* vm)
79 {
80 vm_ = vm;
81 usingExistVM_ = true;
82 return vm_ != nullptr;
83 }
84
Reset()85 void ArkJSRuntime::Reset()
86 {
87 if (vm_ != nullptr) {
88 if (!usingExistVM_) {
89 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
90 JSNApi::StopDebugger(vm_);
91 #endif
92 JSNApi::DestroyJSVM(vm_);
93 vm_ = nullptr;
94 }
95 }
96 #if defined(PREVIEW)
97 previewComponents_.clear();
98 #endif
99 }
100
SetLogPrint(LOG_PRINT out)101 void ArkJSRuntime::SetLogPrint(LOG_PRINT out)
102 {
103 print_ = out;
104 }
105
StartDebugger()106 bool ArkJSRuntime::StartDebugger()
107 {
108 bool ret = false;
109 #if !defined(PREVIEW)
110 if (!libPath_.empty()) {
111 #if !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
112 ConnectServerManager::Get().AddInstance(instanceId_);
113 ret = JSNApi::StartDebugger(libPath_.c_str(), vm_, isDebugMode_, instanceId_, debuggerPostTask_);
114 #elif defined(ANDROID_PLATFORM)
115 ret = JSNApi::StartDebugger(libPath_.c_str(), vm_, isDebugMode_, instanceId_, debuggerPostTask_);
116 #elif defined(IOS_PLATFORM)
117 ret = JSNApi::StartDebugger(vm_, isDebugMode_, instanceId_, debuggerPostTask_);
118 #endif
119 }
120 #endif
121 return ret;
122 }
123
ExecuteModuleBuffer(const uint8_t * data,int32_t size,const std::string & filename,bool needUpdate)124 bool ArkJSRuntime::ExecuteModuleBuffer(const uint8_t* data, int32_t size, const std::string& filename, bool needUpdate)
125 {
126 #if defined(PREVIEW)
127 return JSNApi::ExecuteModuleBuffer(vm_, data, size, filename, needUpdate);
128 #else
129 JSExecutionScope executionScope(vm_);
130 LocalScope scope(vm_);
131 bool ret = JSNApi::ExecuteModuleBuffer(vm_, data, size, filename, needUpdate);
132 HandleUncaughtException();
133 return ret;
134 #endif
135 }
136
EvaluateJsCode(const std::string & src)137 shared_ptr<JsValue> ArkJSRuntime::EvaluateJsCode([[maybe_unused]] const std::string& src)
138 {
139 return NewUndefined();
140 }
141
EvaluateJsCode(const uint8_t * buffer,int32_t size,const std::string & filePath,bool needUpdate)142 bool ArkJSRuntime::EvaluateJsCode(const uint8_t* buffer, int32_t size, const std::string& filePath, bool needUpdate)
143 {
144 JSExecutionScope executionScope(vm_);
145 LocalScope scope(vm_);
146 bool ret = JSNApi::Execute(vm_, buffer, size, PANDA_MAIN_FUNCTION, filePath, needUpdate);
147 HandleUncaughtException();
148 return ret;
149 }
150
ExecuteJsBin(const std::string & fileName,const std::function<void (const std::string &,int32_t)> & errorCallback)151 bool ArkJSRuntime::ExecuteJsBin(const std::string& fileName,
152 const std::function<void(const std::string&, int32_t)>& errorCallback)
153 {
154 JSExecutionScope executionScope(vm_);
155 LocalScope scope(vm_);
156 bool ret = JSNApi::Execute(vm_, fileName, PANDA_MAIN_FUNCTION);
157 HandleUncaughtException(errorCallback);
158 return ret;
159 }
160
GetGlobal()161 shared_ptr<JsValue> ArkJSRuntime::GetGlobal()
162 {
163 LocalScope scope(vm_);
164 return std::make_shared<ArkJSValue>(shared_from_this(), JSNApi::GetGlobalObject(vm_));
165 }
166
RunGC()167 void ArkJSRuntime::RunGC()
168 {
169 JSExecutionScope executionScope(vm_);
170 LocalScope scope(vm_);
171 JSNApi::TriggerGC(vm_);
172 }
173
RunFullGC()174 void ArkJSRuntime::RunFullGC()
175 {
176 JSExecutionScope executionScope(vm_);
177 LocalScope scope(vm_);
178 JSNApi::TriggerGC(vm_, JSNApi::TRIGGER_GC_TYPE::FULL_GC);
179 }
180
NewInt32(int32_t value)181 shared_ptr<JsValue> ArkJSRuntime::NewInt32(int32_t value)
182 {
183 LocalScope scope(vm_);
184 return std::make_shared<ArkJSValue>(shared_from_this(), IntegerRef::New(vm_, value));
185 }
186
NewBoolean(bool value)187 shared_ptr<JsValue> ArkJSRuntime::NewBoolean(bool value)
188 {
189 LocalScope scope(vm_);
190 return std::make_shared<ArkJSValue>(shared_from_this(), BooleanRef::New(vm_, value));
191 }
192
NewNumber(double d)193 shared_ptr<JsValue> ArkJSRuntime::NewNumber(double d)
194 {
195 LocalScope scope(vm_);
196 return std::make_shared<ArkJSValue>(shared_from_this(), NumberRef::New(vm_, d));
197 }
198
NewNull()199 shared_ptr<JsValue> ArkJSRuntime::NewNull()
200 {
201 LocalScope scope(vm_);
202 return std::make_shared<ArkJSValue>(shared_from_this(), JSValueRef::Null(vm_));
203 }
204
NewUndefined()205 shared_ptr<JsValue> ArkJSRuntime::NewUndefined()
206 {
207 LocalScope scope(vm_);
208 return std::make_shared<ArkJSValue>(shared_from_this(), JSValueRef::Undefined(vm_));
209 }
210
NewString(const std::string & str)211 shared_ptr<JsValue> ArkJSRuntime::NewString(const std::string& str)
212 {
213 LocalScope scope(vm_);
214 return std::make_shared<ArkJSValue>(shared_from_this(), StringRef::NewFromUtf8(vm_, str.c_str()));
215 }
216
ParseJson(const std::string & str)217 shared_ptr<JsValue> ArkJSRuntime::ParseJson(const std::string& str)
218 {
219 LocalScope scope(vm_);
220 Local<StringRef> string = StringRef::NewFromUtf8(vm_, str.c_str());
221 return std::make_shared<ArkJSValue>(shared_from_this(), JSON::Parse(vm_, string));
222 }
223
NewObject()224 shared_ptr<JsValue> ArkJSRuntime::NewObject()
225 {
226 LocalScope scope(vm_);
227 return std::make_shared<ArkJSValue>(shared_from_this(), ObjectRef::New(vm_));
228 }
229
NewArray()230 shared_ptr<JsValue> ArkJSRuntime::NewArray()
231 {
232 LocalScope scope(vm_);
233 return std::make_shared<ArkJSValue>(shared_from_this(), ArrayRef::New(vm_));
234 }
235
NewFunction(RegisterFunctionType func)236 shared_ptr<JsValue> ArkJSRuntime::NewFunction(RegisterFunctionType func)
237 {
238 LocalScope scope(vm_);
239 auto data = new PandaFunctionData(shared_from_this(), func);
240 return std::make_shared<ArkJSValue>(shared_from_this(),
241 FunctionRef::New(vm_, FunctionCallback, FunctionDeleter, data));
242 }
243
NewNativePointer(void * ptr)244 shared_ptr<JsValue> ArkJSRuntime::NewNativePointer(void* ptr)
245 {
246 LocalScope scope(vm_);
247 return std::make_shared<ArkJSValue>(shared_from_this(), NativePointerRef::New(vm_, ptr));
248 }
249
ThrowError(const std::string & msg,int32_t code)250 void ArkJSRuntime::ThrowError(const std::string& msg, int32_t code)
251 {
252 auto errorVal = panda::Exception::Error(vm_, panda::StringRef::NewFromUtf8(vm_, msg.c_str()));
253 auto codeVal = panda::Exception::Error(vm_, panda::StringRef::NewFromUtf8(vm_, std::to_string(code).c_str()));
254 Local<StringRef> codeKey = StringRef::NewFromUtf8(vm_, "code");
255 Local<ObjectRef> errorObj(errorVal);
256 errorObj->Set(vm_, codeKey, codeVal);
257 panda::JSNApi::ThrowException(vm_, errorObj);
258 }
259
RegisterUncaughtExceptionHandler(UncaughtExceptionCallback callback)260 void ArkJSRuntime::RegisterUncaughtExceptionHandler(UncaughtExceptionCallback callback)
261 {
262 JSNApi::EnableUserUncaughtErrorHandler(vm_);
263 uncaughtErrorHandler_ = callback;
264 }
265
HasPendingException()266 bool ArkJSRuntime::HasPendingException()
267 {
268 return JSNApi::HasPendingException(vm_);
269 }
270
HandleUncaughtException(const std::function<void (const std::string &,int32_t)> & errorCallback)271 void ArkJSRuntime::HandleUncaughtException(
272 const std::function<void(const std::string&, int32_t)>& errorCallback)
273 {
274 if (uncaughtErrorHandler_ == nullptr) {
275 LOGE("uncaughtErrorHandler is null.");
276 return;
277 }
278
279 Local<ObjectRef> exception = JSNApi::GetAndClearUncaughtException(vm_);
280 if (!exception.IsEmpty() && !exception->IsHole() && errorCallback != nullptr) {
281 errorCallback("The uri of router is not exist.", Framework::ERROR_CODE_URI_ERROR);
282 return;
283 }
284
285 if (!exception.IsEmpty() && !exception->IsHole()) {
286 LOGI("HandleUncaughtException catch exception.");
287 shared_ptr<JsValue> errorPtr =
288 std::static_pointer_cast<JsValue>(std::make_shared<ArkJSValue>(shared_from_this(), exception));
289 uncaughtErrorHandler_(errorPtr, shared_from_this());
290 }
291 }
292
ExecutePendingJob()293 void ArkJSRuntime::ExecutePendingJob()
294 {
295 LocalScope scope(vm_);
296 JSNApi::ExecutePendingJob(vm_);
297 }
298
299 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
DumpHeapSnapshot(bool isPrivate)300 void ArkJSRuntime::DumpHeapSnapshot(bool isPrivate)
301 {
302 if (vm_ == nullptr) {
303 LOGW("vm_ is nullptr.");
304 }
305 LocalScope scope(vm_);
306 panda::DFXJSNApi::DumpHeapSnapshot(vm_, FORMAT_JSON, true, isPrivate);
307 }
308 #else
DumpHeapSnapshot(bool isPrivate)309 void ArkJSRuntime::DumpHeapSnapshot(bool isPrivate)
310 {
311 LOGE("Do not support Ark DumpHeapSnapshot on Windows or MacOS");
312 }
313 #endif
314
Callback(panda::JsiRuntimeCallInfo * info) const315 Local<JSValueRef> PandaFunctionData::Callback(panda::JsiRuntimeCallInfo* info) const
316 {
317 auto runtime = runtime_.lock();
318 if (runtime == nullptr) {
319 LOGE("runtime is nullptr");
320 return Local<JSValueRef>();
321 }
322 EscapeLocalScope scope(runtime->GetEcmaVm());
323 shared_ptr<JsValue> thisPtr =
324 std::static_pointer_cast<JsValue>(std::make_shared<ArkJSValue>(runtime, info->GetThisRef()));
325
326 std::vector<shared_ptr<JsValue>> argv;
327 int32_t length = info->GetArgsNumber();
328 argv.reserve(length);
329 for (int32_t i = 0; i < length; ++i) {
330 argv.emplace_back(
331 std::static_pointer_cast<JsValue>(std::make_shared<ArkJSValue>(runtime, info->GetCallArgRef(i))));
332 }
333 shared_ptr<JsValue> result = func_(runtime, thisPtr, argv, length);
334 return scope.Escape(std::static_pointer_cast<ArkJSValue>(result)->GetValue(runtime));
335 }
336
337 } // namespace OHOS::Ace::Framework
338