• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }