/* * Tencent is pleased to support the open source community by making ScriptX available. * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "../../src/Native.hpp" #include "../../src/Reference.h" #include "../../src/Utils.h" #include "V8Engine.h" #include "V8Helper.hpp" namespace script { Local Number::newNumber(int32_t value) { return Local(v8::Integer::New(v8_backend::currentEngineIsolateChecked(), value)); } Local Number::newNumber(int64_t value) { return newNumber(static_cast(value)); } Local Number::newNumber(float value) { return newNumber(static_cast(value)); } Local Number::newNumber(double value) { return Local(v8::Number::New(v8_backend::currentEngineIsolateChecked(), value)); } Local Object::newObject() { return Local(v8::Object::New(v8_backend::currentEngineIsolateChecked())); } Local Object::newObjectImpl(const Local& type, size_t size, const Local* args) { auto&& [isolate, context] = v8_backend::currentEngineIsolateAndContextChecked(); v8::TryCatch tryCatch(isolate); auto ret = v8_backend::toV8ValueArray>( isolate, size, args, [&type, &size, iso = isolate, &ctx = context](auto* v8Args) { return v8_backend::V8Engine::toV8(iso, type.asFunction()) ->NewInstance(ctx, static_cast(size), v8Args); }); v8_backend::checkException(tryCatch); return Local(ret.ToLocalChecked()); } Local String::newString(const char* utf8) { if (!utf8) throw Exception("null pointer"); return newString(std::string_view(utf8)); } Local String::newString(std::string_view utf8) { auto isolate = v8_backend::currentEngineIsolateChecked(); v8::TryCatch tryCatch(isolate); auto ret = v8::String::NewFromUtf8(isolate, utf8.data(), v8::NewStringType::kNormal, static_cast(utf8.length())); v8_backend::checkException(tryCatch); return Local(ret.ToLocalChecked()); } Local String::newString(const std::string& utf8) { return newString(std::string_view(utf8)); } #if defined(__cpp_char8_t) Local String::newString(const char8_t* utf8) { if (!utf8) throw Exception("null pointer"); return newString(std::u8string_view(utf8)); } Local String::newString(std::u8string_view utf8) { // we just cast char8_t* to char8_t for now. // remove cast once V8 have an overloaded version. v8::TryCatch tryCatch(v8_backend::currentEngineIsolateChecked()); auto ret = v8::String::NewFromUtf8(v8_backend::currentEngineIsolateChecked(), reinterpret_cast(utf8.data()), v8::NewStringType::kNormal, utf8.length()); v8_backend::checkException(tryCatch); return Local(ret.ToLocalChecked()); } Local String::newString(const std::u8string& utf8) { return newString(std::u8string_view(utf8)); } #endif Local Boolean::newBoolean(bool value) { return Local(v8::Boolean::New(v8_backend::currentEngineIsolateChecked(), value)); } Local Function::newFunction(::script::FunctionCallback callback) { auto&& [isolate, context] = v8_backend::currentEngineIsolateAndContextChecked(); v8::TryCatch tryCatch(isolate); struct FunctionData { v8_backend::V8Engine* engine = nullptr; ::script::FunctionCallback function; }; auto data = std::make_unique(); data->engine = v8_backend::currentEngine(); data->function = std::move(callback); auto param = v8::External::New(isolate, static_cast(data.get())).As(); auto funcTemplate = v8::FunctionTemplate::New( isolate, [](const v8::FunctionCallbackInfo& info) { auto data = static_cast(info.Data().As()->Value()); // we don't have a function name Tracer trace(data->engine, "NativeFunction"); try { Arguments args = v8_backend::V8Engine::extractV8Arguments(data->engine, info); auto returnVal = (data->function)(args); info.GetReturnValue().Set(v8_backend::V8Engine::toV8(info.GetIsolate(), returnVal)); } catch (Exception& e) { v8_backend::rethrowException(e); } }, param); funcTemplate->RemovePrototype(); auto func = funcTemplate->GetFunction(context); v8_backend::checkException(tryCatch); v8_backend::currentEngineChecked().addManagedObject( data.release(), func.ToLocalChecked(), [](void* ptr) { delete reinterpret_cast(ptr); }); return Local(func.ToLocalChecked()); } Local Array::newArray(size_t size) { return Local( v8::Array::New(v8_backend::currentEngineIsolateChecked(), static_cast(size))); } template static v8::Local newV8Array(size_t argc, It begin, It end) { auto isolate = v8_backend::currentEngineIsolateChecked(); return v8_backend::toV8ValueArray>( isolate, argc, begin, end, [argc, iso = isolate](auto* args) { return v8::Array::New(iso, args, argc); }); } Local Array::newArrayImpl(size_t size, const Local* args) { auto isolate = v8_backend::currentEngineIsolateChecked(); return v8_backend::toV8ValueArray>( isolate, size, args, [size, iso = isolate](auto* args) { return Local{v8::Array::New(iso, args, size)}; }); } Local ByteBuffer::newByteBuffer(size_t size) { return Local(v8::ArrayBuffer::New(v8_backend::currentEngineIsolateChecked(), size)); } Local ByteBuffer::newByteBuffer(void* nativeBuffer, size_t size) { auto ret = newByteBuffer(size); std::memcpy(ret.getRawBytes(), nativeBuffer, size); return ret; } #if V8_MAJOR_VERSION >= 8 // v8 8.0 introduced new api for this // https://docs.google.com/document/d/1sTc_jRL87Fu175Holm5SV0kajkseGl2r8ifGY76G35k/edit Local ByteBuffer::newByteBuffer(std::shared_ptr buffer, size_t size) { auto data = buffer.get(); auto backingStore = v8::ArrayBuffer::NewBackingStore( data, size, [](void* /*data*/, size_t /*length*/, void* deleter_data) { delete static_cast*>(deleter_data); }, new std::shared_ptr(std::move(buffer))); return Local( v8::ArrayBuffer::New(v8_backend::currentEngineIsolateChecked(), std::move(backingStore))); } #else Local ByteBuffer::newByteBuffer(std::shared_ptr buffer, size_t size) { auto arrayBuffer = v8::ArrayBuffer::New(v8_backend::currentEngineIsolateChecked(), buffer.get(), size); using BookKeep = std::shared_ptr; auto bookKeep = std::make_unique(std::move(buffer)); v8_backend::currentEngine()->addManagedObject( bookKeep.get(), arrayBuffer, [](void* ptr) { delete static_cast(ptr); }); Local ret(arrayBuffer); static_cast(bookKeep.release()); return ret; } #endif } // namespace script