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 
139 namespace panda {
140 using NativeFinalize = void (*)(EcmaVM *);
141 class JSNApiHelper {
142 public:
143     template<typename T>
ToLocal(ecmascript::JSHandle<ecmascript::JSTaggedValue> from)144     static inline Local<T> ToLocal(ecmascript::JSHandle<ecmascript::JSTaggedValue> from)
145     {
146         return Local<T>(from.GetAddress());
147     }
148 
ToJSTaggedValue(JSValueRef *from)149     static inline ecmascript::JSTaggedValue ToJSTaggedValue(JSValueRef *from)
150     {
151         ASSERT(from != nullptr);
152         return *reinterpret_cast<ecmascript::JSTaggedValue *>(from);
153     }
154 
ToJSMutableHandle(Local<JSValueRef> from)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 
ToJSHandle(Local<JSValueRef> from)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 
ToJSHandle(JSValueRef *from)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 
174 class NativeReferenceHelper {
175 public:
NativeReferenceHelper(EcmaVM *vm, Global<ObjectRef> obj, NativeFinalize callback)176     NativeReferenceHelper(EcmaVM *vm, Global<ObjectRef> obj, NativeFinalize callback)
177         :  vm_(vm), obj_(obj), callback_(callback) {}
~NativeReferenceHelper()178     ~NativeReferenceHelper()
179     {
180         obj_.FreeGlobalHandleAddr();
181     }
FreeGlobalCallBack(void* ref)182     static void FreeGlobalCallBack(void* ref)
183     {
184         auto that = reinterpret_cast<NativeReferenceHelper*>(ref);
185         that->obj_.FreeGlobalHandleAddr();
186     }
187 
NativeFinalizeCallBack(void* ref)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 
SetWeakCallback()197     void SetWeakCallback()
198     {
199         obj_.SetWeakCallback(this, FreeGlobalCallBack, NativeFinalizeCallBack);
200     }
201 
202 private:
203     EcmaVM *vm_;
204     Global<ObjectRef> obj_;
205     NativeFinalize callback_ = nullptr;
206 };
207 
208 class Callback {
209 public:
210     static ecmascript::JSTaggedValue RegisterCallback(ecmascript::EcmaRuntimeCallInfo *ecmaRuntimeCallInfo);
211 };
212 }  // namespace panda
213 #endif  // ECMASCRIPT_NAPI_JSNAPI_HELPER_H
214