• 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 "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::FOLLOW);
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     JSNApi::DebugOption debugOption = {libPath_.c_str(), isDebugMode_};
112 #if !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
113         ConnectServerManager::Get().AddInstance(instanceId_, language_);
114         ret = JSNApi::StartDebugger(vm_, debugOption, instanceId_, debuggerPostTask_);
115 #elif defined(ANDROID_PLATFORM)
116         ret = JSNApi::StartDebugger(vm_, debugOption, instanceId_, debuggerPostTask_);
117 #endif
118     }
119 #if defined(IOS_PLATFORM)
120     JSNApi::DebugOption debugOption = {nullptr, isDebugMode_};
121     ret = JSNApi::StartDebugger(vm_, debugOption, instanceId_, debuggerPostTask_);
122 #endif
123 #endif
124     return ret;
125 }
126 
ExecuteModuleBuffer(const uint8_t * data,int32_t size,const std::string & filename,bool needUpdate)127 bool ArkJSRuntime::ExecuteModuleBuffer(const uint8_t* data, int32_t size, const std::string& filename, bool needUpdate)
128 {
129 #if defined(PREVIEW)
130     return JSNApi::ExecuteModuleBuffer(vm_, data, size, filename, needUpdate);
131 #else
132     JSExecutionScope executionScope(vm_);
133     LocalScope scope(vm_);
134     bool ret = JSNApi::ExecuteModuleBuffer(vm_, data, size, filename, needUpdate);
135     HandleUncaughtException();
136     return ret;
137 #endif
138 }
139 
EvaluateJsCode(const std::string & src)140 shared_ptr<JsValue> ArkJSRuntime::EvaluateJsCode([[maybe_unused]] const std::string& src)
141 {
142     return NewUndefined();
143 }
144 
EvaluateJsCode(const uint8_t * buffer,int32_t size,const std::string & filePath,bool needUpdate)145 bool ArkJSRuntime::EvaluateJsCode(const uint8_t* buffer, int32_t size, const std::string& filePath, bool needUpdate)
146 {
147     JSExecutionScope executionScope(vm_);
148     LocalScope scope(vm_);
149     bool ret = JSNApi::Execute(vm_, buffer, size, PANDA_MAIN_FUNCTION, filePath, needUpdate);
150     HandleUncaughtException();
151     return ret;
152 }
153 
ExecuteJsBin(const std::string & fileName,const std::function<void (const std::string &,int32_t)> & errorCallback)154 bool ArkJSRuntime::ExecuteJsBin(const std::string& fileName,
155     const std::function<void(const std::string&, int32_t)>& errorCallback)
156 {
157     JSExecutionScope executionScope(vm_);
158     LocalScope scope(vm_);
159     bool ret = JSNApi::Execute(vm_, fileName, PANDA_MAIN_FUNCTION);
160     HandleUncaughtException(errorCallback);
161     return ret;
162 }
163 
GetGlobal()164 shared_ptr<JsValue> ArkJSRuntime::GetGlobal()
165 {
166     LocalScope scope(vm_);
167     return std::make_shared<ArkJSValue>(shared_from_this(), JSNApi::GetGlobalObject(vm_));
168 }
169 
RunGC()170 void ArkJSRuntime::RunGC()
171 {
172     JSExecutionScope executionScope(vm_);
173     LocalScope scope(vm_);
174     JSNApi::TriggerGC(vm_);
175 }
176 
RunFullGC()177 void ArkJSRuntime::RunFullGC()
178 {
179     JSExecutionScope executionScope(vm_);
180     LocalScope scope(vm_);
181     JSNApi::TriggerGC(vm_, JSNApi::TRIGGER_GC_TYPE::FULL_GC);
182 }
183 
NewInt32(int32_t value)184 shared_ptr<JsValue> ArkJSRuntime::NewInt32(int32_t value)
185 {
186     LocalScope scope(vm_);
187     return std::make_shared<ArkJSValue>(shared_from_this(), IntegerRef::New(vm_, value));
188 }
189 
NewBoolean(bool value)190 shared_ptr<JsValue> ArkJSRuntime::NewBoolean(bool value)
191 {
192     LocalScope scope(vm_);
193     return std::make_shared<ArkJSValue>(shared_from_this(), BooleanRef::New(vm_, value));
194 }
195 
NewNumber(double d)196 shared_ptr<JsValue> ArkJSRuntime::NewNumber(double d)
197 {
198     LocalScope scope(vm_);
199     return std::make_shared<ArkJSValue>(shared_from_this(), NumberRef::New(vm_, d));
200 }
201 
NewNull()202 shared_ptr<JsValue> ArkJSRuntime::NewNull()
203 {
204     LocalScope scope(vm_);
205     return std::make_shared<ArkJSValue>(shared_from_this(), JSValueRef::Null(vm_));
206 }
207 
NewUndefined()208 shared_ptr<JsValue> ArkJSRuntime::NewUndefined()
209 {
210     LocalScope scope(vm_);
211     return std::make_shared<ArkJSValue>(shared_from_this(), JSValueRef::Undefined(vm_));
212 }
213 
NewString(const std::string & str)214 shared_ptr<JsValue> ArkJSRuntime::NewString(const std::string& str)
215 {
216     LocalScope scope(vm_);
217     return std::make_shared<ArkJSValue>(shared_from_this(), StringRef::NewFromUtf8(vm_, str.c_str()));
218 }
219 
ParseJson(const std::string & str)220 shared_ptr<JsValue> ArkJSRuntime::ParseJson(const std::string& str)
221 {
222     LocalScope scope(vm_);
223     Local<StringRef> string = StringRef::NewFromUtf8(vm_, str.c_str());
224     return std::make_shared<ArkJSValue>(shared_from_this(), JSON::Parse(vm_, string));
225 }
226 
NewObject()227 shared_ptr<JsValue> ArkJSRuntime::NewObject()
228 {
229     LocalScope scope(vm_);
230     return std::make_shared<ArkJSValue>(shared_from_this(), ObjectRef::New(vm_));
231 }
232 
NewArray()233 shared_ptr<JsValue> ArkJSRuntime::NewArray()
234 {
235     LocalScope scope(vm_);
236     return std::make_shared<ArkJSValue>(shared_from_this(), ArrayRef::New(vm_));
237 }
238 
NewFunction(RegisterFunctionType func)239 shared_ptr<JsValue> ArkJSRuntime::NewFunction(RegisterFunctionType func)
240 {
241     LocalScope scope(vm_);
242     auto data = new PandaFunctionData(shared_from_this(), func);
243     return std::make_shared<ArkJSValue>(shared_from_this(),
244         FunctionRef::New(vm_, FunctionCallback, FunctionDeleter, data));
245 }
246 
NewNativePointer(void * ptr)247 shared_ptr<JsValue> ArkJSRuntime::NewNativePointer(void* ptr)
248 {
249     LocalScope scope(vm_);
250     return std::make_shared<ArkJSValue>(shared_from_this(), NativePointerRef::New(vm_, ptr));
251 }
252 
ThrowError(const std::string & msg,int32_t code)253 void ArkJSRuntime::ThrowError(const std::string& msg, int32_t code)
254 {
255     auto errorVal = panda::Exception::Error(vm_, panda::StringRef::NewFromUtf8(vm_, msg.c_str()));
256     auto codeVal = panda::Exception::Error(vm_, panda::StringRef::NewFromUtf8(vm_, std::to_string(code).c_str()));
257     Local<StringRef> codeKey = StringRef::NewFromUtf8(vm_, "code");
258     Local<ObjectRef> errorObj(errorVal);
259     errorObj->Set(vm_, codeKey, codeVal);
260     panda::JSNApi::ThrowException(vm_, errorObj);
261 }
262 
RegisterUncaughtExceptionHandler(UncaughtExceptionCallback callback)263 void ArkJSRuntime::RegisterUncaughtExceptionHandler(UncaughtExceptionCallback callback)
264 {
265     JSNApi::EnableUserUncaughtErrorHandler(vm_);
266     uncaughtErrorHandler_ = callback;
267 }
268 
HasPendingException()269 bool ArkJSRuntime::HasPendingException()
270 {
271     return JSNApi::HasPendingException(vm_);
272 }
273 
HandleUncaughtException(const std::function<void (const std::string &,int32_t)> & errorCallback)274 void ArkJSRuntime::HandleUncaughtException(
275     const std::function<void(const std::string&, int32_t)>& errorCallback)
276 {
277     if (uncaughtErrorHandler_ == nullptr) {
278         LOGE("uncaughtErrorHandler is null.");
279         return;
280     }
281 
282     Local<ObjectRef> exception = JSNApi::GetAndClearUncaughtException(vm_);
283     if (!exception.IsEmpty() && !exception->IsHole() && errorCallback != nullptr) {
284         errorCallback("loading js file has crash or the uri of router is not exist.", Framework::ERROR_CODE_URI_ERROR);
285         return;
286     }
287 
288     if (!exception.IsEmpty() && !exception->IsHole()) {
289         LOGI("HandleUncaughtException catch exception.");
290         shared_ptr<JsValue> errorPtr =
291             std::static_pointer_cast<JsValue>(std::make_shared<ArkJSValue>(shared_from_this(), exception));
292         uncaughtErrorHandler_(errorPtr, shared_from_this());
293     }
294 }
295 
ExecutePendingJob()296 void ArkJSRuntime::ExecutePendingJob()
297 {
298     LocalScope scope(vm_);
299     JSNApi::ExecutePendingJob(vm_);
300 }
301 
302 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
DumpHeapSnapshot(bool isPrivate)303 void ArkJSRuntime::DumpHeapSnapshot(bool isPrivate)
304 {
305     if (vm_ == nullptr) {
306         LOGW("vm_ is nullptr.");
307     }
308     LocalScope scope(vm_);
309     panda::DFXJSNApi::DumpHeapSnapshot(vm_, FORMAT_JSON, true, isPrivate);
310 }
311 #else
DumpHeapSnapshot(bool isPrivate)312 void ArkJSRuntime::DumpHeapSnapshot(bool isPrivate)
313 {
314     LOGE("Do not support Ark DumpHeapSnapshot on Windows or MacOS");
315 }
316 #endif
317 
Callback(panda::JsiRuntimeCallInfo * info) const318 Local<JSValueRef> PandaFunctionData::Callback(panda::JsiRuntimeCallInfo* info) const
319 {
320     auto runtime = runtime_.lock();
321     if (runtime == nullptr) {
322         LOGE("runtime is nullptr");
323         return Local<JSValueRef>();
324     }
325     EscapeLocalScope scope(runtime->GetEcmaVm());
326     shared_ptr<JsValue> thisPtr =
327         std::static_pointer_cast<JsValue>(std::make_shared<ArkJSValue>(runtime, info->GetThisRef()));
328 
329     std::vector<shared_ptr<JsValue>> argv;
330     int32_t length = info->GetArgsNumber();
331     argv.reserve(length);
332     for (int32_t i = 0; i < length; ++i) {
333         argv.emplace_back(
334             std::static_pointer_cast<JsValue>(std::make_shared<ArkJSValue>(runtime, info->GetCallArgRef(i))));
335     }
336     shared_ptr<JsValue> result = func_(runtime, thisPtr, argv, length);
337     return scope.Escape(std::static_pointer_cast<ArkJSValue>(result)->GetValue(runtime));
338 }
339 
340 } // namespace OHOS::Ace::Framework
341