diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index e580beed..5f01d805 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -20,8 +20,8 @@ jobs: matrix: backends: [ V8, JavaScriptCore, QuickJs, Lua ] steps: - - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/checkout@v4.1.7 + - uses: actions/cache@v4.0.2 with: key: ScriptX-UnitTests-Depedencies-${{ hashFiles('test/cmake/**') }} path: | diff --git a/.github/workflows/sync_to_tencent_code.yml b/.github/workflows/sync_to_tencent_code.yml index a18ad9c3..7002ec66 100644 --- a/.github/workflows/sync_to_tencent_code.yml +++ b/.github/workflows/sync_to_tencent_code.yml @@ -9,7 +9,7 @@ jobs: timeout-minutes: 30 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4.1.7 with: fetch-depth: 0 - name: mirror-repository diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 0ede8b4f..a093bd33 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -24,8 +24,8 @@ jobs: # mac runner seems to be slow and rear # - Release steps: - - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/checkout@v4.1.7 + - uses: actions/cache@v4.0.2 with: key: ScriptX-UnitTests-Depedencies-${{ hashFiles('test/cmake/**') }} path: | @@ -61,15 +61,15 @@ jobs: - Debug - Release steps: - - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/checkout@v4.1.7 + - uses: actions/cache@v4.0.2 with: key: ScriptX-UnitTests-Depedencies-${{ hashFiles('test/cmake/**') }} path: | build/ScriptXTestLibs build/googletest-src - name: Add MSBuild to PATH - uses: microsoft/setup-msbuild@v1.0.2 + uses: microsoft/setup-msbuild@v2 - name: Configure cmake X64 if: matrix.backends != 'JavaScriptCore' shell: powershell @@ -112,8 +112,8 @@ jobs: - Debug - Release steps: - - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/checkout@v4.1.7 + - uses: actions/cache@v4.0.2 with: key: ScriptX-UnitTests-Depedencies-${{ hashFiles('test/cmake/**') }} path: | @@ -138,6 +138,29 @@ jobs: cd build ./UnitTests + ubuntu-v8-versions-build: + timeout-minutes: 60 + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + # format index{0 .. index-1}/concurrency + job_split: [ 0/8, 1/8, 2/8, 3/8, 4/8, 5/8, 6/8, 7/8 ] + steps: + - uses: actions/checkout@v4.1.7 + - uses: actions/cache@v4.0.2 + with: + key: ScriptX-UnitTests-Depedencies-${{ hashFiles('test/cmake/**') }} + path: | + build/ScriptXTestLibs + - name: Test build v8 on supported versions + env: + SCRIPTX_TEST_FORCE_UPDATE_DEPS: ON + SCRIPTX_TEST_V8_JOB_SPLIT_CONFIG: ${{ matrix.job_split }} + run: | + mkdir -p build && cd build + ../test/cmake/test_v8_compiles.sh continue + android-clang-build: # disable for now # 1. we don't have android libraries @@ -153,8 +176,8 @@ jobs: - Debug - Release steps: - - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/checkout@v4.1.7 + - uses: actions/cache@v4.0.2 with: key: ScriptX-UnitTests-Depedencies-${{ hashFiles('test/cmake/**') }} path: | @@ -185,9 +208,9 @@ jobs: matrix: node-version: [ 14.x, 15.x, 16.x, 18.x ] # 19.x steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4.1.7 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4.0.4 with: node-version: ${{ matrix.node-version }} - name: Prepare npm @@ -209,20 +232,20 @@ jobs: matrix: emscripten-version: [ '3.0.0', '3.1.33' ] steps: - - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/checkout@v4.1.7 + - uses: actions/cache@v4.0.2 with: key: ScriptX-UnitTests-Depedencies-${{ hashFiles('test/cmake/**') }} path: | build/ScriptXTestLibs build/googletest-src - name: Setup Emscripten - uses: mymindstorm/setup-emsdk@v11 + uses: mymindstorm/setup-emsdk@v14 with: version: ${{ matrix.emscripten-version }} actions-cache-folder: emsdk-cache-${{ matrix.emscripten-version }} - name: Setup Node.js - uses: actions/setup-node@v1 + uses: actions/setup-node@v4.0.4 with: node-version: '19.3.0' # insteadof '>= 14', use fixed version - name: Configure Webassembly backend diff --git a/CHANGELOG.md b/CHANGELOG.md index 1da39c5e..cc0ecb41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +Version 3.6.0 (2024-09): +1. `[V8]` add test infrastructure to test on multiple v8 versions +2. `[V8]` add support to v8 versions through 7.4~13.0 + Version 3.5.0 (2023-05): 1. `[QuickJs]` add support for QuickJs 2024-01-13 @@ -83,4 +87,4 @@ A Template backend which has no implementation. --- Version 0.0 (2019-10): -Project started. \ No newline at end of file +Project started. diff --git a/README-zh.md b/README-zh.md index 7dc7e6e6..84d297f3 100644 --- a/README-zh.md +++ b/README-zh.md @@ -20,7 +20,7 @@ ScriptX的术语中,"前端"指对外的C++ API,"后端"则指不同的底 | 后端 | 语言 | 版本 | 状态 | | :----: | :----: | :----: | :----: | -| V8 | JavaScript | 7.4+ | done | +| V8 | JavaScript | 7.4+
([tested versions][tested_v8_versions]) | done | | JavaScriptCore | JavaScript | 7604.1.38.0.7+
(iOS 10+/macOS10.12+) | done | | Node.js | JavaScript | 14.x+ | done | | QuickJs | JavaScript | 2024-01-13 | done | @@ -30,6 +30,7 @@ ScriptX的术语中,"前端"指对外的C++ API,"后端"则指不同的底 | YARV | Ruby | | todo | | Mono | C# | | todo | +[tested_v8_versions]: https://github.com/LanderlYoung/ScriptXTestLibs/blob/main/v8/supported_versions.txt # 简介 diff --git a/README.md b/README.md index 1c46d88a..ba3df45f 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ In ScriptX terminology, "front-end" refers to the external C++ API, and "back-en | backend | language | version | states | | :----: | :----: | :----: | :----: | -| V8 | JavaScript | 7.4+ | done | +| V8 | JavaScript | 7.4+
([tested versions][tested_v8_versions]) | done | | JavaScriptCore | JavaScript | 7604.1.38.0.7+
(iOS 10+/macOS10.12+) | done | | Node.js | JavaScript | 14.x+ | done | | QuickJs | JavaScript | 2024-01-13 | done | @@ -29,6 +29,8 @@ In ScriptX terminology, "front-end" refers to the external C++ API, and "back-en | YARV | Ruby | | todo | | Mono | C# | | todo | +[tested_v8_versions]: https://github.com/LanderlYoung/ScriptXTestLibs/blob/main/v8/supported_versions.txt + # Introduction The interface of ScriptX uses modern C++ features. And to be 100% in line with the C++ standard, completely cross-platform. diff --git a/VERSION b/VERSION index e5b82034..40c341bd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.5.0 \ No newline at end of file +3.6.0 diff --git a/backend/V8/V8Engine.cc b/backend/V8/V8Engine.cc index 11306559..5043d2df 100644 --- a/backend/V8/V8Engine.cc +++ b/backend/V8/V8Engine.cc @@ -158,8 +158,9 @@ Local V8Engine::eval(const Local& script, const Local& sou throw Exception("can't eval script"); } v8::ScriptOrigin origin( -#if SCRIPTX_V8_VERSION_AT_LEAST(9, 0) +#if SCRIPTX_V8_VERSION_BETWEEN(9, 0, 12, 0) // V8 9.0 add isolate param for external API + // V8 12.1 deprecated the isolate version, and introduced the one without isolation isolate_, #endif sourceFile.isNull() || !sourceFile.isString() ? v8::Local() @@ -180,17 +181,18 @@ Local V8Engine::eval(const Local& script) { return eval(script, { void V8Engine::registerNativeClassStatic(v8::Local funcT, const internal::StaticDefine* staticDefine) { for (auto& prop : staticDefine->properties) { + using PropDefPtr = internal::StaticDefine::PropertyDefine*; + StackFrameScope stack; auto name = String::newString(prop.name); - v8::AccessorGetterCallback getter = nullptr; - v8::AccessorSetterCallback setter = nullptr; + v8::AccessorNameGetterCallback getter = nullptr; + v8::AccessorNameSetterCallback setter = nullptr; if (prop.getter) { - getter = [](v8::Local /*property*/, + getter = [](v8::Local /*property*/, const v8::PropertyCallbackInfo& info) { - auto ptr = static_cast( - info.Data().As()->Value()); + auto ptr = static_cast(info.Data().As()->Value()); Tracer trace(EngineScope::currentEngine(), ptr->traceName); Local ret = ptr->getter(); try { @@ -202,10 +204,9 @@ void V8Engine::registerNativeClassStatic(v8::Local funcT, } if (prop.setter) { - setter = [](v8::Local /*property*/, v8::Local value, + setter = [](v8::Local /*property*/, v8::Local value, const v8::PropertyCallbackInfo& info) { - auto ptr = static_cast( - info.Data().As()->Value()); + auto ptr = static_cast(info.Data().As()->Value()); Tracer trace(EngineScope::currentEngine(), ptr->traceName); try { ptr->setter(make>(value)); @@ -216,25 +217,26 @@ void V8Engine::registerNativeClassStatic(v8::Local funcT, } else { // v8 requires setter to be present, otherwise, a real js set code with create a new // property... - setter = [](v8::Local property, v8::Local value, + setter = [](v8::Local property, v8::Local value, const v8::PropertyCallbackInfo& info) {}; } - funcT->SetNativeDataProperty( - toV8(isolate_, name), getter, setter, - v8::External::New(isolate_, const_cast(&prop)), - v8::PropertyAttribute::DontDelete); + // SetNativeDataProperty with Local and AccessControl is deprecated + funcT->SetNativeDataProperty(toV8(isolate_, name).As(), getter, setter, + v8::External::New(isolate_, const_cast(&prop)), + v8::PropertyAttribute::DontDelete); } for (auto& func : staticDefine->functions) { + using FuncDefPtr = internal::StaticDefine::FunctionDefine*; + StackFrameScope stack; auto name = String::newString(func.name); auto fn = v8::FunctionTemplate::New( isolate_, [](const v8::FunctionCallbackInfo& info) { - auto funcDef = reinterpret_cast( - info.Data().As()->Value()); + auto funcDef = reinterpret_cast(info.Data().As()->Value()); auto engine = v8_backend::currentEngine(); Tracer trace(engine, funcDef->traceName); @@ -245,8 +247,8 @@ void V8Engine::registerNativeClassStatic(v8::Local funcT, v8_backend::rethrowException(e); } }, - v8::External::New(isolate_, const_cast(&func)), {}, - 0, v8::ConstructorBehavior::kThrow); + v8::External::New(isolate_, const_cast(&func)), {}, 0, + v8::ConstructorBehavior::kThrow); if (!fn.IsEmpty()) { funcT->Set(toV8(isolate_, name), fn, v8::PropertyAttribute::DontDelete); } else { @@ -453,67 +455,67 @@ void V8Engine::registerNativeClassInstance(v8::Local funcT // instance auto instanceT = funcT->PrototypeTemplate(); auto signature = v8::Signature::New(isolate_, funcT); + for (auto& prop : classDefine->instanceDefine.properties) { + // Template::SetAccessor is removed in 12.8 + // using Template::SetAccessorProperty is recommended + + using PropDefPtr = typename internal::InstanceDefine::PropertyDefine*; StackFrameScope stack; auto name = String::newString(prop.name); - - v8::AccessorGetterCallback getter = nullptr; - v8::AccessorSetterCallback setter = nullptr; + auto data = v8::External::New(isolate_, const_cast(&prop)); + v8::Local getter; + v8::Local setter; if (prop.getter) { - getter = [](v8::Local property, const v8::PropertyCallbackInfo& info) { - auto ptr = static_cast(info.Data().As()->Value()); - auto thiz = static_cast(info.This()->GetAlignedPointerFromInternalField( - kInstanceObjectAlignedPointer_PolymorphicPointer)); - auto scriptClass = - static_cast(info.This()->GetAlignedPointerFromInternalField( - kInstanceObjectAlignedPointer_ScriptClass)); - auto& getter = ptr->getter; - - Tracer trace(scriptClass->getScriptEngine(), ptr->traceName); - - Local ret = (getter)(thiz); - try { - info.GetReturnValue().Set(toV8(info.GetIsolate(), ret)); - } catch (const Exception& e) { - v8_backend::rethrowException(e); - } - }; + getter = v8::FunctionTemplate::New( + isolate_, + [](const v8::FunctionCallbackInfo& info) { + auto ptr = static_cast(info.Data().As()->Value()); + auto thiz = static_cast(info.This()->GetAlignedPointerFromInternalField( + kInstanceObjectAlignedPointer_PolymorphicPointer)); + auto scriptClass = + static_cast(info.This()->GetAlignedPointerFromInternalField( + kInstanceObjectAlignedPointer_ScriptClass)); + auto& getter = ptr->getter; + + Tracer trace(scriptClass->getScriptEngine(), ptr->traceName); + + Local ret = (getter)(thiz); + try { + info.GetReturnValue().Set(toV8(info.GetIsolate(), ret)); + } catch (const Exception& e) { + v8_backend::rethrowException(e); + } + }, + data, signature); } if (prop.setter) { - setter = [](v8::Local property, v8::Local value, - const v8::PropertyCallbackInfo& info) { - auto ptr = static_cast(info.Data().As()->Value()); - auto thiz = static_cast(info.This()->GetAlignedPointerFromInternalField( - kInstanceObjectAlignedPointer_PolymorphicPointer)); - auto scriptClass = - static_cast(info.This()->GetAlignedPointerFromInternalField( - kInstanceObjectAlignedPointer_ScriptClass)); - auto& setter = ptr->setter; - - Tracer trace(scriptClass->getScriptEngine(), ptr->traceName); - - try { - (setter)(thiz, make>(value)); - } catch (const Exception& e) { - v8_backend::rethrowException(e); - } - }; + setter = v8::FunctionTemplate::New( + isolate_, + [](const v8::FunctionCallbackInfo& info) { + auto ptr = static_cast(info.Data().As()->Value()); + auto thiz = static_cast(info.This()->GetAlignedPointerFromInternalField( + kInstanceObjectAlignedPointer_PolymorphicPointer)); + auto scriptClass = + static_cast(info.This()->GetAlignedPointerFromInternalField( + kInstanceObjectAlignedPointer_ScriptClass)); + auto& setter = ptr->setter; + + Tracer trace(scriptClass->getScriptEngine(), ptr->traceName); + + try { + (setter)(thiz, make>(info[0])); + } catch (const Exception& e) { + v8_backend::rethrowException(e); + } + }, + data, signature); } - auto v8Name = toV8(isolate_, name); - auto data = v8::External::New( - isolate_, const_cast(&prop)); - -#if SCRIPTX_V8_VERSION_AT_MOST(10, 1) // SetAccessor AccessorSignature deprecated in 10.2 a8beac - auto accessSignature = v8::AccessorSignature::New(isolate_, funcT); - instanceT->SetAccessor(v8Name, getter, setter, data, v8::AccessControl::DEFAULT, - v8::PropertyAttribute::DontDelete, accessSignature); -#else - instanceT->SetAccessor(v8Name, getter, setter, data, v8::AccessControl::DEFAULT, - v8::PropertyAttribute::DontDelete); -#endif + instanceT->SetAccessorProperty(toV8(isolate_, name).As(), getter, setter, + v8::PropertyAttribute::DontDelete); } for (auto& func : classDefine->instanceDefine.functions) { @@ -541,7 +543,7 @@ void V8Engine::registerNativeClassInstance(v8::Local funcT }, v8::External::New(isolate_, const_cast(&func)), signature); if (!fn.IsEmpty()) { - funcT->PrototypeTemplate()->Set(toV8(isolate_, name), fn, v8::PropertyAttribute::DontDelete); + instanceT->Set(toV8(isolate_, name), fn, v8::PropertyAttribute::DontDelete); } else { throw Exception("can't create function for instance"); } diff --git a/backend/V8/V8Helper.h b/backend/V8/V8Helper.h index f03f73d3..7bed27cd 100644 --- a/backend/V8/V8Helper.h +++ b/backend/V8/V8Helper.h @@ -37,17 +37,16 @@ SCRIPTX_END_INCLUDE_LIBRARY // V8 version check helper // V8_version >= version -#define SCRIPTX_V8_VERSION_AT_LEAST(major, minor) \ +#define SCRIPTX_V8_VERSION_GE(major, minor) \ (V8_MAJOR_VERSION > (major) || (V8_MAJOR_VERSION == (major) && V8_MINOR_VERSION >= (minor))) // V8_version <= version -#define SCRIPTX_V8_VERSION_AT_MOST(major, minor) \ +#define SCRIPTX_V8_VERSION_LE(major, minor) \ (V8_MAJOR_VERSION < (major) || (V8_MAJOR_VERSION == (major) && V8_MINOR_VERSION <= (minor))) // old_version <= V8_version <= new_version #define SCRIPTX_V8_VERSION_BETWEEN(old_major, old_minor, new_major, new_minor) \ - SCRIPTX_V8_VERSION_AT_LEAST(old_major, old_minor) && \ - SCRIPTX_V8_VERSION_AT_MOST(new_major, new_minor) + SCRIPTX_V8_VERSION_GE(old_major, old_minor) && SCRIPTX_V8_VERSION_LE(new_major, new_minor) namespace script::v8_backend { @@ -73,4 +72,4 @@ void rethrowException(const Exception& exception); namespace script { struct v8_interop; -} \ No newline at end of file +} diff --git a/backend/V8/V8Platform.cc b/backend/V8/V8Platform.cc index 06c1df22..f8bd974f 100644 --- a/backend/V8/V8Platform.cc +++ b/backend/V8/V8Platform.cc @@ -16,8 +16,9 @@ */ #include "V8Platform.h" -#include +#include #include +#include #include "../../src/Utils.h" #include "V8Engine.h" #include "V8Helper.hpp" @@ -26,14 +27,9 @@ namespace script::v8_backend { class MessageQueueTaskRunner : public v8::TaskRunner { private: - V8Platform* platform_{}; v8::Isolate* isolate_{}; - std::shared_ptr defaultTaskRunner_{}; - V8Engine* engine_{}; - std::atomic_bool isPumpScheduled_{false}; - public: MessageQueueTaskRunner() = default; @@ -41,69 +37,81 @@ class MessageQueueTaskRunner : public v8::TaskRunner { ~MessageQueueTaskRunner() override = default; - bool hasRunner() const { return defaultTaskRunner_ != nullptr; } + bool inited() const { return isolate_ != nullptr; } - void setQueue(V8Platform* platform, v8::Isolate* isolate, - std::shared_ptr defaultTaskRunner) { - platform_ = platform; - isolate_ = isolate; - defaultTaskRunner_ = std::move(defaultTaskRunner); - } + void setQueue(v8::Isolate* isolate) { isolate_ = isolate; } void setEngine(V8Engine* engine) { engine_ = engine; } - void PostTask(std::unique_ptr task) override { - defaultTaskRunner_->PostTask(std::move(task)); - schedulePump(); +#if SCRIPTX_V8_VERSION_GE(12, 4) // changed to PostTaskImpl + void PostTaskImpl(std::unique_ptr task, const v8::SourceLocation& location) override { + scheduleTask(std::move(task)); + } + + void PostDelayedTaskImpl(std::unique_ptr task, double delay_in_seconds, + const v8::SourceLocation& location) override { + scheduleTask(std::move(task), delay_in_seconds); + } + + void PostIdleTaskImpl(std::unique_ptr task, + const v8::SourceLocation& location) override { + ::abort(); } + void PostNonNestableTaskImpl(std::unique_ptr task, + const v8::SourceLocation& location) override { + scheduleTask(std::move(task)); + } + + void PostNonNestableDelayedTaskImpl(std::unique_ptr task, double delay_in_seconds, + const v8::SourceLocation& location) override { + scheduleTask(std::move(task), delay_in_seconds); + } + +#else + void PostTask(std::unique_ptr task) override { scheduleTask(std::move(task)); } + void PostDelayedTask(std::unique_ptr task, double delay_in_seconds) override { - defaultTaskRunner_->PostDelayedTask(std::move(task), delay_in_seconds); - schedulePump(); + scheduleTask(std::move(task), delay_in_seconds); } void PostIdleTask(std::unique_ptr task) override { - defaultTaskRunner_->PostIdleTask(std::move(task)); - schedulePump(); + // not supported + ::abort(); } - bool IdleTasksEnabled() override { return defaultTaskRunner_->IdleTasksEnabled(); } + void PostNonNestableTask(std::unique_ptr task) override { + scheduleTask(std::move(task)); + } +#endif + + bool IdleTasksEnabled() override { return false; } - void PostNonNestableTask(std::unique_ptr task) override { PostTask(std::move(task)); } + bool NonNestableTasksEnabled() const override { return true; } +#if SCRIPTX_V8_VERSION_BETWEEN(7, 5, 12, 4) void PostNonNestableDelayedTask(std::unique_ptr task, double delay_in_seconds) override { - PostDelayedTask(std::move(task), delay_in_seconds); + scheduleTask(std::move(task), delay_in_seconds); } +#endif - bool NonNestableTasksEnabled() const override { return true; } - +#if SCRIPTX_V8_VERSION_GE(7, 5) bool NonNestableDelayedTasksEnabled() const override { return true; } +#endif private: - void schedulePump() { - bool expected = false; - if (engine_ && isPumpScheduled_.compare_exchange_strong(expected, true)) { - script::utils::Message s( - [](auto& msg) { - static_cast(msg.ptr0)->isPumpScheduled_ = false; - auto platform = static_cast(msg.ptr1); - auto isolate = static_cast(msg.ptr2); - - while (platform->pumpMessageQueue(isolate)) { - // loop until no more message to pump - } - }, - nullptr); - - s.name = "SchedulePump"; - s.ptr0 = this; - s.ptr1 = platform_; - s.ptr2 = isolate_; - s.tag = engine_; - - engine_->messageQueue()->postMessage(s); - } + void scheduleTask(std::unique_ptr task, double delay_in_seconds = 0) { + script::utils::Message s([](auto& msg) { static_cast(msg.ptr0)->Run(); }, + [](auto& msg) { + using deleter = std::unique_ptr::deleter_type; + deleter{}(static_cast(msg.ptr0)); + }); + s.name = "SchedulePump"; + s.ptr0 = task.release(); + s.tag = engine_; + + engine_->messageQueue()->postMessage(s, std::chrono::duration(delay_in_seconds)); } }; @@ -162,7 +170,7 @@ V8Platform::~V8Platform() { std::lock_guard lock(lock_); v8::V8::Dispose(); -#if SCRIPTX_V8_VERSION_AT_LEAST(10, 0) +#if SCRIPTX_V8_VERSION_GE(10, 0) v8::V8::DisposePlatform(); #else // DEPRECATED in 10.0 36707481ffa @@ -170,29 +178,29 @@ V8Platform::~V8Platform() { #endif } +#if SCRIPTX_V8_VERSION_GE(11, 7) +std::shared_ptr V8Platform::GetForegroundTaskRunner(v8::Isolate* isolate, + v8::TaskPriority priority) { +#else std::shared_ptr V8Platform::GetForegroundTaskRunner(v8::Isolate* isolate) { +#endif std::lock_guard lock(lock_); auto queueRunner = engineMap_[isolate].messageQueueRunner; - if (!queueRunner->hasRunner()) { + if (!queueRunner->inited()) { // this method may be called during creating Isolate... // set anything we now ASAP - queueRunner->setQueue(this, isolate, defaultPlatform_->GetForegroundTaskRunner(isolate)); + queueRunner->setQueue(isolate); } return queueRunner; } -bool V8Platform::pumpMessageQueue(v8::Isolate* isolate) { - v8::Locker locker(isolate); - return v8::platform::PumpMessageLoop(defaultPlatform_.get(), isolate); -} - void V8Platform::OnCriticalMemoryPressure() { Logger() << "V8Platform::OnCriticalMemoryPressure()"; return defaultPlatform_->OnCriticalMemoryPressure(); } -#if SCRIPTX_V8_VERSION_AT_MOST(10, 6) +#if SCRIPTX_V8_VERSION_LE(10, 6) bool V8Platform::OnCriticalMemoryPressure(size_t length) { Logger() << "V8Platform::OnCriticalMemoryPressure(" << length << ")"; return defaultPlatform_->OnCriticalMemoryPressure(length); diff --git a/backend/V8/V8Platform.h b/backend/V8/V8Platform.h index 8db71957..cada9d89 100644 --- a/backend/V8/V8Platform.h +++ b/backend/V8/V8Platform.h @@ -15,6 +15,8 @@ * limitations under the License. */ +// for all v8 api changes, refer to https://github.com/LanderlYoung/ScriptXTestLibs/blob/main/v8/ + #pragma once #include @@ -23,6 +25,7 @@ #include "../../src/foundation.h" SCRIPTX_BEGIN_INCLUDE_LIBRARY +#include #include SCRIPTX_END_INCLUDE_LIBRARY @@ -43,24 +46,28 @@ class V8Platform : public v8::Platform { SCRIPTX_DISALLOW_COPY_AND_MOVE(V8Platform); public: - // this method is used in v8 internally, we should handle it properly, since V8 7.1.1 +#if SCRIPTX_V8_VERSION_GE(11, 7) + // V7.1: added 1-param one + // V11.7: added 2-param overload one, 1-param one delegate to 2-param one + // V13.0: made 1-param overload one non-virtual + std::shared_ptr GetForegroundTaskRunner(v8::Isolate* isolate, + v8::TaskPriority priority) override; +#else std::shared_ptr GetForegroundTaskRunner(v8::Isolate* isolate) override; - - // call in V8Engine - bool pumpMessageQueue(v8::Isolate* isolate); +#endif void OnCriticalMemoryPressure() override; -#if SCRIPTX_V8_VERSION_AT_MOST(10, 6) +#if SCRIPTX_V8_VERSION_LE(10, 6) // DEPRECATED in 10.7 - 24cf9b // REMOVED in 10.8 - 8b8703 bool OnCriticalMemoryPressure(size_t length) override; #endif - public: // directly delegate to default platform int NumberOfWorkerThreads() override { return defaultPlatform_->NumberOfWorkerThreads(); } +#if SCRIPTX_V8_VERSION_LE(11, 3) // added default impl to call PostTaskOnWorkerThreadImpl in 11.4 void CallOnWorkerThread(std::unique_ptr task) override { return defaultPlatform_->CallOnWorkerThread(std::move(task)); } @@ -68,6 +75,7 @@ class V8Platform : public v8::Platform { void CallDelayedOnWorkerThread(std::unique_ptr task, double delay_in_seconds) override { return defaultPlatform_->CallDelayedOnWorkerThread(std::move(task), delay_in_seconds); } +#endif double MonotonicallyIncreasingTime() override { return defaultPlatform_->MonotonicallyIncreasingTime(); @@ -86,29 +94,65 @@ class V8Platform : public v8::Platform { // NOTE: not available in node 14.x (node.js modified v8 code...) // https://nodejs.org/en/download/releases/ // and node 15.x uses v8 8.6+ -#if defined(BUILDING_NODE_EXTENSION) ? SCRIPTX_V8_VERSION_AT_LEAST(8, 6) \ - : SCRIPTX_V8_VERSION_AT_LEAST(8, 4) - + // V8 8.6 made it pure virtual + // V8 10.5 add default impl to CreateJob + // V12.2 make it none-virtual by delegate to CreateJobImpl +#if defined(BUILDING_NODE_EXTENSION) ? SCRIPTX_V8_VERSION_BETWEEN(8, 6, 12, 1) \ + : SCRIPTX_V8_VERSION_BETWEEN(8, 4, 12, 1) virtual std::unique_ptr PostJob(v8::TaskPriority priority, std::unique_ptr job_task) override { return defaultPlatform_->PostJob(priority, std::move(job_task)); } - #endif -#if SCRIPTX_V8_VERSION_AT_LEAST(10, 5) // added in 10.5 1e0d18 +#if SCRIPTX_V8_VERSION_BETWEEN(10, 5, 11, 3) + // V10.5 added pure-virtual + // V11.4 added default impl to CreateJobImpl + // V12.2 make it none-virtual by delegate to CreateJobImpl std::unique_ptr CreateJob(v8::TaskPriority priority, std::unique_ptr job_task) override { return defaultPlatform_->CreateJob(priority, std::move(job_task)); } #endif -#if !SCRIPTX_V8_VERSION_AT_LEAST(8, 0) - // v8 8.0 added default impl - // v8 8.1 removed those function - // so we won't override them since v8 8.0 - // https://github.com/v8/v8/commit/95aba36b52eecdec56752956a7960b916f986a39 +#if SCRIPTX_V8_VERSION_GE(11, 4) + protected: + // V11.4 added + // V12.2 made pure virtual + virtual std::unique_ptr CreateJobImpl( + v8::TaskPriority priority, std::unique_ptr job_task, + const v8::SourceLocation& location) override { + return defaultPlatform_->CreateJob(priority, std::move(job_task)); + } + + // V11.4 added + // V12.2 made pure virtual + virtual void PostTaskOnWorkerThreadImpl(v8::TaskPriority priority, std::unique_ptr task, + const v8::SourceLocation& location) override { +#if SCRIPTX_V8_VERSION_GE(12, 2) + defaultPlatform_->CallOnWorkerThread(std::move(task), location); +#else + defaultPlatform_->CallOnWorkerThread(std::move(task)); +#endif + } + + // V11.4 added + // V12.2 made pure virtual + virtual void PostDelayedTaskOnWorkerThreadImpl(v8::TaskPriority priority, + std::unique_ptr task, + double delay_in_seconds, + const v8::SourceLocation& location) override { +#if SCRIPTX_V8_VERSION_GE(12, 2) + defaultPlatform_->CallDelayedOnWorkerThread(std::move(task), delay_in_seconds, location); +#else + defaultPlatform_->CallDelayedOnWorkerThread(std::move(task), delay_in_seconds); +#endif + } + public: +#endif + +#if SCRIPTX_V8_VERSION_LE(8, 0) // removed in 8.1 void CallOnForegroundThread(v8::Isolate* isolate, v8::Task* task) override { return GetForegroundTaskRunner(isolate)->PostTask(std::unique_ptr(task)); } @@ -120,6 +164,15 @@ class V8Platform : public v8::Platform { } #endif + bool IdleTasksEnabled(v8::Isolate* isolate) override { return false; } + +#if SCRIPTX_V8_VERSION_GE(11, 3) + virtual std::unique_ptr CreateBlockingScope( + v8::BlockingType blocking_type) override { + return defaultPlatform_->CreateBlockingScope(blocking_type); + } +#endif + public: ~V8Platform() override; diff --git a/backend/V8/V8Reference.hpp b/backend/V8/V8Reference.hpp index 2ffc5106..7d78d827 100644 --- a/backend/V8/V8Reference.hpp +++ b/backend/V8/V8Reference.hpp @@ -32,8 +32,11 @@ namespace script { namespace v8_backend { template + GlobalRefState::GlobalRefState(V8Engine* scriptEngine, const GlobalRefState::V8Global& v8Global) - : engine_(scriptEngine), ref_(v8Global) {} + : engine_(scriptEngine), + // v8::Global don't support copy + ref_{engine_->isolate_, v8Global} {} template GlobalRefState::GlobalRefState(V8Engine* scriptEngine, const Local& localReference) diff --git a/backend/V8/V8Value.cc b/backend/V8/V8Value.cc index 3d738a1b..05013f81 100644 --- a/backend/V8/V8Value.cc +++ b/backend/V8/V8Value.cc @@ -176,9 +176,9 @@ Local ByteBuffer::newByteBuffer(void* nativeBuffer, si return ret; } -#if V8_MAJOR_VERSION >= 8 +#if SCRIPTX_V8_VERSION_GE(8, 1) -// v8 8.0 introduced new api for this +// v8 8.1 introduced new api for this // https://docs.google.com/document/d/1sTc_jRL87Fu175Holm5SV0kajkseGl2r8ifGY76G35k/edit Local ByteBuffer::newByteBuffer(std::shared_ptr buffer, size_t size) { diff --git a/backend/V8/trait/TraitReference.h b/backend/V8/trait/TraitReference.h index 1389dc40..cdd1f00d 100644 --- a/backend/V8/trait/TraitReference.h +++ b/backend/V8/trait/TraitReference.h @@ -56,8 +56,9 @@ TypeMap(::script::Unsupported, v8::Value); template class GlobalRefState { private: - using V8Global = - typename ::v8::CopyablePersistentTraits>::CopyablePersistent; + // v8::CopyablePersistentTraits deprecated in 10.5, removed in 12.5 + // always use v8::Global + using V8Global = v8::Global>; public: V8Engine* engine_ = nullptr; @@ -70,7 +71,17 @@ class GlobalRefState { GlobalRefState(V8Engine* scriptEngine, const V8Global& v8Global); - GlobalRefState(const GlobalRefState& copy) : engine_(copy.engine_), ref_(copy.ref_) {} + // v8::Global don't support copy + GlobalRefState(const GlobalRefState& copy) + : engine_(copy.engine_), ref_{currentEngineIsolateChecked(), copy.ref_} {} + + GlobalRefState& operator=(const GlobalRefState& assign) { + if (this != &assign) { + engine_ = assign.engine_; + ref_ = V8Global(currentEngineIsolateChecked(), assign.ref_); + } + return *this; + } GlobalRefState(GlobalRefState&& move) noexcept : engine_(move.engine_), ref_(std::move(move.ref_)) { @@ -80,14 +91,6 @@ class GlobalRefState { move.engine_ = nullptr; } - GlobalRefState& operator=(const GlobalRefState& assign) { - if (this != &assign) { - engine_ = assign.engine_; - ref_ = assign.ref_; - } - return *this; - } - GlobalRefState& operator=(GlobalRefState&& assign) noexcept { if (this != &assign) { engine_ = assign.engine_; diff --git a/src/version.h b/src/version.h index 6797668c..b1109c5e 100644 --- a/src/version.h +++ b/src/version.h @@ -19,9 +19,9 @@ // ScriptX version config files // auto generated from the file VERSION -#define SCRIPTX_VERSION_STRING "3.5.0" +#define SCRIPTX_VERSION_STRING "3.6.0" #define SCRIPTX_VERSION_MAJOR 3 -#define SCRIPTX_VERSION_MINOR 5 +#define SCRIPTX_VERSION_MINOR 6 #define SCRIPTX_VERSION_PATCH 0 namespace script { diff --git a/test/cmake/TestEnv.cmake b/test/cmake/TestEnv.cmake index 1d582f2a..badcec24 100644 --- a/test/cmake/TestEnv.cmake +++ b/test/cmake/TestEnv.cmake @@ -52,9 +52,15 @@ include(${CMAKE_CURRENT_LIST_DIR}/test_libs/CMakeLists.txt) if (${SCRIPTX_BACKEND} STREQUAL V8) if (SCRIPTX_TEST_BUILD_ONLY) + if ("${SCRIPTX_V8_INCLUDES}" STREQUAL "") set(DEVOPS_LIBS_INCLUDE - "${SCRIPTX_TEST_LIBS}/v8/mac/include" - CACHE STRING "" FORCE) + "${SCRIPTX_TEST_LIBS}/v8/mac/include" + CACHE STRING "" FORCE) + else() + set(DEVOPS_LIBS_INCLUDE + "${SCRIPTX_V8_INCLUDES}" + CACHE STRING "" FORCE) + endif() elseif (APPLE) if (CMAKE_SYSTEM_PROCESSOR STREQUAL arm64) set(DEVOPS_LIBS_INCLUDE diff --git a/test/cmake/test_v8_compiles.sh b/test/cmake/test_v8_compiles.sh new file mode 100755 index 00000000..829ab2d0 --- /dev/null +++ b/test/cmake/test_v8_compiles.sh @@ -0,0 +1,92 @@ +#! /bin/bash + +# USAGE: +#