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