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