1 /**
2 * Copyright (c) 2021-2025 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 <iostream>
17 #include "ets_vm_api.h"
18 #include "ets_vm.h"
19 #include "generated/base_options.h"
20
21 #ifdef PANDA_TARGET_OHOS
22 #include <hilog/log.h>
23
LogPrint(int id,int level,const char * component,const char * fmt,const char * msg)24 static void LogPrint([[maybe_unused]] int id, int level, const char *component, [[maybe_unused]] const char *fmt,
25 const char *msg)
26 {
27 #ifdef PANDA_OHOS_USE_INNER_HILOG
28 constexpr static unsigned int ARK_DOMAIN = 0xD003F00;
29 constexpr static auto TAG = "ArkEtsVm";
30 constexpr static OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, ARK_DOMAIN, TAG};
31 switch (level) {
32 case ark::Logger::PandaLog2MobileLog::DEBUG:
33 OHOS::HiviewDFX::HiLog::Debug(LABEL, "%{public}s", msg);
34 break;
35 case ark::Logger::PandaLog2MobileLog::INFO:
36 OHOS::HiviewDFX::HiLog::Info(LABEL, "%{public}s", msg);
37 break;
38 case ark::Logger::PandaLog2MobileLog::ERROR:
39 OHOS::HiviewDFX::HiLog::Error(LABEL, "%{public}s", msg);
40 break;
41 case ark::Logger::PandaLog2MobileLog::FATAL:
42 OHOS::HiviewDFX::HiLog::Fatal(LABEL, "%{public}s", msg);
43 break;
44 case ark::Logger::PandaLog2MobileLog::WARN:
45 OHOS::HiviewDFX::HiLog::Warn(LABEL, "%{public}s", msg);
46 break;
47 default:
48 UNREACHABLE();
49 }
50 #else
51 switch (level) {
52 case ark::Logger::PandaLog2MobileLog::DEBUG:
53 OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xFF00, "ArkEtsVm", "%s: %s", component, msg);
54 break;
55 case ark::Logger::PandaLog2MobileLog::INFO:
56 OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "ArkEtsVm", "%s: %s", component, msg);
57 break;
58 case ark::Logger::PandaLog2MobileLog::ERROR:
59 OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "ArkEtsVm", "%s: %s", component, msg);
60 break;
61 case ark::Logger::PandaLog2MobileLog::FATAL:
62 OH_LOG_Print(LOG_APP, LOG_FATAL, 0xFF00, "ArkEtsVm", "%s: %s", component, msg);
63 break;
64 case ark::Logger::PandaLog2MobileLog::WARN:
65 OH_LOG_Print(LOG_APP, LOG_WARN, 0xFF00, "ArkEtsVm", "%s: %s", component, msg);
66 break;
67 default:
68 UNREACHABLE();
69 }
70 #endif // PANDA_OHOS_USE_INNER_HILOG
71 }
72 #else
LogPrint(int id,int level,const char * component,const char * fmt,const char * msg)73 static void LogPrint([[maybe_unused]] int id, [[maybe_unused]] int level, [[maybe_unused]] const char *component,
74 [[maybe_unused]] const char *fmt, const char *msg)
75 {
76 std::cerr << msg << "\n";
77 }
78 #endif // PANDA_TARGET_OHOS
79
80 namespace ark::ets {
81
CreateRuntime(std::function<bool (base_options::Options *,RuntimeOptions *)> const & addOptions)82 bool CreateRuntime(std::function<bool(base_options::Options *, RuntimeOptions *)> const &addOptions)
83 {
84 auto runtimeOptions = ark::RuntimeOptions("app");
85 runtimeOptions.SetLoadRuntimes({"ets"});
86 #ifdef PANDA_TARGET_OHOS
87 runtimeOptions.SetMobileLog(reinterpret_cast<void *>(LogPrint));
88 #endif
89
90 ark::base_options::Options baseOptions("app");
91
92 if (!addOptions(&baseOptions, &runtimeOptions)) {
93 return false;
94 }
95
96 ark::Logger::Initialize(baseOptions);
97
98 LOG(DEBUG, RUNTIME) << "CreateRuntime";
99
100 #ifdef PANDA_JS_ETS_HYBRID_MODE
101 if ((runtimeOptions.GetXgcTriggerType() != "never") &&
102 (runtimeOptions.GetGcType("ets") != "g1-gc" || runtimeOptions.IsNoAsyncJit())) {
103 // XGC is not implemented for other GC types
104 LOG(ERROR, RUNTIME) << "GC type must be g1-gc and no-async-jit option must be false";
105 return false;
106 }
107 #endif
108
109 if (!ark::Runtime::Create(runtimeOptions)) {
110 LOG(ERROR, RUNTIME) << "CreateRuntime: cannot create ets runtime";
111 return false;
112 }
113 return true;
114 }
115
CreateRuntime(const std::string & stdlibAbc,const std::string & pathAbc,const bool useJit,const bool useAot)116 bool CreateRuntime(const std::string &stdlibAbc, const std::string &pathAbc, const bool useJit, const bool useAot)
117 {
118 auto addOpts = [&stdlibAbc, &pathAbc, useJit, useAot](base_options::Options *baseOptions,
119 ark::RuntimeOptions *runtimeOptions) {
120 baseOptions->SetLogLevel("info");
121 runtimeOptions->SetBootPandaFiles({stdlibAbc, pathAbc});
122 runtimeOptions->SetPandaFiles({pathAbc});
123 runtimeOptions->SetGcTriggerType("heap-trigger");
124 runtimeOptions->SetCompilerEnableJit(useJit);
125 runtimeOptions->SetEnableAn(useAot);
126 runtimeOptions->SetCoroutineImpl("stackful");
127 return true;
128 };
129 return CreateRuntime(addOpts);
130 }
131
DestroyRuntime()132 bool DestroyRuntime()
133 {
134 LOG(DEBUG, RUNTIME) << "DestroyEtsRuntime: enter";
135 auto res = ark::Runtime::Destroy();
136 LOG(DEBUG, RUNTIME) << "DestroyEtsRuntime: result = " << res;
137 return res;
138 }
139
ExecuteModule(std::string_view name)140 std::pair<bool, int> ExecuteModule(std::string_view name)
141 {
142 auto runtime = ark::Runtime::GetCurrent();
143 auto pfPath = runtime->GetPandaFiles()[0];
144 LOG(INFO, RUNTIME) << "ExecuteEtsModule: '" << pfPath << "'";
145 std::string moduleEp = (name.empty() ? "ETSGLOBAL::main" : std::string(name) + ".ETSGLOBAL::main");
146 auto res = ark::Runtime::GetCurrent()->ExecutePandaFile(pfPath, moduleEp, {});
147 LOG(INFO, RUNTIME) << "ExecuteEtsModule: result = " << (res ? std::to_string(res.Value()) : "failed");
148 return res ? std::make_pair(true, res.Value()) : std::make_pair(false, 1);
149 }
150
BindNative(const char * classDescriptor,const char * methodName,void * impl)151 bool BindNative(const char *classDescriptor, const char *methodName, void *impl)
152 {
153 auto *runtime = ark::Runtime::GetCurrent();
154 auto *classLinker = runtime->GetClassLinker();
155 auto *ext = classLinker->GetExtension(ark::SourceLanguage::ETS);
156 auto *klass = ext->GetClass(ark::utf::CStringAsMutf8(classDescriptor));
157
158 if (klass == nullptr) {
159 auto *thread = ark::ManagedThread::GetCurrent();
160 ASSERT(thread != nullptr);
161 thread->ClearException();
162 LOG(DEBUG, RUNTIME) << "BindNative: Cannot find class '" << classDescriptor << "'";
163 return false;
164 }
165
166 auto *method = klass->GetDirectMethod(ark::utf::CStringAsMutf8(methodName));
167
168 if (method == nullptr) {
169 ark::ManagedThread::GetCurrent()->ClearException();
170 LOG(DEBUG, RUNTIME) << "BindNative: Cannot find method '" << classDescriptor << "." << methodName << "'`";
171 return false;
172 }
173
174 method->SetCompiledEntryPoint(impl);
175 return true;
176 }
177
LogError(const std::string & msg)178 void LogError(const std::string &msg)
179 {
180 LogPrint(0, ark::Logger::PandaLog2MobileLog::ERROR, nullptr, nullptr, msg.c_str());
181 }
182
183 } // namespace ark::ets
184