/* * Copyright (c) 2021-2023 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 #include #include #include "ecmascript/base/json_stringifier.h" #include "ecmascript/base/typed_array_helper-inl.h" #include "ecmascript/builtins/builtins_object.h" #include "ecmascript/pgo_profiler/pgo_profiler_manager.h" #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h" #endif #include "ecmascript/checkpoint/thread_state_transition.h" #include "ecmascript/ecma_global_storage.h" #include "ecmascript/interpreter/fast_runtime_stub-inl.h" #include "ecmascript/interpreter/interpreter_assembly.h" #include "ecmascript/jsnapi_sendable.h" #include "ecmascript/jspandafile/js_pandafile_executor.h" #include "ecmascript/linked_hash_table.h" #include "ecmascript/module/napi_module_loader.h" #if defined(ENABLE_EXCEPTION_BACKTRACE) #include "ecmascript/platform/backtrace.h" #endif #include "ecmascript/regexp/regexp_parser.h" #include "ecmascript/serializer/base_deserializer.h" #include "ecmascript/serializer/value_serializer.h" #include "ecmascript/ohos/ohos_preload_app_info.h" #include "ecmascript/platform/aot_crash_info.h" #ifdef ARK_SUPPORT_INTL #include "ecmascript/js_bigint.h" #include "ecmascript/js_collator.h" #include "ecmascript/js_date_time_format.h" #include "ecmascript/js_number_format.h" #endif namespace panda { using ecmascript::AccessorData; using ecmascript::BigInt; using ecmascript::ByteArray; using ecmascript::DataViewType; using ecmascript::ECMAObject; using ecmascript::EcmaRuntimeCallInfo; using ecmascript::EcmaString; using ecmascript::EcmaStringAccessor; using ecmascript::ErrorType; using ecmascript::FastRuntimeStub; using ecmascript::GeneratorContext; using ecmascript::GlobalEnv; using ecmascript::GlobalEnvConstants; using ecmascript::IterationKind; using ecmascript::JSArray; using ecmascript::JSArrayBuffer; using ecmascript::JSDataView; using ecmascript::JSDate; using ecmascript::JSFunction; using ecmascript::JSFunctionBase; using ecmascript::JSGeneratorFunction; using ecmascript::JSGeneratorObject; using ecmascript::JSGeneratorState; using ecmascript::JSHClass; using ecmascript::JSIterator; using ecmascript::JSMap; using ecmascript::JSMapIterator; using ecmascript::JSNapiSendable; using ecmascript::JSNativePointer; using ecmascript::JSObject; using ecmascript::JSPandaFile; using ecmascript::JSPandaFileManager; using ecmascript::JSPrimitiveRef; using ecmascript::JSPromise; using ecmascript::JSProxy; using ecmascript::ObjectFastOperator; using ecmascript::JSRegExp; using ecmascript::JSRuntimeOptions; using ecmascript::JSSet; using ecmascript::JSSetIterator; using ecmascript::JSSymbol; using ecmascript::JSTaggedNumber; using ecmascript::JSTaggedType; using ecmascript::JSTaggedValue; using ecmascript::JSThread; using ecmascript::JSTypedArray; using ecmascript::LinkedHashMap; using ecmascript::LinkedHashSet; using ecmascript::LockHolder; using ecmascript::MemMapAllocator; using ecmascript::Method; using ecmascript::NativeModuleFailureInfo; using ecmascript::Mutex; using ecmascript::ObjectFactory; using ecmascript::OperationResult; using ecmascript::PromiseCapability; using ecmascript::PropertyDescriptor; using ecmascript::Region; using ecmascript::TaggedArray; using ecmascript::base::BuiltinsBase; using ecmascript::base::JsonStringifier; using ecmascript::base::StringHelper; using ecmascript::base::TypedArrayHelper; using ecmascript::base::Utf16JsonParser; using ecmascript::base::Utf8JsonParser; using ecmascript::builtins::BuiltinsObject; using ecmascript::job::MicroJobQueue; using ecmascript::job::QueueType; #ifdef ARK_SUPPORT_INTL using ecmascript::JSCollator; using ecmascript::JSDateTimeFormat; using ecmascript::JSNumberFormat; #endif using ecmascript::DebugInfoExtractor; using ecmascript::EcmaContext; using ecmascript::JSWeakMap; using ecmascript::JSWeakSet; using ecmascript::Log; using ecmascript::PatchErrorCode; using ecmascript::RegExpParser; using ecmascript::base::NumberHelper; template using JSHandle = ecmascript::JSHandle; template using JSMutableHandle = ecmascript::JSMutableHandle; using PathHelper = ecmascript::base::PathHelper; using ModulePathHelper = ecmascript::ModulePathHelper; using JsDebuggerManager = ecmascript::tooling::JsDebuggerManager; using FrameIterator = ecmascript::FrameIterator; using Concurrent = ecmascript::Concurrent; using EnableAotJitListHelper = ecmascript::ohos::EnableAotJitListHelper; using PGOProfilerManager = ecmascript::pgo::PGOProfilerManager; using AotRuntimeInfo = ecmascript::ohos::AotRuntimeInfo; namespace { // NOLINTNEXTLINE(fuchsia-statically-constructed-objects) constexpr std::string_view ENTRY_POINTER = "_GLOBAL::func_main_0"; } int JSNApi::vmCount_ = 0; bool JSNApi::initialize_ = false; bool JSNApi::isForked_ = false; static Mutex *mutex = new panda::Mutex(); StartIdleMonitorCallback JSNApi::startIdleMonitorCallback_ = nullptr; // ----------------------------------- JSValueRef -------------------------------------- Local JSValueRef::Undefined(const EcmaVM *vm) { return JSNApiHelper::ToLocal( vm->GetJSThread()->GlobalConstants()->GetHandledUndefined()); } Local JSValueRef::Null(const EcmaVM *vm) { return JSNApiHelper::ToLocal( vm->GetJSThread()->GlobalConstants()->GetHandledNull()); } Local JSValueRef::Hole(const EcmaVM *vm) { return JSNApiHelper::ToLocal( vm->GetJSThread()->GlobalConstants()->GetHandledHole()); } Local JSValueRef::True(const EcmaVM *vm) { return JSNApiHelper::ToLocal( vm->GetJSThread()->GlobalConstants()->GetHandledTrue()); } Local JSValueRef::False(const EcmaVM *vm) { return JSNApiHelper::ToLocal( vm->GetJSThread()->GlobalConstants()->GetHandledFalse()); } Local JSValueRef::ToObject(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); if (IsUndefined() || IsNull()) { return Undefined(vm); } ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj(JSTaggedValue::ToObject(thread, JSNApiHelper::ToJSHandle(this))); LOG_IF_SPECIAL(obj, ERROR); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(obj); } Local JSValueRef::ToEcmaObject(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); if (obj->IsECMAObject()) { RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(obj); } return Undefined(vm); } Local JSValueRef::ToString(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); if (!obj->IsString()) { obj = JSHandle(JSTaggedValue::ToString(thread, obj)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); } return JSNApiHelper::ToLocal(obj); } Local JSValueRef::ToNativePointer(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); // The function just get handle' value, and will not read and write js object. Don't need to switch state. JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); return JSNApiHelper::ToLocal(obj); } bool JSValueRef::BooleaValue(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).ToBoolean(); } int64_t JSValueRef::IntegerValue(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle tagged = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(tagged, ERROR); if (tagged->IsNumber()) { if (!NumberHelper::IsFinite(tagged.GetTaggedValue()) || NumberHelper::IsNaN(tagged.GetTaggedValue())) { return 0; } else { return NumberHelper::DoubleToInt64(tagged->GetNumber()); } } JSTaggedNumber number = JSTaggedValue::ToInteger(thread, tagged); RETURN_VALUE_IF_ABRUPT(thread, 0); return NumberHelper::DoubleToInt64(number.GetNumber()); } uint32_t JSValueRef::Uint32Value(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle tagged = JSNApiHelper::ToJSHandle(this); uint32_t number = 0; if (!tagged->IsECMAObject()) { number = JSTaggedValue::ToUint32(thread, tagged); } else { // EcmaObject may call [Symbol.toPrimitive]. number = JSTaggedValue::ToUint32(thread, tagged); } RETURN_VALUE_IF_ABRUPT(thread, 0); return number; } int32_t JSValueRef::Int32Value(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle tagged = JSNApiHelper::ToJSHandle(this); int32_t number = 0; if (!tagged->IsECMAObject()) { number = JSTaggedValue::ToInt32(thread, tagged); } else { // EcmaObject may call [Symbol.toPrimitive]. number = JSTaggedValue::ToInt32(thread, tagged); } RETURN_VALUE_IF_ABRUPT(thread, 0); return number; } double JSValueRef::GetValueDouble(bool &isNumber) { JSTaggedValue value = JSNApiHelper::ToJSTaggedValue(this); if (value.IsInt()) { isNumber = true; return static_cast(value.GetInt()); } if (value.IsDouble()) { isNumber = true; return value.GetDouble(); } isNumber = false; return 0.0; } int32_t JSValueRef::GetValueInt32(bool &isNumber) { JSTaggedValue value = JSNApiHelper::ToJSTaggedValue(this); if (value.IsInt()) { isNumber = true; return value.GetInt(); } if (value.IsDouble()) { isNumber = true; return static_cast(ecmascript::base::NumberHelper::DoubleToInt(value.GetDouble(), ecmascript::base::INT32_BITS)); } isNumber = false; return 0; } uint32_t JSValueRef::GetValueUint32(bool &isNumber) { return static_cast(GetValueInt32(isNumber)); } int64_t JSValueRef::GetValueInt64(bool &isNumber) { JSTaggedValue value = JSNApiHelper::ToJSTaggedValue(this); if (value.IsInt()) { isNumber = true; return static_cast(value.GetInt()); } if (value.IsDouble()) { isNumber = true; double getVale = value.GetDouble(); if (!std::isfinite(getVale) || std::isnan(getVale)) { return 0; } return NumberHelper::DoubleToInt64(getVale); } isNumber = false; return 0; } bool JSValueRef::GetValueBool(bool &isBool) { JSTaggedValue value = JSNApiHelper::ToJSTaggedValue(this); if (value.IsTrue()) { isBool = true; return true; } if (value.IsFalse()) { isBool = true; return false; } isBool = false; return false; } Local JSValueRef::ToBoolean(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); JSHandle booleanObj(thread, JSTaggedValue(obj->ToBoolean())); return JSNApiHelper::ToLocal(booleanObj); } Local JSValueRef::ToBigInt(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); JSHandle bigIntObj(thread, JSTaggedValue::ToBigInt(thread, obj)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(bigIntObj); } Local JSValueRef::ToNumber(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); JSHandle number(thread, JSTaggedValue::ToNumber(thread, obj)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(number); } bool JSValueRef::IsStrictEquals(const EcmaVM *vm, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle xValue = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(xValue, ERROR); JSHandle yValue = JSNApiHelper::ToJSHandle(value); return JSTaggedValue::StrictEqual(thread, xValue, yValue); } Local JSValueRef::Typeof(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedValue value = FastRuntimeStub::FastTypeOf(thread, JSNApiHelper::ToJSTaggedValue(this)); return JSNApiHelper::ToLocal(JSHandle(thread, value)); } bool JSValueRef::InstanceOf(const EcmaVM *vm, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle origin = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(origin, ERROR); JSHandle target = JSNApiHelper::ToJSHandle(value); return JSObject::InstanceOf(thread, origin, target); } // Omit exception check for JSValueRef::IsXxx because ark calls here may not // cause side effect even pending exception exists. 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::IsBigInt(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsBigInt(); } 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(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsString(); } bool JSValueRef::IsSymbol(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsSymbol(); } bool JSValueRef::IsObject(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsECMAObject(); } bool JSValueRef::IsArray(const EcmaVM *vm) { CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsArray(thread); } bool JSValueRef::IsJSArray(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSArray(); } bool JSValueRef::IsConstructor(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedValue value = JSNApiHelper::ToJSTaggedValue(this); return value.IsHeapObject() && value.IsConstructor(); } bool JSValueRef::IsFunction(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedValue value = JSNApiHelper::ToJSTaggedValue(this); return value.IsCallable(); } bool JSValueRef::IsJSFunction(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedValue value = JSNApiHelper::ToJSTaggedValue(this); return value.IsJSFunction(); } bool JSValueRef::IsProxy(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSProxy(); } bool JSValueRef::IsPromise(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSPromise(); } bool JSValueRef::IsDataView(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsDataView(); } bool JSValueRef::IsTypedArray(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsTypedArray(); } bool JSValueRef::IsNativePointer(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSNativePointer(); } bool JSValueRef::IsDate(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsDate(); } bool JSValueRef::IsError(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSError(); } bool JSValueRef::IsMap(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSMap(); } bool JSValueRef::IsSet(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSet(); } bool JSValueRef::IsWeakRef(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSWeakRef(); } bool JSValueRef::IsWeakMap(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSWeakMap(); } bool JSValueRef::IsWeakSet(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSWeakSet(); } bool JSValueRef::IsRegExp(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSRegExp(); } bool JSValueRef::IsArrayIterator(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSArrayIterator(); } bool JSValueRef::IsStringIterator(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsStringIterator(); } bool JSValueRef::IsSetIterator(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSetIterator(); } bool JSValueRef::IsMapIterator(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSMapIterator(); } bool JSValueRef::IsArrayBuffer(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsArrayBuffer(); } bool JSValueRef::IsBuffer(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsArrayBuffer(); } bool JSValueRef::IsUint8Array(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSUint8Array(); } bool JSValueRef::IsInt8Array(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSInt8Array(); } bool JSValueRef::IsUint8ClampedArray(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSUint8ClampedArray(); } bool JSValueRef::IsInt16Array(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSInt16Array(); } bool JSValueRef::IsUint16Array(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSUint16Array(); } bool JSValueRef::IsInt32Array(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSInt32Array(); } bool JSValueRef::IsUint32Array(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSUint32Array(); } bool JSValueRef::IsFloat32Array(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSFloat32Array(); } bool JSValueRef::IsFloat64Array(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSFloat64Array(); } bool JSValueRef::IsBigInt64Array(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSBigInt64Array(); } bool JSValueRef::IsBigUint64Array(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSBigUint64Array(); } bool JSValueRef::IsJSSharedInt8Array(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedInt8Array(); } bool JSValueRef::IsJSSharedUint8Array([[maybe_unused]]const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedUint8Array(); } bool JSValueRef::IsJSSharedUint8ClampedArray([[maybe_unused]]const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedUint8ClampedArray(); } bool JSValueRef::IsJSSharedInt16Array(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedInt16Array(); } bool JSValueRef::IsJSSharedUint16Array(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedUint16Array(); } bool JSValueRef::IsJSSharedInt32Array(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedInt32Array(); } bool JSValueRef::IsJSSharedFloat32Array(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedFloat32Array(); } bool JSValueRef::IsJSSharedUint32Array(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedUint32Array(); } bool JSValueRef::IsJSPrimitiveRef(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSPrimitiveRef(); } bool JSValueRef::IsJSPrimitiveNumber(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, FATAL); return IsJSPrimitiveRef(vm) ? JSPrimitiveRef::Cast(obj->GetTaggedObject())->IsNumber() : false; } bool JSValueRef::IsJSPrimitiveInt(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, FATAL); return IsJSPrimitiveRef(vm) ? JSPrimitiveRef::Cast(obj->GetTaggedObject())->IsInt() : false; } bool JSValueRef::IsJSPrimitiveBoolean(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, FATAL); return IsJSPrimitiveRef(vm) ? JSPrimitiveRef::Cast(obj->GetTaggedObject())->IsBoolean() : false; } bool JSValueRef::IsJSPrimitiveString(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, FATAL); return IsJSPrimitiveRef(vm) ? JSPrimitiveRef::Cast(obj->GetTaggedObject())->IsString() : false; } bool JSValueRef::IsJSPrimitiveSymbol(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, FATAL); return IsJSPrimitiveRef(vm) ? JSPrimitiveRef::Cast(obj->GetTaggedObject())->IsSymbol() : false; } bool JSValueRef::IsGeneratorObject(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsGeneratorObject(); } bool JSValueRef::IsModuleNamespaceObject(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsModuleNamespace(); } bool JSValueRef::IsNativeModuleFailureInfoObject(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsNativeModuleFailureInfo(); } bool JSValueRef::IsSharedArrayBuffer(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsSharedArrayBuffer(); } bool JSValueRef::IsSendableArrayBuffer(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsSendableArrayBuffer(); } bool JSValueRef::IsJSLocale(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSLocale(); } bool JSValueRef::IsJSDateTimeFormat(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSDateTimeFormat(); } bool JSValueRef::IsJSRelativeTimeFormat(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSRelativeTimeFormat(); } bool JSValueRef::IsJSIntl(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSIntl(); } bool JSValueRef::IsJSNumberFormat(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSNumberFormat(); } bool JSValueRef::IsJSCollator(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSCollator(); } bool JSValueRef::IsJSPluralRules(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSPluralRules(); } bool JSValueRef::IsJSListFormat(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSListFormat(); } bool JSValueRef::IsAsyncGeneratorObject(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsAsyncGeneratorObject(); } bool JSValueRef::IsAsyncFunction(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAsyncFunction(); } bool JSValueRef::IsConcurrentFunction(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle funcVal = JSNApiHelper::ToJSHandle(this); JSHandle transFunc = JSHandle::Cast(funcVal); return transFunc->GetFunctionKind() == ecmascript::FunctionKind::CONCURRENT_FUNCTION; } bool JSValueRef::IsArgumentsObject(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsArguments(); } bool JSValueRef::IsGeneratorFunction(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsGeneratorFunction(); } bool JSValueRef::IsAsyncGeneratorFunction(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsAsyncGeneratorFunction(); } bool JSValueRef::IsArrayList(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIArrayList(); } bool JSValueRef::IsDeque(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIDeque(); } bool JSValueRef::IsHashMap(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIHashMap(); } bool JSValueRef::IsHashSet(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIHashSet(); } bool JSValueRef::IsLightWeightMap(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPILightWeightMap(); } bool JSValueRef::IsLightWeightSet(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPILightWeightSet(); } bool JSValueRef::IsLinkedList(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPILinkedList(); } bool JSValueRef::IsLinkedListIterator(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPILinkedListIterator(); } bool JSValueRef::IsList(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIList(); } bool JSValueRef::IsPlainArray(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIPlainArray(); } bool JSValueRef::IsQueue(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIQueue(); } bool JSValueRef::IsStack(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIStack(); } bool JSValueRef::IsTreeMap(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPITreeMap(); } bool JSValueRef::IsTreeSet(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPITreeSet(); } bool JSValueRef::IsVector(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIVector(); } bool JSValueRef::IsSendableObject(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return IsJSShared(vm) && IsObject(vm); } bool JSValueRef::IsJSShared(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSShared(); } bool JSValueRef::IsSharedArray(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedArray(); } bool JSValueRef::IsSharedTypedArray(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsSharedTypedArray(); } bool JSValueRef::IsSharedSet(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedSet(); } bool JSValueRef::IsSharedMap(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedMap(); } bool JSValueRef::IsSharedMapIterator(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToJSTaggedValue(this).IsJSSharedMapIterator(); } bool JSValueRef::IsHeapObject() { return JSNApiHelper::ToJSTaggedValue(this).IsHeapObject(); } void *JSValueRef::GetNativePointerValue(const EcmaVM* vm, bool &isNativePointer) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); if (IsJSShared(vm)) { return GetNativePointerValueImpl(vm, isNativePointer); } else { return GetNativePointerValueImpl(vm, isNativePointer); } } // private void *JSValueRef::GetNativePointerValueImpl(const EcmaVM* vm, bool &isNativePointer) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); if (!IsNativePointer(vm)) { isNativePointer = false; return nullptr; } isNativePointer = true; CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, nullptr); JSHandle nativePointer = JSNApiHelper::ToJSHandle(this); return JSHandle(nativePointer)->GetExternalPointer(); } bool JSValueRef::IsDetachedArraybuffer(const EcmaVM *vm, bool &isArrayBuffer) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); // arraybuffer is not shared. Do not need to switch state if (!IsArrayBuffer(vm)) { isArrayBuffer = false; return false; } isArrayBuffer = true; JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); return arrayBuffer->IsDetach(); } void JSValueRef::DetachedArraybuffer(const EcmaVM *vm, bool &isArrayBuffer) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); if (IsArrayBuffer(vm)) { JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); if (arrayBuffer->IsDetach()) { return; } arrayBuffer->Detach(vm->GetJSThread()); isArrayBuffer = true; } else if (IsSendableArrayBuffer(vm)) { JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); if (arrayBuffer->IsDetach()) { return; } arrayBuffer->Detach(vm->GetJSThread()); isArrayBuffer = true; } else { isArrayBuffer = false; } } void JSValueRef::GetDataViewInfo(const EcmaVM *vm, bool &isDataView, size_t *byteLength, void **data, JSValueRef **arrayBuffer, size_t *byteOffset) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); if (!IsDataView(vm)) { isDataView = false; return; } isDataView = true; JSHandle dataView(JSNApiHelper::ToJSHandle(this)); if (byteLength) { *byteLength = dataView->GetByteLength(); } if (data || arrayBuffer) { JSThread* thread = vm->GetJSThread(); JSHandle retArrayBuffer(thread, dataView->GetViewedArrayBuffer()); if (data) { JSTaggedValue bufferData = retArrayBuffer->GetArrayBufferData(); if (!bufferData.IsJSNativePointer()) { *data = nullptr; } *data = JSNativePointer::Cast(bufferData.GetTaggedObject())->GetExternalPointer(); } if (arrayBuffer) { *arrayBuffer = reinterpret_cast(retArrayBuffer.GetAddress()); } } if (byteOffset) { *byteOffset = dataView->GetByteOffset(); } } void JSValueRef::TryGetArrayLength(const EcmaVM *vm, bool *isArrayOrSharedArray, uint32_t *arrayLength) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedValue thisValue = JSNApiHelper::ToJSTaggedValue(this); if (thisValue.IsJSArray()) { *isArrayOrSharedArray = true; *arrayLength = JSArray::Cast(thisValue.GetTaggedObject())->GetArrayLength(); } else if (thisValue.IsJSSharedArray()) { *isArrayOrSharedArray = true; *arrayLength = ecmascript::JSSharedArray::Cast(thisValue.GetTaggedObject())->GetArrayLength(); } else { *isArrayOrSharedArray = false; } } // ---------------------------------- DataView ----------------------------------- Local DataViewRef::New( const EcmaVM *vm, Local arrayBuffer, uint32_t byteOffset, uint32_t byteLength) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle buffer(JSNApiHelper::ToJSHandle(arrayBuffer)); JSHandle dataView = factory->NewJSDataView(buffer, byteOffset, byteLength); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(JSHandle(dataView)); } uint32_t DataViewRef::ByteLength() { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); JSHandle dataView(JSNApiHelper::ToJSHandle(this)); return dataView->GetByteLength(); } uint32_t DataViewRef::ByteOffset() { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); JSHandle dataView(JSNApiHelper::ToJSHandle(this)); return dataView->GetByteOffset(); } Local DataViewRef::GetArrayBuffer(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle dataView(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(dataView, FATAL); JSHandle arrayBuffer(thread, dataView->GetViewedArrayBuffer()); return JSNApiHelper::ToLocal(arrayBuffer); } // ---------------------------------- DataView ----------------------------------- // ----------------------------------- PritimitiveRef --------------------------------------- Local PrimitiveRef::GetValue(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); if (obj->IsJSPrimitiveRef()) { JSTaggedValue primitiveValue = JSPrimitiveRef::Cast(obj->GetTaggedObject())->GetValue(); JSHandle value(thread, primitiveValue); return JSNApiHelper::ToLocal(value); } return Local(); } // ----------------------------------- NumberRef --------------------------------------- Local NumberRef::New(const EcmaVM *vm, double input) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); if (std::isnan(input)) { input = ecmascript::base::NAN_VALUE; } JSHandle number(thread, JSTaggedValue(input), true); return JSNApiHelper::ToLocal(number); } Local NumberRef::New(const EcmaVM *vm, int32_t input) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); JSHandle number(thread, JSTaggedValue(input), true); return JSNApiHelper::ToLocal(number); } Local NumberRef::New(const EcmaVM *vm, uint32_t input) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); JSHandle number(thread, JSTaggedValue(input), true); return JSNApiHelper::ToLocal(number); } Local NumberRef::New(const EcmaVM *vm, int64_t input) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); JSHandle number(thread, JSTaggedValue(input), true); return JSNApiHelper::ToLocal(number); } double NumberRef::Value() { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. return JSTaggedNumber(JSNApiHelper::ToJSTaggedValue(this)).GetNumber(); } // ----------------------------------- MapRef --------------------------------------- Local MapRef::Get(const EcmaVM *vm, Local key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); return JSNApiHelper::ToLocal(JSHandle(thread, map->Get(thread, JSNApiHelper::ToJSTaggedValue(*key)))); } Local MapRef::Get(const EcmaVM *vm, const char *utf8) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); ObjectFactory *factory = vm->GetFactory(); JSHandle key(factory->NewFromUtf8(utf8)); auto result = JSHandle(thread, map->Get(thread, key.GetTaggedValue())); return JSNApiHelper::ToLocal(result); } void MapRef::Set(const EcmaVM *vm, Local key, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); JSMap::Set(thread, map, JSNApiHelper::ToJSHandle(key), JSNApiHelper::ToJSHandle(value)); } void MapRef::Set(const EcmaVM *vm, const char *utf8, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); ObjectFactory *factory = vm->GetFactory(); JSHandle key(factory->NewFromUtf8(utf8)); JSMap::Set(thread, map, key, JSNApiHelper::ToJSHandle(value)); } bool MapRef::Has(const EcmaVM *vm, Local key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); bool result = map->Has(thread, JSNApiHelper::ToJSTaggedValue(*key)); return result; } bool MapRef::Has(const EcmaVM *vm, const char *utf8) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); ObjectFactory *factory = vm->GetFactory(); JSHandle key(factory->NewFromUtf8(utf8)); bool result = map->Has(thread, key.GetTaggedValue()); return result; } void MapRef::Delete(const EcmaVM *vm, Local key) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); JSMap::Delete(thread, map, JSNApiHelper::ToJSHandle(key)); } void MapRef::Clear(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); JSMap::Clear(thread, map); } Local MapRef::New(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle constructor = env->GetBuiltinsMapFunction(); JSHandle map = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(constructor), constructor)); JSHandle hashMap = LinkedHashMap::Create(thread); map->SetLinkedMap(thread, hashMap); JSHandle mapTag = JSHandle::Cast(map); return JSNApiHelper::ToLocal(mapTag); } int32_t MapRef::GetSize(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); return map->GetSize(); } int32_t MapRef::GetTotalElements(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); return static_cast((map->GetSize())) + LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())->NumberOfDeletedElements(); } Local MapRef::GetKey(const EcmaVM *vm, int entry) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(map, FATAL); return JSNApiHelper::ToLocal(JSHandle(thread, map->GetKey(entry))); } Local MapRef::GetValue(const EcmaVM *vm, int entry) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(map, FATAL); return JSNApiHelper::ToLocal(JSHandle(thread, map->GetValue(entry))); } Local MapRef::GetEntries(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); DCHECK_SPECIAL_VALUE_WITH_RETURN(this, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); JSHandle mapIter = ecmascript::JSMapIterator::CreateMapIterator(thread, map, IterationKind::KEY_AND_VALUE); return JSNApiHelper::ToLocal(mapIter); } Local MapRef::GetKeys(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); DCHECK_SPECIAL_VALUE_WITH_RETURN(this, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); JSHandle mapIter = ecmascript::JSMapIterator::CreateMapIterator(thread, map, IterationKind::KEY); return JSNApiHelper::ToLocal(mapIter); } Local MapRef::GetValues(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); DCHECK_SPECIAL_VALUE_WITH_RETURN(this, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); JSHandle mapIter = ecmascript::JSMapIterator::CreateMapIterator(thread, map, IterationKind::VALUE); return JSNApiHelper::ToLocal(mapIter); } // SendableMapRef Local SendableMapRef::New(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle constructor = env->GetSBuiltininMapFunction(); ASSERT(constructor->IsJSSharedFunction() && constructor.GetTaggedValue().IsInSharedHeap()); JSHandle obj = factory->NewJSObjectByConstructor(JSHandle(constructor), constructor); ASSERT(obj.GetTaggedValue().IsInSharedHeap()); JSHandle sharedMap = JSHandle::Cast(obj); JSHandle linkedMap = LinkedHashMap::Create(thread, LinkedHashMap::MIN_CAPACITY, ecmascript::MemSpaceKind::SHARED); sharedMap->SetLinkedMap(thread, linkedMap); JSHandle sharedMapTag = JSHandle::Cast(sharedMap); return JSNApiHelper::ToLocal(sharedMapTag); } Local SendableMapRef::Get(const EcmaVM *vm, Local key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); JSHandle map(JSNApiHelper::ToJSHandle(this)); return JSNApiHelper::ToLocal(JSHandle(thread, ecmascript::JSSharedMap::Get(thread, map, JSNApiHelper::ToJSTaggedValue(*key)))); } Local SendableMapRef::Get(const EcmaVM *vm, const char *utf8) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); JSHandle map(JSNApiHelper::ToJSHandle(this)); ObjectFactory *factory = vm->GetFactory(); JSHandle key(factory->NewFromUtf8(utf8)); auto result = JSHandle(thread, ecmascript::JSSharedMap::Get(thread, map, key.GetTaggedValue())); return JSNApiHelper::ToLocal(result); } void SendableMapRef::Set(const EcmaVM *vm, Local key, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(thread); JSHandle map(JSNApiHelper::ToJSHandle(this)); ecmascript::JSSharedMap::Set(thread, map, JSNApiHelper::ToJSHandle(key), JSNApiHelper::ToJSHandle(value)); } void SendableMapRef::Set(const EcmaVM *vm, const char *utf8, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(thread); JSHandle map(JSNApiHelper::ToJSHandle(this)); ObjectFactory *factory = vm->GetFactory(); JSHandle key(factory->NewFromUtf8(utf8)); ecmascript::JSSharedMap::Set(thread, map, key, JSNApiHelper::ToJSHandle(value)); } bool SendableMapRef::Has(const EcmaVM *vm, Local key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(thread); JSHandle map(JSNApiHelper::ToJSHandle(this)); bool result = ecmascript::JSSharedMap::Has(thread, map, JSNApiHelper::ToJSTaggedValue(*key)); return result; } bool SendableMapRef::Has(const EcmaVM *vm, const char *utf8) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(thread); JSHandle map(JSNApiHelper::ToJSHandle(this)); ObjectFactory *factory = vm->GetFactory(); JSHandle key(factory->NewFromUtf8(utf8)); bool result = ecmascript::JSSharedMap::Has(thread, map, key.GetTaggedValue()); return result; } void SendableMapRef::Delete(const EcmaVM *vm, Local key) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(thread); JSHandle map(JSNApiHelper::ToJSHandle(this)); ecmascript::JSSharedMap::Delete(thread, map, JSNApiHelper::ToJSHandle(key)); } void SendableMapRef::Clear(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(thread); JSHandle map(JSNApiHelper::ToJSHandle(this)); ecmascript::JSSharedMap::Clear(thread, map); } uint32_t SendableMapRef::GetSize(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); return ecmascript::JSSharedMap::GetSize(thread, map); } uint32_t SendableMapRef::GetTotalElements(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); return static_cast(ecmascript::JSSharedMap::GetSize(thread, map)) + LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())->NumberOfDeletedElements(); } Local SendableMapRef::GetKey(const EcmaVM *vm, int entry) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(map, FATAL); return JSNApiHelper::ToLocal(JSHandle(thread, ecmascript::JSSharedMap::GetKey(thread, map, entry))); } Local SendableMapRef::GetValue(const EcmaVM *vm, int entry) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(map, FATAL); return JSNApiHelper::ToLocal(JSHandle(thread, ecmascript::JSSharedMap::GetValue(thread, map, entry))); } Local SendableMapRef::GetEntries(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); DCHECK_SPECIAL_VALUE_WITH_RETURN(this, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); JSHandle sharedMapIter = ecmascript::JSSharedMapIterator::CreateMapIterator(thread, map, IterationKind::KEY_AND_VALUE); return JSNApiHelper::ToLocal(sharedMapIter); } Local SendableMapRef::GetKeys(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); DCHECK_SPECIAL_VALUE_WITH_RETURN(this, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); JSHandle sharedMapIter = ecmascript::JSSharedMapIterator::CreateMapIterator(thread, map, IterationKind::KEY); return JSNApiHelper::ToLocal(sharedMapIter); } Local SendableMapRef::GetValues(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); DCHECK_SPECIAL_VALUE_WITH_RETURN(this, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle map(JSNApiHelper::ToJSHandle(this)); JSHandle sharedMapIter = ecmascript::JSSharedMapIterator::CreateMapIterator(thread, map, IterationKind::VALUE); return JSNApiHelper::ToLocal(sharedMapIter); } // SendableSetRef Local SendableSetRef::New(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle constructor = env->GetSBuiltininSetFunction(); ASSERT(constructor->IsJSSharedFunction() && constructor.GetTaggedValue().IsInSharedHeap()); JSHandle obj = factory->NewJSObjectByConstructor(JSHandle(constructor), constructor); ASSERT(obj.GetTaggedValue().IsInSharedHeap()); JSHandle set = JSHandle::Cast(obj); JSHandle linkedSet = LinkedHashSet::Create(thread, LinkedHashSet::MIN_CAPACITY, ecmascript::MemSpaceKind::SHARED); set->SetLinkedSet(thread, linkedSet); JSHandle sharedSetTag = JSHandle::Cast(set); return JSNApiHelper::ToLocal(sharedSetTag); } uint32_t SendableSetRef::GetSize(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle set(JSNApiHelper::ToJSHandle(this)); return ecmascript::JSSharedSet::GetSize(thread, set); } uint32_t SendableSetRef::GetTotalElements(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle set(JSNApiHelper::ToJSHandle(this)); return static_cast(ecmascript::JSSharedSet::GetSize(thread, set)) + LinkedHashSet::Cast(set->GetLinkedSet().GetTaggedObject())->NumberOfDeletedElements(); } Local SendableSetRef::GetValue(const EcmaVM *vm, int entry) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle set(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(set, FATAL); return JSNApiHelper::ToLocal( JSHandle(thread, ecmascript::JSSharedSet::GetValue(thread, set, entry))); } void SendableSetRef::Add(const EcmaVM *vm, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(thread); JSHandle set(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(set, FATAL); ecmascript::JSSharedSet::Add(thread, set, JSNApiHelper::ToJSHandle(value)); } // ----------------------------------- MapIteratorRef --------------------------------------- int32_t MapIteratorRef::GetIndex() { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, -1); JSHandle jsMapIter(JSNApiHelper::ToJSHandle(this)); return jsMapIter->GetNextIndex(); } Local MapIteratorRef::GetKind(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle jsMapIter(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(jsMapIter, FATAL); IterationKind iterKind = jsMapIter->GetIterationKind(); Local result; const GlobalEnvConstants *globalConst = thread->GlobalConstants(); switch (iterKind) { case IterationKind::KEY: result = JSNApiHelper::ToLocal(globalConst->GetHandledKeysString()); break; case IterationKind::VALUE: result = JSNApiHelper::ToLocal(globalConst->GetHandledValuesString()); break; case IterationKind::KEY_AND_VALUE: result = JSNApiHelper::ToLocal(globalConst->GetHandledEntriesString()); break; default: break; } return result; } Local MapIteratorRef::New(const EcmaVM *vm, Local map) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); JSHandle jsMap(JSNApiHelper::ToJSHandle(map)); IterationKind iterKind = IterationKind::KEY_AND_VALUE; JSHandle mapIteratorKeyAndValue = JSMapIterator::CreateMapIterator(vm->GetJSThread(), JSHandle::Cast(jsMap), iterKind); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(mapIteratorKeyAndValue); } ecmascript::EcmaRuntimeCallInfo *MapIteratorRef::GetEcmaRuntimeCallInfo(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, nullptr); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle jsMapIter(JSNApiHelper::ToJSHandle(this)); JSHandle linkedHashMap(vm->GetJSThread(), jsMapIter->GetIteratedMap()); uint32_t size = linkedHashMap->GetLength(); return ecmascript::EcmaInterpreter::NewRuntimeCallInfo(vm->GetJSThread(), JSHandle(vm->GetJSThread(), JSTaggedValue::Undefined()), JSHandle(vm->GetJSThread(), jsMapIter.GetTaggedValue()), JSHandle(vm->GetJSThread(), JSTaggedValue::Undefined()), size); } Local MapIteratorRef::Next(const EcmaVM *vm, ecmascript::EcmaRuntimeCallInfo *ecmaRuntimeCallInfo) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); JSHandle nextTagValResult(vm->GetJSThread(), JSMapIterator::Next(ecmaRuntimeCallInfo)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); JSHandle iteratorVal(vm->GetJSThread(), JSIterator::IteratorValue(vm->GetJSThread(), nextTagValResult).GetTaggedValue()); return JSNApiHelper::ToLocal(iteratorVal); } Local MapIteratorRef::Next(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); JSHandle mapIter(JSNApiHelper::ToJSHandle(this)); auto result = JSMapIterator::NextInternal(thread, mapIter); return JSNApiHelper::ToLocal(JSHandle(thread, result)); } // SendableMapIteratorRef Local SendableMapIteratorRef::Next(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); JSHandle sharedMapIter(JSNApiHelper::ToJSHandle(this)); auto result = ecmascript::JSSharedMapIterator::NextInternal(thread, sharedMapIter); return JSNApiHelper::ToLocal(JSHandle(thread, result)); } // ----------------------------------- SetIteratorRef --------------------------------------- int32_t SetIteratorRef::GetIndex() { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, -1); JSHandle jsSetIter(JSNApiHelper::ToJSHandle(this)); return jsSetIter->GetNextIndex(); } Local SetIteratorRef::GetKind(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle jsSetIter(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(jsSetIter, FATAL); IterationKind iterKind = jsSetIter->GetIterationKind(); Local result; const GlobalEnvConstants *globalConst = thread->GlobalConstants(); switch (iterKind) { case IterationKind::KEY: result = JSNApiHelper::ToLocal(globalConst->GetHandledKeysString()); break; case IterationKind::VALUE: result = JSNApiHelper::ToLocal(globalConst->GetHandledValuesString()); break; case IterationKind::KEY_AND_VALUE: result = JSNApiHelper::ToLocal(globalConst->GetHandledEntriesString()); break; default: break; } return result; } Local SetIteratorRef::New(const EcmaVM *vm, Local set) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle jsSet(JSNApiHelper::ToJSHandle(set)); IterationKind iterKind = IterationKind::KEY_AND_VALUE; JSHandle setIteratorKeyAndValue = JSSetIterator::CreateSetIterator(vm->GetJSThread(), JSHandle::Cast(jsSet), iterKind); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(setIteratorKeyAndValue); } ecmascript::EcmaRuntimeCallInfo *SetIteratorRef::GetEcmaRuntimeCallInfo(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, nullptr); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle jsSetIter(JSNApiHelper::ToJSHandle(this)); JSHandle linkedHashSet(vm->GetJSThread(), jsSetIter->GetIteratedSet()); uint32_t size = linkedHashSet->GetLength(); return ecmascript::EcmaInterpreter::NewRuntimeCallInfo(vm->GetJSThread(), JSHandle(vm->GetJSThread(), JSTaggedValue::Undefined()), JSHandle(vm->GetJSThread(), jsSetIter.GetTaggedValue()), JSHandle(vm->GetJSThread(), JSTaggedValue::Undefined()), size); } Local SetIteratorRef::Next(const EcmaVM *vm, ecmascript::EcmaRuntimeCallInfo *ecmaRuntimeCallInfo) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle nextTagValResult(vm->GetJSThread(), JSSetIterator::Next(ecmaRuntimeCallInfo)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); JSHandle iteratorVal(vm->GetJSThread(), JSIterator::IteratorValue(vm->GetJSThread(), nextTagValResult).GetTaggedValue()); return JSNApiHelper::ToLocal(iteratorVal); } // ---------------------------------- Buffer ----------------------------------- Local BufferRef::New(const EcmaVM *vm, int32_t length) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle arrayBuffer = JSHandle::Cast(factory->NewJSArrayBuffer(length)); JSHandle env = vm->GetGlobalEnv(); JSHandle current = factory->NewJSFunction(env, reinterpret_cast(BufferRef::BufferToStringCallback)); Local key = StringRef::NewFromUtf8(vm, "toString"); JSHandle keyValue = JSNApiHelper::ToJSHandle(key); JSHandle currentTaggedValue(current); JSHandle obj(arrayBuffer); bool result = JSTaggedValue::SetProperty(thread, obj, keyValue, currentTaggedValue); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); if (!result) { LOG_ECMA(ERROR) << "SetProperty failed ! ! !"; } return JSNApiHelper::ToLocal(obj); } Local BufferRef::New( const EcmaVM *vm, void *buffer, int32_t length, const NativePointerCallback &deleter, void *data) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle arrayBuffer = factory->NewJSArrayBuffer(buffer, length, deleter, data); JSHandle env = vm->GetGlobalEnv(); JSHandle current = factory->NewJSFunction(env, reinterpret_cast(BufferRef::BufferToStringCallback)); Local key = StringRef::NewFromUtf8(vm, "toString"); JSHandle keyValue = JSNApiHelper::ToJSHandle(key); JSHandle currentTaggedValue(current); JSHandle obj(arrayBuffer); bool result = JSTaggedValue::SetProperty(thread, obj, keyValue, currentTaggedValue); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); if (!result) { LOG_ECMA(ERROR) << "SetProperty failed ! ! !"; } return JSNApiHelper::ToLocal(JSHandle(arrayBuffer)); } int32_t BufferRef::ByteLength(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); return arrayBuffer->GetArrayBufferByteLength(); } void *BufferRef::GetBuffer(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, nullptr); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); JSTaggedValue bufferData = arrayBuffer->GetArrayBufferData(); if (!bufferData.IsJSNativePointer()) { return nullptr; } return JSNativePointer::Cast(bufferData.GetTaggedObject())->GetExternalPointer(); } JSTaggedValue BufferRef::BufferToStringCallback(ecmascript::EcmaRuntimeCallInfo *ecmaRuntimeCallInfo) { JSThread *thread = ecmaRuntimeCallInfo->GetThread(); ecmascript::ThreadManagedScope managedScope(thread); [[maybe_unused]] LocalScope scope(thread->GetEcmaVM()); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle arrayBuff = ecmaRuntimeCallInfo->GetThis(); JSHandle arrayBuffer(arrayBuff); uint32_t length = arrayBuffer->GetArrayBufferByteLength(); JSTaggedValue data = arrayBuffer->GetArrayBufferData(); ecmascript::CVector valueTable; valueTable.reserve(length); for (uint32_t i = 0; i < length; i++) { void* rawData = reinterpret_cast( ToUintPtr(JSNativePointer::Cast(data.GetTaggedObject())->GetExternalPointer()) + i); uint8_t *block = reinterpret_cast(rawData); uint16_t nextCv = static_cast(*block); valueTable.emplace_back(nextCv); } auto *char16tData0 = reinterpret_cast(valueTable.data()); std::u16string u16str(char16tData0, length); const char16_t *constChar16tData = u16str.data(); auto *char16tData = const_cast(constChar16tData); auto *uint16tData = reinterpret_cast(char16tData); uint32_t u16strSize = u16str.size(); JSTaggedValue rString = factory->NewFromUtf16Literal(uint16tData, u16strSize).GetTaggedValue(); JSHandle StringHandle = JSTaggedValue::ToString(thread, rString); RETURN_VALUE_IF_ABRUPT(thread, JSTaggedValue::Undefined()); return StringHandle.GetTaggedValue(); } // ---------------------------------- Promise -------------------------------------- Local PromiseCapabilityRef::New(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle constructor(globalEnv->GetPromiseFunction()); JSHandle capability(JSPromise::NewPromiseCapability(thread, constructor)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(capability); } Local PromiseCapabilityRef::GetPromise(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); JSHandle capacity(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(capacity, FATAL); return JSNApiHelper::ToLocal(JSHandle(thread, capacity->GetPromise())); } bool PromiseCapabilityRef::Resolve(const EcmaVM *vm, uintptr_t value) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSTaggedValue arg = *reinterpret_cast(value); #if ECMASCRIPT_ENABLE_STUB_ARGV_CHECK thread->CheckJSTaggedType(arg.GetRawData()); #endif JSHandle capacity(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(capacity, FATAL); JSTaggedValue resolve = capacity->GetResolve(); JSTaggedValue undefined = constants->GetUndefined(); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, resolve, undefined, undefined, 1); RETURN_VALUE_IF_ABRUPT(thread, false); info->SetCallArg(arg); JSFunction::Call(info); RETURN_VALUE_IF_ABRUPT(thread, false); thread->GetCurrentEcmaContext()->ExecutePromisePendingJob(); RETURN_VALUE_IF_ABRUPT(thread, false); thread->GetCurrentEcmaContext()->ClearKeptObjects(); return true; } bool PromiseCapabilityRef::Resolve(const EcmaVM *vm, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle arg = JSNApiHelper::ToJSHandle(value); #if ECMASCRIPT_ENABLE_STUB_ARGV_CHECK thread->CheckJSTaggedType(arg.GetTaggedValue().GetRawData()); #endif JSHandle capacity(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(capacity, FATAL); JSHandle resolve(thread, capacity->GetResolve()); JSHandle undefined(constants->GetHandledUndefined()); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, resolve, undefined, undefined, 1); RETURN_VALUE_IF_ABRUPT(thread, false); info->SetCallArg(arg.GetTaggedValue()); JSFunction::Call(info); RETURN_VALUE_IF_ABRUPT(thread, false); thread->GetCurrentEcmaContext()->ExecutePromisePendingJob(); RETURN_VALUE_IF_ABRUPT(thread, false); thread->GetCurrentEcmaContext()->ClearKeptObjects(); return true; } bool PromiseCapabilityRef::Reject(const EcmaVM *vm, uintptr_t reason) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSTaggedValue arg = *reinterpret_cast(reason); #if ECMASCRIPT_ENABLE_STUB_ARGV_CHECK thread->CheckJSTaggedType(arg.GetRawData()); #endif JSHandle capacity(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(capacity, FATAL); JSTaggedValue reject = capacity->GetReject(); JSTaggedValue undefined = constants->GetUndefined(); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefined, undefined, 1); RETURN_VALUE_IF_ABRUPT(thread, false); info->SetCallArg(arg); JSFunction::Call(info); RETURN_VALUE_IF_ABRUPT(thread, false); thread->GetCurrentEcmaContext()->ExecutePromisePendingJob(); RETURN_VALUE_IF_ABRUPT(thread, false); thread->GetCurrentEcmaContext()->ClearKeptObjects(); return true; } bool PromiseCapabilityRef::Reject(const EcmaVM *vm, Local reason) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle arg = JSNApiHelper::ToJSHandle(reason); #if ECMASCRIPT_ENABLE_STUB_ARGV_CHECK thread->CheckJSTaggedType(arg.GetTaggedValue().GetRawData()); #endif JSHandle capacity(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(capacity, FATAL); JSHandle reject(thread, capacity->GetReject()); JSHandle undefined(constants->GetHandledUndefined()); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefined, undefined, 1); RETURN_VALUE_IF_ABRUPT(thread, false); info->SetCallArg(arg.GetTaggedValue()); JSFunction::Call(info); RETURN_VALUE_IF_ABRUPT(thread, false); thread->GetCurrentEcmaContext()->ExecutePromisePendingJob(); RETURN_VALUE_IF_ABRUPT(thread, false); thread->GetCurrentEcmaContext()->ClearKeptObjects(); return true; } // ----------------------------------- SymbolRef ----------------------------------------- Local SymbolRef::New(const EcmaVM *vm, Local description) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle symbol = factory->NewJSSymbol(); if (!description.IsEmpty()) { JSTaggedValue desc = JSNApiHelper::ToJSTaggedValue(*description); symbol->SetDescription(thread, desc); } return JSNApiHelper::ToLocal(JSHandle(symbol)); } Local SymbolRef::GetDescription(const EcmaVM *vm) { CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedValue description = JSSymbol::Cast( JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject())->GetDescription(); if (!description.IsString()) { auto constants = thread->GlobalConstants(); return JSNApiHelper::ToLocal(constants->GetHandledEmptyString()); } JSHandle descriptionHandle(thread, description); return JSNApiHelper::ToLocal(descriptionHandle); } // ----------------------------------- BooleanRef --------------------------------------- Local BooleanRef::New(const EcmaVM *vm, bool value) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle boolean(thread, JSTaggedValue(value)); return JSNApiHelper::ToLocal(boolean); } bool BooleanRef::Value() { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. return JSNApiHelper::ToJSTaggedValue(this).IsTrue(); } // ----------------------------------- StringRef ---------------------------------------- Local StringRef::NewFromUtf8(const EcmaVM *vm, const char *utf8, int length) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); if (length < 0) { JSHandle current(factory->NewFromUtf8(utf8)); return JSNApiHelper::ToLocal(current); } JSHandle current(factory->NewFromUtf8(reinterpret_cast(utf8), length)); return JSNApiHelper::ToLocal(current); } Local StringRef::NewFromUtf8WithoutStringTable(const EcmaVM *vm, const char *utf8, int length) { // This only supports for napi_create_string_utf8 CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); if (length < 0) { JSHandle current(factory->NewFromUtf8WithoutStringTable(utf8)); return JSNApiHelper::ToLocal(current); } JSHandle current(factory->NewFromUtf8WithoutStringTable(reinterpret_cast(utf8), length)); return JSNApiHelper::ToLocal(current); } Local StringRef::NewFromUtf16WithoutStringTable(const EcmaVM *vm, const char16_t *utf16, int length) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); if (length < 0) { JSHandle current(factory->NewFromUtf16WithoutStringTable(utf16)); return JSNApiHelper::ToLocal(current); } JSHandle current(factory->NewFromUtf16WithoutStringTable(reinterpret_cast(utf16), length)); return JSNApiHelper::ToLocal(current); } Local StringRef::NewFromUtf16(const EcmaVM *vm, const char16_t *utf16, int length) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); if (length < 0) { JSHandle current(factory->NewFromUtf16(utf16)); return JSNApiHelper::ToLocal(current); } JSHandle current(factory->NewFromUtf16(reinterpret_cast(utf16), length)); return JSNApiHelper::ToLocal(current); } std::string StringRef::ToString(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, ""); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return EcmaStringAccessor(JSNApiHelper::ToJSTaggedValue(this)).ToStdString(); } std::string StringRef::DebuggerToString(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, ""); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return EcmaStringAccessor(JSNApiHelper::ToJSTaggedValue(this)).DebuggerToStdString(); } uint32_t StringRef::Length(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return EcmaStringAccessor(JSNApiHelper::ToJSTaggedValue(this)).GetLength(); } size_t StringRef::Utf8Length(const EcmaVM *vm, bool isGetBufferSize) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle strHandle(vm->GetJSThread(), EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(this))); return EcmaStringAccessor(EcmaStringAccessor::Flatten(vm, strHandle)).GetUtf8Length(isGetBufferSize); } uint32_t StringRef::WriteUtf8(const EcmaVM *vm, char *buffer, uint32_t length, bool isWriteBuffer) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return EcmaStringAccessor(JSNApiHelper::ToJSTaggedValue(this)) .WriteToFlatUtf8(reinterpret_cast(buffer), length, isWriteBuffer); } uint32_t StringRef::WriteUtf16(const EcmaVM *vm, char16_t *buffer, uint32_t length) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return EcmaStringAccessor(JSNApiHelper::ToJSTaggedValue(this)) .WriteToUtf16(reinterpret_cast(buffer), length); } uint32_t StringRef::WriteLatin1(const EcmaVM *vm, char *buffer, uint32_t length) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return EcmaStringAccessor(JSNApiHelper::ToJSTaggedValue(this)) .WriteToOneByte(reinterpret_cast(buffer), length); } Local StringRef::GetNapiWrapperString(const EcmaVM *vm) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle napiWapperString = thread->GlobalConstants()->GetHandledNapiWrapperString(); return JSNApiHelper::ToLocal(napiWapperString); } Local StringRef::EncodeIntoUint8Array(const EcmaVM *vm) { CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle string = JSNApiHelper::ToJSHandle(this); uint32_t length = this->Utf8Length(vm, true); // 1 because Utf8Length adds 1 for the return value if (length <= 1) { return Undefined(vm); } JSHandle obj = TypedArrayHelper::FastCreateTypedArray(thread, thread->GlobalConstants()->GetHandledUint8ArrayString(), length - 1, DataViewType::UINT8); JSHandle arrayBuffer(thread, JSTypedArray::Cast(*obj)->GetViewedArrayBufferOrByteArray()); JSTaggedValue bufferData = JSHandle::Cast(arrayBuffer)->GetArrayBufferData(); void *buffer = JSNativePointer::Cast(bufferData.GetTaggedObject())->GetExternalPointer(); JSHandle stringHandle = JSHandle::Cast(string); EcmaStringAccessor(stringHandle).WriteToFlatUtf8(reinterpret_cast(buffer), length - 1, true); JSHandle typedArrayTag = JSHandle::Cast(obj); return JSNApiHelper::ToLocal(typedArrayTag); } // ---------------------------------- PromiseRejectInfo --------------------------------- PromiseRejectInfo::PromiseRejectInfo(Local promise, Local reason, PromiseRejectInfo::PROMISE_REJECTION_EVENT operation, void* data) : promise_(promise), reason_(reason), operation_(operation), data_(data) {} Local PromiseRejectInfo::GetPromise() const { return promise_; } Local PromiseRejectInfo::GetReason() const { return reason_; } PromiseRejectInfo::PROMISE_REJECTION_EVENT PromiseRejectInfo::GetOperation() const { return operation_; } void* PromiseRejectInfo::GetData() const { return data_; } // ----------------------------------- BigIntRef --------------------------------------- Local BigIntRef::New(const EcmaVM *vm, uint64_t input) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle big = BigInt::Uint64ToBigInt(thread, input); JSHandle bigint = JSHandle::Cast(big); return JSNApiHelper::ToLocal(bigint); } Local BigIntRef::New(const EcmaVM *vm, int64_t input) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle big = BigInt::Int64ToBigInt(thread, input); JSHandle bigint = JSHandle::Cast(big); return JSNApiHelper::ToLocal(bigint); } Local BigIntRef::CreateBigWords(const EcmaVM *vm, bool sign, uint32_t size, const uint64_t* words) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle big = BigInt::CreateBigWords(thread, sign, size, words); JSHandle bigint = JSHandle::Cast(big); return JSNApiHelper::ToLocal(bigint); } void BigIntRef::BigIntToInt64(const EcmaVM *vm, int64_t *value, bool *lossless) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle bigintVal(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(bigintVal, ERROR); BigInt::BigIntToInt64(thread, bigintVal, value, lossless); } void BigIntRef::BigIntToUint64(const EcmaVM *vm, uint64_t *value, bool *lossless) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle bigintVal(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(bigintVal, ERROR); BigInt::BigIntToUint64(thread, bigintVal, value, lossless); } void BigIntRef::GetWordsArray(const EcmaVM *vm, bool* signBit, size_t wordCount, uint64_t* words) { DCHECK_SPECIAL_VALUE(this); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle bigintVal(JSNApiHelper::ToJSHandle(this)); uint32_t len = bigintVal->GetLength(); uint32_t count = 0; uint32_t index = 0; ASSERT(wordCount > 0); for (; index < wordCount - 1; ++index) { words[index] = static_cast(bigintVal->GetDigit(count++)); words[index] |= static_cast(bigintVal->GetDigit(count++)) << 32; // 32 : int32_t bits } if (len % 2 == 0) { // 2 : len is odd or even words[index] = static_cast(bigintVal->GetDigit(count++)); words[index] |= static_cast(bigintVal->GetDigit(count++)) << 32; // 32 : int32_t bits } else { words[index] = static_cast(bigintVal->GetDigit(count++)); } *signBit = bigintVal->GetSign(); } uint32_t BigIntRef::GetWordsArraySize(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle bigintVal(JSNApiHelper::ToJSHandle(this)); uint32_t len = bigintVal->GetLength(); return len % 2 != 0 ? len / 2 + 1 : len / 2; // 2 : len is odd or even } // ----------------------------------- HandleScope ------------------------------------- LocalScope::LocalScope(const EcmaVM *vm) : thread_(vm->GetJSThread()) { // Only get handle ptr here. Do not need to swtich state. auto context = reinterpret_cast(thread_)->GetCurrentEcmaContext(); prevNext_ = context->GetHandleScopeStorageNext(); prevEnd_ = context->GetHandleScopeStorageEnd(); prevHandleStorageIndex_ = context->GetCurrentHandleStorageIndex(); prevPrimitiveNext_ = context->GetPrimitiveScopeStorageNext(); prevPrimitiveEnd_ = context->GetPrimitiveScopeStorageEnd(); prevPrimitiveStorageIndex_ = context->GetCurrentPrimitiveStorageIndex(); #ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK context->HandleScopeCountAdd(); context->PrimitiveScopeCountAdd(); #endif } LocalScope::LocalScope(const EcmaVM *vm, JSTaggedType value) : thread_(vm->GetJSThread()) { ecmascript::ThreadManagedScope managedScope(reinterpret_cast(thread_)); // Simply reserve a slot on the handlescope. The escaped handle will still be retained in this slot. ecmascript::EcmaHandleScope::NewHandle(reinterpret_cast(thread_), value); auto context = reinterpret_cast(thread_)->GetCurrentEcmaContext(); prevNext_ = context->GetHandleScopeStorageNext(); prevEnd_ = context->GetHandleScopeStorageEnd(); prevHandleStorageIndex_ = context->GetCurrentHandleStorageIndex(); prevPrimitiveNext_ = context->GetPrimitiveScopeStorageNext(); prevPrimitiveEnd_ = context->GetPrimitiveScopeStorageEnd(); prevPrimitiveStorageIndex_ = context->GetCurrentPrimitiveStorageIndex(); #ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK context->HandleScopeCountAdd(); context->PrimitiveScopeCountAdd(); #endif } LocalScope::~LocalScope() { ecmascript::ThreadManagedScope managedScope(reinterpret_cast(thread_)); auto context = reinterpret_cast(thread_)->GetCurrentEcmaContext(); #ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK context->HandleScopeCountDec(); context->PrimitiveScopeCountDec(); #endif context->SetHandleScopeStorageNext(static_cast(prevNext_)); context->SetPrimitiveScopeStorageNext(static_cast(prevPrimitiveNext_)); if (context->GetHandleScopeStorageEnd() != prevEnd_) { context->SetHandleScopeStorageEnd(static_cast(prevEnd_)); context->ShrinkHandleStorage(prevHandleStorageIndex_); } if (context->GetPrimitiveScopeStorageEnd() != prevPrimitiveEnd_) { context->SetPrimitiveScopeStorageEnd(static_cast(prevPrimitiveEnd_)); context->ShrinkPrimitiveStorage(prevPrimitiveStorageIndex_); } } // ----------------------------------- EscapeLocalScope ------------------------------ EscapeLocalScope::EscapeLocalScope(const EcmaVM *vm) : LocalScope(vm, JSTaggedValue::Undefined().GetRawData()) { auto thread = vm->GetJSThread(); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) escapeHandle_ = ToUintPtr(thread->GetCurrentEcmaContext()->GetHandleScopeStorageNext() - 1); } // ----------------------------------- IntegerRef --------------------------------------- Local IntegerRef::New(const EcmaVM *vm, int input) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(thread); JSHandle integer(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(integer); } Local IntegerRef::NewFromUnsigned(const EcmaVM *vm, unsigned int input) { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(thread); JSHandle integer(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(integer); } int IntegerRef::Value() { // Omit exception check because ark calls here may not // cause side effect even pending exception exists. return JSNApiHelper::ToJSTaggedValue(this).GetInt(); } // ----------------------------------- ObjectRef ---------------------------------------- Local ObjectRef::New(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle constructor(globalEnv->GetObjectFunction()); JSHandle object(factory->NewJSObjectByConstructor(constructor)); return JSNApiHelper::ToLocal(object); } uintptr_t ObjectRef::NewObject(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, (vm->GetJSThread()->GlobalConstants()->GetHandledUndefined()).GetAddress()); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle constructor(globalEnv->GetObjectFunction()); JSHandle object(factory->NewJSObjectByConstructor(constructor)); return object.GetAddress(); } Local ObjectRef::NewS(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle constructor(globalEnv->GetSObjectFunction()); JSHandle object(factory->NewJSObjectByConstructor(constructor)); return JSNApiHelper::ToLocal(object); } Local ObjectRef::NewWithProperties(const EcmaVM *vm, size_t propertyCount, const Local *keys, const PropertyAttribute *attributes) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle obj; auto CreateObjImpl = [vm, propertyCount, keys, attributes] (uintptr_t head) -> JSHandle { JSThread *thread = vm->GetJSThread(); const PropertyDescriptor *desc = reinterpret_cast(head); for (size_t i = 0; i < propertyCount; ++i) { const PropertyAttribute &attr = attributes[i]; new (reinterpret_cast(head)) PropertyDescriptor(thread, JSNApiHelper::ToJSHandle(attr.GetValue(vm)), attr.IsWritable(), attr.IsEnumerable(), attr.IsConfigurable()); head += sizeof(PropertyDescriptor); } ObjectFactory *factory = vm->GetFactory(); return factory->CreateJSObjectWithProperties(propertyCount, keys, desc); }; if (propertyCount <= MAX_PROPERTIES_ON_STACK) { char desc[sizeof(PropertyDescriptor) * MAX_PROPERTIES_ON_STACK]; obj = CreateObjImpl(reinterpret_cast(desc)); } else { void *desc = malloc(sizeof(PropertyDescriptor) * propertyCount); obj = CreateObjImpl(reinterpret_cast(desc)); free(desc); } RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return scope.Escape(JSNApiHelper::ToLocal(obj)); } Local ObjectRef::NewSWithProperties(const EcmaVM *vm, SendablePropertiesInfo &info) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); ObjectFactory *factory = vm->GetFactory(); std::vector descs; JSNapiSendable::InitWithPropertiesInfo(thread, info, descs); auto obj = factory->CreateSObjectWithProperties(descs); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return scope.Escape(JSNApiHelper::ToLocal(obj)); } Local ObjectRef::NewWithNamedProperties(const EcmaVM *vm, size_t propertyCount, const char **keys, const Local *values) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); ObjectFactory *factory = vm->GetFactory(); JSHandle obj = factory->CreateJSObjectWithNamedProperties(propertyCount, keys, values); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return scope.Escape(JSNApiHelper::ToLocal(obj)); } Local ObjectRef::CreateNativeModuleFailureInfo(const EcmaVM *vm, const std::string &failureInfo) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); if (EcmaVM::GetErrorInfoEnhance()) { JSHandle nativeModuleErrorFailureInfo = NativeModuleFailureInfo::CreateNativeModuleFailureInfo(vm, failureInfo); return JSNApiHelper::ToLocal(JSHandle::Cast(nativeModuleErrorFailureInfo)); } return JSValueRef::Undefined(vm); } Local ObjectRef::CreateAccessorData(const EcmaVM *vm, Local getter, Local setter) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle getterValue = JSNApiHelper::ToJSHandle(getter); JSHandle setterValue = JSNApiHelper::ToJSHandle(setter); JSHandle accessor = thread->GetEcmaVM()->GetFactory()->NewAccessorData(); accessor->SetGetter(thread, getterValue); accessor->SetSetter(thread, setterValue); return JSNApiHelper::ToLocal(JSHandle::Cast(accessor)); } Local ObjectRef::CreateSendableAccessorData(const EcmaVM *vm, Local getter, Local setter) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); JSHandle getterValue = JSNApiHelper::ToJSHandle(getter); JSHandle setterValue = JSNApiHelper::ToJSHandle(setter); JSHandle accessor = thread->GetEcmaVM()->GetFactory()->NewSAccessorData(); accessor->SetGetter(thread, getterValue); accessor->SetSetter(thread, setterValue); return JSNApiHelper::ToLocal(JSHandle::Cast(accessor)); } bool ObjectRef::ConvertToNativeBindingObject(const EcmaVM *vm, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); [[maybe_unused]] LocalScope scope(vm); JSHandle object = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(object, ERROR); JSHandle env = vm->GetGlobalEnv(); JSHandle keyValue = env->GetNativeBindingSymbol(); JSHandle valueValue = JSNApiHelper::ToJSHandle(value); bool result = JSTaggedValue::SetProperty(vm->GetJSThread(), object, keyValue, valueValue); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); object->GetTaggedObject()->GetClass()->SetIsNativeBindingObject(true); return result; } bool ObjectRef::Set(const EcmaVM *vm, Local key, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); [[maybe_unused]] LocalScope scope(vm); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); JSHandle keyValue = JSNApiHelper::ToJSHandle(key); JSHandle valueValue = JSNApiHelper::ToJSHandle(value); if (!obj->IsHeapObject()) { return JSTaggedValue::SetProperty(thread, obj, keyValue, valueValue); } return ObjectFastOperator::FastSetPropertyByValue(thread, obj.GetTaggedValue(), keyValue.GetTaggedValue(), valueValue.GetTaggedValue()); } bool ObjectRef::Set(const EcmaVM *vm, const char *utf8, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); [[maybe_unused]] LocalScope scope(vm); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); ObjectFactory *factory = vm->GetFactory(); JSHandle keyValue(factory->NewFromUtf8(utf8)); JSTaggedValue valueValue = JSNApiHelper::ToJSTaggedValue(*value); if (!obj->IsHeapObject()) { return JSTaggedValue::SetProperty(thread, obj, keyValue, JSHandle(thread, valueValue)); } JSTaggedValue res = ObjectFastOperator::TrySetPropertyByNameThroughCacheAtLocal(thread, obj.GetTaggedValue(), keyValue.GetTaggedValue(), valueValue); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); if (!res.IsHole()) { return !res.IsException(); } if (!JSNApi::KeyIsNumber(utf8)) { res = ObjectFastOperator::SetPropertyByName(thread, obj.GetTaggedValue(), keyValue.GetTaggedValue(), valueValue); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); if (!res.IsHole()) { return !res.IsException(); } return JSTaggedValue::SetProperty(thread, JSHandle(thread, obj.GetTaggedValue()), keyValue, JSHandle(thread, valueValue), true); } return ObjectFastOperator::FastSetPropertyByValue(thread, obj.GetTaggedValue(), keyValue.GetTaggedValue(), valueValue); } bool ObjectRef::Set(const EcmaVM *vm, uint32_t key, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); [[maybe_unused]] LocalScope scope(vm); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); JSHandle valueValue = JSNApiHelper::ToJSHandle(value); if (!obj->IsHeapObject()) { return JSTaggedValue::SetProperty(thread, obj, key, valueValue); } return ObjectFastOperator::FastSetPropertyByIndex(thread, obj.GetTaggedValue(), key, valueValue.GetTaggedValue()); } bool ObjectRef::SetAccessorProperty(const EcmaVM *vm, Local key, Local getter, Local setter, PropertyAttribute attribute) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); [[maybe_unused]] LocalScope scope(vm); 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); LOG_IF_SPECIAL(obj, ERROR); JSHandle keyValue = JSNApiHelper::ToJSHandle(key); return JSTaggedValue::DefineOwnProperty(thread, obj, keyValue, desc); } Local ObjectRef::Get(const EcmaVM *vm, Local key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedValue result; { LocalScope scope(vm); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); JSHandle keyValue = JSNApiHelper::ToJSHandle(key); if (UNLIKELY(!obj->IsHeapObject())) { OperationResult ret = JSTaggedValue::GetProperty(thread, obj, keyValue); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); result = ret.GetValue().GetTaggedValue(); } else { result = ObjectFastOperator::FastGetPropertyByValue(thread, obj.GetTaggedValue(), keyValue.GetTaggedValue()); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); } } JSHandle resultValue(thread, result); return JSNApiHelper::ToLocal(resultValue); } Local ObjectRef::Get(const EcmaVM *vm, const char *utf8) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedValue result; { LocalScope scope(vm); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); ObjectFactory *factory = vm->GetFactory(); JSHandle keyValue(factory->NewFromUtf8(utf8)); if (UNLIKELY(!obj->IsHeapObject())) { OperationResult ret = JSTaggedValue::GetProperty(thread, obj, keyValue); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); result = ret.GetValue().GetTaggedValue(); } else { result = ObjectFastOperator::FastGetPropertyByValue(thread, obj.GetTaggedValue(), keyValue.GetTaggedValue()); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); } } JSHandle resultValue(thread, result); return JSNApiHelper::ToLocal(resultValue); } Local ObjectRef::Get(const EcmaVM *vm, int32_t key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedValue result; { LocalScope scope(vm); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); if (!obj->IsHeapObject()) { OperationResult ret = JSTaggedValue::GetProperty(thread, obj, key); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); result = ret.GetValue().GetTaggedValue(); } else { result = ObjectFastOperator::FastGetPropertyByIndex(thread, obj.GetTaggedValue(), key); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); } } JSHandle resultValue(thread, result); return JSNApiHelper::ToLocal(resultValue); } bool ObjectRef::GetOwnProperty(const EcmaVM *vm, Local key, PropertyAttribute &property) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(obj, ERROR); 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) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(obj, ERROR); JSHandle array(JSTaggedValue::GetOwnPropertyKeys(thread, obj)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); JSHandle jsArray(JSArray::CreateArrayFromList(thread, array)); return JSNApiHelper::ToLocal(jsArray); } Local ObjectRef::GetAllPropertyNames(const EcmaVM *vm, uint32_t filter) { // This interface is only used by napi. // This interface currently only supports normal objects. CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(obj, ERROR); JSHandle array(JSTaggedValue::GetAllPropertyKeys(thread, obj, filter)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); JSHandle jsArray(JSArray::CreateArrayFromList(thread, array)); return JSNApiHelper::ToLocal(jsArray); } Local ObjectRef::GetOwnEnumerablePropertyNames(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle obj(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(obj, ERROR); JSHandle array(JSObject::EnumerableOwnNames(thread, obj)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); JSHandle jsArray(JSArray::CreateArrayFromList(thread, array)); return JSNApiHelper::ToLocal(jsArray); } Local ObjectRef::GetPrototype(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(object, ERROR); JSHandle prototype(thread, JSTaggedValue::GetPrototype(thread, JSHandle(object))); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(prototype); } bool ObjectRef::SetPrototype(const EcmaVM *vm, Local prototype) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); JSHandle proto(JSNApiHelper::ToJSHandle(prototype)); return JSTaggedValue::SetPrototype(thread, JSHandle(object), JSHandle(proto)); } bool ObjectRef::DefineProperty(const EcmaVM *vm, Local key, PropertyAttribute attribute) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(object, ERROR); JSHandle keyValue(JSNApiHelper::ToJSHandle(key)); PropertyDescriptor desc(thread, attribute.IsWritable(), attribute.IsEnumerable(), attribute.IsConfigurable()); desc.SetValue(JSNApiHelper::ToJSHandle(attribute.GetValue(vm))); return JSTaggedValue::DefinePropertyOrThrow(thread, object, keyValue, desc); } bool ObjectRef::Has(const EcmaVM *vm, Local key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(object, ERROR); JSHandle keyValue(JSNApiHelper::ToJSHandle(key)); return JSTaggedValue::HasProperty(thread, object, keyValue); } bool ObjectRef::Has(const EcmaVM *vm, uint32_t key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(object, ERROR); return JSTaggedValue::HasProperty(thread, object, key); } bool ObjectRef::HasOwnProperty(const EcmaVM *vm, Local key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(object, ERROR); JSHandle keyValue(JSNApiHelper::ToJSHandle(key)); return JSTaggedValue::HasOwnProperty(thread, object, keyValue); } bool ObjectRef::Delete(const EcmaVM *vm, Local key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(object, ERROR); JSHandle keyValue(JSNApiHelper::ToJSHandle(key)); return JSTaggedValue::DeleteProperty(thread, object, keyValue); } bool ObjectRef::Delete(const EcmaVM *vm, uint32_t key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(object, ERROR); JSHandle keyHandle(thread, JSTaggedValue(key)); return JSTaggedValue::DeleteProperty(thread, object, keyHandle); } Local ObjectRef::Freeze(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle object = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(object, ERROR); JSHandle obj(object); bool status = JSObject::SetIntegrityLevel(thread, obj, ecmascript::IntegrityLevel::FROZEN); if (JSNApi::HasPendingException(vm)) { JSHandle exception(thread, JSTaggedValue::Exception()); return scope.Escape(JSNApiHelper::ToLocal(exception)); } if (!status) { LOG_ECMA(ERROR) << "Freeze: freeze failed"; Local message = StringRef::NewFromUtf8(vm, "Freeze: freeze failed"); Local error = Exception::Error(vm, message); JSNApi::ThrowException(vm, error); JSHandle exception(thread, JSTaggedValue::Exception()); return scope.Escape(JSNApiHelper::ToLocal(exception)); } JSHandle resultValue(obj); return scope.Escape(JSNApiHelper::ToLocal(resultValue)); } Local ObjectRef::Seal(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle object = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(object, ERROR); JSHandle obj(object); bool status = JSObject::SetIntegrityLevel(thread, obj, ecmascript::IntegrityLevel::SEALED); if (JSNApi::HasPendingException(vm)) { JSHandle exception(thread, JSTaggedValue::Exception()); return scope.Escape(JSNApiHelper::ToLocal(exception)); } if (!status) { LOG_ECMA(ERROR) << "Seal: seal failed"; Local message = StringRef::NewFromUtf8(vm, "Freeze: freeze failed"); Local error = Exception::Error(vm, message); JSNApi::ThrowException(vm, error); JSHandle exception(thread, JSTaggedValue::Exception()); return scope.Escape(JSNApiHelper::ToLocal(exception)); } JSHandle resultValue(obj); return scope.Escape(JSNApiHelper::ToLocal(resultValue)); } void ObjectRef::SetNativePointerFieldCount(const EcmaVM *vm, int32_t count) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); // ObjectRef::New may return special value if exception occurs. // So we need do special value check before use it. DCHECK_SPECIAL_VALUE(this); JSHandle object(JSNApiHelper::ToJSHandle(this)); object->SetNativePointerFieldCount(thread, count); } int32_t ObjectRef::GetNativePointerFieldCount(const EcmaVM *vm) { // ObjectRef::New may return special value if exception occurs. // So we need do special value check before use it. DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); return object->GetNativePointerFieldCount(); } void *ObjectRef::GetNativePointerField(const EcmaVM *vm, int32_t index) { // ObjectRef::New may return special value if exception occurs. // So we need do special value check before use it. DCHECK_SPECIAL_VALUE_WITH_RETURN(this, nullptr); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object(JSNApiHelper::ToJSHandle(this)); return object->GetNativePointerField(index); } void ObjectRef::SetNativePointerField(const EcmaVM *vm, int32_t index, void *nativePointer, NativePointerCallback callBack, void *data, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); // ObjectRef::New may return special value if exception occurs. // So we need do special value check before use it. DCHECK_SPECIAL_VALUE(this); JSHandle object(JSNApiHelper::ToJSHandle(this)); object->SetNativePointerField(thread, index, nativePointer, callBack, data, nativeBindingsize); } void ObjectRef::SetConcurrentNativePointerField(const EcmaVM *vm, int32_t index, void *nativePointer, NativePointerCallback callBack, void *data, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); // ObjectRef::New may return special value if exception occurs. // So we need do special value check before use it. DCHECK_SPECIAL_VALUE(this); JSHandle object(JSNApiHelper::ToJSHandle(this)); object->SetNativePointerField(thread, index, nativePointer, callBack, data, nativeBindingsize, Concurrent::YES); } // -------------------------------- NativePointerRef ------------------------------------ Local NativePointerRef::New(const EcmaVM *vm, void *nativePointer, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle obj = factory->NewJSNativePointer(nativePointer, nullptr, nullptr, false, nativeBindingsize); return JSNApiHelper::ToLocal(JSHandle(obj)); } Local NativePointerRef::New( const EcmaVM *vm, void *nativePointer, NativePointerCallback callBack, void *data, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle obj = factory->NewJSNativePointer(nativePointer, callBack, data, false, nativeBindingsize); return JSNApiHelper::ToLocal(JSHandle(obj)); } Local NativePointerRef::NewConcurrent( const EcmaVM *vm, void *nativePointer, NativePointerCallback callBack, void *data, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); ObjectFactory *factory = vm->GetFactory(); JSHandle obj = factory->NewJSNativePointer(nativePointer, callBack, data, false, nativeBindingsize, Concurrent::YES); return JSNApiHelper::ToLocal(JSHandle(obj)); } Local NativePointerRef::NewSendable( const EcmaVM *vm, void *nativePointer, NativePointerCallback callBack, void *data, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle obj = factory->NewSJSNativePointer(nativePointer, callBack, data, false, nativeBindingsize); return JSNApiHelper::ToLocal(JSHandle(obj)); } void *NativePointerRef::Value() { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, nullptr); JSHandle nativePointer = JSNApiHelper::ToJSHandle(this); return JSHandle(nativePointer)->GetExternalPointer(); } // ---------------------------------- Buffer ----------------------------------- Local ArrayBufferRef::New(const EcmaVM *vm, int32_t length) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle arrayBuffer = factory->NewJSArrayBuffer(length); return JSNApiHelper::ToLocal(JSHandle(arrayBuffer)); } Local ArrayBufferRef::New( const EcmaVM *vm, void *buffer, int32_t length, const NativePointerCallback &deleter, void *data) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle arrayBuffer = factory->NewJSArrayBuffer(buffer, length, deleter, data); return JSNApiHelper::ToLocal(JSHandle(arrayBuffer)); } int32_t ArrayBufferRef::ByteLength(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(arrayBuffer, FATAL); return arrayBuffer->GetArrayBufferByteLength(); } void *ArrayBufferRef::GetBuffer(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, nullptr); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); JSTaggedValue bufferData = arrayBuffer->GetArrayBufferData(); if (!bufferData.IsJSNativePointer()) { return nullptr; } return JSNativePointer::Cast(bufferData.GetTaggedObject())->GetExternalPointer(); } void ArrayBufferRef::Detach(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); // arraybuffer is not shared. Do not need to switch state JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); arrayBuffer->Detach(thread); } bool ArrayBufferRef::IsDetach(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); return arrayBuffer->IsDetach(); } Local SendableArrayBufferRef::New(const EcmaVM *vm, int32_t length) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle arrayBuffer = factory->NewJSSendableArrayBuffer(length); return JSNApiHelper::ToLocal(JSHandle(arrayBuffer)); } Local SendableArrayBufferRef::New( const EcmaVM *vm, void *buffer, int32_t length, const NativePointerCallback &deleter, void *data) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle arrayBuffer = factory->NewJSSendableArrayBuffer(buffer, length, deleter, data); return JSNApiHelper::ToLocal(JSHandle(arrayBuffer)); } int32_t SendableArrayBufferRef::ByteLength(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(arrayBuffer, FATAL); return arrayBuffer->GetArrayBufferByteLength(); } void SendableArrayBufferRef::Detach(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); arrayBuffer->Detach(thread); } bool SendableArrayBufferRef::IsDetach(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); return arrayBuffer->IsDetach(); } void *SendableArrayBufferRef::GetBuffer(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, nullptr); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); JSTaggedValue bufferData = arrayBuffer->GetArrayBufferData(); if (!bufferData.IsJSNativePointer()) { return nullptr; } return JSNativePointer::Cast(bufferData.GetTaggedObject())->GetExternalPointer(); } // ---------------------------------- DateRef ----------------------------------- Local DateRef::New(const EcmaVM *vm, double time) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle dateFunction(globalEnv->GetDateFunction()); JSHandle dateObject(factory->NewJSObjectByConstructor(dateFunction)); dateObject->SetTimeValue(thread, JSTaggedValue(time)); return JSNApiHelper::ToLocal(JSHandle(dateObject)); } Local DateRef::ToString(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle date(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(date, ERROR); 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); } double DateRef::GetTime(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0.0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle date(JSNApiHelper::ToJSHandle(this)); if (!date->IsDate()) { LOG_ECMA(ERROR) << "Not a Date Object"; } return date->GetTime().GetDouble(); } // ---------------------------------- TypedArray ----------------------------------- uint32_t TypedArrayRef::ByteLength(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(typedArray, FATAL); return typedArray->GetByteLength(); } uint32_t TypedArrayRef::ByteOffset(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(typedArray, FATAL); return typedArray->GetByteOffset(); } uint32_t TypedArrayRef::ArrayLength(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(typedArray, FATAL); return typedArray->GetArrayLength(); } Local TypedArrayRef::GetArrayBuffer(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); JSHandle typeArray(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(typeArray, ERROR); JSHandle arrayBuffer(thread, JSTypedArray::GetOffHeapBuffer(thread, typeArray)); return JSNApiHelper::ToLocal(arrayBuffer); } uint32_t SendableTypedArrayRef::ByteLength(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(typedArray, FATAL); return typedArray->GetByteLength(); } uint32_t SendableTypedArrayRef::ByteOffset(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(typedArray, FATAL); return typedArray->GetByteOffset(); } uint32_t SendableTypedArrayRef::ArrayLength(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(typedArray, FATAL); return typedArray->GetArrayLength(); } Local SendableTypedArrayRef::GetArrayBuffer(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); JSHandle typeArray(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(typeArray, ERROR); JSHandle arrayBuffer(thread, ecmascript::JSSharedTypedArray::GetSharedOffHeapBuffer(thread, typeArray)); return JSNApiHelper::ToLocal(arrayBuffer); } // ----------------------------------- FunctionRef -------------------------------------- Local FunctionRef::New(EcmaVM *vm, FunctionCallback nativeFunc, NativePointerCallback deleter, void *data, bool callNapi, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle current(factory->NewJSFunction(env, reinterpret_cast(Callback::RegisterCallback))); current->SetFunctionExtraInfo(thread, reinterpret_cast(nativeFunc), deleter, data, nativeBindingsize); current->SetCallNapi(callNapi); return JSNApiHelper::ToLocal(JSHandle(current)); } Local FunctionRef::NewConcurrent(EcmaVM *vm, FunctionCallback nativeFunc, NativePointerCallback deleter, void *data, bool callNapi, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle current(factory->NewJSFunction(env, reinterpret_cast(Callback::RegisterCallback))); current->SetFunctionExtraInfo(thread, reinterpret_cast(nativeFunc), deleter, data, nativeBindingsize, Concurrent::YES); current->SetCallNapi(callNapi); return JSNApiHelper::ToLocal(JSHandle(current)); } Local FunctionRef::New(EcmaVM *vm, InternalFunctionCallback nativeFunc, NativePointerCallback deleter, void *data, bool callNapi, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle current(factory->NewJSFunction(env, reinterpret_cast(nativeFunc))); current->SetFunctionExtraInfo(thread, nullptr, deleter, data, nativeBindingsize); current->SetCallNapi(callNapi); return JSNApiHelper::ToLocal(JSHandle(current)); } Local FunctionRef::NewSendable(EcmaVM *vm, InternalFunctionCallback nativeFunc, NativePointerCallback deleter, void *data, bool callNapi, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle current(factory->NewSFunction(env, reinterpret_cast(nativeFunc))); current->SetSFunctionExtraInfo(thread, nullptr, deleter, data, nativeBindingsize); current->SetCallNapi(callNapi); return JSNApiHelper::ToLocal(JSHandle(current)); } Local FunctionRef::NewConcurrent(EcmaVM *vm, InternalFunctionCallback nativeFunc, NativePointerCallback deleter, void *data, bool callNapi, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle current(factory->NewJSFunction(env, reinterpret_cast(nativeFunc))); current->SetFunctionExtraInfo(thread, nullptr, deleter, data, nativeBindingsize, Concurrent::YES); current->SetCallNapi(callNapi); return JSNApiHelper::ToLocal(JSHandle(current)); } static void InitClassFunction(EcmaVM *vm, JSHandle &func, bool callNapi) { CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle env = vm->GetGlobalEnv(); auto globalConst = thread->GlobalConstants(); JSHandle accessor = globalConst->GetHandledFunctionPrototypeAccessor(); func->SetPropertyInlinedProps(thread, JSFunction::CLASS_PROTOTYPE_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue()); accessor = globalConst->GetHandledFunctionLengthAccessor(); func->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue()); JSHandle clsPrototype = JSFunction::NewJSFunctionPrototype(thread, func); clsPrototype->GetClass()->SetClassPrototype(true); func->SetClassConstructor(true); JSHandle parent = env->GetFunctionPrototype(); JSObject::SetPrototype(thread, JSHandle::Cast(func), parent); func->SetHomeObject(thread, clsPrototype); func->SetCallNapi(callNapi); } Local FunctionRef::NewClassFunction(EcmaVM *vm, FunctionCallback nativeFunc, NativePointerCallback deleter, void *data, bool callNapi, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle hclass = JSHandle::Cast(env->GetFunctionClassWithoutName()); JSHandle current = factory->NewJSFunctionByHClass(reinterpret_cast(Callback::RegisterCallback), hclass, ecmascript::FunctionKind::CLASS_CONSTRUCTOR); InitClassFunction(vm, current, callNapi); current->SetFunctionExtraInfo(thread, reinterpret_cast(nativeFunc), deleter, data, nativeBindingsize); Local result = JSNApiHelper::ToLocal(JSHandle(current)); return scope.Escape(result); } Local FunctionRef::NewConcurrentClassFunction(EcmaVM *vm, InternalFunctionCallback nativeFunc, NativePointerCallback deleter, void *data, bool callNapi, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle hclass = JSHandle::Cast(env->GetFunctionClassWithoutName()); JSHandle current = factory->NewJSFunctionByHClass(reinterpret_cast(nativeFunc), hclass, ecmascript::FunctionKind::CLASS_CONSTRUCTOR); InitClassFunction(vm, current, callNapi); current->SetFunctionExtraInfo(thread, nullptr, deleter, data, nativeBindingsize, Concurrent::YES); Local result = JSNApiHelper::ToLocal(JSHandle(current)); return scope.Escape(result); } Local FunctionRef::NewClassFunction(EcmaVM *vm, InternalFunctionCallback nativeFunc, NativePointerCallback deleter, void *data, bool callNapi, size_t nativeBindingsize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle hclass = JSHandle::Cast(env->GetFunctionClassWithoutName()); JSHandle current = factory->NewJSFunctionByHClass(reinterpret_cast(nativeFunc), hclass, ecmascript::FunctionKind::CLASS_CONSTRUCTOR); InitClassFunction(vm, current, callNapi); current->SetFunctionExtraInfo(thread, nullptr, deleter, data, nativeBindingsize); Local result = JSNApiHelper::ToLocal(JSHandle(current)); return scope.Escape(result); } Local FunctionRef::NewSendableClassFunction(const EcmaVM *vm, InternalFunctionCallback nativeFunc, NativePointerCallback deleter, void *data, Local name, SendablePropertiesInfos &infos, Local parent, bool callNapi, size_t nativeBindingSize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); EscapeLocalScope scope(vm); ObjectFactory *factory = vm->GetFactory(); bool hasParent = !parent->IsNull(); JSNapiSendable sendable(thread, infos, name); JSHandle prototypeHClass = JSHClass::CreateSPrototypeHClass(thread, sendable.GetNonStaticDescs()); JSHandle prototype = factory->NewSharedOldSpaceJSObject(prototypeHClass); JSHandle constructorHClass = JSHClass::CreateSConstructorHClass(thread, sendable.GetStaticDescs()); JSHandle constructor = factory->NewSFunctionByHClass( reinterpret_cast(nativeFunc), constructorHClass, ecmascript::FunctionKind::CLASS_CONSTRUCTOR); sendable.SetSConstructor(constructor); JSObject::SetSProperties(thread, prototype, sendable.GetNonStaticDescs()); JSObject::SetSProperties(thread, JSHandle::Cast(constructor), sendable.GetStaticDescs()); if (hasParent) { auto parentPrototype = parent->GetFunctionPrototype(vm); prototypeHClass->SetPrototype(thread, JSNApiHelper::ToJSHandle(parentPrototype)); constructorHClass->SetPrototype(thread, JSNApiHelper::ToJSHandle(parent)); } prototypeHClass->SetExtensible(false); constructor->SetHomeObject(thread, prototype); constructor->SetProtoOrHClass(thread, prototype); constructor->SetLexicalEnv(thread, constructor); constructor->SetCallNapi(callNapi); constructor->SetSFunctionExtraInfo(thread, nullptr, deleter, data, nativeBindingSize); JSHClass *parentIHClass{nullptr}; if (hasParent) { JSHandle parentHandle(JSNApiHelper::ToJSHandle(parent)); parentIHClass = reinterpret_cast(parentHandle->GetProtoOrHClass().GetTaggedObject()); } JSHandle iHClass = JSHClass::CreateSHClass(thread, sendable.GetInstanceDescs(), parentIHClass); iHClass->SetPrototype(thread, JSHandle(prototype)); iHClass->SetExtensible(false); constructor->SetProtoOrHClass(thread, iHClass); constructorHClass->SetExtensible(false); Local result = JSNApiHelper::ToLocal(JSHandle(constructor)); return scope.Escape(result); } Local FunctionRef::Call(const EcmaVM *vm, Local thisObj, const Local argv[], // NOLINTNEXTLINE(modernize-avoid-c-arrays) int32_t length) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); FunctionCallScope callScope(EcmaVM::ConstCast(vm)); if (!IsFunction(vm)) { return JSValueRef::Undefined(vm); } vm->GetJsDebuggerManager()->ClearSingleStepper(); JSHandle func = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(func, ERROR); JSHandle thisValue = JSNApiHelper::ToJSHandle(thisObj); JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, func, thisValue, undefined, length); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); for (int32_t i = 0; i < length; i++) { JSHandle arg = JSNApiHelper::ToJSHandle(argv[i]); #if ECMASCRIPT_ENABLE_STUB_ARGV_CHECK thread->CheckJSTaggedType(arg.GetTaggedValue().GetRawData()); #endif info->SetCallArg(i, arg.GetTaggedValue()); } JSTaggedValue result = JSFunction::Call(info); #if ECMASCRIPT_ENABLE_STUB_RESULT_CHECK thread->CheckJSTaggedType(result.GetRawData()); #endif if (thread->HasPendingException()) { ecmascript::JsStackInfo::BuildCrashInfo(thread); } RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); JSHandle resultValue(thread, result); thread->GetCurrentEcmaContext()->ClearKeptObjects(); vm->GetJsDebuggerManager()->NotifyReturnNative(); return scope.Escape(JSNApiHelper::ToLocal(resultValue)); } JSValueRef* FunctionRef::CallForNapi(const EcmaVM *vm, JSValueRef *thisObj, JSValueRef *const argv[], // NOLINTNEXTLINE(modernize-avoid-c-arrays) int32_t length) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, *JSValueRef::Hole(vm)); ecmascript::ThreadManagedScope managedScope(thread); JSTaggedValue result; FunctionCallScope callScope(EcmaVM::ConstCast(vm)); ASSERT(IsFunction(vm)); // IsFunction check has been done in napi. { LocalScope scope(vm); ecmascript::tooling::JsDebuggerManager *dm = vm->GetJsDebuggerManager(); bool isDebugApp = dm->IsDebugApp(); if (isDebugApp) { dm->ClearSingleStepper(); } JSTaggedValue func = *reinterpret_cast(this); JSTaggedValue undefined = thread->GlobalConstants()->GetUndefined(); JSTaggedValue thisValue = undefined; if (thisObj != nullptr) { thisValue = *reinterpret_cast(thisObj); } EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, func, thisValue, undefined, length); RETURN_VALUE_IF_ABRUPT(thread, *JSValueRef::Hole(vm)); for (int32_t i = 0; i < length; i++) { if (argv[i]) { #if ECMASCRIPT_ENABLE_STUB_ARGV_CHECK thread->CheckJSTaggedType(JSNApiHelper::ToJSTaggedValue(argv[i]).GetRawData()); #endif // NewRuntimeCallInfo has set Undefined defaultly in Argv's slot. info->SetCallArg(i, JSNApiHelper::ToJSTaggedValue(argv[i])); } } if (LIKELY(thread->IsAsmInterpreter())) { STACK_LIMIT_CHECK(thread, reinterpret_cast(*JSValueRef::Hole(vm))); auto *hclass = func.GetTaggedObject()->GetClass(); if (hclass->IsClassConstructor()) { RETURN_STACK_BEFORE_THROW_IF_ASM(thread); THROW_TYPE_ERROR_AND_RETURN(thread, "class constructor cannot call", reinterpret_cast(*JSValueRef::Hole(vm))); } result = ecmascript::InterpreterAssembly::Execute(info); } else { result = JSFunction::Call(info); } #if ECMASCRIPT_ENABLE_STUB_RESULT_CHECK thread->CheckJSTaggedType(result.GetRawData()); #endif RETURN_VALUE_IF_ABRUPT(thread, *JSValueRef::Hole(vm)); if (thread->GetCurrentEcmaContext()->HasKeptObjects()) { thread->GetCurrentEcmaContext()->ClearKeptObjects(); } if (isDebugApp && dm->IsMixedDebugEnabled()) { dm->NotifyReturnNative(); } } JSHandle resultValue(thread, result); return reinterpret_cast(resultValue.GetAddress()); } Local FunctionRef::Constructor(const EcmaVM *vm, const Local argv[], // NOLINTNEXTLINE(modernize-avoid-c-arrays) int32_t length) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); FunctionCallScope callScope(EcmaVM::ConstCast(vm)); if (!IsFunction(vm)) { return JSValueRef::Undefined(vm); } JSHandle func = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(func, ERROR); JSHandle newTarget = func; JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, func, undefined, newTarget, length); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); for (int32_t i = 0; i < length; i++) { JSHandle arg = JSNApiHelper::ToJSHandle(argv[i]); #if ECMASCRIPT_ENABLE_STUB_ARGV_CHECK thread->CheckJSTaggedType(arg.GetTaggedValue().GetRawData()); #endif info->SetCallArg(i, arg.GetTaggedValue()); } JSTaggedValue result = JSFunction::Construct(info); #if ECMASCRIPT_ENABLE_STUB_RESULT_CHECK thread->CheckJSTaggedType(result.GetRawData()); #endif RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); JSHandle resultValue(thread, result); return JSNApiHelper::ToLocal(resultValue); } JSValueRef* FunctionRef::ConstructorOptimize(const EcmaVM *vm, JSValueRef* argv[], // NOLINTNEXTLINE(modernize-avoid-c-arrays) int32_t length) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, *JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedValue result; FunctionCallScope callScope(EcmaVM::ConstCast(vm)); ASSERT(IsFunction(vm)); // IsFunction check has been done in napi. { LocalScope scope(vm); JSTaggedValue func = *reinterpret_cast(this); JSTaggedValue newTarget = func; JSTaggedValue undefined = thread->GlobalConstants()->GetUndefined(); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, func, undefined, newTarget, length); RETURN_VALUE_IF_ABRUPT(thread, *JSValueRef::Undefined(vm)); for (int32_t i = 0; i < length; ++i) { JSTaggedValue arg = argv[i] == nullptr ? JSTaggedValue::Undefined() : JSNApiHelper::ToJSTaggedValue(argv[i]); #if ECMASCRIPT_ENABLE_STUB_ARGV_CHECK thread->CheckJSTaggedType(arg.GetRawData()); #endif info->SetCallArg(i, arg); } result = JSFunction::ConstructInternal(info); RETURN_VALUE_IF_ABRUPT(thread, *JSValueRef::Undefined(vm)); } #if ECMASCRIPT_ENABLE_STUB_RESULT_CHECK thread->CheckJSTaggedType(result.GetRawData()); #endif JSHandle resultValue(thread, result); return reinterpret_cast(resultValue.GetAddress()); } Local FunctionRef::GetFunctionPrototype(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle func = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(func, FATAL); JSHandle prototype(thread, JSHandle(func)->GetFunctionPrototype()); return JSNApiHelper::ToLocal(prototype); } bool FunctionRef::Inherit(const EcmaVM *vm, Local parent) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); [[maybe_unused]] LocalScope scope(vm); JSHandle parentValue = JSNApiHelper::ToJSHandle(parent); JSHandle parentHandle = JSHandle::Cast(parentValue); JSHandle thisHandle = JSHandle::Cast(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(thisHandle, ERROR); // Set this.__proto__ to parent bool res = JSObject::SetPrototype(thread, thisHandle, parentValue); if (!res) { return false; } // Set this.Prototype.__proto__ to parent.Prototype JSHandle parentProtoType(thread, JSFunction::PrototypeGetter(thread, parentHandle)); JSHandle thisProtoType(thread, JSFunction::PrototypeGetter(thread, thisHandle)); return JSObject::SetPrototype(thread, JSHandle::Cast(thisProtoType), parentProtoType); } void FunctionRef::SetName(const EcmaVM *vm, Local name) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); [[maybe_unused]] LocalScope scope(vm); JSFunction *func = JSFunction::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject()); JSTaggedValue key = JSNApiHelper::ToJSTaggedValue(*name); JSFunction::SetFunctionNameNoPrefix(thread, func, key); } Local FunctionRef::GetName(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle func(thread, JSNApiHelper::ToJSTaggedValue(this)); JSHandle name = JSFunctionBase::GetFunctionName(thread, func); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return scope.Escape(JSNApiHelper::ToLocal(name)); } Local FunctionRef::GetSourceCode(const EcmaVM *vm, int lineNumber) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle func(thread, JSNApiHelper::ToJSTaggedValue(this)); JSHandle method(thread, func->GetMethod()); const JSPandaFile *jsPandaFile = method->GetJSPandaFile(); DebugInfoExtractor *debugExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile); ecmascript::CString entry = JSPandaFile::ENTRY_FUNCTION_NAME; if (!jsPandaFile->IsBundlePack()) { JSFunction *function = JSFunction::Cast(func.GetTaggedValue().GetTaggedObject()); ecmascript::CString recordName = function->GetRecordName(); ASSERT(!recordName.empty()); entry = recordName; } uint32_t mainMethodIndex = jsPandaFile->GetMainMethodIndex(entry); JSMutableHandle sourceCodeHandle(thread, BuiltinsBase::GetTaggedString(thread, "")); if (mainMethodIndex == 0) { return scope.Escape(JSNApiHelper::ToLocal(sourceCodeHandle)); } const std::string &allSourceCode = debugExtractor->GetSourceCode(panda_file::File::EntityId(mainMethodIndex)); std::string sourceCode = StringHelper::GetSpecifiedLine(allSourceCode, lineNumber); uint32_t codeLen = sourceCode.length(); if (codeLen == 0) { return scope.Escape(JSNApiHelper::ToLocal(sourceCodeHandle)); } if (sourceCode[codeLen - 1] == '\r') { sourceCode = sourceCode.substr(0, codeLen - 1); } sourceCodeHandle.Update(BuiltinsBase::GetTaggedString(thread, sourceCode.c_str())); return scope.Escape(JSNApiHelper::ToLocal(sourceCodeHandle)); } bool FunctionRef::IsNative(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle func(thread, JSNApiHelper::ToJSTaggedValue(this)); JSHandle method(thread, func->GetMethod()); return method->IsNativeWithCallField(); } void FunctionRef::SetData(const EcmaVM *vm, void *data, NativePointerCallback deleter, [[maybe_unused]] bool callNapi) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle funcValue = JSNApiHelper::ToJSHandle(this); JSHandle function(funcValue); if (function->IsJSShared()) { function->SetSFunctionExtraInfo(thread, nullptr, deleter, data, 0); } else { function->SetFunctionExtraInfo(thread, nullptr, deleter, data, 0); } } void* FunctionRef::GetData(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, nullptr); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle funcValue = JSNApiHelper::ToJSHandle(this); JSHandle function(funcValue); JSTaggedValue extraInfoValue = function->GetFunctionExtraInfo(); if (!extraInfoValue.IsNativePointer()) { return nullptr; } auto extraInfo = JSNativePointer::Cast(extraInfoValue.GetTaggedObject()); return extraInfo->GetData(); } // ----------------------------------- ArrayRef ---------------------------------------- Local ArrayRef::New(const EcmaVM *vm, uint32_t length) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedNumber arrayLen(length); JSHandle array = JSArray::ArrayCreate(thread, arrayLen); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(array); } uint32_t ArrayRef::Length(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); return JSArray::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject())->GetArrayLength(); } Local ArrayRef::GetValueAt(const EcmaVM *vm, Local obj, uint32_t index) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(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) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle objectHandle = JSNApiHelper::ToJSHandle(obj); JSHandle valueHandle = JSNApiHelper::ToJSHandle(value); return JSArray::FastSetPropertyByValue(thread, objectHandle, index, valueHandle); } // ----------------------------------- SendableArrayRef ---------------------------------------- Local SendableArrayRef::New(const EcmaVM *vm, uint32_t length) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSTaggedNumber arrayLen(length); JSHandle array = ecmascript::JSSharedArray::ArrayCreate(thread, arrayLen); JSHandle initialValue(thread, JSTaggedValue::Undefined()); JSMutableHandle key(thread, JSTaggedValue::Undefined()); for (uint32_t i = 0; i < length; i++) { key.Update(JSTaggedValue(i)); JSObject::CreateDataPropertyOrThrow( thread, JSHandle(array), key, initialValue, ecmascript::JSShared::SCheckMode::SKIP); } RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(array); } uint32_t SendableArrayRef::Length(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return ecmascript::JSSharedArray::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject())->GetArrayLength(); } Local SendableArrayRef::GetValueAt(const EcmaVM *vm, Local obj, uint32_t index) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle object = JSNApiHelper::ToJSHandle(obj); JSHandle result = ecmascript::JSSharedArray::FastGetPropertyByValue(thread, object, index); return JSNApiHelper::ToLocal(result); } bool SendableArrayRef::SetProperty(const EcmaVM *vm, Local obj, uint32_t index, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle objectHandle = JSNApiHelper::ToJSHandle(obj); JSHandle valueHandle = JSNApiHelper::ToJSHandle(value); return ecmascript::JSSharedArray::SetProperty( thread, objectHandle, index, valueHandle, true, ecmascript::SCheckMode::CHECK); } // ---------------------------------- Error --------------------------------------- // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define EXCEPTION_ERROR_NEW(name, type) \ Local Exception::name(const EcmaVM *vm, Local message) \ { \ CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); \ ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); \ ObjectFactory *factory = vm->GetFactory(); \ \ JSHandle messageValue(JSNApiHelper::ToJSHandle(message)); \ JSHandle result(factory->NewJSError(ErrorType::type, \ messageValue, ecmascript::StackCheck::NO)); \ return JSNApiHelper::ToLocal(result); \ } EXCEPTION_ERROR_ALL(EXCEPTION_ERROR_NEW) #undef EXCEPTION_ERROR_NEW // ---------------------------------- Error --------------------------------------- // ---------------------------------- FunctionCallScope --------------------------------------- FunctionCallScope::FunctionCallScope(EcmaVM *vm) : vm_(vm) { vm_->IncreaseCallDepth(); } FunctionCallScope::~FunctionCallScope() { vm_->DecreaseCallDepth(); if (vm_->IsTopLevelCallDepth()) { JSThread *thread = vm_->GetJSThread(); ecmascript::ThreadManagedScope managedScope(vm_->GetJSThread()); thread->GetCurrentEcmaContext()->ExecutePromisePendingJob(); } } // ------------------------------------- JSExecutionScope ------------------------------ JSExecutionScope::JSExecutionScope([[maybe_unused]] const EcmaVM *vm) { } JSExecutionScope::~JSExecutionScope() { lastCurrentThread_ = nullptr; isRevert_ = false; } // ------------------------------------ JsiNativeScope ----------------------------------------------- JsiNativeScope::JsiNativeScope(const EcmaVM *vm) { thread_ = vm->GetAssociatedJSThread(); #if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT if (vm->IsCollectingScopeLockStats()) { const_cast(vm)->IncreaseEnterJsiNativeScopeCount(); const_cast(vm)->IncreaseUpdateThreadStateTransCount(); } #endif oldThreadState_ = static_cast(thread_->GetState()); thread_->UpdateState(ecmascript::ThreadState::NATIVE); } JsiNativeScope::~JsiNativeScope() { thread_->UpdateState(static_cast(oldThreadState_)); } // ------------------------------------ JsiFastNativeScope ----------------------------------------------- JsiFastNativeScope::JsiFastNativeScope(const EcmaVM *vm) { thread_ = vm->GetAssociatedJSThread(); #if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT if (vm->IsCollectingScopeLockStats()) { const_cast(vm)->IncreaseEnterFastNativeScopeCount(); const_cast(vm)->IncreaseUpdateThreadStateTransCount(); } #endif ecmascript::ThreadState oldState = thread_->GetState(); if (oldState == ecmascript::ThreadState::RUNNING) { return; } oldThreadState_ = static_cast(oldState); hasSwitchState_ = true; thread_->UpdateState(ecmascript::ThreadState::RUNNING); } JsiFastNativeScope::~JsiFastNativeScope() { if (hasSwitchState_) { thread_->UpdateState(static_cast(oldThreadState_)); } } // ------------------------------------ JsiRuntimeCallInfo ----------------------------------------------- void *JsiRuntimeCallInfo::GetData() { ecmascript::ThreadManagedScope managedScope(thread_); JSHandle constructor = BuiltinsBase::GetConstructor(reinterpret_cast(this)); if (!constructor->IsJSFunction()) { return nullptr; } JSHandle function(constructor); JSTaggedValue extraInfoValue = function->GetFunctionExtraInfo(); if (!extraInfoValue.IsJSNativePointer()) { return nullptr; } return JSNativePointer::Cast(extraInfoValue.GetTaggedObject())->GetData(); } EcmaVM *JsiRuntimeCallInfo::GetVM() const { return thread_->GetEcmaVM(); } // ---------------------------------------JSNApi------------------------------------------- PatchErrorCode JSNApi::LoadPatch(EcmaVM *vm, const std::string &patchFileName, const std::string &baseFileName) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, PatchErrorCode::INTERNAL_ERROR); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ecmascript::QuickFixManager *quickFixManager = vm->GetQuickFixManager(); return quickFixManager->LoadPatch(thread, patchFileName, baseFileName); } PatchErrorCode JSNApi::LoadPatch(EcmaVM *vm, const std::string &patchFileName, uint8_t *patchBuffer, size_t patchSize, const std::string &baseFileName, uint8_t *baseBuffer, size_t baseSize) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, PatchErrorCode::INTERNAL_ERROR); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ecmascript::QuickFixManager *quickFixManager = vm->GetQuickFixManager(); return quickFixManager->LoadPatch( thread, patchFileName, patchBuffer, patchSize, baseFileName, baseBuffer, baseSize); } PatchErrorCode JSNApi::UnloadPatch(EcmaVM *vm, const std::string &patchFileName) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, PatchErrorCode::INTERNAL_ERROR); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); ecmascript::QuickFixManager *quickFixManager = vm->GetQuickFixManager(); return quickFixManager->UnloadPatch(thread, patchFileName); } /* * check whether the exception is caused by quickfix methods. */ bool JSNApi::IsQuickFixCausedException(EcmaVM *vm, Local exception, const std::string &patchFileName) { if (exception.IsEmpty()) { return false; } CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(thread); ecmascript::QuickFixManager *quickFixManager = vm->GetQuickFixManager(); JSHandle exceptionInfo = JSNApiHelper::ToJSHandle(exception); return quickFixManager->IsQuickFixCausedException(thread, exceptionInfo, patchFileName); } /* * register quickfix query function. */ void JSNApi::RegisterQuickFixQueryFunc(EcmaVM *vm, std::function callBack) { CROSS_THREAD_CHECK(vm); ecmascript::QuickFixManager *quickFixManager = vm->GetQuickFixManager(); quickFixManager->RegisterQuickFixQueryFunc(callBack); } bool JSNApi::IsBundle(EcmaVM *vm) { return vm->IsBundlePack(); } void JSNApi::SetBundle(EcmaVM *vm, bool value) { vm->SetIsBundlePack(value); } bool JSNApi::IsNormalizedOhmUrlPack(EcmaVM *vm) { return vm->IsNormalizedOhmUrlPack(); } bool JSNApi::IsOhmUrl(const std::string &srcName) { return ModulePathHelper::IsOhmUrl(srcName.c_str()); } void JSNApi::SetModuleInfo(EcmaVM *vm, const std::string &assetPath, const std::string &entryPoint) { SetAssetPath(vm, assetPath); size_t pos = entryPoint.find_first_of("/"); if (pos != std::string::npos) { SetBundleName(vm, entryPoint.substr(0, pos)); ecmascript::CString moduleName = ModulePathHelper::GetModuleName(entryPoint.c_str()); if (!moduleName.empty()) { SetModuleName(vm, moduleName.c_str()); return; } } std::string errmsg = "SetModuleInfo: entryPoint:" + entryPoint + "is invalid."; LOG_ECMA(ERROR) << errmsg; Local message = StringRef::NewFromUtf8(vm, errmsg.c_str()); Local error = Exception::Error(vm, message); JSNApi::ThrowException(vm, error); } // note: The function SetAssetPath is a generic interface for previewing and physical machines. void JSNApi::SetAssetPath(EcmaVM *vm, const std::string &assetPath) { ecmascript::CString path = assetPath.c_str(); // check input assetPath #if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) if (!ModulePathHelper::ValidateAbcPath(path, ecmascript::ValidateFilePath::ABC)) { LOG_FULL(FATAL) << "Invalid input assetPath: " << assetPath.c_str(); } #endif vm->SetAssetPath(path); } void JSNApi::SetLoop(EcmaVM *vm, void *loop) { vm->SetLoop(loop); } void JSNApi::SetWeakFinalizeTaskCallback(EcmaVM *vm, const WeakFinalizeTaskCallback &callback) { vm->GetAssociatedJSThread()->SetWeakFinalizeTaskCallback(callback); } void JSNApi::SetAsyncCleanTaskCallback(EcmaVM *vm, const NativePointerTaskCallback &callback) { vm->GetAssociatedJSThread()->SetAsyncCleanTaskCallback(callback); } void JSNApi::SetTriggerGCTaskCallback(EcmaVM *vm, const TriggerGCTaskCallback& callback) { vm->GetHeap()->GetIdleGCTrigger()->SetTriggerGCTaskCallback(callback); } std::string JSNApi::GetAssetPath(EcmaVM *vm) { return vm->GetAssetPath().c_str(); } void JSNApi::SetMockModuleList(EcmaVM *vm, const std::map &list) { vm->SetMockModuleList(list); } void JSNApi::SetHmsModuleList(EcmaVM *vm, const std::vector &list) { vm->SetHmsModuleList(list); } void JSNApi::SetPkgAliasList(EcmaVM *vm, const std::map &list) { ecmascript::CMap pkgAliasList; for (auto it = list.begin(); it != list.end(); ++it) { pkgAliasList.emplace(it->first.c_str(), it->second.c_str()); } vm->SetPkgAliasList(pkgAliasList); } void JSNApi::SetPkgNameList(EcmaVM *vm, const std::map &list) { ecmascript::CMap pkgNameList; for (auto it = list.begin(); it != list.end(); ++it) { pkgNameList.emplace(it->first.c_str(), it->second.c_str()); } vm->SetPkgNameList(pkgNameList); } std::string JSNApi::GetPkgName(EcmaVM *vm, const std::string &moduleName) { return vm->GetPkgName(moduleName.c_str()).c_str(); } void JSNApi::SetpkgContextInfoList(EcmaVM *vm, const std::map>> &list) { ecmascript::CMap>> pkgContextInfoList; for (auto it = list.begin(); it != list.end(); it++) { const std::vector> vec = it->second; ecmascript::CMap> map; for (size_t i = 0; i < vec.size(); i++) { ecmascript::CString pkgName = vec[i][0].c_str(); ecmascript::CVector pkgContextInfo; for (size_t j = 1; j < vec[i].size(); j++) { pkgContextInfo.emplace_back(vec[i][j].c_str()); } map.emplace(pkgName, pkgContextInfo); } pkgContextInfoList.emplace(it->first.c_str(), map); } vm->SetpkgContextInfoList(pkgContextInfoList); } // Only used for env created by napi to set module execution mode void JSNApi::SetExecuteBufferMode(const EcmaVM *vm) { ecmascript::ModuleManager *moduleManager = vm->GetAssociatedJSThread()->GetCurrentEcmaContext()->GetModuleManager(); moduleManager->SetExecuteMode(ecmascript::ModuleExecuteMode::ExecuteBufferMode); } bool JSNApi::InitForConcurrentThread(EcmaVM *vm, ConcurrentCallback cb, void *data) { vm->SetConcurrentCallback(cb, data); return true; } bool JSNApi::InitForConcurrentFunction(EcmaVM *vm, Local function, void *taskInfo) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); [[maybe_unused]] LocalScope scope(vm); JSHandle funcVal = JSNApiHelper::ToJSHandle(function); JSHandle transFunc = JSHandle::Cast(funcVal); if (transFunc->GetFunctionKind() != ecmascript::FunctionKind::CONCURRENT_FUNCTION) { LOG_ECMA(ERROR) << "Function is not concurrent"; return false; } transFunc->SetTaskConcurrentFuncFlag(1); // 1 : concurrent function flag thread->SetTaskInfo(reinterpret_cast(taskInfo)); thread->SetIsInConcurrentScope(true); return true; } void* JSNApi::GetCurrentTaskInfo(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, nullptr); return reinterpret_cast(thread->GetTaskInfo()); } void JSNApi::ClearCurrentTaskInfo(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); thread->SetTaskInfo(reinterpret_cast(nullptr)); thread->SetIsInConcurrentScope(false); } void JSNApi::SetBundleName(EcmaVM *vm, const std::string &bundleName) { ecmascript::CString name = bundleName.c_str(); vm->SetBundleName(name); } std::string JSNApi::GetBundleName(EcmaVM *vm) { return vm->GetBundleName().c_str(); } void JSNApi::SetModuleName(EcmaVM *vm, const std::string &moduleName) { ecmascript::CString name = moduleName.c_str(); ecmascript::pgo::PGOProfilerManager::GetInstance()->SetModuleName(moduleName); vm->SetModuleName(name); } std::string JSNApi::GetModuleName(EcmaVM *vm) { return vm->GetModuleName().c_str(); } std::pair JSNApi::GetCurrentModuleInfo(EcmaVM *vm, bool needRecordName) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return vm->GetCurrentModuleInfo(needRecordName); } std::string JSNApi::NormalizePath(const std::string &string) { return PathHelper::NormalizePath(string.c_str()).c_str(); } // Enable cross thread execution. void JSNApi::AllowCrossThreadExecution(EcmaVM *vm) { LOG_ECMA(WARN) << "enable cross thread execution"; vm->GetAssociatedJSThread()->EnableCrossThreadExecution(); } void* JSNApi::GetEnv(EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); return thread->GetEnv(); } void JSNApi::SetEnv(EcmaVM *vm, void *env) { JSThread *thread = vm->GetJSThread(); thread->SetEnv(env); } void JSNApi::SynchronizVMInfo(EcmaVM *vm, const EcmaVM *hostVM) { std::atomic_thread_fence(std::memory_order_seq_cst); vm->SetBundleName(hostVM->GetBundleName()); vm->SetModuleName(hostVM->GetModuleName()); vm->SetAssetPath(hostVM->GetAssetPath()); vm->SetIsBundlePack(hostVM->IsBundlePack()); vm->SetPkgNameList(hostVM->GetPkgNameList()); vm->SetPkgAliasList(hostVM->GetPkgAliasList()); vm->SetpkgContextInfoList(hostVM->GetPkgContextInfoLit()); ecmascript::ModuleManager *vmModuleManager = vm->GetAssociatedJSThread()->GetCurrentEcmaContext()->GetModuleManager(); ecmascript::ModuleManager *hostVMModuleManager = hostVM->GetAssociatedJSThread()->GetCurrentEcmaContext()->GetModuleManager(); vmModuleManager->SetExecuteMode(hostVMModuleManager->GetExecuteMode()); vm->SetResolveBufferCallback(hostVM->GetResolveBufferCallback()); } bool JSNApi::IsProfiling(EcmaVM *vm) { return vm->GetProfilerState(); } void JSNApi::SetProfilerState(const EcmaVM *vm, bool value) { const_cast(vm)->SetProfilerState(value); } void JSNApi::SetSourceMapTranslateCallback(EcmaVM *vm, SourceMapTranslateCallback callback) { vm->SetSourceMapTranslateCallback(callback); } void JSNApi::SetSourceMapCallback(EcmaVM *vm, SourceMapCallback callback) { vm->SetSourceMapCallback(callback); } void JSNApi::GetStackBeforeCallNapiSuccess([[maybe_unused]] EcmaVM *vm, [[maybe_unused]] bool &getStackBeforeCallNapiSuccess) { #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) JSThread *thread = vm->GetJSThread(); if (thread->GetIsProfiling()) { ecmascript::ThreadManagedScope managedScope(thread); getStackBeforeCallNapiSuccess = vm->GetProfiler()->GetStackBeforeCallNapi(thread); } #endif } void JSNApi::GetStackAfterCallNapi([[maybe_unused]] EcmaVM *vm) { #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) JSThread *thread = vm->GetJSThread(); if (thread->GetIsProfiling()) { ecmascript::ThreadManagedScope managedScope(thread); vm->GetProfiler()->GetStackAfterCallNapi(thread); } #endif } EcmaVM *JSNApi::CreateJSVM(const RuntimeOption &option) { JSRuntimeOptions runtimeOptions; runtimeOptions.SetArkProperties(option.GetArkProperties()); runtimeOptions.SetMemConfigProperty(option.GetMemConfigProperty()); runtimeOptions.SetArkBundleName(option.GetArkBundleName()); runtimeOptions.SetLongPauseTime(option.GetLongPauseTime()); runtimeOptions.SetGcThreadNum(option.GetGcThreadNum()); runtimeOptions.SetIsWorker(option.GetIsWorker()); runtimeOptions.SetIsRestrictedWorker(option.GetIsRestrictedWorker()); // Mem runtimeOptions.SetHeapSizeLimit(option.GetGcPoolSize()); // Disable the asm-interpreter of ark-engine for ios-platform temporarily. #if !defined(PANDA_TARGET_IOS) // asmInterpreter runtimeOptions.SetEnableAsmInterpreter(option.GetEnableAsmInterpreter()); #else runtimeOptions.SetEnableAsmInterpreter(false); #endif runtimeOptions.SetEnableBuiltinsLazy(option.GetEnableBuiltinsLazy()); runtimeOptions.SetAsmOpcodeDisableRange(option.GetAsmOpcodeDisableRange()); // aot runtimeOptions.SetEnableAOT(option.GetEnableAOT()); runtimeOptions.SetEnablePGOProfiler(option.GetEnableProfile()); runtimeOptions.SetPGOProfilerPath(option.GetProfileDir()); // Dfx runtimeOptions.SetLogLevel(Log::LevelToString(Log::ConvertFromRuntime(option.GetLogLevel()))); runtimeOptions.SetEnableArkTools(option.GetEnableArkTools()); return CreateEcmaVM(runtimeOptions); } EcmaContext *JSNApi::CreateJSContext(EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); ecmascript::ThreadManagedScope managedScope(thread); return EcmaContext::CreateAndInitialize(thread); } void JSNApi::SwitchCurrentContext(EcmaVM *vm, EcmaContext *context) { JSThread *thread = vm->GetJSThread(); ecmascript::ThreadManagedScope managedScope(thread); thread->SwitchCurrentContext(context); } void JSNApi::DestroyJSContext(EcmaVM *vm, EcmaContext *context) { JSThread *thread = vm->GetJSThread(); ecmascript::ThreadManagedScope managedScope(thread); EcmaContext::CheckAndDestroy(thread, context); } EcmaVM *JSNApi::CreateEcmaVM(const JSRuntimeOptions &options) { return EcmaVM::Create(options); } void JSNApi::DestroyJSVM(EcmaVM *ecmaVm) { if (UNLIKELY(ecmaVm == nullptr)) { return; } ecmaVm->GetJSThread()->ManagedCodeBegin(); EcmaVM::Destroy(ecmaVm); } void JSNApi::RegisterUncatchableErrorHandler(EcmaVM *ecmaVm, const UncatchableErrorHandler &handler) { ecmaVm->RegisterUncatchableErrorHandler(handler); } void JSNApi::TriggerGC(const EcmaVM *vm, TRIGGER_GC_TYPE gcType) { TriggerGC(vm, ecmascript::GCReason::EXTERNAL_TRIGGER, gcType); } void JSNApi::TriggerGC(const EcmaVM *vm, ecmascript::GCReason reason, TRIGGER_GC_TYPE gcType) { CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); if (thread != nullptr && vm->IsInitialized()) { #if defined(ENABLE_EXCEPTION_BACKTRACE) if (thread->IsMainThreadFast()) { LOG_ECMA(INFO) << "JSNApi::TriggerGC gcType: " << static_cast(gcType); std::ostringstream stack; ecmascript::Backtrace(stack, true); LOG_ECMA(INFO) << stack.str(); } #endif auto sHeap = ecmascript::SharedHeap::GetInstance(); switch (gcType) { case TRIGGER_GC_TYPE::SEMI_GC: vm->CollectGarbage(vm->GetHeap()->SelectGCType(), reason); break; case TRIGGER_GC_TYPE::OLD_GC: vm->CollectGarbage(ecmascript::TriggerGCType::OLD_GC, reason); break; case TRIGGER_GC_TYPE::FULL_GC: vm->CollectGarbage(ecmascript::TriggerGCType::FULL_GC, reason); break; case TRIGGER_GC_TYPE::SHARED_GC: sHeap->CollectGarbage(thread); break; case TRIGGER_GC_TYPE::SHARED_FULL_GC: sHeap->CollectGarbage(thread); break; default: break; } } } void JSNApi::HintGC(const EcmaVM *vm, MemoryReduceDegree degree, ecmascript::GCReason reason) { CROSS_THREAD_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); if (thread != nullptr && vm->IsInitialized()) { const_cast(vm->GetHeap())->CheckAndTriggerHintGC(degree, reason); } } void JSNApi::TriggerIdleGC(const EcmaVM *vm, TRIGGER_IDLE_GC_TYPE gcType) { CROSS_THREAD_CHECK(vm); if (thread != nullptr && vm->IsInitialized()) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); vm->GetHeap()->GetIdleGCTrigger()->TryTriggerIdleGC(gcType); } } void JSNApi::SetStartIdleMonitorCallback(const StartIdleMonitorCallback& callback) { startIdleMonitorCallback_ = callback; } StartIdleMonitorCallback JSNApi::GetStartIdleMonitorCallback() { return startIdleMonitorCallback_; } void JSNApi::ThrowException(const EcmaVM *vm, Local error) { auto thread = vm->GetJSThread(); ecmascript::ThreadManagedScope managedScope(thread); if (thread->HasPendingException()) { LOG_ECMA(DEBUG) << "An exception has already occurred before, keep old exception here."; return; } thread->SetException(JSNApiHelper::ToJSTaggedValue(*error)); } void JSNApi::PrintExceptionInfo(const EcmaVM *vm) { JSThread* thread = vm->GetJSThread(); ecmascript::ThreadManagedScope managedScope(thread); [[maybe_unused]] ecmascript::EcmaHandleScope handleScope(thread); if (!HasPendingException(vm)) { return; } Local exception = GetAndClearUncaughtException(vm); JSHandle exceptionHandle = JSNApiHelper::ToJSHandle(exception); if (exceptionHandle->IsJSError()) { vm->PrintJSErrorInfo(exceptionHandle); ThrowException(vm, exception); return; } JSHandle result = JSTaggedValue::ToString(thread, exceptionHandle); ecmascript::CString string = ConvertToString(*result); LOG_ECMA(ERROR) << string; ThrowException(vm, exception); } #if defined(ECMASCRIPT_SUPPORT_DEBUGGER) && !defined(PANDA_TARGET_IOS) bool JSNApi::StartDebuggerCheckParameters(EcmaVM *vm, const DebugOption &option, int32_t instanceId, const DebuggerPostTask &debuggerPostTask) { if (vm == nullptr) { LOG_ECMA(ERROR) << "[StartDebugger] vm is nullptr"; return false; } if (option.port < 0) { LOG_ECMA(ERROR) << "[StartDebugger] option.port is -1" ; return false; } CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); const auto &handler = vm->GetJsDebuggerManager()->GetDebugLibraryHandle(); if (handler.IsValid()) { LOG_ECMA(ERROR) << "[StartDebugger] handler has already loaded"; return false; } if (option.libraryPath == nullptr) { LOG_ECMA(ERROR) << "[StartDebugger] option.libraryPath is nullptr"; return false; } auto handle = panda::os::library_loader::Load(std::string(option.libraryPath)); if (!handle) { LOG_ECMA(ERROR) << "[StartDebugger] Load library fail: " << option.libraryPath << " " << errno; return false; } auto sym = panda::os::library_loader::ResolveSymbol(handle.Value(), "StartDebug"); if (!sym) { LOG_ECMA(ERROR) << "[StartDebugger] Resolve symbol fail: " << sym.Error().ToString(); return false; } using StartDebugger = bool (*)( const std::string &, EcmaVM *, bool, int32_t, const DebuggerPostTask &, int); vm->GetJsDebuggerManager()->SetDebugMode(option.isDebugMode); vm->GetJsDebuggerManager()->SetIsDebugApp(true); vm->GetJsDebuggerManager()->SetDebugLibraryHandle(std::move(handle.Value())); bool ret = reinterpret_cast(sym.Value())( "PandaDebugger", vm, option.isDebugMode, instanceId, debuggerPostTask, option.port); if (!ret) { // Reset the config vm->GetJsDebuggerManager()->SetDebugMode(false); panda::os::library_loader::LibraryHandle libraryHandle(nullptr); vm->GetJsDebuggerManager()->SetDebugLibraryHandle(std::move(libraryHandle)); } return ret; } #endif // for previewer, cross platform and testcase debugger bool JSNApi::StartDebugger([[maybe_unused]] EcmaVM *vm, [[maybe_unused]] const DebugOption &option, [[maybe_unused]] int32_t instanceId, [[maybe_unused]] const DebuggerPostTask &debuggerPostTask) { #if defined(ECMASCRIPT_SUPPORT_DEBUGGER) #if !defined(PANDA_TARGET_IOS) LOG_ECMA(INFO) << "JSNApi::StartDebugger, isDebugMode = " << option.isDebugMode << ", port = " << option.port << ", instanceId = " << instanceId; return StartDebuggerCheckParameters(vm, option, instanceId, debuggerPostTask); #else if (vm == nullptr) { return false; } CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); vm->GetJsDebuggerManager()->SetDebugMode(option.isDebugMode); bool ret = OHOS::ArkCompiler::Toolchain::StartDebug( DEBUGGER_NAME, vm, option.isDebugMode, instanceId, debuggerPostTask, option.port); if (!ret) { // Reset the config vm->GetJsDebuggerManager()->SetDebugMode(false); } return ret; #endif // PANDA_TARGET_IOS #else LOG_ECMA(ERROR) << "Not support arkcompiler debugger"; return false; #endif // ECMASCRIPT_SUPPORT_DEBUGGER } // rk // FA or Stage bool JSNApi::StartDebuggerForOldProcess([[maybe_unused]] EcmaVM *vm, [[maybe_unused]] const DebugOption &option, [[maybe_unused]] int32_t instanceId, [[maybe_unused]] const DebuggerPostTask &debuggerPostTask) { #if defined(ECMASCRIPT_SUPPORT_DEBUGGER) #if !defined(PANDA_TARGET_IOS) LOG_ECMA(INFO) << "JSNApi::StartDebuggerForOldProcess, isDebugMode = " << option.isDebugMode << ", instanceId = " << instanceId; if (vm == nullptr) { LOG_ECMA(ERROR) << "[StartDebuggerForOldProcess] vm is nullptr"; return false; } CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); const auto &handle = vm->GetJsDebuggerManager()->GetDebugLibraryHandle(); if (!handle.IsValid()) { LOG_ECMA(ERROR) << "[StartDebuggerForOldProcess] Get library handle fail: " << option.libraryPath; return false; } using StartDebug = bool (*)( const std::string &, EcmaVM *, bool, int32_t, const DebuggerPostTask &, int); auto sym = panda::os::library_loader::ResolveSymbol(handle, "StartDebug"); if (!sym) { LOG_ECMA(ERROR) << "[StartDebuggerForOldProcess] Resolve symbol fail: " << sym.Error().ToString(); return false; } bool ret = reinterpret_cast(sym.Value())( "PandaDebugger", vm, option.isDebugMode, instanceId, debuggerPostTask, option.port); if (!ret) { // Reset the config vm->GetJsDebuggerManager()->SetDebugMode(false); panda::os::library_loader::LibraryHandle libraryHandle(nullptr); vm->GetJsDebuggerManager()->SetDebugLibraryHandle(std::move(libraryHandle)); } return ret; #else if (vm == nullptr) { LOG_ECMA(ERROR) << "[StartDebuggerForOldProcess] vm is nullptr"; return false; } CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); vm->GetJsDebuggerManager()->SetDebugMode(option.isDebugMode); bool ret = OHOS::ArkCompiler::Toolchain::StartDebug( DEBUGGER_NAME, vm, option.isDebugMode, instanceId, debuggerPostTask, option.port); if (!ret) { // Reset the config vm->GetJsDebuggerManager()->SetDebugMode(false); } return ret; #endif // PANDA_TARGET_IOS #else LOG_ECMA(ERROR) << "Not support arkcompiler debugger"; return false; #endif // ECMASCRIPT_SUPPORT_DEBUGGER } // ohos or emulator // FA or Stage bool JSNApi::StartDebuggerForSocketPair([[maybe_unused]] int tid, [[maybe_unused]] int socketfd) { #if defined(ECMASCRIPT_SUPPORT_DEBUGGER) LOG_ECMA(INFO) << "JSNApi::StartDebuggerForSocketPair, tid = " << tid << ", socketfd = " << socketfd; JsDebuggerManager *jsDebuggerManager = JsDebuggerManager::GetJsDebuggerManager(tid); if (jsDebuggerManager == nullptr) { LOG_ECMA(ERROR) << "[StartDebuggerForSocketPair] jsDebuggerManager is nullptr"; return false; } const auto &handle = jsDebuggerManager->GetDebugLibraryHandle(); if (!handle.IsValid()) { LOG_ECMA(ERROR) << "[StartDebuggerForSocketPair] Get library handle fail"; return false; } using StartDebugForSocketpair = bool (*)(int, int); auto sym = panda::os::library_loader::ResolveSymbol(handle, "StartDebugForSocketpair"); if (!sym) { LOG_ECMA(ERROR) << "[StartDebuggerForSocketPair] Resolve symbol fail: " << sym.Error().ToString(); return false; } bool ret = reinterpret_cast(sym.Value())(tid, socketfd); if (!ret) { // Reset the config jsDebuggerManager->SetDebugMode(false); panda::os::library_loader::LibraryHandle libraryHandle(nullptr); jsDebuggerManager->SetDebugLibraryHandle(std::move(libraryHandle)); } return ret; #else LOG_ECMA(ERROR) << "Not support arkcompiler debugger"; return false; #endif // ECMASCRIPT_SUPPORT_DEBUGGER } // ohos or emulator // FA or Stage // release or debug hap : aa start // aa start -D // aa start -p // new worker bool JSNApi::NotifyDebugMode([[maybe_unused]] int tid, [[maybe_unused]] EcmaVM *vm, [[maybe_unused]] const DebugOption &option, [[maybe_unused]] int32_t instanceId, [[maybe_unused]] const DebuggerPostTask &debuggerPostTask, [[maybe_unused]] bool debugApp) { #if defined(ECMASCRIPT_SUPPORT_DEBUGGER) LOG_ECMA(INFO) << "JSNApi::NotifyDebugMode, tid = " << tid << ", debugApp = " << debugApp << ", isDebugMode = " << option.isDebugMode << ", instanceId = " << instanceId; if (vm == nullptr) { LOG_ECMA(ERROR) << "[NotifyDebugMode] vm is nullptr"; return false; } CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); bool ret = false; if (!debugApp) { return true; } if (option.libraryPath == nullptr) { LOG_ECMA(ERROR) << "[NotifyDebugMode] option.libraryPath is nullptr"; return false; } JsDebuggerManager *jsDebuggerManager = vm->GetJsDebuggerManager(); auto handle = panda::os::library_loader::Load(std::string(option.libraryPath)); if (!handle) { LOG_ECMA(ERROR) << "[NotifyDebugMode] Load library fail: " << option.libraryPath << " " << errno; return false; } JsDebuggerManager::AddJsDebuggerManager(tid, jsDebuggerManager); jsDebuggerManager->SetDebugLibraryHandle(std::move(handle.Value())); jsDebuggerManager->SetDebugMode(option.isDebugMode && debugApp); jsDebuggerManager->SetIsDebugApp(debugApp); #ifdef PANDA_TARGET_ARM32 ret = StartDebuggerForOldProcess(vm, option, instanceId, debuggerPostTask); #else ret = true; #endif // store debugger postTask in inspector. using StoreDebuggerInfo = void (*)(int, EcmaVM *, const DebuggerPostTask &); auto symOfStoreDebuggerInfo = panda::os::library_loader::ResolveSymbol( jsDebuggerManager->GetDebugLibraryHandle(), "StoreDebuggerInfo"); if (!symOfStoreDebuggerInfo) { LOG_ECMA(ERROR) << "[NotifyDebugMode] Resolve StoreDebuggerInfo symbol fail: " << symOfStoreDebuggerInfo.Error().ToString(); return false; } reinterpret_cast(symOfStoreDebuggerInfo.Value())(tid, vm, debuggerPostTask); #ifndef PANDA_TARGET_ARM32 // Initialize debugger using InitializeDebuggerForSocketpair = bool(*)(void*); auto sym = panda::os::library_loader::ResolveSymbol( jsDebuggerManager->GetDebugLibraryHandle(), "InitializeDebuggerForSocketpair"); if (!sym) { LOG_ECMA(ERROR) << "[NotifyDebugMode] Resolve InitializeDebuggerForSocketpair symbol fail: " << sym.Error().ToString(); return false; } if (!reinterpret_cast(sym.Value())(vm)) { LOG_ECMA(ERROR) << "[NotifyDebugMode] InitializeDebuggerForSocketpair fail"; return false; } #endif if (option.isDebugMode) { using WaitForDebugger = void (*)(EcmaVM *); auto symOfWaitForDebugger = panda::os::library_loader::ResolveSymbol( jsDebuggerManager->GetDebugLibraryHandle(), "WaitForDebugger"); if (!symOfWaitForDebugger) { LOG_ECMA(ERROR) << "[NotifyDebugMode] Resolve symbol WaitForDebugger fail: " << symOfWaitForDebugger.Error().ToString(); return false; } reinterpret_cast(symOfWaitForDebugger.Value())(vm); } auto anFileDataMgr = ecmascript::AnFileDataManager::GetInstance(); if (anFileDataMgr != nullptr && anFileDataMgr->SafeGetStubFileInfo()) { anFileDataMgr->SafeGetStubFileInfo()->RegisterToDebugger(); } return ret; #else LOG_ECMA(ERROR) << "Not support arkcompiler debugger"; return false; #endif // ECMASCRIPT_SUPPORT_DEBUGGER } bool JSNApi::StoreDebugInfo([[maybe_unused]] int tid, [[maybe_unused]] EcmaVM *vm, [[maybe_unused]] const DebugOption &option, [[maybe_unused]] const DebuggerPostTask &debuggerPostTask, [[maybe_unused]] bool debugApp) { #if defined(ECMASCRIPT_SUPPORT_DEBUGGER) LOG_ECMA(INFO) << "JSNApi::StoreDebugInfo, tid = " << tid; if (vm == nullptr) { LOG_ECMA(ERROR) << "[StoreDebugInfo] vm is nullptr"; return false; } JsDebuggerManager *jsDebuggerManager = vm->GetJsDebuggerManager(); const auto &handler = jsDebuggerManager->GetDebugLibraryHandle(); if (handler.IsValid()) { LOG_ECMA(INFO) << "[StoreDebugInfo] handler has already loaded"; return false; } if (option.libraryPath == nullptr) { LOG_ECMA(ERROR) << "[StoreDebugInfo] option.libraryPath is nullptr"; return false; } auto handle = panda::os::library_loader::Load(std::string(option.libraryPath)); if (!handle) { LOG_ECMA(ERROR) << "[StoreDebugInfo] Load library fail: " << option.libraryPath << " " << errno; return false; } JsDebuggerManager::AddJsDebuggerManager(tid, jsDebuggerManager); jsDebuggerManager->SetDebugLibraryHandle(std::move(handle.Value())); jsDebuggerManager->SetDebugMode(option.isDebugMode && debugApp); jsDebuggerManager->SetIsDebugApp(debugApp); // store debugger postTask in inspector. using StoreDebuggerInfo = void (*)(int, EcmaVM *, const DebuggerPostTask &); auto symOfStoreDebuggerInfo = panda::os::library_loader::ResolveSymbol( jsDebuggerManager->GetDebugLibraryHandle(), "StoreDebuggerInfo"); if (!symOfStoreDebuggerInfo) { LOG_ECMA(ERROR) << "[StoreDebugInfo] Resolve StoreDebuggerInfo symbol fail: " << symOfStoreDebuggerInfo.Error().ToString(); return false; } reinterpret_cast(symOfStoreDebuggerInfo.Value())(tid, vm, debuggerPostTask); bool ret = false; using InitializeDebuggerForSocketpair = bool(*)(void*); auto sym = panda::os::library_loader::ResolveSymbol(handler, "InitializeDebuggerForSocketpair"); if (!sym) { LOG_ECMA(ERROR) << "[InitializeDebuggerForSocketpair] Resolve symbol fail: " << sym.Error().ToString(); return false; } ret = reinterpret_cast(sym.Value())(vm); if (!ret) { // Reset the config vm->GetJsDebuggerManager()->SetDebugMode(false); return false; } return ret; #else LOG_ECMA(ERROR) << "Not support arkcompiler debugger"; return false; #endif // ECMASCRIPT_SUPPORT_DEBUGGER } bool JSNApi::StopDebugger([[maybe_unused]] EcmaVM *vm) { #if defined(ECMASCRIPT_SUPPORT_DEBUGGER) #if !defined(PANDA_TARGET_IOS) LOG_ECMA(DEBUG) << "JSNApi::StopDebugger"; if (vm == nullptr) { LOG_ECMA(ERROR) << "[StopDebugger] vm is nullptr"; return false; } CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); const auto &handle = vm->GetJsDebuggerManager()->GetDebugLibraryHandle(); using StopDebug = void (*)(void *); auto sym = panda::os::library_loader::ResolveSymbol(handle, "StopDebug"); if (!sym) { LOG_ECMA(ERROR) << sym.Error().ToString(); return false; } reinterpret_cast(sym.Value())(vm); vm->GetJsDebuggerManager()->SetDebugMode(false); uint32_t tid = vm->GetTid(); JsDebuggerManager::DeleteJsDebuggerManager(tid); return true; #else if (vm == nullptr) { LOG_ECMA(ERROR) << "[StopDebugger] vm is nullptr"; return false; } CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); OHOS::ArkCompiler::Toolchain::StopDebug(vm); vm->GetJsDebuggerManager()->SetDebugMode(false); return true; #endif // PANDA_TARGET_IOS #else LOG_ECMA(ERROR) << "Not support arkcompiler debugger"; return false; #endif // ECMASCRIPT_SUPPORT_DEBUGGER } bool JSNApi::StopDebugger([[maybe_unused]] int tid) { #if defined(ECMASCRIPT_SUPPORT_DEBUGGER) LOG_ECMA(DEBUG) << "JSNApi::StopDebugger, tid = " << tid; JsDebuggerManager *jsDebuggerManager = JsDebuggerManager::GetJsDebuggerManager(tid); if (jsDebuggerManager == nullptr) { LOG_ECMA(ERROR) << "[StopDebugger] jsDebuggerManager is nullptr"; return false; } const auto &handle = jsDebuggerManager->GetDebugLibraryHandle(); using StopOldDebug = void (*)(int, const std::string &); auto sym = panda::os::library_loader::ResolveSymbol(handle, "StopOldDebug"); if (!sym) { LOG_ECMA(ERROR) << sym.Error().ToString(); return false; } reinterpret_cast(sym.Value())(tid, "PandaDebugger"); return true; #else LOG_ECMA(ERROR) << "Not support arkcompiler debugger"; return false; #endif // ECMASCRIPT_SUPPORT_DEBUGGER } bool JSNApi::IsMixedDebugEnabled([[maybe_unused]] const EcmaVM *vm) { #if defined(ECMASCRIPT_SUPPORT_DEBUGGER) return vm->GetJsDebuggerManager()->IsMixedDebugEnabled(); #else return false; #endif } bool JSNApi::IsDebugModeEnabled([[maybe_unused]] const EcmaVM *vm) { #if defined(ECMASCRIPT_SUPPORT_DEBUGGER) CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); if (vm != nullptr && vm->GetJsDebuggerManager() != nullptr) { return vm->GetJsDebuggerManager()->IsDebugMode(); } return false; #else LOG_ECMA(ERROR) << "Not support arkcompiler debugger"; return false; #endif } void JSNApi::NotifyNativeCalling([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] const void *nativeAddress) { #if defined(ECMASCRIPT_SUPPORT_DEBUGGER) CROSS_THREAD_AND_EXCEPTION_CHECK(vm); vm->GetJsDebuggerManager()->GetNotificationManager()->NativeCallingEvent(nativeAddress); #else LOG_ECMA(ERROR) << "Not support arkcompiler debugger"; #endif } void JSNApi::NotifyNativeReturn([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] const void *nativeAddress) { #if defined(ECMASCRIPT_SUPPORT_DEBUGGER) CROSS_THREAD_AND_EXCEPTION_CHECK(vm); vm->GetJsDebuggerManager()->GetNotificationManager()->NativeReturnEvent(nativeAddress); #else LOG_ECMA(ERROR) << "Not support arkcompiler debugger"; #endif } void JSNApi::NotifyLoadModule([[maybe_unused]] const EcmaVM *vm) { #if defined(ECMASCRIPT_SUPPORT_DEBUGGER) CROSS_THREAD_AND_EXCEPTION_CHECK(vm); // if load module, it needs to check whether clear singlestepper_ vm->GetJsDebuggerManager()->ClearSingleStepper(); #else LOG_ECMA(ERROR) << "Not support arkcompiler debugger"; #endif } void JSNApi::NotifyUIIdle(const EcmaVM *vm, [[maybe_unused]] int idleTime) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); vm->GetHeap()->GetIdleGCTrigger()->NotifyVsyncIdleStart(); } void JSNApi::NotifyLooperIdleStart(const EcmaVM *vm, int64_t timestamp, int idleTime) { if (vm->IsPostForked()) { vm->GetHeap()->GetIdleGCTrigger()->NotifyLooperIdleStart(timestamp, idleTime); } } void JSNApi::NotifyLooperIdleEnd(const EcmaVM *vm, int64_t timestamp) { if (vm->IsPostForked()) { vm->GetHeap()->GetIdleGCTrigger()->NotifyLooperIdleEnd(timestamp); } } bool JSNApi::IsJSMainThreadOfEcmaVM(const EcmaVM *vm) { return vm->GetJSThread()->IsMainThreadFast(); } void JSNApi::SetDeviceDisconnectCallback(EcmaVM *vm, DeviceDisconnectCallback cb) { vm->SetDeviceDisconnectCallback(cb); } bool JSNApi::KeyIsNumber(const char* utf8) { const char *ptr = utf8; for (char c = *ptr; c; c = *++ptr) { if (c >= '0' && c <= '9') { continue; } else { return false; } } return true; } bool JSNApi::IsSerializationTimeoutCheckEnabled(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); // Open Control Timeout Consumption if (const_cast(vm)->GetJSOptions().EnableSerializationTimeoutCheck()) { return thread->IsMainThread(); } // Currently only log trace on main thread auto jsDebuggerManager = vm->GetJsDebuggerManager(); if (jsDebuggerManager != nullptr) { if (jsDebuggerManager->IsSerializationTimeoutCheckEnabled()) { return thread->IsMainThread(); } } return false; } void JSNApi::GenerateTimeoutTraceIfNeeded(const EcmaVM *vm, std::chrono::system_clock::time_point &start, std::chrono::system_clock::time_point &end, bool isSerialization) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope scope(thread); auto duration = std::chrono::duration_cast(end - start).count(); auto threshold = std::chrono::duration_cast (std::chrono::milliseconds(vm->GetJsDebuggerManager()->GetSerializationCheckThreshold())).count(); LOG_ECMA(DEBUG) << "JSNAPI::" << (isSerialization ? "SerializeValue" : "DeserializeValue") << " tid: " << thread->GetThreadId() << " threshold: " << threshold << " duration: " << duration; if (duration >= threshold) { std::stringstream tagMsg; auto startTimeMS = std::chrono::time_point_cast(start); tagMsg << (isSerialization ? "SerializationTimeout::tid=" : "DeserializationTimeout::tid="); tagMsg << thread->GetThreadId(); tagMsg << (isSerialization ? ";task=serialization;startTime=" : ";task=deserialization;startTime="); tagMsg << startTimeMS.time_since_epoch().count() << ";duration=" << duration; ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, tagMsg.str()); } } void JSNApi::LoadAotFileInternal(EcmaVM *vm, const std::string &moduleName, std::string &aotFileName) { if (vm->GetJSOptions().WasAOTOutputFileSet()) { aotFileName = vm->GetJSOptions().GetAOTOutputFile(); } #if defined(CROSS_PLATFORM) && defined(ANDROID_PLATFORM) else if (vm->GetJSOptions().GetEnableAOT()) #else else if (ecmascript::AnFileDataManager::GetInstance()->IsEnable()) #endif { aotFileName = ecmascript::AnFileDataManager::GetInstance()->GetDir() + moduleName; } else { std::string hapPath = ""; ecmascript::SearchHapPathCallBack callback = vm->GetSearchHapPathCallBack(); if (callback) { callback(moduleName, hapPath); } aotFileName = ecmascript::OhosPreloadAppInfo::GetPreloadAOTFileName(hapPath, moduleName); } if (aotFileName.empty()) { LOG_ECMA(INFO) << "can not find aot file"; return; } if (ecmascript::pgo::PGOProfilerManager::GetInstance()->IsDisableAot()) { LOG_ECMA(INFO) << "can't load disable aot file: " << aotFileName; return; } LOG_ECMA(INFO) << "start to load aot file: " << aotFileName; } void JSNApi::LoadAotFile(EcmaVM *vm, const std::string &moduleName) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope scope(thread); std::string aotFileName; LoadAotFileInternal(vm, moduleName, aotFileName); // Disable PGO for applications when an/ai file exists if (isForked_) { vm->DisablePGOProfilerWithAOTFile(aotFileName); } thread->GetCurrentEcmaContext()->LoadAOTFiles(aotFileName); } #if defined(CROSS_PLATFORM) && defined(ANDROID_PLATFORM) void JSNApi::LoadAotFile(EcmaVM *vm, [[maybe_unused]] const std::string &bundleName, const std::string &moduleName, std::function cb) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope scope(thread); std::string aotFileName; LoadAotFileInternal(vm, moduleName, aotFileName); thread->GetCurrentEcmaContext()->LoadAOTFiles(aotFileName, cb); } #endif bool JSNApi::ExecuteInContext(EcmaVM *vm, const std::string &fileName, const std::string &entry, bool needUpdate) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); LOG_ECMA(DEBUG) << "start to execute ark file in context: " << fileName; ecmascript::ThreadManagedScope scope(thread); EcmaContext::MountContext(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteFromAbcFile(thread, fileName.c_str(), entry, needUpdate)) { if (thread->HasPendingException()) { ecmascript::JsStackInfo::BuildCrashInfo(thread); thread->GetCurrentEcmaContext()->HandleUncaughtException(); } LOG_ECMA(ERROR) << "Cannot execute ark file '" << fileName << "' with entry '" << entry << "'" << std::endl; return false; } EcmaContext::UnmountContext(thread); return true; } // function for bundle abc bool JSNApi::ExecuteForAbsolutePath(const EcmaVM *vm, const std::string &fileName, const std::string &entry, bool needUpdate, bool executeFromJob) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); LOG_ECMA(DEBUG) << "start to execute absolute path ark file: " << fileName; ecmascript::ThreadManagedScope scope(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteFromAbsolutePathAbcFile( thread, fileName.c_str(), entry, needUpdate, executeFromJob)) { if (thread->HasPendingException()) { ecmascript::JsStackInfo::BuildCrashInfo(thread); thread->GetCurrentEcmaContext()->HandleUncaughtException(); } LOG_ECMA(ERROR) << "Cannot execute absolute path ark file '" << fileName << "' with entry '" << entry << "'" << std::endl; return false; } return true; } bool JSNApi::Execute(const EcmaVM *vm, const std::string &fileName, const std::string &entry, bool needUpdate, bool executeFromJob) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); LOG_ECMA(DEBUG) << "start to execute ark file: " << fileName; ecmascript::ThreadManagedScope scope(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteFromAbcFile( thread, fileName.c_str(), entry, needUpdate, executeFromJob)) { if (thread->HasPendingException()) { ecmascript::JsStackInfo::BuildCrashInfo(thread); thread->GetCurrentEcmaContext()->HandleUncaughtException(); } LOG_ECMA(ERROR) << "Cannot execute ark file '" << fileName << "' with entry '" << entry << "'" << std::endl; return false; } return true; } // The security interface needs to be modified accordingly. bool JSNApi::Execute(EcmaVM *vm, const uint8_t *data, int32_t size, const std::string &entry, const std::string &filename, bool needUpdate) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); LOG_ECMA(DEBUG) << "start to execute ark buffer: " << filename; ecmascript::ThreadManagedScope scope(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteFromBuffer(thread, data, size, entry, filename.c_str(), needUpdate)) { if (thread->HasPendingException()) { ecmascript::JsStackInfo::BuildCrashInfo(thread); thread->GetCurrentEcmaContext()->HandleUncaughtException(); } LOG_ECMA(ERROR) << "Cannot execute ark buffer file '" << filename << "' with entry '" << entry << "'" << std::endl; return false; } return true; } int JSNApi::ExecuteWithSingletonPatternFlag(EcmaVM *vm, const std::string &bundleName, const std::string &moduleName, const std::string &ohmurl, bool isSingletonPattern) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, ecmascript::JSPandaFileExecutor::ROUTE_INTERNAL_ERROR); ecmascript::ThreadManagedScope scope(thread); int result = ecmascript::JSPandaFileExecutor::ExecuteAbcFileWithSingletonPatternFlag(thread, bundleName.c_str(), moduleName.c_str(), ohmurl.c_str(), isSingletonPattern); if (!result) { if (thread->HasPendingException()) { ecmascript::JsStackInfo::BuildCrashInfo(thread); thread->GetCurrentEcmaContext()->HandleUncaughtException(); } LOG_ECMA(ERROR) << "Execute with singleton-pattern flag failed with bundle name is'" << bundleName << "' and module name is '" << moduleName << "', entry is'" << ohmurl << "'" << std::endl; } return result; } bool JSNApi::IsExecuteModuleInAbcFile(EcmaVM *vm, const std::string &bundleName, const std::string &moduleName, const std::string &ohmurl) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope scope(thread); bool result = ecmascript::JSPandaFileExecutor::IsExecuteModuleInAbcFile(thread, bundleName.c_str(), moduleName.c_str(), ohmurl.c_str()); return result; } // The security interface needs to be modified accordingly. bool JSNApi::ExecuteModuleBuffer(EcmaVM *vm, const uint8_t *data, int32_t size, const std::string &filename, bool needUpdate) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); LOG_ECMA(DEBUG) << "start to execute module buffer: " << filename; ecmascript::ThreadManagedScope scope(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteModuleBuffer(thread, data, size, filename.c_str(), needUpdate)) { if (thread->HasPendingException()) { ecmascript::JsStackInfo::BuildCrashInfo(thread); thread->GetCurrentEcmaContext()->HandleUncaughtException(); } LOG_ECMA(ERROR) << "Cannot execute module buffer file '" << filename; return false; } return true; } /* * srcFilename: data/storage/el1/bundle/modulename/ets/modules.abc * ohmUrl : 1. @bundle:bundleName/moduleName@namespace/ets/pages/Index * 2. @package:pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx/xxx * 3. @normalized:N&moduleName&bundleName&entryPath&version * 4. @normalized:N&moduleName&bundleName&entryPath& */ bool JSNApi::ExecuteSecureWithOhmUrl(EcmaVM *vm, uint8_t *data, int32_t size, const std::string &srcFilename, const std::string &ohmUrl) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); LOG_ECMA(INFO) << "start to execute ark buffer with secure memory use file: " << srcFilename << ", entrypoint: " << ohmUrl; ecmascript::ThreadManagedScope scope(thread); ecmascript::CString filename = PathHelper::NormalizePath(srcFilename.c_str()); // check input filePath #if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) if (!ModulePathHelper::ValidateAbcPath(filename, ecmascript::ValidateFilePath::ETS_MODULES)) { LOG_FULL(FATAL) << "ExecuteSecureWithOhmUrl: Invalid input filePath: " << srcFilename << ", input OhmUrl:" << ohmUrl; } #endif ecmascript::CString entryPoint; // Check and translate OhmUrl to recordName if (!ModulePathHelper::CheckAndGetRecordName(thread, ohmUrl.c_str(), entryPoint)) { LOG_FULL(FATAL) << "ExecuteSecureWithOhmUrl: Invalid input OhmUrl: " << ohmUrl << ", input filePath:" << filename; } if (!ecmascript::JSPandaFileExecutor::ExecuteSecureWithOhmUrl(thread, data, size, filename, entryPoint)) { if (thread->HasPendingException()) { ecmascript::JsStackInfo::BuildCrashInfo(thread); thread->GetCurrentEcmaContext()->HandleUncaughtException(); } LOG_ECMA(ERROR) << "Cannot execute ark buffer file '" << srcFilename << "' with entry '" << ohmUrl << "'" << std::endl; return false; } return true; } bool JSNApi::ExecuteSecure(EcmaVM *vm, uint8_t *data, int32_t size, const std::string &entry, const std::string &filename, bool needUpdate) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); LOG_ECMA(INFO) << "start to execute ark buffer with secure memory: " << filename; ecmascript::ThreadManagedScope scope(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteFromBufferSecure(thread, data, size, entry, filename.c_str(), needUpdate)) { if (thread->HasPendingException()) { ecmascript::JsStackInfo::BuildCrashInfo(thread); thread->GetCurrentEcmaContext()->HandleUncaughtException(); } LOG_ECMA(ERROR) << "Cannot execute ark buffer file '" << filename << "' with entry '" << entry << "'" << std::endl; return false; } return true; } bool JSNApi::ExecuteModuleBufferSecure(EcmaVM *vm, uint8_t* data, int32_t size, const std::string &filename, bool needUpdate) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); LOG_ECMA(INFO) << "start to execute module buffer with secure memory: " << filename; ecmascript::ThreadManagedScope scope(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteModuleBufferSecure(thread, data, size, filename.c_str(), needUpdate)) { if (thread->HasPendingException()) { ecmascript::JsStackInfo::BuildCrashInfo(thread); thread->GetCurrentEcmaContext()->HandleUncaughtException(); } LOG_ECMA(ERROR) << "Cannot execute module buffer file '" << filename; return false; } return true; } void JSNApi::PreFork(EcmaVM *vm) { ecmascript::ThreadManagedScope scope(vm->GetJSThread()); vm->PreFork(); } void JSNApi::UpdateAOTCompileStatus(ecmascript::JSRuntimeOptions &jsOption, const RuntimeOption &option) { // When AOT compilation failed, disable PGO and JIT bool aotHasException = false; for (const auto &value : option.GetAOTCompileStatusMap()) { auto moduleCompileStatus = static_cast(value.second); if (moduleCompileStatus == RuntimeOption::AOTCompileStatus::COMPILE_FAILED || moduleCompileStatus == RuntimeOption::AOTCompileStatus::COMPILE_CRASH) { aotHasException = true; break; } } jsOption.SetAOTHasException(aotHasException); } void JSNApi::PostFork(EcmaVM *vm, const RuntimeOption &option) { isForked_ = true; JSRuntimeOptions &jsOption = vm->GetJSOptions(); jsOption.SetEnablePGOProfiler(option.GetEnableProfile()); jsOption.SetEnableJIT(option.GetEnableJIT()); jsOption.SetEnableBaselineJIT(option.GetEnableBaselineJIT()); jsOption.SetMaxAotMethodSize(JSRuntimeOptions::MAX_APP_COMPILE_METHOD_SIZE); jsOption.SetEnableForceIC(false); ecmascript::pgo::PGOProfilerManager::GetInstance()->SetBundleName(option.GetBundleName()); ecmascript::pgo::PGOProfilerManager::GetInstance()->SetMaxAotMethodSize(jsOption.GetMaxAotMethodSize()); ecmascript::pgo::PGOProfilerManager::GetInstance()->SetEnableForceIC(jsOption.IsEnableForceIC()); JSRuntimeOptions runtimeOptions; runtimeOptions.SetLogLevel(Log::LevelToString(Log::ConvertFromRuntime(option.GetLogLevel()))); Log::Initialize(runtimeOptions); // 1. system switch 2. an file dir exits 3. whitelist 4. escape mechanism bool enableAOT = jsOption.GetEnableAOT() && !option.GetAnDir().empty() && EnableAotJitListHelper::GetInstance()->IsEnableAot(option.GetBundleName()) && !ecmascript::AotCrashInfo::IsAotEscaped(); if (enableAOT) { ecmascript::AnFileDataManager::GetInstance()->SetDir(option.GetAnDir()); ecmascript::AnFileDataManager::GetInstance()->SetEnable(true); } UpdateAOTCompileStatus(jsOption, option); LOG_ECMA(INFO) << "asmint: " << jsOption.GetEnableAsmInterpreter() << ", aot: " << enableAOT << ", jit: " << option.GetEnableJIT() << ", baseline jit: " << option.GetEnableBaselineJIT() << ", bundle name: " << option.GetBundleName(); vm->PostFork(); } void JSNApi::AddWorker(EcmaVM *hostVm, EcmaVM *workerVm) { if (hostVm != nullptr && workerVm != nullptr) { hostVm->WorkersetInfo(workerVm); workerVm->SetBundleName(hostVm->GetBundleName()); } } bool JSNApi::DeleteWorker(EcmaVM *hostVm, EcmaVM *workerVm) { if (hostVm != nullptr && workerVm != nullptr) { return hostVm->DeleteWorker(workerVm); } return false; } Local JSNApi::GetUncaughtException(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToLocal(vm->GetEcmaUncaughtException()); } Local JSNApi::GetAndClearUncaughtException(const EcmaVM *vm) { if (!HasPendingException(vm)) { return Local(); } ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return JSNApiHelper::ToLocal(vm->GetAndClearEcmaUncaughtException()); } bool JSNApi::HasPendingException(const EcmaVM *vm) { return vm->GetJSThread()->HasPendingException(); } bool JSNApi::IsExecutingPendingJob(const EcmaVM *vm) { return vm->GetAssociatedJSThread()->GetCurrentEcmaContext()->IsExecutingPendingJob(); } bool JSNApi::HasPendingJob(const EcmaVM *vm) { ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return vm->GetAssociatedJSThread()->GetCurrentEcmaContext()->HasPendingJob(); } void JSNApi::EnableUserUncaughtErrorHandler(EcmaVM *vm) { return vm->GetJSThread()->GetCurrentEcmaContext()->EnableUserUncaughtErrorHandler(); } Local JSNApi::GetGlobalObject(const EcmaVM *vm) { ecmascript::ThreadManagedScope scope(vm->GetJSThread()); JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle global(vm->GetJSThread(), globalEnv->GetGlobalObject()); return JSNApiHelper::ToLocal(global); } void JSNApi::ExecutePendingJob(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EcmaVM::ConstCast(vm)->GetJSThread()->GetCurrentEcmaContext()->ExecutePromisePendingJob(); } uintptr_t JSNApi::GetHandleAddr(const EcmaVM *vm, uintptr_t localAddress) { if (localAddress == 0) { return 0; } ecmascript::ThreadManagedScope scope(vm->GetJSThread()); CROSS_THREAD_CHECK(vm); JSTaggedType value = *(reinterpret_cast(localAddress)); return ecmascript::EcmaHandleScope::NewHandle(thread, value); } uintptr_t JSNApi::GetGlobalHandleAddr(const EcmaVM *vm, uintptr_t localAddress) { if (localAddress == 0) { return 0; } ecmascript::ThreadManagedScope scope(vm->GetJSThread()); CROSS_THREAD_CHECK(vm); JSTaggedType value = *(reinterpret_cast(localAddress)); return thread->NewGlobalHandle(value); } int JSNApi::GetStartRealTime(const EcmaVM *vm) { ecmascript::ThreadManagedScope scope(vm->GetJSThread()); return vm->GetProcessStartRealtime(); } void JSNApi::NotifyTaskBegin(const EcmaVM *vm) { const_cast(vm->GetHeap())->NotifyRecordMemorySize(); } void JSNApi::NotifyTaskFinished(const EcmaVM *vm) { ecmascript::ThreadManagedScope scope(vm->GetJSThread()); const_cast(vm->GetHeap())->CheckAndTriggerTaskFinishedGC(); } bool JSNApi::IsMultiThreadCheckEnabled(const EcmaVM *vm) { return vm->GetThreadCheckStatus(); } uint32_t JSNApi::GetCurrentThreadId() { return JSThread::GetCurrentThreadId(); } uintptr_t JSNApi::SetWeak(const EcmaVM *vm, uintptr_t localAddress) { if (localAddress == 0) { return 0; } ecmascript::ThreadManagedScope scope(vm->GetJSThread()); CROSS_THREAD_CHECK(vm); return thread->SetWeak(localAddress); } uintptr_t JSNApi::SetWeakCallback(const EcmaVM *vm, uintptr_t localAddress, void *ref, WeakRefClearCallBack freeGlobalCallBack, WeakRefClearCallBack nativeFinalizeCallback) { if (localAddress == 0) { return 0; } ecmascript::ThreadManagedScope scope(vm->GetJSThread()); CROSS_THREAD_CHECK(vm); return thread->SetWeak(localAddress, ref, freeGlobalCallBack, nativeFinalizeCallback); } uintptr_t JSNApi::ClearWeak(const EcmaVM *vm, uintptr_t localAddress) { if (localAddress == 0) { return 0; } ecmascript::ThreadManagedScope scope(vm->GetJSThread()); if (JSTaggedValue(reinterpret_cast(localAddress)->GetObject()) .IsUndefined()) { LOG_ECMA(ERROR) << "The object of weak reference has been recycled!"; return 0; } CROSS_THREAD_CHECK(vm); return thread->ClearWeak(localAddress); } bool JSNApi::IsWeak(const EcmaVM *vm, uintptr_t localAddress) { if (localAddress == 0) { return false; } ecmascript::ThreadManagedScope scope(vm->GetJSThread()); CROSS_THREAD_CHECK(vm); return thread->IsWeak(localAddress); } void JSNApi::DisposeGlobalHandleAddr(const EcmaVM *vm, uintptr_t addr) { if (addr == 0 || !reinterpret_cast(addr)->IsUsing()) { return; } ecmascript::ThreadManagedScope scope(vm->GetJSThread()); CROSS_THREAD_CHECK(vm); thread->DisposeGlobalHandle(addr); } void *JSNApi::SerializeValue(const EcmaVM *vm, Local value, Local transfer, Local cloneList, bool defaultTransfer, bool defaultCloneShared) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, nullptr); ecmascript::ThreadManagedScope scope(vm->GetJSThread()); JSHandle arkValue = JSNApiHelper::ToJSHandle(value); JSHandle arkTransfer = JSNApiHelper::ToJSHandle(transfer); JSHandle arkCloneList = JSNApiHelper::ToJSHandle(cloneList); bool serializationTimeoutCheckEnabled = IsSerializationTimeoutCheckEnabled(vm); std::chrono::system_clock::time_point startTime; std::chrono::system_clock::time_point endTime; if (serializationTimeoutCheckEnabled) { startTime = std::chrono::system_clock::now(); } ecmascript::ValueSerializer serializer(thread, defaultTransfer, defaultCloneShared); std::unique_ptr data; if (serializer.WriteValue(thread, arkValue, arkTransfer, arkCloneList)) { data = serializer.Release(); } if (serializationTimeoutCheckEnabled) { endTime = std::chrono::system_clock::now(); GenerateTimeoutTraceIfNeeded(vm, startTime, endTime, true); } if (data == nullptr) { return nullptr; } else { return reinterpret_cast(data.release()); } } Local JSNApi::DeserializeValue(const EcmaVM *vm, void *recoder, void *hint) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope scope(vm->GetJSThread()); std::unique_ptr data(reinterpret_cast(recoder)); ecmascript::BaseDeserializer deserializer(thread, data.release(), hint); bool serializationTimeoutCheckEnabled = IsSerializationTimeoutCheckEnabled(vm); std::chrono::system_clock::time_point startTime; std::chrono::system_clock::time_point endTime; if (serializationTimeoutCheckEnabled) { startTime = std::chrono::system_clock::now(); } JSHandle result = deserializer.ReadValue(); if (serializationTimeoutCheckEnabled) { endTime = std::chrono::system_clock::now(); GenerateTimeoutTraceIfNeeded(vm, startTime, endTime, false); } return JSNApiHelper::ToLocal(result); } void JSNApi::DeleteSerializationData(void *data) { ecmascript::SerializeData *value = reinterpret_cast(data); delete value; value = nullptr; } void HostPromiseRejectionTracker(const EcmaVM *vm, const JSHandle promise, const JSHandle reason, const ecmascript::PromiseRejectionEvent operation, void* data) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::PromiseRejectCallback promiseRejectCallback = thread->GetCurrentEcmaContext()->GetPromiseRejectCallback(); if (promiseRejectCallback != nullptr) { Local promiseVal = JSNApiHelper::ToLocal(JSHandle::Cast(promise)); PromiseRejectInfo promiseRejectInfo(promiseVal, JSNApiHelper::ToLocal(reason), static_cast(operation), data); promiseRejectCallback(reinterpret_cast(&promiseRejectInfo)); } } void JSNApi::SetHostPromiseRejectionTracker(EcmaVM *vm, void *cb, void* data) { CROSS_THREAD_CHECK(vm); thread->GetCurrentEcmaContext()->SetHostPromiseRejectionTracker(HostPromiseRejectionTracker); thread->GetCurrentEcmaContext()->SetPromiseRejectCallback( reinterpret_cast(cb)); thread->GetCurrentEcmaContext()->SetData(data); } void JSNApi::SetHostResolveBufferTracker(EcmaVM *vm, std::function cb) { vm->SetResolveBufferCallback(cb); } void JSNApi::SetSearchHapPathTracker(EcmaVM *vm, std::function cb) { vm->SetSearchHapPathCallBack(cb); } void JSNApi::SetMultiThreadCheck(bool multiThreadCheck) { EcmaVM::SetMultiThreadCheck(multiThreadCheck); } void JSNApi::SetErrorInfoEnhance(bool errorInfoEnhance) { EcmaVM::SetErrorInfoEnhance(errorInfoEnhance); } void JSNApi::SetRequestAotCallback([[maybe_unused]] EcmaVM *vm, const std::function &cb) { ecmascript::pgo::PGOProfilerManager::GetInstance()->SetRequestAotCallback(cb); } void JSNApi::SetUnloadNativeModuleCallback(EcmaVM *vm, const std::function &cb) { vm->SetUnloadNativeModuleCallback(cb); } void JSNApi::SetNativePtrGetter(EcmaVM *vm, void* cb) { vm->SetNativePtrGetter(reinterpret_cast(cb)); } void JSNApi::SetHostEnqueueJob(const EcmaVM *vm, Local cb, QueueType queueType) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope scope(vm->GetJSThread()); JSHandle fun = JSHandle::Cast(JSNApiHelper::ToJSHandle(cb)); JSHandle array = vm->GetFactory()->EmptyArray(); JSHandle job = thread->GetCurrentEcmaContext()->GetMicroJobQueue(); MicroJobQueue::EnqueueJob(thread, job, queueType, fun, array); } bool JSNApi::ExecuteModuleFromBuffer(EcmaVM *vm, const void *data, int32_t size, const std::string &file) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope scope(vm->GetJSThread()); if (!ecmascript::JSPandaFileExecutor::ExecuteFromBuffer(thread, data, size, ENTRY_POINTER, file.c_str(), false, true)) { if (thread->HasPendingException()) { ecmascript::JsStackInfo::BuildCrashInfo(thread); } std::cerr << "Cannot execute panda file from memory" << std::endl; return false; } return true; } Local JSNApi::NapiHasProperty(const EcmaVM *vm, uintptr_t nativeObj, uintptr_t key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle obj(nativeObj); if (!(obj->IsECMAObject() || obj->IsCallable())) { // When input validation is failed, we return JSTaggedValue::Hole to napi native engine. // Using JSTaggedValue::Hole as the "hand-shaking-protocol" to tell native engine to change error state. JSHandle holeHandle(thread, JSTaggedValue::Hole()); return scope.Escape(JSNApiHelper::ToLocal(holeHandle)); } LOG_IF_SPECIAL(obj, ERROR); JSMutableHandle keyValue(key); JSTaggedValue res = ObjectFastOperator::TryFastHasProperty(thread, obj.GetTaggedValue(), keyValue); if (!res.IsHole()) { RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return scope.Escape(JSNApiHelper::ToLocal(JSHandle(thread, res))); } auto ret = JSTaggedValue(JSTaggedValue::HasProperty(thread, obj, keyValue)); return scope.Escape(JSNApiHelper::ToLocal(JSHandle(thread, ret))); } Local JSNApi::NapiHasOwnProperty(const EcmaVM *vm, uintptr_t nativeObj, uintptr_t key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle obj(nativeObj); if (!(obj->IsECMAObject() || obj->IsCallable())) { // When input validation is failed, we return JSTaggedValue::Hole to napi native engine. // Using JSTaggedValue::Hole as the "hand-shaking-protocol" to tell native engine to change error state. JSHandle holeHandle(thread, JSTaggedValue::Hole()); return scope.Escape(JSNApiHelper::ToLocal(holeHandle)); } LOG_IF_SPECIAL(obj, ERROR); JSMutableHandle keyValue(key); JSTaggedValue res = ObjectFastOperator::TryFastHasProperty(thread, obj.GetTaggedValue(), keyValue); if (!res.IsHole()) { RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return scope.Escape(JSNApiHelper::ToLocal(JSHandle(thread, res))); } auto ret = JSTaggedValue(JSTaggedValue::HasProperty(thread, obj, keyValue)); return scope.Escape(JSNApiHelper::ToLocal(JSHandle(thread, ret))); } Local JSNApi::NapiGetProperty(const EcmaVM *vm, uintptr_t nativeObj, uintptr_t key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle obj(nativeObj); if (!(obj->IsECMAObject() || obj->IsCallable())) { // When input validation is failed, we return JSTaggedValue::Hole to napi native engine. // Using JSTaggedValue::Hole as the "hand-shaking-protocol" to tell native engine to change error state. JSHandle holeHandle(thread, JSTaggedValue::Hole()); return scope.Escape(JSNApiHelper::ToLocal(holeHandle)); } LOG_IF_SPECIAL(obj, ERROR); JSMutableHandle keyValue(key); if (!obj->IsHeapObject()) { OperationResult ret = JSTaggedValue::GetProperty(thread, obj, keyValue); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return scope.Escape(JSNApiHelper::ToLocal(ret.GetValue())); } JSTaggedValue res = ObjectFastOperator::TryFastGetPropertyByValue(thread, obj.GetTaggedValue(), keyValue); if (!res.IsHole()) { RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return scope.Escape(JSNApiHelper::ToLocal(JSHandle(thread, res))); } JSTaggedValue ret = ObjectFastOperator::FastGetPropertyByValue(thread, obj.GetTaggedValue(), keyValue.GetTaggedValue()); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return scope.Escape(JSNApiHelper::ToLocal(JSHandle(thread, ret))); } Local JSNApi::NapiDeleteProperty(const EcmaVM *vm, uintptr_t nativeObj, uintptr_t key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle obj(nativeObj); if (!(obj->IsECMAObject() || obj->IsCallable())) { // When input validation is failed, we return JSTaggedValue::Hole to napi native engine. // Using JSTaggedValue::Hole as the "hand-shaking-protocol" to tell native engine to change error state. JSHandle holeHandle(thread, JSTaggedValue::Hole()); return scope.Escape(JSNApiHelper::ToLocal(holeHandle)); } LOG_IF_SPECIAL(obj, ERROR); JSMutableHandle keyValue(key); if (keyValue->IsString() && !EcmaStringAccessor(keyValue.GetTaggedValue()).IsInternString()) { [[maybe_unused]] ecmascript::EcmaHandleScope handleScope(thread); auto string = thread->GetEcmaVM()->GetFactory()->InternString(keyValue); EcmaStringAccessor(string).SetInternString(); keyValue.Update(JSTaggedValue(string)); } auto ret = JSTaggedValue(JSTaggedValue::DeleteProperty(thread, obj, keyValue)); return scope.Escape(JSNApiHelper::ToLocal(JSHandle(thread, ret))); } Local JSNApi::NapiGetNamedProperty(const EcmaVM *vm, uintptr_t nativeObj, const char* utf8Key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EscapeLocalScope scope(vm); JSHandle obj(nativeObj); if (!(obj->IsECMAObject() || obj->IsCallable())) { // When input validation is failed, we return JSTaggedValue::Hole to napi native engine. // Using JSTaggedValue::Hole as the "hand-shaking-protocol" to tell native engine to change error state. JSHandle holeHandle(thread, JSTaggedValue::Hole()); return scope.Escape(JSNApiHelper::ToLocal(holeHandle)); } LOG_IF_SPECIAL(obj, ERROR); ObjectFactory *factory = vm->GetFactory(); JSHandle keyValue(factory->NewFromUtf8(utf8Key)); if (!obj->IsHeapObject()) { OperationResult ret = JSTaggedValue::GetProperty(thread, obj, keyValue); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return scope.Escape(JSNApiHelper::ToLocal(ret.GetValue())); } // FastPath - Try find key entry in cache directly. JSTaggedValue res = ObjectFastOperator::TryGetPropertyByNameThroughCacheAtLocal(thread, obj.GetTaggedValue(), keyValue.GetTaggedValue()); if (!res.IsHole()) { RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return scope.Escape(JSNApiHelper::ToLocal(JSHandle(thread, res))); } if (!KeyIsNumber(utf8Key)) { res = ObjectFastOperator::GetPropertyByName(thread, obj.GetTaggedValue(), keyValue.GetTaggedValue()); if (res.IsHole()) { res = JSTaggedValue::GetProperty(thread, obj, keyValue).GetValue().GetTaggedValue(); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return scope.Escape(JSNApiHelper::ToLocal(JSHandle(thread, res))); } RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return scope.Escape(JSNApiHelper::ToLocal(JSHandle(thread, res))); } res = ObjectFastOperator::FastGetPropertyByValue(thread, obj.GetTaggedValue(), keyValue.GetTaggedValue()); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return scope.Escape(JSNApiHelper::ToLocal(JSHandle(thread, res))); } Local JSNApi::CreateLocal(const EcmaVM *vm, panda::JSValueRef src) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); JSHandle handle(vm->GetJSThread(), JSNApiHelper::ToJSTaggedValue(&src)); return JSNApiHelper::ToLocal(handle); } Local JSNApi::GetExportObject(EcmaVM *vm, const std::string &file, const std::string &key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope scope(vm->GetJSThread()); ecmascript::CString entry = file.c_str(); ecmascript::CString name = vm->GetAssetPath(); if (!vm->IsBundlePack()) { ModulePathHelper::ParseAbcPathAndOhmUrl(vm, entry, name, entry); std::shared_ptr jsPandaFile = JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, name, entry.c_str(), false); if (jsPandaFile == nullptr) { JSHandle exportObj(thread, JSTaggedValue::Null()); return JSNApiHelper::ToLocal(exportObj); } if (!jsPandaFile->IsRecordWithBundleName()) { PathHelper::AdaptOldIsaRecord(entry); } } ecmascript::ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); JSHandle ecmaModule = moduleManager->GetImportedModule(entry); if (ecmaModule->GetIsNewBcVersion()) { int index = ecmascript::ModuleManager::GetExportObjectIndex(vm, ecmaModule, key.c_str()); JSTaggedValue result = ecmaModule->GetModuleValue(thread, index, false); JSHandle exportObj(thread, result); return JSNApiHelper::ToLocal(exportObj); } ObjectFactory *factory = vm->GetFactory(); JSHandle keyHandle = factory->NewFromASCII(key.c_str()); JSTaggedValue result = ecmaModule->GetModuleValue(thread, keyHandle.GetTaggedValue(), false); JSHandle exportObj(thread, result); return JSNApiHelper::ToLocal(exportObj); } Local JSNApi::GetExportObjectFromBuffer(EcmaVM *vm, const std::string &file, const std::string &key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope scope(vm->GetJSThread()); ecmascript::ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); JSHandle ecmaModule = moduleManager->GetImportedModule(file.c_str()); if (ecmaModule->GetIsNewBcVersion()) { int index = ecmascript::ModuleManager::GetExportObjectIndex(vm, ecmaModule, key.c_str()); JSTaggedValue result = ecmaModule->GetModuleValue(thread, index, false); JSHandle exportObj(thread, result); return JSNApiHelper::ToLocal(exportObj); } ObjectFactory *factory = vm->GetFactory(); JSHandle keyHandle = factory->NewFromASCII(key.c_str()); JSTaggedValue result = ecmaModule->GetModuleValue(thread, keyHandle.GetTaggedValue(), false); JSHandle exportObj(thread, result); return JSNApiHelper::ToLocal(exportObj); } Local JSNApi::GetExportObjectFromOhmUrl(EcmaVM *vm, const std::string &ohmUrl, const std::string &key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope scope(vm->GetJSThread()); ecmascript::CString recordName; // Check and translate OhmUrl to recordName if (!ModulePathHelper::CheckAndGetRecordName(thread, ohmUrl.c_str(), recordName)) { LOG_FULL(FATAL) << "ExecuteSecureWithOhmUrl: Invalid input OhmUrl: " << ohmUrl; return JSValueRef::Undefined(vm); } ecmascript::ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); JSHandle ecmaModule = moduleManager->GetImportedModule(recordName.c_str()); int index = ecmascript::ModuleManager::GetExportObjectIndex(vm, ecmaModule, key.c_str()); JSTaggedValue result = ecmaModule->GetModuleValue(thread, index, false); JSHandle exportObj(thread, result); return JSNApiHelper::ToLocal(exportObj); } Local JSNApi::ExecuteNativeModule(EcmaVM *vm, const std::string &key) { ecmascript::ThreadManagedScope scope(vm->GetJSThread()); CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); JSHandle exportObj = moduleManager->LoadNativeModule(thread, key.c_str()); return JSNApiHelper::ToLocal(exportObj); } Local JSNApi::GetModuleNameSpaceFromFile(EcmaVM *vm, const std::string &file, const std::string &module_path) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); ecmascript::CString recordNameStr; ecmascript::CString abcFilePath; if (module_path.size() != 0) { ecmascript::CString moduleName = ModulePathHelper::GetModuleNameWithPath(module_path.c_str()); abcFilePath = ModulePathHelper::ConcatPandaFilePath(moduleName); recordNameStr = ModulePathHelper::TranslateNapiFileRequestPath(thread, module_path.c_str(), file.c_str()); } else { // need get moduleName from stack std::pair moduleInfo = vm->GetCurrentModuleInfo(false); if (thread->HasPendingException()) { thread->GetCurrentEcmaContext()->HandleUncaughtException(); return JSValueRef::Undefined(vm); } std::string path = std::string(vm->GetBundleName().c_str()) + PathHelper::SLASH_TAG + moduleInfo.first; abcFilePath = moduleInfo.second; recordNameStr = ModulePathHelper::TranslateNapiFileRequestPath(thread, path.c_str(), file.c_str()); } LOG_ECMA(DEBUG) << "JSNApi::LoadModuleNameSpaceFromFile: Concated recordName " << recordNameStr; ecmascript::ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); JSHandle moduleNamespace = moduleManager-> GetModuleNameSpaceFromFile(thread, recordNameStr, abcFilePath); return JSNApiHelper::ToLocal(moduleNamespace); } Local JSNApi::GetModuleNameSpaceWithModuleInfo(EcmaVM *vm, const std::string &file, const std::string &module_path) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); ecmascript::CString moduleStr = ModulePathHelper::GetModuleNameWithPath(module_path.c_str()); ecmascript::CString srcPrefix = moduleStr + ModulePathHelper::PHYCICAL_FILE_PATH; std::string prefix = ConvertToStdString(srcPrefix); if (file.find(srcPrefix) == 0) { std::string fileName = file.substr(prefix.size() + 1); return GetModuleNameSpaceFromFile(vm, fileName, module_path); } ecmascript::CString requestPath = file.c_str(); ecmascript::CString modulePath = module_path.c_str(); JSHandle nameSp = ecmascript::NapiModuleLoader::LoadModuleNameSpaceWithModuleInfo(vm, requestPath, modulePath); return JSNApiHelper::ToLocal(nameSp); } // ---------------------------------- Promise ------------------------------------- Local PromiseRef::Catch(const EcmaVM *vm, Local handler) { ecmascript::ThreadManagedScope scope(vm->GetJSThread()); CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle promise = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(promise, ERROR); JSHandle catchKey(thread, constants->GetPromiseCatchString()); JSHandle reject = JSNApiHelper::ToJSHandle(handler); JSHandle undefined = constants->GetHandledUndefined(); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, promise, undefined, 1); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); #if ECMASCRIPT_ENABLE_STUB_ARGV_CHECK thread->CheckJSTaggedType(reject.GetTaggedValue().GetRawData()); #endif info->SetCallArg(reject.GetTaggedValue()); JSTaggedValue result = JSFunction::Invoke(info, catchKey); #if ECMASCRIPT_ENABLE_STUB_RESULT_CHECK thread->CheckJSTaggedType(result.GetRawData()); #endif RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(JSHandle(thread, result)); } Local PromiseRef::Finally(const EcmaVM *vm, Local handler) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope scope(vm->GetJSThread()); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle promise = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(promise, ERROR); JSHandle finallyKey = constants->GetHandledPromiseFinallyString(); JSHandle resolver = JSNApiHelper::ToJSHandle(handler); JSHandle undefined(constants->GetHandledUndefined()); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, promise, undefined, 2); // 2: two args RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); #if ECMASCRIPT_ENABLE_STUB_ARGV_CHECK thread->CheckJSTaggedType(resolver.GetTaggedValue().GetRawData()); thread->CheckJSTaggedType(undefined.GetTaggedValue().GetRawData()); #endif info->SetCallArg(resolver.GetTaggedValue(), undefined.GetTaggedValue()); JSTaggedValue result = JSFunction::Invoke(info, finallyKey); #if ECMASCRIPT_ENABLE_STUB_RESULT_CHECK thread->CheckJSTaggedType(result.GetRawData()); #endif RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(JSHandle(thread, result)); } Local PromiseRef::Then(const EcmaVM *vm, Local handler) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope scope(vm->GetJSThread()); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle promise = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(promise, ERROR); JSHandle thenKey(thread, constants->GetPromiseThenString()); JSHandle resolver = JSNApiHelper::ToJSHandle(handler); JSHandle undefined(constants->GetHandledUndefined()); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, promise, undefined, 2); // 2: two args RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); #if ECMASCRIPT_ENABLE_STUB_ARGV_CHECK thread->CheckJSTaggedType(resolver.GetTaggedValue().GetRawData()); thread->CheckJSTaggedType(undefined.GetTaggedValue().GetRawData()); #endif info->SetCallArg(resolver.GetTaggedValue(), undefined.GetTaggedValue()); JSTaggedValue result = JSFunction::Invoke(info, thenKey); #if ECMASCRIPT_ENABLE_STUB_RESULT_CHECK thread->CheckJSTaggedType(result.GetRawData()); #endif RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(JSHandle(thread, result)); } Local PromiseRef::Then(const EcmaVM *vm, Local onFulfilled, Local onRejected) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope scope(vm->GetJSThread()); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle promise = JSNApiHelper::ToJSHandle(this); LOG_IF_SPECIAL(promise, ERROR); JSHandle thenKey(thread, constants->GetPromiseThenString()); JSHandle resolver = JSNApiHelper::ToJSHandle(onFulfilled); JSHandle reject = JSNApiHelper::ToJSHandle(onRejected); JSHandle undefined(constants->GetHandledUndefined()); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, promise, undefined, 2); // 2: two args RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); #if ECMASCRIPT_ENABLE_STUB_ARGV_CHECK thread->CheckJSTaggedType(resolver.GetTaggedValue().GetRawData()); thread->CheckJSTaggedType(reject.GetTaggedValue().GetRawData()); #endif info->SetCallArg(resolver.GetTaggedValue(), reject.GetTaggedValue()); JSTaggedValue result = JSFunction::Invoke(info, thenKey); #if ECMASCRIPT_ENABLE_STUB_RESULT_CHECK thread->CheckJSTaggedType(result.GetRawData()); #endif RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(JSHandle(thread, result)); } Local PromiseRef::GetPromiseState(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope scope(vm->GetJSThread()); JSHandle promise(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(promise, ERROR); ecmascript::PromiseState state = promise->GetPromiseState(); std::string promiseStateStr; switch (state) { case ecmascript::PromiseState::PENDING: promiseStateStr = "Pending"; break; case ecmascript::PromiseState::FULFILLED: promiseStateStr = "Fulfilled"; break; case ecmascript::PromiseState::REJECTED: promiseStateStr = "Rejected"; break; } ObjectFactory *factory = vm->GetFactory(); return JSNApiHelper::ToLocal(JSHandle(factory->NewFromStdString(promiseStateStr))); } Local PromiseRef::GetPromiseResult(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope scope(vm->GetJSThread()); JSHandle promise(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(promise, ERROR); return JSNApiHelper::ToLocal(JSHandle(vm->GetJSThread(), promise->GetPromiseResult())); } // ---------------------------------- ProxyRef ----------------------------------------- Local ProxyRef::GetHandler(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope scope(vm->GetJSThread()); JSHandle jsProxy(JSNApiHelper::ToJSHandle(this)); return JSNApiHelper::ToLocal(JSHandle(thread, jsProxy->GetHandler())); } Local ProxyRef::GetTarget(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope scope(vm->GetJSThread()); JSHandle jsProxy(JSNApiHelper::ToJSHandle(this)); return JSNApiHelper::ToLocal(JSHandle(thread, jsProxy->GetTarget())); } bool ProxyRef::IsRevoked() { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, false); JSHandle jsProxy(JSNApiHelper::ToJSHandle(this)); return jsProxy->GetIsRevoked(); } // ---------------------------------- SetRef -------------------------------------- int32_t SetRef::GetSize(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle set(JSNApiHelper::ToJSHandle(this)); return set->GetSize(); } int32_t SetRef::GetTotalElements(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle set(JSNApiHelper::ToJSHandle(this)); return static_cast(set->GetSize()) + LinkedHashSet::Cast(set->GetLinkedSet().GetTaggedObject())->NumberOfDeletedElements(); } Local SetRef::GetValue(const EcmaVM *vm, int entry) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); JSHandle set(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(set, FATAL); return JSNApiHelper::ToLocal(JSHandle(thread, set->GetValue(entry))); } Local SetRef::New(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); ObjectFactory *factory = vm->GetJSThread()->GetEcmaVM()->GetFactory(); JSHandle env = vm->GetJSThread()->GetEcmaVM()->GetGlobalEnv(); JSHandle constructor = env->GetBuiltinsSetFunction(); JSHandle set = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(constructor), constructor)); JSHandle hashSet = LinkedHashSet::Create(vm->GetJSThread()); set->SetLinkedSet(vm->GetJSThread(), hashSet); JSHandle setTag = JSHandle::Cast(set); return JSNApiHelper::ToLocal(setTag); } void SetRef::Add(const EcmaVM *vm, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(thread); JSHandle set(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(set, ERROR); JSSet::Add(vm->GetJSThread(), set, JSNApiHelper::ToJSHandle(value)); } // ---------------------------------- WeakMapRef -------------------------------------- int32_t WeakMapRef::GetSize(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle weakMap(JSNApiHelper::ToJSHandle(this)); return weakMap->GetSize(); } int32_t WeakMapRef::GetTotalElements(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle weakMap(JSNApiHelper::ToJSHandle(this)); return weakMap->GetSize() + LinkedHashMap::Cast(weakMap->GetLinkedMap().GetTaggedObject())->NumberOfDeletedElements(); } Local WeakMapRef::GetKey(const EcmaVM *vm, int entry) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); JSHandle weakMap(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(weakMap, FATAL); JSTaggedValue key = weakMap->GetKey(entry); return JSNApiHelper::ToLocal(JSHandle(thread, key.GetWeakRawValue())); } Local WeakMapRef::GetValue(const EcmaVM *vm, int entry) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); JSHandle weakMap(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(weakMap, FATAL); return JSNApiHelper::ToLocal(JSHandle(thread, weakMap->GetValue(entry))); } Local WeakMapRef::New(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); ObjectFactory *factory = vm->GetJSThread()->GetEcmaVM()->GetFactory(); JSHandle env = vm->GetJSThread()->GetEcmaVM()->GetGlobalEnv(); JSHandle constructor = env->GetBuiltinsWeakMapFunction(); JSHandle weakMap = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(constructor), constructor)); JSHandle hashMap = LinkedHashMap::Create(vm->GetJSThread()); weakMap->SetLinkedMap(vm->GetJSThread(), hashMap); JSHandle weakMapTag = JSHandle::Cast(weakMap); return JSNApiHelper::ToLocal(weakMapTag); } void WeakMapRef::Set(const EcmaVM *vm, const Local &key, const Local &value) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(thread); JSHandle weakMap(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(weakMap, FATAL); JSWeakMap::Set(vm->GetJSThread(), weakMap, JSNApiHelper::ToJSHandle(key), JSNApiHelper::ToJSHandle(value)); } bool WeakMapRef::Has(const EcmaVM *vm, Local key) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); DCHECK_SPECIAL_VALUE_WITH_RETURN(this, false); ecmascript::ThreadManagedScope managedScope(thread); JSHandle weakMap(JSNApiHelper::ToJSHandle(this)); return weakMap->Has(thread, JSNApiHelper::ToJSTaggedValue(*key)); } // ---------------------------------- WeakSetRef -------------------------------------- int32_t WeakSetRef::GetSize(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle weakSet(JSNApiHelper::ToJSHandle(this)); return weakSet->GetSize(); } int32_t WeakSetRef::GetTotalElements(const EcmaVM *vm) { DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle weakSet(JSNApiHelper::ToJSHandle(this)); return weakSet->GetSize() + LinkedHashSet::Cast(weakSet->GetLinkedSet().GetTaggedObject())->NumberOfDeletedElements(); } Local WeakSetRef::GetValue(const EcmaVM *vm, int entry) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); JSHandle weakSet(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(weakSet, FATAL); JSTaggedValue value = weakSet->GetValue(entry); return JSNApiHelper::ToLocal(JSHandle(thread, value.GetWeakRawValue())); } Local WeakSetRef::New(const EcmaVM *vm) { CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); ecmascript::ThreadManagedScope managedScope(thread); ObjectFactory *factory = vm->GetJSThread()->GetEcmaVM()->GetFactory(); JSHandle env = vm->GetJSThread()->GetEcmaVM()->GetGlobalEnv(); JSHandle constructor = env->GetBuiltinsWeakSetFunction(); JSHandle weakSet = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(constructor), constructor)); JSHandle hashWeakSet = LinkedHashSet::Create(vm->GetJSThread()); weakSet->SetLinkedSet(vm->GetJSThread(), hashWeakSet); JSHandle setTag = JSHandle::Cast(weakSet); return JSNApiHelper::ToLocal(setTag); } void WeakSetRef::Add(const EcmaVM *vm, Local value) { CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(thread); JSHandle weakSet(JSNApiHelper::ToJSHandle(this)); LOG_IF_SPECIAL(weakSet, ERROR); JSWeakSet::Add(vm->GetJSThread(), weakSet, JSNApiHelper::ToJSHandle(value)); } TryCatch::~TryCatch() {} bool TryCatch::HasCaught() const { return ecmaVm_->GetJSThread()->HasPendingException(); } void TryCatch::Rethrow() { rethrow_ = true; } Local TryCatch::GetAndClearException() { ecmascript::ThreadManagedScope managedScope(ecmaVm_->GetJSThread()); return JSNApiHelper::ToLocal(ecmaVm_->GetAndClearEcmaUncaughtException()); } Local TryCatch::GetException() { ecmascript::ThreadManagedScope managedScope(ecmaVm_->GetJSThread()); return JSNApiHelper::ToLocal(ecmaVm_->GetEcmaUncaughtException()); } void TryCatch::ClearException() { ecmaVm_->GetJSThread()->ClearException(); } bool ExternalStringCache::RegisterStringCacheTable(const EcmaVM *vm, uint32_t size) { auto instance = ecmascript::Runtime::GetInstance(); ASSERT(instance != nullptr); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return instance->CreateStringCacheTable(size); } bool ExternalStringCache::SetCachedString(const EcmaVM *vm, const char *name, uint32_t propertyIndex) { auto instance = ecmascript::Runtime::GetInstance(); ASSERT(instance != nullptr); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); [[maybe_unused]] LocalScope scope(vm); ObjectFactory *factory = vm->GetFactory(); JSHandle str = factory->NewFromUtf8(name); return instance->SetCachedString(str, propertyIndex); } Local ExternalStringCache::GetCachedString(const EcmaVM *vm, uint32_t propertyIndex) { auto instance = ecmascript::Runtime::GetInstance(); ASSERT(instance != nullptr); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); JSHandle str = instance->GetCachedString(vm->GetJSThread(), propertyIndex); return JSNApiHelper::ToLocal(JSHandle(str)); } bool ExternalStringCache::HasCachedString([[maybe_unused]] const EcmaVM *vm, uint32_t propertyIndex) { auto instance = ecmascript::Runtime::GetInstance(); ASSERT(instance != nullptr); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); return instance->HasCachedString(propertyIndex); } } // namespace panda