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#include "frameworks/base/utils/string_utils.h" 17#include "frameworks/bridge/js_frontend/engine/jsi/ark_js_runtime.h" 18#include "frameworks/bridge/declarative_frontend/engine/jsi/jsi_ref.h" 19#include "frameworks/bridge/declarative_frontend/engine/jsi/jsi_types.h" 20 21namespace OHOS::Ace::Framework { 22 23template<typename T> 24JsiType<T>::JsiType(panda::Local<T> val) 25{ 26 if (!val.IsEmpty()) { 27 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 28 handle_ = panda::CopyableGlobal(runtime->GetEcmaVm(), val); 29 } 30} 31 32template<typename T> 33JsiType<T>::JsiType(const EcmaVM *vm, panda::Local<T> val) 34{ 35 if (!val.IsEmpty()) { 36 handle_ = panda::CopyableGlobal(vm, val); 37 } 38} 39 40template<typename T> 41template<typename S> 42JsiType<T>::JsiType(panda::Local<S> val) 43{ 44 if (!val.IsEmpty()) { 45 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 46 handle_ = panda::CopyableGlobal(runtime->GetEcmaVm(), val); 47 } 48} 49 50template<typename T> 51JsiType<T>::JsiType(const panda::CopyableGlobal<T>& other) : handle_(other) 52{ 53} 54 55template<typename T> 56JsiType<T>::JsiType(const JsiType<T>& rhs) : handle_(rhs.handle_) 57{ 58} 59 60template<typename T> 61JsiType<T>::JsiType(JsiType<T>&& rhs) : handle_(std::move(rhs.handle_)) 62{ 63} 64 65template<typename T> 66JsiType<T>& JsiType<T>::operator=(const JsiType<T>& rhs) 67{ 68 handle_ = rhs.handle_; 69 return *this; 70} 71 72template<typename T> 73JsiType<T>& JsiType<T>::operator=(JsiType<T>&& rhs) 74{ 75 handle_ = std::move(rhs.handle_); 76 return *this; 77} 78 79template<typename T> 80void JsiType<T>::SetWeakCallback(void *ref, panda::WeakRefClearCallBack callback) 81{ 82 if (!handle_.IsEmpty()) { 83 handle_.SetWeakCallback(ref, callback, nullptr); 84 } 85} 86 87template<typename T> 88const EcmaVM* JsiType<T>::GetEcmaVM() const 89{ 90 return handle_.GetEcmaVM(); 91} 92 93template<typename T> 94const panda::CopyableGlobal<T>& JsiType<T>::GetHandle() const 95{ 96 return handle_; 97} 98 99template<typename T> 100panda::Local<T> JsiType<T>::GetLocalHandle() const 101{ 102 return handle_.ToLocal(); 103} 104 105template<typename T> 106bool JsiType<T>::IsEmpty() const 107{ 108 return handle_.IsEmpty(); 109} 110 111template<typename T> 112bool JsiType<T>::IsWeak() const 113{ 114 return handle_.IsWeak(); 115} 116 117template<typename T> 118void JsiType<T>::Reset() 119{ 120 handle_.Reset(); 121} 122 123template<typename T> 124const panda::CopyableGlobal<T>& JsiType<T>::operator->() const 125{ 126 return handle_; 127} 128 129template<typename T> 130JsiType<T>::operator panda::CopyableGlobal<T>() const 131{ 132 return handle_; 133} 134 135template<typename T> 136template<class... Args> 137JsiType<T> JsiType<T>::New(Args&&... args) 138{ 139 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 140 return JsiType<T>(T::New(runtime->GetEcmaVm(), std::forward<Args>(args)...)); 141} 142 143template<typename T> 144T JsiValue::ToNumber() const 145{ 146 if (ACE_UNLIKELY(SystemProperties::DetectJsObjTypeConvertion() && !IsNumber())) { 147 LOGF_ABORT("bad call to ToNumber."); 148 } 149 return JsiValueConvertor::fromJsiValue<T>(GetEcmaVM(), GetLocalHandle()); 150} 151 152template<typename T> 153T* JsiObject::Unwrap() const 154{ 155 if (GetHandle()->GetNativePointerFieldCount(GetEcmaVM()) < 1) { 156 return nullptr; 157 } 158 return static_cast<T*>(GetHandle()->GetNativePointerField(GetEcmaVM(), INSTANCE)); 159} 160 161template<typename T> 162void JsiObject::Wrap(T* data) const 163{ 164 GetHandle()->SetNativePointerField(GetEcmaVM(), INSTANCE, static_cast<void*>(data)); 165} 166 167template<typename T> 168void JsiObject::SetProperty(const char* prop, T value) const 169{ 170 auto stringRef = panda::StringRef::NewFromUtf8(GetEcmaVM(), prop); 171 GetHandle()->Set(GetEcmaVM(), stringRef, JsiValueConvertor::toJsiValueWithVM<T>(GetEcmaVM(), value)); 172} 173 174template<typename T> 175void JsiObject::SetProperty(int32_t propertyIndex, T value) const 176{ 177 Local<StringRef> stringRef = panda::ExternalStringCache::GetCachedString(GetEcmaVM(), propertyIndex); 178 GetHandle()->Set(GetEcmaVM(), stringRef, JsiValueConvertor::toJsiValueWithVM<T>(GetEcmaVM(), value)); 179} 180 181template<typename T> 182T JsiObject::GetPropertyValue(const char* prop, T defaultValue) const 183{ 184 static_assert(!std::is_const_v<T> && !std::is_reference_v<T>, 185 "Cannot convert value to reference or cv-qualified types!"); 186 187 const EcmaVM* vm = GetEcmaVM(); 188 Local<StringRef> stringRef = panda::StringRef::NewFromUtf8(vm, prop); 189 Local<JSValueRef> valueRef = GetHandle()->Get(vm, stringRef); 190 if constexpr (std::is_same<T, bool>::value) { 191 return valueRef->IsBoolean() ? valueRef->BooleaValue(vm) : defaultValue; 192 } else if constexpr (std::is_arithmetic<T>::value) { 193 return valueRef->IsNumber() ? JsiValueConvertor::fromJsiValue<T>(vm, valueRef) : defaultValue; 194 } else if constexpr (std::is_same_v<T, std::string>) { 195 return valueRef->IsString(vm) ? valueRef->ToString(vm)->ToString(vm) : defaultValue; 196 } else { 197 LOGW("Get property value failed."); 198 } 199 return defaultValue; 200} 201 202template<typename T> 203T JsiObject::GetPropertyValue(int32_t propertyIndex, T defaultValue) const 204{ 205 static_assert(!std::is_const_v<T> && !std::is_reference_v<T>, 206 "Cannot convert value to reference or cv-qualified types!"); 207 208 const EcmaVM* vm = GetEcmaVM(); 209 Local<StringRef> stringRef = panda::ExternalStringCache::GetCachedString(vm, propertyIndex); 210 Local<JSValueRef> valueRef = GetHandle()->Get(vm, stringRef); 211 if constexpr (std::is_same<T, bool>::value) { 212 return valueRef->IsBoolean() ? valueRef->BooleaValue(vm) : defaultValue; 213 } else if constexpr (std::is_arithmetic<T>::value) { 214 return valueRef->IsNumber() ? JsiValueConvertor::fromJsiValue<T>(vm, valueRef) : defaultValue; 215 } else if constexpr (std::is_same_v<T, std::string>) { 216 return valueRef->IsString(vm) ? valueRef->ToString(vm)->ToString(vm) : defaultValue; 217 } else { 218 LOGW("Get property value failed."); 219 } 220 return defaultValue; 221} 222 223template<typename T> 224void JsiCallbackInfo::SetReturnValue(T* instance) const 225{ 226 retVal_ = instance; 227} 228 229template<typename T> 230void JsiCallbackInfo::SetReturnValue(JsiRef<T> val) const 231{ 232 retVal_ = panda::CopyableGlobal<panda::JSValueRef>(val.Get().GetHandle()); 233} 234 235template<typename T> 236T* JsiCallbackInfo::UnwrapArg(size_t index) const 237{ 238 auto arg = info_->GetCallArgRef(index); 239 if (arg.IsEmpty() || !arg->IsObject(info_->GetVM())) { 240 return nullptr; 241 } 242 return static_cast<T*>(arg->ToEcmaObject(info_->GetVM())->GetNativePointerField(info_->GetVM(), 0)); 243} 244 245template<typename... Args> 246void JsiException::Throw(const char* format, Args... args) 247{ 248 const std::string str = StringUtils::FormatString(format, args...); 249 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 250 auto vm = runtime->GetEcmaVm(); 251 panda::JSNApi::ThrowException(vm, panda::Exception::Error(vm, panda::StringRef::NewFromUtf8(vm, str.c_str()))); 252} 253 254template<typename... Args> 255void JsiException::Throw(int32_t code, const char* format, Args... args) 256{ 257 const std::string str = StringUtils::FormatString(format, args...); 258 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 259 auto vm = runtime->GetEcmaVm(); 260 LocalScope scope(vm); 261 Local<JSValueRef> error(JSValueRef::Undefined(vm)); 262 error = panda::Exception::Error(vm, StringRef::NewFromUtf8(vm, str.c_str())); 263 Local<JSValueRef> codeKey = StringRef::NewFromUtf8(vm, "code"); 264 Local<JSValueRef> codeValue = StringRef::NewFromUtf8(vm, std::to_string(code).c_str()); 265 Local<ObjectRef> errorObj(error); 266 errorObj->Set(vm, codeKey, codeValue); 267 panda::JSNApi::ThrowException(vm, error); 268} 269 270template<typename... Args> 271void JsiException::ThrowRangeError(const char* format, Args... args) 272{ 273 const std::string str = StringUtils::FormatString(format, args...); 274 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 275 auto vm = runtime->GetEcmaVm(); 276 panda::JSNApi::ThrowException(vm, panda::Exception::RangeError(vm, panda::StringRef::NewFromUtf8(vm, str.c_str()))); 277} 278 279template<typename... Args> 280void JsiException::ThrowReferenceError(const char* format, Args... args) 281{ 282 const std::string str = StringUtils::FormatString(format, args...); 283 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 284 auto vm = runtime->GetEcmaVm(); 285 panda::JSNApi::ThrowException( 286 vm, panda::Exception::ReferenceError(vm, panda::StringRef::NewFromUtf8(vm, str.c_str()))); 287} 288 289template<typename... Args> 290void JsiException::ThrowSyntaxError(const char* format, Args... args) 291{ 292 const std::string str = StringUtils::FormatString(format, args...); 293 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 294 auto vm = runtime->GetEcmaVm(); 295 panda::JSNApi::ThrowException( 296 vm, panda::Exception::SyntaxError(vm, panda::StringRef::NewFromUtf8(vm, str.c_str()))); 297} 298 299template<typename... Args> 300void JsiException::ThrowTypeError(const char* format, Args... args) 301{ 302 const std::string str = StringUtils::FormatString(format, args...); 303 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 304 auto vm = runtime->GetEcmaVm(); 305 panda::JSNApi::ThrowException(vm, panda::Exception::TypeError(vm, panda::StringRef::NewFromUtf8(vm, str.c_str()))); 306} 307 308template<typename... Args> 309void JsiException::ThrowEvalError(const char* format, Args... args) 310{ 311 const std::string str = StringUtils::FormatString(format, args...); 312 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 313 auto vm = runtime->GetEcmaVm(); 314 panda::JSNApi::ThrowException(vm, panda::Exception::EvalError(vm, panda::StringRef::NewFromUtf8(vm, str.c_str()))); 315} 316} // namespace OHOS::Ace::Framework 317