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