1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef ECMASCRIPT_NAPI_JSNAPI_HELPER_H
17#define ECMASCRIPT_NAPI_JSNAPI_HELPER_H
18
19#include "ecmascript/ecma_runtime_call_info.h"
20#include "ecmascript/js_handle.h"
21#include "ecmascript/js_tagged_value.h"
22#include "ecmascript/napi/include/jsnapi.h"
23
24// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
25#define RETURN_VALUE_IF_ABRUPT(thread, value)                 \
26    do {                                                      \
27        if (thread->HasPendingException()) {                  \
28            LOG_FULL(ERROR) << "occur exception need return"; \
29            return value;                                     \
30        }                                                     \
31    } while (false)
32
33#if ECMASCRIPT_ENABLE_NAPI_SPECIAL_CHECK
34#define LOG_IF_SPECIAL(handleValue, level)                                                       \
35    do {                                                                                         \
36        LOG_ECMA(DEBUG) << "Enable napi special check";                                           \
37        if ((handleValue).GetTaggedValue().IsSpecial()) {                                        \
38            LOG_FULL(level) << "Special value " << (handleValue).GetTaggedType() << " checked!"; \
39        }                                                                                        \
40    } while (false)
41#else
42#define LOG_IF_SPECIAL(handleValue, level) static_cast<void>(0)
43#endif
44
45#define CROSS_THREAD_CHECK(vm)                                                                  \
46    [[maybe_unused]] JSThread *thread = (vm)->GetJSThread()
47
48#define CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, returnVal)                              \
49    CROSS_THREAD_CHECK(vm);                                                                      \
50    do {                                                                                         \
51        if (thread->HasPendingException()) {                                                     \
52            LOG_ECMA(ERROR) << "Pending exception before " << __FUNCTION__ << " called in line:" \
53                            << __LINE__ << ", exception details as follows:";                    \
54            JSNApi::PrintExceptionInfo(vm);                                                      \
55            return returnVal;                                                                    \
56        }                                                                                        \
57    } while (false)
58
59#define CROSS_THREAD_AND_EXCEPTION_CHECK(vm)                                                      \
60    CROSS_THREAD_CHECK(vm);                                                                       \
61    do {                                                                                          \
62        if (thread->HasPendingException()) {                                                      \
63            LOG_ECMA(ERROR) << "Pending exception before " << __FUNCTION__ << " called, in line:" \
64                            << __LINE__ << ", exception details as follows:";                     \
65            JSNApi::PrintExceptionInfo(vm);                                                       \
66            return;                                                                               \
67        }                                                                                         \
68    } while (false)
69
70#define SINGLE_THREAD_CHECK_WITH_RETURN(vm, result)                                              \
71    [[maybe_unused]] JSThread *thread = (vm)->GetJSThreadNoCheck();                              \
72    do {                                                                                         \
73        if (thread->HasPendingException()) {                                                     \
74            LOG_ECMA(DEBUG) << "Pending exception before " << __FUNCTION__ << " called in line:" \
75                            << __LINE__ << ", exception details as follows:";                    \
76            JSNApi::PrintExceptionInfo(vm);                                                      \
77            return result;                                                                       \
78        }                                                                                        \
79        if (!(vm)->CheckSingleThread()) {                                                        \
80            LOG_ECMA(DEBUG) << "cross thread to call " << __FUNCTION__ << "is not supported";    \
81            return result;                                                                       \
82        }                                                                                        \
83    } while (false)
84
85#define DCHECK_SPECIAL_VALUE(jsValueRef)                                                     \
86    do {                                                                                     \
87        auto val = reinterpret_cast<JSTaggedValue *>(jsValueRef);                            \
88        if (UNLIKELY(val->IsSpecial())) {                                                    \
89            LOG_FULL(ERROR) << "JSNApi special value:0x" << val->GetRawData() << " checked"; \
90            return;                                                                          \
91        }                                                                                    \
92    } while (false)
93
94#define DCHECK_SPECIAL_VALUE_WITH_RETURN(jsValueRef, retValue)                               \
95    do {                                                                                     \
96        auto val = reinterpret_cast<JSTaggedValue *>(jsValueRef);                            \
97        if (UNLIKELY(val->IsSpecial())) {                                                    \
98            LOG_FULL(ERROR) << "JSNApi special value:0x" << val->GetRawData() << " checked"; \
99            return (retValue);                                                               \
100        }                                                                                    \
101    } while (false)
102
103// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
104#define TYPED_ARRAY_ALL(V) \
105    V(Int8Array)           \
106    V(Uint8Array)          \
107    V(Uint8ClampedArray)   \
108    V(Int16Array)          \
109    V(Uint16Array)         \
110    V(Int32Array)          \
111    V(Uint32Array)         \
112    V(Float32Array)        \
113    V(Float64Array)        \
114    V(BigInt64Array)       \
115    V(BigUint64Array)
116
117#define SENDABLE_TYPED_ARRAY_ALL(V) \
118    V(SharedInt8Array)     \
119    V(SharedUint8Array)    \
120    V(SharedInt16Array)    \
121    V(SharedUint16Array)   \
122    V(SharedInt32Array)    \
123    V(SharedUint32Array)   \
124    V(SharedUint8ClampedArray)   \
125    V(SharedFloat32Array)
126
127// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
128#define EXCEPTION_ERROR_ALL(V)         \
129    V(Error, ERROR)                    \
130    V(RangeError, RANGE_ERROR)         \
131    V(SyntaxError, SYNTAX_ERROR)       \
132    V(ReferenceError, REFERENCE_ERROR) \
133    V(TypeError, TYPE_ERROR)           \
134    V(AggregateError, AGGREGATE_ERROR) \
135    V(EvalError, EVAL_ERROR)           \
136    V(OOMError, OOM_ERROR)             \
137    V(TerminationError, TERMINATION_ERROR)
138
139namespace panda {
140using NativeFinalize = void (*)(EcmaVM *);
141class JSNApiHelper {
142public:
143    template<typename T>
144    static inline Local<T> ToLocal(ecmascript::JSHandle<ecmascript::JSTaggedValue> from)
145    {
146        return Local<T>(from.GetAddress());
147    }
148
149    static inline ecmascript::JSTaggedValue ToJSTaggedValue(JSValueRef *from)
150    {
151        ASSERT(from != nullptr);
152        return *reinterpret_cast<ecmascript::JSTaggedValue *>(from);
153    }
154
155    static inline ecmascript::JSMutableHandle<ecmascript::JSTaggedValue> ToJSMutableHandle(Local<JSValueRef> from)
156    {
157        ASSERT(!from.IsEmpty());
158        return ecmascript::JSMutableHandle<ecmascript::JSTaggedValue>(reinterpret_cast<uintptr_t>(*from));
159    }
160
161    static inline ecmascript::JSHandle<ecmascript::JSTaggedValue> ToJSHandle(Local<JSValueRef> from)
162    {
163        ASSERT(!from.IsEmpty());
164        return ecmascript::JSHandle<ecmascript::JSTaggedValue>(reinterpret_cast<uintptr_t>(*from));
165    }
166
167    static inline ecmascript::JSHandle<ecmascript::JSTaggedValue> ToJSHandle(JSValueRef *from)
168    {
169        ASSERT(from != nullptr);
170        return ecmascript::JSHandle<ecmascript::JSTaggedValue>(reinterpret_cast<uintptr_t>(from));
171    }
172};
173
174class NativeReferenceHelper {
175public:
176    NativeReferenceHelper(EcmaVM *vm, Global<ObjectRef> obj, NativeFinalize callback)
177        :  vm_(vm), obj_(obj), callback_(callback) {}
178    ~NativeReferenceHelper()
179    {
180        obj_.FreeGlobalHandleAddr();
181    }
182    static void FreeGlobalCallBack(void* ref)
183    {
184        auto that = reinterpret_cast<NativeReferenceHelper*>(ref);
185        that->obj_.FreeGlobalHandleAddr();
186    }
187
188    static void NativeFinalizeCallBack(void* ref)
189    {
190        auto that = reinterpret_cast<NativeReferenceHelper*>(ref);
191        if (that->callback_ != nullptr) {
192            that->callback_(that->vm_);
193        }
194        that->callback_ = nullptr;
195    }
196
197    void SetWeakCallback()
198    {
199        obj_.SetWeakCallback(this, FreeGlobalCallBack, NativeFinalizeCallBack);
200    }
201
202private:
203    EcmaVM *vm_;
204    Global<ObjectRef> obj_;
205    NativeFinalize callback_ = nullptr;
206};
207
208class Callback {
209public:
210    static ecmascript::JSTaggedValue RegisterCallback(ecmascript::EcmaRuntimeCallInfo *ecmaRuntimeCallInfo);
211};
212}  // namespace panda
213#endif  // ECMASCRIPT_NAPI_JSNAPI_HELPER_H
214