1#include <string.h> 2#include <unistd.h> 3#include <algorithm> 4#include <atomic> 5#include <climits> // INT_MAX 6#include <cmath> 7#include "v8-debug.h" 8#include "v8-internal.h" 9#include "v8-local-handle.h" 10#include "v8-primitive.h" 11#include "v8-statistics.h" 12#include "v8-version-string.h" 13#define JSVM_EXPERIMENTAL 14#include "env-inl.h" 15#include "jsvm.h" 16#include "js_native_api_v8.h" 17#include "js_native_api_v8_inspector.h" 18#include "libplatform/libplatform.h" 19#include "util-inl.h" 20#include "util.h" 21#include "sourcemap.def" 22 23#ifdef ENABLE_HISYSEVENT 24#include "hisysevent.h" 25#endif 26 27#define SECARGCNT 2 28 29#define CHECK_MAYBE_NOTHING(env, maybe, status) \ 30 RETURN_STATUS_IF_FALSE((env), !((maybe).IsNothing()), (status)) 31 32#define CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe, status) \ 33 RETURN_STATUS_IF_FALSE_WITH_PREAMBLE((env), !((maybe).IsNothing()), (status)) 34 35#define CHECK_TO_NUMBER(env, context, result, src) \ 36 CHECK_TO_TYPE((env), Number, (context), (result), (src), JSVM_NUMBER_EXPECTED) 37 38// n-api defines JSVM_AUTO_LENGTH as the indicator that a string 39// is null terminated. For V8 the equivalent is -1. The assert 40// validates that our cast of JSVM_AUTO_LENGTH results in -1 as 41// needed by V8. 42#define CHECK_NEW_FROM_UTF8_LEN(env, result, str, len) \ 43 do { \ 44 static_assert(static_cast<int>(JSVM_AUTO_LENGTH) == -1, \ 45 "Casting JSVM_AUTO_LENGTH to int must result in -1"); \ 46 RETURN_STATUS_IF_FALSE( \ 47 (env), (len == JSVM_AUTO_LENGTH) || len <= INT_MAX, JSVM_INVALID_ARG); \ 48 RETURN_STATUS_IF_FALSE((env), (str) != nullptr, JSVM_INVALID_ARG); \ 49 auto str_maybe = v8::String::NewFromUtf8((env)->isolate, \ 50 (str), \ 51 v8::NewStringType::kInternalized, \ 52 static_cast<int>(len)); \ 53 CHECK_MAYBE_EMPTY((env), str_maybe, JSVM_GENERIC_FAILURE); \ 54 (result) = str_maybe.ToLocalChecked(); \ 55 } while (0) 56 57#define CHECK_NEW_FROM_UTF8(env, result, str) \ 58 CHECK_NEW_FROM_UTF8_LEN((env), (result), (str), JSVM_AUTO_LENGTH) 59 60#define CHECK_NEW_STRING_ARGS(env, str, length, result) \ 61 do { \ 62 CHECK_ENV_NOT_IN_GC((env)); \ 63 if ((length) > 0) CHECK_ARG((env), (str)); \ 64 CHECK_ARG((env), (result)); \ 65 RETURN_STATUS_IF_FALSE( \ 66 (env), \ 67 ((length) == JSVM_AUTO_LENGTH) || (length) <= INT_MAX, \ 68 JSVM_INVALID_ARG); \ 69 } while (0) 70 71#define CREATE_TYPED_ARRAY( \ 72 env, type, size_of_element, buffer, byteOffset, length, out) \ 73 do { \ 74 if ((size_of_element) > 1) { \ 75 THROW_RANGE_ERROR_IF_FALSE( \ 76 (env), \ 77 (byteOffset) % (size_of_element) == 0, \ 78 "ERR_JSVM_INVALID_TYPEDARRAY_ALIGNMENT", \ 79 "start offset of " #type \ 80 " should be a multiple of " #size_of_element); \ 81 } \ 82 THROW_RANGE_ERROR_IF_FALSE( \ 83 (env), \ 84 (length) * (size_of_element) + (byteOffset) <= buffer->ByteLength(), \ 85 "ERR_JSVM_INVALID_TYPEDARRAY_LENGTH", \ 86 "Invalid typed array length"); \ 87 (out) = v8::type::New((buffer), (byteOffset), (length)); \ 88 } while (0) 89 90JSVM_Env__::JSVM_Env__(v8::Isolate* isolate, int32_t module_api_version) 91 : isolate(isolate), module_api_version(module_api_version) { 92 inspector_agent_ = new v8impl::Agent(this); 93 jsvm_clear_last_error(this); 94} 95 96void JSVM_Env__::DeleteMe() { 97 // First we must finalize those references that have `napi_finalizer` 98 // callbacks. The reason is that addons might store other references which 99 // they delete during their `napi_finalizer` callbacks. If we deleted such 100 // references here first, they would be doubly deleted when the 101 // `napi_finalizer` deleted them subsequently. 102 v8impl::RefTracker::FinalizeAll(&finalizing_reflist); 103 v8impl::RefTracker::FinalizeAll(&reflist); 104 { 105 v8::Context::Scope context_scope(context()); 106 if (inspector_agent_->IsActive()) { 107 inspector_agent_->WaitForDisconnect(); 108 } 109 delete inspector_agent_; 110 } 111 delete this; 112} 113 114void JSVM_Env__::RunAndClearInterrupts() { 115 while (native_immediates_interrupts_.size() > 0) { 116 NativeImmediateQueue queue; 117 { 118 node::Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_); 119 queue.ConcatMove(std::move(native_immediates_interrupts_)); 120 } 121 node::DebugSealHandleScope seal_handle_scope(isolate); 122 123 while (auto head = queue.Shift()) 124 head->Call(this); 125 } 126} 127 128void JSVM_Env__::InvokeFinalizerFromGC(v8impl::RefTracker* finalizer) { 129 // The experimental code calls finalizers immediately to release native 130 // objects as soon as possible. In that state any code that may affect GC 131 // state causes a fatal error. To work around this issue the finalizer code 132 // can call node_api_post_finalizer. 133 auto restore_state = node::OnScopeLeave( 134 [this, saved = in_gc_finalizer] { in_gc_finalizer = saved; }); 135 in_gc_finalizer = true; 136 finalizer->Finalize(); 137} 138 139namespace v8impl { 140 141namespace { 142 143enum IsolateDataSlot { 144 kIsolateData = 0, 145 kIsolateSnapshotCreatorSlot = 1, 146}; 147 148enum ContextEmbedderIndex { 149 kContextEnvIndex = 1, 150}; 151 152struct IsolateData { 153 IsolateData(v8::StartupData* blob) : blob(blob) {} 154 155 ~IsolateData() { 156 delete blob; 157 } 158 159 v8::StartupData* blob; 160 v8::Eternal<v8::Private> jsvm_type_tag_key; 161 v8::Eternal<v8::Private> jsvm_wrapper_key; 162}; 163 164static void CreateIsolateData(v8::Isolate* isolate, v8::StartupData* blob) { 165 auto data = new IsolateData(blob); 166 v8::Isolate::Scope isolate_scope(isolate); 167 v8::HandleScope handle_scope(isolate); 168 if (blob) { 169 // NOTE: The order of getting the data must be consistent with the order of 170 // adding data in OH_JSVM_CreateSnapshot. 171 auto wrapper_key = isolate->GetDataFromSnapshotOnce<v8::Private>(0); 172 auto type_tag_key = isolate->GetDataFromSnapshotOnce<v8::Private>(1); 173 data->jsvm_wrapper_key.Set(isolate, wrapper_key.ToLocalChecked()); 174 data->jsvm_type_tag_key.Set(isolate, type_tag_key.ToLocalChecked()); 175 } else { 176 data->jsvm_wrapper_key.Set(isolate, v8::Private::New(isolate)); 177 data->jsvm_type_tag_key.Set(isolate, v8::Private::New(isolate)); 178 } 179 isolate->SetData(v8impl::kIsolateData, data); 180} 181 182static IsolateData* GetIsolateData(v8::Isolate* isolate) { 183 auto data = isolate->GetData(v8impl::kIsolateData); 184 return reinterpret_cast<IsolateData*>(data); 185} 186 187static void SetIsolateSnapshotCreator(v8::Isolate* isolate, 188 v8::SnapshotCreator* creator) { 189 isolate->SetData(v8impl::kIsolateSnapshotCreatorSlot, creator); 190} 191 192static v8::SnapshotCreator* GetIsolateSnapshotCreator(v8::Isolate* isolate) { 193 auto data = isolate->GetData(v8impl::kIsolateSnapshotCreatorSlot); 194 return reinterpret_cast<v8::SnapshotCreator*>(data); 195} 196 197static void SetContextEnv(v8::Local<v8::Context> context, JSVM_Env env) { 198 context->SetAlignedPointerInEmbedderData(kContextEnvIndex, env); 199} 200 201static JSVM_Env GetContextEnv(v8::Local<v8::Context> context) { 202 auto data = context->GetAlignedPointerFromEmbedderData(kContextEnvIndex); 203 return reinterpret_cast<JSVM_Env>(data); 204} 205 206class OutputStream : public v8::OutputStream { 207 public: 208 OutputStream(JSVM_OutputStream stream, void* data, int chunk_size = 65536) 209 : stream_(stream), stream_data_(data), chunk_size_(chunk_size) {} 210 211 int GetChunkSize() override { return chunk_size_; } 212 213 void EndOfStream() override { 214 stream_(nullptr, 0, stream_data_); 215 } 216 217 WriteResult WriteAsciiChunk(char* data, const int size) override { 218 return stream_(data, size, stream_data_) ? kContinue : kAbort; 219 } 220 221 private: 222 JSVM_OutputStream stream_; 223 void* stream_data_; 224 int chunk_size_; 225}; 226 227static std::unique_ptr<v8::Platform> g_platform = v8::platform::NewDefaultPlatform(); 228 229static std::vector<intptr_t> externalReferenceRegistry; 230 231static std::unordered_map<std::string, std::string> sourceMapUrlMap; 232 233static std::unique_ptr<v8::ArrayBuffer::Allocator> defaultArrayBufferAllocator; 234 235static v8::ArrayBuffer::Allocator *GetOrCreateDefaultArrayBufferAllocator() { 236 if (!defaultArrayBufferAllocator) { 237 defaultArrayBufferAllocator.reset(v8::ArrayBuffer::Allocator::NewDefaultAllocator()); 238 } 239 return defaultArrayBufferAllocator.get(); 240} 241 242static void SetFileToSourceMapMapping(std::string &&file, std::string &&sourceMapUrl) { 243 auto it = sourceMapUrlMap.find(file); 244 if (it == sourceMapUrlMap.end()) { 245 sourceMapUrlMap.emplace(file, sourceMapUrl); 246 return; 247 } 248 auto &&prevSourceMapUrl = it->second; 249 CHECK(prevSourceMapUrl == sourceMapUrl); 250} 251 252static std::string GetSourceMapFromFileName(std::string &&file) { 253 auto it = sourceMapUrlMap.find(file); 254 if (it != sourceMapUrlMap.end()) { 255 return it->second; 256 } 257 return ""; 258} 259 260template <typename CCharType, typename StringMaker> 261JSVM_Status NewString(JSVM_Env env, 262 const CCharType* str, 263 size_t length, 264 JSVM_Value* result, 265 StringMaker string_maker) { 266 CHECK_NEW_STRING_ARGS(env, str, length, result); 267 268 auto isolate = env->isolate; 269 auto str_maybe = string_maker(isolate); 270 CHECK_MAYBE_EMPTY(env, str_maybe, JSVM_GENERIC_FAILURE); 271 *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked()); 272 return jsvm_clear_last_error(env); 273} 274 275template <typename CharType, typename CreateAPI, typename StringMaker> 276JSVM_Status NewExternalString(JSVM_Env env, 277 CharType* str, 278 size_t length, 279 JSVM_Finalize finalizeCallback, 280 void* finalizeHint, 281 JSVM_Value* result, 282 bool* copied, 283 CreateAPI create_api, 284 StringMaker string_maker) { 285 CHECK_NEW_STRING_ARGS(env, str, length, result); 286 JSVM_Status status; 287#if defined(V8_ENABLE_SANDBOX) 288 status = create_api(env, str, length, result); 289 if (status == JSVM_OK) { 290 if (copied != nullptr) { 291 *copied = true; 292 } 293 if (finalizeCallback) { 294 env->CallFinalizer( 295 finalizeCallback, static_cast<CharType*>(str), finalizeHint); 296 } 297 } 298#else 299 status = NewString(env, str, length, result, string_maker); 300 if (status == JSVM_OK && copied != nullptr) { 301 *copied = false; 302 } 303#endif // V8_ENABLE_SANDBOX 304 return status; 305} 306 307class TrackedStringResource : public Finalizer, RefTracker { 308 public: 309 TrackedStringResource(JSVM_Env env, 310 JSVM_Finalize finalizeCallback, 311 void* data, 312 void* finalizeHint) 313 : Finalizer(env, finalizeCallback, data, finalizeHint) { 314 Link(finalizeCallback == nullptr ? &env->reflist 315 : &env->finalizing_reflist); 316 } 317 318 protected: 319 // The only time Finalize() gets called before Dispose() is if the 320 // environment is dying. Finalize() expects that the item will be unlinked, 321 // so we do it here. V8 will still call Dispose() on us later, so we don't do 322 // any deleting here. We just null out env_ to avoid passing a stale pointer 323 // to the user's finalizer when V8 does finally call Dispose(). 324 void Finalize() override { 325 Unlink(); 326 env_ = nullptr; 327 } 328 329 ~TrackedStringResource() { 330 if (finalize_callback_ == nullptr) return; 331 if (env_ == nullptr) { 332 // The environment is dead. Call the finalizer directly. 333 finalize_callback_(nullptr, finalize_data_, finalize_hint_); 334 } else { 335 // The environment is still alive. Let's remove ourselves from its list 336 // of references and call the user's finalizer. 337 Unlink(); 338 env_->CallFinalizer(finalize_callback_, finalize_data_, finalize_hint_); 339 } 340 } 341}; 342 343class ExternalOneByteStringResource 344 : public v8::String::ExternalOneByteStringResource, 345 TrackedStringResource { 346 public: 347 ExternalOneByteStringResource(JSVM_Env env, 348 char* string, 349 const size_t length, 350 JSVM_Finalize finalizeCallback, 351 void* finalizeHint) 352 : TrackedStringResource(env, finalizeCallback, string, finalizeHint), 353 string_(string), 354 length_(length) {} 355 356 const char* data() const override { return string_; } 357 size_t length() const override { return length_; } 358 359 private: 360 const char* string_; 361 const size_t length_; 362}; 363 364class ExternalStringResource : public v8::String::ExternalStringResource, 365 TrackedStringResource { 366 public: 367 ExternalStringResource(JSVM_Env env, 368 char16_t* string, 369 const size_t length, 370 JSVM_Finalize finalizeCallback, 371 void* finalizeHint) 372 : TrackedStringResource(env, finalizeCallback, string, finalizeHint), 373 string_(reinterpret_cast<uint16_t*>(string)), 374 length_(length) {} 375 376 const uint16_t* data() const override { return string_; } 377 size_t length() const override { return length_; } 378 379 private: 380 const uint16_t* string_; 381 const size_t length_; 382}; 383 384inline JSVM_Status V8NameFromPropertyDescriptor( 385 JSVM_Env env, 386 const JSVM_PropertyDescriptor* p, 387 v8::Local<v8::Name>* result) { 388 if (p->utf8name != nullptr) { 389 CHECK_NEW_FROM_UTF8(env, *result, p->utf8name); 390 } else { 391 v8::Local<v8::Value> property_value = 392 v8impl::V8LocalValueFromJsValue(p->name); 393 394 RETURN_STATUS_IF_FALSE(env, property_value->IsName(), JSVM_NAME_EXPECTED); 395 *result = property_value.As<v8::Name>(); 396 } 397 398 return JSVM_OK; 399} 400 401// convert from n-api property attributes to v8::PropertyAttribute 402inline v8::PropertyAttribute V8PropertyAttributesFromDescriptor( 403 const JSVM_PropertyDescriptor* descriptor) { 404 unsigned int attribute_flags = v8::PropertyAttribute::None; 405 406 // The JSVM_WRITABLE attribute is ignored for accessor descriptors, but 407 // V8 would throw `TypeError`s on assignment with nonexistence of a setter. 408 if ((descriptor->getter == nullptr && descriptor->setter == nullptr) && 409 (descriptor->attributes & JSVM_WRITABLE) == 0) { 410 attribute_flags |= v8::PropertyAttribute::ReadOnly; 411 } 412 413 if ((descriptor->attributes & JSVM_ENUMERABLE) == 0) { 414 attribute_flags |= v8::PropertyAttribute::DontEnum; 415 } 416 if ((descriptor->attributes & JSVM_CONFIGURABLE) == 0) { 417 attribute_flags |= v8::PropertyAttribute::DontDelete; 418 } 419 420 return static_cast<v8::PropertyAttribute>(attribute_flags); 421} 422 423inline JSVM_Deferred JsDeferredFromNodePersistent( 424 v8impl::Persistent<v8::Value>* local) { 425 return reinterpret_cast<JSVM_Deferred>(local); 426} 427 428inline v8impl::Persistent<v8::Value>* NodePersistentFromJsDeferred( 429 JSVM_Deferred local) { 430 return reinterpret_cast<v8impl::Persistent<v8::Value>*>(local); 431} 432 433class HandleScopeWrapper { 434 public: 435 explicit HandleScopeWrapper(v8::Isolate* isolate) : scope(isolate) {} 436 437 private: 438 v8::HandleScope scope; 439}; 440 441// In node v0.10 version of v8, there is no EscapableHandleScope and the 442// node v0.10 port use HandleScope::Close(Local<T> v) to mimic the behavior 443// of a EscapableHandleScope::Escape(Local<T> v), but it is not the same 444// semantics. This is an example of where the api abstraction fail to work 445// across different versions. 446class EscapableHandleScopeWrapper { 447 public: 448 explicit EscapableHandleScopeWrapper(v8::Isolate* isolate) 449 : scope(isolate), escape_called_(false) {} 450 bool escape_called() const { return escape_called_; } 451 template <typename T> 452 v8::Local<T> Escape(v8::Local<T> handle) { 453 escape_called_ = true; 454 return scope.Escape(handle); 455 } 456 457 private: 458 v8::EscapableHandleScope scope; 459 bool escape_called_; 460}; 461 462inline JSVM_HandleScope JsHandleScopeFromV8HandleScope(HandleScopeWrapper* s) { 463 return reinterpret_cast<JSVM_HandleScope>(s); 464} 465 466inline HandleScopeWrapper* V8HandleScopeFromJsHandleScope(JSVM_HandleScope s) { 467 return reinterpret_cast<HandleScopeWrapper*>(s); 468} 469 470inline JSVM_EscapableHandleScope 471JsEscapableHandleScopeFromV8EscapableHandleScope( 472 EscapableHandleScopeWrapper* s) { 473 return reinterpret_cast<JSVM_EscapableHandleScope>(s); 474} 475 476inline EscapableHandleScopeWrapper* 477V8EscapableHandleScopeFromJsEscapableHandleScope( 478 JSVM_EscapableHandleScope s) { 479 return reinterpret_cast<EscapableHandleScopeWrapper*>(s); 480} 481 482inline JSVM_Status ConcludeDeferred(JSVM_Env env, 483 JSVM_Deferred deferred, 484 JSVM_Value result, 485 bool is_resolved) { 486 JSVM_PREAMBLE(env); 487 CHECK_ARG(env, result); 488 489 v8::Local<v8::Context> context = env->context(); 490 v8impl::Persistent<v8::Value>* deferred_ref = 491 NodePersistentFromJsDeferred(deferred); 492 v8::Local<v8::Value> v8_deferred = 493 v8::Local<v8::Value>::New(env->isolate, *deferred_ref); 494 495 auto v8_resolver = v8_deferred.As<v8::Promise::Resolver>(); 496 497 v8::Maybe<bool> success = 498 is_resolved ? v8_resolver->Resolve( 499 context, v8impl::V8LocalValueFromJsValue(result)) 500 : v8_resolver->Reject( 501 context, v8impl::V8LocalValueFromJsValue(result)); 502 503 delete deferred_ref; 504 505 RETURN_STATUS_IF_FALSE(env, success.FromMaybe(false), JSVM_GENERIC_FAILURE); 506 507 return GET_RETURN_STATUS(env); 508} 509 510enum UnwrapAction { KeepWrap, RemoveWrap }; 511 512inline JSVM_Status Unwrap(JSVM_Env env, 513 JSVM_Value jsObject, 514 void** result, 515 UnwrapAction action) { 516 JSVM_PREAMBLE(env); 517 CHECK_ARG(env, jsObject); 518 if (action == KeepWrap) { 519 CHECK_ARG(env, result); 520 } 521 522 v8::Local<v8::Context> context = env->context(); 523 524 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(jsObject); 525 RETURN_STATUS_IF_FALSE(env, value->IsObject(), JSVM_INVALID_ARG); 526 v8::Local<v8::Object> obj = value.As<v8::Object>(); 527 528 auto val = obj->GetPrivate(context, JSVM_PRIVATE_KEY(env->isolate, wrapper)) 529 .ToLocalChecked(); 530 RETURN_STATUS_IF_FALSE(env, val->IsExternal(), JSVM_INVALID_ARG); 531 Reference* reference = 532 static_cast<v8impl::Reference*>(val.As<v8::External>()->Value()); 533 534 if (result) { 535 *result = reference->Data(); 536 } 537 538 if (action == RemoveWrap) { 539 CHECK(obj->DeletePrivate(context, JSVM_PRIVATE_KEY(env->isolate, wrapper)) 540 .FromJust()); 541 if (reference->ownership() == Ownership::kUserland) { 542 // When the wrap is been removed, the finalizer should be reset. 543 reference->ResetFinalizer(); 544 } else { 545 delete reference; 546 } 547 } 548 549 return GET_RETURN_STATUS(env); 550} 551 552//=== Function JSVM_Callback wrapper ================================= 553 554// Use this data structure to associate callback data with each N-API function 555// exposed to JavaScript. The structure is stored in a v8::External which gets 556// passed into our callback wrapper. This reduces the performance impact of 557// calling through N-API. 558// Ref: benchmark/misc/function_call 559// Discussion (incl. perf. data): https://github.com/nodejs/node/pull/21072 560class CallbackBundle { 561 public: 562 // Creates an object to be made available to the static function callback 563 // wrapper, used to retrieve the native callback function and data pointer. 564 static inline v8::Local<v8::Value> New(JSVM_Env env, 565 JSVM_Callback cb) { 566 return v8::External::New(env->isolate, cb); 567 } 568 569 static inline v8::Local<v8::Value> New(JSVM_Env env, 570 v8impl::JSVM_PropertyHandlerCfgStruct* cb) { 571 return v8::External::New(env->isolate, cb); 572 } 573}; 574 575// Base class extended by classes that wrap V8 function and property callback 576// info. 577class CallbackWrapper { 578 public: 579 inline CallbackWrapper(JSVM_Value thisArg, size_t args_length, void* data) 580 : _this(thisArg), _args_length(args_length), _data(data) {} 581 582 virtual JSVM_Value GetNewTarget() { 583 return nullptr; 584 }; 585 virtual void Args(JSVM_Value* buffer, size_t bufferlength) {}; 586 virtual void SetReturnValue(JSVM_Value value) = 0; 587 588 JSVM_Value This() { return _this; } 589 590 size_t ArgsLength() { return _args_length; } 591 592 void* Data() { return _data; } 593 594 protected: 595 const JSVM_Value _this; 596 const size_t _args_length; 597 void* _data; 598}; 599 600class CallbackWrapperBase : public CallbackWrapper { 601 public: 602 inline CallbackWrapperBase(const v8::FunctionCallbackInfo<v8::Value>& cbinfo, 603 const size_t args_length) 604 : CallbackWrapper( 605 JsValueFromV8LocalValue(cbinfo.This()), args_length, nullptr), 606 _cbinfo(cbinfo) { 607 _cb = (JSVM_Callback)cbinfo.Data().As<v8::External>()->Value(); 608 _data = _cb->data; 609 } 610 611 protected: 612 inline void InvokeCallback() { 613 JSVM_CallbackInfo cbinfo_wrapper = reinterpret_cast<JSVM_CallbackInfo>( 614 static_cast<CallbackWrapper*>(this)); 615 616 // All other pointers we need are stored in `_bundle` 617 auto context = _cbinfo.GetIsolate()->GetCurrentContext(); 618 auto env = v8impl::GetContextEnv(context); 619 auto cb = _cb->callback; 620 621 JSVM_Value result = nullptr; 622 bool exceptionOccurred = false; 623 env->CallIntoModule([&](JSVM_Env env) { result = cb(env, cbinfo_wrapper); }, 624 [&](JSVM_Env env, v8::Local<v8::Value> value) { 625 exceptionOccurred = true; 626 if (env->terminatedOrTerminating()) { 627 return; 628 } 629 env->isolate->ThrowException(value); 630 }); 631 632 if (!exceptionOccurred && (result != nullptr)) { 633 this->SetReturnValue(result); 634 } 635 } 636 637 const v8::FunctionCallbackInfo<v8::Value>& _cbinfo; 638 JSVM_Callback _cb; 639}; 640 641class FunctionCallbackWrapper : public CallbackWrapperBase { 642 public: 643 static void Invoke(const v8::FunctionCallbackInfo<v8::Value>& info) { 644 FunctionCallbackWrapper cbwrapper(info); 645 cbwrapper.InvokeCallback(); 646 } 647 648 static inline JSVM_Status NewFunction(JSVM_Env env, 649 JSVM_Callback cb, 650 v8::Local<v8::Function>* result) { 651 v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New(env, cb); 652 RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), JSVM_GENERIC_FAILURE); 653 654 v8::MaybeLocal<v8::Function> maybe_function = 655 v8::Function::New(env->context(), Invoke, cbdata); 656 CHECK_MAYBE_EMPTY(env, maybe_function, JSVM_GENERIC_FAILURE); 657 658 *result = maybe_function.ToLocalChecked(); 659 return jsvm_clear_last_error(env); 660 } 661 662 static inline JSVM_Status NewTemplate( 663 JSVM_Env env, 664 JSVM_Callback cb, 665 v8::Local<v8::FunctionTemplate>* result, 666 v8::Local<v8::Signature> sig = v8::Local<v8::Signature>()) { 667 v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New(env, cb); 668 RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), JSVM_GENERIC_FAILURE); 669 670 *result = v8::FunctionTemplate::New(env->isolate, Invoke, cbdata, sig); 671 return jsvm_clear_last_error(env); 672 } 673 674 explicit FunctionCallbackWrapper( 675 const v8::FunctionCallbackInfo<v8::Value>& cbinfo) 676 : CallbackWrapperBase(cbinfo, cbinfo.Length()) {} 677 678 JSVM_Value GetNewTarget() override { 679 if (_cbinfo.IsConstructCall()) { 680 return v8impl::JsValueFromV8LocalValue(_cbinfo.NewTarget()); 681 } else { 682 return nullptr; 683 } 684 } 685 686 /*virtual*/ 687 void Args(JSVM_Value* buffer, size_t buffer_length) override { 688 size_t i = 0; 689 size_t min = std::min(buffer_length, _args_length); 690 691 for (; i < min; i += 1) { 692 buffer[i] = v8impl::JsValueFromV8LocalValue(_cbinfo[i]); 693 } 694 695 if (i < buffer_length) { 696 JSVM_Value undefined = 697 v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate())); 698 for (; i < buffer_length; i += 1) { 699 buffer[i] = undefined; 700 } 701 } 702 } 703 704 /*virtual*/ 705 void SetReturnValue(JSVM_Value value) override { 706 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 707 _cbinfo.GetReturnValue().Set(val); 708 } 709}; 710 711template <typename T> 712class PropertyCallbackWrapperBase : public CallbackWrapper { 713 public: 714 inline PropertyCallbackWrapperBase(uint32_t index, v8::Local<v8::Name> property, v8::Local<v8::Value> value, 715 const v8::PropertyCallbackInfo<T>& cbinfo, const size_t args_length) 716 : CallbackWrapper( 717 JsValueFromV8LocalValue(cbinfo.This()), args_length, nullptr), 718 _cbinfo(cbinfo), _property(property), _value(value), _index(index) { 719 _cb = (v8impl::JSVM_PropertyHandlerCfgStruct *)_cbinfo.Data().template As<v8::External>()->Value(); 720 } 721 722 protected: 723 inline void NameSetterInvokeCallback() { 724 auto context = _cbinfo.GetIsolate()->GetCurrentContext(); 725 auto env = v8impl::GetContextEnv(context); 726 auto setterCb = _cb->namedSetterCallback_; 727 728 JSVM_Value innerData = nullptr; 729 if (_cb->namedPropertyData_ != nullptr) { 730 v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(_cb->namedPropertyData_); 731 innerData = v8impl::JsValueFromV8LocalValue(reference->Get()); 732 } 733 734 bool exceptionOccurred = false; 735 JSVM_Value result = nullptr; 736 JSVM_Value name = JsValueFromV8LocalValue(_property); 737 JSVM_Value value = JsValueFromV8LocalValue(_value); 738 JSVM_Value thisArg = this->This(); 739 env->CallIntoModule([&](JSVM_Env env) { 740 if (setterCb) { 741 result = setterCb(env, name, value, thisArg, innerData); 742 } 743 }, 744 [&](JSVM_Env env, v8::Local<v8::Value> value) { 745 exceptionOccurred = true; 746 if (env->terminatedOrTerminating()) { 747 return; 748 } 749 env->isolate->ThrowException(value); 750 }); 751 if (!exceptionOccurred && (result != nullptr)) { 752 this->SetReturnValue(result); 753 } 754 } 755 756 inline void NameGetterInvokeCallback() { 757 auto context = _cbinfo.GetIsolate()->GetCurrentContext(); 758 auto env = v8impl::GetContextEnv(context); 759 auto getterCb = _cb->namedGetterCallback_; 760 761 JSVM_Value innerData = nullptr; 762 if (_cb->namedPropertyData_ != nullptr) { 763 v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(_cb->namedPropertyData_); 764 innerData = v8impl::JsValueFromV8LocalValue(reference->Get()); 765 } 766 bool exceptionOccurred = false; 767 JSVM_Value result = nullptr; 768 JSVM_Value name = JsValueFromV8LocalValue(_property); 769 JSVM_Value thisArg = this->This(); 770 env->CallIntoModule([&](JSVM_Env env) { 771 if (getterCb) { 772 result = getterCb(env, name, thisArg, innerData); 773 } 774 }, 775 [&](JSVM_Env env, v8::Local<v8::Value> value) { 776 exceptionOccurred = true; 777 if (env->terminatedOrTerminating()) { 778 return; 779 } 780 env->isolate->ThrowException(value); 781 }); 782 if (!exceptionOccurred && (result != nullptr)) { 783 this->SetReturnValue(result); 784 } 785 } 786 787 inline void NameDeleterInvokeCallback() { 788 auto context = _cbinfo.GetIsolate()->GetCurrentContext(); 789 auto env = v8impl::GetContextEnv(context); 790 auto deleterCb = _cb->nameDeleterCallback_; 791 792 JSVM_Value innerData = nullptr; 793 if (_cb->namedPropertyData_ != nullptr) { 794 v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(_cb->namedPropertyData_); 795 innerData = v8impl::JsValueFromV8LocalValue(reference->Get()); 796 } 797 798 bool exceptionOccurred = false; 799 JSVM_Value result = nullptr; 800 JSVM_Value name = JsValueFromV8LocalValue(_property); 801 JSVM_Value thisArg = this->This(); 802 env->CallIntoModule([&](JSVM_Env env) { 803 if (deleterCb) { 804 result = deleterCb(env, name, thisArg, innerData); 805 } 806 }, 807 [&](JSVM_Env env, v8::Local<v8::Value> value) { 808 exceptionOccurred = true; 809 if (env->terminatedOrTerminating()) { 810 return; 811 } 812 env->isolate->ThrowException(value); 813 }); 814 if (!exceptionOccurred && (result != nullptr)) { 815 if (v8impl::V8LocalValueFromJsValue(result)->IsBoolean()) { 816 this->SetReturnValue(result); 817 } 818 } 819 } 820 821 inline void NameEnumeratorInvokeCallback() { 822 auto context = _cbinfo.GetIsolate()->GetCurrentContext(); 823 auto env = v8impl::GetContextEnv(context); 824 auto enumeratorCb = _cb->namedEnumeratorCallback_; 825 826 JSVM_Value innerData = nullptr; 827 if (_cb->namedPropertyData_ != nullptr) { 828 v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(_cb->namedPropertyData_); 829 innerData = v8impl::JsValueFromV8LocalValue(reference->Get()); 830 } 831 832 bool exceptionOccurred = false; 833 JSVM_Value result = nullptr; 834 JSVM_Value thisArg = this->This(); 835 env->CallIntoModule([&](JSVM_Env env) { 836 if (enumeratorCb) { 837 result = enumeratorCb(env, thisArg, innerData); 838 } 839 }, 840 [&](JSVM_Env env, v8::Local<v8::Value> value) { 841 exceptionOccurred = true; 842 if (env->terminatedOrTerminating()) { 843 return; 844 } 845 env->isolate->ThrowException(value); 846 }); 847 if (!exceptionOccurred && (result != nullptr)) { 848 if (v8impl::V8LocalValueFromJsValue(result)->IsArray()) { 849 this->SetReturnValue(result); 850 } 851 } 852 } 853 854 inline void IndexSetterInvokeCallback() { 855 auto context = _cbinfo.GetIsolate()->GetCurrentContext(); 856 auto env = v8impl::GetContextEnv(context); 857 auto indexSetterCb = _cb->indexedSetterCallback_; 858 859 JSVM_Value innerData = nullptr; 860 if (_cb->indexedPropertyData_ != nullptr) { 861 v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(_cb->indexedPropertyData_); 862 innerData = v8impl::JsValueFromV8LocalValue(reference->Get()); 863 } 864 865 bool exceptionOccurred = false; 866 JSVM_Value result = nullptr; 867 JSVM_Value index = JsValueFromV8LocalValue(v8::Integer::NewFromUnsigned(env->isolate, _index)); 868 JSVM_Value value = JsValueFromV8LocalValue(_value); 869 JSVM_Value thisArg = this->This(); 870 env->CallIntoModule([&](JSVM_Env env) { 871 if (indexSetterCb) { 872 result = indexSetterCb(env, index, value, thisArg, innerData); 873 } 874 }, 875 [&](JSVM_Env env, v8::Local<v8::Value> value) { 876 exceptionOccurred = true; 877 if (env->terminatedOrTerminating()) { 878 return; 879 } 880 env->isolate->ThrowException(value); 881 }); 882 if (!exceptionOccurred && (result != nullptr)) { 883 this->SetReturnValue(result); 884 } 885 } 886 887 inline void IndexGetterInvokeCallback() { 888 auto context = _cbinfo.GetIsolate()->GetCurrentContext(); 889 auto env = v8impl::GetContextEnv(context); 890 auto indexGetterCb = _cb->indexedGetterCallback_; 891 892 JSVM_Value innerData = nullptr; 893 if (_cb->indexedPropertyData_ != nullptr) { 894 v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(_cb->indexedPropertyData_); 895 innerData = v8impl::JsValueFromV8LocalValue(reference->Get()); 896 } 897 898 JSVM_Value result = nullptr; 899 bool exceptionOccurred = false; 900 JSVM_Value index = JsValueFromV8LocalValue(v8::Integer::NewFromUnsigned(env->isolate, _index)); 901 JSVM_Value thisArg = this->This(); 902 env->CallIntoModule([&](JSVM_Env env) { 903 if (indexGetterCb) { 904 result = indexGetterCb(env, index, thisArg, innerData); 905 } 906 }, 907 [&](JSVM_Env env, v8::Local<v8::Value> value) { 908 exceptionOccurred = true; 909 if (env->terminatedOrTerminating()) { 910 return; 911 } 912 env->isolate->ThrowException(value); 913 }); 914 if (!exceptionOccurred && (result != nullptr)) { 915 this->SetReturnValue(result); 916 } 917 } 918 919 inline void IndexDeleterInvokeCallback() { 920 auto context = _cbinfo.GetIsolate()->GetCurrentContext(); 921 auto env = v8impl::GetContextEnv(context); 922 auto indexDeleterCb = _cb->indexedDeleterCallback_; 923 924 JSVM_Value innerData = nullptr; 925 if (_cb->indexedPropertyData_ != nullptr) { 926 v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(_cb->indexedPropertyData_); 927 innerData = v8impl::JsValueFromV8LocalValue(reference->Get()); 928 } 929 930 bool exceptionOccurred = false; 931 JSVM_Value result = nullptr; 932 JSVM_Value index = JsValueFromV8LocalValue(v8::Integer::NewFromUnsigned(env->isolate, _index)); 933 JSVM_Value thisArg = this->This(); 934 env->CallIntoModule([&](JSVM_Env env) { 935 if (indexDeleterCb) { 936 result = indexDeleterCb(env, index, thisArg, innerData); 937 } 938 }, 939 [&](JSVM_Env env, v8::Local<v8::Value> value) { 940 exceptionOccurred = true; 941 if (env->terminatedOrTerminating()) { 942 return; 943 } 944 env->isolate->ThrowException(value); 945 }); 946 if (!exceptionOccurred && (result != nullptr)) { 947 if (v8impl::V8LocalValueFromJsValue(result)->IsBoolean()) { 948 this->SetReturnValue(result); 949 } 950 } 951 } 952 953 inline void IndexEnumeratorInvokeCallback() { 954 auto context = _cbinfo.GetIsolate()->GetCurrentContext(); 955 auto env = v8impl::GetContextEnv(context); 956 auto enumeratorCb = _cb->indexedEnumeratorCallback_; 957 958 JSVM_Value innerData = nullptr; 959 if (_cb->indexedPropertyData_ != nullptr) { 960 v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(_cb->indexedPropertyData_); 961 innerData = v8impl::JsValueFromV8LocalValue(reference->Get()); 962 } 963 964 bool exceptionOccurred = false; 965 JSVM_Value result = nullptr; 966 JSVM_Value thisArg = this->This(); 967 env->CallIntoModule([&](JSVM_Env env) { 968 if (enumeratorCb) { 969 result = enumeratorCb(env, thisArg, innerData); 970 } 971 }, 972 [&](JSVM_Env env, v8::Local<v8::Value> value) { 973 exceptionOccurred = true; 974 if (env->terminatedOrTerminating()) { 975 return; 976 } 977 env->isolate->ThrowException(value); 978 }); 979 if (!exceptionOccurred && (result != nullptr)) { 980 if (v8impl::V8LocalValueFromJsValue(result)->IsArray()) { 981 this->SetReturnValue(result); 982 } 983 } 984 } 985 986 const v8::PropertyCallbackInfo<T>& _cbinfo; 987 JSVM_PropertyHandlerCfgStruct* _cb; 988 v8::Local<v8::Name> _property; 989 v8::Local<v8::Value> _value; 990 uint32_t _index; 991}; 992 993template <typename T> 994class PropertyCallbackWrapper : public PropertyCallbackWrapperBase<T> { 995 public: 996 static void NameSetterInvoke(v8::Local<v8::Name> property, v8::Local<v8::Value> value, 997 const v8::PropertyCallbackInfo<v8::Value>& info) { 998 PropertyCallbackWrapper<v8::Value> propertyCbWrapper(property, value, info); 999 propertyCbWrapper.NameSetterInvokeCallback(); 1000 } 1001 1002 static void NameGetterInvoke(v8::Local<v8::Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) { 1003 PropertyCallbackWrapper<v8::Value> propertyCbWrapper(property, v8::Local<v8::Value>(), info); 1004 propertyCbWrapper.NameGetterInvokeCallback(); 1005 } 1006 1007 static void NameDeleterInvoke(v8::Local<v8::Name> property, const v8::PropertyCallbackInfo<v8::Boolean>& info) { 1008 PropertyCallbackWrapper<v8::Boolean> propertyCbWrapper(property, v8::Local<v8::Value>(), info); 1009 propertyCbWrapper.NameDeleterInvokeCallback(); 1010 } 1011 1012 static void NameEnumeratorInvoke(const v8::PropertyCallbackInfo<v8::Array>& info) { 1013 PropertyCallbackWrapper<v8::Array> propertyCbWrapper(v8::Local<v8::Name>(), v8::Local<v8::Value>(), info); 1014 propertyCbWrapper.NameEnumeratorInvokeCallback(); 1015 } 1016 1017 static void IndexSetterInvoke(uint32_t index, v8::Local<v8::Value> value, 1018 const v8::PropertyCallbackInfo<v8::Value>& info) { 1019 PropertyCallbackWrapper<v8::Value> propertyCbWrapper(index, value, info); 1020 propertyCbWrapper.IndexSetterInvokeCallback(); 1021 } 1022 1023 static void IndexGetterInvoke(uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) { 1024 PropertyCallbackWrapper<v8::Value> propertyCbWrapper(index, v8::Local<v8::Value>(), info); 1025 propertyCbWrapper.IndexGetterInvokeCallback(); 1026 } 1027 1028 static void IndexDeleterInvoke(uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean>& info) { 1029 PropertyCallbackWrapper<v8::Boolean> propertyCbWrapper(index, v8::Local<v8::Value>(), info); 1030 propertyCbWrapper.IndexDeleterInvokeCallback(); 1031 } 1032 1033 static void IndexEnumeratorInvoke(const v8::PropertyCallbackInfo<v8::Array>& info) { 1034 PropertyCallbackWrapper<v8::Array> propertyCbWrapper(0, v8::Local<v8::Value>(), info); 1035 propertyCbWrapper.IndexEnumeratorInvokeCallback(); 1036 } 1037 1038 explicit PropertyCallbackWrapper(v8::Local<v8::Name> name, v8::Local<v8::Value> value, 1039 const v8::PropertyCallbackInfo<T>& cbinfo) 1040 : PropertyCallbackWrapperBase<T>(0, name, value, cbinfo, 0), _cbInfo(cbinfo) {} 1041 1042 explicit PropertyCallbackWrapper(uint32_t index, v8::Local<v8::Value> value, 1043 const v8::PropertyCallbackInfo<T>& cbinfo) 1044 : PropertyCallbackWrapperBase<T>(index, v8::Local<v8::Name>(), value, cbinfo, 0), _cbInfo(cbinfo) {} 1045 1046 /*virtual*/ 1047 void SetReturnValue(JSVM_Value value) override { 1048 v8::Local<T> val = v8impl::V8LocalValueFromJsValue(value).As<T>(); 1049 _cbInfo.GetReturnValue().Set(val); 1050 } 1051 1052protected: 1053 const v8::PropertyCallbackInfo<T>& _cbInfo; 1054}; 1055 1056inline JSVM_Status Wrap(JSVM_Env env, 1057 JSVM_Value jsObject, 1058 void* nativeObject, 1059 JSVM_Finalize finalizeCb, 1060 void* finalizeHint, 1061 JSVM_Ref* result) { 1062 JSVM_PREAMBLE(env); 1063 CHECK_ARG(env, jsObject); 1064 1065 v8::Local<v8::Context> context = env->context(); 1066 1067 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(jsObject); 1068 RETURN_STATUS_IF_FALSE(env, value->IsObject(), JSVM_INVALID_ARG); 1069 v8::Local<v8::Object> obj = value.As<v8::Object>(); 1070 1071 // If we've already wrapped this object, we error out. 1072 RETURN_STATUS_IF_FALSE( 1073 env, 1074 !obj->HasPrivate(context, JSVM_PRIVATE_KEY(env->isolate, wrapper)).FromJust(), 1075 JSVM_INVALID_ARG); 1076 1077 v8impl::Reference* reference = nullptr; 1078 if (result != nullptr) { 1079 // The returned reference should be deleted via OH_JSVM_DeleteReference() 1080 // ONLY in response to the finalize callback invocation. (If it is deleted 1081 // before then, then the finalize callback will never be invoked.) 1082 // Therefore a finalize callback is required when returning a reference. 1083 CHECK_ARG(env, finalizeCb); 1084 reference = v8impl::Reference::New(env, 1085 obj, 1086 0, 1087 v8impl::Ownership::kUserland, 1088 finalizeCb, 1089 nativeObject, 1090 finalizeHint); 1091 *result = reinterpret_cast<JSVM_Ref>(reference); 1092 } else { 1093 // Create a self-deleting reference. 1094 reference = v8impl::Reference::New( 1095 env, 1096 obj, 1097 0, 1098 v8impl::Ownership::kRuntime, 1099 finalizeCb, 1100 nativeObject, 1101 finalizeCb == nullptr ? nullptr : finalizeHint); 1102 } 1103 1104 CHECK(obj->SetPrivate(context, 1105 JSVM_PRIVATE_KEY(env->isolate, wrapper), 1106 v8::External::New(env->isolate, reference)) 1107 .FromJust()); 1108 1109 return GET_RETURN_STATUS(env); 1110} 1111 1112// In JavaScript, weak references can be created for object types (Object, 1113// Function, and external Object) and for local symbols that are created with 1114// the `Symbol` function call. Global symbols created with the `Symbol.for` 1115// method cannot be weak references because they are never collected. 1116// 1117// Currently, V8 has no API to detect if a symbol is local or global. 1118// Until we have a V8 API for it, we consider that all symbols can be weak. 1119// This matches the current Node-API behavior. 1120inline bool CanBeHeldWeakly(v8::Local<v8::Value> value) { 1121 return value->IsObject() || value->IsSymbol(); 1122} 1123 1124} // end of anonymous namespace 1125 1126void Finalizer::ResetFinalizer() { 1127 finalize_callback_ = nullptr; 1128 finalize_data_ = nullptr; 1129 finalize_hint_ = nullptr; 1130} 1131 1132TrackedFinalizer::TrackedFinalizer(JSVM_Env env, 1133 JSVM_Finalize finalizeCallback, 1134 void* finalizeData, 1135 void* finalizeHint) 1136 : Finalizer(env, finalizeCallback, finalizeData, finalizeHint), 1137 RefTracker() { 1138 Link(finalizeCallback == nullptr ? &env->reflist : &env->finalizing_reflist); 1139} 1140 1141TrackedFinalizer* TrackedFinalizer::New(JSVM_Env env, 1142 JSVM_Finalize finalizeCallback, 1143 void* finalizeData, 1144 void* finalizeHint) { 1145 return new TrackedFinalizer( 1146 env, finalizeCallback, finalizeData, finalizeHint); 1147} 1148 1149// When a TrackedFinalizer is being deleted, it may have been queued to call its 1150// finalizer. 1151TrackedFinalizer::~TrackedFinalizer() { 1152 // Remove from the env's tracked list. 1153 Unlink(); 1154 // Try to remove the finalizer from the scheduled second pass callback. 1155 env_->DequeueFinalizer(this); 1156} 1157 1158void TrackedFinalizer::Finalize() { 1159 FinalizeCore(/*deleteMe:*/ true); 1160} 1161 1162void TrackedFinalizer::FinalizeCore(bool deleteMe) { 1163 // Swap out the field finalize_callback so that it can not be accidentally 1164 // called more than once. 1165 JSVM_Finalize finalizeCallback = finalize_callback_; 1166 void* finalizeData = finalize_data_; 1167 void* finalizeHint = finalize_hint_; 1168 ResetFinalizer(); 1169 1170 // Either the RefBase is going to be deleted in the finalize_callback or not, 1171 // it should be removed from the tracked list. 1172 Unlink(); 1173 // If the finalize_callback is present, it should either delete the 1174 // derived RefBase, or the RefBase ownership was set to Ownership::kRuntime 1175 // and the deleteMe parameter is true. 1176 if (finalizeCallback != nullptr) { 1177 env_->CallFinalizer(finalizeCallback, finalizeData, finalizeHint); 1178 } 1179 1180 if (deleteMe) { 1181 delete this; 1182 } 1183} 1184 1185// Wrapper around v8impl::Persistent that implements reference counting. 1186RefBase::RefBase(JSVM_Env env, 1187 uint32_t initialRefcount, 1188 Ownership ownership, 1189 JSVM_Finalize finalizeCallback, 1190 void* finalizeData, 1191 void* finalizeHint) 1192 : TrackedFinalizer(env, finalizeCallback, finalizeData, finalizeHint), 1193 refcount_(initialRefcount), 1194 ownership_(ownership) {} 1195 1196RefBase* RefBase::New(JSVM_Env env, 1197 uint32_t initialRefcount, 1198 Ownership ownership, 1199 JSVM_Finalize finalizeCallback, 1200 void* finalizeData, 1201 void* finalizeHint) { 1202 return new RefBase(env, 1203 initialRefcount, 1204 ownership, 1205 finalizeCallback, 1206 finalizeData, 1207 finalizeHint); 1208} 1209 1210void* RefBase::Data() { 1211 return finalize_data_; 1212} 1213 1214uint32_t RefBase::Ref() { 1215 return ++refcount_; 1216} 1217 1218uint32_t RefBase::Unref() { 1219 if (refcount_ == 0) { 1220 return 0; 1221 } 1222 return --refcount_; 1223} 1224 1225uint32_t RefBase::RefCount() { 1226 return refcount_; 1227} 1228 1229void RefBase::Finalize() { 1230 // If the RefBase is not Ownership::kRuntime, userland code should delete it. 1231 // Delete it if it is Ownership::kRuntime. 1232 FinalizeCore(/*deleteMe:*/ ownership_ == Ownership::kRuntime); 1233} 1234 1235template <typename... Args> 1236Reference::Reference(JSVM_Env env, v8::Local<v8::Value> value, Args&&... args) 1237 : RefBase(env, std::forward<Args>(args)...), 1238 persistent_(env->isolate, value), 1239 can_be_weak_(CanBeHeldWeakly(value)), 1240 deleted_by_user(false), 1241 wait_callback(false) { 1242 if (RefCount() == 0) { 1243 SetWeak(); 1244 } 1245} 1246 1247Reference::~Reference() { 1248 // Reset the handle. And no weak callback will be invoked. 1249 persistent_.Reset(); 1250} 1251 1252Reference* Reference::New(JSVM_Env env, 1253 v8::Local<v8::Value> value, 1254 uint32_t initialRefcount, 1255 Ownership ownership, 1256 JSVM_Finalize finalizeCallback, 1257 void* finalizeData, 1258 void* finalizeHint) { 1259 return new Reference(env, 1260 value, 1261 initialRefcount, 1262 ownership, 1263 finalizeCallback, 1264 finalizeData, 1265 finalizeHint); 1266} 1267 1268uint32_t Reference::Ref() { 1269 // When the persistent_ is cleared in the WeakCallback, and a second pass 1270 // callback is pending, return 0 unconditionally. 1271 if (persistent_.IsEmpty()) { 1272 return 0; 1273 } 1274 uint32_t refcount = RefBase::Ref(); 1275 if (refcount == 1 && can_be_weak_) { 1276 persistent_.ClearWeak(); 1277 wait_callback = false; 1278 } 1279 return refcount; 1280} 1281 1282uint32_t Reference::Unref() { 1283 // When the persistent_ is cleared in the WeakCallback, and a second pass 1284 // callback is pending, return 0 unconditionally. 1285 if (persistent_.IsEmpty()) { 1286 return 0; 1287 } 1288 uint32_t old_refcount = RefCount(); 1289 uint32_t refcount = RefBase::Unref(); 1290 if (old_refcount == 1 && refcount == 0) { 1291 SetWeak(); 1292 } 1293 return refcount; 1294} 1295 1296v8::Local<v8::Value> Reference::Get() { 1297 if (persistent_.IsEmpty()) { 1298 return v8::Local<v8::Value>(); 1299 } else { 1300 return v8::Local<v8::Value>::New(env_->isolate, persistent_); 1301 } 1302} 1303 1304void Reference::Delete() { 1305 assert(Ownership() == kUserland); 1306 if (!wait_callback) { 1307 delete this; 1308 } else { 1309 deleted_by_user = true; 1310 } 1311} 1312 1313void Reference::Finalize() { 1314 // Unconditionally reset the persistent handle so that no weak callback will 1315 // be invoked again. 1316 persistent_.Reset(); 1317 1318 // Chain up to perform the rest of the finalization. 1319 RefBase::Finalize(); 1320} 1321 1322// Mark the reference as weak and eligible for collection 1323// by the gc. 1324void Reference::SetWeak() { 1325 if (can_be_weak_) { 1326 wait_callback = true; 1327 persistent_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter); 1328 } else { 1329 persistent_.Reset(); 1330 } 1331} 1332 1333// The N-API finalizer callback may make calls into the engine. V8's heap is 1334// not in a consistent state during the weak callback, and therefore it does 1335// not support calls back into it. Enqueue the invocation of the finalizer. 1336void Reference::WeakCallback(const v8::WeakCallbackInfo<Reference>& data) { 1337 Reference* reference = data.GetParameter(); 1338 // The reference must be reset during the weak callback as the API protocol. 1339 reference->persistent_.Reset(); 1340 assert(reference->wait_callback); 1341 // For owership == kRuntime, deleted_by_user is always false. 1342 // Due to reference may be free in InvokeFinalizerFromGC, the status of 1343 // reference should be set before finalize call. 1344 bool need_delete = reference->deleted_by_user; 1345 reference->wait_callback = false; 1346 reference->env_->InvokeFinalizerFromGC(reference); 1347 if (need_delete) { 1348 delete reference; 1349 } 1350} 1351 1352} // end of namespace v8impl 1353 1354v8::Platform* JSVM_Env__::platform() { 1355 return v8impl::g_platform.get(); 1356} 1357 1358constexpr int MAX_FILE_LENGTH = 32 * 1024 * 1024; 1359 1360static bool LoadStringFromFile(const std::string& filePath, std::string& content) 1361{ 1362 std::ifstream file(filePath.c_str()); 1363 if (!file.is_open()) { 1364 return false; 1365 } 1366 1367 file.seekg(0, std::ios::end); 1368 const long fileLength = file.tellg(); 1369 if (fileLength > MAX_FILE_LENGTH) { 1370 return false; 1371 } 1372 1373 content.clear(); 1374 file.seekg(0, std::ios::beg); 1375 std::copy(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>(), std::back_inserter(content)); 1376 return true; 1377} 1378 1379static bool ProcessBundleName(std::string& bundleName) 1380{ 1381 int pid = getprocpid(); 1382 std::string filePath = "/proc/" + std::to_string(pid) + "/cmdline"; 1383 if (!LoadStringFromFile(filePath, bundleName)) { 1384 return false; 1385 } 1386 if (bundleName.empty()) { 1387 return false; 1388 } 1389 auto pos = bundleName.find(":"); 1390 if (pos != std::string::npos) { 1391 bundleName = bundleName.substr(0, pos); 1392 } 1393 bundleName = bundleName.substr(0, strlen(bundleName.c_str())); 1394 return true; 1395} 1396 1397JSVM_Status JSVM_CDECL 1398OH_JSVM_Init(const JSVM_InitOptions* options) { 1399 static std::atomic<bool> initialized(false); 1400 if (initialized.load()) { 1401 return JSVM_GENERIC_FAILURE; 1402 } 1403 initialized.store(true); 1404#ifdef TARGET_OHOS 1405#ifdef ENABLE_HISYSEVENT 1406 std::string bundleName; 1407 if (!ProcessBundleName(bundleName)) { 1408 bundleName = "INVALID_BUNDLE_NAME"; 1409 } 1410 HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::JSVM_RUNTIME, "APP_STATS", 1411 OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, 1412 "BUNDLE_NAME", bundleName); 1413#endif 1414 v8impl::ResourceSchedule::ReportKeyThread(getuid(), getprocpid(), getproctid(), 1415 v8impl::ResourceSchedule::ResType::ThreadRole::IMPORTANT_DISPLAY); 1416#endif 1417 v8::V8::InitializePlatform(v8impl::g_platform.get()); 1418 1419 if (node::ReadSystemXpmState()) { 1420 int secArgc = SECARGCNT; 1421 char *secArgv[SECARGCNT] = {const_cast<char*>("jsvm"), const_cast<char*>("--jitless")}; 1422 v8::V8::SetFlagsFromCommandLine(&secArgc, secArgv, false); 1423 } 1424 1425 if (options && options->argc && options->argv) { 1426 v8::V8::SetFlagsFromCommandLine(options->argc, options->argv, options->removeFlags); 1427 } 1428 v8::V8::Initialize(); 1429 1430 const auto cb = v8impl::FunctionCallbackWrapper::Invoke; 1431 v8impl::externalReferenceRegistry.push_back((intptr_t)cb); 1432 if (auto p = options ? options->externalReferences : nullptr) { 1433 for (; *p != 0; p++) { 1434 v8impl::externalReferenceRegistry.push_back(*p); 1435 } 1436 } 1437 v8impl::externalReferenceRegistry.push_back(0); 1438 return JSVM_OK; 1439} 1440 1441JSVM_Status JSVM_CDECL OH_JSVM_GetVM(JSVM_Env env, 1442 JSVM_VM* result) { 1443 *result = reinterpret_cast<JSVM_VM>(env->isolate); 1444 return JSVM_OK; 1445} 1446 1447JSVM_Status JSVM_CDECL 1448OH_JSVM_CreateVM(const JSVM_CreateVMOptions* options, JSVM_VM* result) { 1449#ifdef TARGET_OHOS 1450 v8impl::ResourceSchedule::ReportKeyThread(getuid(), getprocpid(), getproctid(), 1451 v8impl::ResourceSchedule::ResType::ThreadRole::USER_INTERACT); 1452#endif 1453 v8::Isolate::CreateParams create_params; 1454 auto externalReferences = v8impl::externalReferenceRegistry.data(); 1455 create_params.external_references = externalReferences; 1456 1457 v8::StartupData* snapshotBlob = nullptr; 1458 if (options && options->snapshotBlobData) { 1459 snapshotBlob = new v8::StartupData(); 1460 snapshotBlob->data = options->snapshotBlobData; 1461 snapshotBlob->raw_size = options->snapshotBlobSize; 1462 1463 if (!snapshotBlob->IsValid()) { 1464 // TODO: Is VerifyCheckSum necessay if there has been a validity check? 1465 delete snapshotBlob; 1466 return JSVM_INVALID_ARG; 1467 } 1468 create_params.snapshot_blob = snapshotBlob; 1469 } 1470 1471 v8::Isolate* isolate; 1472 if (options && options->isForSnapshotting) { 1473 isolate = v8::Isolate::Allocate(); 1474 auto creator = new v8::SnapshotCreator(isolate, externalReferences); 1475 v8impl::SetIsolateSnapshotCreator(isolate, creator); 1476 } else { 1477 create_params.array_buffer_allocator = 1478 v8impl::GetOrCreateDefaultArrayBufferAllocator(); 1479 isolate = v8::Isolate::New(create_params); 1480 } 1481 v8impl::CreateIsolateData(isolate, snapshotBlob); 1482 *result = reinterpret_cast<JSVM_VM>(isolate); 1483 1484 return JSVM_OK; 1485} 1486 1487JSVM_Status JSVM_CDECL 1488OH_JSVM_DestroyVM(JSVM_VM vm) { 1489 if (vm == nullptr) { 1490 return JSVM_INVALID_ARG; 1491 } 1492 auto isolate = reinterpret_cast<v8::Isolate*>(vm); 1493 auto creator = v8impl::GetIsolateSnapshotCreator(isolate); 1494 auto data = v8impl::GetIsolateData(isolate); 1495 1496 if (creator != nullptr) { 1497 delete creator; 1498 } else { 1499 isolate->Dispose(); 1500 } 1501 if (data != nullptr) { 1502 delete data; 1503 } 1504 1505 return JSVM_OK; 1506} 1507 1508JSVM_Status JSVM_CDECL OH_JSVM_OpenVMScope(JSVM_VM vm, JSVM_VMScope* result) { 1509 auto isolate = reinterpret_cast<v8::Isolate*>(vm); 1510 auto scope = new v8::Isolate::Scope(isolate); 1511 *result = reinterpret_cast<JSVM_VMScope>(scope); 1512 return JSVM_OK; 1513} 1514 1515JSVM_Status JSVM_CDECL 1516OH_JSVM_CloseVMScope(JSVM_VM vm, JSVM_VMScope scope) { 1517 auto v8scope = reinterpret_cast<v8::Isolate::Scope*>(scope); 1518 delete v8scope; 1519 return JSVM_OK; 1520} 1521 1522JSVM_Status JSVM_CDECL 1523OH_JSVM_CreateEnv(JSVM_VM vm, 1524 size_t propertyCount, 1525 const JSVM_PropertyDescriptor* properties, 1526 JSVM_Env* result) { 1527 auto isolate = reinterpret_cast<v8::Isolate*>(vm); 1528 auto env = new JSVM_Env__(isolate, NODE_API_DEFAULT_MODULE_API_VERSION); 1529 v8::HandleScope handle_scope(isolate); 1530 auto global_template = v8::ObjectTemplate::New(isolate); 1531 1532 for (size_t i = 0; i < propertyCount; i++) { 1533 const JSVM_PropertyDescriptor* p = properties + i; 1534 1535 if ((p->attributes & JSVM_STATIC) != 0) { 1536 //Ignore static properties. 1537 continue; 1538 } 1539 1540 v8::Local<v8::Name> property_name = 1541 v8::String::NewFromUtf8(isolate, p->utf8name, v8::NewStringType::kInternalized) 1542 .ToLocalChecked(); 1543 1544 v8::PropertyAttribute attributes = 1545 v8impl::V8PropertyAttributesFromDescriptor(p); 1546 1547 if (p->getter != nullptr || p->setter != nullptr) { 1548 v8::Local<v8::FunctionTemplate> getter_tpl; 1549 v8::Local<v8::FunctionTemplate> setter_tpl; 1550 if (p->getter != nullptr) { 1551 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate( 1552 env, p->getter, &getter_tpl)); 1553 } 1554 if (p->setter != nullptr) { 1555 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate( 1556 env, p->setter, &setter_tpl)); 1557 } 1558 1559 global_template->SetAccessorProperty( 1560 property_name, getter_tpl, setter_tpl, attributes); 1561 } else if (p->method != nullptr) { 1562 v8::Local<v8::FunctionTemplate> method_tpl; 1563 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate( 1564 env, p->method, &method_tpl)); 1565 1566 global_template->Set(property_name, method_tpl, attributes); 1567 } else { 1568 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value); 1569 global_template->Set(property_name, value, attributes); 1570 } 1571 } 1572 1573 v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global_template); 1574 env->context_persistent.Reset(isolate, context); 1575 v8impl::SetContextEnv(context, env); 1576 *result = env; 1577 return JSVM_OK; 1578} 1579 1580JSVM_EXTERN JSVM_Status JSVM_CDECL 1581OH_JSVM_CreateEnvFromSnapshot(JSVM_VM vm, size_t index, JSVM_Env* result) { 1582 auto isolate = reinterpret_cast<v8::Isolate*>(vm); 1583 v8::HandleScope handle_scope(isolate); 1584 auto maybe = v8::Context::FromSnapshot(isolate, index); 1585 1586 if (maybe.IsEmpty()) { 1587 *result = nullptr; 1588 // TODO: return error message. 1589 return JSVM_GENERIC_FAILURE; 1590 } 1591 1592 auto env = new JSVM_Env__(isolate, NODE_API_DEFAULT_MODULE_API_VERSION); 1593 auto context = maybe.ToLocalChecked(); 1594 env->context_persistent.Reset(isolate, context); 1595 v8impl::SetContextEnv(context, env); 1596 *result = env; 1597 1598 return JSVM_OK; 1599} 1600 1601JSVM_Status JSVM_CDECL 1602OH_JSVM_DestroyEnv(JSVM_Env env) { 1603 env->DeleteMe(); 1604 return JSVM_OK; 1605} 1606 1607JSVM_Status JSVM_CDECL 1608 OH_JSVM_OpenEnvScope(JSVM_Env env, JSVM_EnvScope* result) { 1609 auto v8scope = new v8::Context::Scope(env->context()); 1610 *result = reinterpret_cast<JSVM_EnvScope>(v8scope); 1611 return JSVM_OK; 1612} 1613 1614JSVM_Status JSVM_CDECL 1615OH_JSVM_CloseEnvScope(JSVM_Env env, JSVM_EnvScope scope) { 1616 auto v8scope = reinterpret_cast<v8::Context::Scope*>(scope); 1617 delete v8scope; 1618 return JSVM_OK; 1619} 1620 1621JSVM_Status JSVM_CDECL 1622OH_JSVM_CompileScript(JSVM_Env env, 1623 JSVM_Value script, 1624 const uint8_t *cachedData, 1625 size_t cachedDataLength, 1626 bool eagerCompile, 1627 bool* cacheRejected, 1628 JSVM_Script* result) { 1629 JSVM_PREAMBLE(env); 1630 CHECK_ARG(env, script); 1631 CHECK_ARG(env, result); 1632 1633 v8::Local<v8::Value> v8_script = v8impl::V8LocalValueFromJsValue(script); 1634 1635 RETURN_STATUS_IF_FALSE(env, v8_script->IsString(), JSVM_STRING_EXPECTED); 1636 1637 v8::Local<v8::Context> context = env->context(); 1638 1639 v8::ScriptCompiler::CachedData* cache = cachedData 1640 ? new v8::ScriptCompiler::CachedData(cachedData, cachedDataLength) : nullptr; 1641 v8::ScriptCompiler::Source scriptSource(v8_script.As<v8::String>(), cache); 1642 auto option = cache ? v8::ScriptCompiler::kConsumeCodeCache 1643 : (eagerCompile ? v8::ScriptCompiler::kEagerCompile : v8::ScriptCompiler::kNoCompileOptions); 1644 1645 auto maybe_script = v8::ScriptCompiler::Compile(context, &scriptSource, option); 1646 1647 if (cache) { 1648 delete cache; 1649 } 1650 1651 if (cache && cacheRejected) { 1652 *cacheRejected = cache->rejected; 1653 } 1654 1655 CHECK_MAYBE_EMPTY(env, maybe_script, JSVM_GENERIC_FAILURE); 1656 v8::Local<v8::Script> compiled_script = maybe_script.ToLocalChecked(); 1657 *result = reinterpret_cast<JSVM_Script>(env->NewJsvmData(compiled_script)); 1658 1659 return GET_RETURN_STATUS(env); 1660} 1661 1662v8::ScriptOrigin CreateScriptOrigin( 1663 v8::Isolate* isolate, v8::Local<v8::String> resource_name, v8::ScriptType type) { 1664 const int kOptionsLength = 2; 1665 const uint32_t kOptionsMagicConstant = 0xF1F2F3F0; 1666 auto options = v8::PrimitiveArray::New(isolate, kOptionsLength); 1667 options->Set(isolate, 0, v8::Uint32::New(isolate, kOptionsMagicConstant)); 1668 options->Set(isolate, 1, resource_name); 1669 return v8::ScriptOrigin(isolate, resource_name, 0, 0, false, -1, v8::Local<v8::Value>(), 1670 false, false, type == v8::ScriptType::kModule, options); 1671} 1672 1673v8::MaybeLocal<v8::Value> PrepareStackTraceCallback( 1674 v8::Local<v8::Context> context, v8::Local<v8::Value> error, v8::Local<v8::Array> trace) { 1675 auto *isolate = context->GetIsolate(); 1676 v8::TryCatch try_catch(isolate); 1677 v8::Local<v8::String> moduleName = 1678 v8::String::NewFromUtf8(isolate, "sourcemap").ToLocalChecked(); 1679 v8::Local<v8::String> moduleSourceString = 1680 v8::String::NewFromUtf8(isolate, SourceMapRunner.c_str()).ToLocalChecked(); 1681 1682 v8::ScriptOrigin moduleOrigin = 1683 CreateScriptOrigin(isolate, moduleName, v8::ScriptType::kClassic); 1684 v8::Local<v8::Context> moduleContext = v8::Context::New(isolate); 1685 v8::ScriptCompiler::Source moduleSource(moduleSourceString, moduleOrigin); 1686 auto script = 1687 v8::Script::Compile(moduleContext, moduleSourceString, &moduleOrigin).ToLocalChecked(); 1688 auto result = script->Run(moduleContext).ToLocalChecked(); 1689 auto resultFunc = v8::Local<v8::Function>::Cast(result); 1690 1691 v8::Local<v8::Value> element = trace->Get(context, 0).ToLocalChecked(); 1692 std::string fileName = ""; 1693 if (element->IsObject()) { 1694 auto obj = element->ToObject(context); 1695 auto getFileName = v8::String::NewFromUtf8(isolate, "getFileName", v8::NewStringType::kNormal); 1696 auto function = obj.ToLocalChecked()->Get(context, getFileName.ToLocalChecked()).ToLocalChecked(); 1697 auto lineNumberFunction = v8::Local<v8::Function>::Cast(function); 1698 auto fileNameObj = lineNumberFunction->Call(context, obj.ToLocalChecked(), 0, {}); 1699 fileName = std::string(*v8::String::Utf8Value(isolate, fileNameObj.ToLocalChecked())); 1700 } 1701 auto &&sourceMapUrl = (!fileName.empty()) ? v8impl::GetSourceMapFromFileName(std::move(fileName)) : ""; 1702 std::ifstream sourceMapfile(sourceMapUrl); 1703 std::string content = ""; 1704 if (sourceMapfile.good()) { 1705 std::stringstream buffer; 1706 buffer << sourceMapfile.rdbuf(); 1707 content = buffer.str(); 1708 } 1709 auto sourceMapObject = v8::String::NewFromUtf8( 1710 isolate, content.c_str(), v8::NewStringType::kNormal, content.length()); 1711 v8::Local<v8::Value> args[] = { error, trace, sourceMapObject.ToLocalChecked() }; 1712 return resultFunc->Call(moduleContext, v8::Undefined(isolate), node::arraysize(args), args); 1713} 1714 1715JSVM_Status JSVM_CDECL 1716OH_JSVM_CompileScriptWithOrigin(JSVM_Env env, 1717 JSVM_Value script, 1718 const uint8_t* cachedData, 1719 size_t cachedDataLength, 1720 bool eagerCompile, 1721 bool* cacheRejected, 1722 JSVM_ScriptOrigin* origin, 1723 JSVM_Script* result) { 1724 JSVM_PREAMBLE(env); 1725 CHECK_ARG(env, script); 1726 CHECK_ARG(env, result); 1727 CHECK_NOT_NULL(origin->resourceName); 1728 1729 v8::Local<v8::Value> v8_script = v8impl::V8LocalValueFromJsValue(script); 1730 1731 RETURN_STATUS_IF_FALSE(env, v8_script->IsString(), JSVM_STRING_EXPECTED); 1732 1733 v8::Local<v8::Context> context = env->context(); 1734 auto *isolate = context->GetIsolate(); 1735 1736 if (origin->sourceMapUrl) { 1737 v8impl::SetFileToSourceMapMapping(origin->resourceName, origin->sourceMapUrl); 1738 isolate->SetPrepareStackTraceCallback(PrepareStackTraceCallback); 1739 } 1740 auto sourceMapUrl = !origin->sourceMapUrl ? v8::Local<v8::Value>() : 1741 v8::String::NewFromUtf8(isolate, origin->sourceMapUrl).ToLocalChecked().As<v8::Value>(); 1742 auto resourceName = 1743 v8::String::NewFromUtf8(isolate, origin->resourceName).ToLocalChecked(); 1744 v8::ScriptOrigin scriptOrigin(isolate, resourceName, 1745 origin->resourceLineOffset, origin->resourceColumnOffset, false, -1, sourceMapUrl); 1746 1747 v8::ScriptCompiler::CachedData* cache = cachedData 1748 ? new v8::ScriptCompiler::CachedData(cachedData, cachedDataLength) : nullptr; 1749 v8::ScriptCompiler::Source scriptSource(v8_script.As<v8::String>(), scriptOrigin, cache); 1750 auto option = cache ? v8::ScriptCompiler::kConsumeCodeCache 1751 : (eagerCompile ? v8::ScriptCompiler::kEagerCompile : v8::ScriptCompiler::kNoCompileOptions); 1752 1753 auto maybe_script = v8::ScriptCompiler::Compile(context, &scriptSource, option); 1754 1755 if (cache) { 1756 delete cache; 1757 } 1758 1759 if (cache && cacheRejected) { 1760 *cacheRejected = cache->rejected; 1761 } 1762 1763 CHECK_MAYBE_EMPTY(env, maybe_script, JSVM_GENERIC_FAILURE); 1764 v8::Local<v8::Script> compiled_script = maybe_script.ToLocalChecked(); 1765 *result = reinterpret_cast<JSVM_Script>(env->NewJsvmData(compiled_script)); 1766 1767 return GET_RETURN_STATUS(env); 1768} 1769 1770class CompileOptionResolver { 1771 public: 1772 CompileOptionResolver(size_t length, JSVM_CompileOptions options[], v8::Isolate *isolate) { 1773 for (size_t i = 0; i < length; i++) { 1774 switch(options[i].id) { 1775 case JSVM_COMPILE_MODE: { 1776 v8Option = static_cast<v8::ScriptCompiler::CompileOptions>(options[i].content.num); 1777 break; 1778 } 1779 case JSVM_COMPILE_CODE_CACHE: { 1780 auto cache = static_cast<JSVM_CodeCache*>(options[i].content.ptr); 1781 cachedData = cache->cache ? 1782 new v8::ScriptCompiler::CachedData(cache->cache, cache->length) : nullptr; 1783 break; 1784 } 1785 case JSVM_COMPILE_SCRIPT_ORIGIN: { 1786 jsvmOrigin = static_cast<JSVM_ScriptOrigin*>(options[i].content.ptr); 1787 break; 1788 } 1789 case JSVM_COMPILE_COMPILE_PROFILE: { 1790 profile = static_cast<JSVM_CompileProfile*>(options[i].content.ptr); 1791 break; 1792 } 1793 case JSVM_COMPILE_ENABLE_SOURCE_MAP: { 1794 enableSourceMap = options[i].content.boolean; 1795 break; 1796 } 1797 default: { 1798 continue; 1799 } 1800 } 1801 } 1802 auto sourceString = jsvmOrigin ? jsvmOrigin->resourceName : 1803 "script_" + std::to_string(compileCount++); 1804 auto sourceMapPtr = jsvmOrigin && jsvmOrigin->sourceMapUrl ? 1805 jsvmOrigin->sourceMapUrl : nullptr; 1806 auto sourceMapUrl = (jsvmOrigin && jsvmOrigin->sourceMapUrl) ? 1807 v8::String::NewFromUtf8(isolate, jsvmOrigin->sourceMapUrl).ToLocalChecked().As<v8::Value>() : 1808 v8::Local<v8::Value>(); 1809 auto resourceName = v8::String::NewFromUtf8(isolate, sourceString.c_str()).ToLocalChecked(); 1810 v8Origin = new v8::ScriptOrigin(isolate, resourceName, 1811 jsvmOrigin ? jsvmOrigin->resourceLineOffset : 0, 1812 jsvmOrigin ? jsvmOrigin->resourceColumnOffset : 0, 1813 false, -1, sourceMapUrl); 1814 if (enableSourceMap && sourceMapPtr) { 1815 v8impl::SetFileToSourceMapMapping(jsvmOrigin->resourceName, sourceMapPtr); 1816 isolate->SetPrepareStackTraceCallback(PrepareStackTraceCallback); 1817 } 1818 if (v8Option == v8::ScriptCompiler::kConsumeCodeCache && !cachedData) { 1819 hasInvalidOption = true; 1820 } 1821 } 1822 1823 ~CompileOptionResolver() { 1824 delete v8Origin; 1825 v8Origin = nullptr; 1826 } 1827 1828 v8::ScriptCompiler::CompileOptions v8Option = 1829 v8::ScriptCompiler::kNoCompileOptions; 1830 v8::ScriptCompiler::CachedData *cachedData = nullptr; 1831 v8::ScriptOrigin *v8Origin = nullptr; 1832 JSVM_CompileProfile *profile = nullptr; 1833 JSVM_ScriptOrigin *jsvmOrigin = nullptr; 1834 bool enableSourceMap = false; 1835 static size_t compileCount; 1836 bool hasInvalidOption = false; 1837}; 1838 1839size_t CompileOptionResolver::compileCount = 0; 1840 1841JSVM_Status JSVM_CDECL 1842OH_JSVM_CompileScriptWithOptions(JSVM_Env env, 1843 JSVM_Value script, 1844 size_t optionCount, 1845 JSVM_CompileOptions options[], 1846 JSVM_Script* result) { 1847 JSVM_PREAMBLE(env); 1848 CHECK_ARG(env, script); 1849 CHECK_ARG(env, result); 1850 1851 v8::Local<v8::Context> context = env->context(); 1852 auto *isolate = context->GetIsolate(); 1853 CompileOptionResolver optionResolver(optionCount, options, isolate); 1854 RETURN_STATUS_IF_FALSE(env, !optionResolver.hasInvalidOption, JSVM_INVALID_ARG); 1855 1856 v8::Local<v8::Value> v8_script = v8impl::V8LocalValueFromJsValue(script); 1857 1858 RETURN_STATUS_IF_FALSE(env, v8_script->IsString(), JSVM_STRING_EXPECTED); 1859 1860 v8::ScriptCompiler::Source scriptSource(v8_script.As<v8::String>(), 1861 *optionResolver.v8Origin, optionResolver.cachedData); 1862 auto maybe_script = v8::ScriptCompiler::Compile(context, &scriptSource, optionResolver.v8Option); 1863 1864 CHECK_MAYBE_EMPTY(env, maybe_script, JSVM_GENERIC_FAILURE); 1865 v8::Local<v8::Script> compiled_script = maybe_script.ToLocalChecked(); 1866 *result = reinterpret_cast<JSVM_Script>(*compiled_script); 1867 1868 return GET_RETURN_STATUS(env); 1869} 1870 1871JSVM_Status JSVM_CDECL 1872OH_JSVM_CreateCodeCache(JSVM_Env env, 1873 JSVM_Script script, 1874 const uint8_t** data, 1875 size_t* length) { 1876 CHECK_ENV(env); 1877 CHECK_ARG(env, script); 1878 CHECK_ARG(env, data); 1879 CHECK_ARG(env, length); 1880 auto jsvmData = reinterpret_cast<JSVM_Data__*>(script); 1881 auto v8script = jsvmData->ToV8Local<v8::Script>(env->isolate); 1882 v8::ScriptCompiler::CachedData* cache; 1883 cache = v8::ScriptCompiler::CreateCodeCache(v8script->GetUnboundScript()); 1884 1885 if (cache == nullptr) { 1886 // TODO: return error 1887 return jsvm_set_last_error(env, JSVM_GENERIC_FAILURE); 1888 } 1889 1890 *data = cache->data; 1891 *length = cache->length; 1892 cache->buffer_policy = v8::ScriptCompiler::CachedData::BufferNotOwned; 1893 delete cache; 1894 return JSVM_OK; 1895} 1896 1897JSVM_Status JSVM_CDECL 1898OH_JSVM_RunScript(JSVM_Env env, JSVM_Script script, JSVM_Value* result) { 1899 JSVM_PREAMBLE(env); 1900 CHECK_ARG(env, script); 1901 CHECK_ARG(env, result); 1902 1903 auto jsvmData = reinterpret_cast<JSVM_Data__*>(script); 1904 auto v8script = jsvmData->ToV8Local<v8::Script>(env->isolate); 1905 auto script_result = v8script->Run(env->context()); 1906 CHECK_MAYBE_EMPTY(env, script_result, JSVM_GENERIC_FAILURE); 1907 *result = v8impl::JsValueFromV8LocalValue(script_result.ToLocalChecked()); 1908 1909 return GET_RETURN_STATUS(env); 1910} 1911 1912JSVM_Status JSVM_CDECL 1913OH_JSVM_JsonParse(JSVM_Env env, JSVM_Value json_string, JSVM_Value* result) { 1914 JSVM_PREAMBLE(env); 1915 CHECK_ARG(env, json_string); 1916 1917 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(json_string); 1918 RETURN_STATUS_IF_FALSE(env, val->IsString(), JSVM_STRING_EXPECTED); 1919 1920 auto maybe = v8::JSON::Parse(env->context(), val.As<v8::String>()); 1921 CHECK_MAYBE_EMPTY(env, maybe,JSVM_GENERIC_FAILURE); 1922 *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked()); 1923 1924 return GET_RETURN_STATUS(env); 1925} 1926 1927JSVM_Status JSVM_CDECL 1928OH_JSVM_JsonStringify(JSVM_Env env, JSVM_Value json_object, JSVM_Value* result) { 1929 JSVM_PREAMBLE(env); 1930 CHECK_ARG(env, json_object); 1931 1932 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(json_object); 1933 1934 auto maybe = v8::JSON::Stringify(env->context(), val); 1935 CHECK_MAYBE_EMPTY(env, maybe,JSVM_GENERIC_FAILURE); 1936 *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked()); 1937 1938 return GET_RETURN_STATUS(env); 1939} 1940 1941JSVM_Status JSVM_CDECL 1942OH_JSVM_CreateSnapshot(JSVM_VM vm, 1943 size_t contextCount, 1944 const JSVM_Env* contexts, 1945 const char** blobData, 1946 size_t* blobSize) { 1947 auto isolate = reinterpret_cast<v8::Isolate*>(vm); 1948 auto creator = v8impl::GetIsolateSnapshotCreator(isolate); 1949 1950 if (creator == nullptr) { 1951 // TODO: return specific error message. 1952 return JSVM_GENERIC_FAILURE; 1953 } 1954 { 1955 v8::HandleScope scope(isolate); 1956 v8::Local<v8::Context> default_context = v8::Context::New(isolate); 1957 creator->SetDefaultContext(default_context); 1958 // NOTE: The order of the added data must be consistent with the order of 1959 // getting data in v8impl::CreateIsolateData. 1960 creator->AddData(JSVM_PRIVATE_KEY(isolate, wrapper)); 1961 creator->AddData(JSVM_PRIVATE_KEY(isolate, type_tag)); 1962 1963 for (size_t i = 0; i < contextCount; i++) { 1964 auto ctx = contexts[i]->context(); 1965 creator->AddData(ctx, ctx); 1966 creator->AddContext(ctx); 1967 } 1968 } 1969 auto blob = creator->CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kKeep); 1970 *blobData = blob.data; 1971 *blobSize = blob.raw_size; 1972 1973 return JSVM_OK; 1974} 1975 1976JSVM_EXTERN JSVM_Status JSVM_CDECL OH_JSVM_GetVMInfo(JSVM_VMInfo* result) { 1977 result->apiVersion = 1; 1978 result->engine = "v8"; 1979 result->version = V8_VERSION_STRING; 1980 result->cachedDataVersionTag = v8::ScriptCompiler::CachedDataVersionTag(); 1981 return JSVM_OK; 1982} 1983 1984JSVM_EXTERN JSVM_Status JSVM_CDECL 1985OH_JSVM_MemoryPressureNotification(JSVM_Env env, 1986 JSVM_MemoryPressureLevel level) { 1987 CHECK_ENV(env); 1988 env->isolate->MemoryPressureNotification(v8::MemoryPressureLevel(level)); 1989 return jsvm_clear_last_error(env); 1990} 1991 1992JSVM_EXTERN JSVM_Status JSVM_CDECL 1993OH_JSVM_GetHeapStatistics(JSVM_VM vm, JSVM_HeapStatistics* result) { 1994 auto isolate = reinterpret_cast<v8::Isolate*>(vm); 1995 v8::HeapStatistics stats; 1996 isolate->GetHeapStatistics(&stats); 1997 result->totalHeapSize = stats.total_heap_size(); 1998 result->totalHeapSizeExecutable = stats.total_heap_size_executable(); 1999 result->totalPhysicalSize = stats.total_physical_size(); 2000 result->totalAvailableSize = stats.total_available_size(); 2001 result->usedHeapSize = stats.used_heap_size(); 2002 result->heapSizeLimit = stats.heap_size_limit(); 2003 result->mallocedMemory = stats.malloced_memory(); 2004 result->externalMemory = stats.external_memory(); 2005 result->peakMallocedMemory = stats.peak_malloced_memory(); 2006 result->numberOfNativeContexts = stats.number_of_native_contexts(); 2007 result->numberOfDetachedContexts = stats.number_of_detached_contexts(); 2008 result->totalGlobalHandlesSize = stats.total_global_handles_size(); 2009 result->usedGlobalHandlesSize = stats.used_global_handles_size(); 2010 return JSVM_OK; 2011} 2012 2013JSVM_EXTERN JSVM_Status JSVM_CDECL 2014OH_JSVM_StartCpuProfiler(JSVM_VM vm, JSVM_CpuProfiler* result) { 2015 auto isolate = reinterpret_cast<v8::Isolate*>(vm); 2016 auto profiler = v8::CpuProfiler::New(isolate); 2017 v8::HandleScope scope(isolate); 2018 v8::CpuProfilingOptions options; 2019 profiler->Start(v8::String::Empty(isolate), std::move(options)); 2020 *result = reinterpret_cast<JSVM_CpuProfiler>(profiler); 2021 return JSVM_OK; 2022} 2023 2024JSVM_EXTERN JSVM_Status JSVM_CDECL 2025OH_JSVM_StopCpuProfiler(JSVM_VM vm, JSVM_CpuProfiler profiler, 2026 JSVM_OutputStream stream, void* streamData) { 2027 auto isolate = reinterpret_cast<v8::Isolate*>(vm); 2028 auto v8profiler = reinterpret_cast<v8::CpuProfiler*>(profiler); 2029 v8::HandleScope scope(isolate); 2030 auto profile = v8profiler->StopProfiling(v8::String::Empty(isolate)); 2031 v8impl::OutputStream os(stream, streamData); 2032 profile->Serialize(&os); 2033 return JSVM_OK; 2034} 2035 2036JSVM_EXTERN JSVM_Status JSVM_CDECL 2037OH_JSVM_TakeHeapSnapshot(JSVM_VM vm, 2038 JSVM_OutputStream stream, void* streamData) { 2039 auto isolate = reinterpret_cast<v8::Isolate*>(vm); 2040 auto profiler = isolate->GetHeapProfiler(); 2041 auto snapshot = profiler->TakeHeapSnapshot(); 2042 v8impl::OutputStream os(stream, streamData); 2043 snapshot->Serialize(&os); 2044 return JSVM_OK; 2045} 2046 2047JSVM_EXTERN JSVM_Status JSVM_CDECL 2048OH_JSVM_OpenInspector(JSVM_Env env, const char* host, uint16_t port) { 2049 JSVM_PREAMBLE(env); 2050 2051 std::string inspectorPath; 2052 std::string hostName(host); 2053 auto hostPort = 2054 std::make_shared<node::ExclusiveAccess<node::HostPort>>(hostName, port); 2055 env->inspector_agent()->Start(inspectorPath, hostPort, true, false); 2056 2057 return GET_RETURN_STATUS(env); 2058} 2059 2060JSVM_EXTERN JSVM_Status JSVM_CDECL OH_JSVM_CloseInspector(JSVM_Env env) { 2061 JSVM_PREAMBLE(env); 2062 auto agent = env->inspector_agent(); 2063 if (!agent->IsActive()) { 2064 return JSVM_GENERIC_FAILURE; 2065 } 2066 agent->Stop(); 2067 return GET_RETURN_STATUS(env); 2068} 2069 2070JSVM_EXTERN JSVM_Status JSVM_CDECL OH_JSVM_WaitForDebugger(JSVM_Env env, bool breakNextLine) { 2071 JSVM_PREAMBLE(env); 2072 auto agent = env->inspector_agent(); 2073 if (!agent->IsActive()) { 2074 return JSVM_GENERIC_FAILURE; 2075 } 2076 2077 agent->WaitForConnect(); 2078 if (breakNextLine) { 2079 agent->PauseOnNextJavascriptStatement("Break on debugger attached"); 2080 } 2081 2082 return GET_RETURN_STATUS(env); 2083} 2084 2085JSVM_EXTERN JSVM_Status JSVM_CDECL OH_JSVM_PumpMessageLoop(JSVM_VM vm, bool* result) { 2086 auto isolate = reinterpret_cast<v8::Isolate*>(vm); 2087 *result = v8::platform::PumpMessageLoop(v8impl::g_platform.get(), isolate); 2088 return JSVM_OK; 2089} 2090 2091JSVM_EXTERN JSVM_Status JSVM_CDECL OH_JSVM_PerformMicrotaskCheckpoint(JSVM_VM vm) { 2092 auto isolate = reinterpret_cast<v8::Isolate*>(vm); 2093 isolate->PerformMicrotaskCheckpoint(); 2094 return JSVM_OK; 2095} 2096 2097// Warning: Keep in-sync with JSVM_Status enum 2098static const char* error_messages[] = { 2099 nullptr, 2100 "Invalid argument", 2101 "An object was expected", 2102 "A string was expected", 2103 "A string or symbol was expected", 2104 "A function was expected", 2105 "A number was expected", 2106 "A boolean was expected", 2107 "An array was expected", 2108 "Unknown failure", 2109 "An exception is pending", 2110 "The async work item was cancelled", 2111 "OH_JSVM_EscapeHandle already called on scope", 2112 "Invalid handle scope usage", 2113 "Invalid callback scope usage", 2114 "Thread-safe function queue is full", 2115 "Thread-safe function handle is closing", 2116 "A bigint was expected", 2117 "A date was expected", 2118 "An arraybuffer was expected", 2119 "A detachable arraybuffer was expected", 2120 "Main thread would deadlock", 2121 "External buffers are not allowed", 2122 "Cannot run JavaScript", 2123}; 2124 2125JSVM_Status JSVM_CDECL OH_JSVM_GetLastErrorInfo( 2126 JSVM_Env env, const JSVM_ExtendedErrorInfo** result) { 2127 CHECK_ENV(env); 2128 CHECK_ARG(env, result); 2129 2130 // The value of the constant below must be updated to reference the last 2131 // message in the `JSVM_Status` enum each time a new error message is added. 2132 // We don't have a jsvm_status_last as this would result in an ABI 2133 // change each time a message was added. 2134 const int last_status = JSVM_CANNOT_RUN_JS; 2135 2136 static_assert(JSVM_ARRAYSIZE(error_messages) == last_status + 1, 2137 "Count of error messages must match count of error values"); 2138 CHECK_LE(env->last_error.errorCode, last_status); 2139 // Wait until someone requests the last error information to fetch the error 2140 // message string 2141 env->last_error.errorMessage = error_messages[env->last_error.errorCode]; 2142 2143 if (env->last_error.errorCode == JSVM_OK) { 2144 jsvm_clear_last_error(env); 2145 } 2146 *result = &(env->last_error); 2147 return JSVM_OK; 2148} 2149 2150JSVM_Status JSVM_CDECL OH_JSVM_CreateFunction(JSVM_Env env, 2151 const char* utf8name, 2152 size_t length, 2153 JSVM_Callback cb, 2154 JSVM_Value* result) { 2155 JSVM_PREAMBLE(env); 2156 CHECK_ARG(env, result); 2157 CHECK_ARG(env, cb); 2158 2159 v8::Local<v8::Function> return_value; 2160 v8::EscapableHandleScope scope(env->isolate); 2161 v8::Local<v8::Function> fn; 2162 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction( 2163 env, cb, &fn)); 2164 return_value = scope.Escape(fn); 2165 2166 if (utf8name != nullptr) { 2167 v8::Local<v8::String> name_string; 2168 CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length); 2169 return_value->SetName(name_string); 2170 } 2171 2172 *result = v8impl::JsValueFromV8LocalValue(return_value); 2173 2174 return GET_RETURN_STATUS(env); 2175} 2176 2177JSVM_Status JSVM_CDECL OH_JSVM_CreateFunctionWithScript(JSVM_Env env, 2178 const char* funcName, 2179 size_t length, 2180 size_t argc, 2181 const JSVM_Value* argv, 2182 JSVM_Value script, 2183 JSVM_Value* result) { 2184 JSVM_PREAMBLE(env); 2185 CHECK_ARG(env, script); 2186 CHECK_ARG(env, result); 2187 if (argc > 0) { 2188 CHECK_ARG(env, argv); 2189 for (auto i = 0; i < argc; i++) { 2190 RETURN_STATUS_IF_FALSE(env, v8impl::V8LocalValueFromJsValue(argv[i])->IsString(), 2191 JSVM_STRING_EXPECTED); 2192 } 2193 } 2194 2195 v8::Local<v8::Value> v8_script = v8impl::V8LocalValueFromJsValue(script); 2196 2197 RETURN_STATUS_IF_FALSE(env, v8_script->IsString(), JSVM_STRING_EXPECTED); 2198 2199 v8::ScriptCompiler::Source scriptSource(v8_script.As<v8::String>()); 2200 2201 v8::Local<v8::Context> context = env->context(); 2202 2203 v8::MaybeLocal<v8::Function> maybe_fun = 2204 v8::ScriptCompiler::CompileFunction(context, &scriptSource, argc, 2205 reinterpret_cast<v8::Local<v8::String>*>(const_cast<JSVM_Value*>(argv))); 2206 2207 CHECK_MAYBE_EMPTY(env, maybe_fun, JSVM_GENERIC_FAILURE); 2208 2209 v8::Local<v8::Function> func = maybe_fun.ToLocalChecked(); 2210 2211 if (funcName != nullptr) { 2212 v8::Local<v8::String> funcNameString; 2213 CHECK_NEW_FROM_UTF8_LEN(env, funcNameString, funcName, length); 2214 func->SetName(funcNameString); 2215 } 2216 2217 *result = 2218 v8impl::JsValueFromV8LocalValue(func); 2219 2220 return GET_RETURN_STATUS(env); 2221} 2222 2223JSVM_Status JSVM_CDECL 2224OH_JSVM_DefineClass(JSVM_Env env, 2225 const char* utf8name, 2226 size_t length, 2227 JSVM_Callback constructor, 2228 size_t propertyCount, 2229 const JSVM_PropertyDescriptor* properties, 2230 JSVM_Value* result) { 2231 JSVM_PREAMBLE(env); 2232 CHECK_ARG(env, result); 2233 CHECK_ARG(env, constructor); 2234 2235 if (propertyCount > 0) { 2236 CHECK_ARG(env, properties); 2237 } 2238 2239 v8::Isolate* isolate = env->isolate; 2240 2241 v8::EscapableHandleScope scope(isolate); 2242 v8::Local<v8::FunctionTemplate> tpl; 2243 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate( 2244 env, constructor, &tpl)); 2245 2246 v8::Local<v8::String> name_string; 2247 CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length); 2248 tpl->SetClassName(name_string); 2249 2250 size_t static_property_count = 0; 2251 for (size_t i = 0; i < propertyCount; i++) { 2252 const JSVM_PropertyDescriptor* p = properties + i; 2253 2254 if ((p->attributes & JSVM_STATIC) != 0) { 2255 // Static properties are handled separately below. 2256 static_property_count++; 2257 continue; 2258 } 2259 2260 v8::Local<v8::Name> property_name; 2261 STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name)); 2262 2263 v8::PropertyAttribute attributes = 2264 v8impl::V8PropertyAttributesFromDescriptor(p); 2265 2266 // This code is similar to that in OH_JSVM_DefineProperties(); the 2267 // difference is it applies to a template instead of an object, 2268 // and preferred PropertyAttribute for lack of PropertyDescriptor 2269 // support on ObjectTemplate. 2270 if (p->getter != nullptr || p->setter != nullptr) { 2271 v8::Local<v8::FunctionTemplate> getter_tpl; 2272 v8::Local<v8::FunctionTemplate> setter_tpl; 2273 if (p->getter != nullptr) { 2274 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate( 2275 env, p->getter, &getter_tpl)); 2276 } 2277 if (p->setter != nullptr) { 2278 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate( 2279 env, p->setter, &setter_tpl)); 2280 } 2281 2282 tpl->PrototypeTemplate()->SetAccessorProperty(property_name, 2283 getter_tpl, 2284 setter_tpl, 2285 attributes, 2286 v8::AccessControl::DEFAULT); 2287 } else if (p->method != nullptr) { 2288 v8::Local<v8::FunctionTemplate> t; 2289 if (p->attributes & JSVM_NO_RECEIVER_CHECK) { 2290 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate( 2291 env, p->method, &t)); 2292 } else { 2293 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate( 2294 env, p->method, &t, v8::Signature::New(isolate, tpl))); 2295 } 2296 2297 tpl->PrototypeTemplate()->Set(property_name, t, attributes); 2298 } else { 2299 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value); 2300 tpl->PrototypeTemplate()->Set(property_name, value, attributes); 2301 } 2302 } 2303 2304 v8::Local<v8::Context> context = env->context(); 2305 *result = v8impl::JsValueFromV8LocalValue( 2306 scope.Escape(tpl->GetFunction(context).ToLocalChecked())); 2307 2308 if (static_property_count > 0) { 2309 std::vector<JSVM_PropertyDescriptor> static_descriptors; 2310 static_descriptors.reserve(static_property_count); 2311 2312 for (size_t i = 0; i < propertyCount; i++) { 2313 const JSVM_PropertyDescriptor* p = properties + i; 2314 if ((p->attributes & JSVM_STATIC) != 0) { 2315 static_descriptors.push_back(*p); 2316 } 2317 } 2318 2319 STATUS_CALL(OH_JSVM_DefineProperties( 2320 env, *result, static_descriptors.size(), static_descriptors.data())); 2321 } 2322 2323 return GET_RETURN_STATUS(env); 2324} 2325 2326JSVM_Status JSVM_CDECL OH_JSVM_GetPropertyNames(JSVM_Env env, 2327 JSVM_Value object, 2328 JSVM_Value* result) { 2329 return OH_JSVM_GetAllPropertyNames( 2330 env, 2331 object, 2332 JSVM_KEY_INCLUDE_PROTOTYPES, 2333 static_cast<JSVM_KeyFilter>(JSVM_KEY_ENUMERABLE | JSVM_KEY_SKIP_SYMBOLS), 2334 JSVM_KEY_NUMBERS_TO_STRINGS, 2335 result); 2336} 2337 2338JSVM_Status JSVM_CDECL 2339OH_JSVM_GetAllPropertyNames(JSVM_Env env, 2340 JSVM_Value object, 2341 JSVM_KeyCollectionMode keyMode, 2342 JSVM_KeyFilter keyFilter, 2343 JSVM_KeyConversion keyConversion, 2344 JSVM_Value* result) { 2345 JSVM_PREAMBLE(env); 2346 CHECK_ARG(env, result); 2347 2348 v8::Local<v8::Context> context = env->context(); 2349 v8::Local<v8::Object> obj; 2350 CHECK_TO_OBJECT(env, context, obj, object); 2351 2352 v8::PropertyFilter filter = v8::PropertyFilter::ALL_PROPERTIES; 2353 if (keyFilter & JSVM_KEY_WRITABLE) { 2354 filter = static_cast<v8::PropertyFilter>(filter | 2355 v8::PropertyFilter::ONLY_WRITABLE); 2356 } 2357 if (keyFilter & JSVM_KEY_ENUMERABLE) { 2358 filter = static_cast<v8::PropertyFilter>( 2359 filter | v8::PropertyFilter::ONLY_ENUMERABLE); 2360 } 2361 if (keyFilter & JSVM_KEY_CONFIGURABLE) { 2362 filter = static_cast<v8::PropertyFilter>( 2363 filter | v8::PropertyFilter::ONLY_CONFIGURABLE); 2364 } 2365 if (keyFilter & JSVM_KEY_SKIP_STRINGS) { 2366 filter = static_cast<v8::PropertyFilter>(filter | 2367 v8::PropertyFilter::SKIP_STRINGS); 2368 } 2369 if (keyFilter & JSVM_KEY_SKIP_SYMBOLS) { 2370 filter = static_cast<v8::PropertyFilter>(filter | 2371 v8::PropertyFilter::SKIP_SYMBOLS); 2372 } 2373 v8::KeyCollectionMode collection_mode; 2374 v8::KeyConversionMode conversion_mode; 2375 2376 switch (keyMode) { 2377 case JSVM_KEY_INCLUDE_PROTOTYPES: 2378 collection_mode = v8::KeyCollectionMode::kIncludePrototypes; 2379 break; 2380 case JSVM_KEY_OWN_ONLY: 2381 collection_mode = v8::KeyCollectionMode::kOwnOnly; 2382 break; 2383 default: 2384 return jsvm_set_last_error(env, JSVM_INVALID_ARG); 2385 } 2386 2387 switch (keyConversion) { 2388 case JSVM_KEY_KEEP_NUMBERS: 2389 conversion_mode = v8::KeyConversionMode::kKeepNumbers; 2390 break; 2391 case JSVM_KEY_NUMBERS_TO_STRINGS: 2392 conversion_mode = v8::KeyConversionMode::kConvertToString; 2393 break; 2394 default: 2395 return jsvm_set_last_error(env, JSVM_INVALID_ARG); 2396 } 2397 2398 v8::MaybeLocal<v8::Array> maybe_all_propertynames = 2399 obj->GetPropertyNames(context, 2400 collection_mode, 2401 filter, 2402 v8::IndexFilter::kIncludeIndices, 2403 conversion_mode); 2404 2405 CHECK_MAYBE_EMPTY_WITH_PREAMBLE( 2406 env, maybe_all_propertynames, JSVM_GENERIC_FAILURE); 2407 2408 *result = 2409 v8impl::JsValueFromV8LocalValue(maybe_all_propertynames.ToLocalChecked()); 2410 return GET_RETURN_STATUS(env); 2411} 2412 2413JSVM_Status JSVM_CDECL OH_JSVM_SetProperty(JSVM_Env env, 2414 JSVM_Value object, 2415 JSVM_Value key, 2416 JSVM_Value value) { 2417 JSVM_PREAMBLE(env); 2418 CHECK_ARG(env, key); 2419 CHECK_ARG(env, value); 2420 2421 v8::Local<v8::Context> context = env->context(); 2422 v8::Local<v8::Object> obj; 2423 2424 CHECK_TO_OBJECT(env, context, obj, object); 2425 2426 v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key); 2427 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 2428 2429 v8::Maybe<bool> set_maybe = obj->Set(context, k, val); 2430 2431 RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), JSVM_GENERIC_FAILURE); 2432 return GET_RETURN_STATUS(env); 2433} 2434 2435JSVM_Status JSVM_CDECL OH_JSVM_HasProperty(JSVM_Env env, 2436 JSVM_Value object, 2437 JSVM_Value key, 2438 bool* result) { 2439 JSVM_PREAMBLE(env); 2440 CHECK_ARG(env, result); 2441 CHECK_ARG(env, key); 2442 2443 v8::Local<v8::Context> context = env->context(); 2444 v8::Local<v8::Object> obj; 2445 2446 CHECK_TO_OBJECT(env, context, obj, object); 2447 2448 v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key); 2449 v8::Maybe<bool> has_maybe = obj->Has(context, k); 2450 2451 CHECK_MAYBE_NOTHING(env, has_maybe, JSVM_GENERIC_FAILURE); 2452 2453 *result = has_maybe.FromMaybe(false); 2454 return GET_RETURN_STATUS(env); 2455} 2456 2457JSVM_Status JSVM_CDECL OH_JSVM_GetProperty(JSVM_Env env, 2458 JSVM_Value object, 2459 JSVM_Value key, 2460 JSVM_Value* result) { 2461 JSVM_PREAMBLE(env); 2462 CHECK_ARG(env, key); 2463 CHECK_ARG(env, result); 2464 2465 v8::Local<v8::Context> context = env->context(); 2466 v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key); 2467 v8::Local<v8::Object> obj; 2468 2469 CHECK_TO_OBJECT(env, context, obj, object); 2470 2471 auto get_maybe = obj->Get(context, k); 2472 2473 CHECK_MAYBE_EMPTY(env, get_maybe, JSVM_GENERIC_FAILURE); 2474 2475 v8::Local<v8::Value> val = get_maybe.ToLocalChecked(); 2476 *result = v8impl::JsValueFromV8LocalValue(val); 2477 return GET_RETURN_STATUS(env); 2478} 2479 2480JSVM_Status JSVM_CDECL OH_JSVM_DeleteProperty(JSVM_Env env, 2481 JSVM_Value object, 2482 JSVM_Value key, 2483 bool* result) { 2484 JSVM_PREAMBLE(env); 2485 CHECK_ARG(env, key); 2486 2487 v8::Local<v8::Context> context = env->context(); 2488 v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key); 2489 v8::Local<v8::Object> obj; 2490 2491 CHECK_TO_OBJECT(env, context, obj, object); 2492 v8::Maybe<bool> delete_maybe = obj->Delete(context, k); 2493 CHECK_MAYBE_NOTHING(env, delete_maybe, JSVM_GENERIC_FAILURE); 2494 2495 if (result != nullptr) *result = delete_maybe.FromMaybe(false); 2496 2497 return GET_RETURN_STATUS(env); 2498} 2499 2500JSVM_Status JSVM_CDECL OH_JSVM_HasOwnProperty(JSVM_Env env, 2501 JSVM_Value object, 2502 JSVM_Value key, 2503 bool* result) { 2504 JSVM_PREAMBLE(env); 2505 CHECK_ARG(env, key); 2506 CHECK_ARG(env, result); 2507 2508 v8::Local<v8::Context> context = env->context(); 2509 v8::Local<v8::Object> obj; 2510 2511 CHECK_TO_OBJECT(env, context, obj, object); 2512 v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key); 2513 RETURN_STATUS_IF_FALSE(env, k->IsName(), JSVM_NAME_EXPECTED); 2514 v8::Maybe<bool> has_maybe = obj->HasOwnProperty(context, k.As<v8::Name>()); 2515 CHECK_MAYBE_NOTHING(env, has_maybe, JSVM_GENERIC_FAILURE); 2516 *result = has_maybe.FromMaybe(false); 2517 2518 return GET_RETURN_STATUS(env); 2519} 2520 2521JSVM_Status JSVM_CDECL OH_JSVM_SetNamedProperty(JSVM_Env env, 2522 JSVM_Value object, 2523 const char* utf8name, 2524 JSVM_Value value) { 2525 JSVM_PREAMBLE(env); 2526 CHECK_ARG(env, value); 2527 2528 v8::Local<v8::Context> context = env->context(); 2529 v8::Local<v8::Object> obj; 2530 2531 CHECK_TO_OBJECT(env, context, obj, object); 2532 2533 v8::Local<v8::Name> key; 2534 CHECK_NEW_FROM_UTF8(env, key, utf8name); 2535 2536 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 2537 2538 v8::Maybe<bool> set_maybe = obj->Set(context, key, val); 2539 2540 RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), JSVM_GENERIC_FAILURE); 2541 return GET_RETURN_STATUS(env); 2542} 2543 2544JSVM_Status JSVM_CDECL OH_JSVM_HasNamedProperty(JSVM_Env env, 2545 JSVM_Value object, 2546 const char* utf8name, 2547 bool* result) { 2548 JSVM_PREAMBLE(env); 2549 CHECK_ARG(env, result); 2550 2551 v8::Local<v8::Context> context = env->context(); 2552 v8::Local<v8::Object> obj; 2553 2554 CHECK_TO_OBJECT(env, context, obj, object); 2555 2556 v8::Local<v8::Name> key; 2557 CHECK_NEW_FROM_UTF8(env, key, utf8name); 2558 2559 v8::Maybe<bool> has_maybe = obj->Has(context, key); 2560 2561 CHECK_MAYBE_NOTHING(env, has_maybe, JSVM_GENERIC_FAILURE); 2562 2563 *result = has_maybe.FromMaybe(false); 2564 return GET_RETURN_STATUS(env); 2565} 2566 2567JSVM_Status JSVM_CDECL OH_JSVM_GetNamedProperty(JSVM_Env env, 2568 JSVM_Value object, 2569 const char* utf8name, 2570 JSVM_Value* result) { 2571 JSVM_PREAMBLE(env); 2572 CHECK_ARG(env, result); 2573 2574 v8::Local<v8::Context> context = env->context(); 2575 2576 v8::Local<v8::Name> key; 2577 CHECK_NEW_FROM_UTF8(env, key, utf8name); 2578 2579 v8::Local<v8::Object> obj; 2580 2581 CHECK_TO_OBJECT(env, context, obj, object); 2582 2583 auto get_maybe = obj->Get(context, key); 2584 2585 CHECK_MAYBE_EMPTY(env, get_maybe, JSVM_GENERIC_FAILURE); 2586 2587 v8::Local<v8::Value> val = get_maybe.ToLocalChecked(); 2588 *result = v8impl::JsValueFromV8LocalValue(val); 2589 return GET_RETURN_STATUS(env); 2590} 2591 2592JSVM_Status JSVM_CDECL OH_JSVM_SetElement(JSVM_Env env, 2593 JSVM_Value object, 2594 uint32_t index, 2595 JSVM_Value value) { 2596 JSVM_PREAMBLE(env); 2597 CHECK_ARG(env, value); 2598 2599 v8::Local<v8::Context> context = env->context(); 2600 v8::Local<v8::Object> obj; 2601 2602 CHECK_TO_OBJECT(env, context, obj, object); 2603 2604 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 2605 auto set_maybe = obj->Set(context, index, val); 2606 2607 RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), JSVM_GENERIC_FAILURE); 2608 2609 return GET_RETURN_STATUS(env); 2610} 2611 2612JSVM_Status JSVM_CDECL OH_JSVM_HasElement(JSVM_Env env, 2613 JSVM_Value object, 2614 uint32_t index, 2615 bool* result) { 2616 JSVM_PREAMBLE(env); 2617 CHECK_ARG(env, result); 2618 2619 v8::Local<v8::Context> context = env->context(); 2620 v8::Local<v8::Object> obj; 2621 2622 CHECK_TO_OBJECT(env, context, obj, object); 2623 2624 v8::Maybe<bool> has_maybe = obj->Has(context, index); 2625 2626 CHECK_MAYBE_NOTHING(env, has_maybe, JSVM_GENERIC_FAILURE); 2627 2628 *result = has_maybe.FromMaybe(false); 2629 return GET_RETURN_STATUS(env); 2630} 2631 2632JSVM_Status JSVM_CDECL OH_JSVM_GetElement(JSVM_Env env, 2633 JSVM_Value object, 2634 uint32_t index, 2635 JSVM_Value* result) { 2636 JSVM_PREAMBLE(env); 2637 CHECK_ARG(env, result); 2638 2639 v8::Local<v8::Context> context = env->context(); 2640 v8::Local<v8::Object> obj; 2641 2642 CHECK_TO_OBJECT(env, context, obj, object); 2643 2644 auto get_maybe = obj->Get(context, index); 2645 2646 CHECK_MAYBE_EMPTY(env, get_maybe, JSVM_GENERIC_FAILURE); 2647 2648 *result = v8impl::JsValueFromV8LocalValue(get_maybe.ToLocalChecked()); 2649 return GET_RETURN_STATUS(env); 2650} 2651 2652JSVM_Status JSVM_CDECL OH_JSVM_DeleteElement(JSVM_Env env, 2653 JSVM_Value object, 2654 uint32_t index, 2655 bool* result) { 2656 JSVM_PREAMBLE(env); 2657 2658 v8::Local<v8::Context> context = env->context(); 2659 v8::Local<v8::Object> obj; 2660 2661 CHECK_TO_OBJECT(env, context, obj, object); 2662 v8::Maybe<bool> delete_maybe = obj->Delete(context, index); 2663 CHECK_MAYBE_NOTHING(env, delete_maybe, JSVM_GENERIC_FAILURE); 2664 2665 if (result != nullptr) *result = delete_maybe.FromMaybe(false); 2666 2667 return GET_RETURN_STATUS(env); 2668} 2669 2670JSVM_Status JSVM_CDECL 2671OH_JSVM_DefineProperties(JSVM_Env env, 2672 JSVM_Value object, 2673 size_t propertyCount, 2674 const JSVM_PropertyDescriptor* properties) { 2675 JSVM_PREAMBLE(env); 2676 if (propertyCount > 0) { 2677 CHECK_ARG(env, properties); 2678 } 2679 2680 v8::Local<v8::Context> context = env->context(); 2681 2682 v8::Local<v8::Object> obj; 2683 CHECK_TO_OBJECT(env, context, obj, object); 2684 2685 for (size_t i = 0; i < propertyCount; i++) { 2686 const JSVM_PropertyDescriptor* p = &properties[i]; 2687 2688 v8::Local<v8::Name> property_name; 2689 STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name)); 2690 2691 if (p->getter != nullptr || p->setter != nullptr) { 2692 v8::Local<v8::Function> local_getter; 2693 v8::Local<v8::Function> local_setter; 2694 2695 if (p->getter != nullptr) { 2696 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction( 2697 env, p->getter, &local_getter)); 2698 } 2699 if (p->setter != nullptr) { 2700 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction( 2701 env, p->setter, &local_setter)); 2702 } 2703 2704 v8::PropertyDescriptor descriptor(local_getter, local_setter); 2705 descriptor.set_enumerable((p->attributes & JSVM_ENUMERABLE) != 0); 2706 descriptor.set_configurable((p->attributes & JSVM_CONFIGURABLE) != 0); 2707 2708 auto define_maybe = 2709 obj->DefineProperty(context, property_name, descriptor); 2710 2711 if (!define_maybe.FromMaybe(false)) { 2712 return jsvm_set_last_error(env, JSVM_INVALID_ARG); 2713 } 2714 } else if (p->method != nullptr) { 2715 v8::Local<v8::Function> method; 2716 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction( 2717 env, p->method, &method)); 2718 v8::PropertyDescriptor descriptor(method, 2719 (p->attributes & JSVM_WRITABLE) != 0); 2720 descriptor.set_enumerable((p->attributes & JSVM_ENUMERABLE) != 0); 2721 descriptor.set_configurable((p->attributes & JSVM_CONFIGURABLE) != 0); 2722 2723 auto define_maybe = 2724 obj->DefineProperty(context, property_name, descriptor); 2725 2726 if (!define_maybe.FromMaybe(false)) { 2727 return jsvm_set_last_error(env, JSVM_GENERIC_FAILURE); 2728 } 2729 } else { 2730 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value); 2731 bool defined_successfully = false; 2732 2733 if ((p->attributes & JSVM_ENUMERABLE) && 2734 (p->attributes & JSVM_WRITABLE) && 2735 (p->attributes & JSVM_CONFIGURABLE)) { 2736 // Use a fast path for this type of data property. 2737 auto define_maybe = 2738 obj->CreateDataProperty(context, property_name, value); 2739 defined_successfully = define_maybe.FromMaybe(false); 2740 } else { 2741 v8::PropertyDescriptor descriptor(value, 2742 (p->attributes & JSVM_WRITABLE) != 0); 2743 descriptor.set_enumerable((p->attributes & JSVM_ENUMERABLE) != 0); 2744 descriptor.set_configurable((p->attributes & JSVM_CONFIGURABLE) != 0); 2745 2746 auto define_maybe = 2747 obj->DefineProperty(context, property_name, descriptor); 2748 defined_successfully = define_maybe.FromMaybe(false); 2749 } 2750 2751 if (!defined_successfully) { 2752 return jsvm_set_last_error(env, JSVM_INVALID_ARG); 2753 } 2754 } 2755 } 2756 2757 return GET_RETURN_STATUS(env); 2758} 2759 2760JSVM_Status JSVM_CDECL OH_JSVM_ObjectFreeze(JSVM_Env env, JSVM_Value object) { 2761 JSVM_PREAMBLE(env); 2762 2763 v8::Local<v8::Context> context = env->context(); 2764 v8::Local<v8::Object> obj; 2765 2766 CHECK_TO_OBJECT(env, context, obj, object); 2767 2768 v8::Maybe<bool> set_frozen = 2769 obj->SetIntegrityLevel(context, v8::IntegrityLevel::kFrozen); 2770 2771 RETURN_STATUS_IF_FALSE_WITH_PREAMBLE( 2772 env, set_frozen.FromMaybe(false), JSVM_GENERIC_FAILURE); 2773 2774 return GET_RETURN_STATUS(env); 2775} 2776 2777JSVM_Status JSVM_CDECL OH_JSVM_ObjectSeal(JSVM_Env env, JSVM_Value object) { 2778 JSVM_PREAMBLE(env); 2779 2780 v8::Local<v8::Context> context = env->context(); 2781 v8::Local<v8::Object> obj; 2782 2783 CHECK_TO_OBJECT(env, context, obj, object); 2784 2785 v8::Maybe<bool> set_sealed = 2786 obj->SetIntegrityLevel(context, v8::IntegrityLevel::kSealed); 2787 2788 RETURN_STATUS_IF_FALSE_WITH_PREAMBLE( 2789 env, set_sealed.FromMaybe(false), JSVM_GENERIC_FAILURE); 2790 2791 return GET_RETURN_STATUS(env); 2792} 2793 2794JSVM_Status JSVM_CDECL OH_JSVM_IsArray(JSVM_Env env, 2795 JSVM_Value value, 2796 bool* result) { 2797 CHECK_ENV(env); 2798 CHECK_ARG(env, value); 2799 CHECK_ARG(env, result); 2800 2801 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 2802 2803 *result = val->IsArray(); 2804 return jsvm_clear_last_error(env); 2805} 2806 2807JSVM_Status JSVM_CDECL OH_JSVM_IsRegExp(JSVM_Env env, 2808 JSVM_Value value, 2809 bool* result) { 2810 CHECK_ENV(env); 2811 CHECK_ARG(env, value); 2812 CHECK_ARG(env, result); 2813 2814 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 2815 2816 *result = val->IsRegExp(); 2817 return jsvm_clear_last_error(env); 2818} 2819 2820JSVM_Status JSVM_CDECL OH_JSVM_GetArrayLength(JSVM_Env env, 2821 JSVM_Value value, 2822 uint32_t* result) { 2823 JSVM_PREAMBLE(env); 2824 CHECK_ARG(env, value); 2825 CHECK_ARG(env, result); 2826 2827 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 2828 RETURN_STATUS_IF_FALSE(env, val->IsArray(), JSVM_ARRAY_EXPECTED); 2829 2830 v8::Local<v8::Array> arr = val.As<v8::Array>(); 2831 *result = arr->Length(); 2832 2833 return GET_RETURN_STATUS(env); 2834} 2835 2836JSVM_Status JSVM_CDECL OH_JSVM_StrictEquals(JSVM_Env env, 2837 JSVM_Value lhs, 2838 JSVM_Value rhs, 2839 bool* result) { 2840 JSVM_PREAMBLE(env); 2841 CHECK_ARG(env, lhs); 2842 CHECK_ARG(env, rhs); 2843 CHECK_ARG(env, result); 2844 2845 v8::Local<v8::Value> a = v8impl::V8LocalValueFromJsValue(lhs); 2846 v8::Local<v8::Value> b = v8impl::V8LocalValueFromJsValue(rhs); 2847 2848 *result = a->StrictEquals(b); 2849 return GET_RETURN_STATUS(env); 2850} 2851 2852JSVM_Status JSVM_CDECL OH_JSVM_Equals(JSVM_Env env, 2853 JSVM_Value lhs, 2854 JSVM_Value rhs, 2855 bool* result) { 2856 JSVM_PREAMBLE(env); 2857 CHECK_ARG(env, lhs); 2858 CHECK_ARG(env, rhs); 2859 CHECK_ARG(env, result); 2860 2861 v8::Local<v8::Value> a = v8impl::V8LocalValueFromJsValue(lhs); 2862 v8::Local<v8::Value> b = v8impl::V8LocalValueFromJsValue(rhs); 2863 v8::Local<v8::Context> context = env->context(); 2864 2865 *result = a->Equals(context, b).FromJust(); 2866 return GET_RETURN_STATUS(env); 2867} 2868 2869JSVM_Status JSVM_CDECL OH_JSVM_GetPrototype(JSVM_Env env, 2870 JSVM_Value object, 2871 JSVM_Value* result) { 2872 JSVM_PREAMBLE(env); 2873 CHECK_ARG(env, result); 2874 2875 v8::Local<v8::Context> context = env->context(); 2876 2877 v8::Local<v8::Object> obj; 2878 CHECK_TO_OBJECT(env, context, obj, object); 2879 2880 v8::Local<v8::Value> val = obj->GetPrototype(); 2881 *result = v8impl::JsValueFromV8LocalValue(val); 2882 return GET_RETURN_STATUS(env); 2883} 2884 2885JSVM_Status JSVM_CDECL OH_JSVM_CreateObject(JSVM_Env env, JSVM_Value* result) { 2886 CHECK_ENV(env); 2887 CHECK_ARG(env, result); 2888 2889 *result = v8impl::JsValueFromV8LocalValue(v8::Object::New(env->isolate)); 2890 2891 return jsvm_clear_last_error(env); 2892} 2893 2894JSVM_Status JSVM_CDECL OH_JSVM_CreateArray(JSVM_Env env, JSVM_Value* result) { 2895 CHECK_ENV(env); 2896 CHECK_ARG(env, result); 2897 2898 *result = v8impl::JsValueFromV8LocalValue(v8::Array::New(env->isolate)); 2899 2900 return jsvm_clear_last_error(env); 2901} 2902 2903JSVM_Status JSVM_CDECL OH_JSVM_CreateArrayWithLength(JSVM_Env env, 2904 size_t length, 2905 JSVM_Value* result) { 2906 CHECK_ENV(env); 2907 CHECK_ARG(env, result); 2908 2909 *result = 2910 v8impl::JsValueFromV8LocalValue(v8::Array::New(env->isolate, length)); 2911 2912 return jsvm_clear_last_error(env); 2913} 2914 2915JSVM_Status JSVM_CDECL OH_JSVM_CreateStringLatin1(JSVM_Env env, 2916 const char* str, 2917 size_t length, 2918 JSVM_Value* result) { 2919 return v8impl::NewString(env, str, length, result, [&](v8::Isolate* isolate) { 2920 return v8::String::NewFromOneByte(isolate, 2921 reinterpret_cast<const uint8_t*>(str), 2922 v8::NewStringType::kNormal, 2923 length); 2924 }); 2925} 2926 2927JSVM_Status JSVM_CDECL OH_JSVM_CreateStringUtf8(JSVM_Env env, 2928 const char* str, 2929 size_t length, 2930 JSVM_Value* result) { 2931 return v8impl::NewString(env, str, length, result, [&](v8::Isolate* isolate) { 2932 return v8::String::NewFromUtf8( 2933 isolate, str, v8::NewStringType::kNormal, static_cast<int>(length)); 2934 }); 2935} 2936 2937JSVM_Status JSVM_CDECL OH_JSVM_CreateStringUtf16(JSVM_Env env, 2938 const char16_t* str, 2939 size_t length, 2940 JSVM_Value* result) { 2941 return v8impl::NewString(env, str, length, result, [&](v8::Isolate* isolate) { 2942 return v8::String::NewFromTwoByte(isolate, 2943 reinterpret_cast<const uint16_t*>(str), 2944 v8::NewStringType::kNormal, 2945 length); 2946 }); 2947} 2948 2949JSVM_Status JSVM_CDECL OH_JSVM_CreateDouble(JSVM_Env env, 2950 double value, 2951 JSVM_Value* result) { 2952 CHECK_ENV(env); 2953 CHECK_ARG(env, result); 2954 2955 *result = 2956 v8impl::JsValueFromV8LocalValue(v8::Number::New(env->isolate, value)); 2957 2958 return jsvm_clear_last_error(env); 2959} 2960 2961JSVM_Status JSVM_CDECL OH_JSVM_CreateInt32(JSVM_Env env, 2962 int32_t value, 2963 JSVM_Value* result) { 2964 CHECK_ENV(env); 2965 CHECK_ARG(env, result); 2966 2967 *result = 2968 v8impl::JsValueFromV8LocalValue(v8::Integer::New(env->isolate, value)); 2969 2970 return jsvm_clear_last_error(env); 2971} 2972 2973JSVM_Status JSVM_CDECL OH_JSVM_CreateUint32(JSVM_Env env, 2974 uint32_t value, 2975 JSVM_Value* result) { 2976 CHECK_ENV(env); 2977 CHECK_ARG(env, result); 2978 2979 *result = v8impl::JsValueFromV8LocalValue( 2980 v8::Integer::NewFromUnsigned(env->isolate, value)); 2981 2982 return jsvm_clear_last_error(env); 2983} 2984 2985JSVM_Status JSVM_CDECL OH_JSVM_CreateInt64(JSVM_Env env, 2986 int64_t value, 2987 JSVM_Value* result) { 2988 CHECK_ENV(env); 2989 CHECK_ARG(env, result); 2990 2991 *result = v8impl::JsValueFromV8LocalValue( 2992 v8::Number::New(env->isolate, static_cast<double>(value))); 2993 2994 return jsvm_clear_last_error(env); 2995} 2996 2997JSVM_Status JSVM_CDECL OH_JSVM_CreateBigintInt64(JSVM_Env env, 2998 int64_t value, 2999 JSVM_Value* result) { 3000 CHECK_ENV(env); 3001 CHECK_ARG(env, result); 3002 3003 *result = 3004 v8impl::JsValueFromV8LocalValue(v8::BigInt::New(env->isolate, value)); 3005 3006 return jsvm_clear_last_error(env); 3007} 3008 3009JSVM_Status JSVM_CDECL OH_JSVM_CreateBigintUint64(JSVM_Env env, 3010 uint64_t value, 3011 JSVM_Value* result) { 3012 CHECK_ENV(env); 3013 CHECK_ARG(env, result); 3014 3015 *result = v8impl::JsValueFromV8LocalValue( 3016 v8::BigInt::NewFromUnsigned(env->isolate, value)); 3017 3018 return jsvm_clear_last_error(env); 3019} 3020 3021JSVM_Status JSVM_CDECL OH_JSVM_CreateBigintWords(JSVM_Env env, 3022 int signBit, 3023 size_t wordCount, 3024 const uint64_t* words, 3025 JSVM_Value* result) { 3026 JSVM_PREAMBLE(env); 3027 CHECK_ARG(env, words); 3028 CHECK_ARG(env, result); 3029 3030 v8::Local<v8::Context> context = env->context(); 3031 3032 RETURN_STATUS_IF_FALSE(env, wordCount <= INT_MAX, JSVM_INVALID_ARG); 3033 3034 v8::MaybeLocal<v8::BigInt> b = 3035 v8::BigInt::NewFromWords(context, signBit, wordCount, words); 3036 3037 CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, b, JSVM_GENERIC_FAILURE); 3038 3039 *result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked()); 3040 return GET_RETURN_STATUS(env); 3041} 3042 3043JSVM_Status JSVM_CDECL OH_JSVM_GetBoolean(JSVM_Env env, 3044 bool value, 3045 JSVM_Value* result) { 3046 CHECK_ENV(env); 3047 CHECK_ARG(env, result); 3048 3049 v8::Isolate* isolate = env->isolate; 3050 3051 if (value) { 3052 *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate)); 3053 } else { 3054 *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate)); 3055 } 3056 3057 return jsvm_clear_last_error(env); 3058} 3059 3060JSVM_Status JSVM_CDECL OH_JSVM_CreateSymbol(JSVM_Env env, 3061 JSVM_Value description, 3062 JSVM_Value* result) { 3063 CHECK_ENV(env); 3064 CHECK_ARG(env, result); 3065 3066 v8::Isolate* isolate = env->isolate; 3067 3068 if (description == nullptr) { 3069 *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate)); 3070 } else { 3071 v8::Local<v8::Value> desc = v8impl::V8LocalValueFromJsValue(description); 3072 RETURN_STATUS_IF_FALSE(env, desc->IsString(), JSVM_STRING_EXPECTED); 3073 3074 *result = v8impl::JsValueFromV8LocalValue( 3075 v8::Symbol::New(isolate, desc.As<v8::String>())); 3076 } 3077 3078 return jsvm_clear_last_error(env); 3079} 3080 3081JSVM_Status JSVM_CDECL OH_JSVM_SymbolFor(JSVM_Env env, 3082 const char* utf8description, 3083 size_t length, 3084 JSVM_Value* result) { 3085 CHECK_ENV(env); 3086 CHECK_ARG(env, result); 3087 3088 JSVM_Value js_description_string; 3089 STATUS_CALL(OH_JSVM_CreateStringUtf8( 3090 env, utf8description, length, &js_description_string)); 3091 v8::Local<v8::String> description_string = 3092 v8impl::V8LocalValueFromJsValue(js_description_string).As<v8::String>(); 3093 3094 *result = v8impl::JsValueFromV8LocalValue( 3095 v8::Symbol::For(env->isolate, description_string)); 3096 3097 return jsvm_clear_last_error(env); 3098} 3099 3100static inline JSVM_Status set_error_code(JSVM_Env env, 3101 v8::Local<v8::Value> error, 3102 JSVM_Value code, 3103 const char* code_cstring) { 3104 if ((code != nullptr) || (code_cstring != nullptr)) { 3105 v8::Local<v8::Context> context = env->context(); 3106 v8::Local<v8::Object> err_object = error.As<v8::Object>(); 3107 3108 v8::Local<v8::Value> code_value = v8impl::V8LocalValueFromJsValue(code); 3109 if (code != nullptr) { 3110 code_value = v8impl::V8LocalValueFromJsValue(code); 3111 RETURN_STATUS_IF_FALSE(env, code_value->IsString(), JSVM_STRING_EXPECTED); 3112 } else { 3113 CHECK_NEW_FROM_UTF8(env, code_value, code_cstring); 3114 } 3115 3116 v8::Local<v8::Name> code_key; 3117 CHECK_NEW_FROM_UTF8(env, code_key, "code"); 3118 3119 v8::Maybe<bool> set_maybe = err_object->Set(context, code_key, code_value); 3120 RETURN_STATUS_IF_FALSE( 3121 env, set_maybe.FromMaybe(false), JSVM_GENERIC_FAILURE); 3122 } 3123 return JSVM_OK; 3124} 3125 3126JSVM_Status JSVM_CDECL OH_JSVM_CreateError(JSVM_Env env, 3127 JSVM_Value code, 3128 JSVM_Value msg, 3129 JSVM_Value* result) { 3130 CHECK_ENV(env); 3131 CHECK_ARG(env, msg); 3132 CHECK_ARG(env, result); 3133 3134 v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg); 3135 RETURN_STATUS_IF_FALSE(env, message_value->IsString(), JSVM_STRING_EXPECTED); 3136 3137 v8::Local<v8::Value> error_obj = 3138 v8::Exception::Error(message_value.As<v8::String>()); 3139 STATUS_CALL(set_error_code(env, error_obj, code, nullptr)); 3140 3141 *result = v8impl::JsValueFromV8LocalValue(error_obj); 3142 3143 return jsvm_clear_last_error(env); 3144} 3145 3146JSVM_Status JSVM_CDECL OH_JSVM_CreateTypeError(JSVM_Env env, 3147 JSVM_Value code, 3148 JSVM_Value msg, 3149 JSVM_Value* result) { 3150 CHECK_ENV(env); 3151 CHECK_ARG(env, msg); 3152 CHECK_ARG(env, result); 3153 3154 v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg); 3155 RETURN_STATUS_IF_FALSE(env, message_value->IsString(), JSVM_STRING_EXPECTED); 3156 3157 v8::Local<v8::Value> error_obj = 3158 v8::Exception::TypeError(message_value.As<v8::String>()); 3159 STATUS_CALL(set_error_code(env, error_obj, code, nullptr)); 3160 3161 *result = v8impl::JsValueFromV8LocalValue(error_obj); 3162 3163 return jsvm_clear_last_error(env); 3164} 3165 3166JSVM_Status JSVM_CDECL OH_JSVM_CreateRangeError(JSVM_Env env, 3167 JSVM_Value code, 3168 JSVM_Value msg, 3169 JSVM_Value* result) { 3170 CHECK_ENV(env); 3171 CHECK_ARG(env, msg); 3172 CHECK_ARG(env, result); 3173 3174 v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg); 3175 RETURN_STATUS_IF_FALSE(env, message_value->IsString(), JSVM_STRING_EXPECTED); 3176 3177 v8::Local<v8::Value> error_obj = 3178 v8::Exception::RangeError(message_value.As<v8::String>()); 3179 STATUS_CALL(set_error_code(env, error_obj, code, nullptr)); 3180 3181 *result = v8impl::JsValueFromV8LocalValue(error_obj); 3182 3183 return jsvm_clear_last_error(env); 3184} 3185 3186JSVM_Status JSVM_CDECL OH_JSVM_CreateSyntaxError(JSVM_Env env, 3187 JSVM_Value code, 3188 JSVM_Value msg, 3189 JSVM_Value* result) { 3190 CHECK_ENV(env); 3191 CHECK_ARG(env, msg); 3192 CHECK_ARG(env, result); 3193 3194 v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg); 3195 RETURN_STATUS_IF_FALSE(env, message_value->IsString(), JSVM_STRING_EXPECTED); 3196 3197 v8::Local<v8::Value> error_obj = 3198 v8::Exception::SyntaxError(message_value.As<v8::String>()); 3199 STATUS_CALL(set_error_code(env, error_obj, code, nullptr)); 3200 3201 *result = v8impl::JsValueFromV8LocalValue(error_obj); 3202 3203 return jsvm_clear_last_error(env); 3204} 3205 3206JSVM_Status JSVM_CDECL OH_JSVM_Typeof(JSVM_Env env, 3207 JSVM_Value value, 3208 JSVM_ValueType* result) { 3209 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 3210 // JS exceptions. 3211 CHECK_ENV(env); 3212 CHECK_ARG(env, value); 3213 CHECK_ARG(env, result); 3214 3215 v8::Local<v8::Value> v = v8impl::V8LocalValueFromJsValue(value); 3216 3217 if (v->IsNumber()) { 3218 *result = JSVM_NUMBER; 3219 } else if (v->IsBigInt()) { 3220 *result = JSVM_BIGINT; 3221 } else if (v->IsString()) { 3222 *result = JSVM_STRING; 3223 } else if (v->IsFunction()) { 3224 // This test has to come before IsObject because IsFunction 3225 // implies IsObject 3226 *result = JSVM_FUNCTION; 3227 } else if (v->IsExternal()) { 3228 // This test has to come before IsObject because IsExternal 3229 // implies IsObject 3230 *result = JSVM_EXTERNAL; 3231 } else if (v->IsObject()) { 3232 *result = JSVM_OBJECT; 3233 } else if (v->IsBoolean()) { 3234 *result = JSVM_BOOLEAN; 3235 } else if (v->IsUndefined()) { 3236 *result = JSVM_UNDEFINED; 3237 } else if (v->IsSymbol()) { 3238 *result = JSVM_SYMBOL; 3239 } else if (v->IsNull()) { 3240 *result = JSVM_NULL; 3241 } else { 3242 // Should not get here unless V8 has added some new kind of value. 3243 return jsvm_set_last_error(env, JSVM_INVALID_ARG); 3244 } 3245 3246 return jsvm_clear_last_error(env); 3247} 3248 3249JSVM_Status JSVM_CDECL OH_JSVM_GetUndefined(JSVM_Env env, JSVM_Value* result) { 3250 CHECK_ENV(env); 3251 CHECK_ARG(env, result); 3252 3253 *result = v8impl::JsValueFromV8LocalValue(v8::Undefined(env->isolate)); 3254 3255 return jsvm_clear_last_error(env); 3256} 3257 3258JSVM_Status JSVM_CDECL OH_JSVM_GetNull(JSVM_Env env, JSVM_Value* result) { 3259 CHECK_ENV(env); 3260 CHECK_ARG(env, result); 3261 3262 *result = v8impl::JsValueFromV8LocalValue(v8::Null(env->isolate)); 3263 3264 return jsvm_clear_last_error(env); 3265} 3266 3267// Gets all callback info in a single call. (Ugly, but faster.) 3268JSVM_Status JSVM_CDECL OH_JSVM_GetCbInfo( 3269 JSVM_Env env, // [in] JSVM environment handle 3270 JSVM_CallbackInfo cbinfo, // [in] Opaque callback-info handle 3271 size_t* argc, // [in-out] Specifies the size of the provided argv array 3272 // and receives the actual count of args. 3273 JSVM_Value* argv, // [out] Array of values 3274 JSVM_Value* thisArg, // [out] Receives the JS 'this' arg for the call 3275 void** data) { // [out] Receives the data pointer for the callback. 3276 CHECK_ENV(env); 3277 CHECK_ARG(env, cbinfo); 3278 3279 v8impl::CallbackWrapper* info = 3280 reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo); 3281 3282 if (argv != nullptr) { 3283 CHECK_ARG(env, argc); 3284 info->Args(argv, *argc); 3285 } 3286 if (argc != nullptr) { 3287 *argc = info->ArgsLength(); 3288 } 3289 if (thisArg != nullptr) { 3290 *thisArg = info->This(); 3291 } 3292 if (data != nullptr) { 3293 *data = info->Data(); 3294 } 3295 3296 return jsvm_clear_last_error(env); 3297} 3298 3299JSVM_Status JSVM_CDECL OH_JSVM_GetNewTarget(JSVM_Env env, 3300 JSVM_CallbackInfo cbinfo, 3301 JSVM_Value* result) { 3302 CHECK_ENV(env); 3303 CHECK_ARG(env, cbinfo); 3304 CHECK_ARG(env, result); 3305 3306 v8impl::CallbackWrapper* info = 3307 reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo); 3308 3309 *result = info->GetNewTarget(); 3310 return jsvm_clear_last_error(env); 3311} 3312 3313JSVM_Status JSVM_CDECL OH_JSVM_CallFunction(JSVM_Env env, 3314 JSVM_Value recv, 3315 JSVM_Value func, 3316 size_t argc, 3317 const JSVM_Value* argv, 3318 JSVM_Value* result) { 3319 JSVM_PREAMBLE(env); 3320 CHECK_ARG(env, recv); 3321 if (argc > 0) { 3322 CHECK_ARG(env, argv); 3323 } 3324 3325 v8::Local<v8::Context> context = env->context(); 3326 3327 v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv); 3328 3329 v8::Local<v8::Function> v8func; 3330 CHECK_TO_FUNCTION(env, v8func, func); 3331 3332 auto maybe = v8func->Call( 3333 context, 3334 v8recv, 3335 argc, 3336 reinterpret_cast<v8::Local<v8::Value>*>(const_cast<JSVM_Value*>(argv))); 3337 3338 if (try_catch.HasCaught()) { 3339 return jsvm_set_last_error(env, JSVM_PENDING_EXCEPTION); 3340 } else { 3341 if (result != nullptr) { 3342 CHECK_MAYBE_EMPTY(env, maybe, JSVM_GENERIC_FAILURE); 3343 *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked()); 3344 } 3345 return jsvm_clear_last_error(env); 3346 } 3347} 3348 3349JSVM_Status JSVM_CDECL OH_JSVM_GetGlobal(JSVM_Env env, JSVM_Value* result) { 3350 CHECK_ENV(env); 3351 CHECK_ARG(env, result); 3352 3353 *result = v8impl::JsValueFromV8LocalValue(env->context()->Global()); 3354 3355 return jsvm_clear_last_error(env); 3356} 3357 3358JSVM_Status JSVM_CDECL OH_JSVM_Throw(JSVM_Env env, JSVM_Value error) { 3359 JSVM_PREAMBLE(env); 3360 CHECK_ARG(env, error); 3361 3362 v8::Isolate* isolate = env->isolate; 3363 3364 isolate->ThrowException(v8impl::V8LocalValueFromJsValue(error)); 3365 // any VM calls after this point and before returning 3366 // to the javascript invoker will fail 3367 return jsvm_clear_last_error(env); 3368} 3369 3370JSVM_Status JSVM_CDECL OH_JSVM_ThrowError(JSVM_Env env, 3371 const char* code, 3372 const char* msg) { 3373 JSVM_PREAMBLE(env); 3374 3375 v8::Isolate* isolate = env->isolate; 3376 v8::Local<v8::String> str; 3377 CHECK_NEW_FROM_UTF8(env, str, msg); 3378 3379 v8::Local<v8::Value> error_obj = v8::Exception::Error(str); 3380 STATUS_CALL(set_error_code(env, error_obj, nullptr, code)); 3381 3382 isolate->ThrowException(error_obj); 3383 // any VM calls after this point and before returning 3384 // to the javascript invoker will fail 3385 return jsvm_clear_last_error(env); 3386} 3387 3388JSVM_Status JSVM_CDECL OH_JSVM_ThrowTypeError(JSVM_Env env, 3389 const char* code, 3390 const char* msg) { 3391 JSVM_PREAMBLE(env); 3392 3393 v8::Isolate* isolate = env->isolate; 3394 v8::Local<v8::String> str; 3395 CHECK_NEW_FROM_UTF8(env, str, msg); 3396 3397 v8::Local<v8::Value> error_obj = v8::Exception::TypeError(str); 3398 STATUS_CALL(set_error_code(env, error_obj, nullptr, code)); 3399 3400 isolate->ThrowException(error_obj); 3401 // any VM calls after this point and before returning 3402 // to the javascript invoker will fail 3403 return jsvm_clear_last_error(env); 3404} 3405 3406JSVM_Status JSVM_CDECL OH_JSVM_ThrowRangeError(JSVM_Env env, 3407 const char* code, 3408 const char* msg) { 3409 JSVM_PREAMBLE(env); 3410 3411 v8::Isolate* isolate = env->isolate; 3412 v8::Local<v8::String> str; 3413 CHECK_NEW_FROM_UTF8(env, str, msg); 3414 3415 v8::Local<v8::Value> error_obj = v8::Exception::RangeError(str); 3416 STATUS_CALL(set_error_code(env, error_obj, nullptr, code)); 3417 3418 isolate->ThrowException(error_obj); 3419 // any VM calls after this point and before returning 3420 // to the javascript invoker will fail 3421 return jsvm_clear_last_error(env); 3422} 3423 3424JSVM_Status JSVM_CDECL OH_JSVM_ThrowSyntaxError(JSVM_Env env, 3425 const char* code, 3426 const char* msg) { 3427 JSVM_PREAMBLE(env); 3428 3429 v8::Isolate* isolate = env->isolate; 3430 v8::Local<v8::String> str; 3431 CHECK_NEW_FROM_UTF8(env, str, msg); 3432 3433 v8::Local<v8::Value> error_obj = v8::Exception::SyntaxError(str); 3434 STATUS_CALL(set_error_code(env, error_obj, nullptr, code)); 3435 3436 isolate->ThrowException(error_obj); 3437 // any VM calls after this point and before returning 3438 // to the javascript invoker will fail 3439 return jsvm_clear_last_error(env); 3440} 3441 3442JSVM_Status JSVM_CDECL OH_JSVM_IsError(JSVM_Env env, 3443 JSVM_Value value, 3444 bool* result) { 3445 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot 3446 // throw JS exceptions. 3447 CHECK_ENV(env); 3448 CHECK_ARG(env, value); 3449 CHECK_ARG(env, result); 3450 3451 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 3452 *result = val->IsNativeError(); 3453 3454 return jsvm_clear_last_error(env); 3455} 3456 3457JSVM_Status JSVM_CDECL OH_JSVM_GetValueDouble(JSVM_Env env, 3458 JSVM_Value value, 3459 double* result) { 3460 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 3461 // JS exceptions. 3462 CHECK_ENV(env); 3463 CHECK_ARG(env, value); 3464 CHECK_ARG(env, result); 3465 3466 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 3467 RETURN_STATUS_IF_FALSE(env, val->IsNumber(), JSVM_NUMBER_EXPECTED); 3468 3469 *result = val.As<v8::Number>()->Value(); 3470 3471 return jsvm_clear_last_error(env); 3472} 3473 3474JSVM_Status JSVM_CDECL OH_JSVM_GetValueInt32(JSVM_Env env, 3475 JSVM_Value value, 3476 int32_t* result) { 3477 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 3478 // JS exceptions. 3479 CHECK_ENV(env); 3480 CHECK_ARG(env, value); 3481 CHECK_ARG(env, result); 3482 3483 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 3484 3485 if (val->IsInt32()) { 3486 *result = val.As<v8::Int32>()->Value(); 3487 } else { 3488 RETURN_STATUS_IF_FALSE(env, val->IsNumber(), JSVM_NUMBER_EXPECTED); 3489 3490 // Empty context: https://github.com/nodejs/node/issues/14379 3491 v8::Local<v8::Context> context; 3492 *result = val->Int32Value(context).FromJust(); 3493 } 3494 3495 return jsvm_clear_last_error(env); 3496} 3497 3498JSVM_Status JSVM_CDECL OH_JSVM_GetValueUint32(JSVM_Env env, 3499 JSVM_Value value, 3500 uint32_t* result) { 3501 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 3502 // JS exceptions. 3503 CHECK_ENV(env); 3504 CHECK_ARG(env, value); 3505 CHECK_ARG(env, result); 3506 3507 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 3508 3509 if (val->IsUint32()) { 3510 *result = val.As<v8::Uint32>()->Value(); 3511 } else { 3512 RETURN_STATUS_IF_FALSE(env, val->IsNumber(), JSVM_NUMBER_EXPECTED); 3513 3514 // Empty context: https://github.com/nodejs/node/issues/14379 3515 v8::Local<v8::Context> context; 3516 *result = val->Uint32Value(context).FromJust(); 3517 } 3518 3519 return jsvm_clear_last_error(env); 3520} 3521 3522JSVM_Status JSVM_CDECL OH_JSVM_GetValueInt64(JSVM_Env env, 3523 JSVM_Value value, 3524 int64_t* result) { 3525 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 3526 // JS exceptions. 3527 CHECK_ENV(env); 3528 CHECK_ARG(env, value); 3529 CHECK_ARG(env, result); 3530 3531 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 3532 3533 // This is still a fast path very likely to be taken. 3534 if (val->IsInt32()) { 3535 *result = val.As<v8::Int32>()->Value(); 3536 return jsvm_clear_last_error(env); 3537 } 3538 3539 RETURN_STATUS_IF_FALSE(env, val->IsNumber(), JSVM_NUMBER_EXPECTED); 3540 3541 // v8::Value::IntegerValue() converts NaN, +Inf, and -Inf to INT64_MIN, 3542 // inconsistent with v8::Value::Int32Value() which converts those values to 0. 3543 // Special-case all non-finite values to match that behavior. 3544 double doubleValue = val.As<v8::Number>()->Value(); 3545 if (std::isfinite(doubleValue)) { 3546 // Empty context: https://github.com/nodejs/node/issues/14379 3547 v8::Local<v8::Context> context; 3548 *result = val->IntegerValue(context).FromJust(); 3549 } else { 3550 *result = 0; 3551 } 3552 3553 return jsvm_clear_last_error(env); 3554} 3555 3556JSVM_Status JSVM_CDECL OH_JSVM_GetValueBigintInt64(JSVM_Env env, 3557 JSVM_Value value, 3558 int64_t* result, 3559 bool* lossless) { 3560 CHECK_ENV(env); 3561 CHECK_ARG(env, value); 3562 CHECK_ARG(env, result); 3563 CHECK_ARG(env, lossless); 3564 3565 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 3566 3567 RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), JSVM_BIGINT_EXPECTED); 3568 3569 *result = val.As<v8::BigInt>()->Int64Value(lossless); 3570 3571 return jsvm_clear_last_error(env); 3572} 3573 3574JSVM_Status JSVM_CDECL OH_JSVM_GetValueBigintUint64(JSVM_Env env, 3575 JSVM_Value value, 3576 uint64_t* result, 3577 bool* lossless) { 3578 CHECK_ENV(env); 3579 CHECK_ARG(env, value); 3580 CHECK_ARG(env, result); 3581 CHECK_ARG(env, lossless); 3582 3583 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 3584 3585 RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), JSVM_BIGINT_EXPECTED); 3586 3587 *result = val.As<v8::BigInt>()->Uint64Value(lossless); 3588 3589 return jsvm_clear_last_error(env); 3590} 3591 3592JSVM_Status JSVM_CDECL OH_JSVM_GetValueBigintWords(JSVM_Env env, 3593 JSVM_Value value, 3594 int* signBit, 3595 size_t* wordCount, 3596 uint64_t* words) { 3597 CHECK_ENV(env); 3598 CHECK_ARG(env, value); 3599 CHECK_ARG(env, wordCount); 3600 3601 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 3602 3603 RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), JSVM_BIGINT_EXPECTED); 3604 3605 v8::Local<v8::BigInt> big = val.As<v8::BigInt>(); 3606 3607 int word_count_int = *wordCount; 3608 3609 if (signBit == nullptr && words == nullptr) { 3610 word_count_int = big->WordCount(); 3611 } else { 3612 CHECK_ARG(env, signBit); 3613 CHECK_ARG(env, words); 3614 big->ToWordsArray(signBit, &word_count_int, words); 3615 } 3616 3617 *wordCount = word_count_int; 3618 3619 return jsvm_clear_last_error(env); 3620} 3621 3622JSVM_Status JSVM_CDECL OH_JSVM_GetValueBool(JSVM_Env env, 3623 JSVM_Value value, 3624 bool* result) { 3625 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 3626 // JS exceptions. 3627 CHECK_ENV(env); 3628 CHECK_ARG(env, value); 3629 CHECK_ARG(env, result); 3630 3631 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 3632 RETURN_STATUS_IF_FALSE(env, val->IsBoolean(), JSVM_BOOLEAN_EXPECTED); 3633 3634 *result = val.As<v8::Boolean>()->Value(); 3635 3636 return jsvm_clear_last_error(env); 3637} 3638 3639// Copies a JavaScript string into a LATIN-1 string buffer. The result is the 3640// number of bytes (excluding the null terminator) copied into buf. 3641// A sufficient buffer size should be greater than the length of string, 3642// reserving space for null terminator. 3643// If bufsize is insufficient, the string will be truncated and null terminated. 3644// If buf is NULL, this method returns the length of the string (in bytes) 3645// via the result parameter. 3646// The result argument is optional unless buf is NULL. 3647JSVM_Status JSVM_CDECL OH_JSVM_GetValueStringLatin1( 3648 JSVM_Env env, JSVM_Value value, char* buf, size_t bufsize, size_t* result) { 3649 CHECK_ENV(env); 3650 CHECK_ARG(env, value); 3651 3652 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 3653 RETURN_STATUS_IF_FALSE(env, val->IsString(), JSVM_STRING_EXPECTED); 3654 3655 if (!buf) { 3656 CHECK_ARG(env, result); 3657 *result = val.As<v8::String>()->Length(); 3658 } else if (bufsize != 0) { 3659 int copied = 3660 val.As<v8::String>()->WriteOneByte(env->isolate, 3661 reinterpret_cast<uint8_t*>(buf), 3662 0, 3663 bufsize - 1, 3664 v8::String::NO_NULL_TERMINATION); 3665 3666 buf[copied] = '\0'; 3667 if (result != nullptr) { 3668 *result = copied; 3669 } 3670 } else if (result != nullptr) { 3671 *result = 0; 3672 } 3673 3674 return jsvm_clear_last_error(env); 3675} 3676 3677// Copies a JavaScript string into a UTF-8 string buffer. The result is the 3678// number of bytes (excluding the null terminator) copied into buf. 3679// A sufficient buffer size should be greater than the length of string, 3680// reserving space for null terminator. 3681// If bufsize is insufficient, the string will be truncated and null terminated. 3682// If buf is NULL, this method returns the length of the string (in bytes) 3683// via the result parameter. 3684// The result argument is optional unless buf is NULL. 3685JSVM_Status JSVM_CDECL OH_JSVM_GetValueStringUtf8( 3686 JSVM_Env env, JSVM_Value value, char* buf, size_t bufsize, size_t* result) { 3687 CHECK_ENV(env); 3688 CHECK_ARG(env, value); 3689 3690 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 3691 RETURN_STATUS_IF_FALSE(env, val->IsString(), JSVM_STRING_EXPECTED); 3692 3693 if (!buf) { 3694 CHECK_ARG(env, result); 3695 *result = val.As<v8::String>()->Utf8Length(env->isolate); 3696 } else if (bufsize != 0) { 3697 int copied = val.As<v8::String>()->WriteUtf8( 3698 env->isolate, 3699 buf, 3700 bufsize - 1, 3701 nullptr, 3702 v8::String::REPLACE_INVALID_UTF8 | v8::String::NO_NULL_TERMINATION); 3703 3704 buf[copied] = '\0'; 3705 if (result != nullptr) { 3706 *result = copied; 3707 } 3708 } else if (result != nullptr) { 3709 *result = 0; 3710 } 3711 3712 return jsvm_clear_last_error(env); 3713} 3714 3715// Copies a JavaScript string into a UTF-16 string buffer. The result is the 3716// number of 2-byte code units (excluding the null terminator) copied into buf. 3717// A sufficient buffer size should be greater than the length of string, 3718// reserving space for null terminator. 3719// If bufsize is insufficient, the string will be truncated and null terminated. 3720// If buf is NULL, this method returns the length of the string (in 2-byte 3721// code units) via the result parameter. 3722// The result argument is optional unless buf is NULL. 3723JSVM_Status JSVM_CDECL OH_JSVM_GetValueStringUtf16(JSVM_Env env, 3724 JSVM_Value value, 3725 char16_t* buf, 3726 size_t bufsize, 3727 size_t* result) { 3728 CHECK_ENV(env); 3729 CHECK_ARG(env, value); 3730 3731 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 3732 RETURN_STATUS_IF_FALSE(env, val->IsString(), JSVM_STRING_EXPECTED); 3733 3734 if (!buf) { 3735 CHECK_ARG(env, result); 3736 // V8 assumes UTF-16 length is the same as the number of characters. 3737 *result = val.As<v8::String>()->Length(); 3738 } else if (bufsize != 0) { 3739 int copied = val.As<v8::String>()->Write(env->isolate, 3740 reinterpret_cast<uint16_t*>(buf), 3741 0, 3742 bufsize - 1, 3743 v8::String::NO_NULL_TERMINATION); 3744 3745 buf[copied] = '\0'; 3746 if (result != nullptr) { 3747 *result = copied; 3748 } 3749 } else if (result != nullptr) { 3750 *result = 0; 3751 } 3752 3753 return jsvm_clear_last_error(env); 3754} 3755 3756JSVM_Status JSVM_CDECL OH_JSVM_CoerceToBool(JSVM_Env env, 3757 JSVM_Value value, 3758 JSVM_Value* result) { 3759 JSVM_PREAMBLE(env); 3760 CHECK_ARG(env, value); 3761 CHECK_ARG(env, result); 3762 3763 v8::Isolate* isolate = env->isolate; 3764 v8::Local<v8::Boolean> b = 3765 v8impl::V8LocalValueFromJsValue(value)->ToBoolean(isolate); 3766 *result = v8impl::JsValueFromV8LocalValue(b); 3767 return GET_RETURN_STATUS(env); 3768} 3769 3770#define GEN_COERCE_FUNCTION(UpperCaseName, MixedCaseName, LowerCaseName) \ 3771 JSVM_Status JSVM_CDECL OH_JSVM_CoerceTo##MixedCaseName( \ 3772 JSVM_Env env, JSVM_Value value, JSVM_Value* result) { \ 3773 JSVM_PREAMBLE(env); \ 3774 CHECK_ARG(env, value); \ 3775 CHECK_ARG(env, result); \ 3776 \ 3777 v8::Local<v8::Context> context = env->context(); \ 3778 v8::Local<v8::MixedCaseName> str; \ 3779 \ 3780 CHECK_TO_##UpperCaseName(env, context, str, value); \ 3781 \ 3782 *result = v8impl::JsValueFromV8LocalValue(str); \ 3783 return GET_RETURN_STATUS(env); \ 3784 } 3785 3786GEN_COERCE_FUNCTION(NUMBER, Number, number) 3787GEN_COERCE_FUNCTION(OBJECT, Object, object) 3788GEN_COERCE_FUNCTION(STRING, String, string) 3789GEN_COERCE_FUNCTION(BIGINT, BigInt, bigint) 3790 3791#undef GEN_COERCE_FUNCTION 3792 3793JSVM_Status JSVM_CDECL OH_JSVM_Wrap(JSVM_Env env, 3794 JSVM_Value jsObject, 3795 void* nativeObject, 3796 JSVM_Finalize finalizeCb, 3797 void* finalizeHint, 3798 JSVM_Ref* result) { 3799 return v8impl::Wrap( 3800 env, jsObject, nativeObject, finalizeCb, finalizeHint, result); 3801} 3802 3803JSVM_Status JSVM_CDECL OH_JSVM_Unwrap(JSVM_Env env, 3804 JSVM_Value obj, 3805 void** result) { 3806 return v8impl::Unwrap(env, obj, result, v8impl::KeepWrap); 3807} 3808 3809JSVM_Status JSVM_CDECL OH_JSVM_RemoveWrap(JSVM_Env env, 3810 JSVM_Value obj, 3811 void** result) { 3812 return v8impl::Unwrap(env, obj, result, v8impl::RemoveWrap); 3813} 3814 3815JSVM_Status JSVM_CDECL OH_JSVM_CreateExternal(JSVM_Env env, 3816 void* data, 3817 JSVM_Finalize finalizeCb, 3818 void* finalizeHint, 3819 JSVM_Value* result) { 3820 JSVM_PREAMBLE(env); 3821 CHECK_ARG(env, result); 3822 3823 v8::Isolate* isolate = env->isolate; 3824 3825 v8::Local<v8::Value> external_value = v8::External::New(isolate, data); 3826 3827 if (finalizeCb) { 3828 // The Reference object will delete itself after invoking the finalizer 3829 // callback. 3830 v8impl::Reference::New(env, 3831 external_value, 3832 0, 3833 v8impl::Ownership::kRuntime, 3834 finalizeCb, 3835 data, 3836 finalizeHint); 3837 } 3838 3839 *result = v8impl::JsValueFromV8LocalValue(external_value); 3840 3841 return jsvm_clear_last_error(env); 3842} 3843 3844JSVM_Status JSVM_CDECL OH_JSVM_TypeTagObject(JSVM_Env env, 3845 JSVM_Value object, 3846 const JSVM_TypeTag* typeTag) { 3847 JSVM_PREAMBLE(env); 3848 v8::Local<v8::Context> context = env->context(); 3849 v8::Local<v8::Object> obj; 3850 CHECK_TO_OBJECT_WITH_PREAMBLE(env, context, obj, object); 3851 CHECK_ARG_WITH_PREAMBLE(env, typeTag); 3852 3853 auto key = JSVM_PRIVATE_KEY(env->isolate, type_tag); 3854 auto maybe_has = obj->HasPrivate(context, key); 3855 CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, JSVM_GENERIC_FAILURE); 3856 RETURN_STATUS_IF_FALSE_WITH_PREAMBLE( 3857 env, !maybe_has.FromJust(), JSVM_INVALID_ARG); 3858 3859 auto tag = v8::BigInt::NewFromWords( 3860 context, 0, 2, reinterpret_cast<const uint64_t*>(typeTag)); 3861 CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, tag, JSVM_GENERIC_FAILURE); 3862 3863 auto maybe_set = obj->SetPrivate(context, key, tag.ToLocalChecked()); 3864 CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, JSVM_GENERIC_FAILURE); 3865 RETURN_STATUS_IF_FALSE_WITH_PREAMBLE( 3866 env, maybe_set.FromJust(), JSVM_GENERIC_FAILURE); 3867 3868 return GET_RETURN_STATUS(env); 3869} 3870 3871JSVM_Status JSVM_CDECL OH_JSVM_CheckObjectTypeTag(JSVM_Env env, 3872 JSVM_Value object, 3873 const JSVM_TypeTag* typeTag, 3874 bool* result) { 3875 JSVM_PREAMBLE(env); 3876 v8::Local<v8::Context> context = env->context(); 3877 v8::Local<v8::Object> obj; 3878 CHECK_TO_OBJECT_WITH_PREAMBLE(env, context, obj, object); 3879 CHECK_ARG_WITH_PREAMBLE(env, typeTag); 3880 CHECK_ARG_WITH_PREAMBLE(env, result); 3881 3882 auto maybe_value = 3883 obj->GetPrivate(context, JSVM_PRIVATE_KEY(env->isolate, type_tag)); 3884 CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, maybe_value, JSVM_GENERIC_FAILURE); 3885 v8::Local<v8::Value> val = maybe_value.ToLocalChecked(); 3886 3887 // We consider the type check to have failed unless we reach the line below 3888 // where we set whether the type check succeeded or not based on the 3889 // comparison of the two type tags. 3890 *result = false; 3891 if (val->IsBigInt()) { 3892 int sign; 3893 int size = 2; 3894 JSVM_TypeTag tag; 3895 val.As<v8::BigInt>()->ToWordsArray( 3896 &sign, &size, reinterpret_cast<uint64_t*>(&tag)); 3897 if (sign == 0) { 3898 if (size == 2) { 3899 *result = 3900 (tag.lower == typeTag->lower && tag.upper == typeTag->upper); 3901 } else if (size == 1) { 3902 *result = (tag.lower == typeTag->lower && 0 == typeTag->upper); 3903 } else if (size == 0) { 3904 *result = (0 == typeTag->lower && 0 == typeTag->upper); 3905 } 3906 } 3907 } 3908 3909 return GET_RETURN_STATUS(env); 3910} 3911 3912JSVM_Status JSVM_CDECL OH_JSVM_GetValueExternal(JSVM_Env env, 3913 JSVM_Value value, 3914 void** result) { 3915 CHECK_ENV(env); 3916 CHECK_ARG(env, value); 3917 CHECK_ARG(env, result); 3918 3919 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 3920 RETURN_STATUS_IF_FALSE(env, val->IsExternal(), JSVM_INVALID_ARG); 3921 3922 v8::Local<v8::External> external_value = val.As<v8::External>(); 3923 *result = external_value->Value(); 3924 3925 return jsvm_clear_last_error(env); 3926} 3927 3928// Set initialRefcount to 0 for a weak reference, >0 for a strong reference. 3929JSVM_Status JSVM_CDECL OH_JSVM_CreateReference(JSVM_Env env, 3930 JSVM_Value value, 3931 uint32_t initialRefcount, 3932 JSVM_Ref* result) { 3933 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 3934 // JS exceptions. 3935 CHECK_ENV(env); 3936 CHECK_ARG(env, value); 3937 CHECK_ARG(env, result); 3938 3939 v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value); 3940 v8impl::Reference* reference = v8impl::Reference::New( 3941 env, v8_value, initialRefcount, v8impl::Ownership::kUserland); 3942 3943 *result = reinterpret_cast<JSVM_Ref>(reference); 3944 return jsvm_clear_last_error(env); 3945} 3946 3947// Deletes a reference. The referenced value is released, and may be GC'd unless 3948// there are other references to it. 3949JSVM_Status JSVM_CDECL OH_JSVM_DeleteReference(JSVM_Env env, JSVM_Ref ref) { 3950 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 3951 // JS exceptions. 3952 CHECK_ENV(env); 3953 CHECK_ARG(env, ref); 3954 3955 reinterpret_cast<v8impl::Reference*>(ref)->Delete(); 3956 3957 return jsvm_clear_last_error(env); 3958} 3959 3960// Increments the reference count, optionally returning the resulting count. 3961// After this call the reference will be a strong reference because its 3962// refcount is >0, and the referenced object is effectively "pinned". 3963// Calling this when the refcount is 0 and the object is unavailable 3964// results in an error. 3965JSVM_Status JSVM_CDECL OH_JSVM_ReferenceRef(JSVM_Env env, 3966 JSVM_Ref ref, 3967 uint32_t* result) { 3968 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 3969 // JS exceptions. 3970 CHECK_ENV(env); 3971 CHECK_ARG(env, ref); 3972 3973 v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref); 3974 if (reference->HasDeletedByUser()) { 3975 return jsvm_set_last_error(env, JSVM_GENERIC_FAILURE); 3976 } 3977 uint32_t count = reference->Ref(); 3978 3979 if (result != nullptr) { 3980 *result = count; 3981 } 3982 3983 return jsvm_clear_last_error(env); 3984} 3985 3986// Decrements the reference count, optionally returning the resulting count. If 3987// the result is 0 the reference is now weak and the object may be GC'd at any 3988// time if there are no other references. Calling this when the refcount is 3989// already 0 results in an error. 3990JSVM_Status JSVM_CDECL OH_JSVM_ReferenceUnref(JSVM_Env env, 3991 JSVM_Ref ref, 3992 uint32_t* result) { 3993 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 3994 // JS exceptions. 3995 CHECK_ENV(env); 3996 CHECK_ARG(env, ref); 3997 3998 v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref); 3999 4000 if (reference->RefCount() == 0 || reference->HasDeletedByUser()) { 4001 return jsvm_set_last_error(env, JSVM_GENERIC_FAILURE); 4002 } 4003 4004 uint32_t count = reference->Unref(); 4005 4006 if (result != nullptr) { 4007 *result = count; 4008 } 4009 4010 return jsvm_clear_last_error(env); 4011} 4012 4013// Attempts to get a referenced value. If the reference is weak, the value might 4014// no longer be available, in that case the call is still successful but the 4015// result is NULL. 4016JSVM_Status JSVM_CDECL OH_JSVM_GetReferenceValue(JSVM_Env env, 4017 JSVM_Ref ref, 4018 JSVM_Value* result) { 4019 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 4020 // JS exceptions. 4021 CHECK_ENV(env); 4022 CHECK_ARG(env, ref); 4023 CHECK_ARG(env, result); 4024 4025 v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref); 4026 *result = v8impl::JsValueFromV8LocalValue(reference->Get()); 4027 4028 return jsvm_clear_last_error(env); 4029} 4030 4031JSVM_Status JSVM_CDECL OH_JSVM_OpenHandleScope(JSVM_Env env, 4032 JSVM_HandleScope* result) { 4033 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 4034 // JS exceptions. 4035 CHECK_ENV(env); 4036 CHECK_ARG(env, result); 4037 4038 *result = v8impl::JsHandleScopeFromV8HandleScope( 4039 new v8impl::HandleScopeWrapper(env->isolate)); 4040 env->open_handle_scopes++; 4041 return jsvm_clear_last_error(env); 4042} 4043 4044JSVM_Status JSVM_CDECL OH_JSVM_CloseHandleScope(JSVM_Env env, 4045 JSVM_HandleScope scope) { 4046 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 4047 // JS exceptions. 4048 CHECK_ENV(env); 4049 CHECK_ARG(env, scope); 4050 if (env->open_handle_scopes == 0) { 4051 return JSVM_HANDLE_SCOPE_MISMATCH; 4052 } 4053 4054 env->ReleaseJsvmData(); 4055 env->open_handle_scopes--; 4056 delete v8impl::V8HandleScopeFromJsHandleScope(scope); 4057 return jsvm_clear_last_error(env); 4058} 4059 4060JSVM_Status JSVM_CDECL OH_JSVM_OpenEscapableHandleScope( 4061 JSVM_Env env, JSVM_EscapableHandleScope* result) { 4062 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 4063 // JS exceptions. 4064 CHECK_ENV(env); 4065 CHECK_ARG(env, result); 4066 4067 *result = v8impl::JsEscapableHandleScopeFromV8EscapableHandleScope( 4068 new v8impl::EscapableHandleScopeWrapper(env->isolate)); 4069 env->open_handle_scopes++; 4070 return jsvm_clear_last_error(env); 4071} 4072 4073JSVM_Status JSVM_CDECL OH_JSVM_CloseEscapableHandleScope( 4074 JSVM_Env env, JSVM_EscapableHandleScope scope) { 4075 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 4076 // JS exceptions. 4077 CHECK_ENV(env); 4078 CHECK_ARG(env, scope); 4079 if (env->open_handle_scopes == 0) { 4080 return JSVM_HANDLE_SCOPE_MISMATCH; 4081 } 4082 4083 delete v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope); 4084 env->open_handle_scopes--; 4085 return jsvm_clear_last_error(env); 4086} 4087 4088JSVM_Status JSVM_CDECL OH_JSVM_EscapeHandle(JSVM_Env env, 4089 JSVM_EscapableHandleScope scope, 4090 JSVM_Value escapee, 4091 JSVM_Value* result) { 4092 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 4093 // JS exceptions. 4094 CHECK_ENV(env); 4095 CHECK_ARG(env, scope); 4096 CHECK_ARG(env, escapee); 4097 CHECK_ARG(env, result); 4098 4099 v8impl::EscapableHandleScopeWrapper* s = 4100 v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope); 4101 if (!s->escape_called()) { 4102 *result = v8impl::JsValueFromV8LocalValue( 4103 s->Escape(v8impl::V8LocalValueFromJsValue(escapee))); 4104 return jsvm_clear_last_error(env); 4105 } 4106 return jsvm_set_last_error(env, JSVM_ESCAPE_CALLED_TWICE); 4107} 4108 4109JSVM_Status JSVM_CDECL OH_JSVM_NewInstance(JSVM_Env env, 4110 JSVM_Value constructor, 4111 size_t argc, 4112 const JSVM_Value* argv, 4113 JSVM_Value* result) { 4114 JSVM_PREAMBLE(env); 4115 CHECK_ARG(env, constructor); 4116 if (argc > 0) { 4117 CHECK_ARG(env, argv); 4118 } 4119 CHECK_ARG(env, result); 4120 4121 v8::Local<v8::Context> context = env->context(); 4122 4123 v8::Local<v8::Function> ctor; 4124 CHECK_TO_FUNCTION(env, ctor, constructor); 4125 4126 auto maybe = ctor->NewInstance( 4127 context, 4128 argc, 4129 reinterpret_cast<v8::Local<v8::Value>*>(const_cast<JSVM_Value*>(argv))); 4130 4131 CHECK_MAYBE_EMPTY(env, maybe, JSVM_PENDING_EXCEPTION); 4132 4133 *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked()); 4134 return GET_RETURN_STATUS(env); 4135} 4136 4137JSVM_Status JSVM_CDECL OH_JSVM_Instanceof(JSVM_Env env, 4138 JSVM_Value object, 4139 JSVM_Value constructor, 4140 bool* result) { 4141 JSVM_PREAMBLE(env); 4142 CHECK_ARG(env, object); 4143 CHECK_ARG(env, result); 4144 4145 *result = false; 4146 4147 v8::Local<v8::Object> ctor; 4148 v8::Local<v8::Context> context = env->context(); 4149 4150 CHECK_TO_OBJECT(env, context, ctor, constructor); 4151 4152 if (!ctor->IsFunction()) { 4153 OH_JSVM_ThrowTypeError( 4154 env, "ERR_NAPI_CONS_FUNCTION", "Constructor must be a function"); 4155 4156 return jsvm_set_last_error(env, JSVM_FUNCTION_EXPECTED); 4157 } 4158 4159 JSVM_Status status = JSVM_GENERIC_FAILURE; 4160 4161 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(object); 4162 auto maybe_result = val->InstanceOf(context, ctor); 4163 CHECK_MAYBE_NOTHING(env, maybe_result, status); 4164 *result = maybe_result.FromJust(); 4165 return GET_RETURN_STATUS(env); 4166} 4167 4168// Methods to support catching exceptions 4169JSVM_Status JSVM_CDECL OH_JSVM_IsExceptionPending(JSVM_Env env, bool* result) { 4170 // JSVM_PREAMBLE is not used here: this function must execute when there is a 4171 // pending exception. 4172 CHECK_ENV(env); 4173 CHECK_ARG(env, result); 4174 4175 *result = !env->last_exception.IsEmpty(); 4176 return jsvm_clear_last_error(env); 4177} 4178 4179JSVM_Status JSVM_CDECL OH_JSVM_GetAndClearLastException(JSVM_Env env, 4180 JSVM_Value* result) { 4181 // JSVM_PREAMBLE is not used here: this function must execute when there is a 4182 // pending exception. 4183 CHECK_ENV(env); 4184 CHECK_ARG(env, result); 4185 4186 if (env->last_exception.IsEmpty()) { 4187 return OH_JSVM_GetUndefined(env, result); 4188 } else { 4189 *result = v8impl::JsValueFromV8LocalValue( 4190 v8::Local<v8::Value>::New(env->isolate, env->last_exception)); 4191 env->last_exception.Reset(); 4192 } 4193 4194 return jsvm_clear_last_error(env); 4195} 4196 4197JSVM_Status JSVM_CDECL OH_JSVM_IsArraybuffer(JSVM_Env env, 4198 JSVM_Value value, 4199 bool* result) { 4200 CHECK_ENV(env); 4201 CHECK_ARG(env, value); 4202 CHECK_ARG(env, result); 4203 4204 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 4205 *result = val->IsArrayBuffer(); 4206 4207 return jsvm_clear_last_error(env); 4208} 4209 4210JSVM_Status JSVM_CDECL OH_JSVM_CreateArraybuffer(JSVM_Env env, 4211 size_t byteLength, 4212 void** data, 4213 JSVM_Value* result) { 4214 JSVM_PREAMBLE(env); 4215 CHECK_ARG(env, result); 4216 4217 v8::Isolate* isolate = env->isolate; 4218 v8::Local<v8::ArrayBuffer> buffer = 4219 v8::ArrayBuffer::New(isolate, byteLength); 4220 4221 // Optionally return a pointer to the buffer's data, to avoid another call to 4222 // retrieve it. 4223 if (data != nullptr) { 4224 *data = buffer->Data(); 4225 } 4226 4227 *result = v8impl::JsValueFromV8LocalValue(buffer); 4228 return GET_RETURN_STATUS(env); 4229} 4230 4231JSVM_Status JSVM_CDECL OH_JSVM_AllocateArrayBufferBackingStoreData(size_t byteLength, 4232 JSVM_InitializedFlag initialized, 4233 void **data) { 4234 if (!data) { 4235 return JSVM_INVALID_ARG; 4236 } 4237 auto allocator = v8impl::GetOrCreateDefaultArrayBufferAllocator(); 4238 *data = (initialized == JSVM_ZERO_INITIALIZED) ? 4239 allocator->Allocate(byteLength) : 4240 allocator->AllocateUninitialized(byteLength); 4241 return *data ? JSVM_OK : JSVM_GENERIC_FAILURE; 4242} 4243 4244JSVM_Status JSVM_CDECL OH_JSVM_FreeArrayBufferBackingStoreData(void *data) { 4245 if (!data) { 4246 return JSVM_INVALID_ARG; 4247 } 4248 auto allocator = v8impl::GetOrCreateDefaultArrayBufferAllocator(); 4249 allocator->Free(data, JSVM_AUTO_LENGTH); 4250 return JSVM_OK; 4251} 4252 4253JSVM_Status JSVM_CDECL OH_JSVM_CreateArrayBufferFromBackingStoreData(JSVM_Env env, 4254 void *data, 4255 size_t backingStoreSize, 4256 size_t offset, 4257 size_t arrayBufferSize, 4258 JSVM_Value *result) { 4259 CHECK_ENV(env); 4260 JSVM_PREAMBLE(env); 4261 CHECK_ARG(env, data); 4262 CHECK_ARG(env, result); 4263 CHECK_ARG_NOT_ZERO(env, backingStoreSize); 4264 CHECK_ARG_NOT_ZERO(env, arrayBufferSize); 4265 void *dataPtr = static_cast<uint8_t*>(data) + offset; 4266 RETURN_STATUS_IF_FALSE(env, offset + arrayBufferSize <= backingStoreSize, JSVM_INVALID_ARG); 4267 auto backingStore = v8::ArrayBuffer::NewBackingStore( 4268 dataPtr, arrayBufferSize, v8::BackingStore::EmptyDeleter, nullptr); 4269 v8::Local<v8::ArrayBuffer> arrayBuffer = 4270 v8::ArrayBuffer::New(env->isolate, std::move(backingStore)); 4271 *result = v8impl::JsValueFromV8LocalValue(arrayBuffer); 4272 return jsvm_clear_last_error(env); 4273} 4274 4275JSVM_Status JSVM_CDECL 4276OH_JSVM_CreateExternalArraybuffer(JSVM_Env env, 4277 void* externalData, 4278 size_t byteLength, 4279 JSVM_Finalize finalizeCb, 4280 void* finalizeHint, 4281 JSVM_Value* result) { 4282 // The API contract here is that the cleanup function runs on the JS thread, 4283 // and is able to use JSVM_Env. Implementing that properly is hard, so use the 4284 // `Buffer` variant for easier implementation. 4285 JSVM_Value buffer; 4286 STATUS_CALL(OH_JSVM_CreateExternal_buffer( 4287 env, byteLength, externalData, finalizeCb, finalizeHint, &buffer)); 4288 return OH_JSVM_GetTypedarrayInfo( 4289 env, buffer, nullptr, nullptr, nullptr, result, nullptr); 4290} 4291 4292JSVM_Status JSVM_CDECL OH_JSVM_GetArraybufferInfo(JSVM_Env env, 4293 JSVM_Value arraybuffer, 4294 void** data, 4295 size_t* byteLength) { 4296 CHECK_ENV(env); 4297 CHECK_ARG(env, arraybuffer); 4298 4299 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer); 4300 RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), JSVM_INVALID_ARG); 4301 4302 v8::Local<v8::ArrayBuffer> ab = value.As<v8::ArrayBuffer>(); 4303 4304 if (data != nullptr) { 4305 *data = ab->Data(); 4306 } 4307 4308 if (byteLength != nullptr) { 4309 *byteLength = ab->ByteLength(); 4310 } 4311 4312 return jsvm_clear_last_error(env); 4313} 4314 4315JSVM_Status JSVM_CDECL OH_JSVM_IsTypedarray(JSVM_Env env, 4316 JSVM_Value value, 4317 bool* result) { 4318 CHECK_ENV(env); 4319 CHECK_ARG(env, value); 4320 CHECK_ARG(env, result); 4321 4322 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 4323 *result = val->IsTypedArray(); 4324 4325 return jsvm_clear_last_error(env); 4326} 4327 4328JSVM_Status JSVM_CDECL OH_JSVM_CreateTypedarray(JSVM_Env env, 4329 JSVM_TypedarrayType type, 4330 size_t length, 4331 JSVM_Value arraybuffer, 4332 size_t byteOffset, 4333 JSVM_Value* result) { 4334 JSVM_PREAMBLE(env); 4335 CHECK_ARG(env, arraybuffer); 4336 CHECK_ARG(env, result); 4337 4338 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer); 4339 RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), JSVM_INVALID_ARG); 4340 4341 v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>(); 4342 v8::Local<v8::TypedArray> typedArray; 4343 4344 switch (type) { 4345 case JSVM_INT8_ARRAY: 4346 CREATE_TYPED_ARRAY( 4347 env, Int8Array, 1, buffer, byteOffset, length, typedArray); 4348 break; 4349 case JSVM_UINT8_ARRAY: 4350 CREATE_TYPED_ARRAY( 4351 env, Uint8Array, 1, buffer, byteOffset, length, typedArray); 4352 break; 4353 case JSVM_UINT8_CLAMPED_ARRAY: 4354 CREATE_TYPED_ARRAY( 4355 env, Uint8ClampedArray, 1, buffer, byteOffset, length, typedArray); 4356 break; 4357 case JSVM_INT16_ARRAY: 4358 CREATE_TYPED_ARRAY( 4359 env, Int16Array, 2, buffer, byteOffset, length, typedArray); 4360 break; 4361 case JSVM_UINT16_ARRAY: 4362 CREATE_TYPED_ARRAY( 4363 env, Uint16Array, 2, buffer, byteOffset, length, typedArray); 4364 break; 4365 case JSVM_INT32_ARRAY: 4366 CREATE_TYPED_ARRAY( 4367 env, Int32Array, 4, buffer, byteOffset, length, typedArray); 4368 break; 4369 case JSVM_UINT32_ARRAY: 4370 CREATE_TYPED_ARRAY( 4371 env, Uint32Array, 4, buffer, byteOffset, length, typedArray); 4372 break; 4373 case JSVM_FLOAT32_ARRAY: 4374 CREATE_TYPED_ARRAY( 4375 env, Float32Array, 4, buffer, byteOffset, length, typedArray); 4376 break; 4377 case JSVM_FLOAT64_ARRAY: 4378 CREATE_TYPED_ARRAY( 4379 env, Float64Array, 8, buffer, byteOffset, length, typedArray); 4380 break; 4381 case JSVM_BIGINT64_ARRAY: 4382 CREATE_TYPED_ARRAY( 4383 env, BigInt64Array, 8, buffer, byteOffset, length, typedArray); 4384 break; 4385 case JSVM_BIGUINT64_ARRAY: 4386 CREATE_TYPED_ARRAY( 4387 env, BigUint64Array, 8, buffer, byteOffset, length, typedArray); 4388 break; 4389 default: 4390 return jsvm_set_last_error(env, JSVM_INVALID_ARG); 4391 } 4392 4393 *result = v8impl::JsValueFromV8LocalValue(typedArray); 4394 return GET_RETURN_STATUS(env); 4395} 4396 4397JSVM_Status JSVM_CDECL OH_JSVM_GetTypedarrayInfo(JSVM_Env env, 4398 JSVM_Value typedarray, 4399 JSVM_TypedarrayType* type, 4400 size_t* length, 4401 void** data, 4402 JSVM_Value* arraybuffer, 4403 size_t* byteOffset) { 4404 CHECK_ENV(env); 4405 CHECK_ARG(env, typedarray); 4406 4407 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(typedarray); 4408 RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), JSVM_INVALID_ARG); 4409 4410 v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>(); 4411 4412 if (type != nullptr) { 4413 if (value->IsInt8Array()) { 4414 *type = JSVM_INT8_ARRAY; 4415 } else if (value->IsUint8Array()) { 4416 *type = JSVM_UINT8_ARRAY; 4417 } else if (value->IsUint8ClampedArray()) { 4418 *type = JSVM_UINT8_CLAMPED_ARRAY; 4419 } else if (value->IsInt16Array()) { 4420 *type = JSVM_INT16_ARRAY; 4421 } else if (value->IsUint16Array()) { 4422 *type = JSVM_UINT16_ARRAY; 4423 } else if (value->IsInt32Array()) { 4424 *type = JSVM_INT32_ARRAY; 4425 } else if (value->IsUint32Array()) { 4426 *type = JSVM_UINT32_ARRAY; 4427 } else if (value->IsFloat32Array()) { 4428 *type = JSVM_FLOAT32_ARRAY; 4429 } else if (value->IsFloat64Array()) { 4430 *type = JSVM_FLOAT64_ARRAY; 4431 } else if (value->IsBigInt64Array()) { 4432 *type = JSVM_BIGINT64_ARRAY; 4433 } else if (value->IsBigUint64Array()) { 4434 *type = JSVM_BIGUINT64_ARRAY; 4435 } 4436 } 4437 4438 if (length != nullptr) { 4439 *length = array->Length(); 4440 } 4441 4442 v8::Local<v8::ArrayBuffer> buffer; 4443 if (data != nullptr || arraybuffer != nullptr) { 4444 // Calling Buffer() may have the side effect of allocating the buffer, 4445 // so only do this when it's needed. 4446 buffer = array->Buffer(); 4447 } 4448 4449 if (data != nullptr) { 4450 *data = static_cast<uint8_t*>(buffer->Data()) + array->ByteOffset(); 4451 } 4452 4453 if (arraybuffer != nullptr) { 4454 *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer); 4455 } 4456 4457 if (byteOffset != nullptr) { 4458 *byteOffset = array->ByteOffset(); 4459 } 4460 4461 return jsvm_clear_last_error(env); 4462} 4463 4464JSVM_Status JSVM_CDECL OH_JSVM_CreateDataview(JSVM_Env env, 4465 size_t byteLength, 4466 JSVM_Value arraybuffer, 4467 size_t byteOffset, 4468 JSVM_Value* result) { 4469 JSVM_PREAMBLE(env); 4470 CHECK_ARG(env, arraybuffer); 4471 CHECK_ARG(env, result); 4472 4473 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer); 4474 RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), JSVM_INVALID_ARG); 4475 4476 v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>(); 4477 if (byteLength + byteOffset > buffer->ByteLength()) { 4478 OH_JSVM_ThrowRangeError(env, 4479 "ERR_JSVM_INVALID_DATAVIEW_ARGS", 4480 "byteOffset + byteLength should be less than or " 4481 "equal to the size in bytes of the array passed in"); 4482 return jsvm_set_last_error(env, JSVM_PENDING_EXCEPTION); 4483 } 4484 v8::Local<v8::DataView> DataView = 4485 v8::DataView::New(buffer, byteOffset, byteLength); 4486 4487 *result = v8impl::JsValueFromV8LocalValue(DataView); 4488 return GET_RETURN_STATUS(env); 4489} 4490 4491JSVM_Status JSVM_CDECL OH_JSVM_IsDataview(JSVM_Env env, 4492 JSVM_Value value, 4493 bool* result) { 4494 CHECK_ENV(env); 4495 CHECK_ARG(env, value); 4496 CHECK_ARG(env, result); 4497 4498 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 4499 *result = val->IsDataView(); 4500 4501 return jsvm_clear_last_error(env); 4502} 4503 4504JSVM_Status JSVM_CDECL OH_JSVM_GetDataviewInfo(JSVM_Env env, 4505 JSVM_Value dataview, 4506 size_t* byteLength, 4507 void** data, 4508 JSVM_Value* arraybuffer, 4509 size_t* byteOffset) { 4510 CHECK_ENV(env); 4511 CHECK_ARG(env, dataview); 4512 4513 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(dataview); 4514 RETURN_STATUS_IF_FALSE(env, value->IsDataView(), JSVM_INVALID_ARG); 4515 4516 v8::Local<v8::DataView> array = value.As<v8::DataView>(); 4517 4518 if (byteLength != nullptr) { 4519 *byteLength = array->ByteLength(); 4520 } 4521 4522 v8::Local<v8::ArrayBuffer> buffer; 4523 if (data != nullptr || arraybuffer != nullptr) { 4524 // Calling Buffer() may have the side effect of allocating the buffer, 4525 // so only do this when it's needed. 4526 buffer = array->Buffer(); 4527 } 4528 4529 if (data != nullptr) { 4530 *data = static_cast<uint8_t*>(buffer->Data()) + array->ByteOffset(); 4531 } 4532 4533 if (arraybuffer != nullptr) { 4534 *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer); 4535 } 4536 4537 if (byteOffset != nullptr) { 4538 *byteOffset = array->ByteOffset(); 4539 } 4540 4541 return jsvm_clear_last_error(env); 4542} 4543 4544JSVM_Status JSVM_CDECL OH_JSVM_GetVersion(JSVM_Env env, uint32_t* result) { 4545 CHECK_ENV(env); 4546 CHECK_ARG(env, result); 4547 *result = NAPI_VERSION; 4548 return jsvm_clear_last_error(env); 4549} 4550 4551JSVM_Status JSVM_CDECL OH_JSVM_CreatePromise(JSVM_Env env, 4552 JSVM_Deferred* deferred, 4553 JSVM_Value* promise) { 4554 JSVM_PREAMBLE(env); 4555 CHECK_ARG(env, deferred); 4556 CHECK_ARG(env, promise); 4557 4558 auto maybe = v8::Promise::Resolver::New(env->context()); 4559 CHECK_MAYBE_EMPTY(env, maybe, JSVM_GENERIC_FAILURE); 4560 4561 auto v8_resolver = maybe.ToLocalChecked(); 4562 auto v8_deferred = new v8impl::Persistent<v8::Value>(); 4563 v8_deferred->Reset(env->isolate, v8_resolver); 4564 4565 *deferred = v8impl::JsDeferredFromNodePersistent(v8_deferred); 4566 *promise = v8impl::JsValueFromV8LocalValue(v8_resolver->GetPromise()); 4567 return GET_RETURN_STATUS(env); 4568} 4569 4570JSVM_Status JSVM_CDECL OH_JSVM_ResolveDeferred(JSVM_Env env, 4571 JSVM_Deferred deferred, 4572 JSVM_Value resolution) { 4573 return v8impl::ConcludeDeferred(env, deferred, resolution, true); 4574} 4575 4576JSVM_Status JSVM_CDECL OH_JSVM_RejectDeferred(JSVM_Env env, 4577 JSVM_Deferred deferred, 4578 JSVM_Value resolution) { 4579 return v8impl::ConcludeDeferred(env, deferred, resolution, false); 4580} 4581 4582JSVM_Status JSVM_CDECL OH_JSVM_IsPromise(JSVM_Env env, 4583 JSVM_Value value, 4584 bool* is_promise) { 4585 CHECK_ENV(env); 4586 CHECK_ARG(env, value); 4587 CHECK_ARG(env, is_promise); 4588 4589 *is_promise = v8impl::V8LocalValueFromJsValue(value)->IsPromise(); 4590 4591 return jsvm_clear_last_error(env); 4592} 4593 4594JSVM_Status JSVM_CDECL OH_JSVM_CreateDate(JSVM_Env env, 4595 double time, 4596 JSVM_Value* result) { 4597 JSVM_PREAMBLE(env); 4598 CHECK_ARG(env, result); 4599 4600 v8::MaybeLocal<v8::Value> maybe_date = v8::Date::New(env->context(), time); 4601 CHECK_MAYBE_EMPTY(env, maybe_date, JSVM_GENERIC_FAILURE); 4602 4603 *result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked()); 4604 4605 return GET_RETURN_STATUS(env); 4606} 4607 4608JSVM_Status JSVM_CDECL OH_JSVM_IsDate(JSVM_Env env, 4609 JSVM_Value value, 4610 bool* isDate) { 4611 CHECK_ENV(env); 4612 CHECK_ARG(env, value); 4613 CHECK_ARG(env, isDate); 4614 4615 *isDate = v8impl::V8LocalValueFromJsValue(value)->IsDate(); 4616 4617 return jsvm_clear_last_error(env); 4618} 4619 4620JSVM_Status JSVM_CDECL OH_JSVM_GetDateValue(JSVM_Env env, 4621 JSVM_Value value, 4622 double* result) { 4623 JSVM_PREAMBLE(env); 4624 CHECK_ARG(env, value); 4625 CHECK_ARG(env, result); 4626 4627 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 4628 RETURN_STATUS_IF_FALSE(env, val->IsDate(), JSVM_DATE_EXPECTED); 4629 4630 v8::Local<v8::Date> date = val.As<v8::Date>(); 4631 *result = date->ValueOf(); 4632 4633 return GET_RETURN_STATUS(env); 4634} 4635 4636JSVM_Status JSVM_CDECL OH_JSVM_AddFinalizer(JSVM_Env env, 4637 JSVM_Value jsObject, 4638 void* finalizeData, 4639 JSVM_Finalize finalizeCb, 4640 void* finalizeHint, 4641 JSVM_Ref* result) { 4642 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw 4643 // JS exceptions. 4644 CHECK_ENV(env); 4645 CHECK_ARG(env, jsObject); 4646 CHECK_ARG(env, finalizeCb); 4647 4648 v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(jsObject); 4649 RETURN_STATUS_IF_FALSE(env, v8_value->IsObject(), JSVM_INVALID_ARG); 4650 4651 // Create a self-deleting reference if the optional out-param result is not 4652 // set. 4653 v8impl::Ownership ownership = result == nullptr 4654 ? v8impl::Ownership::kRuntime 4655 : v8impl::Ownership::kUserland; 4656 v8impl::Reference* reference = v8impl::Reference::New( 4657 env, v8_value, 0, ownership, finalizeCb, finalizeData, finalizeHint); 4658 4659 if (result != nullptr) { 4660 *result = reinterpret_cast<JSVM_Ref>(reference); 4661 } 4662 return jsvm_clear_last_error(env); 4663} 4664 4665JSVM_Status JSVM_CDECL OH_JSVM_AdjustExternalMemory(JSVM_Env env, 4666 int64_t changeInBytes, 4667 int64_t* adjustedValue) { 4668 CHECK_ENV(env); 4669 CHECK_ARG(env, adjustedValue); 4670 4671 *adjustedValue = 4672 env->isolate->AdjustAmountOfExternalAllocatedMemory(changeInBytes); 4673 4674 return jsvm_clear_last_error(env); 4675} 4676 4677JSVM_Status JSVM_CDECL OH_JSVM_SetInstanceData(JSVM_Env env, 4678 void* data, 4679 JSVM_Finalize finalizeCb, 4680 void* finalizeHint) { 4681 CHECK_ENV(env); 4682 4683 v8impl::RefBase* old_data = static_cast<v8impl::RefBase*>(env->instance_data); 4684 if (old_data != nullptr) { 4685 // Our contract so far has been to not finalize any old data there may be. 4686 // So we simply delete it. 4687 delete old_data; 4688 } 4689 4690 env->instance_data = v8impl::RefBase::New( 4691 env, 0, v8impl::Ownership::kRuntime, finalizeCb, data, finalizeHint); 4692 4693 return jsvm_clear_last_error(env); 4694} 4695 4696JSVM_Status JSVM_CDECL OH_JSVM_GetInstanceData(JSVM_Env env, void** data) { 4697 CHECK_ENV(env); 4698 CHECK_ARG(env, data); 4699 4700 v8impl::RefBase* idata = static_cast<v8impl::RefBase*>(env->instance_data); 4701 4702 *data = (idata == nullptr ? nullptr : idata->Data()); 4703 4704 return jsvm_clear_last_error(env); 4705} 4706 4707JSVM_Status JSVM_CDECL OH_JSVM_DetachArraybuffer(JSVM_Env env, 4708 JSVM_Value arraybuffer) { 4709 CHECK_ENV(env); 4710 CHECK_ARG(env, arraybuffer); 4711 4712 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer); 4713 RETURN_STATUS_IF_FALSE( 4714 env, value->IsArrayBuffer() || value->IsSharedArrayBuffer(), JSVM_ARRAYBUFFER_EXPECTED); 4715 4716 v8::Local<v8::ArrayBuffer> it = value.As<v8::ArrayBuffer>(); 4717 RETURN_STATUS_IF_FALSE( 4718 env, it->IsDetachable(), JSVM_DETACHABLE_ARRAYBUFFER_EXPECTED); 4719 4720 it->Detach(); 4721 4722 return jsvm_clear_last_error(env); 4723} 4724 4725JSVM_Status JSVM_CDECL OH_JSVM_IsDetachedArraybuffer(JSVM_Env env, 4726 JSVM_Value arraybuffer, 4727 bool* result) { 4728 CHECK_ENV(env); 4729 CHECK_ARG(env, arraybuffer); 4730 CHECK_ARG(env, result); 4731 4732 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer); 4733 4734 *result = 4735 value->IsArrayBuffer() && value.As<v8::ArrayBuffer>()->WasDetached(); 4736 4737 return jsvm_clear_last_error(env); 4738} 4739 4740JSVM_Status JSVM_CDECL 4741OH_JSVM_DefineClassWithPropertyHandler(JSVM_Env env, 4742 const char* utf8name, 4743 size_t length, 4744 JSVM_Callback constructor, 4745 size_t propertyCount, 4746 const JSVM_PropertyDescriptor* properties, 4747 JSVM_PropertyHandlerCfg propertyHandlerCfg, 4748 JSVM_Callback callAsFunctionCallback, 4749 JSVM_Value* result) { 4750 JSVM_PREAMBLE(env); 4751 CHECK_ARG(env, result); 4752 CHECK_ARG(env, constructor); 4753 CHECK_ARG(env, constructor->callback); 4754 CHECK_ARG(env, propertyHandlerCfg); 4755 4756 if (propertyCount > 0) { 4757 CHECK_ARG(env, properties); 4758 } 4759 4760 v8::Isolate* isolate = env->isolate; 4761 v8::EscapableHandleScope scope(isolate); 4762 v8::Local<v8::FunctionTemplate> tpl; 4763 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate( 4764 env, constructor, &tpl)); 4765 4766 v8::Local<v8::String> name_string; 4767 CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length); 4768 tpl->SetClassName(name_string); 4769 4770 size_t static_property_count = 0; 4771 for (size_t i = 0; i < propertyCount; i++) { 4772 const JSVM_PropertyDescriptor* p = properties + i; 4773 4774 if ((p->attributes & JSVM_STATIC) != 0) { // attributes 4775 // Static properties are handled separately below. 4776 static_property_count++; 4777 continue; 4778 } 4779 4780 v8::Local<v8::Name> property_name; 4781 STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name)); 4782 v8::PropertyAttribute attributes = v8impl::V8PropertyAttributesFromDescriptor(p); 4783 4784 // This code is similar to that in OH_JSVM_DefineProperties(); the 4785 // difference is it applies to a template instead of an object, 4786 // and preferred PropertyAttribute for lack of PropertyDescriptor 4787 // support on ObjectTemplate. 4788 if (p->getter != nullptr || p->setter != nullptr) { 4789 v8::Local<v8::FunctionTemplate> getter_tpl; 4790 v8::Local<v8::FunctionTemplate> setter_tpl; 4791 if (p->getter != nullptr) { 4792 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate( 4793 env, p->getter, &getter_tpl)); 4794 } 4795 if (p->setter != nullptr) { 4796 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate( 4797 env, p->setter, &setter_tpl)); 4798 } 4799 4800 tpl->PrototypeTemplate()->SetAccessorProperty(property_name, 4801 getter_tpl, 4802 setter_tpl, 4803 attributes, 4804 v8::AccessControl::DEFAULT); 4805 } else if (p->method != nullptr) { 4806 v8::Local<v8::FunctionTemplate> t; 4807 if (p->attributes & JSVM_NO_RECEIVER_CHECK) { 4808 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate( 4809 env, p->method, &t)); 4810 } else { 4811 STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate( 4812 env, p->method, &t, v8::Signature::New(isolate, tpl))); 4813 } 4814 4815 tpl->PrototypeTemplate()->Set(property_name, t, attributes); 4816 } else { 4817 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value); 4818 tpl->PrototypeTemplate()->Set(property_name, value, attributes); 4819 } 4820 } 4821 4822 /* register property handler for instance object */ 4823 v8impl::JSVM_PropertyHandlerCfgStruct* propertyHandleCfg = v8impl::CreatePropertyCfg(env, propertyHandlerCfg); 4824 if (propertyHandleCfg == nullptr) { 4825 return JSVM_Status::JSVM_GENERIC_FAILURE; 4826 } 4827 v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New(env, propertyHandleCfg); 4828 4829 // register named property handler 4830 v8::NamedPropertyHandlerConfiguration namedPropertyHandler; 4831 if (propertyHandlerCfg->genericNamedPropertyGetterCallback) { 4832 namedPropertyHandler.getter = v8impl::PropertyCallbackWrapper<v8::Value>::NameGetterInvoke; 4833 } 4834 if (propertyHandlerCfg->genericNamedPropertySetterCallback) { 4835 namedPropertyHandler.setter = v8impl::PropertyCallbackWrapper<v8::Value>::NameSetterInvoke; 4836 } 4837 if (propertyHandlerCfg->genericNamedPropertyDeleterCallback) { 4838 namedPropertyHandler.deleter = v8impl::PropertyCallbackWrapper<v8::Boolean>::NameDeleterInvoke; 4839 } 4840 if (propertyHandlerCfg->genericNamedPropertyEnumeratorCallback) { 4841 namedPropertyHandler.enumerator = v8impl::PropertyCallbackWrapper<v8::Array>::NameEnumeratorInvoke; 4842 } 4843 namedPropertyHandler.data = cbdata; 4844 tpl->InstanceTemplate()->SetHandler(namedPropertyHandler); 4845 4846 // register indexed property handle 4847 v8::IndexedPropertyHandlerConfiguration indexPropertyHandler; 4848 if (propertyHandlerCfg->genericIndexedPropertyGetterCallback) { 4849 indexPropertyHandler.getter = v8impl::PropertyCallbackWrapper<v8::Value>::IndexGetterInvoke; 4850 } 4851 if (propertyHandlerCfg->genericIndexedPropertySetterCallback) { 4852 indexPropertyHandler.setter = v8impl::PropertyCallbackWrapper<v8::Value>::IndexSetterInvoke; 4853 } 4854 if (propertyHandlerCfg->genericIndexedPropertyDeleterCallback) { 4855 indexPropertyHandler.deleter = v8impl::PropertyCallbackWrapper<v8::Boolean>::IndexDeleterInvoke; 4856 } 4857 if (propertyHandlerCfg->genericIndexedPropertyEnumeratorCallback) { 4858 indexPropertyHandler.enumerator = v8impl::PropertyCallbackWrapper<v8::Array>::IndexEnumeratorInvoke; 4859 } 4860 indexPropertyHandler.data = cbdata; 4861 tpl->InstanceTemplate()->SetHandler(indexPropertyHandler); 4862 4863 // register call as function 4864 if (callAsFunctionCallback && callAsFunctionCallback->callback) { 4865 v8::Local<v8::Value> funcCbdata = v8impl::CallbackBundle::New(env, callAsFunctionCallback); 4866 tpl->InstanceTemplate()->SetCallAsFunctionHandler(v8impl::FunctionCallbackWrapper::Invoke, funcCbdata); 4867 } 4868 4869 v8::Local<v8::Context> context = env->context(); 4870 *result = v8impl::JsValueFromV8LocalValue( 4871 scope.Escape(tpl->GetFunction(context).ToLocalChecked())); 4872 4873 v8impl::Reference::New(env, v8impl::V8LocalValueFromJsValue(*result), 0, v8impl::Ownership::kRuntime, 4874 v8impl::CfgFinalizedCallback, propertyHandleCfg, nullptr); 4875 4876 if (static_property_count > 0) { 4877 std::vector<JSVM_PropertyDescriptor> static_descriptors; 4878 static_descriptors.reserve(static_property_count); 4879 4880 for (size_t i = 0; i < propertyCount; i++) { 4881 const JSVM_PropertyDescriptor* p = properties + i; 4882 if ((p->attributes & JSVM_STATIC) != 0) { 4883 static_descriptors.push_back(*p); 4884 } 4885 } 4886 4887 STATUS_CALL(OH_JSVM_DefineProperties( 4888 env, *result, static_descriptors.size(), static_descriptors.data())); 4889 } 4890 4891 return GET_RETURN_STATUS(env); 4892} 4893 4894JSVM_Status JSVM_CDECL OH_JSVM_IsLocked(JSVM_Env env, 4895 bool* isLocked) { 4896 CHECK_ENV(env); 4897 CHECK_ARG(env, isLocked); 4898 4899 *isLocked = v8::Locker::IsLocked(env->isolate); 4900 4901 return jsvm_clear_last_error(env); 4902} 4903 4904JSVM_Status JSVM_CDECL OH_JSVM_AcquireLock(JSVM_Env env) { 4905 CHECK_ENV(env); 4906 4907 bool isLocked = v8::Locker::IsLocked(env->isolate); 4908 if (!isLocked) { 4909 env->locker = new v8::Locker(env->isolate); 4910 } 4911 4912 return jsvm_clear_last_error(env); 4913} 4914 4915JSVM_Status JSVM_CDECL OH_JSVM_ReleaseLock(JSVM_Env env) { 4916 CHECK_ENV(env); 4917 4918 bool isLocked = v8::Locker::IsLocked(env->isolate); 4919 if (isLocked && env->locker != nullptr) { 4920 delete env->locker; 4921 env->locker = nullptr; 4922 } 4923 4924 return jsvm_clear_last_error(env); 4925} 4926 4927JSVM_Status JSVM_CDECL OH_JSVM_IsCallable(JSVM_Env env, 4928 JSVM_Value value, 4929 bool* isCallable) { 4930 CHECK_ENV(env); 4931 CHECK_ARG(env, value); 4932 CHECK_ARG(env, isCallable); 4933 4934 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 4935 4936 *isCallable = val->IsFunction(); 4937 return jsvm_clear_last_error(env); 4938} 4939 4940JSVM_Status JSVM_CDECL OH_JSVM_IsUndefined(JSVM_Env env, 4941 JSVM_Value value, 4942 bool* isUndefined) { 4943 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 4944 // calls here cannot throw JS exceptions. 4945 CHECK_ENV(env); 4946 CHECK_ARG(env, value); 4947 CHECK_ARG(env, isUndefined); 4948 4949 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 4950 *isUndefined = val->IsUndefined(); 4951 4952 return jsvm_clear_last_error(env); 4953} 4954 4955JSVM_Status JSVM_CDECL OH_JSVM_IsNull(JSVM_Env env, 4956 JSVM_Value value, 4957 bool* isNull) { 4958 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 4959 // calls here cannot throw JS exceptions. 4960 CHECK_ENV(env); 4961 CHECK_ARG(env, value); 4962 CHECK_ARG(env, isNull); 4963 4964 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 4965 *isNull = val->IsNull(); 4966 4967 return jsvm_clear_last_error(env); 4968} 4969 4970JSVM_Status JSVM_CDECL OH_JSVM_IsNullOrUndefined(JSVM_Env env, 4971 JSVM_Value value, 4972 bool* isNullOrUndefined) { 4973 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 4974 // calls here cannot throw JS exceptions. 4975 CHECK_ENV(env); 4976 CHECK_ARG(env, value); 4977 CHECK_ARG(env, isNullOrUndefined); 4978 4979 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 4980 *isNullOrUndefined = val->IsNullOrUndefined(); 4981 4982 return jsvm_clear_last_error(env); 4983} 4984 4985JSVM_Status JSVM_CDECL OH_JSVM_IsBoolean(JSVM_Env env, 4986 JSVM_Value value, 4987 bool* isBoolean) { 4988 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 4989 // calls here cannot throw JS exceptions. 4990 CHECK_ENV(env); 4991 CHECK_ARG(env, value); 4992 CHECK_ARG(env, isBoolean); 4993 4994 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 4995 *isBoolean = val->IsBoolean(); 4996 4997 return jsvm_clear_last_error(env); 4998} 4999 5000JSVM_Status JSVM_CDECL OH_JSVM_IsNumber(JSVM_Env env, 5001 JSVM_Value value, 5002 bool* isNumber) { 5003 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 5004 // calls here cannot throw JS exceptions. 5005 CHECK_ENV(env); 5006 CHECK_ARG(env, value); 5007 CHECK_ARG(env, isNumber); 5008 5009 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 5010 *isNumber = val->IsNumber(); 5011 5012 return jsvm_clear_last_error(env); 5013} 5014 5015JSVM_Status JSVM_CDECL OH_JSVM_IsString(JSVM_Env env, 5016 JSVM_Value value, 5017 bool* isString) { 5018 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 5019 // calls here cannot throw JS exceptions. 5020 CHECK_ENV(env); 5021 CHECK_ARG(env, value); 5022 CHECK_ARG(env, isString); 5023 5024 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 5025 *isString = val->IsString(); 5026 5027 return jsvm_clear_last_error(env); 5028} 5029 5030JSVM_Status JSVM_CDECL OH_JSVM_IsSymbol(JSVM_Env env, 5031 JSVM_Value value, 5032 bool* isSymbol) { 5033 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 5034 // calls here cannot throw JS exceptions. 5035 CHECK_ENV(env); 5036 CHECK_ARG(env, value); 5037 CHECK_ARG(env, isSymbol); 5038 5039 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 5040 *isSymbol = val->IsSymbol(); 5041 5042 return jsvm_clear_last_error(env); 5043} 5044 5045JSVM_Status JSVM_CDECL OH_JSVM_IsFunction(JSVM_Env env, 5046 JSVM_Value value, 5047 bool* isFunction) { 5048 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 5049 // calls here cannot throw JS exceptions. 5050 CHECK_ENV(env); 5051 CHECK_ARG(env, value); 5052 CHECK_ARG(env, isFunction); 5053 5054 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 5055 *isFunction = val->IsFunction(); 5056 5057 return jsvm_clear_last_error(env); 5058} 5059 5060JSVM_Status JSVM_CDECL OH_JSVM_IsObject(JSVM_Env env, 5061 JSVM_Value value, 5062 bool* isObject) { 5063 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 5064 // calls here cannot throw JS exceptions. 5065 CHECK_ENV(env); 5066 CHECK_ARG(env, value); 5067 CHECK_ARG(env, isObject); 5068 5069 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 5070 *isObject = val->IsObject(); 5071 5072 return jsvm_clear_last_error(env); 5073} 5074 5075JSVM_Status JSVM_CDECL OH_JSVM_IsBigInt(JSVM_Env env, 5076 JSVM_Value value, 5077 bool* isBigInt) { 5078 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 5079 // calls here cannot throw JS exceptions. 5080 CHECK_ENV(env); 5081 CHECK_ARG(env, value); 5082 CHECK_ARG(env, isBigInt); 5083 5084 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 5085 *isBigInt = val->IsBigInt(); 5086 5087 return jsvm_clear_last_error(env); 5088} 5089 5090JSVM_Status JSVM_CDECL OH_JSVM_IsConstructor(JSVM_Env env, 5091 JSVM_Value value, 5092 bool* isConstructor) { 5093 CHECK_ENV(env); 5094 CHECK_ARG(env, value); 5095 CHECK_ARG(env, isConstructor); 5096 5097 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 5098 if (!val->IsObject()) { 5099 *isConstructor = false; 5100 return jsvm_clear_last_error(env); 5101 } 5102 v8::Local<v8::Object> obj = val.As<v8::Object>(); 5103 *isConstructor = obj->IsConstructor(); 5104 5105 return jsvm_clear_last_error(env); 5106} 5107 5108JSVM_Status JSVM_CDECL OH_JSVM_CreateSet(JSVM_Env env, 5109 JSVM_Value* result) { 5110 CHECK_ENV(env); 5111 CHECK_ARG(env, result); 5112 5113 *result = v8impl::JsValueFromV8LocalValue(v8::Set::New(env->isolate)); 5114 5115 return jsvm_clear_last_error(env); 5116} 5117 5118JSVM_Status JSVM_CDECL OH_JSVM_CreateRegExp(JSVM_Env env, 5119 JSVM_Value value, 5120 JSVM_RegExpFlags flags, 5121 JSVM_Value* result) { 5122 JSVM_PREAMBLE(env); 5123 CHECK_ARG(env, value); 5124 CHECK_ARG(env, result); 5125 5126 v8::Local<v8::Value> pattern = v8impl::V8LocalValueFromJsValue(value); 5127 RETURN_STATUS_IF_FALSE(env, pattern->IsString(), JSVM_STRING_EXPECTED); 5128 v8::Local<v8::Context> context = env->context(); 5129 v8::MaybeLocal<v8::RegExp> regExp = v8::RegExp::New(context, pattern.As<v8::String>(), 5130 static_cast<v8::RegExp::Flags>(flags)); 5131 CHECK_MAYBE_EMPTY(env, regExp, JSVM_GENERIC_FAILURE); 5132 *result = v8impl::JsValueFromV8LocalValue(regExp.ToLocalChecked()); 5133 5134 return GET_RETURN_STATUS(env); 5135} 5136 5137JSVM_Status JSVM_CDECL OH_JSVM_CreateMap(JSVM_Env env, JSVM_Value* result) { 5138 CHECK_ENV(env); 5139 CHECK_ARG(env, result); 5140 5141 *result = v8impl::JsValueFromV8LocalValue(v8::Map::New(env->isolate)); 5142 5143 return jsvm_clear_last_error(env); 5144} 5145 5146JSVM_Status JSVM_CDECL OH_JSVM_IsMap(JSVM_Env env, 5147 JSVM_Value value, 5148 bool* isMap) { 5149 CHECK_ENV(env); 5150 CHECK_ARG(env, value); 5151 CHECK_ARG(env, isMap); 5152 5153 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 5154 5155 *isMap = val->IsMap(); 5156 return jsvm_clear_last_error(env); 5157} 5158 5159JSVM_Status JSVM_CDECL OH_JSVM_IsSet(JSVM_Env env, 5160 JSVM_Value value, 5161 bool* isSet) { 5162 CHECK_ENV(env); 5163 CHECK_ARG(env, value); 5164 CHECK_ARG(env, isSet); 5165 5166 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 5167 *isSet = val->IsSet(); 5168 5169 return jsvm_clear_last_error(env); 5170} 5171 5172JSVM_Status JSVM_CDECL OH_JSVM_ObjectGetPrototypeOf(JSVM_Env env, 5173 JSVM_Value object, 5174 JSVM_Value* result) { 5175 JSVM_PREAMBLE(env); 5176 CHECK_ARG(env, result); 5177 5178 v8::Local<v8::Context> context = env->context(); 5179 5180 v8::Local<v8::Object> obj; 5181 CHECK_TO_OBJECT(env, context, obj, object); 5182 5183 v8::Local<v8::Value> val = obj->GetPrototypeV2(); 5184 *result = v8impl::JsValueFromV8LocalValue(val); 5185 return GET_RETURN_STATUS(env); 5186} 5187 5188JSVM_Status JSVM_CDECL OH_JSVM_ObjectSetPrototypeOf(JSVM_Env env, 5189 JSVM_Value object, 5190 JSVM_Value prototype) { 5191 JSVM_PREAMBLE(env); 5192 CHECK_ARG(env, prototype); 5193 5194 v8::Local<v8::Context> context = env->context(); 5195 5196 v8::Local<v8::Object> obj; 5197 CHECK_TO_OBJECT(env, context, obj, object); 5198 5199 v8::Local<v8::Value> type = v8impl::V8LocalValueFromJsValue(prototype); 5200 RETURN_STATUS_IF_FALSE(env, type->IsObject(), JSVM_INVALID_ARG); 5201 v8::Maybe<bool> set_maybe = obj->SetPrototypeV2(context, type); 5202 5203 RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), JSVM_GENERIC_FAILURE); 5204 return GET_RETURN_STATUS(env); 5205} 5206 5207JSVM_Status JSVM_CDECL OH_JSVM_RetainScript(JSVM_Env env, JSVM_Script script) { 5208 CHECK_ENV(env); 5209 auto jsvmData = reinterpret_cast<JSVM_Data__ *>(script); 5210 5211 RETURN_STATUS_IF_FALSE(env, jsvmData && !jsvmData->isGlobal, JSVM_INVALID_ARG); 5212 5213 jsvmData->taggedPointer = v8::Global<v8::Script>( 5214 env->isolate, jsvmData->ToV8Local<v8::Script>(env->isolate)); 5215 5216 jsvmData->isGlobal = true; 5217 return jsvm_clear_last_error(env); 5218} 5219 5220JSVM_Status JSVM_CDECL OH_JSVM_ReleaseScript(JSVM_Env env, JSVM_Script script) { 5221 CHECK_ENV(env); 5222 auto jsvmData = reinterpret_cast<JSVM_Data__ *>(script); 5223 5224 RETURN_STATUS_IF_FALSE(env, jsvmData && jsvmData->isGlobal, JSVM_INVALID_ARG); 5225 5226 std::get<v8::Global<v8::Script>>(jsvmData->taggedPointer).Reset(); 5227 delete jsvmData; 5228 return jsvm_clear_last_error(env); 5229} 5230 5231int FindAvailablePort() { 5232 constexpr int startPort = 9229; 5233 constexpr int endPort = 9999; 5234 constexpr int invalidPort = -1; 5235 int sockfd = -1; 5236 5237 for (auto port = startPort; port <= endPort; ++port) { 5238 sockfd = socket(AF_INET, SOCK_STREAM, 0); 5239 if (sockfd < 0) { 5240 continue; 5241 } 5242 struct sockaddr_in addr; 5243 addr.sin_family = AF_INET; 5244 addr.sin_addr.s_addr = htonl(INADDR_ANY); 5245 addr.sin_port = htons(port); 5246 5247 if (bind(sockfd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 0) { 5248 close(sockfd); 5249 if (errno == EADDRINUSE) { 5250 continue; 5251 } else { 5252 break; 5253 } 5254 } 5255 close(sockfd); 5256 return port; 5257 } 5258 return invalidPort; 5259} 5260 5261JSVM_Status JSVM_CDECL OH_JSVM_OpenInspectorWithName(JSVM_Env env, 5262 int pid, 5263 const char* name) { 5264 JSVM_PREAMBLE(env); 5265 RETURN_STATUS_IF_FALSE(env, !name || strlen(name) < SIZE_MAX , JSVM_INVALID_ARG); 5266 RETURN_STATUS_IF_FALSE(env, pid >= 0, JSVM_INVALID_ARG); 5267 std::string path(name ? name : "jsvm"); 5268 auto port = FindAvailablePort(); 5269 auto hostPort = 5270 std::make_shared<node::ExclusiveAccess<node::HostPort>>("localhost", port, pid); 5271 env->inspector_agent()->Start(path, hostPort, true, false); 5272 return GET_RETURN_STATUS(env); 5273} 5274 5275JSVM_Status JSVM_CDECL OH_JSVM_CompileWasmModule(JSVM_Env env, 5276 const uint8_t *wasmBytecode, 5277 size_t wasmBytecodeLength, 5278 const uint8_t *cacheData, 5279 size_t cacheDataLength, 5280 bool *cacheRejected, 5281 JSVM_Value *wasmModule) { 5282 JSVM_PREAMBLE(env); 5283 CHECK_ARG(env, wasmBytecode); 5284 RETURN_STATUS_IF_FALSE(env, wasmBytecodeLength > 0, JSVM_INVALID_ARG); 5285 v8::MaybeLocal<v8::WasmModuleObject> maybe_module; 5286 if (cacheData == nullptr) { 5287 maybe_module = v8::WasmModuleObject::Compile(env->isolate, {wasmBytecode, wasmBytecodeLength}); 5288 } else { 5289 RETURN_STATUS_IF_FALSE(env, cacheDataLength > 0, JSVM_INVALID_ARG); 5290 bool rejected; 5291 maybe_module = v8::WasmModuleObject::DeserializeOrCompile( 5292 env->isolate, {wasmBytecode, wasmBytecodeLength}, {cacheData, cacheDataLength}, rejected); 5293 if (cacheRejected != nullptr) { 5294 *cacheRejected = rejected; 5295 } 5296 } 5297 // To avoid the status code caused by exception being override, check exception once v8 API finished 5298 if (try_catch.HasCaught()) { 5299 return jsvm_set_last_error(env, JSVM_PENDING_EXCEPTION); 5300 } 5301 CHECK_MAYBE_EMPTY(env, maybe_module, JSVM_GENERIC_FAILURE); 5302 *wasmModule = v8impl::JsValueFromV8LocalValue(maybe_module.ToLocalChecked()); 5303 return jsvm_clear_last_error(env); 5304} 5305 5306JSVM_Status JSVM_CDECL OH_JSVM_CompileWasmFunction(JSVM_Env env, 5307 JSVM_Value wasmModule, 5308 uint32_t functionIndex, 5309 JSVM_WasmOptLevel optLevel) { 5310 JSVM_PREAMBLE(env); 5311 CHECK_ARG(env, wasmModule); 5312 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(wasmModule); 5313 RETURN_STATUS_IF_FALSE(env, val->IsWasmModuleObject(), JSVM_INVALID_ARG); 5314 5315 v8::Local<v8::WasmModuleObject> v8WasmModule = val.As<v8::WasmModuleObject>(); 5316 v8::WasmExecutionTier tier = v8::WasmExecutionTier::kNone; 5317 if (optLevel == JSVM_WASM_OPT_BASELINE) { 5318 // v8 liftoff has bug, keep BASELINE same as HIGH. 5319 tier = v8::WasmExecutionTier::kTurbofan; 5320 } else if (optLevel == JSVM_WASM_OPT_HIGH) { 5321 tier = v8::WasmExecutionTier::kTurbofan; 5322 } else { 5323 // Unsupported optLevel 5324 return jsvm_set_last_error(env, JSVM_INVALID_ARG); 5325 } 5326 bool compileSuccess = v8WasmModule->CompileFunction(env->isolate, functionIndex, tier); 5327 // To avoid the status code caused by exception being override, check exception once v8 API finished 5328 if (try_catch.HasCaught()) { 5329 return jsvm_set_last_error(env, JSVM_PENDING_EXCEPTION); 5330 } 5331 RETURN_STATUS_IF_FALSE(env, compileSuccess, JSVM_GENERIC_FAILURE); 5332 return jsvm_clear_last_error(env); 5333} 5334 5335JSVM_Status JSVM_CDECL OH_JSVM_IsWasmModuleObject(JSVM_Env env, 5336 JSVM_Value value, 5337 bool* result) { 5338 // Omit JSVM_PREAMBLE and GET_RETURN_STATUS because V8 5339 // calls here cannot throw JS exceptions. 5340 CHECK_ENV(env); 5341 CHECK_ARG(env, value); 5342 CHECK_ARG(env, result); 5343 5344 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value); 5345 *result = val->IsWasmModuleObject(); 5346 5347 return jsvm_clear_last_error(env); 5348} 5349 5350JSVM_Status JSVM_CDECL OH_JSVM_CreateWasmCache(JSVM_Env env, 5351 JSVM_Value wasmModule, 5352 const uint8_t** data, 5353 size_t* length) { 5354 JSVM_PREAMBLE(env); 5355 CHECK_ARG(env, wasmModule); 5356 CHECK_ARG(env, data); 5357 CHECK_ARG(env, length); 5358 5359 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(wasmModule); 5360 RETURN_STATUS_IF_FALSE(env, val->IsWasmModuleObject(), JSVM_INVALID_ARG); 5361 5362 v8::Local<v8::WasmModuleObject> v8WasmModule = val.As<v8::WasmModuleObject>(); 5363 v8::CompiledWasmModule compiledWasmModule = v8WasmModule->GetCompiledModule(); 5364 v8::OwnedBuffer serialized_bytes = compiledWasmModule.Serialize(); 5365 // To avoid the status code caused by exception being override, check exception once v8 API finished 5366 if (try_catch.HasCaught()) { 5367 return jsvm_set_last_error(env, JSVM_PENDING_EXCEPTION); 5368 } 5369 // If buffer size is 0, create wasm cache failed. 5370 RETURN_STATUS_IF_FALSE(env, serialized_bytes.size > 0, JSVM_GENERIC_FAILURE); 5371 *data = serialized_bytes.buffer.get(); 5372 *length = serialized_bytes.size; 5373 // Release the ownership of buffer, OH_JSVM_ReleaseCache must be called explicitly to release the buffer 5374 serialized_bytes.buffer.release(); 5375 5376 return GET_RETURN_STATUS(env); 5377} 5378 5379JSVM_Status JSVM_CDECL OH_JSVM_ReleaseCache(JSVM_Env env, 5380 const uint8_t* cacheData, 5381 JSVM_CacheType cacheType) { 5382 CHECK_ENV(env); 5383 CHECK_ARG(env, cacheData); 5384 if (cacheType == JSVM_CACHE_TYPE_JS) { 5385 // The release behavior MUST match the memory allocation of OH_JSVM_CreateCodeCache. 5386 delete[] cacheData; 5387 } else if (cacheType == JSVM_CACHE_TYPE_WASM) { 5388 // The release behavior MUST match the memory allocation of OH_JSVM_CreateWasmCache. 5389 delete[] cacheData; 5390 } else { 5391 // Unsupported cacheType 5392 return jsvm_set_last_error(env, JSVM_INVALID_ARG); 5393 } 5394 return jsvm_clear_last_error(env); 5395} 5396