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