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