• 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::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