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 "plugins/ets/runtime/napi/ets_napi_invoke_interface.h"
17
18 #include <vector>
19
20 #include "generated/base_options.h"
21 #include "libpandabase/utils/logger.h"
22 #include "plugins/ets/runtime/ets_coroutine.h"
23 #include "plugins/ets/runtime/ets_vm.h"
24
25 namespace panda::ets::napi {
DestroyEtsVM(EtsVM * vm)26 static ets_int DestroyEtsVM(EtsVM *vm)
27 {
28 if (vm == nullptr) {
29 LOG(ERROR, RUNTIME) << "Cannot destroy eTS VM, it is null";
30 return ETS_ERR;
31 }
32
33 auto runtime = Runtime::GetCurrent();
34 if (runtime == nullptr) {
35 LOG(ERROR, RUNTIME) << "Cannot destroy eTS VM, there is no current runtime";
36 return ETS_ERR;
37 }
38
39 auto pandaVm = PandaEtsVM::FromEtsVM(vm);
40 auto mainVm = runtime->GetPandaVM();
41 if (pandaVm == mainVm) {
42 Runtime::Destroy();
43 } else {
44 PandaEtsVM::Destroy(pandaVm);
45 }
46
47 return ETS_OK;
48 }
49
CheckVersionEtsNapi(ets_int version)50 bool CheckVersionEtsNapi(ets_int version)
51 {
52 return (version == ETS_NAPI_VERSION_1_0);
53 }
54
GetEnv(EtsVM * vm,EtsEnv ** pEnv,ets_int version)55 static ets_int GetEnv([[maybe_unused]] EtsVM *vm, EtsEnv **pEnv, [[maybe_unused]] ets_int version)
56 {
57 if (pEnv == nullptr) {
58 LOG(ERROR, RUNTIME) << "Cannot get environment, p_env is null";
59 return ETS_ERR;
60 }
61
62 auto coroutine = EtsCoroutine::GetCurrent();
63 if (coroutine == nullptr) {
64 LOG(ERROR, RUNTIME) << "Cannot get environment, there is no current coroutine";
65 return ETS_ERR;
66 }
67
68 if (!CheckVersionEtsNapi(version)) {
69 *pEnv = nullptr;
70 return ETS_ERR_VER;
71 }
72 *pEnv = coroutine->GetEtsNapiEnv();
73
74 return ETS_OK;
75 }
76
77 static const struct ETS_InvokeInterface S_INVOKE_INTERFACE = {DestroyEtsVM, GetEnv};
78
GetInvokeInterface()79 const ETS_InvokeInterface *GetInvokeInterface()
80 {
81 return &S_INVOKE_INTERFACE;
82 }
83
84 static EtsVMInitArgs g_sDefaultArgs = {0, 0, nullptr};
85
ETS_GetDefaultVMInitArgs(EtsVMInitArgs * vmArgs)86 extern "C" ets_int ETS_GetDefaultVMInitArgs(EtsVMInitArgs *vmArgs)
87 {
88 *vmArgs = g_sDefaultArgs;
89 return ETS_OK;
90 }
91
ETS_GetCreatedVMs(EtsVM ** vmBuf,ets_size bufLen,ets_size * nVms)92 extern "C" ets_int ETS_GetCreatedVMs(EtsVM **vmBuf, ets_size bufLen, ets_size *nVms)
93 {
94 if (nVms == nullptr) {
95 return ETS_ERR;
96 }
97
98 if (auto coroutine = EtsCoroutine::GetCurrent()) {
99 *nVms = 1;
100
101 if (vmBuf == nullptr || bufLen < 1) {
102 return ETS_ERR;
103 }
104
105 *vmBuf = coroutine->GetPandaVM();
106 } else {
107 *nVms = 0;
108 }
109
110 return ETS_OK;
111 }
112
113 static void *g_logPrintFunction = nullptr;
114
EtsMobileLogPrint(int id,int level,const char * component,const char * fmt,const char * msg)115 static void EtsMobileLogPrint(int id, int level, const char *component, const char *fmt, const char *msg)
116 {
117 int etsLevel = EtsMobileLogggerLevel::ETS_MOBILE_LOG_LEVEL_UNKNOWN;
118 switch (level) {
119 case panda::Logger::PandaLog2MobileLog::UNKNOWN:
120 etsLevel = EtsMobileLogggerLevel::ETS_MOBILE_LOG_LEVEL_UNKNOWN;
121 break;
122 case panda::Logger::PandaLog2MobileLog::DEFAULT:
123 etsLevel = EtsMobileLogggerLevel::ETS_MOBILE_LOG_LEVEL_DEFAULT;
124 break;
125 case panda::Logger::PandaLog2MobileLog::VERBOSE:
126 etsLevel = EtsMobileLogggerLevel::ETS_MOBILE_LOG_LEVEL_VERBOSE;
127 break;
128 case panda::Logger::PandaLog2MobileLog::DEBUG:
129 etsLevel = EtsMobileLogggerLevel::ETS_MOBILE_LOG_LEVEL_DEBUG;
130 break;
131 case panda::Logger::PandaLog2MobileLog::INFO:
132 etsLevel = EtsMobileLogggerLevel::ETS_MOBILE_LOG_LEVEL_INFO;
133 break;
134 case panda::Logger::PandaLog2MobileLog::WARN:
135 etsLevel = EtsMobileLogggerLevel::ETS_MOBILE_LOG_LEVEL_WARN;
136 break;
137 case panda::Logger::PandaLog2MobileLog::ERROR:
138 etsLevel = EtsMobileLogggerLevel::ETS_MOBILE_LOG_LEVEL_ERROR;
139 break;
140 case panda::Logger::PandaLog2MobileLog::FATAL:
141 etsLevel = EtsMobileLogggerLevel::ETS_MOBILE_LOG_LEVEL_FATAL;
142 break;
143 case panda::Logger::PandaLog2MobileLog::SILENT:
144 etsLevel = EtsMobileLogggerLevel::ETS_MOBILE_LOG_LEVEL_SILENT;
145 break;
146 default:
147 LOG(ERROR, RUNTIME) << "No such mobile log option";
148 }
149
150 auto logPrintCallback = reinterpret_cast<FuncMobileLogPrint>(g_logPrintFunction);
151 ASSERT(logPrintCallback != nullptr);
152 logPrintCallback(id, etsLevel, component, fmt, msg);
153 }
154
ParseOptionsHelper(RuntimeOptions & runtimeOptions,std::vector<std::string> & bootPandaFiles,std::vector<std::string> & aotFiles,std::vector<std::string> & arkFiles,base_options::Options & baseOptions,Span<const EtsVMOption> & options)155 static void ParseOptionsHelper(RuntimeOptions &runtimeOptions, std::vector<std::string> &bootPandaFiles,
156 std::vector<std::string> &aotFiles, std::vector<std::string> &arkFiles,
157 base_options::Options &baseOptions, Span<const EtsVMOption> &options)
158 {
159 for (auto &o : options) {
160 auto extraStr = reinterpret_cast<const char *>(o.extraInfo);
161
162 switch (o.option) {
163 case EtsOptionType::ETS_LOG_LEVEL:
164 baseOptions.SetLogLevel(extraStr);
165 break;
166 case EtsOptionType::ETS_MOBILE_LOG:
167 g_logPrintFunction = const_cast<void *>(o.extraInfo);
168 runtimeOptions.SetMobileLog(reinterpret_cast<void *>(EtsMobileLogPrint));
169 break;
170 case EtsOptionType::ETS_BOOT_FILE:
171 bootPandaFiles.emplace_back(extraStr);
172 break;
173 case EtsOptionType::ETS_AOT_FILE:
174 aotFiles.emplace_back(extraStr);
175 break;
176 case EtsOptionType::ETS_ARK_FILE:
177 arkFiles.emplace_back(extraStr);
178 break;
179 case EtsOptionType::ETS_JIT:
180 runtimeOptions.SetCompilerEnableJit(true);
181 break;
182 case EtsOptionType::ETS_NO_JIT:
183 runtimeOptions.SetCompilerEnableJit(false);
184 break;
185 case EtsOptionType::ETS_AOT:
186 runtimeOptions.SetEnableAn(true);
187 break;
188 case EtsOptionType::ETS_NO_AOT:
189 runtimeOptions.SetEnableAn(false);
190 break;
191 case EtsOptionType::ETS_GC_TRIGGER_TYPE:
192 runtimeOptions.SetGcTriggerType(extraStr);
193 break;
194 case EtsOptionType::ETS_GC_TYPE:
195 runtimeOptions.SetGcType(extraStr);
196 break;
197 case EtsOptionType::ETS_RUN_GC_IN_PLACE:
198 runtimeOptions.SetRunGcInPlace(true);
199 break;
200 case EtsOptionType::ETS_INTERPRETER_TYPE:
201 runtimeOptions.SetInterpreterType(extraStr);
202 break;
203 default:
204 LOG(ERROR, RUNTIME) << "No such option";
205 }
206 }
207 }
208
ParseOptions(const EtsVMInitArgs * args,RuntimeOptions & runtimeOptions)209 static bool ParseOptions(const EtsVMInitArgs *args, RuntimeOptions &runtimeOptions)
210 {
211 std::vector<std::string> bootPandaFiles;
212 std::vector<std::string> aotFiles;
213 std::vector<std::string> arkFiles;
214 base_options::Options baseOptions("");
215
216 runtimeOptions.SetLoadRuntimes({"ets"});
217
218 Span<const EtsVMOption> options(args->options, args->nOptions);
219 ParseOptionsHelper(runtimeOptions, bootPandaFiles, aotFiles, arkFiles, baseOptions, options);
220
221 Logger::Initialize(baseOptions);
222
223 runtimeOptions.SetBootPandaFiles(bootPandaFiles);
224 runtimeOptions.SetAotFiles(aotFiles);
225 runtimeOptions.SetPandaFiles(arkFiles);
226
227 return true;
228 }
229
ETS_CreateVM(EtsVM ** pVm,EtsEnv ** pEnv,EtsVMInitArgs * vmArgs)230 extern "C" ETS_EXPORT ets_int ETS_CreateVM(EtsVM **pVm, EtsEnv **pEnv, EtsVMInitArgs *vmArgs)
231 {
232 trace::ScopedTrace scopedTrace(__FUNCTION__);
233
234 if (pVm == nullptr || pEnv == nullptr) {
235 return ETS_ERR;
236 }
237
238 if (!CheckVersionEtsNapi(vmArgs->version)) {
239 LOG(ERROR, ETS_NAPI) << "Error: Unsupported Ets napi version = " << vmArgs->version;
240 return ETS_ERR_VER;
241 }
242
243 RuntimeOptions runtimeOptions;
244
245 if (!ParseOptions(vmArgs, runtimeOptions)) {
246 return ETS_ERR;
247 }
248
249 if (!Runtime::Create(runtimeOptions)) {
250 LOG(ERROR, RUNTIME) << "Cannot create runtime";
251 return ETS_ERR;
252 }
253
254 ASSERT(Runtime::GetCurrent() != nullptr);
255
256 auto coroutine = EtsCoroutine::GetCurrent();
257 ASSERT(coroutine != nullptr);
258
259 *pVm = coroutine->GetPandaVM();
260 ASSERT(*pVm != nullptr);
261
262 *pEnv = coroutine->GetEtsNapiEnv();
263 ASSERT(*pEnv != nullptr);
264
265 return ETS_OK;
266 }
267 } // namespace panda::ets::napi
268