/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ECMASCRIPT_NAPI_INCLUDE_JSNAPI_H #define ECMASCRIPT_NAPI_INCLUDE_JSNAPI_H #include #include #include #include #include #include #include "ecmascript/base/config.h" #include "ecmascript/common.h" #include "ecmascript/mem/mem_common.h" #include "libpandabase/macros.h" namespace panda { class JSNApiHelper; class EscapeLocalScope; class PromiseRejectInfo; template class CopyableGlobal; template class Global; class JSNApi; template class Local; class JSValueRef; class PrimitiveRef; class ArrayRef; class StringRef; class ObjectRef; class FunctionRef; class NumberRef; class BooleanRef; class NativePointerRef; class JsiRuntimeCallInfo; namespace test { class JSNApiTests; } // namespace test class BufferRef; namespace ecmascript { class EcmaVM; class JSTaggedValue; class EcmaContext; class JSRuntimeOptions; class JSThread; struct EcmaRuntimeCallInfo; static constexpr uint32_t DEFAULT_GC_POOL_SIZE = 256_MB; } // namespace ecmascript using Deleter = void (*)(void *nativePointer, void *data); using WeakRefClearCallBack = void (*)(void *); using EcmaVM = ecmascript::EcmaVM; using EcmaContext = ecmascript::EcmaContext; using JSThread = ecmascript::JSThread; using JSTaggedType = uint64_t; using ConcurrentCallback = void (*)(Local result, bool success, void *taskInfo, void *data); static constexpr size_t DEFAULT_GC_THREAD_NUM = 7; static constexpr size_t DEFAULT_LONG_PAUSE_TIME = 40; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define ECMA_DISALLOW_COPY(className) \ className(const className &) = delete; \ className &operator=(const className &) = delete // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define ECMA_DISALLOW_MOVE(className) \ className(className &&) = delete; \ className &operator=(className &&) = delete template class PUBLIC_API Local { // NOLINT(cppcoreguidelines-special-member-functions, hicpp-special-member-functions) public: inline Local() = default; template inline Local(const Local ¤t) : address_(reinterpret_cast(*current)) { // Check } Local(const EcmaVM *vm, const Global ¤t); Local(const EcmaVM *vm, const CopyableGlobal ¤t); ~Local() = default; inline T *operator*() const { return GetAddress(); } inline T *operator->() const { return GetAddress(); } inline bool IsEmpty() const { return GetAddress() == nullptr; } inline bool IsNull() const { return IsEmpty() || GetAddress()->IsHole(); } private: explicit inline Local(uintptr_t addr) : address_(addr) {} inline T *GetAddress() const { return reinterpret_cast(address_); }; uintptr_t address_ = 0U; friend JSNApiHelper; friend EscapeLocalScope; friend JsiRuntimeCallInfo; }; /** * A Copyable global handle, keeps a separate global handle for each CopyableGlobal. * * Support Copy Constructor and Assign, Move Constructor And Assign. * * If destructed, the global handle held will be automatically released. * * Usage: It Can be used as heap object assign to another variable, a value passing parameter, or * a value passing return value and so on. */ template class PUBLIC_API CopyableGlobal { public: inline CopyableGlobal() = default; ~CopyableGlobal() { Free(); } inline CopyableGlobal(const CopyableGlobal &that) { Copy(that); } inline CopyableGlobal &operator=(const CopyableGlobal &that) { Copy(that); return *this; } inline CopyableGlobal(CopyableGlobal &&that) { Move(that); } inline CopyableGlobal &operator=(CopyableGlobal &&that) { Move(that); return *this; } template CopyableGlobal(const EcmaVM *vm, const Local ¤t); CopyableGlobal(const EcmaVM *vm, const Local ¤t); template CopyableGlobal(const CopyableGlobal &that) { Copy(that); } void Reset() { Free(); } Local ToLocal() const { if (IsEmpty()) { return Local(); } return Local(vm_, *this); } void Empty() { address_ = 0; } inline T *operator*() const { return GetAddress(); } inline T *operator->() const { return GetAddress(); } inline bool IsEmpty() const { return GetAddress() == nullptr; } void SetWeakCallback(void *ref, WeakRefClearCallBack freeGlobalCallBack, WeakRefClearCallBack nativeFinalizeCallback); void SetWeak(); void ClearWeak(); bool IsWeak() const; const EcmaVM *GetEcmaVM() const { return vm_; } private: inline T *GetAddress() const { return reinterpret_cast(address_); }; inline void Copy(const CopyableGlobal &that); template inline void Copy(const CopyableGlobal &that); inline void Move(CopyableGlobal &that); inline void Free(); uintptr_t address_ = 0U; const EcmaVM *vm_ {nullptr}; }; template class PUBLIC_API Global { // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions public: inline Global() = default; inline Global(const Global &that) { Update(that); } inline Global &operator=(const Global &that) { Update(that); return *this; } inline Global(Global &&that) { Update(that); } inline Global &operator=(Global &&that) { Update(that); return *this; } template Global(const EcmaVM *vm, const Local ¤t); template Global(const EcmaVM *vm, const Global ¤t); ~Global() = default; Local ToLocal() const { if (IsEmpty()) { return Local(); } return Local(vm_, *this); } Local ToLocal(const EcmaVM *vm) const { return Local(vm, *this); } void Empty() { address_ = 0; } // This method must be called before Global is released. void FreeGlobalHandleAddr(); inline T *operator*() const { return GetAddress(); } inline T *operator->() const { return GetAddress(); } inline bool IsEmpty() const { return GetAddress() == nullptr; } void SetWeak(); void SetWeakCallback(void *ref, WeakRefClearCallBack freeGlobalCallBack, WeakRefClearCallBack nativeFinalizeCallback); void ClearWeak(); bool IsWeak() const; private: inline T *GetAddress() const { return reinterpret_cast(address_); }; inline void Update(const Global &that); uintptr_t address_ = 0U; const EcmaVM *vm_ {nullptr}; }; // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions, hicpp-special-member-functions) class PUBLIC_API LocalScope { public: explicit LocalScope(const EcmaVM *vm); virtual ~LocalScope(); protected: inline LocalScope(const EcmaVM *vm, JSTaggedType value); private: void *prevNext_ = nullptr; void *prevEnd_ = nullptr; int prevHandleStorageIndex_ {-1}; void *thread_ = nullptr; }; class PUBLIC_API EscapeLocalScope final : public LocalScope { public: explicit EscapeLocalScope(const EcmaVM *vm); ~EscapeLocalScope() override = default; ECMA_DISALLOW_COPY(EscapeLocalScope); ECMA_DISALLOW_MOVE(EscapeLocalScope); template inline Local Escape(Local current) { ASSERT(!alreadyEscape_); alreadyEscape_ = true; *(reinterpret_cast(escapeHandle_)) = **current; return Local(escapeHandle_); } private: bool alreadyEscape_ = false; uintptr_t escapeHandle_ = 0U; }; class PUBLIC_API JSExecutionScope { public: explicit JSExecutionScope(const EcmaVM *vm); ~JSExecutionScope(); ECMA_DISALLOW_COPY(JSExecutionScope); ECMA_DISALLOW_MOVE(JSExecutionScope); private: void *lastCurrentThread_ = nullptr; bool isRevert_ = false; }; class PUBLIC_API JSValueRef { public: static Local Undefined(const EcmaVM *vm); static Local Null(const EcmaVM *vm); static Local True(const EcmaVM *vm); static Local False(const EcmaVM *vm); bool BooleaValue(); int64_t IntegerValue(const EcmaVM *vm); uint32_t Uint32Value(const EcmaVM *vm); int32_t Int32Value(const EcmaVM *vm); Local ToNumber(const EcmaVM *vm); Local ToBoolean(const EcmaVM *vm); Local ToString(const EcmaVM *vm); Local ToObject(const EcmaVM *vm); Local ToNativePointer(const EcmaVM *vm); bool IsUndefined(); bool IsNull(); bool IsHole(); bool IsTrue(); bool IsFalse(); bool IsNumber(); bool IsBigInt(); bool IsInt(); bool WithinInt32(); bool IsBoolean(); bool IsString(); bool IsSymbol(); bool IsObject(); bool IsArray(const EcmaVM *vm); bool IsJSArray(const EcmaVM *vm); bool IsConstructor(); bool IsFunction(); bool IsProxy(); bool IsPromise(); bool IsDataView(); bool IsTypedArray(); bool IsNativePointer(); bool IsDate(); bool IsError(); bool IsMap(); bool IsSet(); bool IsWeakRef(); bool IsWeakMap(); bool IsWeakSet(); bool IsRegExp(); bool IsArrayIterator(); bool IsStringIterator(); bool IsSetIterator(); bool IsMapIterator(); bool IsArrayBuffer(); bool IsBuffer(); bool IsUint8Array(); bool IsInt8Array(); bool IsUint8ClampedArray(); bool IsInt16Array(); bool IsUint16Array(); bool IsInt32Array(); bool IsUint32Array(); bool IsFloat32Array(); bool IsFloat64Array(); bool IsBigInt64Array(); bool IsBigUint64Array(); bool IsJSPrimitiveRef(); bool IsJSPrimitiveNumber(); bool IsJSPrimitiveInt(); bool IsJSPrimitiveBoolean(); bool IsJSPrimitiveString(); bool IsGeneratorObject(); bool IsJSPrimitiveSymbol(); bool IsArgumentsObject(); bool IsGeneratorFunction(); bool IsAsyncFunction(); bool IsJSLocale(); bool IsJSDateTimeFormat(); bool IsJSRelativeTimeFormat(); bool IsJSIntl(); bool IsJSNumberFormat(); bool IsJSCollator(); bool IsJSPluralRules(); bool IsJSListFormat(); bool IsAsyncGeneratorFunction(); bool IsAsyncGeneratorObject(); bool IsModuleNamespaceObject(); bool IsSharedArrayBuffer(); bool IsStrictEquals(const EcmaVM *vm, Local value); Local Typeof(const EcmaVM *vm); bool InstanceOf(const EcmaVM *vm, Local value); bool IsArrayList(); bool IsDeque(); bool IsHashMap(); bool IsHashSet(); bool IsLightWeightMap(); bool IsLightWeightSet(); bool IsLinkedList(); bool IsLinkedListIterator(); bool IsList(); bool IsPlainArray(); bool IsQueue(); bool IsStack(); bool IsTreeMap(); bool IsTreeSet(); bool IsVector(); private: JSTaggedType value_; friend JSNApi; template friend class Global; template friend class Local; }; class PUBLIC_API PrimitiveRef : public JSValueRef { public: Local GetValue(const EcmaVM *vm); }; class PUBLIC_API IntegerRef : public PrimitiveRef { public: static Local New(const EcmaVM *vm, int input); static Local NewFromUnsigned(const EcmaVM *vm, unsigned int input); int Value(); }; class PUBLIC_API NumberRef : public PrimitiveRef { public: static Local New(const EcmaVM *vm, double input); static Local New(const EcmaVM *vm, int32_t input); static Local New(const EcmaVM *vm, uint32_t input); static Local New(const EcmaVM *vm, int64_t input); double Value(); }; class PUBLIC_API BigIntRef : public PrimitiveRef { public: static Local New(const EcmaVM *vm, uint64_t input); static Local New(const EcmaVM *vm, int64_t input); static Local CreateBigWords(const EcmaVM *vm, bool sign, uint32_t size, const uint64_t* words); void BigIntToInt64(const EcmaVM *vm, int64_t *cValue, bool *lossless); void BigIntToUint64(const EcmaVM *vm, uint64_t *cValue, bool *lossless); void GetWordsArray(bool* signBit, size_t wordCount, uint64_t* words); uint32_t GetWordsArraySize(); }; class PUBLIC_API BooleanRef : public PrimitiveRef { public: static Local New(const EcmaVM *vm, bool input); bool Value(); }; class PUBLIC_API StringRef : public PrimitiveRef { public: static inline StringRef *Cast(JSValueRef *value) { // check return static_cast(value); } static Local NewFromUtf8(const EcmaVM *vm, const char *utf8, int length = -1); static Local NewFromUtf16(const EcmaVM *vm, const char16_t *utf16, int length = -1); std::string ToString(); uint32_t Length(); int32_t Utf8Length(const EcmaVM *vm); int WriteUtf8(char *buffer, int length, bool isWriteBuffer = false); int WriteUtf16(char16_t *buffer, int length); int WriteLatin1(char *buffer, int length); static Local GetNapiWrapperString(const EcmaVM *vm); }; class PUBLIC_API SymbolRef : public PrimitiveRef { public: static Local New(const EcmaVM *vm, Local description); Local GetDescription(const EcmaVM *vm); }; using NativePointerCallback = void (*)(void* value, void* hint); class PUBLIC_API NativePointerRef : public JSValueRef { public: static Local New(const EcmaVM *vm, void *nativePointer, size_t nativeBindingsize = 0); static Local New(const EcmaVM *vm, void *nativePointer, NativePointerCallback callBack, void *data, size_t nativeBindingsize = 0); void *Value(); }; // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions, hicpp-special-member-functions) class PUBLIC_API PropertyAttribute { public: static PropertyAttribute Default() { return PropertyAttribute(); } PropertyAttribute() = default; PropertyAttribute(Local value, bool w, bool e, bool c) : value_(value), writable_(w), enumerable_(e), configurable_(c), hasWritable_(true), hasEnumerable_(true), hasConfigurable_(true) {} ~PropertyAttribute() = default; bool IsWritable() const { return writable_; } void SetWritable(bool flag) { writable_ = flag; hasWritable_ = true; } bool IsEnumerable() const { return enumerable_; } void SetEnumerable(bool flag) { enumerable_ = flag; hasEnumerable_ = true; } bool IsConfigurable() const { return configurable_; } void SetConfigurable(bool flag) { configurable_ = flag; hasConfigurable_ = true; } bool HasWritable() const { return hasWritable_; } bool HasConfigurable() const { return hasConfigurable_; } bool HasEnumerable() const { return hasEnumerable_; } Local GetValue(const EcmaVM *vm) const { if (value_.IsEmpty()) { return JSValueRef::Undefined(vm); } return value_; } void SetValue(Local value) { value_ = value; } inline bool HasValue() const { return !value_.IsEmpty(); } Local GetGetter(const EcmaVM *vm) const { if (getter_.IsEmpty()) { return JSValueRef::Undefined(vm); } return getter_; } void SetGetter(Local value) { getter_ = value; } bool HasGetter() const { return !getter_.IsEmpty(); } Local GetSetter(const EcmaVM *vm) const { if (setter_.IsEmpty()) { return JSValueRef::Undefined(vm); } return setter_; } void SetSetter(Local value) { setter_ = value; } bool HasSetter() const { return !setter_.IsEmpty(); } private: Local value_; Local getter_; Local setter_; bool writable_ = false; bool enumerable_ = false; bool configurable_ = false; bool hasWritable_ = false; bool hasEnumerable_ = false; bool hasConfigurable_ = false; }; class PUBLIC_API ObjectRef : public JSValueRef { public: static inline ObjectRef *Cast(JSValueRef *value) { // check return static_cast(value); } static Local New(const EcmaVM *vm); static Local New(const EcmaVM *vm, void *attach, void *detach); bool Set(const EcmaVM *vm, void *attach, void *detach); bool Set(const EcmaVM *vm, Local key, Local value); bool Set(const EcmaVM *vm, uint32_t key, Local value); bool SetAccessorProperty(const EcmaVM *vm, Local key, Local getter, Local setter, PropertyAttribute attribute = PropertyAttribute::Default()); Local Get(const EcmaVM *vm, Local key); Local Get(const EcmaVM *vm, int32_t key); bool GetOwnProperty(const EcmaVM *vm, Local key, PropertyAttribute &property); Local GetOwnPropertyNames(const EcmaVM *vm); Local GetAllPropertyNames(const EcmaVM *vm, uint32_t filter); Local GetOwnEnumerablePropertyNames(const EcmaVM *vm); Local GetPrototype(const EcmaVM *vm); bool SetPrototype(const EcmaVM *vm, Local prototype); bool DefineProperty(const EcmaVM *vm, Local key, PropertyAttribute attribute); bool Has(const EcmaVM *vm, Local key); bool Has(const EcmaVM *vm, uint32_t key); bool Delete(const EcmaVM *vm, Local key); bool Delete(const EcmaVM *vm, uint32_t key); Local Freeze(const EcmaVM *vm); Local Seal(const EcmaVM *vm); void SetNativePointerFieldCount(int32_t count); int32_t GetNativePointerFieldCount(); void *GetNativePointerField(int32_t index); void SetNativePointerField(int32_t index, void *nativePointer = nullptr, NativePointerCallback callBack = nullptr, void *data = nullptr, size_t nativeBindingsize = 0); }; using FunctionCallback = Local(*)(JsiRuntimeCallInfo*); class PUBLIC_API FunctionRef : public ObjectRef { public: static Local New(EcmaVM *vm, FunctionCallback nativeFunc, Deleter deleter = nullptr, void *data = nullptr, bool callNapi = false, size_t nativeBindingsize = 0); static Local NewClassFunction(EcmaVM *vm, FunctionCallback nativeFunc, Deleter deleter, void *data, bool callNapi = false, size_t nativeBindingsize = 0); Local Call(const EcmaVM *vm, Local thisObj, const Local argv[], int32_t length); Local Constructor(const EcmaVM *vm, const Local argv[], int32_t length); Local GetFunctionPrototype(const EcmaVM *vm); // Inherit Prototype from parent function // set this.Prototype.__proto__ to parent.Prototype, set this.__proto__ to parent function bool Inherit(const EcmaVM *vm, Local parent); void SetName(const EcmaVM *vm, Local name); Local GetName(const EcmaVM *vm); Local GetSourceCode(const EcmaVM *vm, int lineNumber); bool IsNative(const EcmaVM *vm); }; class PUBLIC_API ArrayRef : public ObjectRef { public: static Local New(const EcmaVM *vm, uint32_t length = 0); uint32_t Length(const EcmaVM *vm); static bool SetValueAt(const EcmaVM *vm, Local obj, uint32_t index, Local value); static Local GetValueAt(const EcmaVM *vm, Local obj, uint32_t index); }; class PUBLIC_API PromiseRef : public ObjectRef { public: Local Catch(const EcmaVM *vm, Local handler); Local Then(const EcmaVM *vm, Local handler); Local Finally(const EcmaVM *vm, Local handler); Local Then(const EcmaVM *vm, Local onFulfilled, Local onRejected); }; class PUBLIC_API PromiseCapabilityRef : public ObjectRef { public: static Local New(const EcmaVM *vm); bool Resolve(const EcmaVM *vm, Local value); bool Reject(const EcmaVM *vm, Local reason); Local GetPromise(const EcmaVM *vm); }; class PUBLIC_API ArrayBufferRef : public ObjectRef { public: static Local New(const EcmaVM *vm, int32_t length); static Local New(const EcmaVM *vm, void *buffer, int32_t length, const Deleter &deleter, void *data); int32_t ByteLength(const EcmaVM *vm); void *GetBuffer(); void Detach(const EcmaVM *vm); bool IsDetach(); }; class PUBLIC_API BufferRef : public ObjectRef { public: static Local New(const EcmaVM *vm, int32_t length); static Local New(const EcmaVM *vm, void *buffer, int32_t length, const Deleter &deleter, void *data); int32_t ByteLength(const EcmaVM *vm); void *GetBuffer(); static ecmascript::JSTaggedValue BufferToStringCallback(ecmascript::EcmaRuntimeCallInfo *ecmaRuntimeCallInfo); }; class PUBLIC_API DataViewRef : public ObjectRef { public: static Local New(const EcmaVM *vm, Local arrayBuffer, uint32_t byteOffset, uint32_t byteLength); uint32_t ByteLength(); uint32_t ByteOffset(); Local GetArrayBuffer(const EcmaVM *vm); }; class PUBLIC_API TypedArrayRef : public ObjectRef { public: uint32_t ByteLength(const EcmaVM *vm); uint32_t ByteOffset(const EcmaVM *vm); uint32_t ArrayLength(const EcmaVM *vm); Local GetArrayBuffer(const EcmaVM *vm); }; class PUBLIC_API Int8ArrayRef : public TypedArrayRef { public: static Local New(const EcmaVM *vm, Local buffer, int32_t byteOffset, int32_t length); }; class PUBLIC_API Uint8ArrayRef : public TypedArrayRef { public: static Local New(const EcmaVM *vm, Local buffer, int32_t byteOffset, int32_t length); }; class PUBLIC_API Uint8ClampedArrayRef : public TypedArrayRef { public: static Local New(const EcmaVM *vm, Local buffer, int32_t byteOffset, int32_t length); }; class PUBLIC_API Int16ArrayRef : public TypedArrayRef { public: static Local New(const EcmaVM *vm, Local buffer, int32_t byteOffset, int32_t length); }; class PUBLIC_API Uint16ArrayRef : public TypedArrayRef { public: static Local New(const EcmaVM *vm, Local buffer, int32_t byteOffset, int32_t length); }; class PUBLIC_API Int32ArrayRef : public TypedArrayRef { public: static Local New(const EcmaVM *vm, Local buffer, int32_t byteOffset, int32_t length); }; class PUBLIC_API Uint32ArrayRef : public TypedArrayRef { public: static Local New(const EcmaVM *vm, Local buffer, int32_t byteOffset, int32_t length); }; class PUBLIC_API Float32ArrayRef : public TypedArrayRef { public: static Local New(const EcmaVM *vm, Local buffer, int32_t byteOffset, int32_t length); }; class PUBLIC_API Float64ArrayRef : public TypedArrayRef { public: static Local New(const EcmaVM *vm, Local buffer, int32_t byteOffset, int32_t length); }; class PUBLIC_API BigInt64ArrayRef : public TypedArrayRef { public: static Local New(const EcmaVM *vm, Local buffer, int32_t byteOffset, int32_t length); }; class PUBLIC_API BigUint64ArrayRef : public TypedArrayRef { public: static Local New(const EcmaVM *vm, Local buffer, int32_t byteOffset, int32_t length); }; class PUBLIC_API RegExpRef : public ObjectRef { public: Local GetOriginalSource(const EcmaVM *vm); std::string GetOriginalFlags(); Local IsGlobal(const EcmaVM *vm); Local IsIgnoreCase(const EcmaVM *vm); Local IsMultiline(const EcmaVM *vm); Local IsDotAll(const EcmaVM *vm); Local IsUtf16(const EcmaVM *vm); Local IsStick(const EcmaVM *vm); }; class PUBLIC_API DateRef : public ObjectRef { public: static Local New(const EcmaVM *vm, double time); Local ToString(const EcmaVM *vm); double GetTime(); }; class PUBLIC_API ProxyRef : public ObjectRef { public: Local GetHandler(const EcmaVM *vm); Local GetTarget(const EcmaVM *vm); bool IsRevoked(); }; class PUBLIC_API MapRef : public ObjectRef { public: int32_t GetSize(); int32_t GetTotalElements(); Local Get(const EcmaVM *vm, Local key); Local GetKey(const EcmaVM *vm, int entry); Local GetValue(const EcmaVM *vm, int entry); static Local New(const EcmaVM *vm); void Set(const EcmaVM *vm, Local key, Local value); }; class PUBLIC_API WeakMapRef : public ObjectRef { public: int32_t GetSize(); int32_t GetTotalElements(); Local GetKey(const EcmaVM *vm, int entry); Local GetValue(const EcmaVM *vm, int entry); }; class PUBLIC_API SetRef : public ObjectRef { public: int32_t GetSize(); int32_t GetTotalElements(); Local GetValue(const EcmaVM *vm, int entry); }; class PUBLIC_API WeakSetRef : public ObjectRef { public: int32_t GetSize(); int32_t GetTotalElements(); Local GetValue(const EcmaVM *vm, int entry); }; class PUBLIC_API MapIteratorRef : public ObjectRef { public: int32_t GetIndex(); Local GetKind(const EcmaVM *vm); }; class PUBLIC_API SetIteratorRef : public ObjectRef { public: int32_t GetIndex(); Local GetKind(const EcmaVM *vm); }; class PUBLIC_API GeneratorFunctionRef : public ObjectRef { public: bool IsGenerator(); }; class PUBLIC_API GeneratorObjectRef : public ObjectRef { public: Local GetGeneratorState(const EcmaVM *vm); Local GetGeneratorFunction(const EcmaVM *vm); Local GetGeneratorReceiver(const EcmaVM *vm); }; class PUBLIC_API CollatorRef : public ObjectRef { public: Local GetCompareFunction(const EcmaVM *vm); }; class PUBLIC_API DataTimeFormatRef : public ObjectRef { public: Local GetFormatFunction(const EcmaVM *vm); }; class PUBLIC_API NumberFormatRef : public ObjectRef { public: Local GetFormatFunction(const EcmaVM *vm); }; class PUBLIC_API JSON { public: static Local Parse(const EcmaVM *vm, Local string); static Local Stringify(const EcmaVM *vm, Local json); }; class PUBLIC_API Exception { public: static Local Error(const EcmaVM *vm, Local message); static Local RangeError(const EcmaVM *vm, Local message); static Local ReferenceError(const EcmaVM *vm, Local message); static Local SyntaxError(const EcmaVM *vm, Local message); static Local TypeError(const EcmaVM *vm, Local message); static Local AggregateError(const EcmaVM *vm, Local message); static Local EvalError(const EcmaVM *vm, Local message); static Local OOMError(const EcmaVM *vm, Local message); }; using LOG_PRINT = int (*)(int id, int level, const char *tag, const char *fmt, const char *message); class PUBLIC_API RuntimeOption { public: enum class PUBLIC_API GC_TYPE : uint8_t { EPSILON, GEN_GC, STW }; enum class PUBLIC_API LOG_LEVEL : uint8_t { DEBUG = 3, INFO = 4, WARN = 5, ERROR = 6, FATAL = 7, FOLLOW = 100, // if hilog enabled follow hilog, otherwise use INFO level }; void SetGcType(GC_TYPE type) { gcType_ = type; } void SetGcPoolSize(uint32_t size) { gcPoolSize_ = size; } void SetLogLevel(LOG_LEVEL logLevel) { logLevel_ = logLevel; } void SetLogBufPrint(LOG_PRINT out) { logBufPrint_ = out; } void SetDebuggerLibraryPath(const std::string &path) { debuggerLibraryPath_ = path; } void SetEnableArkTools(bool value) { enableArkTools_ = value; } void SetEnableCpuprofiler(bool value) { enableCpuprofiler_ = value; } void SetArkProperties(int prop) { arkProperties_ = prop; } void SetArkBundleName(const std::string &bundleName) { arkBundleName_ = bundleName; } void SetGcThreadNum(size_t num) { gcThreadNum_ = num; } void SetLongPauseTime(size_t time) { longPauseTime_ = time; } void SetEnableAsmInterpreter(bool value) { enableAsmInterpreter_ = value; } void SetEnableBuiltinsLazy(bool value) { enableBuiltinsLazy_ = value; } void SetAsmOpcodeDisableRange(const std::string &value) { asmOpcodeDisableRange_ = value; } void SetIsWorker() { isWorker_ = true; } bool GetIsWorker() const { return isWorker_; } void SetBundleName(const std::string &value) { bundleName_ = value; } void SetEnableAOT(bool value) { enableAOT_ = value; } void SetAnDir(const std::string &value) { anDir_ = value; } void SetEnableProfile(bool value) { enableProfile_ = value; } // Valid only when SetEnableProfile(true) void SetProfileDir(const std::string &value) { profileDir_ = value; } private: std::string GetGcType() const { std::string gcType; switch (gcType_) { case GC_TYPE::GEN_GC: gcType = "gen-gc"; break; case GC_TYPE::STW: gcType = "stw"; break; case GC_TYPE::EPSILON: gcType = "epsilon"; break; default: UNREACHABLE(); } return gcType; } LOG_LEVEL GetLogLevel() const { return logLevel_; } uint32_t GetGcPoolSize() const { return gcPoolSize_; } LOG_PRINT GetLogBufPrint() const { return logBufPrint_; } std::string GetDebuggerLibraryPath() const { return debuggerLibraryPath_; } bool GetEnableArkTools() const { return enableArkTools_; } bool GetEnableCpuprofiler() const { return enableCpuprofiler_; } int GetArkProperties() const { return arkProperties_; } std::string GetArkBundleName() const { return arkBundleName_; } size_t GetGcThreadNum() const { return gcThreadNum_; } size_t GetLongPauseTime() const { return longPauseTime_; } bool GetEnableAsmInterpreter() const { return enableAsmInterpreter_; } bool GetEnableBuiltinsLazy() const { return enableBuiltinsLazy_; } std::string GetAsmOpcodeDisableRange() const { return asmOpcodeDisableRange_; } std::string GetBundleName() const { return bundleName_; } bool GetEnableAOT() const { return enableAOT_; } std::string GetAnDir() const { return anDir_; } bool GetEnableProfile() const { return enableProfile_; } std::string GetProfileDir() const { return profileDir_; } GC_TYPE gcType_ = GC_TYPE::EPSILON; LOG_LEVEL logLevel_ = LOG_LEVEL::DEBUG; uint32_t gcPoolSize_ = ecmascript::DEFAULT_GC_POOL_SIZE; LOG_PRINT logBufPrint_ {nullptr}; std::string debuggerLibraryPath_ {}; bool enableArkTools_ {false}; bool enableCpuprofiler_ {false}; int arkProperties_ {-1}; std::string arkBundleName_ = {""}; size_t gcThreadNum_ {DEFAULT_GC_THREAD_NUM}; size_t longPauseTime_ {DEFAULT_LONG_PAUSE_TIME}; bool enableAsmInterpreter_ {true}; bool enableBuiltinsLazy_ {true}; bool isWorker_ {false}; std::string asmOpcodeDisableRange_ {""}; std::string bundleName_ {}; bool enableAOT_ {false}; std::string anDir_ {}; bool enableProfile_ {false}; std::string profileDir_ {}; friend JSNApi; }; class PUBLIC_API PromiseRejectInfo { public: enum class PUBLIC_API PROMISE_REJECTION_EVENT : uint32_t { REJECT = 0, HANDLE }; PromiseRejectInfo(Local promise, Local reason, PromiseRejectInfo::PROMISE_REJECTION_EVENT operation, void* data); ~PromiseRejectInfo() {} Local GetPromise() const; Local GetReason() const; PromiseRejectInfo::PROMISE_REJECTION_EVENT GetOperation() const; void* GetData() const; private: Local promise_ {}; Local reason_ {}; PROMISE_REJECTION_EVENT operation_ = PROMISE_REJECTION_EVENT::REJECT; void* data_ {nullptr}; }; class PUBLIC_API JSNApi { public: struct DebugOption { const char *libraryPath; bool isDebugMode; int port = -1; }; using DebuggerPostTask = std::function&&)>; // JSVM // fixme: Rename SEMI_GC to YOUNG_GC enum class PUBLIC_API TRIGGER_GC_TYPE : uint8_t { SEMI_GC, OLD_GC, FULL_GC }; enum class PatchErrorCode : uint8_t { SUCCESS = 0, PATCH_HAS_LOADED, PATCH_NOT_LOADED, FILE_NOT_EXECUTED, FILE_NOT_FOUND, PACKAGE_NOT_ESMODULE, MODIFY_IMPORT_EXPORT_NOT_SUPPORT, INTERNAL_ERROR }; static EcmaVM *CreateJSVM(const RuntimeOption &option); static void DestroyJSVM(EcmaVM *ecmaVm); // aot load static void LoadAotFile(EcmaVM *vm, const std::string &moduleName); // context static EcmaContext *CreateJSContext(EcmaVM *vm); static void SwitchCurrentContext(EcmaVM *vm, EcmaContext *context); static void DestroyJSContext(EcmaVM *vm, EcmaContext *context); // context execute static bool ExecuteInContext(EcmaVM *vm, const std::string &fileName, const std::string &entry, bool needUpdate = false); // JS code static bool Execute(EcmaVM *vm, const std::string &fileName, const std::string &entry, bool needUpdate = false); static bool Execute(EcmaVM *vm, const uint8_t *data, int32_t size, const std::string &entry, const std::string &filename = "", bool needUpdate = false); // merge abc, execute module buffer static bool ExecuteModuleBuffer(EcmaVM *vm, const uint8_t *data, int32_t size, const std::string &filename = "", bool needUpdate = false); static bool ExecuteModuleFromBuffer(EcmaVM *vm, const void *data, int32_t size, const std::string &file); static Local GetExportObject(EcmaVM *vm, const std::string &file, const std::string &key); static Local GetExportObjectFromBuffer(EcmaVM *vm, const std::string &file, const std::string &key); /* * Execute panda file from secure mem. secure memory lifecycle managed externally. * The data parameter needs to be created externally by an external caller and managed externally * by the external caller. The size parameter is the size of the data memory. The entry parameter * is the name of the entry function. The filename parameter is used to uniquely identify this * memory internally. */ static bool ExecuteSecure(EcmaVM *vm, uint8_t *data, int32_t size, const std::string &entry, const std::string &filename = "", bool needUpdate = false); /* * Execute panda file(merge abc) from secure mem. secure memory lifecycle managed externally. * The data parameter needs to be created externally by an external caller and managed externally * by the external caller. The size parameter is the size of the data memory. The filename parameter * is used to uniquely identify this memory internally. */ static bool ExecuteModuleBufferSecure(EcmaVM *vm, uint8_t *data, int32_t size, const std::string &filename = "", bool needUpdate = false); // ObjectRef Operation static Local GetGlobalObject(const EcmaVM *vm); static void ExecutePendingJob(const EcmaVM *vm); // Memory // fixme: Rename SEMI_GC to YOUNG_GC static void TriggerGC(const EcmaVM *vm, TRIGGER_GC_TYPE gcType = TRIGGER_GC_TYPE::SEMI_GC); // Exception static void ThrowException(const EcmaVM *vm, Local error); static void PrintExceptionInfo(const EcmaVM *vm); static Local GetAndClearUncaughtException(const EcmaVM *vm); static Local GetUncaughtException(const EcmaVM *vm); static bool HasPendingException(const EcmaVM *vm); static void EnableUserUncaughtErrorHandler(EcmaVM *vm); static bool StartDebugger(EcmaVM *vm, const DebugOption &option, int32_t instanceId = 0, const DebuggerPostTask &debuggerPostTask = {}); static bool StopDebugger(EcmaVM *vm); static bool IsMixedDebugEnabled(const EcmaVM *vm); static void NotifyNativeCalling(const EcmaVM *vm, const void *nativeAddress); // Serialize & Deserialize. static void* SerializeValue(const EcmaVM *vm, Local data, Local transfer); static Local DeserializeValue(const EcmaVM *vm, void *recoder, void *hint); static void DeleteSerializationData(void *data); static void SetHostPromiseRejectionTracker(EcmaVM *vm, void *cb, void* data); static void SetHostResolveBufferTracker(EcmaVM *vm, std::function cb); static void SetUnloadNativeModuleCallback(EcmaVM *vm, const std::function &cb); static void SetNativePtrGetter(EcmaVM *vm, void* cb); static void SetHostEnqueueJob(const EcmaVM* vm, Local cb); static void InitializeIcuData(const ecmascript::JSRuntimeOptions &options); static void InitializeMemMapAllocator(); static void InitializePGOProfiler(const ecmascript::JSRuntimeOptions &options); static void DestroyAnDataManager(); static void DestroyMemMapAllocator(); static void DestroyPGOProfiler(); static EcmaVM* CreateEcmaVM(const ecmascript::JSRuntimeOptions &options); static void PreFork(EcmaVM *vm); static void PostFork(EcmaVM *vm, const RuntimeOption &option); static void addWorker(EcmaVM *hostVm, EcmaVM *workerVm); static bool DeleteWorker(EcmaVM *hostVm, EcmaVM *workerVm); static PatchErrorCode LoadPatch(EcmaVM *vm, const std::string &patchFileName, const std::string &baseFileName); static PatchErrorCode LoadPatch(EcmaVM *vm, const std::string &patchFileName, const void *patchBuffer, size_t patchSize, const std::string &baseFileName, const void *baseBuffer, size_t baseSize); static PatchErrorCode UnloadPatch(EcmaVM *vm, const std::string &patchFileName); // check whether the exception is caused by quickfix methods. static bool IsQuickFixCausedException(EcmaVM *vm, Local exception, const std::string &patchFileName); // register quickfix query function. static void RegisterQuickFixQueryFunc(EcmaVM *vm, std::function callBack); static bool IsBundle(EcmaVM *vm); static void SetBundle(EcmaVM *vm, bool value); static void SetAssetPath(EcmaVM *vm, const std::string &assetPath); static void SetLoop(EcmaVM *vm, void *loop); static std::string GetAssetPath(EcmaVM *vm); static bool InitForConcurrentThread(EcmaVM *vm, ConcurrentCallback cb, void *data); static bool InitForConcurrentFunction(EcmaVM *vm, Local func, void *taskInfo); static void* GetCurrentTaskInfo(const EcmaVM *vm); static void SetBundleName(EcmaVM *vm, const std::string &bundleName); static std::string GetBundleName(EcmaVM *vm); static void SetModuleName(EcmaVM *vm, const std::string &moduleName); static std::string GetModuleName(EcmaVM *vm); static void AllowCrossThreadExecution(EcmaVM *vm); static void SynchronizVMInfo(EcmaVM *vm, const EcmaVM *hostVM); private: static int vmCount_; static bool initialize_; static bool CreateRuntime(const RuntimeOption &option); static bool DestroyRuntime(); static uintptr_t GetHandleAddr(const EcmaVM *vm, uintptr_t localAddress); static uintptr_t GetGlobalHandleAddr(const EcmaVM *vm, uintptr_t localAddress); static uintptr_t SetWeak(const EcmaVM *vm, uintptr_t localAddress); static uintptr_t SetWeakCallback(const EcmaVM *vm, uintptr_t localAddress, void *ref, WeakRefClearCallBack freeGlobalCallBack, WeakRefClearCallBack nativeFinalizeCallback); static uintptr_t ClearWeak(const EcmaVM *vm, uintptr_t localAddress); static bool IsWeak(const EcmaVM *vm, uintptr_t localAddress); static void DisposeGlobalHandleAddr(const EcmaVM *vm, uintptr_t addr); template friend class Global; template friend class CopyableGlobal; template friend class Local; friend class test::JSNApiTests; }; /** * JsiRuntimeCallInfo is used for ace_engine and napi, is same to ark EcamRuntimeCallInfo except data. */ class PUBLIC_API JsiRuntimeCallInfo { public: JsiRuntimeCallInfo(ecmascript::EcmaRuntimeCallInfo* ecmaInfo, void* data); ~JsiRuntimeCallInfo() = default; inline JSThread *GetThread() const { return thread_; } EcmaVM *GetVM() const; inline uint32_t GetArgsNumber() const { return numArgs_; } inline void* GetData() const { return data_; } inline Local GetFunctionRef() const { return GetArgRef(FUNC_INDEX); } inline Local GetNewTargetRef() const { return GetArgRef(NEW_TARGET_INDEX); } inline Local GetThisRef() const { return GetArgRef(THIS_INDEX); } inline Local GetCallArgRef(uint32_t idx) const { return GetArgRef(FIRST_ARGS_INDEX + idx); } private: enum ArgsIndex : uint8_t { FUNC_INDEX = 0, NEW_TARGET_INDEX, THIS_INDEX, FIRST_ARGS_INDEX }; Local GetArgRef(uint32_t idx) const { return Local(GetArgAddress(idx)); } uintptr_t GetArgAddress(uint32_t idx) const { if (idx < static_cast(numArgs_ + FIRST_ARGS_INDEX)) { return reinterpret_cast(&stackArgs_[idx]); } return 0U; } private: JSThread *thread_ {nullptr}; uint32_t numArgs_ = 0; JSTaggedType *stackArgs_ {nullptr}; void *data_ {nullptr}; friend class FunctionRef; }; class PUBLIC_API FunctionCallScope { public: FunctionCallScope(EcmaVM *vm); ~FunctionCallScope(); private: EcmaVM *vm_; }; template template Global::Global(const EcmaVM *vm, const Local ¤t) : vm_(vm) { if (!current.IsEmpty()) { address_ = JSNApi::GetGlobalHandleAddr(vm_, reinterpret_cast(*current)); } } template template Global::Global(const EcmaVM *vm, const Global ¤t) : vm_(vm) { if (!current.IsEmpty()) { address_ = JSNApi::GetGlobalHandleAddr(vm_, reinterpret_cast(*current)); } } template CopyableGlobal::CopyableGlobal(const EcmaVM *vm, const Local ¤t) : vm_(vm) { if (!current.IsEmpty()) { address_ = JSNApi::GetGlobalHandleAddr(vm_, reinterpret_cast(*current)); } } template template CopyableGlobal::CopyableGlobal(const EcmaVM *vm, const Local ¤t) : vm_(vm) { if (!current.IsEmpty()) { address_ = JSNApi::GetGlobalHandleAddr(vm_, reinterpret_cast(*current)); } } template void CopyableGlobal::Copy(const CopyableGlobal &that) { Free(); vm_ = that.vm_; if (!that.IsEmpty()) { ASSERT(vm_ != nullptr); address_ = JSNApi::GetGlobalHandleAddr(vm_, reinterpret_cast(*that)); } } template template void CopyableGlobal::Copy(const CopyableGlobal &that) { Free(); vm_ = that.GetEcmaVM(); if (!that.IsEmpty()) { ASSERT(vm_ != nullptr); address_ = JSNApi::GetGlobalHandleAddr(vm_, reinterpret_cast(*that)); } } template void CopyableGlobal::Move(CopyableGlobal &that) { Free(); vm_ = that.vm_; address_ = that.address_; that.vm_ = nullptr; that.address_ = 0U; } template inline void CopyableGlobal::Free() { if (!IsEmpty()) { JSNApi::DisposeGlobalHandleAddr(vm_, address_); address_ = 0U; } } template void CopyableGlobal::SetWeakCallback(void *ref, WeakRefClearCallBack freeGlobalCallBack, WeakRefClearCallBack nativeFinalizeCallback) { address_ = JSNApi::SetWeakCallback(vm_, address_, ref, freeGlobalCallBack, nativeFinalizeCallback); } template void CopyableGlobal::SetWeak() { address_ = JSNApi::SetWeak(vm_, address_); } template void CopyableGlobal::ClearWeak() { address_ = JSNApi::ClearWeak(vm_, address_); } template bool CopyableGlobal::IsWeak() const { return JSNApi::IsWeak(vm_, address_); } template void Global::Update(const Global &that) { if (address_ != 0) { JSNApi::DisposeGlobalHandleAddr(vm_, address_); } address_ = that.address_; vm_ = that.vm_; } template void Global::FreeGlobalHandleAddr() { if (address_ == 0) { return; } JSNApi::DisposeGlobalHandleAddr(vm_, address_); address_ = 0; } template void Global::SetWeak() { address_ = JSNApi::SetWeak(vm_, address_); } template void Global::SetWeakCallback(void *ref, WeakRefClearCallBack freeGlobalCallBack, WeakRefClearCallBack nativeFinalizeCallback) { address_ = JSNApi::SetWeakCallback(vm_, address_, ref, freeGlobalCallBack, nativeFinalizeCallback); } template void Global::ClearWeak() { address_ = JSNApi::ClearWeak(vm_, address_); } template bool Global::IsWeak() const { return JSNApi::IsWeak(vm_, address_); } // ---------------------------------- Local -------------------------------------------- template Local::Local(const EcmaVM *vm, const CopyableGlobal ¤t) { address_ = JSNApi::GetHandleAddr(vm, reinterpret_cast(*current)); } template Local::Local(const EcmaVM *vm, const Global ¤t) { address_ = JSNApi::GetHandleAddr(vm, reinterpret_cast(*current)); } } // namespace panda #endif // ECMASCRIPT_NAPI_INCLUDE_JSNAPI_H