arkcompiler_ets_runtime/ecmascript/napi/jsnapi_expo.cpp
openharmony_ci b070a9a866
!10057 Revert "Add Option Enable Force IC"
Merge pull request !10057 from zhuangkudecha/revertCloseForceIC
2024-11-22 00:16:01 +00:00

6369 lines
261 KiB
C++

/*
* 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 <array>
#include <cstdint>
#include <fcntl.h>
#include "ecmascript/base/json_stringifier.h"
#include "ecmascript/base/typed_array_helper-inl.h"
#include "ecmascript/builtins/builtins_object.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 <typename T>
using JSHandle = ecmascript::JSHandle<T>;
template <typename T>
using JSMutableHandle = ecmascript::JSMutableHandle<T>;
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";
}
bool JSNApi::isForked_ = false;
static Mutex *mutex = new panda::Mutex();
StartIdleMonitorCallback JSNApi::startIdleMonitorCallback_ = nullptr;
// ----------------------------------- JSValueRef --------------------------------------
Local<PrimitiveRef> JSValueRef::Undefined(const EcmaVM *vm)
{
return JSNApiHelper::ToLocal<PrimitiveRef>(
vm->GetJSThread()->GlobalConstants()->GetHandledUndefined());
}
Local<PrimitiveRef> JSValueRef::Null(const EcmaVM *vm)
{
return JSNApiHelper::ToLocal<PrimitiveRef>(
vm->GetJSThread()->GlobalConstants()->GetHandledNull());
}
Local<PrimitiveRef> JSValueRef::Hole(const EcmaVM *vm)
{
return JSNApiHelper::ToLocal<PrimitiveRef>(
vm->GetJSThread()->GlobalConstants()->GetHandledHole());
}
Local<PrimitiveRef> JSValueRef::True(const EcmaVM *vm)
{
return JSNApiHelper::ToLocal<PrimitiveRef>(
vm->GetJSThread()->GlobalConstants()->GetHandledTrue());
}
Local<PrimitiveRef> JSValueRef::False(const EcmaVM *vm)
{
return JSNApiHelper::ToLocal<PrimitiveRef>(
vm->GetJSThread()->GlobalConstants()->GetHandledFalse());
}
Local<ObjectRef> 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(thread);
JSHandle<JSTaggedValue> obj(JSTaggedValue::ToObject(thread, JSNApiHelper::ToJSHandle(this)));
LOG_IF_SPECIAL(obj, ERROR);
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return JSNApiHelper::ToLocal<ObjectRef>(obj);
}
Local<ObjectRef> JSValueRef::ToEcmaObject(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(obj, ERROR);
if (obj->IsECMAObject()) {
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return JSNApiHelper::ToLocal<ObjectRef>(obj);
}
return Undefined(vm);
}
Local<StringRef> JSValueRef::ToString(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(obj, ERROR);
if (!obj->IsString()) {
obj = JSHandle<JSTaggedValue>(JSTaggedValue::ToString(thread, obj));
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
}
return JSNApiHelper::ToLocal<StringRef>(obj);
}
Local<NativePointerRef> JSValueRef::ToNativePointer(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
// The function just get handle' value, and will not read and write js object. Don't need to switch state.
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(obj, ERROR);
return JSNApiHelper::ToLocal<NativePointerRef>(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(thread);
JSHandle<JSTaggedValue> 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(thread);
JSHandle<JSTaggedValue> 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(thread);
JSHandle<JSTaggedValue> 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<double>(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<int32_t>(ecmascript::base::NumberHelper::DoubleToInt(value.GetDouble(),
ecmascript::base::INT32_BITS));
}
isNumber = false;
return 0;
}
uint32_t JSValueRef::GetValueUint32(bool &isNumber)
{
return static_cast<uint32_t>(GetValueInt32(isNumber));
}
int64_t JSValueRef::GetValueInt64(bool &isNumber)
{
JSTaggedValue value = JSNApiHelper::ToJSTaggedValue(this);
if (value.IsInt()) {
isNumber = true;
return static_cast<int64_t>(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<BooleanRef> JSValueRef::ToBoolean(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(obj, ERROR);
JSHandle<JSTaggedValue> booleanObj(thread, JSTaggedValue(obj->ToBoolean()));
return JSNApiHelper::ToLocal<BooleanRef>(booleanObj);
}
Local<BigIntRef> JSValueRef::ToBigInt(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(obj, ERROR);
JSHandle<JSTaggedValue> bigIntObj(thread, JSTaggedValue::ToBigInt(thread, obj));
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return JSNApiHelper::ToLocal<BigIntRef>(bigIntObj);
}
Local<NumberRef> JSValueRef::ToNumber(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(obj, ERROR);
JSHandle<JSTaggedValue> number(thread, JSTaggedValue::ToNumber(thread, obj));
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return JSNApiHelper::ToLocal<NumberRef>(number);
}
bool JSValueRef::IsStrictEquals(const EcmaVM *vm, Local<JSValueRef> value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> xValue = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(xValue, ERROR);
JSHandle<JSTaggedValue> yValue = JSNApiHelper::ToJSHandle(value);
return JSTaggedValue::StrictEqual(thread, xValue, yValue);
}
Local<StringRef> JSValueRef::Typeof(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSTaggedValue value = FastRuntimeStub::FastTypeOf(thread, JSNApiHelper::ToJSTaggedValue(this));
return JSNApiHelper::ToLocal<StringRef>(JSHandle<JSTaggedValue>(thread, value));
}
bool JSValueRef::InstanceOf(const EcmaVM *vm, Local<JSValueRef> value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> origin = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(origin, ERROR);
JSHandle<JSTaggedValue> 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<JSTaggedValue> 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<JSTaggedValue> 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<JSTaggedValue> 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<JSTaggedValue> 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<JSTaggedValue> 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<JSTaggedValue> funcVal = JSNApiHelper::ToJSHandle(this);
JSHandle<JSFunction> transFunc = JSHandle<JSFunction>::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::IsBitVector(const EcmaVM *vm)
{
ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
return JSNApiHelper::ToJSTaggedValue(this).IsJSAPIBitVector();
}
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<JSTaggedValue> nativePointer = JSNApiHelper::ToJSHandle(this);
return JSHandle<JSNativePointer>(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<JSArrayBuffer> arrayBuffer(JSNApiHelper::ToJSHandle(this));
return arrayBuffer->IsDetach();
}
void JSValueRef::DetachedArraybuffer(const EcmaVM *vm, bool &isArrayBuffer)
{
auto thread = vm->GetJSThread();
ecmascript::ThreadManagedScope managedScope(thread);
if (IsArrayBuffer(vm)) {
JSHandle<JSArrayBuffer> arrayBuffer(JSNApiHelper::ToJSHandle(this));
if (arrayBuffer->IsDetach()) {
return;
}
arrayBuffer->Detach(thread);
isArrayBuffer = true;
} else if (IsSendableArrayBuffer(vm)) {
JSHandle<ecmascript::JSSendableArrayBuffer> arrayBuffer(JSNApiHelper::ToJSHandle(this));
if (arrayBuffer->IsDetach()) {
return;
}
arrayBuffer->Detach(thread);
isArrayBuffer = true;
} else {
isArrayBuffer = false;
}
}
void JSValueRef::GetDataViewInfo(const EcmaVM *vm,
bool &isDataView,
size_t *byteLength,
void **data,
JSValueRef **arrayBuffer,
size_t *byteOffset)
{
auto thread = vm->GetJSThread();
ecmascript::ThreadManagedScope managedScope(thread);
if (!IsDataView(vm)) {
isDataView = false;
return;
}
isDataView = true;
JSHandle<JSDataView> dataView(JSNApiHelper::ToJSHandle(this));
if (byteLength) {
*byteLength = dataView->GetByteLength();
}
if (data || arrayBuffer) {
JSHandle<JSArrayBuffer> 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<JSValueRef*>(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> DataViewRef::New(
const EcmaVM *vm, Local<ArrayBufferRef> arrayBuffer, uint32_t byteOffset, uint32_t byteLength)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSArrayBuffer> buffer(JSNApiHelper::ToJSHandle(arrayBuffer));
JSHandle<JSDataView> dataView = factory->NewJSDataView(buffer, byteOffset, byteLength);
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return JSNApiHelper::ToLocal<DataViewRef>(JSHandle<JSTaggedValue>(dataView));
}
uint32_t DataViewRef::ByteLength()
{
DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0);
JSHandle<JSDataView> dataView(JSNApiHelper::ToJSHandle(this));
return dataView->GetByteLength();
}
uint32_t DataViewRef::ByteOffset()
{
DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0);
JSHandle<JSDataView> dataView(JSNApiHelper::ToJSHandle(this));
return dataView->GetByteOffset();
}
Local<ArrayBufferRef> DataViewRef::GetArrayBuffer(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSDataView> dataView(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(dataView, FATAL);
JSHandle<JSTaggedValue> arrayBuffer(thread, dataView->GetViewedArrayBuffer());
return JSNApiHelper::ToLocal<ArrayBufferRef>(arrayBuffer);
}
// ---------------------------------- DataView -----------------------------------
// ----------------------------------- PritimitiveRef ---------------------------------------
Local<JSValueRef> PrimitiveRef::GetValue(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(obj, ERROR);
if (obj->IsJSPrimitiveRef()) {
JSTaggedValue primitiveValue = JSPrimitiveRef::Cast(obj->GetTaggedObject())->GetValue();
JSHandle<JSTaggedValue> value(thread, primitiveValue);
return JSNApiHelper::ToLocal<JSValueRef>(value);
}
return Local<JSValueRef>();
}
// ----------------------------------- NumberRef ---------------------------------------
Local<NumberRef> 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<JSTaggedValue> number(thread, JSTaggedValue(input), true);
return JSNApiHelper::ToLocal<NumberRef>(number);
}
Local<NumberRef> 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<JSTaggedValue> number(thread, JSTaggedValue(input), true);
return JSNApiHelper::ToLocal<NumberRef>(number);
}
Local<NumberRef> 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<JSTaggedValue> number(thread, JSTaggedValue(input), true);
return JSNApiHelper::ToLocal<NumberRef>(number);
}
Local<NumberRef> 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<JSTaggedValue> number(thread, JSTaggedValue(input), true);
return JSNApiHelper::ToLocal<NumberRef>(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<JSValueRef> MapRef::Get(const EcmaVM *vm, Local<JSValueRef> key)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSMap> map(JSNApiHelper::ToJSHandle(this));
return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread,
map->Get(thread, JSNApiHelper::ToJSTaggedValue(*key))));
}
Local<JSValueRef> MapRef::Get(const EcmaVM *vm, const char *utf8)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSMap> map(JSNApiHelper::ToJSHandle(this));
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSTaggedValue> key(factory->NewFromUtf8(utf8));
auto result = JSHandle<JSTaggedValue>(thread, map->Get(thread, key.GetTaggedValue()));
return JSNApiHelper::ToLocal<JSValueRef>(result);
}
void MapRef::Set(const EcmaVM *vm, Local<JSValueRef> key, Local<JSValueRef> value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSMap> map(JSNApiHelper::ToJSHandle(this));
JSMap::Set(thread, map, JSNApiHelper::ToJSHandle(key), JSNApiHelper::ToJSHandle(value));
}
void MapRef::Set(const EcmaVM *vm, const char *utf8, Local<JSValueRef> value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSMap> map(JSNApiHelper::ToJSHandle(this));
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSTaggedValue> key(factory->NewFromUtf8(utf8));
JSMap::Set(thread, map, key, JSNApiHelper::ToJSHandle(value));
}
bool MapRef::Has(const EcmaVM *vm, Local<JSValueRef> key)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSMap> 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(thread);
JSHandle<JSMap> map(JSNApiHelper::ToJSHandle(this));
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSTaggedValue> key(factory->NewFromUtf8(utf8));
bool result = map->Has(thread, key.GetTaggedValue());
return result;
}
void MapRef::Delete(const EcmaVM *vm, Local<JSValueRef> key)
{
CROSS_THREAD_AND_EXCEPTION_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSMap> 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(thread);
JSHandle<JSMap> map(JSNApiHelper::ToJSHandle(this));
JSMap::Clear(thread, map);
}
Local<MapRef> MapRef::New(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> constructor = env->GetBuiltinsMapFunction();
JSHandle<JSMap> map =
JSHandle<JSMap>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
JSHandle<LinkedHashMap> hashMap = LinkedHashMap::Create(thread);
map->SetLinkedMap(thread, hashMap);
JSHandle<JSTaggedValue> mapTag = JSHandle<JSTaggedValue>::Cast(map);
return JSNApiHelper::ToLocal<MapRef>(mapTag);
}
int32_t MapRef::GetSize(const EcmaVM *vm)
{
DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0);
ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
JSHandle<JSMap> 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<JSMap> map(JSNApiHelper::ToJSHandle(this));
return static_cast<int>((map->GetSize())) +
LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())->NumberOfDeletedElements();
}
Local<JSValueRef> MapRef::GetKey(const EcmaVM *vm, int entry)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSMap> map(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(map, FATAL);
return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, map->GetKey(entry)));
}
Local<JSValueRef> MapRef::GetValue(const EcmaVM *vm, int entry)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSMap> map(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(map, FATAL);
return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, map->GetValue(entry)));
}
Local<MapIteratorRef> 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(thread);
JSHandle<ecmascript::JSTaggedValue> map(JSNApiHelper::ToJSHandle(this));
JSHandle<JSTaggedValue> mapIter =
ecmascript::JSMapIterator::CreateMapIterator(thread, map, IterationKind::KEY_AND_VALUE);
return JSNApiHelper::ToLocal<MapIteratorRef>(mapIter);
}
Local<MapIteratorRef> 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(thread);
JSHandle<ecmascript::JSTaggedValue> map(JSNApiHelper::ToJSHandle(this));
JSHandle<JSTaggedValue> mapIter = ecmascript::JSMapIterator::CreateMapIterator(thread, map, IterationKind::KEY);
return JSNApiHelper::ToLocal<MapIteratorRef>(mapIter);
}
Local<MapIteratorRef> 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(thread);
JSHandle<ecmascript::JSTaggedValue> map(JSNApiHelper::ToJSHandle(this));
JSHandle<JSTaggedValue> mapIter = ecmascript::JSMapIterator::CreateMapIterator(thread, map, IterationKind::VALUE);
return JSNApiHelper::ToLocal<MapIteratorRef>(mapIter);
}
// SendableMapRef
Local<SendableMapRef> 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<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<JSTaggedValue> constructor = env->GetSBuiltininMapFunction();
ASSERT(constructor->IsJSSharedFunction() && constructor.GetTaggedValue().IsInSharedHeap());
JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor);
ASSERT(obj.GetTaggedValue().IsInSharedHeap());
JSHandle<ecmascript::JSSharedMap> sharedMap = JSHandle<ecmascript::JSSharedMap>::Cast(obj);
JSHandle<LinkedHashMap> linkedMap =
LinkedHashMap::Create(thread, LinkedHashMap::MIN_CAPACITY, ecmascript::MemSpaceKind::SHARED);
sharedMap->SetLinkedMap(thread, linkedMap);
JSHandle<JSTaggedValue> sharedMapTag = JSHandle<JSTaggedValue>::Cast(sharedMap);
return JSNApiHelper::ToLocal<SendableMapRef>(sharedMapTag);
}
Local<JSValueRef> SendableMapRef::Get(const EcmaVM *vm, Local<JSValueRef> key)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<ecmascript::JSSharedMap> map(JSNApiHelper::ToJSHandle(this));
return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread,
ecmascript::JSSharedMap::Get(thread, map, JSNApiHelper::ToJSTaggedValue(*key))));
}
Local<JSValueRef> SendableMapRef::Get(const EcmaVM *vm, const char *utf8)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<ecmascript::JSSharedMap> map(JSNApiHelper::ToJSHandle(this));
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSTaggedValue> key(factory->NewFromUtf8(utf8));
auto result = JSHandle<JSTaggedValue>(thread, ecmascript::JSSharedMap::Get(thread, map, key.GetTaggedValue()));
return JSNApiHelper::ToLocal<JSValueRef>(result);
}
void SendableMapRef::Set(const EcmaVM *vm, Local<JSValueRef> key, Local<JSValueRef> value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<ecmascript::JSSharedMap> 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<JSValueRef> value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<ecmascript::JSSharedMap> map(JSNApiHelper::ToJSHandle(this));
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSTaggedValue> key(factory->NewFromUtf8(utf8));
ecmascript::JSSharedMap::Set(thread, map, key, JSNApiHelper::ToJSHandle(value));
}
bool SendableMapRef::Has(const EcmaVM *vm, Local<JSValueRef> key)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<ecmascript::JSSharedMap> 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<ecmascript::JSSharedMap> map(JSNApiHelper::ToJSHandle(this));
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSTaggedValue> key(factory->NewFromUtf8(utf8));
bool result = ecmascript::JSSharedMap::Has(thread, map, key.GetTaggedValue());
return result;
}
void SendableMapRef::Delete(const EcmaVM *vm, Local<JSValueRef> key)
{
CROSS_THREAD_AND_EXCEPTION_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<ecmascript::JSSharedMap> 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<ecmascript::JSSharedMap> 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(thread);
JSHandle<ecmascript::JSSharedMap> 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(thread);
JSHandle<ecmascript::JSSharedMap> map(JSNApiHelper::ToJSHandle(this));
return static_cast<int>(ecmascript::JSSharedMap::GetSize(thread, map)) +
LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())->NumberOfDeletedElements();
}
Local<JSValueRef> SendableMapRef::GetKey(const EcmaVM *vm, int entry)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<ecmascript::JSSharedMap> map(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(map, FATAL);
return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread,
ecmascript::JSSharedMap::GetKey(thread, map, entry)));
}
Local<JSValueRef> SendableMapRef::GetValue(const EcmaVM *vm, int entry)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<ecmascript::JSSharedMap> map(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(map, FATAL);
return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread,
ecmascript::JSSharedMap::GetValue(thread, map, entry)));
}
Local<SendableMapIteratorRef> 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(thread);
JSHandle<ecmascript::JSTaggedValue> map(JSNApiHelper::ToJSHandle(this));
JSHandle<JSTaggedValue> sharedMapIter =
ecmascript::JSSharedMapIterator::CreateMapIterator(thread, map, IterationKind::KEY_AND_VALUE);
return JSNApiHelper::ToLocal<SendableMapIteratorRef>(sharedMapIter);
}
Local<SendableMapIteratorRef> 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(thread);
JSHandle<ecmascript::JSTaggedValue> map(JSNApiHelper::ToJSHandle(this));
JSHandle<JSTaggedValue> sharedMapIter =
ecmascript::JSSharedMapIterator::CreateMapIterator(thread, map, IterationKind::KEY);
return JSNApiHelper::ToLocal<SendableMapIteratorRef>(sharedMapIter);
}
Local<SendableMapIteratorRef> 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(thread);
JSHandle<ecmascript::JSTaggedValue> map(JSNApiHelper::ToJSHandle(this));
JSHandle<JSTaggedValue> sharedMapIter =
ecmascript::JSSharedMapIterator::CreateMapIterator(thread, map, IterationKind::VALUE);
return JSNApiHelper::ToLocal<SendableMapIteratorRef>(sharedMapIter);
}
// SendableSetRef
Local<SendableSetRef> 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<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<JSTaggedValue> constructor = env->GetSBuiltininSetFunction();
ASSERT(constructor->IsJSSharedFunction() && constructor.GetTaggedValue().IsInSharedHeap());
JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor);
ASSERT(obj.GetTaggedValue().IsInSharedHeap());
JSHandle<ecmascript::JSSharedSet> set = JSHandle<ecmascript::JSSharedSet>::Cast(obj);
JSHandle<LinkedHashSet> linkedSet =
LinkedHashSet::Create(thread, LinkedHashSet::MIN_CAPACITY, ecmascript::MemSpaceKind::SHARED);
set->SetLinkedSet(thread, linkedSet);
JSHandle<JSTaggedValue> sharedSetTag = JSHandle<JSTaggedValue>::Cast(set);
return JSNApiHelper::ToLocal<SendableSetRef>(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(thread);
JSHandle<ecmascript::JSSharedSet> 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(thread);
JSHandle<ecmascript::JSSharedSet> set(JSNApiHelper::ToJSHandle(this));
return static_cast<int>(ecmascript::JSSharedSet::GetSize(thread, set)) +
LinkedHashSet::Cast(set->GetLinkedSet().GetTaggedObject())->NumberOfDeletedElements();
}
Local<JSValueRef> SendableSetRef::GetValue(const EcmaVM *vm, int entry)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<ecmascript::JSSharedSet> set(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(set, FATAL);
return JSNApiHelper::ToLocal<JSValueRef>(
JSHandle<JSTaggedValue>(thread, ecmascript::JSSharedSet::GetValue(thread, set, entry)));
}
void SendableSetRef::Add(const EcmaVM *vm, Local<JSValueRef> value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<ecmascript::JSSharedSet> 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<JSMapIterator> jsMapIter(JSNApiHelper::ToJSHandle(this));
return jsMapIter->GetNextIndex();
}
Local<JSValueRef> MapIteratorRef::GetKind(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSMapIterator> jsMapIter(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(jsMapIter, FATAL);
IterationKind iterKind = jsMapIter->GetIterationKind();
Local<JSValueRef> result;
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
switch (iterKind) {
case IterationKind::KEY:
result = JSNApiHelper::ToLocal<JSValueRef>(globalConst->GetHandledKeysString());
break;
case IterationKind::VALUE:
result = JSNApiHelper::ToLocal<JSValueRef>(globalConst->GetHandledValuesString());
break;
case IterationKind::KEY_AND_VALUE:
result = JSNApiHelper::ToLocal<JSValueRef>(globalConst->GetHandledEntriesString());
break;
default:
break;
}
return result;
}
Local<MapIteratorRef> MapIteratorRef::New(const EcmaVM *vm, Local<MapRef> map)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSMap> jsMap(JSNApiHelper::ToJSHandle(map));
IterationKind iterKind = IterationKind::KEY_AND_VALUE;
JSHandle<JSTaggedValue> mapIteratorKeyAndValue =
JSMapIterator::CreateMapIterator(vm->GetJSThread(), JSHandle<JSTaggedValue>::Cast(jsMap), iterKind);
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return JSNApiHelper::ToLocal<JSValueRef>(mapIteratorKeyAndValue);
}
ecmascript::EcmaRuntimeCallInfo *MapIteratorRef::GetEcmaRuntimeCallInfo(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, nullptr);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSMapIterator> jsMapIter(JSNApiHelper::ToJSHandle(this));
JSHandle<LinkedHashMap> linkedHashMap(thread, jsMapIter->GetIteratedMap());
uint32_t size = linkedHashMap->GetLength();
return ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread,
JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()),
JSHandle<JSTaggedValue>(thread, jsMapIter.GetTaggedValue()),
JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()), size);
}
Local<ArrayRef> MapIteratorRef::Next(const EcmaVM *vm, ecmascript::EcmaRuntimeCallInfo *ecmaRuntimeCallInfo)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> nextTagValResult(thread, JSMapIterator::Next(ecmaRuntimeCallInfo));
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
JSHandle<JSTaggedValue> iteratorVal(thread,
JSIterator::IteratorValue(thread, nextTagValResult).GetTaggedValue());
return JSNApiHelper::ToLocal<ArrayRef>(iteratorVal);
}
Local<JSValueRef> MapIteratorRef::Next(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> mapIter(JSNApiHelper::ToJSHandle(this));
auto result = JSMapIterator::NextInternal(thread, mapIter);
return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, result));
}
// SendableMapIteratorRef
Local<JSValueRef> SendableMapIteratorRef::Next(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> sharedMapIter(JSNApiHelper::ToJSHandle(this));
auto result = ecmascript::JSSharedMapIterator::NextInternal(thread, sharedMapIter);
return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, result));
}
// ----------------------------------- SetIteratorRef ---------------------------------------
int32_t SetIteratorRef::GetIndex()
{
DCHECK_SPECIAL_VALUE_WITH_RETURN(this, -1);
JSHandle<JSSetIterator> jsSetIter(JSNApiHelper::ToJSHandle(this));
return jsSetIter->GetNextIndex();
}
Local<JSValueRef> SetIteratorRef::GetKind(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSSetIterator> jsSetIter(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(jsSetIter, FATAL);
IterationKind iterKind = jsSetIter->GetIterationKind();
Local<JSValueRef> result;
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
switch (iterKind) {
case IterationKind::KEY:
result = JSNApiHelper::ToLocal<JSValueRef>(globalConst->GetHandledKeysString());
break;
case IterationKind::VALUE:
result = JSNApiHelper::ToLocal<JSValueRef>(globalConst->GetHandledValuesString());
break;
case IterationKind::KEY_AND_VALUE:
result = JSNApiHelper::ToLocal<JSValueRef>(globalConst->GetHandledEntriesString());
break;
default:
break;
}
return result;
}
Local<SetIteratorRef> SetIteratorRef::New(const EcmaVM *vm, Local<SetRef> set)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSSet> jsSet(JSNApiHelper::ToJSHandle(set));
IterationKind iterKind = IterationKind::KEY_AND_VALUE;
JSHandle<JSTaggedValue> setIteratorKeyAndValue =
JSSetIterator::CreateSetIterator(thread, JSHandle<JSTaggedValue>::Cast(jsSet), iterKind);
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return JSNApiHelper::ToLocal<JSValueRef>(setIteratorKeyAndValue);
}
ecmascript::EcmaRuntimeCallInfo *SetIteratorRef::GetEcmaRuntimeCallInfo(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, nullptr);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSSetIterator> jsSetIter(JSNApiHelper::ToJSHandle(this));
JSHandle<LinkedHashSet> linkedHashSet(thread, jsSetIter->GetIteratedSet());
uint32_t size = linkedHashSet->GetLength();
return ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread,
JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()),
JSHandle<JSTaggedValue>(thread, jsSetIter.GetTaggedValue()),
JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()), size);
}
Local<ArrayRef> SetIteratorRef::Next(const EcmaVM *vm, ecmascript::EcmaRuntimeCallInfo *ecmaRuntimeCallInfo)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> nextTagValResult(thread, JSSetIterator::Next(ecmaRuntimeCallInfo));
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
JSHandle<JSTaggedValue> iteratorVal(thread,
JSIterator::IteratorValue(thread, nextTagValResult).GetTaggedValue());
return JSNApiHelper::ToLocal<ArrayRef>(iteratorVal);
}
// ---------------------------------- Buffer -----------------------------------
Local<BufferRef> BufferRef::New(const EcmaVM *vm, int32_t length)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSArrayBuffer> arrayBuffer = JSHandle<JSArrayBuffer>::Cast(factory->NewJSArrayBuffer(length));
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<JSFunction> current =
factory->NewJSFunction(env, reinterpret_cast<void *>(BufferRef::BufferToStringCallback));
Local<StringRef> key = StringRef::NewFromUtf8(vm, "toString");
JSHandle<JSTaggedValue> keyValue = JSNApiHelper::ToJSHandle(key);
JSHandle<JSTaggedValue> currentTaggedValue(current);
JSHandle<JSTaggedValue> 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<BufferRef>(obj);
}
Local<BufferRef> 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(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSArrayBuffer> arrayBuffer = factory->NewJSArrayBuffer(buffer, length, deleter, data);
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<JSFunction> current =
factory->NewJSFunction(env, reinterpret_cast<void *>(BufferRef::BufferToStringCallback));
Local<StringRef> key = StringRef::NewFromUtf8(vm, "toString");
JSHandle<JSTaggedValue> keyValue = JSNApiHelper::ToJSHandle(key);
JSHandle<JSTaggedValue> currentTaggedValue(current);
JSHandle<JSTaggedValue> 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<ArrayBufferRef>(JSHandle<JSTaggedValue>(arrayBuffer));
}
int32_t BufferRef::ByteLength(const EcmaVM *vm)
{
DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0);
ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
JSHandle<JSArrayBuffer> 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<JSArrayBuffer> 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<JSTaggedValue> arrayBuff = ecmaRuntimeCallInfo->GetThis();
JSHandle<JSArrayBuffer> arrayBuffer(arrayBuff);
uint32_t length = arrayBuffer->GetArrayBufferByteLength();
JSTaggedValue data = arrayBuffer->GetArrayBufferData();
ecmascript::CVector<uint16_t> valueTable;
valueTable.reserve(length);
for (uint32_t i = 0; i < length; i++) {
void* rawData = reinterpret_cast<void *>(
ToUintPtr(JSNativePointer::Cast(data.GetTaggedObject())->GetExternalPointer()) + i);
uint8_t *block = reinterpret_cast<uint8_t *>(rawData);
uint16_t nextCv = static_cast<uint16_t>(*block);
valueTable.emplace_back(nextCv);
}
auto *char16tData0 = reinterpret_cast<const char16_t *>(valueTable.data());
std::u16string u16str(char16tData0, length);
const char16_t *constChar16tData = u16str.data();
auto *char16tData = const_cast<char16_t *>(constChar16tData);
auto *uint16tData = reinterpret_cast<uint16_t *>(char16tData);
uint32_t u16strSize = u16str.size();
JSTaggedValue rString = factory->NewFromUtf16Literal(uint16tData, u16strSize).GetTaggedValue();
JSHandle<EcmaString> StringHandle = JSTaggedValue::ToString(thread, rString);
RETURN_VALUE_IF_ABRUPT(thread, JSTaggedValue::Undefined());
return StringHandle.GetTaggedValue();
}
// ---------------------------------- Promise --------------------------------------
Local<PromiseCapabilityRef> PromiseCapabilityRef::New(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<GlobalEnv> globalEnv = vm->GetGlobalEnv();
JSHandle<JSTaggedValue> constructor(globalEnv->GetPromiseFunction());
JSHandle<JSTaggedValue> capability(JSPromise::NewPromiseCapability(thread, constructor));
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return JSNApiHelper::ToLocal<PromiseCapabilityRef>(capability);
}
Local<PromiseRef> PromiseCapabilityRef::GetPromise(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<PromiseCapability> capacity(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(capacity, FATAL);
return JSNApiHelper::ToLocal<PromiseRef>(JSHandle<JSTaggedValue>(thread, capacity->GetPromise()));
}
bool PromiseCapabilityRef::Resolve(const EcmaVM *vm, uintptr_t value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
const GlobalEnvConstants *constants = thread->GlobalConstants();
JSTaggedValue arg = *reinterpret_cast<JSTaggedValue *>(value);
#if ECMASCRIPT_ENABLE_STUB_ARGV_CHECK
thread->CheckJSTaggedType(arg.GetRawData());
#endif
JSHandle<PromiseCapability> 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<JSValueRef> value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
const GlobalEnvConstants *constants = thread->GlobalConstants();
JSHandle<JSTaggedValue> arg = JSNApiHelper::ToJSHandle(value);
#if ECMASCRIPT_ENABLE_STUB_ARGV_CHECK
thread->CheckJSTaggedType(arg.GetTaggedValue().GetRawData());
#endif
JSHandle<PromiseCapability> capacity(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(capacity, FATAL);
JSHandle<JSTaggedValue> resolve(thread, capacity->GetResolve());
JSHandle<JSTaggedValue> 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(thread);
const GlobalEnvConstants *constants = thread->GlobalConstants();
JSTaggedValue arg = *reinterpret_cast<JSTaggedValue *>(reason);
#if ECMASCRIPT_ENABLE_STUB_ARGV_CHECK
thread->CheckJSTaggedType(arg.GetRawData());
#endif
JSHandle<PromiseCapability> 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<JSValueRef> reason)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
const GlobalEnvConstants *constants = thread->GlobalConstants();
JSHandle<JSTaggedValue> arg = JSNApiHelper::ToJSHandle(reason);
#if ECMASCRIPT_ENABLE_STUB_ARGV_CHECK
thread->CheckJSTaggedType(arg.GetTaggedValue().GetRawData());
#endif
JSHandle<PromiseCapability> capacity(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(capacity, FATAL);
JSHandle<JSTaggedValue> reject(thread, capacity->GetReject());
JSHandle<JSTaggedValue> 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> SymbolRef::New(const EcmaVM *vm, Local<StringRef> description)
{
// Omit exception check because ark calls here may not
// cause side effect even pending exception exists.
CROSS_THREAD_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSSymbol> symbol = factory->NewJSSymbol();
if (!description.IsEmpty()) {
JSTaggedValue desc = JSNApiHelper::ToJSTaggedValue(*description);
symbol->SetDescription(thread, desc);
}
return JSNApiHelper::ToLocal<SymbolRef>(JSHandle<JSTaggedValue>(symbol));
}
Local<StringRef> SymbolRef::GetDescription(const EcmaVM *vm)
{
CROSS_THREAD_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
JSTaggedValue description = JSSymbol::Cast(
JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject())->GetDescription();
if (!description.IsString()) {
auto constants = thread->GlobalConstants();
return JSNApiHelper::ToLocal<StringRef>(constants->GetHandledEmptyString());
}
JSHandle<JSTaggedValue> descriptionHandle(thread, description);
return JSNApiHelper::ToLocal<StringRef>(descriptionHandle);
}
// ----------------------------------- BooleanRef ---------------------------------------
Local<BooleanRef> 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(thread);
JSHandle<JSTaggedValue> boolean(thread, JSTaggedValue(value));
return JSNApiHelper::ToLocal<BooleanRef>(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> 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(thread);
ObjectFactory *factory = vm->GetFactory();
if (length < 0) {
JSHandle<JSTaggedValue> current(factory->NewFromUtf8(utf8));
return JSNApiHelper::ToLocal<StringRef>(current);
}
JSHandle<JSTaggedValue> current(factory->NewFromUtf8(reinterpret_cast<const uint8_t *>(utf8), length));
return JSNApiHelper::ToLocal<StringRef>(current);
}
Local<StringRef> 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(thread);
ObjectFactory *factory = vm->GetFactory();
if (length < 0) {
JSHandle<JSTaggedValue> current(factory->NewFromUtf8WithoutStringTable(utf8));
return JSNApiHelper::ToLocal<StringRef>(current);
}
JSHandle<JSTaggedValue> current(factory->NewFromUtf8WithoutStringTable(reinterpret_cast<const uint8_t *>(utf8),
length));
return JSNApiHelper::ToLocal<StringRef>(current);
}
Local<StringRef> 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(thread);
ObjectFactory *factory = vm->GetFactory();
if (length < 0) {
JSHandle<JSTaggedValue> current(factory->NewFromUtf16WithoutStringTable(utf16));
return JSNApiHelper::ToLocal<StringRef>(current);
}
JSHandle<JSTaggedValue> current(factory->NewFromUtf16WithoutStringTable(reinterpret_cast<const uint16_t *>(utf16),
length));
return JSNApiHelper::ToLocal<StringRef>(current);
}
Local<StringRef> 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(thread);
ObjectFactory *factory = vm->GetFactory();
if (length < 0) {
JSHandle<JSTaggedValue> current(factory->NewFromUtf16(utf16));
return JSNApiHelper::ToLocal<StringRef>(current);
}
JSHandle<JSTaggedValue> current(factory->NewFromUtf16(reinterpret_cast<const uint16_t *>(utf16), length));
return JSNApiHelper::ToLocal<StringRef>(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);
auto thread = vm->GetJSThread();
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<EcmaString> strHandle(thread, 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<uint8_t *>(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<uint16_t *>(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<uint8_t *>(buffer), length);
}
Local<StringRef> 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(thread);
JSHandle<JSTaggedValue> napiWapperString = thread->GlobalConstants()->GetHandledNapiWrapperString();
return JSNApiHelper::ToLocal<StringRef>(napiWapperString);
}
Local<TypedArrayRef> StringRef::EncodeIntoUint8Array(const EcmaVM *vm)
{
CROSS_THREAD_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> 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<JSObject> obj =
TypedArrayHelper::FastCreateTypedArray(thread, thread->GlobalConstants()->GetHandledUint8ArrayString(),
length - 1, DataViewType::UINT8);
JSHandle<JSObject> arrayBuffer(thread, JSTypedArray::Cast(*obj)->GetViewedArrayBufferOrByteArray());
JSTaggedValue bufferData = JSHandle<JSArrayBuffer>::Cast(arrayBuffer)->GetArrayBufferData();
void *buffer = JSNativePointer::Cast(bufferData.GetTaggedObject())->GetExternalPointer();
JSHandle<EcmaString> stringHandle = JSHandle<EcmaString>::Cast(string);
EcmaStringAccessor(stringHandle).WriteToFlatUtf8(reinterpret_cast<uint8_t*>(buffer), length - 1, true);
JSHandle<JSTaggedValue> typedArrayTag = JSHandle<JSTaggedValue>::Cast(obj);
return JSNApiHelper::ToLocal<TypedArrayRef>(typedArrayTag);
}
// ---------------------------------- PromiseRejectInfo ---------------------------------
PromiseRejectInfo::PromiseRejectInfo(Local<JSValueRef> promise, Local<JSValueRef> reason,
PromiseRejectInfo::PROMISE_REJECTION_EVENT operation, void* data)
: promise_(promise), reason_(reason), operation_(operation), data_(data) {}
Local<JSValueRef> PromiseRejectInfo::GetPromise() const
{
return promise_;
}
Local<JSValueRef> PromiseRejectInfo::GetReason() const
{
return reason_;
}
PromiseRejectInfo::PROMISE_REJECTION_EVENT PromiseRejectInfo::GetOperation() const
{
return operation_;
}
void* PromiseRejectInfo::GetData() const
{
return data_;
}
// ----------------------------------- BigIntRef ---------------------------------------
Local<BigIntRef> 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(thread);
JSHandle<BigInt> big = BigInt::Uint64ToBigInt(thread, input);
JSHandle<JSTaggedValue> bigint = JSHandle<JSTaggedValue>::Cast(big);
return JSNApiHelper::ToLocal<BigIntRef>(bigint);
}
Local<BigIntRef> 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(thread);
JSHandle<BigInt> big = BigInt::Int64ToBigInt(thread, input);
JSHandle<JSTaggedValue> bigint = JSHandle<JSTaggedValue>::Cast(big);
return JSNApiHelper::ToLocal<BigIntRef>(bigint);
}
Local<JSValueRef> 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(thread);
JSHandle<BigInt> big = BigInt::CreateBigWords(thread, sign, size, words);
JSHandle<JSTaggedValue> bigint = JSHandle<JSTaggedValue>::Cast(big);
return JSNApiHelper::ToLocal<JSValueRef>(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(thread);
JSHandle<JSTaggedValue> 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(thread);
JSHandle<JSTaggedValue> 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<BigInt> 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<uint64_t>(bigintVal->GetDigit(count++));
words[index] |= static_cast<uint64_t>(bigintVal->GetDigit(count++)) << 32; // 32 : int32_t bits
}
if (len % 2 == 0) { // 2 : len is odd or even
words[index] = static_cast<uint64_t>(bigintVal->GetDigit(count++));
words[index] |= static_cast<uint64_t>(bigintVal->GetDigit(count++)) << 32; // 32 : int32_t bits
} else {
words[index] = static_cast<uint64_t>(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<BigInt> 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<JSThread *>(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<JSThread *>(thread_));
// Simply reserve a slot on the handlescope. The escaped handle will still be retained in this slot.
ecmascript::EcmaHandleScope::NewHandle(reinterpret_cast<JSThread *>(thread_), value);
auto context = reinterpret_cast<JSThread *>(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<JSThread *>(thread_));
auto context = reinterpret_cast<JSThread *>(thread_)->GetCurrentEcmaContext();
#ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK
context->HandleScopeCountDec();
context->PrimitiveScopeCountDec();
#endif
context->SetHandleScopeStorageNext(static_cast<JSTaggedType *>(prevNext_));
context->SetPrimitiveScopeStorageNext(static_cast<JSTaggedType *>(prevPrimitiveNext_));
if (context->GetHandleScopeStorageEnd() != prevEnd_) {
context->SetHandleScopeStorageEnd(static_cast<JSTaggedType *>(prevEnd_));
context->ShrinkHandleStorage(prevHandleStorageIndex_);
}
if (context->GetPrimitiveScopeStorageEnd() != prevPrimitiveEnd_) {
context->SetPrimitiveScopeStorageEnd(static_cast<JSTaggedType *>(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> 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<JSTaggedValue> integer(thread, JSTaggedValue(input));
return JSNApiHelper::ToLocal<IntegerRef>(integer);
}
Local<IntegerRef> 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<JSTaggedValue> integer(thread, JSTaggedValue(input));
return JSNApiHelper::ToLocal<IntegerRef>(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> ObjectRef::New(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<GlobalEnv> globalEnv = vm->GetGlobalEnv();
JSHandle<JSFunction> constructor(globalEnv->GetObjectFunction());
JSHandle<JSTaggedValue> object(factory->NewJSObjectByConstructor(constructor));
return JSNApiHelper::ToLocal<ObjectRef>(object);
}
uintptr_t ObjectRef::NewObject(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm,
(thread->GlobalConstants()->GetHandledUndefined()).GetAddress());
ecmascript::ThreadManagedScope managedScope(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<GlobalEnv> globalEnv = vm->GetGlobalEnv();
JSHandle<JSFunction> constructor(globalEnv->GetObjectFunction());
JSHandle<JSTaggedValue> object(factory->NewJSObjectByConstructor(constructor));
return object.GetAddress();
}
Local<ObjectRef> ObjectRef::NewS(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<GlobalEnv> globalEnv = vm->GetGlobalEnv();
JSHandle<JSFunction> constructor(globalEnv->GetSObjectFunction());
JSHandle<JSTaggedValue> object(factory->NewJSObjectByConstructor(constructor));
return JSNApiHelper::ToLocal<ObjectRef>(object);
}
Local<ObjectRef> ObjectRef::NewWithProperties(const EcmaVM *vm, size_t propertyCount,
const Local<JSValueRef> *keys,
const PropertyAttribute *attributes)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
EscapeLocalScope scope(vm);
JSHandle<JSTaggedValue> obj;
auto CreateObjImpl = [vm, thread, propertyCount, keys, attributes] (uintptr_t head) -> JSHandle<JSTaggedValue> {
const PropertyDescriptor *desc = reinterpret_cast<const PropertyDescriptor *>(head);
for (size_t i = 0; i < propertyCount; ++i) {
const PropertyAttribute &attr = attributes[i];
new (reinterpret_cast<void *>(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<uintptr_t>(desc));
} else {
void *desc = malloc(sizeof(PropertyDescriptor) * propertyCount);
obj = CreateObjImpl(reinterpret_cast<uintptr_t>(desc));
free(desc);
}
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return scope.Escape(JSNApiHelper::ToLocal<ObjectRef>(obj));
}
Local<ObjectRef> ObjectRef::NewSWithProperties(const EcmaVM *vm, SendablePropertiesInfo &info)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
EscapeLocalScope scope(vm);
ObjectFactory *factory = vm->GetFactory();
std::vector<PropertyDescriptor> descs;
JSNapiSendable::InitWithPropertiesInfo(thread, info, descs);
auto obj = factory->CreateSObjectWithProperties(descs);
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return scope.Escape(JSNApiHelper::ToLocal<ObjectRef>(obj));
}
Local<ObjectRef> ObjectRef::NewWithNamedProperties(const EcmaVM *vm, size_t propertyCount,
const char **keys, const Local<JSValueRef> *values)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
EscapeLocalScope scope(vm);
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSTaggedValue> obj = factory->CreateJSObjectWithNamedProperties(propertyCount, keys, values);
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return scope.Escape(JSNApiHelper::ToLocal<ObjectRef>(obj));
}
Local<ObjectRef> ObjectRef::CreateNativeModuleFailureInfo(const EcmaVM *vm, const std::string &failureInfo)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
if (EcmaVM::GetErrorInfoEnhance()) {
JSHandle<NativeModuleFailureInfo> nativeModuleErrorFailureInfo =
NativeModuleFailureInfo::CreateNativeModuleFailureInfo(vm, failureInfo);
return JSNApiHelper::ToLocal<ObjectRef>(JSHandle<JSTaggedValue>::Cast(nativeModuleErrorFailureInfo));
}
return JSValueRef::Undefined(vm);
}
Local<ObjectRef> ObjectRef::CreateAccessorData(const EcmaVM *vm,
Local<FunctionRef> getter, Local<FunctionRef> setter)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> getterValue = JSNApiHelper::ToJSHandle(getter);
JSHandle<JSTaggedValue> setterValue = JSNApiHelper::ToJSHandle(setter);
JSHandle<AccessorData> accessor = thread->GetEcmaVM()->GetFactory()->NewAccessorData();
accessor->SetGetter(thread, getterValue);
accessor->SetSetter(thread, setterValue);
return JSNApiHelper::ToLocal<ObjectRef>(JSHandle<JSTaggedValue>::Cast(accessor));
}
Local<ObjectRef> ObjectRef::CreateSendableAccessorData(const EcmaVM *vm,
Local<FunctionRef> getter,
Local<FunctionRef> setter)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> getterValue = JSNApiHelper::ToJSHandle(getter);
JSHandle<JSTaggedValue> setterValue = JSNApiHelper::ToJSHandle(setter);
JSHandle<AccessorData> accessor = thread->GetEcmaVM()->GetFactory()->NewSAccessorData();
accessor->SetGetter(thread, getterValue);
accessor->SetSetter(thread, setterValue);
return JSNApiHelper::ToLocal<ObjectRef>(JSHandle<JSTaggedValue>::Cast(accessor));
}
bool ObjectRef::ConvertToNativeBindingObject(const EcmaVM *vm, Local<NativePointerRef> value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
[[maybe_unused]] LocalScope scope(vm);
JSHandle<JSTaggedValue> object = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(object, ERROR);
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<JSTaggedValue> keyValue = env->GetNativeBindingSymbol();
JSHandle<JSTaggedValue> valueValue = JSNApiHelper::ToJSHandle(value);
bool result = JSTaggedValue::SetProperty(thread, object, keyValue, valueValue);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
object->GetTaggedObject()->GetClass()->SetIsNativeBindingObject(true);
return result;
}
bool ObjectRef::Set(const EcmaVM *vm, Local<JSValueRef> key, Local<JSValueRef> value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
[[maybe_unused]] LocalScope scope(vm);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(obj, ERROR);
JSHandle<JSTaggedValue> keyValue = JSNApiHelper::ToJSHandle(key);
JSHandle<JSTaggedValue> 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<JSValueRef> value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
[[maybe_unused]] LocalScope scope(vm);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(obj, ERROR);
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSTaggedValue> keyValue(factory->NewFromUtf8(utf8));
JSTaggedValue valueValue = JSNApiHelper::ToJSTaggedValue(*value);
if (!obj->IsHeapObject()) {
return JSTaggedValue::SetProperty(thread, obj, keyValue, JSHandle<JSTaggedValue>(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<JSTaggedValue>(thread, obj.GetTaggedValue()), keyValue,
JSHandle<JSTaggedValue>(thread, valueValue), true);
}
return ObjectFastOperator::FastSetPropertyByValue(thread, obj.GetTaggedValue(),
keyValue.GetTaggedValue(),
valueValue);
}
bool ObjectRef::Set(const EcmaVM *vm, uint32_t key, Local<JSValueRef> value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
[[maybe_unused]] LocalScope scope(vm);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(obj, ERROR);
JSHandle<JSTaggedValue> 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<JSValueRef> key, Local<FunctionRef> getter,
Local<FunctionRef> setter, PropertyAttribute attribute)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
[[maybe_unused]] LocalScope scope(vm);
JSHandle<JSTaggedValue> getterValue = JSNApiHelper::ToJSHandle(getter);
JSHandle<JSTaggedValue> 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<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(obj, ERROR);
JSHandle<JSTaggedValue> keyValue = JSNApiHelper::ToJSHandle(key);
return JSTaggedValue::DefineOwnProperty(thread, obj, keyValue, desc);
}
Local<JSValueRef> ObjectRef::Get(const EcmaVM *vm, Local<JSValueRef> key)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSTaggedValue result;
{
LocalScope scope(vm);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(obj, ERROR);
JSHandle<JSTaggedValue> 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<JSTaggedValue> resultValue(thread, result);
return JSNApiHelper::ToLocal<JSValueRef>(resultValue);
}
Local<JSValueRef> ObjectRef::Get(const EcmaVM *vm, const char *utf8)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSTaggedValue result;
{
LocalScope scope(vm);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(obj, ERROR);
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSTaggedValue> 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<JSTaggedValue> resultValue(thread, result);
return JSNApiHelper::ToLocal<JSValueRef>(resultValue);
}
Local<JSValueRef> ObjectRef::Get(const EcmaVM *vm, int32_t key)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSTaggedValue result;
{
LocalScope scope(vm);
JSHandle<JSTaggedValue> 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<JSTaggedValue> resultValue(thread, result);
return JSNApiHelper::ToLocal<JSValueRef>(resultValue);
}
bool ObjectRef::GetOwnProperty(const EcmaVM *vm, Local<JSValueRef> key, PropertyAttribute &property)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(obj, ERROR);
JSHandle<JSTaggedValue> keyValue = JSNApiHelper::ToJSHandle(key);
PropertyDescriptor desc(thread);
bool ret = JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), keyValue, desc);
if (!ret) {
return false;
}
property.SetValue(JSNApiHelper::ToLocal<JSValueRef>(desc.GetValue()));
if (desc.HasGetter()) {
property.SetGetter(JSNApiHelper::ToLocal<JSValueRef>(desc.GetGetter()));
}
if (desc.HasSetter()) {
property.SetSetter(JSNApiHelper::ToLocal<JSValueRef>(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<ArrayRef> ObjectRef::GetOwnPropertyNames(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> obj(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(obj, ERROR);
JSHandle<TaggedArray> array(JSTaggedValue::GetOwnPropertyKeys(thread, obj));
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
JSHandle<JSTaggedValue> jsArray(JSArray::CreateArrayFromList(thread, array));
return JSNApiHelper::ToLocal<ArrayRef>(jsArray);
}
Local<ArrayRef> 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(thread);
JSHandle<JSTaggedValue> obj(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(obj, ERROR);
JSHandle<TaggedArray> array(JSTaggedValue::GetAllPropertyKeys(thread, obj, filter));
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
JSHandle<JSTaggedValue> jsArray(JSArray::CreateArrayFromList(thread, array));
return JSNApiHelper::ToLocal<ArrayRef>(jsArray);
}
Local<ArrayRef> ObjectRef::GetOwnEnumerablePropertyNames(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSObject> obj(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(obj, ERROR);
JSHandle<TaggedArray> array(JSObject::EnumerableOwnNames(thread, obj));
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
JSHandle<JSTaggedValue> jsArray(JSArray::CreateArrayFromList(thread, array));
return JSNApiHelper::ToLocal<ArrayRef>(jsArray);
}
Local<JSValueRef> ObjectRef::GetPrototype(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSObject> object(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(object, ERROR);
JSHandle<JSTaggedValue> prototype(thread, JSTaggedValue::GetPrototype(thread, JSHandle<JSTaggedValue>(object)));
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return JSNApiHelper::ToLocal<JSValueRef>(prototype);
}
bool ObjectRef::SetPrototype(const EcmaVM *vm, Local<ObjectRef> prototype)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSObject> object(JSNApiHelper::ToJSHandle(this));
JSHandle<JSObject> proto(JSNApiHelper::ToJSHandle(prototype));
return JSTaggedValue::SetPrototype(thread, JSHandle<JSTaggedValue>(object), JSHandle<JSTaggedValue>(proto));
}
bool ObjectRef::DefineProperty(const EcmaVM *vm, Local<JSValueRef> key, PropertyAttribute attribute)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> object(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(object, ERROR);
JSHandle<JSTaggedValue> 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<JSValueRef> key)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> object(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(object, ERROR);
JSHandle<JSTaggedValue> 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(thread);
JSHandle<JSTaggedValue> object(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(object, ERROR);
return JSTaggedValue::HasProperty(thread, object, key);
}
bool ObjectRef::HasOwnProperty(const EcmaVM *vm, Local<JSValueRef> key)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> object(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(object, ERROR);
JSHandle<JSTaggedValue> keyValue(JSNApiHelper::ToJSHandle(key));
return JSTaggedValue::HasOwnProperty(thread, object, keyValue);
}
bool ObjectRef::Delete(const EcmaVM *vm, Local<JSValueRef> key)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> object(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(object, ERROR);
JSHandle<JSTaggedValue> 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(thread);
JSHandle<JSTaggedValue> object(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(object, ERROR);
JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
return JSTaggedValue::DeleteProperty(thread, object, keyHandle);
}
Local<JSValueRef> ObjectRef::Freeze(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
EscapeLocalScope scope(vm);
JSHandle<JSTaggedValue> object = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(object, ERROR);
JSHandle<JSObject> obj(object);
bool status = JSObject::SetIntegrityLevel(thread, obj, ecmascript::IntegrityLevel::FROZEN);
if (JSNApi::HasPendingException(vm)) {
JSHandle<JSTaggedValue> exception(thread, JSTaggedValue::Exception());
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(exception));
}
if (!status) {
LOG_ECMA(ERROR) << "Freeze: freeze failed";
Local<StringRef> message = StringRef::NewFromUtf8(vm, "Freeze: freeze failed");
Local<JSValueRef> error = Exception::Error(vm, message);
JSNApi::ThrowException(vm, error);
JSHandle<JSTaggedValue> exception(thread, JSTaggedValue::Exception());
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(exception));
}
JSHandle<JSTaggedValue> resultValue(obj);
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(resultValue));
}
Local<JSValueRef> ObjectRef::Seal(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
EscapeLocalScope scope(vm);
JSHandle<JSTaggedValue> object = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(object, ERROR);
JSHandle<JSObject> obj(object);
bool status = JSObject::SetIntegrityLevel(thread, obj, ecmascript::IntegrityLevel::SEALED);
if (JSNApi::HasPendingException(vm)) {
JSHandle<JSTaggedValue> exception(thread, JSTaggedValue::Exception());
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(exception));
}
if (!status) {
LOG_ECMA(ERROR) << "Seal: seal failed";
Local<StringRef> message = StringRef::NewFromUtf8(vm, "Freeze: freeze failed");
Local<JSValueRef> error = Exception::Error(vm, message);
JSNApi::ThrowException(vm, error);
JSHandle<JSTaggedValue> exception(thread, JSTaggedValue::Exception());
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(exception));
}
JSHandle<JSTaggedValue> resultValue(obj);
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(resultValue));
}
void ObjectRef::SetNativePointerFieldCount(const EcmaVM *vm, int32_t count)
{
CROSS_THREAD_AND_EXCEPTION_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
// ObjectRef::New may return special value if exception occurs.
// So we need do special value check before use it.
DCHECK_SPECIAL_VALUE(this);
JSHandle<JSObject> object(JSNApiHelper::ToJSHandle(this));
ECMAObject::SetNativePointerFieldCount(thread, object, 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<JSObject> 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<JSObject> 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(thread);
// ObjectRef::New may return special value if exception occurs.
// So we need do special value check before use it.
DCHECK_SPECIAL_VALUE(this);
JSHandle<JSObject> object(JSNApiHelper::ToJSHandle(this));
ECMAObject::SetNativePointerField(thread, object, 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(thread);
// ObjectRef::New may return special value if exception occurs.
// So we need do special value check before use it.
DCHECK_SPECIAL_VALUE(this);
JSHandle<JSObject> object(JSNApiHelper::ToJSHandle(this));
ECMAObject::SetNativePointerField(thread, object, index, nativePointer, callBack, data,
nativeBindingsize, Concurrent::YES);
}
// -------------------------------- NativePointerRef ------------------------------------
Local<NativePointerRef> NativePointerRef::New(const EcmaVM *vm, void *nativePointer, size_t nativeBindingsize)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSNativePointer> obj = factory->NewJSNativePointer(nativePointer, nullptr, nullptr,
false, nativeBindingsize);
return JSNApiHelper::ToLocal<NativePointerRef>(JSHandle<JSTaggedValue>(obj));
}
Local<NativePointerRef> 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(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSNativePointer> obj = factory->NewJSNativePointer(nativePointer, callBack, data,
false, nativeBindingsize);
return JSNApiHelper::ToLocal<NativePointerRef>(JSHandle<JSTaggedValue>(obj));
}
Local<NativePointerRef> 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<JSNativePointer> obj =
factory->NewJSNativePointer(nativePointer, callBack, data, false, nativeBindingsize, Concurrent::YES);
return JSNApiHelper::ToLocal<NativePointerRef>(JSHandle<JSTaggedValue>(obj));
}
Local<NativePointerRef> 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(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSNativePointer> obj =
factory->NewSJSNativePointer(nativePointer, callBack, data, false, nativeBindingsize);
return JSNApiHelper::ToLocal<NativePointerRef>(JSHandle<JSTaggedValue>(obj));
}
void *NativePointerRef::Value()
{
DCHECK_SPECIAL_VALUE_WITH_RETURN(this, nullptr);
JSHandle<JSTaggedValue> nativePointer = JSNApiHelper::ToJSHandle(this);
return JSHandle<JSNativePointer>(nativePointer)->GetExternalPointer();
}
// ---------------------------------- Buffer -----------------------------------
Local<ArrayBufferRef> ArrayBufferRef::New(const EcmaVM *vm, int32_t length)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSArrayBuffer> arrayBuffer = factory->NewJSArrayBuffer(length);
return JSNApiHelper::ToLocal<ArrayBufferRef>(JSHandle<JSTaggedValue>(arrayBuffer));
}
Local<ArrayBufferRef> 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(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSArrayBuffer> arrayBuffer = factory->NewJSArrayBuffer(buffer, length, deleter, data);
return JSNApiHelper::ToLocal<ArrayBufferRef>(JSHandle<JSTaggedValue>(arrayBuffer));
}
int32_t ArrayBufferRef::ByteLength(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSArrayBuffer> 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<JSArrayBuffer> 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(thread);
// arraybuffer is not shared. Do not need to switch state
JSHandle<JSArrayBuffer> 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<JSArrayBuffer> arrayBuffer(JSNApiHelper::ToJSHandle(this));
return arrayBuffer->IsDetach();
}
Local<SendableArrayBufferRef> SendableArrayBufferRef::New(const EcmaVM *vm, int32_t length)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<ecmascript::JSSendableArrayBuffer> arrayBuffer = factory->NewJSSendableArrayBuffer(length);
return JSNApiHelper::ToLocal<SendableArrayBufferRef>(JSHandle<JSTaggedValue>(arrayBuffer));
}
Local<SendableArrayBufferRef> 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(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<ecmascript::JSSendableArrayBuffer> arrayBuffer =
factory->NewJSSendableArrayBuffer(buffer, length, deleter, data);
return JSNApiHelper::ToLocal<SendableArrayBufferRef>(JSHandle<JSTaggedValue>(arrayBuffer));
}
int32_t SendableArrayBufferRef::ByteLength(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<ecmascript::JSSendableArrayBuffer> 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(thread);
JSHandle<ecmascript::JSSendableArrayBuffer> 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<ecmascript::JSSendableArrayBuffer> 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<ecmascript::JSSendableArrayBuffer> arrayBuffer(JSNApiHelper::ToJSHandle(this));
JSTaggedValue bufferData = arrayBuffer->GetArrayBufferData();
if (!bufferData.IsJSNativePointer()) {
return nullptr;
}
return JSNativePointer::Cast(bufferData.GetTaggedObject())->GetExternalPointer();
}
// ---------------------------------- DateRef -----------------------------------
Local<DateRef> DateRef::New(const EcmaVM *vm, double time)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<GlobalEnv> globalEnv = vm->GetGlobalEnv();
JSHandle<JSFunction> dateFunction(globalEnv->GetDateFunction());
JSHandle<JSDate> dateObject(factory->NewJSObjectByConstructor(dateFunction));
dateObject->SetTimeValue(thread, JSTaggedValue(time));
return JSNApiHelper::ToLocal<DateRef>(JSHandle<JSTaggedValue>(dateObject));
}
Local<StringRef> DateRef::ToString(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSDate> date(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(date, ERROR);
JSTaggedValue dateStr = date->ToString(thread);
if (!dateStr.IsString()) {
auto constants = thread->GlobalConstants();
return JSNApiHelper::ToLocal<StringRef>(constants->GetHandledEmptyString());
}
JSHandle<JSTaggedValue> dateStrHandle(thread, dateStr);
return JSNApiHelper::ToLocal<StringRef>(dateStrHandle);
}
double DateRef::GetTime(const EcmaVM *vm)
{
DCHECK_SPECIAL_VALUE_WITH_RETURN(this, 0.0);
ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
JSHandle<JSDate> 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(thread);
JSHandle<JSTypedArray> 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(thread);
JSHandle<JSTypedArray> 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(thread);
JSHandle<JSTypedArray> typedArray(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(typedArray, FATAL);
return typedArray->GetArrayLength();
}
Local<ArrayBufferRef> TypedArrayRef::GetArrayBuffer(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTypedArray> typeArray(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(typeArray, ERROR);
JSHandle<JSTaggedValue> arrayBuffer(thread, JSTypedArray::GetOffHeapBuffer(thread, typeArray));
return JSNApiHelper::ToLocal<ArrayBufferRef>(arrayBuffer);
}
uint32_t SendableTypedArrayRef::ByteLength(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<ecmascript::JSSharedTypedArray> 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(thread);
JSHandle<ecmascript::JSSharedTypedArray> 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(thread);
JSHandle<ecmascript::JSSharedTypedArray> typedArray(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(typedArray, FATAL);
return typedArray->GetArrayLength();
}
Local<SendableArrayBufferRef> SendableTypedArrayRef::GetArrayBuffer(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<ecmascript::JSSharedTypedArray> typeArray(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(typeArray, ERROR);
JSHandle<JSTaggedValue> arrayBuffer(thread,
ecmascript::JSSharedTypedArray::GetSharedOffHeapBuffer(thread, typeArray));
return JSNApiHelper::ToLocal<SendableArrayBufferRef>(arrayBuffer);
}
// ----------------------------------- FunctionRef --------------------------------------
Local<FunctionRef> 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(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<JSFunction> current(factory->NewJSFunction(env, reinterpret_cast<void *>(Callback::RegisterCallback)));
JSFunction::SetFunctionExtraInfo(thread, current, reinterpret_cast<void *>(nativeFunc),
deleter, data, nativeBindingsize);
current->SetCallNapi(callNapi);
return JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(current));
}
Local<FunctionRef> 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<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<JSFunction> current(factory->NewJSFunction(env, reinterpret_cast<void *>(Callback::RegisterCallback)));
JSFunction::SetFunctionExtraInfo(thread, current, reinterpret_cast<void *>(nativeFunc), deleter,
data, nativeBindingsize, Concurrent::YES);
current->SetCallNapi(callNapi);
return JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(current));
}
Local<FunctionRef> 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(thread);
ObjectFactory *factory = vm->GetFactory();
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<JSFunction> current(factory->NewJSFunction(env, reinterpret_cast<void *>(nativeFunc)));
JSFunction::SetFunctionExtraInfo(thread, current, nullptr, deleter, data, nativeBindingsize);
current->SetCallNapi(callNapi);
return JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(current));
}
Local<FunctionRef> 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<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<JSFunction> current(factory->NewSFunction(env, reinterpret_cast<void *>(nativeFunc)));
JSFunction::SetSFunctionExtraInfo(thread, current, nullptr, deleter, data, nativeBindingsize);
current->SetCallNapi(callNapi);
return JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(current));
}
Local<FunctionRef> 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<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<JSFunction> current(factory->NewJSFunction(env, reinterpret_cast<void *>(nativeFunc)));
JSFunction::SetFunctionExtraInfo(thread, current, nullptr, deleter, data, nativeBindingsize, Concurrent::YES);
current->SetCallNapi(callNapi);
return JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(current));
}
static void InitClassFunction(EcmaVM *vm, JSHandle<JSFunction> &func, bool callNapi)
{
CROSS_THREAD_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
auto globalConst = thread->GlobalConstants();
JSHandle<JSTaggedValue> 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<JSObject> clsPrototype = JSFunction::NewJSFunctionPrototype(thread, func);
clsPrototype->GetClass()->SetClassPrototype(true);
func->SetClassConstructor(true);
JSHandle<JSTaggedValue> parent = env->GetFunctionPrototype();
JSObject::SetPrototype(thread, JSHandle<JSObject>::Cast(func), parent);
func->SetHomeObject(thread, clsPrototype);
func->SetCallNapi(callNapi);
}
Local<FunctionRef> 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(thread);
EscapeLocalScope scope(vm);
ObjectFactory *factory = vm->GetFactory();
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<JSHClass> hclass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithoutName());
JSHandle<JSFunction> current =
factory->NewJSFunctionByHClass(reinterpret_cast<void *>(Callback::RegisterCallback),
hclass, ecmascript::FunctionKind::CLASS_CONSTRUCTOR);
InitClassFunction(vm, current, callNapi);
JSFunction::SetFunctionExtraInfo(thread, current, reinterpret_cast<void *>(nativeFunc),
deleter, data, nativeBindingsize);
Local<FunctionRef> result = JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(current));
return scope.Escape(result);
}
Local<FunctionRef> 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(thread);
EscapeLocalScope scope(vm);
ObjectFactory *factory = vm->GetFactory();
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<JSHClass> hclass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithoutName());
JSHandle<JSFunction> current =
factory->NewJSFunctionByHClass(reinterpret_cast<void *>(nativeFunc),
hclass, ecmascript::FunctionKind::CLASS_CONSTRUCTOR);
InitClassFunction(vm, current, callNapi);
JSFunction::SetFunctionExtraInfo(thread, current, nullptr, deleter, data, nativeBindingsize, Concurrent::YES);
Local<FunctionRef> result = JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(current));
return scope.Escape(result);
}
Local<FunctionRef> 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(thread);
EscapeLocalScope scope(vm);
ObjectFactory *factory = vm->GetFactory();
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<JSHClass> hclass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithoutName());
JSHandle<JSFunction> current =
factory->NewJSFunctionByHClass(reinterpret_cast<void *>(nativeFunc),
hclass, ecmascript::FunctionKind::CLASS_CONSTRUCTOR);
InitClassFunction(vm, current, callNapi);
JSFunction::SetFunctionExtraInfo(thread, current, nullptr, deleter, data, nativeBindingsize);
Local<FunctionRef> result = JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(current));
return scope.Escape(result);
}
Local<FunctionRef> FunctionRef::NewSendableClassFunction(const EcmaVM *vm,
InternalFunctionCallback nativeFunc,
NativePointerCallback deleter,
void *data,
Local<StringRef> name,
SendablePropertiesInfos &infos,
Local<FunctionRef> 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<JSHClass> prototypeHClass = JSHClass::CreateSPrototypeHClass(thread, sendable.GetNonStaticDescs());
JSHandle<JSObject> prototype = factory->NewSharedOldSpaceJSObject(prototypeHClass);
JSHandle<JSHClass> constructorHClass = JSHClass::CreateSConstructorHClass(thread, sendable.GetStaticDescs());
JSHandle<JSFunction> constructor = factory->NewSFunctionByHClass(
reinterpret_cast<void *>(nativeFunc), constructorHClass, ecmascript::FunctionKind::CLASS_CONSTRUCTOR);
sendable.SetSConstructor(constructor);
JSObject::SetSProperties(thread, prototype, sendable.GetNonStaticDescs());
JSObject::SetSProperties(thread, JSHandle<JSObject>::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);
JSFunction::SetSFunctionExtraInfo(thread, constructor, nullptr, deleter, data, nativeBindingSize);
JSHClass *parentIHClass{nullptr};
if (hasParent) {
JSHandle<JSFunction> parentHandle(JSNApiHelper::ToJSHandle(parent));
parentIHClass = reinterpret_cast<JSHClass *>(parentHandle->GetProtoOrHClass().GetTaggedObject());
}
JSHandle<JSHClass> iHClass = JSHClass::CreateSHClass(thread, sendable.GetInstanceDescs(), parentIHClass);
iHClass->SetPrototype(thread, JSHandle<JSTaggedValue>(prototype));
iHClass->SetExtensible(false);
constructor->SetProtoOrHClass(thread, iHClass);
constructorHClass->SetExtensible(false);
Local<FunctionRef> result = JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(constructor));
return scope.Escape(result);
}
Local<JSValueRef> FunctionRef::Call(const EcmaVM *vm, Local<JSValueRef> thisObj,
const Local<JSValueRef> argv[], // NOLINTNEXTLINE(modernize-avoid-c-arrays)
int32_t length)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
EscapeLocalScope scope(vm);
FunctionCallScope callScope(EcmaVM::ConstCast(vm));
if (!IsFunction(vm)) {
return JSValueRef::Undefined(vm);
}
vm->GetJsDebuggerManager()->ClearSingleStepper();
JSHandle<JSTaggedValue> func = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(func, ERROR);
JSHandle<JSTaggedValue> thisValue = JSNApiHelper::ToJSHandle(thisObj);
JSHandle<JSTaggedValue> 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<JSTaggedValue> 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<JSTaggedValue> resultValue(thread, result);
thread->GetCurrentEcmaContext()->ClearKeptObjects();
vm->GetJsDebuggerManager()->NotifyReturnNative();
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(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<JSTaggedValue *>(this);
JSTaggedValue undefined = thread->GlobalConstants()->GetUndefined();
JSTaggedValue thisValue = undefined;
if (thisObj != nullptr) {
thisValue = *reinterpret_cast<JSTaggedValue *>(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 *>(*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 *>(*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<JSTaggedValue> resultValue(thread, result);
return reinterpret_cast<JSValueRef *>(resultValue.GetAddress());
}
Local<JSValueRef> FunctionRef::Constructor(const EcmaVM *vm,
const Local<JSValueRef> argv[], // NOLINTNEXTLINE(modernize-avoid-c-arrays)
int32_t length)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
FunctionCallScope callScope(EcmaVM::ConstCast(vm));
if (!IsFunction(vm)) {
return JSValueRef::Undefined(vm);
}
JSHandle<JSTaggedValue> func = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(func, ERROR);
JSHandle<JSTaggedValue> newTarget = func;
JSHandle<JSTaggedValue> 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<JSTaggedValue> 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<JSTaggedValue> resultValue(thread, result);
return JSNApiHelper::ToLocal<JSValueRef>(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(thread);
JSTaggedValue result;
FunctionCallScope callScope(EcmaVM::ConstCast(vm));
ASSERT(IsFunction(vm)); // IsFunction check has been done in napi.
{
LocalScope scope(vm);
JSTaggedValue func = *reinterpret_cast<JSTaggedValue*>(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<JSTaggedValue> resultValue(thread, result);
return reinterpret_cast<JSValueRef*>(resultValue.GetAddress());
}
Local<JSValueRef> FunctionRef::GetFunctionPrototype(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> func = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(func, FATAL);
JSHandle<JSTaggedValue> prototype(thread, JSHandle<JSFunction>(func)->GetFunctionPrototype());
return JSNApiHelper::ToLocal<JSValueRef>(prototype);
}
bool FunctionRef::Inherit(const EcmaVM *vm, Local<FunctionRef> parent)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
[[maybe_unused]] LocalScope scope(vm);
JSHandle<JSTaggedValue> parentValue = JSNApiHelper::ToJSHandle(parent);
JSHandle<JSObject> parentHandle = JSHandle<JSObject>::Cast(parentValue);
JSHandle<JSObject> thisHandle = JSHandle<JSObject>::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<JSTaggedValue> parentPrototype(thread, JSFunction::PrototypeGetter(thread, parentHandle));
JSHandle<JSTaggedValue> thisPrototype(thread, JSFunction::PrototypeGetter(thread, thisHandle));
return JSObject::SetPrototype(thread, JSHandle<JSObject>::Cast(thisPrototype), parentPrototype);
}
void FunctionRef::SetName(const EcmaVM *vm, Local<StringRef> name)
{
CROSS_THREAD_AND_EXCEPTION_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
[[maybe_unused]] LocalScope scope(vm);
JSFunction *func = JSFunction::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject());
JSTaggedValue key = JSNApiHelper::ToJSTaggedValue(*name);
JSFunction::SetFunctionNameNoPrefix(thread, func, key);
}
Local<StringRef> FunctionRef::GetName(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
EscapeLocalScope scope(vm);
JSHandle<JSFunctionBase> func(thread, JSNApiHelper::ToJSTaggedValue(this));
JSHandle<JSTaggedValue> name = JSFunctionBase::GetFunctionName(thread, func);
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return scope.Escape(JSNApiHelper::ToLocal<StringRef>(name));
}
Local<StringRef> FunctionRef::GetSourceCode(const EcmaVM *vm, int lineNumber)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
EscapeLocalScope scope(vm);
JSHandle<JSFunctionBase> func(thread, JSNApiHelper::ToJSTaggedValue(this));
JSHandle<Method> 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<JSTaggedValue> sourceCodeHandle(thread, BuiltinsBase::GetTaggedString(thread, ""));
if (mainMethodIndex == 0) {
return scope.Escape(JSNApiHelper::ToLocal<StringRef>(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<StringRef>(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<StringRef>(sourceCodeHandle));
}
bool FunctionRef::IsNative(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSFunctionBase> func(thread, JSNApiHelper::ToJSTaggedValue(this));
JSHandle<Method> 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(thread);
JSHandle<JSTaggedValue> funcValue = JSNApiHelper::ToJSHandle(this);
JSHandle<JSFunction> function(funcValue);
if (function->IsJSShared()) {
JSFunction::SetSFunctionExtraInfo(thread, function, nullptr, deleter, data, 0);
} else {
JSFunction::SetFunctionExtraInfo(thread, function, nullptr, deleter, data, 0);
}
}
void* FunctionRef::GetData(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, nullptr);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> funcValue = JSNApiHelper::ToJSHandle(this);
JSHandle<JSFunctionBase> function(funcValue);
JSTaggedValue extraInfoValue = function->GetFunctionExtraInfo();
if (!extraInfoValue.IsNativePointer()) {
return nullptr;
}
auto extraInfo = JSNativePointer::Cast(extraInfoValue.GetTaggedObject());
return extraInfo->GetData();
}
// ----------------------------------- ArrayRef ----------------------------------------
Local<ArrayRef> ArrayRef::New(const EcmaVM *vm, uint32_t length)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSTaggedNumber arrayLen(length);
JSHandle<JSTaggedValue> array = JSArray::ArrayCreate(thread, arrayLen);
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return JSNApiHelper::ToLocal<ArrayRef>(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<JSValueRef> ArrayRef::GetValueAt(const EcmaVM *vm, Local<JSValueRef> obj, uint32_t index)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> object = JSNApiHelper::ToJSHandle(obj);
JSHandle<JSTaggedValue> result = JSArray::FastGetPropertyByValue(thread, object, index);
return JSNApiHelper::ToLocal<JSValueRef>(result);
}
bool ArrayRef::SetValueAt(const EcmaVM *vm, Local<JSValueRef> obj, uint32_t index, Local<JSValueRef> value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> objectHandle = JSNApiHelper::ToJSHandle(obj);
JSHandle<JSTaggedValue> valueHandle = JSNApiHelper::ToJSHandle(value);
return JSArray::FastSetPropertyByValue(thread, objectHandle, index, valueHandle);
}
// ----------------------------------- SendableArrayRef ----------------------------------------
Local<SendableArrayRef> SendableArrayRef::New(const EcmaVM *vm, uint32_t length)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSTaggedNumber arrayLen(length);
JSHandle<JSTaggedValue> array = ecmascript::JSSharedArray::ArrayCreate(thread, arrayLen);
JSHandle<JSTaggedValue> initialValue(thread, JSTaggedValue::Undefined());
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
for (uint32_t i = 0; i < length; i++) {
key.Update(JSTaggedValue(i));
JSObject::CreateDataPropertyOrThrow(
thread, JSHandle<JSObject>(array), key, initialValue, ecmascript::JSShared::SCheckMode::SKIP);
}
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return JSNApiHelper::ToLocal<SendableArrayRef>(array);
}
uint32_t SendableArrayRef::Length(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, 0);
ecmascript::ThreadManagedScope managedScope(thread);
return ecmascript::JSSharedArray::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject())->GetArrayLength();
}
Local<JSValueRef> SendableArrayRef::GetValueAt(const EcmaVM *vm, Local<JSValueRef> obj, uint32_t index)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> object = JSNApiHelper::ToJSHandle(obj);
JSHandle<JSTaggedValue> result = ecmascript::JSSharedArray::FastGetPropertyByValue(thread, object, index);
return JSNApiHelper::ToLocal<JSValueRef>(result);
}
bool SendableArrayRef::SetProperty(const EcmaVM *vm, Local<JSValueRef> obj, uint32_t index, Local<JSValueRef> value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSTaggedValue> objectHandle = JSNApiHelper::ToJSHandle(obj);
JSHandle<JSTaggedValue> 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<JSValueRef> Exception::name(const EcmaVM *vm, Local<StringRef> message) \
{ \
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm)); \
ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); \
ObjectFactory *factory = vm->GetFactory(); \
\
JSHandle<EcmaString> messageValue(JSNApiHelper::ToJSHandle(message)); \
JSHandle<JSTaggedValue> result(factory->NewJSError(ErrorType::type, \
messageValue, ecmascript::StackCheck::NO)); \
return JSNApiHelper::ToLocal<JSValueRef>(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<EcmaVM*>(vm)->IncreaseEnterJsiNativeScopeCount();
const_cast<EcmaVM*>(vm)->IncreaseUpdateThreadStateTransCount();
}
#endif
oldThreadState_ = static_cast<uint16_t>(thread_->GetState());
thread_->UpdateState(ecmascript::ThreadState::NATIVE);
}
JsiNativeScope::~JsiNativeScope()
{
thread_->UpdateState(static_cast<ecmascript::ThreadState>(oldThreadState_));
}
// ------------------------------------ JsiFastNativeScope -----------------------------------------------
JsiFastNativeScope::JsiFastNativeScope(const EcmaVM *vm)
{
thread_ = vm->GetAssociatedJSThread();
#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
if (vm->IsCollectingScopeLockStats()) {
const_cast<EcmaVM*>(vm)->IncreaseEnterFastNativeScopeCount();
const_cast<EcmaVM*>(vm)->IncreaseUpdateThreadStateTransCount();
}
#endif
ecmascript::ThreadState oldState = thread_->GetState();
if (oldState == ecmascript::ThreadState::RUNNING) {
return;
}
oldThreadState_ = static_cast<uint16_t>(oldState);
hasSwitchState_ = true;
thread_->UpdateState(ecmascript::ThreadState::RUNNING);
}
JsiFastNativeScope::~JsiFastNativeScope()
{
if (hasSwitchState_) {
thread_->UpdateState(static_cast<ecmascript::ThreadState>(oldThreadState_));
}
}
// ------------------------------------ JsiRuntimeCallInfo -----------------------------------------------
void *JsiRuntimeCallInfo::GetData()
{
ecmascript::ThreadManagedScope managedScope(thread_);
JSHandle<JSTaggedValue> constructor = BuiltinsBase::GetConstructor(reinterpret_cast<EcmaRuntimeCallInfo *>(this));
if (!constructor->IsJSFunction()) {
return nullptr;
}
JSHandle<JSFunctionBase> 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(thread);
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(thread);
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(thread);
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<ObjectRef> exception, const std::string &patchFileName)
{
if (exception.IsEmpty()) {
return false;
}
CROSS_THREAD_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
ecmascript::QuickFixManager *quickFixManager = vm->GetQuickFixManager();
JSHandle<JSTaggedValue> exceptionInfo = JSNApiHelper::ToJSHandle(exception);
return quickFixManager->IsQuickFixCausedException(thread, exceptionInfo, patchFileName);
}
/*
* register quickfix query function.
*/
void JSNApi::RegisterQuickFixQueryFunc(EcmaVM *vm, std::function<bool(std::string baseFileName,
std::string &patchFileName,
uint8_t **patchBuffer,
size_t &patchSize)> 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<StringRef> message = StringRef::NewFromUtf8(vm, errmsg.c_str());
Local<JSValueRef> 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<std::string, std::string> &list)
{
vm->SetMockModuleList(list);
}
void JSNApi::SetHmsModuleList(EcmaVM *vm, const std::vector<panda::HmsMap> &list)
{
vm->SetHmsModuleList(list);
}
void JSNApi::SetPkgAliasList(EcmaVM *vm, const std::map<std::string, std::string> &list)
{
ecmascript::CMap<ecmascript::CString, ecmascript::CString> 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<std::string, std::string> &list)
{
ecmascript::CMap<ecmascript::CString, ecmascript::CString> 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<std::string,
std::vector<std::vector<std::string>>> &list)
{
ecmascript::CMap<ecmascript::CString, ecmascript::CMap<ecmascript::CString,
ecmascript::CVector<ecmascript::CString>>> pkgContextInfoList;
for (auto it = list.begin(); it != list.end(); it++) {
const std::vector<std::vector<std::string>> vec = it->second;
ecmascript::CMap<ecmascript::CString, ecmascript::CVector<ecmascript::CString>> map;
for (size_t i = 0; i < vec.size(); i++) {
ecmascript::CString pkgName = vec[i][0].c_str();
ecmascript::CVector<ecmascript::CString> 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<JSValueRef> function, void *taskInfo)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
ecmascript::ThreadManagedScope managedScope(thread);
[[maybe_unused]] LocalScope scope(vm);
JSHandle<JSTaggedValue> funcVal = JSNApiHelper::ToJSHandle(function);
JSHandle<JSFunction> transFunc = JSHandle<JSFunction>::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<uintptr_t>(taskInfo));
thread->SetIsInConcurrentScope(true);
return true;
}
void* JSNApi::GetCurrentTaskInfo(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, nullptr);
return reinterpret_cast<void*>(thread->GetTaskInfo());
}
void JSNApi::ClearCurrentTaskInfo(const EcmaVM *vm)
{
JSThread *thread = vm->GetJSThread();
thread->SetTaskInfo(reinterpret_cast<uintptr_t>(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<std::string, std::string> 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<EcmaVM*>(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(thread);
if (thread != nullptr && vm->IsInitialized()) {
#if defined(ENABLE_EXCEPTION_BACKTRACE)
if (thread->IsMainThreadFast()) {
LOG_ECMA(INFO) << "JSNApi::TriggerGC gcType: " << static_cast<int>(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<ecmascript::TriggerGCType::SHARED_GC,
ecmascript::GCReason::EXTERNAL_TRIGGER>(thread);
break;
case TRIGGER_GC_TYPE::SHARED_FULL_GC:
sHeap->CollectGarbage<ecmascript::TriggerGCType::SHARED_FULL_GC,
ecmascript::GCReason::EXTERNAL_TRIGGER>(thread);
break;
default:
break;
}
}
}
void JSNApi::HintGC(const EcmaVM *vm, MemoryReduceDegree degree, ecmascript::GCReason reason)
{
CROSS_THREAD_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
if (thread != nullptr && vm->IsInitialized()) {
const_cast<ecmascript::Heap *>(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(thread);
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<JSValueRef> 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<ObjectRef> exception = GetAndClearUncaughtException(vm);
JSHandle<JSTaggedValue> exceptionHandle = JSNApiHelper::ToJSHandle(exception);
if (exceptionHandle->IsJSError()) {
vm->PrintJSErrorInfo(exceptionHandle);
ThrowException(vm, exception);
return;
}
JSHandle<EcmaString> 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<StartDebugger>(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<StartDebug>(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<StartDebugForSocketpair>(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<StoreDebuggerInfo>(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<InitializeDebuggerForSocketpair>(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<WaitForDebugger>(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<StoreDebuggerInfo>(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<InitializeDebuggerForSocketpair>(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<StopDebug>(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<StopOldDebug>(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<EcmaVM *>(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<std::chrono::milliseconds>(end - start).count();
auto threshold = std::chrono::duration_cast<std::chrono::milliseconds>
(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<std::chrono::nanoseconds>(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<bool(std::string fileName, uint8_t **buff, size_t *buffSize)> 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<RuntimeOption::AOTCompileStatus>(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);
ecmascript::pgo::PGOProfilerManager::GetInstance()->SetBundleName(option.GetBundleName());
ecmascript::pgo::PGOProfilerManager::GetInstance()->SetMaxAotMethodSize(jsOption.GetMaxAotMethodSize());
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<ObjectRef> JSNApi::GetUncaughtException(const EcmaVM *vm)
{
ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
return JSNApiHelper::ToLocal<ObjectRef>(vm->GetEcmaUncaughtException());
}
Local<ObjectRef> JSNApi::GetAndClearUncaughtException(const EcmaVM *vm)
{
if (!HasPendingException(vm)) {
return Local<ObjectRef>();
}
ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
return JSNApiHelper::ToLocal<ObjectRef>(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<ObjectRef> JSNApi::GetGlobalObject(const EcmaVM *vm)
{
auto thread = vm->GetJSThread();
ecmascript::ThreadManagedScope scope(thread);
JSHandle<GlobalEnv> globalEnv = vm->GetGlobalEnv();
JSHandle<JSTaggedValue> global(thread, globalEnv->GetGlobalObject());
return JSNApiHelper::ToLocal<ObjectRef>(global);
}
void JSNApi::ExecutePendingJob(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
EcmaVM::ConstCast(vm)->GetJSThread()->GetCurrentEcmaContext()->ExecutePromisePendingJob();
}
uintptr_t JSNApi::GetHandleAddr(const EcmaVM *vm, uintptr_t localAddress)
{
if (localAddress == 0) {
return 0;
}
CROSS_THREAD_CHECK(vm);
ecmascript::ThreadManagedScope scope(thread);
JSTaggedType value = *(reinterpret_cast<JSTaggedType *>(localAddress));
return ecmascript::EcmaHandleScope::NewHandle(thread, value);
}
uintptr_t JSNApi::GetGlobalHandleAddr(const EcmaVM *vm, uintptr_t localAddress)
{
if (localAddress == 0) {
return 0;
}
CROSS_THREAD_CHECK(vm);
ecmascript::ThreadManagedScope scope(thread);
JSTaggedType value = *(reinterpret_cast<JSTaggedType *>(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<ecmascript::Heap *>(vm->GetHeap())->NotifyRecordMemorySize();
}
void JSNApi::NotifyTaskFinished(const EcmaVM *vm)
{
ecmascript::ThreadManagedScope scope(vm->GetJSThread());
const_cast<ecmascript::Heap *>(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<ecmascript::Node *>(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;
}
CROSS_THREAD_CHECK(vm);
ecmascript::ThreadManagedScope scope(thread);
return thread->IsWeak(localAddress);
}
void JSNApi::DisposeGlobalHandleAddr(const EcmaVM *vm, uintptr_t addr)
{
if (addr == 0 || !reinterpret_cast<ecmascript::Node *>(addr)->IsUsing()) {
return;
}
CROSS_THREAD_CHECK(vm);
ecmascript::ThreadManagedScope scope(thread);
thread->DisposeGlobalHandle(addr);
}
void *JSNApi::SerializeValue(const EcmaVM *vm, Local<JSValueRef> value, Local<JSValueRef> transfer,
Local<JSValueRef> cloneList, bool defaultTransfer, bool defaultCloneShared)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, nullptr);
ecmascript::ThreadManagedScope scope(thread);
JSHandle<JSTaggedValue> arkValue = JSNApiHelper::ToJSHandle(value);
JSHandle<JSTaggedValue> arkTransfer = JSNApiHelper::ToJSHandle(transfer);
JSHandle<JSTaggedValue> 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<ecmascript::SerializeData> 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<void *>(data.release());
}
}
Local<JSValueRef> JSNApi::DeserializeValue(const EcmaVM *vm, void *recoder, void *hint)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope scope(thread);
std::unique_ptr<ecmascript::SerializeData> data(reinterpret_cast<ecmascript::SerializeData *>(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<JSTaggedValue> result = deserializer.ReadValue();
if (serializationTimeoutCheckEnabled) {
endTime = std::chrono::system_clock::now();
GenerateTimeoutTraceIfNeeded(vm, startTime, endTime, false);
}
return JSNApiHelper::ToLocal<ObjectRef>(result);
}
void JSNApi::DeleteSerializationData(void *data)
{
ecmascript::SerializeData *value = reinterpret_cast<ecmascript::SerializeData *>(data);
delete value;
value = nullptr;
}
void HostPromiseRejectionTracker(const EcmaVM *vm,
const JSHandle<JSPromise> promise,
const JSHandle<JSTaggedValue> reason,
const ecmascript::PromiseRejectionEvent operation,
void* data)
{
CROSS_THREAD_AND_EXCEPTION_CHECK(vm);
ecmascript::PromiseRejectCallback promiseRejectCallback =
thread->GetCurrentEcmaContext()->GetPromiseRejectCallback();
if (promiseRejectCallback != nullptr) {
Local<JSValueRef> promiseVal = JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>::Cast(promise));
PromiseRejectInfo promiseRejectInfo(promiseVal, JSNApiHelper::ToLocal<JSValueRef>(reason),
static_cast<PromiseRejectInfo::PROMISE_REJECTION_EVENT>(operation), data);
promiseRejectCallback(reinterpret_cast<void*>(&promiseRejectInfo));
}
}
void JSNApi::SetHostPromiseRejectionTracker(EcmaVM *vm, void *cb, void* data)
{
CROSS_THREAD_CHECK(vm);
thread->GetCurrentEcmaContext()->SetHostPromiseRejectionTracker(HostPromiseRejectionTracker);
thread->GetCurrentEcmaContext()->SetPromiseRejectCallback(
reinterpret_cast<ecmascript::PromiseRejectCallback>(cb));
thread->GetCurrentEcmaContext()->SetData(data);
}
void JSNApi::SetHostResolveBufferTracker(EcmaVM *vm,
std::function<bool(std::string dirPath, uint8_t **buff, size_t *buffSize, std::string &errorMsg)> cb)
{
vm->SetResolveBufferCallback(cb);
}
void JSNApi::SetSearchHapPathTracker(EcmaVM *vm,
std::function<bool(const std::string moduleName, std::string &hapPath)> 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<int32_t
(const std::string &bundleName, const std::string &moduleName, int32_t triggerMode)> &cb)
{
ecmascript::pgo::PGOProfilerManager::GetInstance()->SetRequestAotCallback(cb);
}
void JSNApi::SetUnloadNativeModuleCallback(EcmaVM *vm, const std::function<bool(const std::string &moduleKey)> &cb)
{
vm->SetUnloadNativeModuleCallback(cb);
}
void JSNApi::SetNativePtrGetter(EcmaVM *vm, void* cb)
{
vm->SetNativePtrGetter(reinterpret_cast<ecmascript::NativePtrGetter>(cb));
}
void JSNApi::SetHostEnqueueJob(const EcmaVM *vm, Local<JSValueRef> cb, QueueType queueType)
{
CROSS_THREAD_AND_EXCEPTION_CHECK(vm);
ecmascript::ThreadManagedScope scope(thread);
JSHandle<JSFunction> fun = JSHandle<JSFunction>::Cast(JSNApiHelper::ToJSHandle(cb));
JSHandle<TaggedArray> array = vm->GetFactory()->EmptyArray();
JSHandle<MicroJobQueue> 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(thread);
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<JSValueRef> 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(thread);
EscapeLocalScope scope(vm);
JSHandle<JSTaggedValue> 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<JSTaggedValue> holeHandle(thread, JSTaggedValue::Hole());
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(holeHandle));
}
LOG_IF_SPECIAL(obj, ERROR);
JSMutableHandle<JSTaggedValue> 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<JSValueRef>(JSHandle<JSTaggedValue>(thread, res)));
}
auto ret = JSTaggedValue(JSTaggedValue::HasProperty(thread, obj, keyValue));
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, ret)));
}
Local<JSValueRef> 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(thread);
EscapeLocalScope scope(vm);
JSHandle<JSTaggedValue> 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<JSTaggedValue> holeHandle(thread, JSTaggedValue::Hole());
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(holeHandle));
}
LOG_IF_SPECIAL(obj, ERROR);
JSMutableHandle<JSTaggedValue> 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<JSValueRef>(JSHandle<JSTaggedValue>(thread, res)));
}
auto ret = JSTaggedValue(JSTaggedValue::HasProperty(thread, obj, keyValue));
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, ret)));
}
Local<JSValueRef> 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(thread);
EscapeLocalScope scope(vm);
JSHandle<JSTaggedValue> 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<JSTaggedValue> holeHandle(thread, JSTaggedValue::Hole());
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(holeHandle));
}
LOG_IF_SPECIAL(obj, ERROR);
JSMutableHandle<JSTaggedValue> 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<JSValueRef>(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<JSValueRef>(JSHandle<JSTaggedValue>(thread, res)));
}
JSTaggedValue ret = ObjectFastOperator::FastGetPropertyByValue(thread, obj.GetTaggedValue(),
keyValue.GetTaggedValue());
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, ret)));
}
Local<JSValueRef> 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(thread);
EscapeLocalScope scope(vm);
JSHandle<JSTaggedValue> 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<JSTaggedValue> holeHandle(thread, JSTaggedValue::Hole());
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(holeHandle));
}
LOG_IF_SPECIAL(obj, ERROR);
JSMutableHandle<JSTaggedValue> 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<JSValueRef>(JSHandle<JSTaggedValue>(thread, ret)));
}
Local<JSValueRef> 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(thread);
EscapeLocalScope scope(vm);
JSHandle<JSTaggedValue> 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<JSTaggedValue> holeHandle(thread, JSTaggedValue::Hole());
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(holeHandle));
}
LOG_IF_SPECIAL(obj, ERROR);
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSTaggedValue> 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<JSValueRef>(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<JSValueRef>(JSHandle<JSTaggedValue>(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<JSValueRef>(JSHandle<JSTaggedValue>(thread, res)));
}
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, res)));
}
res = ObjectFastOperator::FastGetPropertyByValue(thread, obj.GetTaggedValue(), keyValue.GetTaggedValue());
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm));
return scope.Escape(JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, res)));
}
Local<JSValueRef> JSNApi::CreateLocal(const EcmaVM *vm, panda::JSValueRef src)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
JSHandle<JSTaggedValue> handle(thread, JSNApiHelper::ToJSTaggedValue(&src));
return JSNApiHelper::ToLocal<JSValueRef>(handle);
}
Local<ObjectRef> 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(thread);
ecmascript::CString entry = file.c_str();
ecmascript::CString name = vm->GetAssetPath();
if (!vm->IsBundlePack()) {
ModulePathHelper::ParseAbcPathAndOhmUrl(vm, entry, name, entry);
std::shared_ptr<JSPandaFile> jsPandaFile =
JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, name, entry.c_str(), false);
if (jsPandaFile == nullptr) {
JSHandle<JSTaggedValue> exportObj(thread, JSTaggedValue::Null());
return JSNApiHelper::ToLocal<ObjectRef>(exportObj);
}
if (!jsPandaFile->IsRecordWithBundleName()) {
PathHelper::AdaptOldIsaRecord(entry);
}
}
ecmascript::ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
JSHandle<ecmascript::SourceTextModule> 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<JSTaggedValue> exportObj(thread, result);
return JSNApiHelper::ToLocal<ObjectRef>(exportObj);
}
ObjectFactory *factory = vm->GetFactory();
JSHandle<EcmaString> keyHandle = factory->NewFromASCII(key.c_str());
JSTaggedValue result = ecmaModule->GetModuleValue(thread, keyHandle.GetTaggedValue(), false);
JSHandle<JSTaggedValue> exportObj(thread, result);
return JSNApiHelper::ToLocal<ObjectRef>(exportObj);
}
Local<ObjectRef> 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(thread);
ecmascript::ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
JSHandle<ecmascript::SourceTextModule> 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<JSTaggedValue> exportObj(thread, result);
return JSNApiHelper::ToLocal<ObjectRef>(exportObj);
}
ObjectFactory *factory = vm->GetFactory();
JSHandle<EcmaString> keyHandle = factory->NewFromASCII(key.c_str());
JSTaggedValue result = ecmaModule->GetModuleValue(thread, keyHandle.GetTaggedValue(), false);
JSHandle<JSTaggedValue> exportObj(thread, result);
return JSNApiHelper::ToLocal<ObjectRef>(exportObj);
}
Local<ObjectRef> 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(thread);
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<ecmascript::SourceTextModule> ecmaModule = moduleManager->GetImportedModule(recordName.c_str());
int index = ecmascript::ModuleManager::GetExportObjectIndex(vm, ecmaModule, key.c_str());
JSTaggedValue result = ecmaModule->GetModuleValue(thread, index, false);
JSHandle<JSTaggedValue> exportObj(thread, result);
return JSNApiHelper::ToLocal<ObjectRef>(exportObj);
}
Local<ObjectRef> 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<JSTaggedValue> exportObj = moduleManager->LoadNativeModule(thread, key.c_str());
return JSNApiHelper::ToLocal<ObjectRef>(exportObj);
}
Local<ObjectRef> 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<std::string, std::string> 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<JSTaggedValue> moduleNamespace = moduleManager->
GetModuleNameSpaceFromFile(thread, recordNameStr, abcFilePath);
return JSNApiHelper::ToLocal<ObjectRef>(moduleNamespace);
}
Local<ObjectRef> 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<JSTaggedValue> nameSp = ecmascript::NapiModuleLoader::LoadModuleNameSpaceWithModuleInfo(vm,
requestPath, modulePath);
return JSNApiHelper::ToLocal<ObjectRef>(nameSp);
}
// ---------------------------------- Promise -------------------------------------
Local<PromiseRef> PromiseRef::Catch(const EcmaVM *vm, Local<FunctionRef> handler)
{
ecmascript::ThreadManagedScope scope(vm->GetJSThread());
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
const GlobalEnvConstants *constants = thread->GlobalConstants();
JSHandle<JSTaggedValue> promise = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(promise, ERROR);
JSHandle<JSTaggedValue> catchKey(thread, constants->GetPromiseCatchString());
JSHandle<JSTaggedValue> reject = JSNApiHelper::ToJSHandle(handler);
JSHandle<JSTaggedValue> 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<PromiseRef>(JSHandle<JSTaggedValue>(thread, result));
}
Local<PromiseRef> PromiseRef::Finally(const EcmaVM *vm, Local<FunctionRef> handler)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope scope(thread);
const GlobalEnvConstants *constants = thread->GlobalConstants();
JSHandle<JSTaggedValue> promise = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(promise, ERROR);
JSHandle<JSTaggedValue> finallyKey = constants->GetHandledPromiseFinallyString();
JSHandle<JSTaggedValue> resolver = JSNApiHelper::ToJSHandle(handler);
JSHandle<JSTaggedValue> 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<PromiseRef>(JSHandle<JSTaggedValue>(thread, result));
}
Local<PromiseRef> PromiseRef::Then(const EcmaVM *vm, Local<FunctionRef> handler)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope scope(thread);
const GlobalEnvConstants *constants = thread->GlobalConstants();
JSHandle<JSTaggedValue> promise = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(promise, ERROR);
JSHandle<JSTaggedValue> thenKey(thread, constants->GetPromiseThenString());
JSHandle<JSTaggedValue> resolver = JSNApiHelper::ToJSHandle(handler);
JSHandle<JSTaggedValue> 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<PromiseRef>(JSHandle<JSTaggedValue>(thread, result));
}
Local<PromiseRef> PromiseRef::Then(const EcmaVM *vm, Local<FunctionRef> onFulfilled, Local<FunctionRef> onRejected)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope scope(thread);
const GlobalEnvConstants *constants = thread->GlobalConstants();
JSHandle<JSTaggedValue> promise = JSNApiHelper::ToJSHandle(this);
LOG_IF_SPECIAL(promise, ERROR);
JSHandle<JSTaggedValue> thenKey(thread, constants->GetPromiseThenString());
JSHandle<JSTaggedValue> resolver = JSNApiHelper::ToJSHandle(onFulfilled);
JSHandle<JSTaggedValue> reject = JSNApiHelper::ToJSHandle(onRejected);
JSHandle<JSTaggedValue> 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<PromiseRef>(JSHandle<JSTaggedValue>(thread, result));
}
Local<JSValueRef> PromiseRef::GetPromiseState(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope scope(thread);
JSHandle<JSPromise> 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<JSValueRef>(JSHandle<JSTaggedValue>(factory->NewFromStdString(promiseStateStr)));
}
Local<JSValueRef> PromiseRef::GetPromiseResult(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope scope(thread);
JSHandle<JSPromise> promise(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(promise, ERROR);
return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, promise->GetPromiseResult()));
}
// ---------------------------------- ProxyRef -----------------------------------------
Local<JSValueRef> ProxyRef::GetHandler(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope scope(thread);
JSHandle<JSProxy> jsProxy(JSNApiHelper::ToJSHandle(this));
return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, jsProxy->GetHandler()));
}
Local<JSValueRef> ProxyRef::GetTarget(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope scope(thread);
JSHandle<JSProxy> jsProxy(JSNApiHelper::ToJSHandle(this));
return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, jsProxy->GetTarget()));
}
bool ProxyRef::IsRevoked()
{
DCHECK_SPECIAL_VALUE_WITH_RETURN(this, false);
JSHandle<JSProxy> 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<JSSet> 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<JSSet> set(JSNApiHelper::ToJSHandle(this));
return static_cast<int>(set->GetSize()) +
LinkedHashSet::Cast(set->GetLinkedSet().GetTaggedObject())->NumberOfDeletedElements();
}
Local<JSValueRef> SetRef::GetValue(const EcmaVM *vm, int entry)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSSet> set(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(set, FATAL);
return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, set->GetValue(entry)));
}
Local<SetRef> SetRef::New(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> constructor = env->GetBuiltinsSetFunction();
JSHandle<JSSet> set =
JSHandle<JSSet>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
JSHandle<LinkedHashSet> hashSet = LinkedHashSet::Create(thread);
set->SetLinkedSet(thread, hashSet);
JSHandle<JSTaggedValue> setTag = JSHandle<JSTaggedValue>::Cast(set);
return JSNApiHelper::ToLocal<SetRef>(setTag);
}
void SetRef::Add(const EcmaVM *vm, Local<JSValueRef> value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSSet> set(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(set, ERROR);
JSSet::Add(thread, 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<JSWeakMap> 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<JSWeakMap> weakMap(JSNApiHelper::ToJSHandle(this));
return weakMap->GetSize() +
LinkedHashMap::Cast(weakMap->GetLinkedMap().GetTaggedObject())->NumberOfDeletedElements();
}
Local<JSValueRef> WeakMapRef::GetKey(const EcmaVM *vm, int entry)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSWeakMap> weakMap(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(weakMap, FATAL);
JSTaggedValue key = weakMap->GetKey(entry);
return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, key.GetWeakRawValue()));
}
Local<JSValueRef> WeakMapRef::GetValue(const EcmaVM *vm, int entry)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
JSHandle<JSWeakMap> weakMap(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(weakMap, FATAL);
return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, weakMap->GetValue(entry)));
}
Local<WeakMapRef> WeakMapRef::New(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> constructor = env->GetBuiltinsWeakMapFunction();
JSHandle<JSWeakMap> weakMap =
JSHandle<JSWeakMap>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
JSHandle<LinkedHashMap> hashMap = LinkedHashMap::Create(thread);
weakMap->SetLinkedMap(thread, hashMap);
JSHandle<JSTaggedValue> weakMapTag = JSHandle<JSTaggedValue>::Cast(weakMap);
return JSNApiHelper::ToLocal<WeakMapRef>(weakMapTag);
}
void WeakMapRef::Set(const EcmaVM *vm, const Local<JSValueRef> &key, const Local<JSValueRef> &value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSWeakMap> weakMap(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(weakMap, FATAL);
JSWeakMap::Set(thread, weakMap, JSNApiHelper::ToJSHandle(key), JSNApiHelper::ToJSHandle(value));
}
bool WeakMapRef::Has(const EcmaVM *vm, Local<JSValueRef> key)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false);
DCHECK_SPECIAL_VALUE_WITH_RETURN(this, false);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSWeakMap> 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<JSWeakSet> 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<JSWeakSet> weakSet(JSNApiHelper::ToJSHandle(this));
return weakSet->GetSize() +
LinkedHashSet::Cast(weakSet->GetLinkedSet().GetTaggedObject())->NumberOfDeletedElements();
}
Local<JSValueRef> WeakSetRef::GetValue(const EcmaVM *vm, int entry)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSWeakSet> weakSet(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(weakSet, FATAL);
JSTaggedValue value = weakSet->GetValue(entry);
return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, value.GetWeakRawValue()));
}
Local<WeakSetRef> WeakSetRef::New(const EcmaVM *vm)
{
CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, JSValueRef::Undefined(vm));
ecmascript::ThreadManagedScope managedScope(thread);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> constructor = env->GetBuiltinsWeakSetFunction();
JSHandle<JSWeakSet> weakSet =
JSHandle<JSWeakSet>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
JSHandle<LinkedHashSet> hashWeakSet = LinkedHashSet::Create(thread);
weakSet->SetLinkedSet(thread, hashWeakSet);
JSHandle<JSTaggedValue> setTag = JSHandle<JSTaggedValue>::Cast(weakSet);
return JSNApiHelper::ToLocal<WeakSetRef>(setTag);
}
void WeakSetRef::Add(const EcmaVM *vm, Local<JSValueRef> value)
{
CROSS_THREAD_AND_EXCEPTION_CHECK(vm);
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<JSWeakSet> weakSet(JSNApiHelper::ToJSHandle(this));
LOG_IF_SPECIAL(weakSet, ERROR);
JSWeakSet::Add(thread, weakSet, JSNApiHelper::ToJSHandle(value));
}
TryCatch::~TryCatch() {}
bool TryCatch::HasCaught() const
{
return ecmaVm_->GetJSThread()->HasPendingException();
}
void TryCatch::Rethrow()
{
rethrow_ = true;
}
Local<ObjectRef> TryCatch::GetAndClearException()
{
ecmascript::ThreadManagedScope managedScope(ecmaVm_->GetJSThread());
return JSNApiHelper::ToLocal<ObjectRef>(ecmaVm_->GetAndClearEcmaUncaughtException());
}
Local<ObjectRef> TryCatch::GetException()
{
ecmascript::ThreadManagedScope managedScope(ecmaVm_->GetJSThread());
return JSNApiHelper::ToLocal<ObjectRef>(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<EcmaString> str = factory->NewFromUtf8(name);
return instance->SetCachedString(str, propertyIndex);
}
Local<StringRef> ExternalStringCache::GetCachedString(const EcmaVM *vm, uint32_t propertyIndex)
{
auto instance = ecmascript::Runtime::GetInstance();
ASSERT(instance != nullptr);
auto thread = vm->GetJSThread();
ecmascript::ThreadManagedScope managedScope(thread);
JSHandle<EcmaString> str = instance->GetCachedString(thread, propertyIndex);
return JSNApiHelper::ToLocal<StringRef>(JSHandle<JSTaggedValue>(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