/* * Copyright (c) 2021-2022 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 "jerryscript_native_engine_impl.h" #include "jerryscript-ext/handler.h" #include "jerryscript_native_deferred.h" #include "jerryscript_native_reference.h" #include "native_value/jerryscript_native_array.h" #include "native_value/jerryscript_native_array_buffer.h" #include "native_value/jerryscript_native_big_int.h" #include "native_value/jerryscript_native_boolean.h" #include "native_value/jerryscript_native_buffer.h" #include "native_value/jerryscript_native_data_view.h" #include "native_value/jerryscript_native_date.h" #include "native_value/jerryscript_native_external.h" #include "native_value/jerryscript_native_function.h" #include "native_value/jerryscript_native_number.h" #include "native_value/jerryscript_native_object.h" #include "native_value/jerryscript_native_string.h" #include "native_value/jerryscript_native_typed_array.h" #include "utils/log.h" JerryScriptNativeEngineImpl::JerryScriptNativeEngineImpl(NativeEngine* engine, void* jsEngineInterface) : NativeEngineInterface(engine, jsEngineInterface) { HILOG_INFO("JerryScriptNativeEngineImpl::JerryScriptNativeEngineImpl begin"); jerry_add_external(); jerry_value_t global = jerry_get_global_object(); jerry_value_t require = jerry_create_external_function([](const jerry_value_t function, const jerry_value_t thisVal, const jerry_value_t args[], const jerry_length_t argc) -> jerry_value_t { JerryScriptNativeEngineImpl* that = nullptr; jerry_get_object_native_pointer(function, (void**)&that, nullptr); jerry_value_t result = jerry_create_undefined(); if (!(argc >= 1 && jerry_value_is_string(args[0]))) { return result; } jerry_size_t moduleNameSize = jerry_get_utf8_string_size(args[0]); if (moduleNameSize == 0) { return result; } char* moduleName = new char[moduleNameSize + 1] { 0 }; uint32_t moduleNameLength = jerry_string_to_char_buffer(args[0], (jerry_char_t*)moduleName, moduleNameSize + 1); moduleName[moduleNameLength] = '\0'; NativeModule* module = that->GetModuleManager()->LoadNativeModule(moduleName, nullptr, false); if (module != nullptr) { std::string strModuleName(moduleName); JerryScriptNativeEngine* nativeEngine = new JerryScriptNativeEngine(that, that->GetJsEngine(), false); auto jsNativeEngine = static_cast<JerryScriptNativeEngine*>(that->GetRootNativeEngine()); if (!jsNativeEngine) { HILOG_ERROR("init module failed"); return result; } NativeValue* value = that->CreateObject(static_cast<JerryScriptNativeEngine*>(nativeEngine)); module->registerCallback(jsNativeEngine, value); result = jerry_acquire_value(*value); nativeEngine->SetModuleFileName(strModuleName); } return result; }); jerry_set_object_native_pointer(require, this, nullptr); jerryx_set_property_str(global, "requireNapi", require); jerry_release_value(require); jerry_release_value(global); HILOG_INFO("JerryScriptNativeEngineImpl::JerryScriptNativeEngineImpl end"); Init(); } JerryScriptNativeEngineImpl::~JerryScriptNativeEngineImpl() { HILOG_INFO("JerryScriptNativeEngineImpl::~JerryScriptNativeEngineImpl"); Deinit(); } void JerryScriptNativeEngineImpl::Loop(LoopMode mode, bool needSync) { NativeEngineInterface::Loop(mode, needSync); jerry_value_t retVal = jerry_run_all_enqueued_jobs(); jerry_release_value(retVal); } NativeValue* JerryScriptNativeEngineImpl::GetGlobal(NativeEngine* engine) { return new JerryScriptNativeObject(static_cast<JerryScriptNativeEngine*>(engine), jerry_get_global_object()); } NativeValue* JerryScriptNativeEngineImpl::CreateNull(NativeEngine* engine) { return new JerryScriptNativeValue(static_cast<JerryScriptNativeEngine*>(engine), jerry_create_null()); } NativeValue* JerryScriptNativeEngineImpl::CreateUndefined(NativeEngine* engine) { return new JerryScriptNativeValue(static_cast<JerryScriptNativeEngine*>(engine), jerry_create_undefined()); } NativeValue* JerryScriptNativeEngineImpl::CreateBoolean(NativeEngine* engine, bool value) { return new JerryScriptNativeBoolean(static_cast<JerryScriptNativeEngine*>(engine), value); } NativeValue* JerryScriptNativeEngineImpl::CreateNumber(NativeEngine* engine, int32_t value) { return new JerryScriptNativeNumber(static_cast<JerryScriptNativeEngine*>(engine), (double)value); } NativeValue* JerryScriptNativeEngineImpl::CreateNumber(NativeEngine* engine, uint32_t value) { return new JerryScriptNativeNumber(static_cast<JerryScriptNativeEngine*>(engine), (double)value); } NativeValue* JerryScriptNativeEngineImpl::CreateNumber(NativeEngine* engine, int64_t value) { return new JerryScriptNativeNumber(static_cast<JerryScriptNativeEngine*>(engine), (double)value); } NativeValue* JerryScriptNativeEngineImpl::CreateNumber(NativeEngine* engine, double value) { return new JerryScriptNativeNumber(static_cast<JerryScriptNativeEngine*>(engine), (double)value); } NativeValue* JerryScriptNativeEngineImpl::CreateString(NativeEngine* engine, const char* value, size_t length) { return new JerryScriptNativeString(static_cast<JerryScriptNativeEngine*>(engine), value, length); } NativeValue* JerryScriptNativeEngineImpl::CreateSymbol(NativeEngine* engine, NativeValue* value) { return new JerryScriptNativeValue(static_cast<JerryScriptNativeEngine*>(engine), jerry_create_symbol(*value)); } NativeValue* JerryScriptNativeEngineImpl::CreateExternal( NativeEngine* engine, void* value, NativeFinalize callback, void* hint, [[maybe_unused]] size_t nativeBindingSize) { return new JerryScriptNativeExternal(static_cast<JerryScriptNativeEngine*>(engine), value, callback, hint); } NativeValue* JerryScriptNativeEngineImpl::CreateObject(NativeEngine* engine) { return new JerryScriptNativeObject(static_cast<JerryScriptNativeEngine*>(engine)); } NativeValue* JerryScriptNativeEngineImpl::CreateNativeBindingObject( NativeEngine* engine, void* detach, void* attach) { return nullptr; } NativeValue* JerryScriptNativeEngineImpl::CreateFunction( NativeEngine* engine, const char* name, size_t length, NativeCallback cb, void* value) { return new JerryScriptNativeFunction(static_cast<JerryScriptNativeEngine*>(engine), name, cb, value); } NativeValue* JerryScriptNativeEngineImpl::CreateArray(NativeEngine* engine, size_t length) { return new JerryScriptNativeArray(static_cast<JerryScriptNativeEngine*>(engine), (int)length); } NativeValue* JerryScriptNativeEngineImpl::CreateArrayBuffer(NativeEngine* engine, void** value, size_t length) { return new JerryScriptNativeArrayBuffer(static_cast<JerryScriptNativeEngine*>(engine), value, length); } NativeValue* JerryScriptNativeEngineImpl::CreateArrayBufferExternal( NativeEngine* engine, void* value, size_t length, NativeFinalize cb, void* hint) { return new JerryScriptNativeArrayBuffer( static_cast<JerryScriptNativeEngine*>(engine), (unsigned char*)value, length, cb, hint); } NativeValue* JerryScriptNativeEngineImpl::CreateBuffer(NativeEngine* engine, void** value, size_t length) { return new JerryScriptNativeBuffer(static_cast<JerryScriptNativeEngine*>(engine), (uint8_t**)value, length); } NativeValue* JerryScriptNativeEngineImpl::CreateBufferCopy( NativeEngine* engine, void** value, size_t length, const void* data) { return new JerryScriptNativeBuffer( static_cast<JerryScriptNativeEngine*>(engine), (uint8_t**)value, length, (uint8_t*)data); } NativeValue* JerryScriptNativeEngineImpl::CreateBufferExternal( NativeEngine* engine, void* value, size_t length, NativeFinalize cb, void* hint) { return new JerryScriptNativeBuffer( static_cast<JerryScriptNativeEngine*>(engine), (uint8_t*)value, length, cb, hint); } NativeValue* JerryScriptNativeEngineImpl::CreateTypedArray( NativeEngine* engine, NativeTypedArrayType type, NativeValue* value, size_t length, size_t offset) { return new JerryScriptNativeTypedArray(static_cast<JerryScriptNativeEngine*>(engine), type, value, length, offset); } NativeValue* JerryScriptNativeEngineImpl::CreateDataView( NativeEngine* engine, NativeValue* value, size_t length, size_t offset) { return new JerryScriptNativeDataView(static_cast<JerryScriptNativeEngine*>(engine), value, length, offset); } NativeValue* JerryScriptNativeEngineImpl::CreatePromise(NativeEngine* engine, NativeDeferred** deferred) { jerry_value_t promise = jerry_create_promise(); *deferred = new JerryScriptNativeDeferred(promise); return new JerryScriptNativeValue(static_cast<JerryScriptNativeEngine*>(engine), promise); } NativeValue* JerryScriptNativeEngineImpl::CreateError(NativeEngine* engine, NativeValue* code, NativeValue* message) { jerry_value_t jerror = 0; jerror = jerry_create_error_sz(JERRY_ERROR_COMMON, nullptr, 0); jerror = jerry_get_value_from_error(jerror, true); if (message) { jerry_value_t jreturn = jerryx_set_property_str(jerror, "message", *message); jerry_release_value(jreturn); } if (code) { jerry_value_t jreturn = jerryx_set_property_str(jerror, "code", *code); jerry_release_value(jreturn); } jerror = jerry_create_error_from_value(jerror, true); return new JerryScriptNativeObject(static_cast<JerryScriptNativeEngine*>(engine), jerror); } NativeValue* JerryScriptNativeEngineImpl::CallFunction( NativeEngine* engine, NativeValue* thisVar, NativeValue* function, NativeValue* const *argv, size_t argc) { jerry_value_t* args = nullptr; if (argc > 0) { args = new jerry_value_t[argc]; for (size_t i = 0; i < argc; i++) { if (argv[i] == nullptr) { args[i] = jerry_create_undefined(); } else { args[i] = *argv[i]; } } } NativeScope* scope = scopeManager_->Open(); jerry_value_t result = jerry_call_function(*function, thisVar ? *thisVar : 0, (const jerry_value_t*)args, argc); scopeManager_->Close(scope); if (args != nullptr) { delete[] args; } if (jerry_value_is_error(result)) { jerry_value_t errorObj = jerry_get_value_from_error(result, true); jerry_value_t propName = jerry_create_string_from_utf8((const jerry_char_t*)"message"); jerry_property_descriptor_t propDescriptor = { 0 }; jerry_get_own_property_descriptor(errorObj, propName, &propDescriptor); jerry_value_t setResult = jerry_set_property(errorObj, propName, propDescriptor.value); jerry_release_value(propName); jerry_release_value(setResult); Throw(JerryValueToNativeValue(static_cast<JerryScriptNativeEngine*>(engine), errorObj)); return JerryValueToNativeValue(static_cast<JerryScriptNativeEngine*>(engine), jerry_create_undefined()); } else { return JerryValueToNativeValue(static_cast<JerryScriptNativeEngine*>(engine), result); } } NativeValue* JerryScriptNativeEngineImpl::RunScript(NativeEngine* engine, NativeValue* script) { NativeString* pscript = (NativeString*)script->GetInterface(NativeString::INTERFACE_ID); size_t length = pscript->GetLength(); if (length == 0) { return nullptr; } char* strScript = new char[length] { 0 }; pscript->GetCString(strScript, length, &length); jerry_value_t result = jerry_eval((const unsigned char*)strScript, pscript->GetLength(), JERRY_PARSE_NO_OPTS); if (jerry_value_is_error(result)) { result = jerry_get_value_from_error(result, true); } delete[] strScript; return JerryValueToNativeValue(static_cast<JerryScriptNativeEngine*>(engine), result); } NativeValue* JerryScriptNativeEngineImpl::RunBufferScript(NativeEngine* engine, std::vector<uint8_t>& buffer) { return nullptr; } NativeValue* JerryScriptNativeEngineImpl::RunActor( NativeEngine* engine, std::vector<uint8_t>& buffer, const char *descriptor) { return RunBufferScript(engine, buffer); } NativeValue* JerryScriptNativeEngineImpl::DefineClass( NativeEngine* engine, const char* name, NativeCallback callback, void* data, const NativePropertyDescriptor* properties, size_t length) { auto classConstructor = new JerryScriptNativeFunction( static_cast<JerryScriptNativeEngine*>(engine), name, callback, data); auto classProto = new JerryScriptNativeObject(static_cast<JerryScriptNativeEngine*>(engine)); jerryx_set_property_str(*classConstructor, "prototype", *classProto); for (size_t i = 0; i < length; ++i) { if (properties[i].attributes & NATIVE_STATIC) { classConstructor->DefineProperty(properties[i]); } else { classProto->DefineProperty(properties[i]); } } return classConstructor; } NativeValue* JerryScriptNativeEngineImpl::CreateInstance( NativeEngine* engine, NativeValue* constructor, NativeValue* const *argv, size_t argc) { return JerryValueToNativeValue(static_cast<JerryScriptNativeEngine*>(engine), jerry_construct_object( *constructor, (const jerry_value_t*)argv, argc)); } NativeReference* JerryScriptNativeEngineImpl::CreateReference( NativeEngine* engine, NativeValue* value, uint32_t initialRefcount, NativeFinalize callback, void* data, void* hint) { return new JerryScriptNativeReference( static_cast<JerryScriptNativeEngine*>(engine), value, initialRefcount, callback, data, hint); } bool JerryScriptNativeEngineImpl::Throw(NativeValue* error) { this->lastException_ = error; return true; } bool JerryScriptNativeEngineImpl::Throw( NativeEngine* engine, NativeErrorType type, const char* code, const char* message) { jerry_value_t jerror = 0; jerry_error_t jtype; switch (type) { case NATIVE_COMMON_ERROR: jtype = JERRY_ERROR_COMMON; break; case NATIVE_TYPE_ERROR: jtype = JERRY_ERROR_TYPE; break; case NATIVE_RANGE_ERROR: jtype = JERRY_ERROR_RANGE; break; default: return false; } jerror = jerry_create_error(jtype, (const unsigned char*)message); jerror = jerry_get_value_from_error(jerror, true); if (code) { jerry_value_t jcode = jerry_create_string_from_utf8((const unsigned char*)code); jerryx_set_property_str(jerror, "code", jcode); } jerror = jerry_create_error_from_value(jerror, true); this->lastException_ = new JerryScriptNativeObject(static_cast<JerryScriptNativeEngine*>(engine), jerror); return true; } void* JerryScriptNativeEngineImpl::CreateRuntime(NativeEngine* engine) { return nullptr; } NativeValue* JerryScriptNativeEngineImpl::Serialize(NativeEngine* context, NativeValue* value, NativeValue* transfer) { return nullptr; } NativeValue* JerryScriptNativeEngineImpl::Deserialize( NativeEngine* engine, NativeEngine* context, NativeValue* recorder) { return nullptr; } NativeValue* JerryScriptNativeEngineImpl::LoadModule( NativeEngine* engine, NativeValue* str, const std::string& fileName) { return nullptr; } NativeValue* JerryScriptNativeEngineImpl::JerryValueToNativeValue( JerryScriptNativeEngine* engine, jerry_value_t value) { NativeValue* result = nullptr; switch (jerry_value_get_type(value)) { case JERRY_TYPE_NONE: result = new JerryScriptNativeValue(engine, value); break; case JERRY_TYPE_UNDEFINED: result = new JerryScriptNativeValue(engine, value); break; case JERRY_TYPE_NULL: result = new JerryScriptNativeValue(engine, value); break; case JERRY_TYPE_BOOLEAN: result = new JerryScriptNativeBoolean(engine, value); break; case JERRY_TYPE_NUMBER: result = new JerryScriptNativeNumber(engine, value); break; case JERRY_TYPE_STRING: result = new JerryScriptNativeString(engine, value); break; case JERRY_TYPE_OBJECT: if (jerry_value_is_array(value)) { result = new JerryScriptNativeArray(engine, value); } else if (jerry_value_is_arraybuffer(value)) { result = new JerryScriptNativeArrayBuffer(engine, value); } else if (jerry_value_is_dataview(value)) { result = new JerryScriptNativeDataView(engine, value); } else if (jerry_value_is_typedarray(value)) { result = new JerryScriptNativeTypedArray(engine, value); } else if (jerry_value_is_external(value)) { result = new JerryScriptNativeExternal(engine, value); } else if (jerry_is_date(value)) { result = new JerryScriptNativeDate(engine, value); } else { result = new JerryScriptNativeObject(engine, value); } break; case JERRY_TYPE_FUNCTION: result = new JerryScriptNativeFunction(engine, value); break; case JERRY_TYPE_ERROR: result = new JerryScriptNativeObject(engine, value); break; case JERRY_TYPE_SYMBOL: result = new JerryScriptNativeValue(engine, value); break; #if JERRY_API_MINOR_VERSION > 3 case JERRY_TYPE_BIGINT: result = new JerryScriptNativeBigInt(engine, value); break; #endif default:; } return result; } NativeValue* JerryScriptNativeEngineImpl::ValueToNativeValue(NativeEngine* engine, JSValueWrapper& value) { jerry_value_t jerryValue = value; return JerryValueToNativeValue(static_cast<JerryScriptNativeEngine*>(engine), jerryValue); } bool JerryScriptNativeEngineImpl::TriggerFatalException(NativeValue* error) { return false; } bool JerryScriptNativeEngineImpl::AdjustExternalMemory(int64_t ChangeInBytes, int64_t* AdjustedValue) { HILOG_INFO("L1: napi_adjust_external_memory not supported!"); return true; } NativeValue* JerryScriptNativeEngineImpl::CreateDate(NativeEngine* engine, double time) { jerry_value_t value = jerry_strict_date(time); return JerryValueToNativeValue(static_cast<JerryScriptNativeEngine*>(engine), value); } void JerryScriptNativeEngineImpl::SetPromiseRejectCallback( NativeEngine* engine, NativeReference* rejectCallbackRef, NativeReference* checkCallbackRef) {} NativeValue* JerryScriptNativeEngineImpl::CreateBigWords( NativeEngine* engine, int sign_bit, size_t word_count, const uint64_t* words) { #if JERRY_API_MINOR_VERSION > 3 // jerryscript2.3: 3, jerryscript2.4: 4 constexpr int bigintMod = 2; bool sign = false; if ((sign_bit % bigintMod) == 1) { sign = true; } uint32_t size = (uint32_t)word_count; jerry_value_t jerryValue = jerry_create_bigint(words, size, sign); return new JerryScriptNativeBigInt(static_cast<JerryScriptNativeEngine*>(engine), jerryValue); #else return nullptr; #endif } NativeValue* JerryScriptNativeEngineImpl::CreateBigInt(NativeEngine* engine, int64_t value) { return new JerryScriptNativeBigInt(static_cast<JerryScriptNativeEngine*>(engine), value); } NativeValue* JerryScriptNativeEngineImpl::CreateBigInt(NativeEngine* engine, uint64_t value) { #if JERRY_API_MINOR_VERSION > 3 // jerryscript2.3: 3, jerryscript2.4: 4 return new JerryScriptNativeBigInt(static_cast<JerryScriptNativeEngine*>(engine), value, true); #else return nullptr; #endif } NativeValue* JerryScriptNativeEngineImpl::CreateString16(NativeEngine* engine, const char16_t* value, size_t length) { return new JerryScriptNativeString(static_cast<JerryScriptNativeEngine*>(engine), value, length); }