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