/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ark_native_engine.h" #include "ark_native_deferred.h" #include "ark_native_reference.h" #include "native_engine/native_property.h" #include "native_value/ark_native_array.h" #include "native_value/ark_native_array_buffer.h" #include "native_value/ark_native_boolean.h" #include "native_value/ark_native_data_view.h" #include "native_value/ark_native_external.h" #include "native_value/ark_native_function.h" #include "native_value/ark_native_number.h" #include "native_value/ark_native_object.h" #include "native_value/ark_native_string.h" #include "native_value/ark_native_typed_array.h" #include "utils/log.h" using panda::ObjectRef; using panda::StringRef; using panda::FunctionRef; using panda::PrimitiveRef; using panda::JSValueRef; using panda::ArrayBufferRef; using panda::TypedArrayRef; using panda::PromiseCapabilityRef; using panda::NativePointerRef; using panda::SymbolRef; ArkNativeEngine::ArkNativeEngine(EcmaVM* vm, void* jsEngine) : NativeEngine(jsEngine), vm_(vm), topScope_(vm) { Local requireName = StringRef::NewFromUtf8(vm, "requireNapi"); Local requireInternalName = StringRef::NewFromUtf8(vm, "requireInternal"); void* requireData = static_cast(this); Local requireNapi = FunctionRef::New( vm, [](EcmaVM *ecmaVm, Local thisObj, const Local argv[], // NOLINTNEXTLINE(modernize-avoid-c-arrays) int32_t length, void *data) -> Local { panda::EscapeLocalScope scope(ecmaVm); NativeModuleManager* moduleManager = NativeModuleManager::GetInstance(); ArkNativeEngine* engine = static_cast(data); Local moduleName(argv[0]); NativeModule* module = moduleManager->LoadNativeModule(moduleName->ToString().c_str(), nullptr, false); Global exports; if (module != nullptr) { if (module->jsCode != nullptr) { HILOG_INFO("load js code"); NativeValue* script = engine->CreateString(module->jsCode, strlen(module->jsCode)); NativeValue* exportObject = engine->LoadModule(script, "testjsnapi.js"); if (exportObject == nullptr) { HILOG_ERROR("load module failed"); } else { exports = *exportObject; } } else if (module->registerCallback != nullptr) { NativeValue* exportObject = new ArkNativeObject(engine); module->registerCallback(engine, exportObject); exports = *exportObject; } else { HILOG_ERROR("init module failed"); } } return scope.Escape(exports.ToLocal(ecmaVm)); }, requireData); Local requireInternal = FunctionRef::New( vm, [](EcmaVM *ecmaVm, Local thisObj, const Local argv[], // NOLINTNEXTLINE(modernize-avoid-c-arrays) int32_t length, void *data) -> Local { panda::EscapeLocalScope scope(ecmaVm); NativeModuleManager* moduleManager = NativeModuleManager::GetInstance(); ArkNativeEngine* engine = static_cast(data); Local moduleName(argv[0]); NativeModule* module = moduleManager->LoadNativeModule(moduleName->ToString().c_str(), nullptr, false); Global exports; if (module != nullptr) { NativeValue* exportObject = new ArkNativeObject(engine); module->registerCallback(engine, exportObject); exports = *exportObject; } return scope.Escape(exports.ToLocal(ecmaVm)); }, requireData); Local global = panda::JSNApi::GetGlobalObject(vm); global->Set(vm, requireName, requireNapi); global->Set(vm, requireInternalName, requireInternal); } ArkNativeEngine::~ArkNativeEngine() {} void ArkNativeEngine::Loop(LoopMode mode, bool needSync) { LocalScope scope(vm_); NativeEngine::Loop(mode); //panda::JSNApi::ExecutePendingJob(vm_); } NativeValue* ArkNativeEngine::GetGlobal() { Local value = panda::JSNApi::GetGlobalObject(vm_); return ArkValueToNativeValue(this, value); } NativeValue* ArkNativeEngine::CreateNull() { Local value = JSValueRef::Null(vm_); return new ArkNativeValue(this, value); } NativeValue* ArkNativeEngine::CreateUndefined() { Local value = JSValueRef::Undefined(vm_); return new ArkNativeValue(this, value); } NativeValue* ArkNativeEngine::CreateBoolean(bool value) { return new ArkNativeBoolean(this, value); } NativeValue* ArkNativeEngine::CreateNumber(int32_t value) { return new ArkNativeNumber(this, value); } NativeValue* ArkNativeEngine::CreateNumber(uint32_t value) { return new ArkNativeNumber(this, value); } NativeValue* ArkNativeEngine::CreateNumber(int64_t value) { return new ArkNativeNumber(this, value); } NativeValue* ArkNativeEngine::CreateNumber(double value) { return new ArkNativeNumber(this, value); } NativeValue* ArkNativeEngine::CreateString(const char* value, size_t length) { return new ArkNativeString(this, value, length); } NativeValue* ArkNativeEngine::CreateSymbol(NativeValue* value) { LocalScope scope(vm_); Global str = *value; Local symbol = SymbolRef::New(vm_, str.ToLocal(vm_)); return new ArkNativeValue(this, symbol); } NativeValue* ArkNativeEngine::CreateExternal(void* value, NativeFinalize callback, void* hint) { return new ArkNativeExternal(this, value, callback, hint); } NativeValue* ArkNativeEngine::CreateObject() { return new ArkNativeObject(this); } NativeValue* ArkNativeEngine::CreateFunction(const char* name, size_t length, NativeCallback cb, void* value) { return new ArkNativeFunction(this, name, length, cb, value); } NativeValue* ArkNativeEngine::CreateArray(size_t length) { return new ArkNativeArray(this, length); } NativeValue* ArkNativeEngine::CreateArrayBuffer(void** value, size_t length) { return new ArkNativeArrayBuffer(this, (uint8_t**)value, length); } NativeValue* ArkNativeEngine::CreateArrayBufferExternal(void* value, size_t length, NativeFinalize cb, void* hint) { return new ArkNativeArrayBuffer(this, (uint8_t*)value, length, cb, hint); } NativeValue* ArkNativeEngine::CreateTypedArray(NativeTypedArrayType type, NativeValue* value, size_t length, size_t offset) { LocalScope scope(vm_); Global globalBuffer = *value; Local buffer = globalBuffer.ToLocal(vm_); Local typedArray; switch (type) { case NATIVE_INT8_ARRAY: typedArray = panda::Int8ArrayRef::New(vm_, buffer, offset, length); break; case NATIVE_UINT8_ARRAY: typedArray = panda::Uint8ArrayRef::New(vm_, buffer, offset, length); break; case NATIVE_UINT8_CLAMPED_ARRAY: typedArray = panda::Uint8ClampedArrayRef::New(vm_, buffer, offset, length); break; case NATIVE_INT16_ARRAY: typedArray = panda::Int16ArrayRef::New(vm_, buffer, offset, length); break; case NATIVE_UINT16_ARRAY: typedArray = panda::Uint16ArrayRef::New(vm_, buffer, offset, length); break; case NATIVE_INT32_ARRAY: typedArray = panda::Int32ArrayRef::New(vm_, buffer, offset, length); break; case NATIVE_UINT32_ARRAY: typedArray = panda::Uint32ArrayRef::New(vm_, buffer, offset, length); break; case NATIVE_FLOAT32_ARRAY: typedArray = panda::Float32ArrayRef::New(vm_, buffer, offset, length); break; case NATIVE_FLOAT64_ARRAY: typedArray = panda::Float64ArrayRef::New(vm_, buffer, offset, length); break; case NATIVE_BIGINT64_ARRAY: // not support yet return nullptr; case NATIVE_BIGUINT64_ARRAY: // not support yet return nullptr; default: return nullptr; } return new ArkNativeTypedArray(this, typedArray); } NativeValue* ArkNativeEngine::CreateDataView(NativeValue* value, size_t length, size_t offset) { return new ArkNativeDataView(this, value, length, offset); } NativeValue* ArkNativeEngine::CreatePromise(NativeDeferred** deferred) { LocalScope scope(vm_); Local capability = PromiseCapabilityRef::New(vm_); *deferred = new ArkNativeDeferred(this, capability); return new ArkNativeValue(this, capability->GetPromise(vm_)); } NativeValue* ArkNativeEngine::CreateError(NativeValue* code, NativeValue* message) { LocalScope scope(vm_); Local errorVal = panda::Exception::Error(vm_, *message); if (code != nullptr) { Local codeKey = StringRef::NewFromUtf8(vm_, "code"); Local errorObj(errorVal); errorObj->Set(vm_, codeKey, *code); } return ArkValueToNativeValue(this, errorVal); } NativeValue* ArkNativeEngine::CallFunction(NativeValue* thisVar, NativeValue* function, NativeValue* const* argv, size_t argc) { if (function == nullptr) { return nullptr; } LocalScope scope(vm_); Global thisObj = (thisVar != nullptr) ? *thisVar : Global(vm_, JSValueRef::Undefined(vm_)); Global funcObj = *function; Local* args = nullptr; if (argc > 0) { args = new Local[argc]; for (size_t i = 0; i < argc; i++) { if (argv[i] != nullptr) { Global arg = *argv[i]; args[i] = arg.ToLocal(vm_); } else { args[i] = JSValueRef::Undefined(vm_); } } } Local value = funcObj->Call(vm_, thisObj.ToLocal(vm_), args, argc); if (args != nullptr) { delete []args; } return ArkValueToNativeValue(this, value); } NativeValue* ArkNativeEngine::RunScript(NativeValue* script) { // not support yet return nullptr; } NativeValue* ArkNativeEngine::DefineClass(const char* name, NativeCallback callback, void* data, const NativePropertyDescriptor* properties, size_t length) { LocalScope scope(vm_); auto classConstructor = new ArkNativeFunction(this, name, callback, data); for (size_t i = 0; i < length; i++) { if (properties[i].attributes & NATIVE_STATIC) { classConstructor->DefineProperty(properties[i]); } else { auto classPrototype = classConstructor->GetFunctionPrototype(); static_cast(classPrototype)->DefineProperty(properties[i]); } } return classConstructor; } NativeValue* ArkNativeEngine::CreateInstance(NativeValue* constructor, NativeValue* const* argv, size_t argc) { if (constructor == nullptr) { return nullptr; } LocalScope scope(vm_); Global value = *constructor; Local* args = nullptr; if (argc > 0) { args = new Local[argc]; for (size_t i = 0; i < argc; i++) { Global arg = *argv[i]; args[i] = arg.ToLocal(vm_); } } Local instance = value->Constructor(vm_, args, argc); if (args != nullptr) { delete[] args; } return ArkValueToNativeValue(this, instance); } NativeReference* ArkNativeEngine::CreateReference(NativeValue* value, uint32_t initialRefcount) { return new ArkNativeReference(this, value, initialRefcount); } bool ArkNativeEngine::Throw(NativeValue* error) { LocalScope scope(vm_); Global errorVal = *error; panda::JSNApi::ThrowException(vm_, errorVal.ToLocal(vm_)); lastException_ = error; return true; } bool ArkNativeEngine::Throw(NativeErrorType type, const char* code, const char* message) { LocalScope scope(vm_); Local error; switch (type) { case NATIVE_COMMON_ERROR: error = panda::Exception::Error(vm_, StringRef::NewFromUtf8(vm_, message)); break; case NATIVE_TYPE_ERROR: error = panda::Exception::TypeError(vm_, StringRef::NewFromUtf8(vm_, message)); break; case NATIVE_RANGE_ERROR: error = panda::Exception::RangeError(vm_, StringRef::NewFromUtf8(vm_, message)); break; default: return false; } if (code != nullptr) { Local codeKey = StringRef::NewFromUtf8(vm_, "code"); Local codeValue = StringRef::NewFromUtf8(vm_, code); Local errorObj(error); errorObj->Set(vm_, codeKey, codeValue); } panda::JSNApi::ThrowException(vm_, error); lastException_ = ArkValueToNativeValue(this, error); return true; } void* ArkNativeEngine::CreateRuntime() { return nullptr; } NativeValue* ArkNativeEngine::Serialize(NativeEngine* context, NativeValue* value, NativeValue* transfer) { return nullptr; } NativeValue* ArkNativeEngine::Deserialize(NativeEngine* context, NativeValue* recorder) { return nullptr; } void ArkNativeEngine::DeleteSerializationData(NativeValue* value) const { } ExceptionInfo* ArkNativeEngine::GetExceptionForWorker() const { return nullptr; } NativeValue* ArkNativeEngine::LoadModule(NativeValue* str, const std::string& fileName) { return nullptr; } NativeValue* ArkNativeEngine::ArkValueToNativeValue(ArkNativeEngine* engine, Local value) { NativeValue* result = nullptr; if (value->IsNull() || value->IsUndefined() || value->IsSymbol() || value->IsPromise()) { result = new ArkNativeValue(engine, value); } else if (value->IsNumber()) { result = new ArkNativeNumber(engine, value); } else if (value->IsString()) { result = new ArkNativeString(engine, value); } else if (value->IsArray(engine->GetEcmaVm())) { result = new ArkNativeArray(engine, value); } else if (value->IsFunction()) { result = new ArkNativeFunction(engine, value); } else if (value->IsArrayBuffer()) { result = new ArkNativeArrayBuffer(engine, value); } else if (value->IsDataView()) { result = new ArkNativeDataView(engine, value); } else if (value->IsTypedArray()) { result = new ArkNativeTypedArray(engine, value); } else if (value->IsNativeObject() || value->IsNativePointer()) { result = new ArkNativeExternal(engine, value); } else if (value->IsObject()) { result = new ArkNativeObject(engine, value); } else if (value->IsBoolean()) { result = new ArkNativeBoolean(engine, value); } return result; } NativeValue* ArkNativeEngine::ValueToNativeValue(JSValueWrapper& value) { Global arkValue = value; return ArkValueToNativeValue(this, arkValue.ToLocal(vm_)); }