14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_NAPI_JSNAPI_HELPER_H
174514f5e3Sopenharmony_ci#define ECMASCRIPT_NAPI_JSNAPI_HELPER_H
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_ci#include "ecmascript/ecma_runtime_call_info.h"
204514f5e3Sopenharmony_ci#include "ecmascript/js_handle.h"
214514f5e3Sopenharmony_ci#include "ecmascript/js_tagged_value.h"
224514f5e3Sopenharmony_ci#include "ecmascript/napi/include/jsnapi.h"
234514f5e3Sopenharmony_ci
244514f5e3Sopenharmony_ci// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
254514f5e3Sopenharmony_ci#define RETURN_VALUE_IF_ABRUPT(thread, value)                 \
264514f5e3Sopenharmony_ci    do {                                                      \
274514f5e3Sopenharmony_ci        if (thread->HasPendingException()) {                  \
284514f5e3Sopenharmony_ci            LOG_FULL(ERROR) << "occur exception need return"; \
294514f5e3Sopenharmony_ci            return value;                                     \
304514f5e3Sopenharmony_ci        }                                                     \
314514f5e3Sopenharmony_ci    } while (false)
324514f5e3Sopenharmony_ci
334514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_NAPI_SPECIAL_CHECK
344514f5e3Sopenharmony_ci#define LOG_IF_SPECIAL(handleValue, level)                                                       \
354514f5e3Sopenharmony_ci    do {                                                                                         \
364514f5e3Sopenharmony_ci        LOG_ECMA(DEBUG) << "Enable napi special check";                                           \
374514f5e3Sopenharmony_ci        if ((handleValue).GetTaggedValue().IsSpecial()) {                                        \
384514f5e3Sopenharmony_ci            LOG_FULL(level) << "Special value " << (handleValue).GetTaggedType() << " checked!"; \
394514f5e3Sopenharmony_ci        }                                                                                        \
404514f5e3Sopenharmony_ci    } while (false)
414514f5e3Sopenharmony_ci#else
424514f5e3Sopenharmony_ci#define LOG_IF_SPECIAL(handleValue, level) static_cast<void>(0)
434514f5e3Sopenharmony_ci#endif
444514f5e3Sopenharmony_ci
454514f5e3Sopenharmony_ci#define CROSS_THREAD_CHECK(vm)                                                                  \
464514f5e3Sopenharmony_ci    [[maybe_unused]] JSThread *thread = (vm)->GetJSThread()
474514f5e3Sopenharmony_ci
484514f5e3Sopenharmony_ci#define CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, returnVal)                              \
494514f5e3Sopenharmony_ci    CROSS_THREAD_CHECK(vm);                                                                      \
504514f5e3Sopenharmony_ci    do {                                                                                         \
514514f5e3Sopenharmony_ci        if (thread->HasPendingException()) {                                                     \
524514f5e3Sopenharmony_ci            LOG_ECMA(ERROR) << "Pending exception before " << __FUNCTION__ << " called in line:" \
534514f5e3Sopenharmony_ci                            << __LINE__ << ", exception details as follows:";                    \
544514f5e3Sopenharmony_ci            JSNApi::PrintExceptionInfo(vm);                                                      \
554514f5e3Sopenharmony_ci            return returnVal;                                                                    \
564514f5e3Sopenharmony_ci        }                                                                                        \
574514f5e3Sopenharmony_ci    } while (false)
584514f5e3Sopenharmony_ci
594514f5e3Sopenharmony_ci#define CROSS_THREAD_AND_EXCEPTION_CHECK(vm)                                                      \
604514f5e3Sopenharmony_ci    CROSS_THREAD_CHECK(vm);                                                                       \
614514f5e3Sopenharmony_ci    do {                                                                                          \
624514f5e3Sopenharmony_ci        if (thread->HasPendingException()) {                                                      \
634514f5e3Sopenharmony_ci            LOG_ECMA(ERROR) << "Pending exception before " << __FUNCTION__ << " called, in line:" \
644514f5e3Sopenharmony_ci                            << __LINE__ << ", exception details as follows:";                     \
654514f5e3Sopenharmony_ci            JSNApi::PrintExceptionInfo(vm);                                                       \
664514f5e3Sopenharmony_ci            return;                                                                               \
674514f5e3Sopenharmony_ci        }                                                                                         \
684514f5e3Sopenharmony_ci    } while (false)
694514f5e3Sopenharmony_ci
704514f5e3Sopenharmony_ci#define SINGLE_THREAD_CHECK_WITH_RETURN(vm, result)                                              \
714514f5e3Sopenharmony_ci    [[maybe_unused]] JSThread *thread = (vm)->GetJSThreadNoCheck();                              \
724514f5e3Sopenharmony_ci    do {                                                                                         \
734514f5e3Sopenharmony_ci        if (thread->HasPendingException()) {                                                     \
744514f5e3Sopenharmony_ci            LOG_ECMA(DEBUG) << "Pending exception before " << __FUNCTION__ << " called in line:" \
754514f5e3Sopenharmony_ci                            << __LINE__ << ", exception details as follows:";                    \
764514f5e3Sopenharmony_ci            JSNApi::PrintExceptionInfo(vm);                                                      \
774514f5e3Sopenharmony_ci            return result;                                                                       \
784514f5e3Sopenharmony_ci        }                                                                                        \
794514f5e3Sopenharmony_ci        if (!(vm)->CheckSingleThread()) {                                                        \
804514f5e3Sopenharmony_ci            LOG_ECMA(DEBUG) << "cross thread to call " << __FUNCTION__ << "is not supported";    \
814514f5e3Sopenharmony_ci            return result;                                                                       \
824514f5e3Sopenharmony_ci        }                                                                                        \
834514f5e3Sopenharmony_ci    } while (false)
844514f5e3Sopenharmony_ci
854514f5e3Sopenharmony_ci#define DCHECK_SPECIAL_VALUE(jsValueRef)                                                     \
864514f5e3Sopenharmony_ci    do {                                                                                     \
874514f5e3Sopenharmony_ci        auto val = reinterpret_cast<JSTaggedValue *>(jsValueRef);                            \
884514f5e3Sopenharmony_ci        if (UNLIKELY(val->IsSpecial())) {                                                    \
894514f5e3Sopenharmony_ci            LOG_FULL(ERROR) << "JSNApi special value:0x" << val->GetRawData() << " checked"; \
904514f5e3Sopenharmony_ci            return;                                                                          \
914514f5e3Sopenharmony_ci        }                                                                                    \
924514f5e3Sopenharmony_ci    } while (false)
934514f5e3Sopenharmony_ci
944514f5e3Sopenharmony_ci#define DCHECK_SPECIAL_VALUE_WITH_RETURN(jsValueRef, retValue)                               \
954514f5e3Sopenharmony_ci    do {                                                                                     \
964514f5e3Sopenharmony_ci        auto val = reinterpret_cast<JSTaggedValue *>(jsValueRef);                            \
974514f5e3Sopenharmony_ci        if (UNLIKELY(val->IsSpecial())) {                                                    \
984514f5e3Sopenharmony_ci            LOG_FULL(ERROR) << "JSNApi special value:0x" << val->GetRawData() << " checked"; \
994514f5e3Sopenharmony_ci            return (retValue);                                                               \
1004514f5e3Sopenharmony_ci        }                                                                                    \
1014514f5e3Sopenharmony_ci    } while (false)
1024514f5e3Sopenharmony_ci
1034514f5e3Sopenharmony_ci// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
1044514f5e3Sopenharmony_ci#define TYPED_ARRAY_ALL(V) \
1054514f5e3Sopenharmony_ci    V(Int8Array)           \
1064514f5e3Sopenharmony_ci    V(Uint8Array)          \
1074514f5e3Sopenharmony_ci    V(Uint8ClampedArray)   \
1084514f5e3Sopenharmony_ci    V(Int16Array)          \
1094514f5e3Sopenharmony_ci    V(Uint16Array)         \
1104514f5e3Sopenharmony_ci    V(Int32Array)          \
1114514f5e3Sopenharmony_ci    V(Uint32Array)         \
1124514f5e3Sopenharmony_ci    V(Float32Array)        \
1134514f5e3Sopenharmony_ci    V(Float64Array)        \
1144514f5e3Sopenharmony_ci    V(BigInt64Array)       \
1154514f5e3Sopenharmony_ci    V(BigUint64Array)
1164514f5e3Sopenharmony_ci
1174514f5e3Sopenharmony_ci#define SENDABLE_TYPED_ARRAY_ALL(V) \
1184514f5e3Sopenharmony_ci    V(SharedInt8Array)     \
1194514f5e3Sopenharmony_ci    V(SharedUint8Array)    \
1204514f5e3Sopenharmony_ci    V(SharedInt16Array)    \
1214514f5e3Sopenharmony_ci    V(SharedUint16Array)   \
1224514f5e3Sopenharmony_ci    V(SharedInt32Array)    \
1234514f5e3Sopenharmony_ci    V(SharedUint32Array)   \
1244514f5e3Sopenharmony_ci    V(SharedUint8ClampedArray)   \
1254514f5e3Sopenharmony_ci    V(SharedFloat32Array)
1264514f5e3Sopenharmony_ci
1274514f5e3Sopenharmony_ci// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
1284514f5e3Sopenharmony_ci#define EXCEPTION_ERROR_ALL(V)         \
1294514f5e3Sopenharmony_ci    V(Error, ERROR)                    \
1304514f5e3Sopenharmony_ci    V(RangeError, RANGE_ERROR)         \
1314514f5e3Sopenharmony_ci    V(SyntaxError, SYNTAX_ERROR)       \
1324514f5e3Sopenharmony_ci    V(ReferenceError, REFERENCE_ERROR) \
1334514f5e3Sopenharmony_ci    V(TypeError, TYPE_ERROR)           \
1344514f5e3Sopenharmony_ci    V(AggregateError, AGGREGATE_ERROR) \
1354514f5e3Sopenharmony_ci    V(EvalError, EVAL_ERROR)           \
1364514f5e3Sopenharmony_ci    V(OOMError, OOM_ERROR)             \
1374514f5e3Sopenharmony_ci    V(TerminationError, TERMINATION_ERROR)
1384514f5e3Sopenharmony_ci
1394514f5e3Sopenharmony_cinamespace panda {
1404514f5e3Sopenharmony_ciusing NativeFinalize = void (*)(EcmaVM *);
1414514f5e3Sopenharmony_ciclass JSNApiHelper {
1424514f5e3Sopenharmony_cipublic:
1434514f5e3Sopenharmony_ci    template<typename T>
1444514f5e3Sopenharmony_ci    static inline Local<T> ToLocal(ecmascript::JSHandle<ecmascript::JSTaggedValue> from)
1454514f5e3Sopenharmony_ci    {
1464514f5e3Sopenharmony_ci        return Local<T>(from.GetAddress());
1474514f5e3Sopenharmony_ci    }
1484514f5e3Sopenharmony_ci
1494514f5e3Sopenharmony_ci    static inline ecmascript::JSTaggedValue ToJSTaggedValue(JSValueRef *from)
1504514f5e3Sopenharmony_ci    {
1514514f5e3Sopenharmony_ci        ASSERT(from != nullptr);
1524514f5e3Sopenharmony_ci        return *reinterpret_cast<ecmascript::JSTaggedValue *>(from);
1534514f5e3Sopenharmony_ci    }
1544514f5e3Sopenharmony_ci
1554514f5e3Sopenharmony_ci    static inline ecmascript::JSMutableHandle<ecmascript::JSTaggedValue> ToJSMutableHandle(Local<JSValueRef> from)
1564514f5e3Sopenharmony_ci    {
1574514f5e3Sopenharmony_ci        ASSERT(!from.IsEmpty());
1584514f5e3Sopenharmony_ci        return ecmascript::JSMutableHandle<ecmascript::JSTaggedValue>(reinterpret_cast<uintptr_t>(*from));
1594514f5e3Sopenharmony_ci    }
1604514f5e3Sopenharmony_ci
1614514f5e3Sopenharmony_ci    static inline ecmascript::JSHandle<ecmascript::JSTaggedValue> ToJSHandle(Local<JSValueRef> from)
1624514f5e3Sopenharmony_ci    {
1634514f5e3Sopenharmony_ci        ASSERT(!from.IsEmpty());
1644514f5e3Sopenharmony_ci        return ecmascript::JSHandle<ecmascript::JSTaggedValue>(reinterpret_cast<uintptr_t>(*from));
1654514f5e3Sopenharmony_ci    }
1664514f5e3Sopenharmony_ci
1674514f5e3Sopenharmony_ci    static inline ecmascript::JSHandle<ecmascript::JSTaggedValue> ToJSHandle(JSValueRef *from)
1684514f5e3Sopenharmony_ci    {
1694514f5e3Sopenharmony_ci        ASSERT(from != nullptr);
1704514f5e3Sopenharmony_ci        return ecmascript::JSHandle<ecmascript::JSTaggedValue>(reinterpret_cast<uintptr_t>(from));
1714514f5e3Sopenharmony_ci    }
1724514f5e3Sopenharmony_ci};
1734514f5e3Sopenharmony_ci
1744514f5e3Sopenharmony_ciclass NativeReferenceHelper {
1754514f5e3Sopenharmony_cipublic:
1764514f5e3Sopenharmony_ci    NativeReferenceHelper(EcmaVM *vm, Global<ObjectRef> obj, NativeFinalize callback)
1774514f5e3Sopenharmony_ci        :  vm_(vm), obj_(obj), callback_(callback) {}
1784514f5e3Sopenharmony_ci    ~NativeReferenceHelper()
1794514f5e3Sopenharmony_ci    {
1804514f5e3Sopenharmony_ci        obj_.FreeGlobalHandleAddr();
1814514f5e3Sopenharmony_ci    }
1824514f5e3Sopenharmony_ci    static void FreeGlobalCallBack(void* ref)
1834514f5e3Sopenharmony_ci    {
1844514f5e3Sopenharmony_ci        auto that = reinterpret_cast<NativeReferenceHelper*>(ref);
1854514f5e3Sopenharmony_ci        that->obj_.FreeGlobalHandleAddr();
1864514f5e3Sopenharmony_ci    }
1874514f5e3Sopenharmony_ci
1884514f5e3Sopenharmony_ci    static void NativeFinalizeCallBack(void* ref)
1894514f5e3Sopenharmony_ci    {
1904514f5e3Sopenharmony_ci        auto that = reinterpret_cast<NativeReferenceHelper*>(ref);
1914514f5e3Sopenharmony_ci        if (that->callback_ != nullptr) {
1924514f5e3Sopenharmony_ci            that->callback_(that->vm_);
1934514f5e3Sopenharmony_ci        }
1944514f5e3Sopenharmony_ci        that->callback_ = nullptr;
1954514f5e3Sopenharmony_ci    }
1964514f5e3Sopenharmony_ci
1974514f5e3Sopenharmony_ci    void SetWeakCallback()
1984514f5e3Sopenharmony_ci    {
1994514f5e3Sopenharmony_ci        obj_.SetWeakCallback(this, FreeGlobalCallBack, NativeFinalizeCallBack);
2004514f5e3Sopenharmony_ci    }
2014514f5e3Sopenharmony_ci
2024514f5e3Sopenharmony_ciprivate:
2034514f5e3Sopenharmony_ci    EcmaVM *vm_;
2044514f5e3Sopenharmony_ci    Global<ObjectRef> obj_;
2054514f5e3Sopenharmony_ci    NativeFinalize callback_ = nullptr;
2064514f5e3Sopenharmony_ci};
2074514f5e3Sopenharmony_ci
2084514f5e3Sopenharmony_ciclass Callback {
2094514f5e3Sopenharmony_cipublic:
2104514f5e3Sopenharmony_ci    static ecmascript::JSTaggedValue RegisterCallback(ecmascript::EcmaRuntimeCallInfo *ecmaRuntimeCallInfo);
2114514f5e3Sopenharmony_ci};
2124514f5e3Sopenharmony_ci}  // namespace panda
2134514f5e3Sopenharmony_ci#endif  // ECMASCRIPT_NAPI_JSNAPI_HELPER_H
214