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