• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "v8_native_engine.h"
17 
18 #include <js_native_api.h>
19 
20 #include "native_engine/native_property.h"
21 #include "native_value/v8_native_array.h"
22 #include "native_value/v8_native_array_buffer.h"
23 #include "native_value/v8_native_boolean.h"
24 #include "native_value/v8_native_data_view.h"
25 #include "native_value/v8_native_external.h"
26 #include "native_value/v8_native_function.h"
27 #include "native_value/v8_native_number.h"
28 #include "native_value/v8_native_object.h"
29 #include "native_value/v8_native_string.h"
30 #include "native_value/v8_native_typed_array.h"
31 #include "securec.h"
32 #include "utils/log.h"
33 #include "v8_native_deferred.h"
34 #include "v8_native_reference.h"
35 
36 
37 static thread_local V8NativeEngine* g_env = nullptr;
38 
V8NativeEngine(v8::Platform * platform,v8::Isolate * isolate,v8::Persistent<v8::Context> & context,void * jsEngine)39 V8NativeEngine::V8NativeEngine(v8::Platform* platform, v8::Isolate* isolate,
40     v8::Persistent<v8::Context>& context, void* jsEngine)
41     : NativeEngine(jsEngine),
42       platform_(platform),
43       isolate_(isolate),
44       context_(isolate, context),
45       isolateScope_(isolate),
46       handleScope_(isolate_),
47       contextScope_(context.Get(isolate_)),
48       tryCatch_(isolate_)
49 {
50     g_env = this;
51     v8::Local<v8::String> requireNapiName = v8::String::NewFromUtf8(isolate_, "requireNapi").ToLocalChecked();
52     v8::Local<v8::String> requireInternalName = v8::String::NewFromUtf8(isolate_, "requireInternal").ToLocalChecked();
53 
54     v8::Local<v8::Value> requireData = v8::External::New(isolate_, (void*)this).As<v8::Value>();
55 
56     v8::Local<v8::Function> requireNapi =
57         v8::Function::New(
58             context_.Get(isolate_),
59             [](const v8::FunctionCallbackInfo<v8::Value>& info) {
60                 v8::Isolate::Scope isolateScope(info.GetIsolate());
61                 v8::HandleScope handleScope(info.GetIsolate());
62 
63                 V8NativeEngine* engine = (V8NativeEngine*)info.Data().As<v8::External>()->Value();
64                 if (engine == nullptr) {
65                     return;
66                 }
67                 v8::String::Utf8Value moduleName(info.GetIsolate(), info[0]);
68                 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
69                 if (moduleManager == nullptr) {
70                     return;
71                 }
72 
73                 bool isAppModule = false;
74                 if (info.Length() == 2) {
75                     isAppModule = info[1]->ToBoolean(info.GetIsolate())->Value();
76                 }
77                 NativeModule* module = moduleManager->LoadNativeModule(*moduleName, nullptr, isAppModule);
78 
79                 if (module == nullptr) {
80                     return;
81                 }
82 
83                 if (module->jsCode != nullptr) {
84                     HILOG_INFO("load js code");
85                     NativeValue* script = engine->CreateString(module->jsCode, module->jsCodeLen);
86                     NativeValue* exportObject = engine->LoadModule(script, "jsnapi.js");
87                     if (exportObject == nullptr) {
88                         HILOG_ERROR("load module failed");
89                         return;
90                     }
91                     v8::Local<v8::Object> exports = *exportObject;
92                     info.GetReturnValue().Set(exports);
93                     HILOG_ERROR("load module succ");
94                 } else if (module->registerCallback != nullptr) {
95                     HILOG_INFO("load napi module");
96                     NativeValue* exportObject = new V8NativeObject(engine);
97                     if (exportObject == nullptr) {
98                         return;
99                     }
100                     module->registerCallback(engine, exportObject);
101                     v8::Local<v8::Object> exports = *exportObject;
102                     info.GetReturnValue().Set(exports);
103                 }
104             },
105             requireData, 1)
106             .ToLocalChecked();
107 
108     v8::Local<v8::Function> requireInternal =
109         v8::Function::New(
110             context_.Get(isolate_),
111             [](const v8::FunctionCallbackInfo<v8::Value>& info) {
112                 v8::Isolate::Scope isolateScope(info.GetIsolate());
113                 v8::HandleScope handleScope(info.GetIsolate());
114 
115                 V8NativeEngine* engine = (V8NativeEngine*)info.Data().As<v8::External>()->Value();
116                 if (engine == nullptr) {
117                     return;
118                 }
119                 v8::String::Utf8Value moduleName(info.GetIsolate(), info[0]);
120                 NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
121                 if (moduleManager == nullptr) {
122                     return;
123                 }
124                 NativeModule* module = moduleManager->LoadNativeModule(*moduleName, nullptr, false, true);
125                 if (module == nullptr) {
126                     return;
127                 }
128                 NativeValue* exportObject = new V8NativeObject(engine);
129                 if (exportObject == nullptr) {
130                     return;
131                 }
132                 module->registerCallback(engine, exportObject);
133                 v8::Local<v8::Object> exports = *exportObject;
134                 info.GetReturnValue().Set(exports);
135             },
136             requireData, 1)
137             .ToLocalChecked();
138 
139     v8::Local<v8::Object> global = context_.Get(isolate_)->Global();
140 
141     global->Set(context_.Get(isolate_), requireNapiName, requireNapi).FromJust();
142     global->Set(context_.Get(isolate_), requireInternalName, requireInternal).FromJust();
143     // need to call init of base class.
144     Init();
145 }
146 
~V8NativeEngine()147 V8NativeEngine::~V8NativeEngine()
148 {
149     if (promiseRejectCallbackRef_ != nullptr) {
150         delete promiseRejectCallbackRef_;
151     }
152     if (checkCallbackRef_ != nullptr) {
153         delete checkCallbackRef_;
154     }
155     // need to call deinit before base class.
156     Deinit();
157 }
158 
GetModuleFromName(const std::string & moduleName,bool isAppModule,const std::string & id,const std::string & param,const std::string & instanceName,void ** instance)159 v8::Local<v8::Object> V8NativeEngine::GetModuleFromName(
160     const std::string& moduleName, bool isAppModule, const std::string& id, const std::string& param,
161     const std::string& instanceName, void** instance)
162 {
163     v8::Isolate* isolate = this->GetContext()->GetIsolate();
164     v8::HandleScope handleScope(isolate);
165 
166     v8::Local<v8::Object> exports;
167     NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
168     NativeModule* module = moduleManager->LoadNativeModule(moduleName.c_str(), nullptr, isAppModule);
169     if (module != nullptr) {
170         NativeValue* idValue = new V8NativeString(this, id.c_str(), id.size());
171         NativeValue* paramValue = new V8NativeString(this, param.c_str(), param.size());
172         NativeValue* exportObject = new V8NativeObject(this);
173 
174         NativePropertyDescriptor idProperty, paramProperty;
175         idProperty.utf8name = "id";
176         idProperty.value = idValue;
177         paramProperty.utf8name = "param";
178         paramProperty.value = paramValue;
179         V8NativeObject* exportObj = reinterpret_cast<V8NativeObject*>(exportObject);
180         exportObj->DefineProperty(idProperty);
181         exportObj->DefineProperty(paramProperty);
182         module->registerCallback(this, exportObject);
183 
184         napi_value nExport = reinterpret_cast<napi_value>(exportObject);
185         napi_value exportInstance = nullptr;
186         napi_status status = napi_get_named_property(
187             reinterpret_cast<napi_env>(this), nExport, instanceName.c_str(), &exportInstance);
188         if (status != napi_ok) {
189             HILOG_ERROR("GetModuleFromName napi_get_named_property status != napi_ok");
190         }
191 
192         status = napi_unwrap(reinterpret_cast<napi_env>(this), exportInstance, reinterpret_cast<void**>(instance));
193         if (status != napi_ok) {
194             HILOG_ERROR("GetModuleFromName napi_unwrap status != napi_ok");
195         }
196 
197         exports = *exportObject;
198     }
199     return exports;
200 }
201 
LoadModuleByName(const std::string & moduleName,bool isAppModule,const std::string & param,const std::string & instanceName,void * instance)202 v8::Local<v8::Object> V8NativeEngine::LoadModuleByName(
203     const std::string& moduleName, bool isAppModule, const std::string& param,
204     const std::string& instanceName, void* instance)
205 {
206     v8::Isolate* isolate = this->GetContext()->GetIsolate();
207     v8::HandleScope handleScope(isolate);
208 
209     v8::Local<v8::Object> exports;
210     NativeModuleManager* moduleManager = NativeModuleManager::GetInstance();
211     NativeModule* module = moduleManager->LoadNativeModule(moduleName.c_str(), nullptr, isAppModule);
212     if (module != nullptr) {
213         NativeValue* exportObject = new V8NativeObject(this);
214         V8NativeObject* exportObj = reinterpret_cast<V8NativeObject*>(exportObject);
215 
216         NativePropertyDescriptor paramProperty, instanceProperty;
217 
218         NativeValue* paramValue = new V8NativeString(this, param.c_str(), param.size());
219         paramProperty.utf8name = "param";
220         paramProperty.value = paramValue;
221 
222         V8NativeObject* instanceValue = new V8NativeObject(this);
223         instanceValue->SetNativePointer(instance, nullptr, nullptr);
224         instanceProperty.utf8name = instanceName.c_str();
225         instanceProperty.value = instanceValue;
226 
227         exportObj->DefineProperty(paramProperty);
228         exportObj->DefineProperty(instanceProperty);
229 
230         module->registerCallback(this, exportObject);
231         exports = *exportObject;
232     }
233     return exports;
234 }
235 
GetIsolate()236 v8::Isolate* V8NativeEngine::GetIsolate()
237 {
238     return isolate_;
239 }
240 
GetContext()241 v8::Local<v8::Context> V8NativeEngine::GetContext()
242 {
243     return *reinterpret_cast<v8::Local<v8::Context>*>(const_cast<v8::Global<v8::Context>*>(&context_));
244 }
245 
Loop(LoopMode mode,bool needSync)246 void V8NativeEngine::Loop(LoopMode mode, bool needSync)
247 {
248     NativeEngine::Loop(mode, needSync);
249     v8::platform::PumpMessageLoop(platform_, isolate_);
250 }
251 
GetGlobal()252 NativeValue* V8NativeEngine::GetGlobal()
253 {
254     v8::Local<v8::Object> value = context_.Get(isolate_)->Global();
255     return V8ValueToNativeValue(this, value);
256 }
257 
CreateNull()258 NativeValue* V8NativeEngine::CreateNull()
259 {
260     v8::Local<v8::Primitive> value = v8::Null(isolate_);
261     return new V8NativeValue(this, value);
262 }
263 
CreateUndefined()264 NativeValue* V8NativeEngine::CreateUndefined()
265 {
266     v8::Local<v8::Primitive> value = v8::Undefined(isolate_);
267     return new V8NativeValue(this, value);
268 }
269 
CreateBoolean(bool value)270 NativeValue* V8NativeEngine::CreateBoolean(bool value)
271 {
272     return new V8NativeBoolean(this, value);
273 }
274 
CreateNumber(int32_t value)275 NativeValue* V8NativeEngine::CreateNumber(int32_t value)
276 {
277     return new V8NativeNumber(this, value);
278 }
279 
CreateNumber(uint32_t value)280 NativeValue* V8NativeEngine::CreateNumber(uint32_t value)
281 {
282     return new V8NativeNumber(this, value);
283 }
284 
CreateNumber(int64_t value)285 NativeValue* V8NativeEngine::CreateNumber(int64_t value)
286 {
287     return new V8NativeNumber(this, value);
288 }
289 
CreateNumber(double value)290 NativeValue* V8NativeEngine::CreateNumber(double value)
291 {
292     return new V8NativeNumber(this, value);
293 }
294 
CreateString(const char * value,size_t length)295 NativeValue* V8NativeEngine::CreateString(const char* value, size_t length)
296 {
297     return new V8NativeString(this, value, length);
298 }
299 
CreateSymbol(NativeValue * value)300 NativeValue* V8NativeEngine::CreateSymbol(NativeValue* value)
301 {
302     return new V8NativeValue(this, v8::Symbol::New(isolate_, *value));
303 }
304 
CreateExternal(void * value,NativeFinalize callback,void * hint,size_t nativeBindingSize)305 NativeValue* V8NativeEngine::CreateExternal(void* value, NativeFinalize callback, void* hint,
306     [[maybe_unused]] size_t nativeBindingSize)
307 {
308     return new V8NativeExternal(this, value, callback, hint);
309 }
310 
CreateObject()311 NativeValue* V8NativeEngine::CreateObject()
312 {
313     return new V8NativeObject(this);
314 }
315 
CreateNativeBindingObject(void * detach,void * attach)316 NativeValue* V8NativeEngine::CreateNativeBindingObject(void* detach, void* attach)
317 {
318     return nullptr;
319 }
320 
CreateFunction(const char * name,size_t length,NativeCallback cb,void * value)321 NativeValue* V8NativeEngine::CreateFunction(const char* name, size_t length, NativeCallback cb, void* value)
322 {
323     return new V8NativeFunction(this, name, length, cb, value);
324 }
325 
CreateArray(size_t length)326 NativeValue* V8NativeEngine::CreateArray(size_t length)
327 {
328     return new V8NativeArray(this, length);
329 }
330 
CreateArrayBuffer(void ** value,size_t length)331 NativeValue* V8NativeEngine::CreateArrayBuffer(void** value, size_t length)
332 {
333     return new V8NativeArrayBuffer(this, (uint8_t**)value, length);
334 }
335 
CreateArrayBufferExternal(void * value,size_t length,NativeFinalize cb,void * hint)336 NativeValue* V8NativeEngine::CreateArrayBufferExternal(void* value, size_t length, NativeFinalize cb, void* hint)
337 {
338     return new V8NativeArrayBuffer(this, (uint8_t*)value, length, cb, hint);
339 }
340 
CreateTypedArray(NativeTypedArrayType type,NativeValue * value,size_t length,size_t offset)341 NativeValue* V8NativeEngine::CreateTypedArray(NativeTypedArrayType type,
342                                               NativeValue* value,
343                                               size_t length,
344                                               size_t offset)
345 {
346     v8::Local<v8::ArrayBuffer> buffer = *value;
347     v8::Local<v8::TypedArray> typedArray;
348 
349     switch (type) {
350         case NATIVE_INT8_ARRAY:
351             typedArray = v8::Int8Array::New(buffer, offset, length);
352             break;
353         case NATIVE_UINT8_ARRAY:
354             typedArray = v8::Uint8Array::New(buffer, offset, length);
355             break;
356         case NATIVE_UINT8_CLAMPED_ARRAY:
357             typedArray = v8::Uint8ClampedArray::New(buffer, offset, length);
358             break;
359         case NATIVE_INT16_ARRAY:
360             typedArray = v8::Int16Array::New(buffer, offset, length);
361             break;
362         case NATIVE_UINT16_ARRAY:
363             typedArray = v8::Uint16Array::New(buffer, offset, length);
364             break;
365         case NATIVE_INT32_ARRAY:
366             typedArray = v8::Int32Array::New(buffer, offset, length);
367             break;
368         case NATIVE_UINT32_ARRAY:
369             typedArray = v8::Uint32Array::New(buffer, offset, length);
370             break;
371         case NATIVE_FLOAT32_ARRAY:
372             typedArray = v8::Float32Array::New(buffer, offset, length);
373             break;
374         case NATIVE_FLOAT64_ARRAY:
375             typedArray = v8::Float64Array::New(buffer, offset, length);
376             break;
377         case NATIVE_BIGINT64_ARRAY:
378             typedArray = v8::BigInt64Array::New(buffer, offset, length);
379             break;
380         case NATIVE_BIGUINT64_ARRAY:
381             typedArray = v8::BigUint64Array::New(buffer, offset, length);
382             break;
383         default:
384             return nullptr;
385     }
386     return new V8NativeTypedArray(this, typedArray);
387 }
388 
389 struct CompleteWrapData {
390     NativeAsyncExecuteCallback execute_ = nullptr;
391     NativeAsyncCompleteCallback complete_ = nullptr;
392     void* data_ = nullptr;
393     v8::Isolate* isolate_ = nullptr;
394 };
395 
ExecuteWrap(NativeEngine * engine,void * data)396 void V8NativeEngine::ExecuteWrap(NativeEngine* engine, void* data)
397 {
398     CompleteWrapData* wrapData = (CompleteWrapData*)data;
399     wrapData->execute_(engine, wrapData->data_);
400 }
401 
CompleteWrap(NativeEngine * engine,int status,void * data)402 void V8NativeEngine::CompleteWrap(NativeEngine* engine, int status, void* data)
403 {
404     CompleteWrapData* wrapData = (CompleteWrapData*)data;
405     v8::Isolate::Scope isolateScope(wrapData->isolate_);
406     v8::HandleScope handleScope(wrapData->isolate_);
407     wrapData->complete_(engine, status, wrapData->data_);
408     delete wrapData;
409 }
410 
CreateAsyncWork(NativeValue * asyncResource,NativeValue * asyncResourceName,NativeAsyncExecuteCallback execute,NativeAsyncCompleteCallback complete,void * data)411 NativeAsyncWork* V8NativeEngine::CreateAsyncWork(NativeValue* asyncResource, NativeValue* asyncResourceName,
412     NativeAsyncExecuteCallback execute, NativeAsyncCompleteCallback complete, void* data)
413 {
414     CompleteWrapData* wrapData = new CompleteWrapData();
415     if (wrapData == nullptr) {
416         HILOG_ERROR("create wrap data failed");
417         return nullptr;
418     }
419     wrapData->execute_ = execute;
420     wrapData->complete_ = complete;
421     wrapData->data_ = data;
422     wrapData->isolate_ = GetIsolate();
423 
424     return NativeEngine::CreateAsyncWork(asyncResource, asyncResourceName, ExecuteWrap, CompleteWrap, (void*)wrapData);
425 }
426 
CreateDataView(NativeValue * value,size_t length,size_t offset)427 NativeValue* V8NativeEngine::CreateDataView(NativeValue* value, size_t length, size_t offset)
428 {
429     return new V8NativeDataView(this, value, length, offset);
430 }
431 
CreatePromise(NativeDeferred ** deferred)432 NativeValue* V8NativeEngine::CreatePromise(NativeDeferred** deferred)
433 {
434     auto v8Resolver = v8::Promise::Resolver::New(context_.Get(isolate_)).ToLocalChecked();
435 
436     *deferred = new V8NativeDeferred(this, v8Resolver);
437 
438     return new V8NativeValue(this, v8Resolver->GetPromise());
439 }
440 
CreateError(NativeValue * code,NativeValue * message)441 NativeValue* V8NativeEngine::CreateError(NativeValue* code, NativeValue* message)
442 {
443     v8::Local<v8::Value> errorObj = v8::Exception::Error(*message);
444     if (code) {
445         v8::Local<v8::Value> codeKey = v8::String::NewFromUtf8(isolate_, "code").ToLocalChecked();
446         errorObj.As<v8::Object>()->Set(context_.Get(isolate_), codeKey, *code).FromJust();
447     }
448     return V8ValueToNativeValue(this, errorObj);
449 }
450 
CallFunction(NativeValue * thisVar,NativeValue * function,NativeValue * const * argv,size_t argc)451 NativeValue* V8NativeEngine::CallFunction(NativeValue* thisVar,
452                                           NativeValue* function,
453                                           NativeValue* const* argv,
454                                           size_t argc)
455 {
456     if (function == nullptr) {
457         return nullptr;
458     }
459     v8::Local<v8::Value> v8recv = (thisVar != nullptr) ? *thisVar : v8::Undefined(isolate_);
460     v8::Local<v8::Function> v8func = *function;
461     v8::Local<v8::Value>* args = nullptr;
462     v8::Local<v8::Context> context = context_.Get(isolate_);
463     if (argc > 0) {
464         args = new v8::Local<v8::Value>[argc];
465         for (size_t i = 0; i < argc && args != nullptr; i++) {
466             if (argv[i] != nullptr) {
467                 args[i] = *argv[i];
468             } else {
469                 args[i] = v8::Undefined(isolate_);
470             }
471         }
472     }
473     v8::MaybeLocal<v8::Value> maybeValue = v8func->Call(context, v8recv, argc, args);
474     if (args != nullptr) {
475         delete []args;
476     }
477     v8::Local<v8::Value> result;
478     if (!maybeValue.ToLocal(&result)) {
479         return nullptr;
480     }
481     return V8ValueToNativeValue(this, result);
482 }
483 
RunScript(NativeValue * script)484 NativeValue* V8NativeEngine::RunScript(NativeValue* script)
485 {
486     v8::Local<v8::Value> v8Script = *script;
487     auto maybeScript = v8::Script::Compile(context_.Get(isolate_), v8Script.As<v8::String>());
488     auto localScript = maybeScript.ToLocalChecked();
489     auto scriptResult = localScript->Run(context_.Get(isolate_));
490 
491     v8::Local<v8::Value> result;
492     if (!scriptResult.ToLocal(&result)) {
493         return nullptr;
494     }
495 
496     return V8ValueToNativeValue(this, result);
497 }
498 
RunBufferScript(std::vector<uint8_t> & buffer)499 NativeValue* V8NativeEngine::RunBufferScript(std::vector<uint8_t>& buffer)
500 {
501     NativeValue* script = CreateString(reinterpret_cast<char*>(buffer.data()), buffer.size());
502     return RunScript(script);
503 }
504 
RunActor(std::vector<uint8_t> & buffer,const char * descriptor)505 NativeValue* V8NativeEngine::RunActor(std::vector<uint8_t>& buffer, const char *descriptor)
506 {
507     return RunBufferScript(buffer);
508 }
509 
510 namespace {
ReadFile(v8::Isolate * isolate,const char * path)511 v8::MaybeLocal<v8::String> ReadFile(v8::Isolate* isolate, const char* path)
512 {
513     std::ifstream file(path);
514     if (file.fail()) {
515         file.close();
516         return v8::MaybeLocal<v8::String>();
517     }
518 
519     std::string fileContent;
520     fileContent.clear();
521     file.seekg(0, std::ios::end);
522     fileContent.reserve(static_cast<std::string::size_type>(file.tellg()));
523     file.seekg(0, std::ios::beg);
524     fileContent.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
525     file.close();
526 
527     v8::MaybeLocal<v8::String> result = v8::String::NewFromUtf8(isolate, fileContent.c_str(),
528                                                                 v8::NewStringType::kNormal, fileContent.size());
529     return result;
530 }
531 
ModuleResolveCallback(v8::Local<v8::Context> context,v8::Local<v8::String> specifier,v8::Local<v8::Module> referrer)532 v8::MaybeLocal<v8::Module> ModuleResolveCallback(v8::Local<v8::Context> context,
533                                                  v8::Local<v8::String> specifier,
534                                                  v8::Local<v8::Module> referrer)
535 {
536     v8::Isolate* isolate = context->GetIsolate();
537     int len = specifier->Length();
538     char *buffer = new char[len + 1];
539     specifier->WriteUtf8(isolate, buffer, len, nullptr,
540                          v8::String::REPLACE_INVALID_UTF8 | v8::String::NO_NULL_TERMINATION);
541     auto maybeSourceCode = ReadFile(isolate, buffer);
542     v8::Local<v8::String> sourceCode;
543     if (!maybeSourceCode.ToLocal(&sourceCode)) {
544         v8::ScriptOrigin origin(v8::String::NewFromUtf8(isolate, "moduleloader.js").ToLocalChecked(),
545                                 v8::Local<v8::Integer>(), v8::Local<v8::Integer>(), v8::Local<v8::Boolean>(),
546                                 v8::Local<v8::Integer>(), v8::Local<v8::Value>(), v8::Local<v8::Boolean>(),
547                                 v8::Local<v8::Boolean>(), True(isolate));
548         v8::ScriptCompiler::Source source(specifier, origin);
549         delete[] buffer;
550         return v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
551     }
552 
553     v8::ScriptOrigin origin(specifier, v8::Local<v8::Integer>(), v8::Local<v8::Integer>(), v8::Local<v8::Boolean>(),
554                             v8::Local<v8::Integer>(), v8::Local<v8::Value>(), v8::Local<v8::Boolean>(),
555                             v8::Local<v8::Boolean>(), True(isolate));
556     v8::ScriptCompiler::Source source(sourceCode, origin);
557     auto result = v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
558     delete[] buffer;
559     return result;
560 }
561 }
562 
LoadModule(NativeValue * str,const std::string & fileName)563 NativeValue* V8NativeEngine::LoadModule(NativeValue* str, const std::string& fileName)
564 {
565     v8::Local<v8::Value> value = *str;
566     auto source = value.As<v8::String>();
567     if (source.IsEmpty() || fileName.empty()) {
568         isolate_->ThrowException(
569             v8::String::NewFromUtf8(isolate_, "Invalid input parameter", v8::NewStringType::kNormal).ToLocalChecked());
570         return nullptr;
571     }
572 
573     v8::ScriptOrigin origin(v8::String::NewFromUtf8(isolate_, fileName.c_str()).ToLocalChecked(),
574                             v8::Local<v8::Integer>(), v8::Local<v8::Integer>(), v8::Local<v8::Boolean>(),
575                             v8::Local<v8::Integer>(), v8::Local<v8::Value>(), v8::Local<v8::Boolean>(),
576                             v8::Local<v8::Boolean>(), True(isolate_));
577     v8::ScriptCompiler::Source moduleSource(source, origin);
578     v8::Local<v8::Module> module = v8::ScriptCompiler::CompileModule(isolate_, &moduleSource).ToLocalChecked();
579 
580     auto context = context_.Get(isolate_);
581     if (!module->InstantiateModule(context, ModuleResolveCallback).FromJust()) {
582         return nullptr;
583     }
584     auto maybeEvaluate = module->Evaluate(context);
585     v8::Local<v8::Value> evaluate;
586     if (!maybeEvaluate.ToLocal(&evaluate)) {
587         return nullptr;
588     }
589 
590     v8::Local<v8::Value> moduleNameSpace = module->GetModuleNamespace();
591     v8::Local<v8::Object> nameSpaceObject = moduleNameSpace->ToObject(context).ToLocalChecked();
592     auto exportObj = nameSpaceObject->Get(context, v8::String::NewFromUtf8(isolate_, "default").ToLocalChecked());
593     v8::Local<v8::Value> result;
594     if (!exportObj.ToLocal(&result)) {
595         return nullptr;
596     }
597 
598     // can use return V8ValueToNativeValue(this, result) ?
599     return new V8NativeObject(this, result);
600 }
601 
DefineClass(const char * name,NativeCallback callback,void * data,const NativePropertyDescriptor * properties,size_t length)602 NativeValue* V8NativeEngine::DefineClass(const char* name,
603                                          NativeCallback callback,
604                                          void* data,
605                                          const NativePropertyDescriptor* properties,
606                                          size_t length)
607 {
608     auto classConstructor = new V8NativeFunction(this, name, 0, callback, data);
609     if (classConstructor == nullptr) {
610         return nullptr;
611     }
612 
613     auto classPrototype = new V8NativeObject(this);
614     if (classPrototype == nullptr) {
615         delete classConstructor;
616         return nullptr;
617     }
618 
619     classConstructor->SetProperty("prototype", classPrototype);
620 
621     for (size_t i = 0; i < length; i++) {
622         if (properties[i].attributes & NATIVE_STATIC) {
623             classConstructor->DefineProperty(properties[i]);
624         } else {
625             classPrototype->DefineProperty(properties[i]);
626         }
627     }
628 
629     return classConstructor;
630 }
631 
CreateInstance(NativeValue * constructor,NativeValue * const * argv,size_t argc)632 NativeValue* V8NativeEngine::CreateInstance(NativeValue* constructor, NativeValue* const* argv, size_t argc)
633 {
634     v8::Local<v8::Object> value = *constructor;
635     v8::Local<v8::Value>* args = new v8::Local<v8::Value>[argc];
636     for (size_t i = 0; i < argc && args != nullptr; i++) {
637         args[i] = *argv[i];
638     }
639 
640     v8::TryCatch tryCatch(isolate_);
641     v8::MaybeLocal<v8::Value> maybeInstance = value->CallAsConstructor(context_.Get(isolate_), argc, args);
642     delete[] args;
643 
644     v8::Local<v8::Value> result;
645     if (maybeInstance.IsEmpty()) {
646         result = v8::Undefined(isolate_);
647     } else {
648         result = maybeInstance.ToLocalChecked();
649     }
650 
651     return V8ValueToNativeValue(this, result);
652 }
653 
CreateReference(NativeValue * value,uint32_t initialRefcount)654 NativeReference* V8NativeEngine::CreateReference(NativeValue* value, uint32_t initialRefcount)
655 {
656     return new V8NativeReference(this, value, initialRefcount, false);
657 }
658 
Throw(NativeValue * error)659 bool V8NativeEngine::Throw(NativeValue* error)
660 {
661     isolate_->ThrowException(*error);
662     lastException_ = error;
663     return true;
664 }
665 
Throw(NativeErrorType type,const char * code,const char * message)666 bool V8NativeEngine::Throw(NativeErrorType type, const char* code, const char* message)
667 {
668     v8::Local<v8::Value> error;
669 
670     switch (type) {
671         case NATIVE_COMMON_ERROR:
672             error = v8::Exception::Error(v8::String::NewFromUtf8(isolate_, message).ToLocalChecked());
673             break;
674         case NATIVE_TYPE_ERROR:
675             error = v8::Exception::TypeError(v8::String::NewFromUtf8(isolate_, message).ToLocalChecked());
676             break;
677         case NATIVE_RANGE_ERROR:
678             error = v8::Exception::RangeError(v8::String::NewFromUtf8(isolate_, message).ToLocalChecked());
679             break;
680         default:
681             return false;
682     }
683     if (code) {
684         v8::Local<v8::Value> codeKey = v8::String::NewFromUtf8(isolate_, "code").ToLocalChecked();
685         v8::Local<v8::Value> codeValue = v8::String::NewFromUtf8(isolate_, code).ToLocalChecked();
686         error.As<v8::Object>()->Set(context_.Get(isolate_), codeKey, codeValue).FromJust();
687     }
688 
689     isolate_->ThrowException(error);
690     lastException_ = V8ValueToNativeValue(this, error);
691     return true;
692 }
693 
V8ValueToNativeValue(V8NativeEngine * engine,v8::Local<v8::Value> value)694 NativeValue* V8NativeEngine::V8ValueToNativeValue(V8NativeEngine* engine, v8::Local<v8::Value> value)
695 {
696     NativeValue* result = nullptr;
697     if (value->IsNull() || value->IsUndefined() || value->IsSymbol() || value->IsPromise()) {
698         result = new V8NativeValue(engine, value);
699     } else if (value->IsNumber()) {
700         result = new V8NativeNumber(engine, value);
701     } else if (value->IsString()) {
702         result = new V8NativeString(engine, value);
703     } else if (value->IsArray()) {
704         result = new V8NativeArray(engine, value);
705     } else if (value->IsFunction()) {
706         result = new V8NativeFunction(engine, value);
707     } else if (value->IsArrayBuffer()) {
708         result = new V8NativeArrayBuffer(engine, value);
709     } else if (value->IsDataView()) {
710         result = new V8NativeDataView(engine, value);
711     } else if (value->IsTypedArray()) {
712         result = new V8NativeTypedArray(engine, value);
713     } else if (value->IsExternal()) {
714         result = new V8NativeExternal(engine, value);
715     } else if (value->IsObject()) {
716         result = new V8NativeObject(engine, value);
717     } else if (value->IsBoolean()) {
718         result = new V8NativeBoolean(engine, value);
719     }
720     return result;
721 }
722 
CreateRuntime()723 void* V8NativeEngine::CreateRuntime()
724 {
725     v8::Isolate::CreateParams createParams;
726     createParams.array_buffer_allocator = isolate_->GetArrayBufferAllocator();
727     v8::Isolate* isolate = v8::Isolate::New(createParams);
728     v8::Persistent<v8::Context> persistContext;
729     {
730         v8::HandleScope handleScope(isolate);
731         v8::Isolate::Scope isolateScope(isolate);
732         v8::Local<v8::Context> context = v8::Context::New(isolate);
733         if (context.IsEmpty()) {
734             return nullptr;
735         }
736         persistContext.Reset(isolate, context);
737     }
738 
739     V8NativeEngine* v8Engine = new V8NativeEngine(platform_, isolate, persistContext, jsEngine_);
740 
741     // init callback
742     v8Engine->SetInitWorkerFunc(initWorkerFunc_);
743     v8Engine->SetGetAssetFunc(getAssetFunc_);
744     v8Engine->SetOffWorkerFunc(offWorkerFunc_);
745     v8Engine->SetWorkerAsyncWorkFunc(nativeAsyncExecuteCallback_, nativeAsyncCompleteCallback_);
746 
747     v8Engine->MarkAutoDispose();
748     auto cleanEnv = [isolate]() {
749         if (isolate != nullptr) {
750             HILOG_INFO("worker:: cleanEnv is called");
751             isolate->Dispose();
752         }
753     };
754     v8Engine->SetCleanEnv(cleanEnv);
755     return static_cast<void*>(v8Engine);
756 }
757 
758 class Serializer {
759 public:
Serializer(v8::Isolate * isolate)760     explicit Serializer(v8::Isolate* isolate) : isolate_(isolate), v8Serializer_(isolate, nullptr) {}
761     ~Serializer() = default;
762 
SerializeValue(v8::Local<v8::Value> value,v8::Local<v8::Value> transfer)763     bool SerializeValue(v8::Local<v8::Value> value, v8::Local<v8::Value> transfer)
764     {
765         v8::Local<v8::Context> context = isolate_->GetCurrentContext();
766         bool ok = false;
767         DCHECK(!data_);
768         data_.reset(new SerializationData);
769 
770         // check transfer list is right
771         if (!CheckTransferReliability(transfer)) {
772             return false;
773         }
774 
775         // serial value
776         v8Serializer_.WriteHeader();
777         if (!v8Serializer_.WriteValue(context, value).To(&ok)) {
778             data_.reset();
779             return false;
780         }
781 
782         // releasing Data Control Rights
783         if (!DetachTransfer()) {
784             data_.reset();
785             return false;
786         }
787 
788         std::pair<uint8_t*, size_t> pair = v8Serializer_.Release();
789         data_->data_.reset(pair.first);
790         data_->size_ = pair.second;
791         return true;
792     }
793 
Release()794     std::unique_ptr<SerializationData> Release()
795     {
796         return std::move(data_);
797     }
798 
799 private:
CheckTransferReliability(v8::Local<v8::Value> transfer)800     bool CheckTransferReliability(v8::Local<v8::Value> transfer)
801     {
802         if (transfer->IsUndefined()) {
803             return true;
804         }
805         if (!transfer->IsArray()) {
806             std::string msg = "Transfer list must be an Array or undefined";
807             isolate_->ThrowException(
808                 v8::String::NewFromUtf8(isolate_, msg.c_str(), v8::NewStringType::kNormal).ToLocalChecked());
809             return false;
810         }
811 
812         v8::Local<v8::Array> transferArray = v8::Local<v8::Array>::Cast(transfer);
813         uint32_t length = transferArray->Length();
814         uint32_t arrayBufferIdx = 0;
815         v8::Local<v8::Context> context = isolate_->GetCurrentContext();
816         for (uint32_t i = 0; i < length; ++i) {
817             v8::Local<v8::Value> element;
818             if (transferArray->Get(context, i).ToLocal(&element)) {
819                 if (!element->IsArrayBuffer()) {
820                     std::string msg = "Transfer array elements must be an ArrayBuffer";
821                     isolate_->ThrowException(
822                         v8::String::NewFromUtf8(isolate_, msg.c_str(), v8::NewStringType::kNormal).ToLocalChecked());
823                     return false;
824                 }
825 
826                 v8::Local<v8::ArrayBuffer> arrayBuffer = v8::Local<v8::ArrayBuffer>::Cast(element);
827                 auto iter = std::find(visitedTransfer_.begin(), visitedTransfer_.end(), arrayBuffer);
828                 if (iter != visitedTransfer_.end()) {
829                     std::string msg = "ArrayBuffer occurs in the transfer array more than once";
830                     isolate_->ThrowException(
831                         v8::String::NewFromUtf8(isolate_, msg.c_str(), v8::NewStringType::kNormal).ToLocalChecked());
832                     return false;
833                 }
834 
835                 v8Serializer_.TransferArrayBuffer(arrayBufferIdx++, arrayBuffer);
836                 visitedTransfer_.emplace_back(isolate_, arrayBuffer);
837             } else {
838                 return false;
839             }
840         }
841         return true;
842     }
843 
DetachTransfer()844     bool DetachTransfer()
845     {
846         for (const auto& item : visitedTransfer_) {
847             v8::Local<v8::ArrayBuffer> arrayBuffer = v8::Local<v8::ArrayBuffer>::New(isolate_, item);
848             if (!arrayBuffer->IsDetachable()) {
849                 std::string msg = "ArrayBuffer could not be transferred";
850                 isolate_->ThrowException(
851                     v8::String::NewFromUtf8(isolate_, msg.c_str(), v8::NewStringType::kNormal).ToLocalChecked());
852                 return false;
853             }
854 
855             auto backingStore = arrayBuffer->GetBackingStore();
856             data_->backingStores_.push_back(std::move(backingStore));
857             arrayBuffer->Detach();
858         }
859 
860         return true;
861     }
862 
863     v8::Isolate* isolate_ {nullptr};
864     v8::ValueSerializer v8Serializer_;
865     std::unique_ptr<SerializationData> data_;
866     std::vector<v8::Global<v8::ArrayBuffer>> visitedTransfer_;
867     std::vector<std::unique_ptr<v8::BackingStore>> backingStores_;
868 
869     DISALLOW_COPY_AND_ASSIGN(Serializer);
870 };
871 
872 class Deserializer {
873 public:
Deserializer(v8::Isolate * isolate,std::unique_ptr<SerializationData> data)874     explicit Deserializer(v8::Isolate* isolate, std::unique_ptr<SerializationData> data)
875         : isolate_(isolate), v8Deserializer_(isolate, data->GetData(), data->GetSize(), nullptr), data_(std::move(data))
876     {
877         v8Deserializer_.SetSupportsLegacyWireFormat(true);
878     }
879     ~Deserializer() = default;
880 
DeserializeValue()881     v8::MaybeLocal<v8::Value> DeserializeValue()
882     {
883         v8::Local<v8::Context> context = isolate_->GetCurrentContext();
884         bool readResult = false;
885         if (!v8Deserializer_.ReadHeader(context).To(&readResult)) {
886             return v8::MaybeLocal<v8::Value>();
887         }
888 
889         uint32_t index = 0;
890         for (const auto& backingStore : data_->GetBackingStores()) {
891             v8::Local<v8::ArrayBuffer> arrayBuffer = v8::ArrayBuffer::New(isolate_, std::move(backingStore));
892             v8Deserializer_.TransferArrayBuffer(index++, arrayBuffer);
893         }
894 
895         return v8Deserializer_.ReadValue(context);
896     }
897 
898 private:
899     v8::Isolate* isolate_ {nullptr};
900     v8::ValueDeserializer v8Deserializer_;
901     std::unique_ptr<SerializationData> data_;
902 
903     DISALLOW_COPY_AND_ASSIGN(Deserializer);
904 };
905 
Serialize(NativeEngine * context,NativeValue * value,NativeValue * transfer)906 NativeValue* V8NativeEngine::Serialize(NativeEngine* context, NativeValue* value, NativeValue* transfer)
907 {
908     v8::Isolate* isolate = reinterpret_cast<V8NativeEngine*>(context)->GetIsolate();
909     v8::Local<v8::Value> v8Value = *value;
910     v8::Local<v8::Value> v8Transfer = *transfer;
911     Serializer serializer(isolate);
912     std::unique_ptr<SerializationData> data;
913     if (serializer.SerializeValue(v8Value, v8Transfer)) {
914         data = serializer.Release();
915     }
916     return reinterpret_cast<NativeValue*>(data.release());
917 }
918 
Deserialize(NativeEngine * context,NativeValue * recorder)919 NativeValue* V8NativeEngine::Deserialize(NativeEngine* context, NativeValue* recorder)
920 {
921     v8::Isolate* isolate = reinterpret_cast<V8NativeEngine*>(context)->GetIsolate();
922     std::unique_ptr<SerializationData> data(reinterpret_cast<SerializationData*>(recorder));
923     Deserializer deserializer(isolate, std::move(data));
924     v8::MaybeLocal<v8::Value> result = deserializer.DeserializeValue();
925     return V8ValueToNativeValue(this, result.ToLocalChecked());
926 }
927 
DeleteSerializationData(NativeValue * value) const928 void V8NativeEngine::DeleteSerializationData(NativeValue* value) const
929 {
930     SerializationData* data = reinterpret_cast<SerializationData*>(value);
931     delete data;
932 }
933 
SetPackagePath(const std::vector<std::string> & packagePath)934 void V8NativeEngine::SetPackagePath(const std::vector<std::string>& packagePath)
935 {
936     auto moduleManager = NativeModuleManager::GetInstance();
937     if (moduleManager && !packagePath.empty()) {
938         moduleManager->SetAppLibPath(packagePath);
939     }
940 }
941 
942 // Extracts a C string from a V8 Utf8Value.
ToCString(const v8::String::Utf8Value & value)943 const char* ToCString(const v8::String::Utf8Value& value)
944 {
945     return *value ? *value : "<string conversion failed>";
946 }
947 
GetExceptionForWorker() const948 ExceptionInfo* V8NativeEngine::GetExceptionForWorker() const
949 {
950     DCHECK(tryCatch_.HasCaught());
951     v8::HandleScope handle_scope(isolate_);
952 
953     ExceptionInfo* exceptionInfo = new ExceptionInfo();
954     v8::String::Utf8Value exception(isolate_, tryCatch_.Exception());
955     const char* exceptionString = ToCString(exception);
956     char* exceptionMessage = new char[strlen(exceptionString) + 1] { 0 };
957     if (memcpy_s(exceptionMessage, strlen(exceptionString) + 1, exceptionString, strlen(exceptionString)) != EOK) {
958         HILOG_INFO("worker:: memcpy_s error");
959         delete exceptionInfo;
960         delete[] exceptionMessage;
961         return nullptr;
962     }
963     exceptionInfo->message_ = exceptionMessage;
964 
965     v8::Local<v8::Context> context = context_.Get(isolate_);
966     v8::Context::Scope contextScope(context);
967     v8::Local<v8::Message> message = tryCatch_.Message();
968     if (!message.IsEmpty()) {
969         int32_t lineno = message->GetLineNumber(context).FromJust();
970         exceptionInfo->lineno_ = lineno;
971 
972         int32_t colno = message->GetStartColumn(context).FromJust();
973         exceptionInfo->colno_ = colno;
974     }
975     return exceptionInfo;
976 }
977 
ValueToNativeValue(JSValueWrapper & value)978 NativeValue* V8NativeEngine::ValueToNativeValue(JSValueWrapper& value)
979 {
980     v8::Local<v8::Value> v8Value = value;
981     return V8ValueToNativeValue(this, v8Value);
982 }
983 
SetPromiseRejectCallback(NativeReference * rejectCallbackRef,NativeReference * checkCallbackRef)984 void V8NativeEngine::SetPromiseRejectCallback(NativeReference* rejectCallbackRef, NativeReference* checkCallbackRef)
985 {
986     if (rejectCallbackRef == nullptr || checkCallbackRef == nullptr) {
987         HILOG_ERROR("rejectCallbackRef or checkCallbackRef is nullptr");
988         return;
989     }
990     promiseRejectCallbackRef_ = rejectCallbackRef;
991     checkCallbackRef_ = checkCallbackRef;
992     isolate_->SetPromiseRejectCallback(PromiseRejectCallback);
993 }
994 
995 
PromiseRejectCallback(v8::PromiseRejectMessage message)996 void V8NativeEngine::PromiseRejectCallback(v8::PromiseRejectMessage message)
997 {
998     v8::Local<v8::Promise> promise = message.GetPromise();
999     v8::PromiseRejectEvent event = message.GetEvent();
1000     v8::Isolate* isolate = promise->GetIsolate();
1001     v8::Local<v8::Value> reason = message.GetValue();
1002     if (reason.IsEmpty()) {
1003         reason = v8::Undefined(isolate);
1004     }
1005     V8NativeEngine* engine = g_env;
1006     if (engine == nullptr) {
1007         HILOG_ERROR("engine is nullptr");
1008         return;
1009     }
1010     v8::Local<v8::Function> promiseRejectCallback = *(engine->promiseRejectCallbackRef_->Get());
1011 
1012     if (promiseRejectCallback.IsEmpty()) {
1013         HILOG_ERROR("promiseRejectCallback is empty");
1014         return;
1015     }
1016     v8::Local<v8::Value> type = v8::Number::New(isolate, event);
1017     v8::Local<v8::Value> promiseValue(promise);
1018     v8::Local<v8::Context> context = engine->context_.Get(isolate);
1019     v8::Local<v8::Value> args[] = {type, promiseValue, reason};
1020 
1021     size_t size = sizeof(args) / sizeof(args[0]);
1022     bool succ = promiseRejectCallback->Call(context, v8::Undefined(isolate), size, args).IsEmpty();
1023     if (succ) {
1024         HILOG_ERROR("error : call function promiseRejectCallback is failed");
1025     }
1026     if (event == v8::kPromiseRejectWithNoHandler) {
1027         v8::Local<v8::Function> cb = *(engine->checkCallbackRef_->Get());
1028         isolate->EnqueueMicrotask(cb);
1029     }
1030 }
1031