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