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 V(SharedFloat64Array) \ 127 V(SharedBigInt64Array) \ 128 V(SharedBigUint64Array) 129 130 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 131 #define EXCEPTION_ERROR_ALL(V) \ 132 V(Error, ERROR) \ 133 V(RangeError, RANGE_ERROR) \ 134 V(SyntaxError, SYNTAX_ERROR) \ 135 V(ReferenceError, REFERENCE_ERROR) \ 136 V(TypeError, TYPE_ERROR) \ 137 V(AggregateError, AGGREGATE_ERROR) \ 138 V(EvalError, EVAL_ERROR) \ 139 V(OOMError, OOM_ERROR) \ 140 V(TerminationError, TERMINATION_ERROR) 141 142 namespace panda { 143 using NativeFinalize = void (*)(EcmaVM *); 144 class JSNApiHelper { 145 public: 146 template<typename T> ToLocal(ecmascript::JSHandle<ecmascript::JSTaggedValue> from)147 static inline Local<T> ToLocal(ecmascript::JSHandle<ecmascript::JSTaggedValue> from) 148 { 149 return Local<T>(from.GetAddress()); 150 } 151 ToJSTaggedValue(JSValueRef * from)152 static inline ecmascript::JSTaggedValue ToJSTaggedValue(JSValueRef *from) 153 { 154 ASSERT(from != nullptr); 155 return *reinterpret_cast<ecmascript::JSTaggedValue *>(from); 156 } 157 ToJSMutableHandle(Local<JSValueRef> from)158 static inline ecmascript::JSMutableHandle<ecmascript::JSTaggedValue> ToJSMutableHandle(Local<JSValueRef> from) 159 { 160 ASSERT(!from.IsEmpty()); 161 return ecmascript::JSMutableHandle<ecmascript::JSTaggedValue>(reinterpret_cast<uintptr_t>(*from)); 162 } 163 ToJSHandle(Local<JSValueRef> from)164 static inline ecmascript::JSHandle<ecmascript::JSTaggedValue> ToJSHandle(Local<JSValueRef> from) 165 { 166 ASSERT(!from.IsEmpty()); 167 return ecmascript::JSHandle<ecmascript::JSTaggedValue>(reinterpret_cast<uintptr_t>(*from)); 168 } 169 ToJSHandle(JSValueRef * from)170 static inline ecmascript::JSHandle<ecmascript::JSTaggedValue> ToJSHandle(JSValueRef *from) 171 { 172 ASSERT(from != nullptr); 173 return ecmascript::JSHandle<ecmascript::JSTaggedValue>(reinterpret_cast<uintptr_t>(from)); 174 } 175 }; 176 177 class NativeReferenceHelper { 178 public: NativeReferenceHelper(EcmaVM * vm,Global<ObjectRef> obj,NativeFinalize callback)179 NativeReferenceHelper(EcmaVM *vm, Global<ObjectRef> obj, NativeFinalize callback) 180 : vm_(vm), obj_(obj), callback_(callback) {} ~NativeReferenceHelper()181 ~NativeReferenceHelper() 182 { 183 obj_.FreeGlobalHandleAddr(); 184 } FreeGlobalCallBack(void * ref)185 static void FreeGlobalCallBack(void* ref) 186 { 187 auto that = reinterpret_cast<NativeReferenceHelper*>(ref); 188 that->obj_.FreeGlobalHandleAddr(); 189 } 190 NativeFinalizeCallBack(void * ref)191 static void NativeFinalizeCallBack(void* ref) 192 { 193 auto that = reinterpret_cast<NativeReferenceHelper*>(ref); 194 if (that->callback_ != nullptr) { 195 that->callback_(that->vm_); 196 } 197 that->callback_ = nullptr; 198 } 199 SetWeakCallback()200 void SetWeakCallback() 201 { 202 obj_.SetWeakCallback(this, FreeGlobalCallBack, NativeFinalizeCallBack); 203 } 204 205 private: 206 EcmaVM *vm_; 207 Global<ObjectRef> obj_; 208 NativeFinalize callback_ = nullptr; 209 }; 210 211 class Callback { 212 public: 213 static ecmascript::JSTaggedValue RegisterCallback(ecmascript::EcmaRuntimeCallInfo *ecmaRuntimeCallInfo); 214 }; 215 } // namespace panda 216 #endif // ECMASCRIPT_NAPI_JSNAPI_HELPER_H 217