/* * 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 "jsnapi_helper-inl.h" #include #include #include "ecmascript/base/builtins_base.h" #include "ecmascript/base/json_parser.h" #include "ecmascript/base/json_stringifier.h" #include "ecmascript/base/string_helper.h" #include "ecmascript/base/typed_array_helper-inl.h" #include "ecmascript/ecma_global_storage-inl.h" #include "ecmascript/ecma_language_context.h" #include "ecmascript/ecma_module.h" #include "ecmascript/ecma_string.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" #include "ecmascript/internal_call_params.h" #include "ecmascript/interpreter/fast_runtime_stub-inl.h" #include "ecmascript/js_array.h" #include "ecmascript/js_arraybuffer.h" #include "ecmascript/js_dataview.h" #include "ecmascript/js_function.h" #include "ecmascript/js_map.h" #include "ecmascript/js_primitive_ref.h" #include "ecmascript/js_promise.h" #include "ecmascript/js_regexp.h" #include "ecmascript/js_serializer.h" #include "ecmascript/js_set.h" #include "ecmascript/js_tagged_number.h" #include "ecmascript/js_thread.h" #include "ecmascript/js_typed_array.h" #include "ecmascript/mem/region.h" #include "ecmascript/object_factory.h" #include "ecmascript/tagged_array.h" #include "libpandabase/os/library_loader.h" #include "utils/pandargs.h" namespace panda { using ecmascript::CString; using ecmascript::ECMAObject; using ecmascript::EcmaString; using ecmascript::ErrorType; using ecmascript::FastRuntimeStub; using ecmascript::GlobalEnv; using ecmascript::GlobalEnvConstants; using ecmascript::InternalCallParams; using ecmascript::JSArray; using ecmascript::JSArrayBuffer; using ecmascript::JSDataView; using ecmascript::JSDate; using ecmascript::JSFunction; using ecmascript::JSFunctionBase; using ecmascript::JSFunctionExtraInfo; using ecmascript::JSHClass; using ecmascript::JSMap; using ecmascript::JSMethod; using ecmascript::JSNativePointer; using ecmascript::JSObject; using ecmascript::JSPrimitiveRef; using ecmascript::JSPromise; using ecmascript::JSRegExp; using ecmascript::JSSerializer; using ecmascript::JSSet; using ecmascript::JSSymbol; using ecmascript::JSTaggedNumber; using ecmascript::JSTaggedType; using ecmascript::JSTaggedValue; using ecmascript::JSThread; using ecmascript::ObjectFactory; using ecmascript::PromiseCapability; using ecmascript::PropertyDescriptor; using ecmascript::OperationResult; using ecmascript::Region; using ecmascript::TaggedArray; using ecmascript::JSTypedArray; using ecmascript::base::BuiltinsBase; using ecmascript::base::JsonParser; using ecmascript::base::JsonStringifier; using ecmascript::base::StringHelper; using ecmascript::base::TypedArrayHelper; template using JSHandle = ecmascript::JSHandle; namespace { constexpr uint32_t INTERNAL_POOL_SIZE = 0; constexpr uint32_t CODE_POOL_SIZE = 0; constexpr uint32_t COMPILER_POOL_SIZE = 0; // NOLINTNEXTLINE(fuchsia-statically-constructed-objects) constexpr std::string_view ENTRY_POINTER = "_GLOBAL::func_main_0"; } // ------------------------------------ Panda ----------------------------------------------- bool JSNApi::CreateRuntime(const RuntimeOption &option) { RuntimeOptions runtimeOptions; runtimeOptions.SetRuntimeType("ecmascript"); // GC runtimeOptions.SetGcType(option.GetGcType()); runtimeOptions.SetRunGcInPlace(true); // Mem runtimeOptions.SetHeapSizeLimit(option.GetGcPoolSize()); runtimeOptions.SetInternalMemorySizeLimit(INTERNAL_POOL_SIZE); runtimeOptions.SetCodeCacheSizeLimit(CODE_POOL_SIZE); runtimeOptions.SetCompilerMemorySizeLimit(COMPILER_POOL_SIZE); runtimeOptions.SetInternalAllocatorType("malloc"); // Boot runtimeOptions.SetShouldLoadBootPandaFiles(false); runtimeOptions.SetShouldInitializeIntrinsics(false); runtimeOptions.SetBootClassSpaces({"ecmascript"}); // Dfx runtimeOptions.SetLogLevel(option.GetLogLevel()); arg_list_t logComponents; logComponents.emplace_back("all"); runtimeOptions.SetLogComponents(logComponents); if (option.GetLogBufPrint() != nullptr) { runtimeOptions.SetMobileLog(reinterpret_cast(option.GetLogBufPrint())); } // Debugger runtimeOptions.SetDebuggerLibraryPath(option.GetDebuggerLibraryPath()); static EcmaLanguageContext lcEcma; if (!Runtime::Create(runtimeOptions, {&lcEcma})) { std::cerr << "Error: cannot create runtime" << std::endl; return false; } return true; } bool JSNApi::DestoryRuntime() { return Runtime::Destroy(); } EcmaVM *JSNApi::CreateJSVM(const RuntimeOption &option) { auto runtime = Runtime::GetCurrent(); if (runtime == nullptr) { // Art java + Panda js or L2 pure JS app if (!CreateRuntime(option)) { return nullptr; } runtime = Runtime::GetCurrent(); return EcmaVM::Cast(runtime->GetPandaVM()); } RuntimeOptions runtimeOptions; // GC runtimeOptions.SetGcTriggerType("no-gc-for-start-up"); // A non-production gc strategy. Prohibit stw-gc 10 times. return EcmaVM::Cast(EcmaVM::Create(runtimeOptions)); } void JSNApi::DestoryJSVM(EcmaVM *ecmaVm) { auto runtime = Runtime::GetCurrent(); if (runtime != nullptr) { PandaVM *mainVm = runtime->GetPandaVM(); // Art java + Panda js if (mainVm == ecmaVm) { DestoryRuntime(); } else { EcmaVM::Destroy(ecmaVm); } } } void JSNApi::TriggerGC(const EcmaVM *vm, TRIGGER_GC_TYPE gcType) { if (vm->GetJSThread() != nullptr && vm->IsInitialized()) { switch (gcType) { case TRIGGER_GC_TYPE::SEMI_GC: vm->CollectGarbage(ecmascript::TriggerGCType::SEMI_GC); break; case TRIGGER_GC_TYPE::OLD_GC: vm->CollectGarbage(ecmascript::TriggerGCType::OLD_GC); break; case TRIGGER_GC_TYPE::COMPRESS_FULL_GC: vm->CollectGarbage(ecmascript::TriggerGCType::COMPRESS_FULL_GC); break; default: break; } } } void JSNApi::ThrowException(const EcmaVM *vm, Local error) { auto thread = vm->GetJSThread(); thread->SetException(JSNApiHelper::ToJSTaggedValue(*error)); } bool JSNApi::StartDebugger(const char *library_path, EcmaVM *vm) { auto handle = panda::os::library_loader::Load(std::string(library_path)); if (!handle) { return false; } using StartDebugger = bool (*)(const std::string &, EcmaVM *); auto sym = panda::os::library_loader::ResolveSymbol(handle.Value(), "StartDebug"); if (!sym) { LOG(ERROR, RUNTIME) << sym.Error().ToString(); return false; } bool ret = reinterpret_cast(sym.Value())("PandaDebugger", vm); if (ret) { auto runtime = Runtime::GetCurrent(); runtime->SetDebugMode(true); runtime->SetDebuggerLibrary(std::move(handle.Value())); } return ret; } bool JSNApi::Execute(EcmaVM *vm, Local fileName, Local entry) { std::string file = fileName->ToString(); std::string entryPoint = entry->ToString(); std::vector argv; LOG_ECMA(DEBUG) << "start to execute ark file" << file; if (!vm->ExecuteFromPf(file, entryPoint, argv)) { LOG_ECMA(ERROR) << "Cannot execute ark file" << file; std::cerr << "Cannot execute ark file '" << file << "' with entry '" << entryPoint << "'" << std::endl; return false; } return true; } bool JSNApi::Execute(EcmaVM *vm, const uint8_t *data, int32_t size, Local entry) { std::string entryPoint = entry->ToString(); std::vector argv; if (!vm->ExecuteFromBuffer(data, size, entryPoint, argv)) { std::cerr << "Cannot execute panda file from memory " << "' with entry '" << entryPoint << "'" << std::endl; return false; } return true; } Local JSNApi::GetUncaughtException(const EcmaVM *vm) { return JSNApiHelper::ToLocal(vm->GetEcmaUncaughtException()); } void JSNApi::EnableUserUncaughtErrorHandler(EcmaVM *vm) { return vm->EnableUserUncaughtErrorHandler(); } Local JSNApi::GetGlobalObject(const EcmaVM *vm) { JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle global(vm->GetJSThread(), globalEnv->GetGlobalObject()); return JSNApiHelper::ToLocal(global); } void JSNApi::ExecutePendingJob(const EcmaVM *vm) { vm->ExecutePromisePendingJob(); } uintptr_t JSNApi::GetHandleAddr(const EcmaVM *vm, uintptr_t localAddress) { if (localAddress == 0) { return 0; } JSTaggedType value = *(reinterpret_cast(localAddress)); return ecmascript::EcmaHandleScope::NewHandle(vm->GetJSThread(), value); } uintptr_t JSNApi::GetGlobalHandleAddr(const EcmaVM *vm, uintptr_t localAddress) { if (localAddress == 0) { return 0; } JSTaggedType value = *(reinterpret_cast(localAddress)); return vm->GetJSThread()->GetEcmaGlobalStorage()->NewGlobalHandle(value); } uintptr_t JSNApi::SetWeak(const EcmaVM *vm, uintptr_t localAddress) { if (localAddress == 0) { return 0; } return vm->GetJSThread()->GetEcmaGlobalStorage()->SetWeak(localAddress); } bool JSNApi::IsWeak(const EcmaVM *vm, uintptr_t localAddress) { if (localAddress == 0) { return false; } return vm->GetJSThread()->GetEcmaGlobalStorage()->IsWeak(localAddress); } void JSNApi::DisposeGlobalHandleAddr(const EcmaVM *vm, uintptr_t addr) { if (addr == 0) { return; } vm->GetJSThread()->GetEcmaGlobalStorage()->DisposeGlobalHandle(addr); } void *JSNApi::SerializeValue(const EcmaVM *vm, Local value, Local transfer) { ecmascript::JSThread *thread = vm->GetJSThread(); ecmascript::Serializer serializer(thread); JSHandle arkValue = JSNApiHelper::ToJSHandle(value); JSHandle arkTransfer = JSNApiHelper::ToJSHandle(transfer); std::unique_ptr data; if (serializer.WriteValue(thread, arkValue, arkTransfer)) { data = serializer.Release(); } return reinterpret_cast(data.release()); } Local JSNApi::DeserializeValue(const EcmaVM *vm, void *recoder) { ecmascript::JSThread *thread = vm->GetJSThread(); std::unique_ptr data(reinterpret_cast(recoder)); ecmascript::Deserializer deserializer(thread, data.release()); JSHandle result = deserializer.ReadValue(); return JSNApiHelper::ToLocal(result); } void JSNApi::DeleteSerializationData(void *data) { ecmascript::SerializationData *value = reinterpret_cast(data); delete value; } bool JSNApi::ExecuteModuleFromBuffer(EcmaVM *vm, const void *data, int32_t size, const std::string &file) { auto moduleManager = vm->GetModuleManager(); moduleManager->SetCurrentExportModuleName(file); // Update Current Module vm->GetJSThread()->SetIsEcmaInterpreter(true); std::vector argv; if (!vm->ExecuteFromBuffer(data, size, ENTRY_POINTER, argv)) { std::cerr << "Cannot execute panda file from memory" << std::endl; moduleManager->RestoreCurrentExportModuleName(); return false; } // Restore Current Module moduleManager->RestoreCurrentExportModuleName(); return true; } Local JSNApi::GetExportObject(EcmaVM *vm, const std::string &file, const std::string &itemName) { auto moduleManager = vm->GetModuleManager(); ObjectFactory *factory = vm->GetFactory(); JSHandle moduleName(factory->NewFromStdStringUnCheck(file, true)); JSHandle moduleObj = moduleManager->GetModule(vm->GetJSThread(), moduleName); JSHandle itemString(factory->NewFromStdString(itemName)); JSHandle exportObj = moduleManager->GetModuleItem(vm->GetJSThread(), moduleObj, itemString); return JSNApiHelper::ToLocal(exportObj); } // ----------------------------------- HandleScope ------------------------------------- LocalScope::LocalScope(const EcmaVM *vm) : thread_(vm->GetJSThread()) { auto thread = reinterpret_cast(thread_); prevNext_ = thread->GetHandleScopeStorageNext(); prevEnd_ = thread->GetHandleScopeStorageEnd(); prevHandleStorageIndex_ = thread->GetCurrentHandleStorageIndex(); } LocalScope::LocalScope(const EcmaVM *vm, JSTaggedType value) : thread_(vm->GetJSThread()) { auto thread = reinterpret_cast(thread_); prevNext_ = thread->GetHandleScopeStorageNext(); prevEnd_ = thread->GetHandleScopeStorageEnd(); prevHandleStorageIndex_ = thread->GetCurrentHandleStorageIndex(); ecmascript::EcmaHandleScope::NewHandle(thread, value); } LocalScope::~LocalScope() { auto thread = reinterpret_cast(thread_); thread->SetHandleScopeStorageNext(static_cast(prevNext_)); if (thread->GetHandleScopeStorageEnd() != prevEnd_) { thread->SetHandleScopeStorageEnd(static_cast(prevEnd_)); thread->ShrinkHandleStorage(prevHandleStorageIndex_); } } // ----------------------------------- EscapeLocalScope ------------------------------ EscapeLocalScope::EscapeLocalScope(const EcmaVM *vm) : LocalScope(vm, 0U) { auto thread = vm->GetJSThread(); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) escapeHandle_ = ToUintPtr(thread->GetHandleScopeStorageNext() - 1); } // ----------------------------------- NumberRef --------------------------------------- Local NumberRef::New(const EcmaVM *vm, double input) { JSThread *thread = vm->GetJSThread(); JSHandle number(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(number); } double NumberRef::Value() { return JSTaggedNumber(JSNApiHelper::ToJSTaggedValue(this)).GetNumber(); } // ----------------------------------- BooleanRef --------------------------------------- Local BooleanRef::New(const EcmaVM *vm, bool input) { JSThread *thread = vm->GetJSThread(); JSHandle boolean(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(boolean); } bool BooleanRef::Value() { return JSNApiHelper::ToJSTaggedValue(this).IsTrue(); } // ----------------------------------- IntegerRef --------------------------------------- Local IntegerRef::New(const EcmaVM *vm, int input) { JSThread *thread = vm->GetJSThread(); JSHandle integer(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(integer); } Local IntegerRef::NewFromUnsigned(const EcmaVM *vm, unsigned int input) { JSThread *thread = vm->GetJSThread(); JSHandle integer(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(integer); } int IntegerRef::Value() { return JSNApiHelper::ToJSTaggedValue(this).GetInt(); } // ----------------------------------- StringRef ---------------------------------------- Local StringRef::NewFromUtf8(const EcmaVM *vm, const char *utf8, int length) { ObjectFactory *factory = vm->GetFactory(); if (length < 0) { JSHandle current(factory->NewFromString(utf8)); return JSNApiHelper::ToLocal(current); } JSHandle current(factory->NewFromUtf8(reinterpret_cast(utf8), length)); return JSNApiHelper::ToLocal(current); } std::string StringRef::ToString() { return StringHelper::ToStdString(EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject())); } int32_t StringRef::Length() { return EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject())->GetLength(); } int32_t StringRef::Utf8Length() { return EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject())->GetUtf8Length(); } int StringRef::WriteUtf8(char *buffer, int length) { return EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject()) ->CopyDataUtf8(reinterpret_cast(buffer), length); } // ----------------------------------- SymbolRef ----------------------------------------- Local SymbolRef::New(const EcmaVM *vm, Local description) { ObjectFactory *factory = vm->GetFactory(); JSHandle symbol = factory->NewJSSymbol(); JSTaggedValue desc = JSNApiHelper::ToJSTaggedValue(*description); symbol->SetDescription(vm->GetJSThread(), desc); return JSNApiHelper::ToLocal(JSHandle(symbol)); } Local SymbolRef::GetDescription(const EcmaVM *vm) { JSTaggedValue description = JSSymbol::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject())->GetDescription(); if (!description.IsString()) { auto constants = vm->GetJSThread()->GlobalConstants(); return JSNApiHelper::ToLocal(constants->GetHandledEmptyString()); } JSHandle descriptionHandle(vm->GetJSThread(), description); return JSNApiHelper::ToLocal(descriptionHandle); } // -------------------------------- NativePointerRef ------------------------------------ Local NativePointerRef::New(const EcmaVM *vm, void *nativePointer) { ObjectFactory *factory = vm->GetFactory(); JSHandle obj = factory->NewJSNativePointer(nativePointer); return JSNApiHelper::ToLocal(JSHandle(obj)); } Local NativePointerRef::New( const EcmaVM *vm, void *nativePointer, NativePointerCallback callBack, void *data) { ObjectFactory *factory = vm->GetFactory(); JSHandle obj = factory->NewJSNativePointer(nativePointer, callBack, data); return JSNApiHelper::ToLocal(JSHandle(obj)); } void *NativePointerRef::Value() { JSHandle nativePointer = JSNApiHelper::ToJSHandle(this); return JSHandle(nativePointer)->GetExternalPointer(); } // ----------------------------------- ObjectRef ---------------------------------------- Local ObjectRef::New(const EcmaVM *vm) { ObjectFactory *factory = vm->GetFactory(); JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle constructor = globalEnv->GetObjectFunction(); JSHandle object(factory->NewJSObjectByConstructor(JSHandle(constructor), constructor)); RETURN_VALUE_IF_ABRUPT(vm->GetJSThread(), JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(object); } bool ObjectRef::Set(const EcmaVM *vm, Local key, Local value) { JSHandle obj = JSNApiHelper::ToJSHandle(this); JSHandle keyValue = JSNApiHelper::ToJSHandle(key); JSHandle valueValue = JSNApiHelper::ToJSHandle(value); bool result = JSTaggedValue::SetProperty(vm->GetJSThread(), obj, keyValue, valueValue); RETURN_VALUE_IF_ABRUPT(vm->GetJSThread(), false); return result; } bool ObjectRef::Set(const EcmaVM *vm, uint32_t key, Local value) { Local keyValue = NumberRef::New(vm, key); return Set(vm, keyValue, value); } bool ObjectRef::SetAccessorProperty(const EcmaVM *vm, Local key, Local getter, Local setter, PropertyAttribute attribute) { JSThread *thread = vm->GetJSThread(); JSHandle getterValue = JSNApiHelper::ToJSHandle(getter); JSHandle setterValue = JSNApiHelper::ToJSHandle(setter); PropertyDescriptor desc(thread, attribute.IsWritable(), attribute.IsEnumerable(), attribute.IsConfigurable()); desc.SetValue(JSNApiHelper::ToJSHandle(attribute.GetValue(vm))); desc.SetSetter(setterValue); desc.SetGetter(getterValue); JSHandle obj = JSNApiHelper::ToJSHandle(this); JSHandle keyValue = JSNApiHelper::ToJSHandle(key); bool result = JSTaggedValue::DefineOwnProperty(thread, obj, keyValue, desc); RETURN_VALUE_IF_ABRUPT(thread, false); return result; } Local ObjectRef::Get(const EcmaVM *vm, Local key) { JSThread *thread = vm->GetJSThread(); JSHandle obj = JSNApiHelper::ToJSHandle(this); JSHandle keyValue = JSNApiHelper::ToJSHandle(key); OperationResult ret = JSTaggedValue::GetProperty(thread, obj, keyValue); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); if (!ret.GetPropertyMetaData().IsFound()) { return JSValueRef::Undefined(vm); } return JSNApiHelper::ToLocal(ret.GetValue()); } Local ObjectRef::Get(const EcmaVM *vm, int32_t key) { Local keyValue = IntegerRef::New(vm, key); return Get(vm, keyValue); } bool ObjectRef::GetOwnProperty(const EcmaVM *vm, Local key, PropertyAttribute &property) { JSThread *thread = vm->GetJSThread(); JSHandle obj = JSNApiHelper::ToJSHandle(this); JSHandle keyValue = JSNApiHelper::ToJSHandle(key); PropertyDescriptor desc(thread); bool ret = JSObject::GetOwnProperty(thread, JSHandle(obj), keyValue, desc); if (!ret) { return false; } property.SetValue(JSNApiHelper::ToLocal(desc.GetValue())); if (desc.HasGetter()) { property.SetGetter(JSNApiHelper::ToLocal(desc.GetGetter())); } if (desc.HasSetter()) { property.SetSetter(JSNApiHelper::ToLocal(desc.GetSetter())); } if (desc.HasWritable()) { property.SetWritable(desc.IsWritable()); } if (desc.HasEnumerable()) { property.SetEnumerable(desc.IsEnumerable()); } if (desc.HasConfigurable()) { property.SetConfigurable(desc.IsConfigurable()); } return true; } Local ObjectRef::GetOwnPropertyNames(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle obj(JSNApiHelper::ToJSHandle(this)); JSHandle array(JSTaggedValue::GetOwnPropertyKeys(thread, obj)); JSHandle jsArray(JSArray::CreateArrayFromList(thread, array)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(jsArray); } Local ObjectRef::GetOwnEnumerablePropertyNames(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle obj(JSNApiHelper::ToJSHandle(this)); JSHandle array(JSObject::EnumerableOwnNames(thread, obj)); JSHandle jsArray(JSArray::CreateArrayFromList(thread, array)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(jsArray); } Local ObjectRef::GetPrototype(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle object(JSNApiHelper::ToJSHandle(this)); JSHandle prototype(thread, object->GetPrototype(thread)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(prototype); } bool ObjectRef::DefineProperty(const EcmaVM *vm, Local key, PropertyAttribute attribute) { JSThread *thread = vm->GetJSThread(); JSHandle object(JSNApiHelper::ToJSHandle(this)); JSHandle keyValue(JSNApiHelper::ToJSHandle(key)); PropertyDescriptor desc(thread, attribute.IsWritable(), attribute.IsEnumerable(), attribute.IsConfigurable()); desc.SetValue(JSNApiHelper::ToJSHandle(attribute.GetValue(vm))); bool result = object->DefinePropertyOrThrow(thread, object, keyValue, desc); RETURN_VALUE_IF_ABRUPT(thread, false); return result; } bool ObjectRef::Has(const EcmaVM *vm, Local key) { JSThread *thread = vm->GetJSThread(); JSHandle object(JSNApiHelper::ToJSHandle(this)); JSHandle keyValue(JSNApiHelper::ToJSHandle(key)); bool result = object->HasProperty(thread, object, keyValue); RETURN_VALUE_IF_ABRUPT(thread, false); return result; } bool ObjectRef::Has(const EcmaVM *vm, uint32_t key) { JSThread *thread = vm->GetJSThread(); JSHandle object(JSNApiHelper::ToJSHandle(this)); bool result = object->HasProperty(thread, object, key); RETURN_VALUE_IF_ABRUPT(thread, false); return result; } bool ObjectRef::Delete(const EcmaVM *vm, Local key) { JSThread *thread = vm->GetJSThread(); JSHandle object(JSNApiHelper::ToJSHandle(this)); JSHandle keyValue(JSNApiHelper::ToJSHandle(key)); bool result = object->DeleteProperty(thread, object, keyValue); RETURN_VALUE_IF_ABRUPT(thread, false); return result; } bool ObjectRef::Delete(const EcmaVM *vm, uint32_t key) { JSThread *thread = vm->GetJSThread(); JSHandle object(JSNApiHelper::ToJSHandle(this)); JSHandle keyHandle(thread, JSTaggedValue(key)); bool result = object->DeleteProperty(thread, object, keyHandle); RETURN_VALUE_IF_ABRUPT(thread, false); return result; } void ObjectRef::SetNativePointerFieldCount(int32_t count) { JSHandle object(JSNApiHelper::ToJSHandle(this)); object->SetNativePointerFieldCount(count); } int32_t ObjectRef::GetNativePointerFieldCount() { JSHandle object(JSNApiHelper::ToJSHandle(this)); return object->GetNativePointerFieldCount(); } void *ObjectRef::GetNativePointerField(int32_t index) { JSHandle object(JSNApiHelper::ToJSHandle(this)); return object->GetNativePointerField(index); } void ObjectRef::SetNativePointerField(int32_t index, void *nativePointer, NativePointerCallback callBack, void *data) { JSHandle object(JSNApiHelper::ToJSHandle(this)); object->SetNativePointerField(index, nativePointer, callBack, data); } // ----------------------------------- FunctionRef -------------------------------------- Local FunctionRef::New(EcmaVM *vm, FunctionCallback nativeFunc, void *data) { JSThread *thread = vm->GetJSThread(); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle current(factory->NewJSFunction(env, reinterpret_cast(Callback::RegisterCallback))); JSHandle funcCallback = factory->NewJSNativePointer(reinterpret_cast(nativeFunc)); JSHandle dataCaddress = factory->NewJSNativePointer(data); JSHandle extraInfo(factory->NewFunctionExtraInfo(funcCallback, dataCaddress)); current->SetFunctionExtraInfo(thread, extraInfo.GetTaggedValue()); return JSNApiHelper::ToLocal(JSHandle(current)); } Local FunctionRef::New(EcmaVM *vm, FunctionCallback nativeFunc, Deleter deleter, void *data) { JSThread *thread = vm->GetJSThread(); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle current(factory->NewJSFunction(env, reinterpret_cast(Callback::RegisterCallback))); JSHandle funcCallback = factory->NewJSNativePointer(reinterpret_cast(nativeFunc)); JSHandle dataCaddress = factory->NewJSNativePointer(data, deleter, nullptr); vm->PushToArrayDataList(*dataCaddress); JSHandle extraInfo(factory->NewFunctionExtraInfo(funcCallback, dataCaddress)); current->SetFunctionExtraInfo(thread, extraInfo.GetTaggedValue()); return JSNApiHelper::ToLocal(JSHandle(current)); } Local FunctionRef::NewWithProperty(EcmaVM *vm, FunctionCallback nativeFunc, void *data) { JSThread *thread = vm->GetJSThread(); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle current = factory->NewJSFunction(env, reinterpret_cast(Callback::RegisterCallbackWithProperty)); JSHandle funcCallback = factory->NewJSNativePointer(reinterpret_cast(nativeFunc)); JSHandle dataCaddress = factory->NewJSNativePointer(data); JSHandle extraInfo(factory->NewFunctionExtraInfo(funcCallback, dataCaddress)); current->SetFunctionExtraInfo(thread, extraInfo.GetTaggedValue()); return JSNApiHelper::ToLocal(JSHandle(current)); } Local FunctionRef::NewClassFunction(EcmaVM *vm, FunctionCallbackWithNewTarget nativeFunc, Deleter deleter, void *data) { JSThread *thread = vm->GetJSThread(); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle dynclass = JSHandle::Cast(env->GetFunctionClassWithoutName()); JSMethod *method = vm->GetMethodForNativeFunction(reinterpret_cast(Callback::RegisterCallbackWithNewTarget)); JSHandle current = factory->NewJSFunctionByDynClass(method, dynclass, ecmascript::FunctionKind::CLASS_CONSTRUCTOR); JSHandle funcCallback = factory->NewJSNativePointer(reinterpret_cast(nativeFunc)); JSHandle dataCaddress(thread, JSTaggedValue::Undefined()); if (deleter == nullptr) { dataCaddress = factory->NewJSNativePointer(data); } else { dataCaddress = factory->NewJSNativePointer(data, deleter, nullptr); vm->PushToArrayDataList(*dataCaddress); } JSHandle extraInfo(factory->NewFunctionExtraInfo(funcCallback, dataCaddress)); current->SetFunctionExtraInfo(thread, extraInfo.GetTaggedValue()); JSHandle clsPrototype = JSObject::ObjectCreate(thread, JSHandle(env->GetObjectFunctionPrototype())); clsPrototype.GetTaggedValue().GetTaggedObject()->GetClass()->SetClassPrototype(true); JSHandle::Cast(current)->GetTaggedObject()->GetClass()->SetClassConstructor(true); current->SetClassConstructor(thread, true); JSHandle parent = env->GetFunctionPrototype(); JSObject::SetPrototype(thread, JSHandle::Cast(current), parent); JSFunction::MakeClassConstructor(thread, JSHandle::Cast(current), clsPrototype); return JSNApiHelper::ToLocal(JSHandle(current)); } Local FunctionRef::Call(const EcmaVM *vm, Local thisObj, const Local argv[], // NOLINTNEXTLINE(modernize-avoid-c-arrays) int32_t length) { JSThread *thread = vm->GetJSThread(); if (!IsFunction()) { return JSValueRef::Undefined(vm); } JSHandle func = JSNApiHelper::ToJSHandle(this); JSHandle thisValue = JSNApiHelper::ToJSHandle(thisObj); ObjectFactory *factory = vm->GetFactory(); JSHandle arguments = factory->NewTaggedArray(length); Span> sp(argv, length); for (int i = 0; i < length; ++i) { arguments->Set(thread, i, JSNApiHelper::ToJSHandle(sp[i])); } InternalCallParams *args = thread->GetInternalCallParams(); args->MakeArgList(*arguments); JSTaggedValue result = JSFunction::Call(thread, func, thisValue, arguments->GetLength(), args->GetArgv()); RETURN_VALUE_IF_ABRUPT_NOT_CLEAR_EXCEPTION(thread, JSValueRef::Exception(vm)); JSHandle resultValue(thread, result); vm->ExecutePromisePendingJob(); RETURN_VALUE_IF_ABRUPT_NOT_CLEAR_EXCEPTION(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(resultValue); } Local FunctionRef::Constructor(const EcmaVM *vm, const Local argv[], // NOLINTNEXTLINE(modernize-avoid-c-arrays) int32_t length) { JSThread *thread = vm->GetJSThread(); if (!IsFunction()) { return JSValueRef::Undefined(vm); } JSHandle func = JSNApiHelper::ToJSHandle(this); JSHandle newTarget = func; ObjectFactory *factory = vm->GetFactory(); JSHandle arguments = factory->NewTaggedArray(length); Span> sp(argv, length); for (int i = 0; i < length; ++i) { arguments->Set(thread, i, JSNApiHelper::ToJSHandle(sp[i])); } ecmascript::InternalCallParams *params = thread->GetInternalCallParams(); params->MakeArgList(*arguments); JSTaggedValue result = JSFunction::Construct(thread, func, length, params->GetArgv(), newTarget); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); JSHandle resultValue(vm->GetJSThread(), result); return JSNApiHelper::ToLocal(resultValue); } Local FunctionRef::GetFunctionPrototype(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle func = JSNApiHelper::ToJSHandle(this); JSHandle prototype(thread, JSHandle(func)->GetFunctionPrototype()); return JSNApiHelper::ToLocal(prototype); } void FunctionRef::SetName(const EcmaVM *vm, Local name) { JSThread *thread = vm->GetJSThread(); JSFunction *func = JSFunction::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject()); JSTaggedValue key = JSNApiHelper::ToJSTaggedValue(*name); JSFunction::SetFunctionNameNoPrefix(thread, func, key); } Local FunctionRef::GetName(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle func = JSHandle(thread, JSNApiHelper::ToJSTaggedValue(this)); JSHandle name = JSFunctionBase::GetFunctionName(thread, func); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(name); } bool FunctionRef::IsNative(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle func = JSHandle(thread, JSNApiHelper::ToJSTaggedValue(this)); JSMethod *method = func->GetMethod(); return method->IsNative(); } // ----------------------------------- ArrayRef ---------------------------------------- Local ArrayRef::New(const EcmaVM *vm, int32_t length) { JSThread *thread = vm->GetJSThread(); JSTaggedNumber arrayLen(length); JSHandle array = JSArray::ArrayCreate(thread, arrayLen); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(array); } int32_t ArrayRef::Length([[maybe_unused]] const EcmaVM *vm) { return JSArray::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject())->GetArrayLength(); } Local ArrayRef::GetValueAt(const EcmaVM *vm, Local obj, uint32_t index) { JSThread *thread = vm->GetJSThread(); JSHandle object = JSNApiHelper::ToJSHandle(obj); JSHandle result = JSArray::FastGetPropertyByValue(thread, object, index); return JSNApiHelper::ToLocal(result); } bool ArrayRef::SetValueAt(const EcmaVM *vm, Local obj, uint32_t index, Local value) { JSThread *thread = vm->GetJSThread(); JSHandle objectHandle = JSNApiHelper::ToJSHandle(obj); JSHandle valueHandle = JSNApiHelper::ToJSHandle(value); return JSArray::FastSetPropertyByValue(thread, objectHandle, index, valueHandle); } // ---------------------------------- Promise -------------------------------------- Local PromiseCapabilityRef::New(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle constructor(globalEnv->GetPromiseFunction()); JSHandle capability(JSPromise::NewPromiseCapability(thread, constructor)); return JSNApiHelper::ToLocal(capability); } Local PromiseCapabilityRef::GetPromise(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle capacity(JSNApiHelper::ToJSHandle(this)); return JSNApiHelper::ToLocal(JSHandle(thread, capacity->GetPromise())); } bool PromiseCapabilityRef::Resolve(const EcmaVM *vm, Local value) { JSThread *thread = vm->GetJSThread(); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle arg = JSNApiHelper::ToJSHandle(value); JSHandle capacity(JSNApiHelper::ToJSHandle(this)); JSHandle resolve(thread, capacity->GetResolve()); JSHandle undefined(thread, constants->GetUndefined()); InternalCallParams *arguments = thread->GetInternalCallParams(); arguments->MakeArgv(arg); JSFunction::Call(thread, resolve, undefined, 1, arguments->GetArgv()); RETURN_VALUE_IF_ABRUPT(thread, false); return true; } bool PromiseCapabilityRef::Reject(const EcmaVM *vm, Local reason) { JSThread *thread = vm->GetJSThread(); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle arg = JSNApiHelper::ToJSHandle(reason); JSHandle capacity(JSNApiHelper::ToJSHandle(this)); JSHandle reject(thread, capacity->GetReject()); JSHandle undefined(thread, constants->GetUndefined()); InternalCallParams *arguments = thread->GetInternalCallParams(); arguments->MakeArgv(arg); JSFunction::Call(thread, reject, undefined, 1, arguments->GetArgv()); RETURN_VALUE_IF_ABRUPT(thread, false); return true; } Local PromiseRef::Catch(const EcmaVM *vm, Local handler) { JSThread *thread = vm->GetJSThread(); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle promise = JSNApiHelper::ToJSHandle(this); JSHandle catchKey(thread, constants->GetPromiseCatchString()); JSHandle reject = JSNApiHelper::ToJSHandle(handler); ecmascript::InternalCallParams *arguments = thread->GetInternalCallParams(); arguments->MakeArgv(reject); JSTaggedValue result = JSFunction::Invoke(thread, promise, catchKey, 1, arguments->GetArgv()); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(JSHandle(thread, result)); } Local PromiseRef::Then(const EcmaVM *vm, Local handler) { JSThread *thread = vm->GetJSThread(); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle promise = JSNApiHelper::ToJSHandle(this); JSHandle thenKey(thread, constants->GetPromiseThenString()); JSHandle resolver = JSNApiHelper::ToJSHandle(handler); ecmascript::InternalCallParams *arguments = thread->GetInternalCallParams(); arguments->MakeArgv(resolver.GetTaggedValue(), constants->GetUndefined()); JSTaggedValue result = JSFunction::Invoke(thread, promise, thenKey, 2, arguments->GetArgv()); // 2: two args RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(JSHandle(thread, result)); } Local PromiseRef::Then(const EcmaVM *vm, Local onFulfilled, Local onRejected) { JSThread *thread = vm->GetJSThread(); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle promise = JSNApiHelper::ToJSHandle(this); JSHandle thenKey(thread, constants->GetPromiseThenString()); JSHandle resolver = JSNApiHelper::ToJSHandle(onFulfilled); JSHandle reject = JSNApiHelper::ToJSHandle(onRejected); ecmascript::InternalCallParams *arguments = thread->GetInternalCallParams(); arguments->MakeArgv(resolver, reject); JSTaggedValue result = JSFunction::Invoke(thread, promise, thenKey, 2, arguments->GetArgv()); // 2: two args RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(JSHandle(thread, result)); } // ---------------------------------- Promise ------------------------------------- // ---------------------------------- Buffer ----------------------------------- Local ArrayBufferRef::New(const EcmaVM *vm, int32_t length) { JSThread *thread = vm->GetJSThread(); ObjectFactory *factory = vm->GetFactory(); JSHandle arrayBuffer = factory->NewJSArrayBuffer(length); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(JSHandle(arrayBuffer)); } Local ArrayBufferRef::New( const EcmaVM *vm, void *buffer, int32_t length, const Deleter &deleter, void *data) { JSThread *thread = vm->GetJSThread(); ObjectFactory *factory = vm->GetFactory(); JSHandle arrayBuffer = factory->NewJSArrayBuffer(buffer, length, reinterpret_cast(deleter), data); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(JSHandle(arrayBuffer)); } int32_t ArrayBufferRef::ByteLength(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); JSHandle length(thread, arrayBuffer->GetArrayBufferByteLength()); if (!length->IsNumber()) { return 0; } return length->GetNumber(); } void *ArrayBufferRef::GetBuffer() { JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); JSTaggedValue bufferData = arrayBuffer->GetArrayBufferData(); if (!bufferData.IsJSNativePointer()) { return nullptr; } return JSNativePointer::Cast(bufferData.GetTaggedObject())->GetExternalPointer(); } // ---------------------------------- Buffer ----------------------------------- // ---------------------------------- DataView ----------------------------------- Local DataViewRef::New( const EcmaVM *vm, Local arrayBuffer, int32_t byteOffset, int32_t byteLength) { JSThread *thread = vm->GetJSThread(); ObjectFactory *factory = vm->GetFactory(); JSHandle buffer(JSNApiHelper::ToJSHandle(arrayBuffer)); JSHandle dataView = factory->NewJSDataView(buffer, byteOffset, byteLength); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(JSHandle(dataView)); } int32_t DataViewRef::ByteLength() { JSHandle dataView(JSNApiHelper::ToJSHandle(this)); JSTaggedValue length = dataView->GetByteLength(); if (!length.IsNumber()) { return 0; } return length.GetNumber(); } int32_t DataViewRef::ByteOffset() { JSHandle dataView(JSNApiHelper::ToJSHandle(this)); JSTaggedValue offset = dataView->GetByteOffset(); if (!offset.IsNumber()) { return 0; } return offset.GetNumber(); } Local DataViewRef::GetArrayBuffer(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle dataView(JSNApiHelper::ToJSHandle(this)); JSHandle arrayBuffer(thread, dataView->GetViewedArrayBuffer()); return JSNApiHelper::ToLocal(arrayBuffer); } // ---------------------------------- DataView ----------------------------------- // ---------------------------------- TypedArray ----------------------------------- int32_t TypedArrayRef::ByteLength(const EcmaVM *vm) { JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); JSTaggedValue length = typedArray->GetByteLength(); if (!length.IsNumber()) { return 0; } return length.GetNumber(); } int32_t TypedArrayRef::ByteOffset(const EcmaVM *vm) { JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); JSTaggedValue length = typedArray->GetByteOffset(); if (!length.IsNumber()) { return 0; } return length.GetNumber(); } int32_t TypedArrayRef::ArrayLength(const EcmaVM *vm) { JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); JSTaggedValue length = typedArray->GetArrayLength(); if (!length.IsNumber()) { return 0; } return length.GetNumber(); } Local TypedArrayRef::GetArrayBuffer(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle typeArray(JSNApiHelper::ToJSHandle(this)); JSHandle arrayBuffer(thread, JSTypedArray::Cast(*typeArray)->GetViewedArrayBuffer()); return JSNApiHelper::ToLocal(arrayBuffer); } // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define TYPED_ARRAY_NEW(Type) \ Local Type##Ref::New( \ const EcmaVM *vm, Local buffer, int32_t byteOffset, int32_t length) \ { \ JSThread *thread = vm->GetJSThread(); \ JSHandle env = vm->GetGlobalEnv(); \ \ JSHandle func = env->Get##Type##Function(); \ JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(buffer)); \ ecmascript::InternalCallParams *argv = thread->GetInternalCallParams(); \ argv->MakeArgv(arrayBuffer.GetTaggedValue(), JSTaggedValue(byteOffset), JSTaggedValue(length)); \ array_size_t argc = 3; \ JSTaggedValue result = JSFunction::Construct(thread, func, argc, argv->GetArgv(), func); \ RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); \ JSHandle resultHandle(thread, result); \ return JSNApiHelper::ToLocal(resultHandle); \ } TYPED_ARRAY_ALL(TYPED_ARRAY_NEW) #undef TYPED_ARRAY_NEW // ---------------------------------- TypedArray ----------------------------------- // ---------------------------------- Error --------------------------------------- // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define EXCEPTION_ERROR_NEW(name, type) \ Local Exception::name(const EcmaVM *vm, Local message) \ { \ JSThread *thread = vm->GetJSThread(); \ ObjectFactory *factory = vm->GetFactory(); \ \ JSHandle messageValue(JSNApiHelper::ToJSHandle(message)); \ JSHandle result(factory->NewJSError(ErrorType::type, messageValue)); \ RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); \ return JSNApiHelper::ToLocal(result); \ } EXCEPTION_ERROR_ALL(EXCEPTION_ERROR_NEW) #undef EXCEPTION_ERROR_NEW // ---------------------------------- Error --------------------------------------- // ---------------------------------- JSON ------------------------------------------ Local JSON::Parse(const EcmaVM *vm, Local string) { JSThread *thread = vm->GetJSThread(); auto ecmaStr = EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(*string).GetTaggedObject()); JSHandle result; if (ecmaStr->IsUtf8()) { JsonParser parser(thread); result = parser.ParseUtf8(EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(*string).GetTaggedObject())); } else { JsonParser parser(thread); result = parser.ParseUtf16(EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(*string).GetTaggedObject())); } RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(result); } Local JSON::Stringify(const EcmaVM *vm, Local json) { JSThread *thread = vm->GetJSThread(); auto constants = thread->GlobalConstants(); JsonStringifier stringifier(thread); JSHandle str = stringifier.Stringify( JSNApiHelper::ToJSHandle(json), constants->GetHandledUndefined(), constants->GetHandledUndefined()); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(str); } Local RegExpRef::GetOriginalSource(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle regExp(JSNApiHelper::ToJSHandle(this)); JSTaggedValue source = regExp->GetOriginalSource(); if (!source.IsString()) { auto constants = thread->GlobalConstants(); return JSNApiHelper::ToLocal(constants->GetHandledEmptyString()); } JSHandle sourceHandle(thread, source); return JSNApiHelper::ToLocal(sourceHandle); } Local DateRef::ToString(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle date(JSNApiHelper::ToJSHandle(this)); JSTaggedValue dateStr = date->ToString(thread); if (!dateStr.IsString()) { auto constants = thread->GlobalConstants(); return JSNApiHelper::ToLocal(constants->GetHandledEmptyString()); } JSHandle dateStrHandle(thread, dateStr); return JSNApiHelper::ToLocal(dateStrHandle); } int32_t MapRef::GetSize() { JSHandle map(JSNApiHelper::ToJSHandle(this)); return map->GetSize(); } int32_t SetRef::GetSize() { JSHandle set(JSNApiHelper::ToJSHandle(this)); return set->GetSize(); } // ----------------------------------- FunctionCallback --------------------------------- JSTaggedValue Callback::RegisterCallback(ecmascript::EcmaRuntimeCallInfo *info) { // Constructor JSThread *thread = info->GetThread(); JSHandle constructor = BuiltinsBase::GetConstructor(info); if (!constructor->IsJSFunction()) { return JSTaggedValue::False(); } JSHandle function(constructor); JSHandle extraInfoValue(thread, function->GetFunctionExtraInfo()); if (!extraInfoValue->IsJSFunctionExtraInfo()) { return JSTaggedValue::False(); } JSHandle extraInfo(extraInfoValue); // vm Region *region = Region::ObjectAddressToRange(extraInfo.GetTaggedValue().GetTaggedObject()); if (region == nullptr) { return JSTaggedValue::False(); } EcmaVM *vm = region->GetSpace()->GetHeap()->GetEcmaVM(); // data JSHandle data(thread, extraInfo->GetData()); if (!data->IsHeapObject()) { return JSTaggedValue::False(); } JSHandle dataObj(data); // callBack JSHandle callBack(thread, extraInfo->GetCallback()); if (!callBack->IsHeapObject()) { return JSTaggedValue::False(); } JSHandle callBackObj(callBack); FunctionCallback nativeFunc = (reinterpret_cast(callBackObj->GetExternalPointer())); // this JSHandle thisValue(BuiltinsBase::GetThis(info)); // arguments std::vector> arguments; array_size_t length = info->GetArgsNumber(); for (array_size_t i = 0; i < length; ++i) { arguments.emplace_back(JSNApiHelper::ToLocal(BuiltinsBase::GetCallArg(info, i))); } Local result = nativeFunc(vm, JSNApiHelper::ToLocal(thisValue), arguments.data(), arguments.size(), dataObj->GetExternalPointer()); return JSNApiHelper::ToJSHandle(result).GetTaggedValue(); } JSTaggedValue Callback::RegisterCallbackWithProperty(ecmascript::EcmaRuntimeCallInfo *info) { // Constructor JSThread *thread = info->GetThread(); JSHandle constructor = BuiltinsBase::GetConstructor(info); if (!constructor->IsJSFunction()) { return JSTaggedValue::False(); } JSHandle function(constructor); JSHandle extraInfoValue(thread, function->GetFunctionExtraInfo()); if (!extraInfoValue->IsJSFunctionExtraInfo()) { return JSTaggedValue::False(); } JSHandle extraInfo(extraInfoValue); // vm Region *region = Region::ObjectAddressToRange(extraInfo.GetTaggedValue().GetTaggedObject()); if (region == nullptr) { return JSTaggedValue::False(); } EcmaVM *vm = region->GetSpace()->GetHeap()->GetEcmaVM(); // data JSHandle data(thread, extraInfo->GetData()); if (!data->IsHeapObject()) { return JSTaggedValue::False(); } JSHandle dataObj(data); // callBack JSHandle callBack(thread, extraInfo->GetCallback()); if (!callBack->IsHeapObject()) { return JSTaggedValue::False(); } JSHandle callBackObj(callBack); FunctionCallback nativeFunc = (reinterpret_cast(callBackObj->GetExternalPointer())); // constructor JSHandle thisValue(BuiltinsBase::GetConstructor(info)); // arguments std::vector> arguments; array_size_t length = info->GetArgsNumber(); for (array_size_t i = 0; i < length; ++i) { arguments.emplace_back(JSNApiHelper::ToLocal(BuiltinsBase::GetCallArg(info, i))); } Local result = nativeFunc(vm, JSNApiHelper::ToLocal(thisValue), arguments.data(), arguments.size(), dataObj->GetExternalPointer()); return JSNApiHelper::ToJSHandle(result).GetTaggedValue(); } JSTaggedValue Callback::RegisterCallbackWithNewTarget(ecmascript::EcmaRuntimeCallInfo *info) { // Constructor JSThread *thread = info->GetThread(); JSHandle constructor = BuiltinsBase::GetConstructor(info); if (!constructor->IsJSFunction()) { return JSTaggedValue::False(); } JSHandle function(constructor); JSHandle extraInfoValue(thread, function->GetFunctionExtraInfo()); if (!extraInfoValue->IsJSFunctionExtraInfo()) { return JSTaggedValue::False(); } JSHandle extraInfo(extraInfoValue); // vm Region *region = Region::ObjectAddressToRange(extraInfo.GetTaggedValue().GetTaggedObject()); if (region == nullptr) { return JSTaggedValue::False(); } EcmaVM *vm = region->GetSpace()->GetHeap()->GetEcmaVM(); // data JSHandle data(thread, extraInfo->GetData()); if (!data->IsHeapObject()) { return JSTaggedValue::False(); } JSHandle dataObj(data); // callBack JSHandle callBack(thread, extraInfo->GetCallback()); if (!callBack->IsHeapObject()) { return JSTaggedValue::False(); } JSHandle callBackObj(callBack); FunctionCallbackWithNewTarget nativeFunc = (reinterpret_cast(callBackObj->GetExternalPointer())); // newTarget JSHandle newTarget(BuiltinsBase::GetNewTarget(info)); // this JSHandle thisValue(BuiltinsBase::GetThis(info)); // arguments std::vector> arguments; array_size_t length = info->GetArgsNumber(); for (array_size_t i = 0; i < length; ++i) { arguments.emplace_back(JSNApiHelper::ToLocal(BuiltinsBase::GetCallArg(info, i))); } Local result = nativeFunc(vm, JSNApiHelper::ToLocal(thisValue), JSNApiHelper::ToLocal(newTarget), arguments.data(), arguments.size(), dataObj->GetExternalPointer()); return JSNApiHelper::ToJSHandle(result).GetTaggedValue(); } // ------------------------------------- JSExecutionScope ------------------------------ JSExecutionScope::JSExecutionScope(const EcmaVM *vm) { (void)vm; } JSExecutionScope::~JSExecutionScope() { last_current_thread_ = nullptr; is_revert_ = false; } // ----------------------------------- JSValueRef -------------------------------------- Local JSValueRef::Undefined(const EcmaVM *vm) { return JSNApiHelper::ToLocal(JSHandle(vm->GetJSThread(), JSTaggedValue::Undefined())); } Local JSValueRef::Null(const EcmaVM *vm) { return JSNApiHelper::ToLocal(JSHandle(vm->GetJSThread(), JSTaggedValue::Null())); } Local JSValueRef::True(const EcmaVM *vm) { return JSNApiHelper::ToLocal(JSHandle(vm->GetJSThread(), JSTaggedValue::True())); } Local JSValueRef::False(const EcmaVM *vm) { return JSNApiHelper::ToLocal(JSHandle(vm->GetJSThread(), JSTaggedValue::False())); } Local JSValueRef::Exception(const EcmaVM *vm) { return JSNApiHelper::ToLocal(JSHandle(vm->GetJSThread(), JSTaggedValue::Exception())); } Local JSValueRef::ToObject(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); if (IsUndefined() || IsNull()) { return Exception(vm); } JSHandle obj(JSTaggedValue::ToObject(thread, JSNApiHelper::ToJSHandle(this))); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(obj); } Local JSValueRef::ToString(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle obj = JSNApiHelper::ToJSHandle(this); if (!obj->IsString()) { obj = JSHandle(JSTaggedValue::ToString(thread, obj)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); } return JSNApiHelper::ToLocal(obj); } Local JSValueRef::ToNativePointer(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle obj = JSNApiHelper::ToJSHandle(this); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(obj); } bool JSValueRef::BooleaValue() { return JSNApiHelper::ToJSTaggedValue(this).ToBoolean(); } int64_t JSValueRef::IntegerValue(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSTaggedNumber number = JSTaggedValue::ToInteger(thread, JSNApiHelper::ToJSHandle(this)); RETURN_VALUE_IF_ABRUPT(thread, 0); return number.GetNumber(); } uint32_t JSValueRef::Uint32Value(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); uint32_t number = JSTaggedValue::ToUint32(thread, JSNApiHelper::ToJSHandle(this)); RETURN_VALUE_IF_ABRUPT(thread, 0); return number; } int32_t JSValueRef::Int32Value(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); int32_t number = JSTaggedValue::ToInt32(thread, JSNApiHelper::ToJSHandle(this)); RETURN_VALUE_IF_ABRUPT(thread, 0); return number; } Local JSValueRef::ToBoolean(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle obj = JSNApiHelper::ToJSHandle(this); JSHandle booleanObj = JSHandle(thread, JSTaggedValue(obj->ToBoolean())); return JSNApiHelper::ToLocal(booleanObj); } Local JSValueRef::ToNumber(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle obj = JSNApiHelper::ToJSHandle(this); JSHandle number(thread, JSTaggedValue::ToNumber(thread, obj)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(number); } bool JSValueRef::IsStrictEquals(const EcmaVM *vm, Local value) { JSThread *thread = vm->GetJSThread(); JSHandle xValue = JSNApiHelper::ToJSHandle(this); JSHandle yValue = JSNApiHelper::ToJSHandle(value); return JSTaggedValue::StrictEqual(thread, xValue, yValue); } Local JSValueRef::Typeof(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSTaggedValue value = FastRuntimeStub::FastTypeOf(thread, JSNApiHelper::ToJSTaggedValue(this)); return JSNApiHelper::ToLocal(JSHandle(thread, value)); } bool JSValueRef::InstanceOf(const EcmaVM *vm, Local value) { JSThread *thread = vm->GetJSThread(); JSHandle origin = JSNApiHelper::ToJSHandle(this); JSHandle target = JSNApiHelper::ToJSHandle(value); bool result = JSObject::InstanceOf(thread, origin, target); RETURN_VALUE_IF_ABRUPT(thread, false); return result; } bool JSValueRef::IsUndefined() { return JSNApiHelper::ToJSTaggedValue(this).IsUndefined(); } bool JSValueRef::IsNull() { return JSNApiHelper::ToJSTaggedValue(this).IsNull(); } bool JSValueRef::IsHole() { return JSNApiHelper::ToJSTaggedValue(this).IsHole(); } bool JSValueRef::IsTrue() { return JSNApiHelper::ToJSTaggedValue(this).IsTrue(); } bool JSValueRef::IsFalse() { return JSNApiHelper::ToJSTaggedValue(this).IsFalse(); } bool JSValueRef::IsNumber() { return JSNApiHelper::ToJSTaggedValue(this).IsNumber(); } bool JSValueRef::IsInt() { return JSNApiHelper::ToJSTaggedValue(this).IsInt(); } bool JSValueRef::WithinInt32() { return JSNApiHelper::ToJSTaggedValue(this).WithinInt32(); } bool JSValueRef::IsBoolean() { return JSNApiHelper::ToJSTaggedValue(this).IsBoolean(); } bool JSValueRef::IsString() { return JSNApiHelper::ToJSTaggedValue(this).IsString(); } bool JSValueRef::IsSymbol() { return JSNApiHelper::ToJSTaggedValue(this).IsSymbol(); } bool JSValueRef::IsObject() { return JSNApiHelper::ToJSTaggedValue(this).IsECMAObject(); } bool JSValueRef::IsArray(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); return JSNApiHelper::ToJSTaggedValue(this).IsArray(thread); } bool JSValueRef::IsConstructor() { JSTaggedValue value = JSNApiHelper::ToJSTaggedValue(this); return value.IsHeapObject() && value.IsConstructor(); } bool JSValueRef::IsFunction() { JSTaggedValue value = JSNApiHelper::ToJSTaggedValue(this); return value.IsHeapObject() && value.IsCallable(); } bool JSValueRef::IsProxy() { return JSNApiHelper::ToJSTaggedValue(this).IsJSProxy(); } bool JSValueRef::IsException() { return JSNApiHelper::ToJSTaggedValue(this).IsException(); } bool JSValueRef::IsPromise() { return JSNApiHelper::ToJSTaggedValue(this).IsJSPromise(); } bool JSValueRef::IsDataView() { return JSNApiHelper::ToJSTaggedValue(this).IsDataView(); } bool JSValueRef::IsTypedArray() { return JSNApiHelper::ToJSTaggedValue(this).IsTypedArray(); } bool JSValueRef::IsNativePointer() { return JSNApiHelper::ToJSTaggedValue(this).IsJSNativePointer(); } bool JSValueRef::IsDate() { return JSNApiHelper::ToJSTaggedValue(this).IsDate(); } bool JSValueRef::IsError() { return JSNApiHelper::ToJSTaggedValue(this).IsJSError(); } bool JSValueRef::IsMap() { return JSNApiHelper::ToJSTaggedValue(this).IsJSMap(); } bool JSValueRef::IsSet() { return JSNApiHelper::ToJSTaggedValue(this).IsJSSet(); } bool JSValueRef::IsWeakMap() { return JSNApiHelper::ToJSTaggedValue(this).IsJSWeakMap(); } bool JSValueRef::IsWeakSet() { return JSNApiHelper::ToJSTaggedValue(this).IsJSWeakSet(); } bool JSValueRef::IsRegExp() { return JSNApiHelper::ToJSTaggedValue(this).IsJSRegExp(); } bool JSValueRef::IsArrayIterator() { return JSNApiHelper::ToJSTaggedValue(this).IsJSArrayIterator(); } bool JSValueRef::IsStringIterator() { return JSNApiHelper::ToJSTaggedValue(this).IsStringIterator(); } bool JSValueRef::IsSetIterator() { return JSNApiHelper::ToJSTaggedValue(this).IsJSSetIterator(); } bool JSValueRef::IsMapIterator() { return JSNApiHelper::ToJSTaggedValue(this).IsJSMapIterator(); } bool JSValueRef::IsArrayBuffer() { return JSNApiHelper::ToJSTaggedValue(this).IsArrayBuffer(); } bool JSValueRef::IsUint8Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSUint8Array(); } bool JSValueRef::IsInt8Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSInt8Array(); } bool JSValueRef::IsUint8ClampedArray() { return JSNApiHelper::ToJSTaggedValue(this).IsJSUint8ClampedArray(); } bool JSValueRef::IsInt16Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSInt16Array(); } bool JSValueRef::IsUint16Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSUint16Array(); } bool JSValueRef::IsInt32Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSInt32Array(); } bool JSValueRef::IsUint32Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSUint32Array(); } bool JSValueRef::IsFloat32Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSFloat32Array(); } bool JSValueRef::IsFloat64Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSFloat64Array(); } bool JSValueRef::IsJSPrimitiveRef() { return JSNApiHelper::ToJSTaggedValue(this).IsJSPrimitiveRef(); } bool JSValueRef::IsJSPrimitiveNumber() { JSHandle obj = JSNApiHelper::ToJSHandle(this); return JSPrimitiveRef::Cast(obj->GetHeapObject())->IsNumber(); } bool JSValueRef::IsJSPrimitiveInt() { JSHandle obj = JSNApiHelper::ToJSHandle(this); return JSPrimitiveRef::Cast(obj->GetHeapObject())->IsInt(); } bool JSValueRef::IsJSPrimitiveBoolean() { JSHandle obj = JSNApiHelper::ToJSHandle(this); return JSPrimitiveRef::Cast(obj->GetHeapObject())->IsBoolean(); } bool JSValueRef::IsJSPrimitiveString() { JSHandle obj = JSNApiHelper::ToJSHandle(this); return JSPrimitiveRef::Cast(obj->GetHeapObject())->IsString(); } } // namespace panda