From 775049db6f6f3f96e9e9250d8c95761ffb339824 Mon Sep 17 00:00:00 2001 From: Sam Cao Date: Mon, 14 Oct 2024 11:24:22 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=91=20Javet=20v4.0.0=20(#406)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Upgraded Node.js to `v22.9.0` ([2024-09-17](https://github.com/nodejs/node/blob/main/doc/changelogs/CHANGELOG_V22.md#22.9.0)) * Upgraded V8 to `v13.0.245.16` (2024-10-08) * Added `NodeI18n`, `V8I18n` to `JSRuntimeType` * Added `getNodeI18nInstance()`, `getV8I18nInstance()` to `V8Host` * Renamed `V8Runtime.hasPendingException()` to `V8Runtime.hasException()` * Removed `V8Runtime.hasScheduledException()` and `V8Runtime.promoteScheduledException()` * Moved `JavetReflectionObjectFactory` to `JavetBuddy` * Added `NodeFlags` * Added `NODE_FLAGS` to `NodeRuntimeOptions` * Supported `node:sqlite` --- .github/workflows/android_node_build.yml | 109 ++++- .github/workflows/android_v8_build.yml | 130 +++++- .github/workflows/linux_build_artifact.yml | 6 +- .../workflows/linux_build_node_v8_image.yml | 6 +- .github/workflows/linux_x86_64_build.yml | 144 ++++++- .github/workflows/macos_arm64_build.yml | 144 ++++++- .github/workflows/macos_x86_64_build.yml | 144 ++++++- .github/workflows/windows_x86_64_build.yml | 157 +++++-- README.rst | 28 +- android/javet-android/build.gradle.kts | 2 +- .../src/main/AndroidManifest.xml | 2 +- android/pom.xml | 4 +- build.gradle.kts | 9 +- cpp/CMakeLists.txt | 108 ++--- cpp/build-android.sh | 2 +- cpp/build-linux-arm64.sh | 2 +- cpp/build-linux-x86_64.sh | 2 +- cpp/build-macos.sh | 2 +- cpp/build-windows.cmd | 2 +- cpp/jni/com_caoccao_javet_interop_V8Native.h | 40 +- cpp/jni/javet_converter.cpp | 18 +- cpp/jni/javet_converter.h | 18 +- cpp/jni/javet_exceptions.cpp | 14 +- cpp/jni/javet_jni_context.cpp | 8 +- cpp/jni/javet_jni_core_v8.cpp | 9 + cpp/jni/javet_jni_error.cpp | 28 +- cpp/jni/javet_jni_function.cpp | 181 ++------ cpp/jni/javet_jni_module.cpp | 10 +- cpp/jni/javet_jni_object.cpp | 4 +- cpp/jni/javet_native.cpp | 42 +- cpp/jni/javet_resource_node.rc | 12 +- cpp/jni/javet_resource_v8.rc | 12 +- cpp/jni/javet_v8_internal.h | 16 +- cpp/jni/javet_v8_runtime.cpp | 29 +- cpp/jni/javet_v8_runtime.h | 4 - docker/android/base.Dockerfile | 4 +- docker/android/build.Dockerfile | 2 +- docker/linux-arm64/base_all_in_one.Dockerfile | 4 +- docker/linux-arm64/base_gradle.Dockerfile | 2 +- docker/linux-arm64/base_v8.Dockerfile | 6 +- docker/linux-arm64/build_artifact.Dockerfile | 4 +- .../linux-x86_64/base_all_in_one.Dockerfile | 6 +- docker/linux-x86_64/base_gradle.Dockerfile | 2 +- docker/linux-x86_64/base_node.Dockerfile | 6 +- docker/linux-x86_64/base_v8.Dockerfile | 6 +- docker/linux-x86_64/build.env | 6 +- .../linux-x86_64/build_all_in_one.Dockerfile | 2 +- docker/linux-x86_64/build_artifact.Dockerfile | 4 +- docker/windows-x86_64/base.Dockerfile | 6 +- docker/windows-x86_64/build.Dockerfile | 2 +- docs/conf.py | 2 +- docs/development/build_javet_from_scratch.rst | 13 +- .../troubleshooting/can_i18n_be_supported.rst | 8 +- docs/release_notes/index.rst | 6 +- docs/release_notes/release_notes_4_0.rst | 17 + .../advanced/cli_options_in_node_js.rst | 92 ++++ docs/tutorial/advanced/index.rst | 2 + .../advanced/internationalization_i18n.rst | 73 ++++ docs/tutorial/basic/installation.rst | 39 +- scripts/node/javet-rebuild/rebuild.cmd | 2 +- scripts/node/javet-rebuild/rebuild.sh | 2 +- ...ync.js => test-node-module-sqlite-sync.js} | 29 +- .../patches/android/node/trap-handler.h.patch | 23 +- scripts/python/change_javet_version.py | 2 +- scripts/python/change_node_v8_version.py | 4 +- .../caoccao/javet/enums/JSRuntimeType.java | 45 +- .../com/caoccao/javet/interop/IV8Native.java | 10 +- .../caoccao/javet/interop/NodeRuntime.java | 16 +- .../com/caoccao/javet/interop/V8Host.java | 68 ++- .../com/caoccao/javet/interop/V8Native.java | 13 +- .../com/caoccao/javet/interop/V8Runtime.java | 66 ++- .../javet/interop/executors/IV8Executor.java | 1 + .../javet/interop/loader/JavetLibLoader.java | 9 +- .../javet/interop/options/NodeFlags.java | 402 ++++++++++++++++++ .../interop/options/NodeRuntimeOptions.java | 19 +- .../javet/interop/options/V8Flags.java | 29 +- .../com/caoccao/javet/utils/StringUtils.java | 11 + .../java/com/caoccao/javet/BaseTestJavet.java | 85 +++- .../caoccao/javet/BaseTestJavetRuntime.java | 13 + .../jvm/TestJavetJVMInterceptor.java | 5 +- .../javet/interop/TestJavetLibLoader.java | 65 ++- .../javet/interop/TestNodeRuntime.java | 95 +---- .../com/caoccao/javet/interop/TestV8Host.java | 29 +- .../caoccao/javet/interop/TestV8Native.java | 20 +- .../caoccao/javet/interop/TestV8Runtime.java | 4 +- .../converters/TestJavetBridgeConverter.java | 28 +- .../converters/TestJavetProxyConverter.java | 7 +- .../javet/interop/options/TestI18n.java | 41 ++ .../javet/interop/options/TestNodeFlags.java | 99 +++++ .../options/TestNodeRuntimeOptions.java | 74 ++++ .../javet/tutorial/TestI18nInNode.java | 44 ++ .../caoccao/javet/tutorial/TestI18nInV8.java | 44 ++ .../values/reference/TestV8ValueFunction.java | 14 +- 93 files changed, 2322 insertions(+), 858 deletions(-) create mode 100644 docs/release_notes/release_notes_4_0.rst create mode 100644 docs/tutorial/advanced/cli_options_in_node_js.rst create mode 100644 docs/tutorial/advanced/internationalization_i18n.rst rename scripts/node/test-node/{test-node-module-sqlite3-sync.js => test-node-module-sqlite-sync.js} (62%) create mode 100644 src/main/java/com/caoccao/javet/interop/options/NodeFlags.java create mode 100644 src/test/java/com/caoccao/javet/interop/options/TestI18n.java create mode 100644 src/test/java/com/caoccao/javet/interop/options/TestNodeFlags.java create mode 100644 src/test/java/com/caoccao/javet/interop/options/TestNodeRuntimeOptions.java create mode 100644 src/test/java/com/caoccao/javet/tutorial/TestI18nInNode.java create mode 100644 src/test/java/com/caoccao/javet/tutorial/TestI18nInV8.java diff --git a/.github/workflows/android_node_build.yml b/.github/workflows/android_node_build.yml index 9fe32ebb1..b07ffb9b0 100644 --- a/.github/workflows/android_node_build.yml +++ b/.github/workflows/android_node_build.yml @@ -8,8 +8,8 @@ on: workflow_dispatch: env: - JAVET_NODE_VERSION: 20.17.0 - JAVET_VERSION: 3.1.8 + JAVET_NODE_VERSION: 22.9.0 + JAVET_VERSION: 4.0.0 ROOT: /home/runner/work/Javet jobs: @@ -19,14 +19,36 @@ jobs: include: - android_arch: arm android_abi: armeabi-v7a + i18n_name: non-i18n + cmake_flag: + config_patch: - android_arch: arm64 android_abi: arm64-v8a + i18n_name: non-i18n + cmake_flag: + config_patch: - android_arch: x86 android_abi: x86 + i18n_name: non-i18n + cmake_flag: + config_patch: - android_arch: x86_64 android_abi: x86_64 + i18n_name: non-i18n + cmake_flag: + config_patch: + - android_arch: arm64 + android_abi: arm64-v8a + i18n_name: i18n + cmake_flag: -DENABLE_I18N=1 + config_patch: sed -i 's/--with-intl=none/--with-intl=full-icu/g' android_configure.py + - android_arch: x86_64 + android_abi: x86_64 + i18n_name: i18n + cmake_flag: -DENABLE_I18N=1 + config_patch: sed -i 's/--with-intl=none/--with-intl=full-icu/g' android_configure.py - name: Build Javet ${{ matrix.android_arch }} + name: Build Javet ${{ matrix.android_arch }} ${{ matrix.i18n_name }} runs-on: ubuntu-latest steps: @@ -67,9 +89,16 @@ jobs: git apply < ../Javet/scripts/patches/android/node/push_registers_asm.cc.patch git apply < ../Javet/scripts/patches/android/node/trap-handler.h.patch git apply < ../Javet/scripts/patches/android/node/test_crypto_clienthello.cc.patch + ${{ matrix.config_patch }} ./android-configure ${{ steps.setup-ndk.outputs.ndk-path }} 24 ${{ matrix.android_arch }} make -j4 - mv out out.${{ matrix.android_arch }} + mv out out.${{ matrix.android_arch }}.${{ matrix.i18n_name }} + + - name: Copy the i18n + if: matrix.i18n_name == 'i18n' && matrix.android_arch == 'arm64' + run: | + mkdir icu-node + cp ../node/deps/icu-tmp/*.dat icu-node - name: Setup JDK 11 uses: actions/setup-java@v4 @@ -85,14 +114,21 @@ jobs: - name: Build Javet JNI run: | cd ${{ env.ROOT }}/Javet/cpp - sh ./build-android.sh -DNODE_DIR=${{ env.ROOT }}/node -DCMAKE_ANDROID_NDK=${{ steps.setup-ndk.outputs.ndk-path }} -DCMAKE_ANDROID_ARCH=${{ matrix.android_arch }} + sh ./build-android.sh -DNODE_DIR=${{ env.ROOT }}/node -DCMAKE_ANDROID_NDK=${{ steps.setup-ndk.outputs.ndk-path }} -DCMAKE_ANDROID_ARCH=${{ matrix.android_arch }} ${{ matrix.cmake_flag }} - name: Upload the Artifact uses: actions/upload-artifact@v4 with: - name: javet-android-node-${{ matrix.android_arch }}-${{ env.JAVET_VERSION }} + name: javet-android-node-${{ matrix.android_arch }}-${{ env.JAVET_VERSION }}-${{ matrix.i18n_name }} path: android/javet-android/src/main/jniLibs/${{ matrix.android_abi }}/*.so + - name: Upload the i18n + uses: actions/upload-artifact@v4 + if: matrix.i18n_name == 'i18n' && matrix.android_arch == 'arm64' + with: + name: icu-node + path: icu-node/*.dat + build_javet_aar: needs: [build_javet_lib] name: Build Javet AAR @@ -119,35 +155,52 @@ jobs: with: gradle-version: 8.5 - - name: Prepare JNI Libs + - name: Prepare JNI Libs i18n + run: | + mkdir -p android/javet-android/src/main/jniLibs/arm64-v8a + mkdir -p android/javet-android/src/main/jniLibs/x86_64 + + - name: Prepare JNI Libs non-i18n run: | mkdir -p android/javet-android/src/main/jniLibs/armeabi-v7a mkdir -p android/javet-android/src/main/jniLibs/arm64-v8a mkdir -p android/javet-android/src/main/jniLibs/x86 mkdir -p android/javet-android/src/main/jniLibs/x86_64 - - name: Download Javet arm + - name: Download Javet arm64 i18n uses: actions/download-artifact@v4 with: - name: javet-android-node-arm-${{ env.JAVET_VERSION }} + name: javet-android-node-arm64-${{ env.JAVET_VERSION }}-i18n + path: android/javet-android/src/main/jniLibs/arm64-v8a + + - name: Download Javet x86_64 i18n + uses: actions/download-artifact@v4 + with: + name: javet-android-node-x86_64-${{ env.JAVET_VERSION }}-i18n + path: android/javet-android/src/main/jniLibs/x86_64 + + - name: Download Javet arm non-i18n + uses: actions/download-artifact@v4 + with: + name: javet-android-node-arm-${{ env.JAVET_VERSION }}-non-i18n path: android/javet-android/src/main/jniLibs/armeabi-v7a - - name: Download Javet arm64 + - name: Download Javet arm64 non-i18n uses: actions/download-artifact@v4 with: - name: javet-android-node-arm64-${{ env.JAVET_VERSION }} + name: javet-android-node-arm64-${{ env.JAVET_VERSION }}-non-i18n path: android/javet-android/src/main/jniLibs/arm64-v8a - - name: Download Javet x86 + - name: Download Javet x86 non-i18n uses: actions/download-artifact@v4 with: - name: javet-android-node-x86-${{ env.JAVET_VERSION }} + name: javet-android-node-x86-${{ env.JAVET_VERSION }}-non-i18n path: android/javet-android/src/main/jniLibs/x86 - - name: Download Javet x86_64 + - name: Download Javet x86_64 non-i18n uses: actions/download-artifact@v4 with: - name: javet-android-node-x86_64-${{ env.JAVET_VERSION }} + name: javet-android-node-x86_64-${{ env.JAVET_VERSION }}-non-i18n path: android/javet-android/src/main/jniLibs/x86_64 - name: Build the Artifact @@ -163,22 +216,32 @@ jobs: name: javet-android-node-${{ env.JAVET_VERSION }} path: android/javet-android/build/outputs/aar/javet*release.aar - - name: Delete Javet arm + - name: Delete Javet arm64 i18n + uses: geekyeggo/delete-artifact@v4 + with: + name: javet-android-node-arm64-${{ env.JAVET_VERSION }}-i18n + + - name: Delete Javet x86_64 i18n + uses: geekyeggo/delete-artifact@v4 + with: + name: javet-android-node-x86_64-${{ env.JAVET_VERSION }}-i18n + + - name: Delete Javet arm non-i18n uses: geekyeggo/delete-artifact@v4 with: - name: javet-android-node-arm-${{ env.JAVET_VERSION }} + name: javet-android-node-arm-${{ env.JAVET_VERSION }}-non-i18n - - name: Delete Javet arm64 + - name: Delete Javet arm64 non-i18n uses: geekyeggo/delete-artifact@v4 with: - name: javet-android-node-arm64-${{ env.JAVET_VERSION }} + name: javet-android-node-arm64-${{ env.JAVET_VERSION }}-non-i18n - - name: Delete Javet x86 + - name: Delete Javet x86 non-i18n uses: geekyeggo/delete-artifact@v4 with: - name: javet-android-node-x86-${{ env.JAVET_VERSION }} + name: javet-android-node-x86-${{ env.JAVET_VERSION }}-non-i18n - - name: Delete Javet x86_64 + - name: Delete Javet x86_64 non-i18n uses: geekyeggo/delete-artifact@v4 with: - name: javet-android-node-x86_64-${{ env.JAVET_VERSION }} + name: javet-android-node-x86_64-${{ env.JAVET_VERSION }}-non-i18n diff --git a/.github/workflows/android_v8_build.yml b/.github/workflows/android_v8_build.yml index 26ba1c96a..6bea7b8f7 100644 --- a/.github/workflows/android_v8_build.yml +++ b/.github/workflows/android_v8_build.yml @@ -8,8 +8,8 @@ on: workflow_dispatch: env: - JAVET_V8_VERSION: 12.9.202.18 - JAVET_VERSION: 3.1.8 + JAVET_V8_VERSION: 13.0.245.16 + JAVET_VERSION: 4.0.0 ROOT: /home/runner/work/Javet jobs: @@ -21,20 +21,60 @@ jobs: v8_arch: arm android_arch: arm android_abi: armeabi-v7a + i18n_name: i18n + cmake_flag: -DENABLE_I18N=1 + v8_flag: v8_enable_i18n_support=true - v8_release: arm64 v8_arch: arm64 android_arch: arm64 android_abi: arm64-v8a + i18n_name: i18n + cmake_flag: -DENABLE_I18N=1 + v8_flag: v8_enable_i18n_support=true - v8_release: ia32 v8_arch: x86 android_arch: x86 android_abi: x86 + i18n_name: i18n + cmake_flag: -DENABLE_I18N=1 + v8_flag: v8_enable_i18n_support=true - v8_release: x64 v8_arch: x64 android_arch: x86_64 android_abi: x86_64 + i18n_name: i18n + cmake_flag: -DENABLE_I18N=1 + v8_flag: v8_enable_i18n_support=true + - v8_release: arm + v8_arch: arm + android_arch: arm + android_abi: armeabi-v7a + i18n_name: non-i18n + cmake_flag: + v8_flag: v8_enable_i18n_support=false + - v8_release: arm64 + v8_arch: arm64 + android_arch: arm64 + android_abi: arm64-v8a + i18n_name: non-i18n + cmake_flag: + v8_flag: v8_enable_i18n_support=false + - v8_release: ia32 + v8_arch: x86 + android_arch: x86 + android_abi: x86 + i18n_name: non-i18n + cmake_flag: + v8_flag: v8_enable_i18n_support=false + - v8_release: x64 + v8_arch: x64 + android_arch: x86_64 + android_abi: x86_64 + i18n_name: non-i18n + cmake_flag: + v8_flag: v8_enable_i18n_support=false - name: Build Javet ${{ matrix.android_arch }} + name: Build Javet ${{ matrix.android_arch }} ${{ matrix.i18n_name }} runs-on: ubuntu-latest steps: @@ -79,9 +119,16 @@ jobs: echo 'target_os = ["android"]' >> .gclient gclient sync -D cd v8 - python3 tools/dev/v8gen.py ${{ matrix.v8_release }}.release -- 'target_os="android"' 'target_cpu="${{ matrix.v8_arch }}"' 'v8_target_cpu="${{ matrix.v8_arch }}"' v8_monolithic=true v8_use_external_startup_data=false is_component_build=false v8_enable_i18n_support=false v8_enable_pointer_compression=false v8_static_library=true symbol_level=0 use_custom_libcxx=false v8_enable_sandbox=false + python3 tools/dev/v8gen.py ${{ matrix.v8_release }}.release -- 'target_os="android"' 'target_cpu="${{ matrix.v8_arch }}"' 'v8_target_cpu="${{ matrix.v8_arch }}"' v8_monolithic=true v8_use_external_startup_data=false is_component_build=false ${{ matrix.v8_flag }} v8_enable_pointer_compression=false v8_static_library=true symbol_level=0 use_custom_libcxx=false v8_enable_sandbox=false ninja -C out.gn/${{ matrix.v8_release }}.release v8_monolith || python3 ${{ env.ROOT }}/Javet/scripts/python/patch_v8_build.py -p ./ ninja -C out.gn/${{ matrix.v8_release }}.release v8_monolith + mv out.gn out.gn.${{ matrix.i18n_name }} + + - name: Copy the i18n + if: matrix.i18n_name == 'i18n' && matrix.android_arch == 'arm64' + run: | + mkdir icu-v8 + cp ../google/v8/third_party/icu/android/*.dat icu-v8 - name: Setup JDK 11 uses: actions/setup-java@v4 @@ -97,14 +144,21 @@ jobs: - name: Build Javet JNI run: | cd ${{ env.ROOT }}/Javet/cpp - sh ./build-android.sh -DV8_DIR=${{ env.ROOT }}/google/v8 -DCMAKE_ANDROID_NDK=${{ steps.setup-ndk.outputs.ndk-path }} -DCMAKE_ANDROID_ARCH=${{ matrix.android_arch }} + sh ./build-android.sh -DV8_DIR=${{ env.ROOT }}/google/v8 -DCMAKE_ANDROID_NDK=${{ steps.setup-ndk.outputs.ndk-path }} -DCMAKE_ANDROID_ARCH=${{ matrix.android_arch }} ${{ matrix.cmake_flag }} - name: Upload the Artifact uses: actions/upload-artifact@v4 with: - name: javet-android-v8-${{ matrix.android_arch }}-${{ env.JAVET_VERSION }} + name: javet-android-v8-${{ matrix.android_arch }}-${{ env.JAVET_VERSION }}-${{ matrix.i18n_name }} path: android/javet-android/src/main/jniLibs/${{ matrix.android_abi }}/*.so + - name: Upload the i18n + uses: actions/upload-artifact@v4 + if: matrix.i18n_name == 'i18n' && matrix.android_arch == 'arm64' + with: + name: icu-v8 + path: icu-v8/*.dat + build_javet_aar: needs: [build_javet_lib] name: Build Javet AAR @@ -138,28 +192,40 @@ jobs: mkdir -p android/javet-android/src/main/jniLibs/x86 mkdir -p android/javet-android/src/main/jniLibs/x86_64 - - name: Download Javet arm + - name: Download Javet arm64 i18n uses: actions/download-artifact@v4 with: - name: javet-android-v8-arm-${{ env.JAVET_VERSION }} + name: javet-android-v8-arm64-${{ env.JAVET_VERSION }}-i18n + path: android/javet-android/src/main/jniLibs/arm64-v8a + + - name: Download Javet x86_64 i18n + uses: actions/download-artifact@v4 + with: + name: javet-android-v8-x86_64-${{ env.JAVET_VERSION }}-i18n + path: android/javet-android/src/main/jniLibs/x86_64 + + - name: Download Javet arm non-i18n + uses: actions/download-artifact@v4 + with: + name: javet-android-v8-arm-${{ env.JAVET_VERSION }}-non-i18n path: android/javet-android/src/main/jniLibs/armeabi-v7a - - name: Download Javet arm64 + - name: Download Javet arm64 non-i18n uses: actions/download-artifact@v4 with: - name: javet-android-v8-arm64-${{ env.JAVET_VERSION }} + name: javet-android-v8-arm64-${{ env.JAVET_VERSION }}-non-i18n path: android/javet-android/src/main/jniLibs/arm64-v8a - - name: Download Javet x86 + - name: Download Javet x86 non-i18n uses: actions/download-artifact@v4 with: - name: javet-android-v8-x86-${{ env.JAVET_VERSION }} + name: javet-android-v8-x86-${{ env.JAVET_VERSION }}-non-i18n path: android/javet-android/src/main/jniLibs/x86 - - name: Download Javet x86_64 + - name: Download Javet x86_64 non-i18n uses: actions/download-artifact@v4 with: - name: javet-android-v8-x86_64-${{ env.JAVET_VERSION }} + name: javet-android-v8-x86_64-${{ env.JAVET_VERSION }}-non-i18n path: android/javet-android/src/main/jniLibs/x86_64 - name: Build the Artifact @@ -175,22 +241,42 @@ jobs: name: javet-android-v8-${{ env.JAVET_VERSION }} path: android/javet-android/build/outputs/aar/javet*release.aar - - name: Delete Javet arm + - name: Delete Javet arm i18n + uses: geekyeggo/delete-artifact@v4 + with: + name: javet-android-v8-arm-${{ env.JAVET_VERSION }}-i18n + + - name: Delete Javet arm64 i18n + uses: geekyeggo/delete-artifact@v4 + with: + name: javet-android-v8-arm64-${{ env.JAVET_VERSION }}-i18n + + - name: Delete Javet x86 i18n + uses: geekyeggo/delete-artifact@v4 + with: + name: javet-android-v8-x86-${{ env.JAVET_VERSION }}-i18n + + - name: Delete Javet x86_64 i18n + uses: geekyeggo/delete-artifact@v4 + with: + name: javet-android-v8-x86_64-${{ env.JAVET_VERSION }}-i18n + + - name: Delete Javet arm non-i18n uses: geekyeggo/delete-artifact@v4 with: - name: javet-android-v8-arm-${{ env.JAVET_VERSION }} + name: javet-android-v8-arm-${{ env.JAVET_VERSION }}-non-i18n - - name: Delete Javet arm64 + - name: Delete Javet arm64 non-i18n uses: geekyeggo/delete-artifact@v4 with: - name: javet-android-v8-arm64-${{ env.JAVET_VERSION }} + name: javet-android-v8-arm64-${{ env.JAVET_VERSION }}-non-i18n - - name: Delete Javet x86 + - name: Delete Javet x86 non-i18n uses: geekyeggo/delete-artifact@v4 with: - name: javet-android-v8-x86-${{ env.JAVET_VERSION }} + name: javet-android-v8-x86-${{ env.JAVET_VERSION }}-non-i18n - - name: Delete Javet x86_64 + - name: Delete Javet x86_64 non-i18n uses: geekyeggo/delete-artifact@v4 with: - name: javet-android-v8-x86_64-${{ env.JAVET_VERSION }} + name: javet-android-v8-x86_64-${{ env.JAVET_VERSION }}-non-i18n diff --git a/.github/workflows/linux_build_artifact.yml b/.github/workflows/linux_build_artifact.yml index 8c1a4a657..bb143fb16 100644 --- a/.github/workflows/linux_build_artifact.yml +++ b/.github/workflows/linux_build_artifact.yml @@ -17,9 +17,9 @@ on: env: DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_REPO_JAVET: ${{ secrets.DOCKERHUB_REPO_JAVET }} - JAVET_NODE_VERSION: 20.17.0 - JAVET_V8_VERSION: 12.9.202.18 - JAVET_VERSION: 3.1.8 + JAVET_NODE_VERSION: 22.9.0 + JAVET_V8_VERSION: 13.0.245.16 + JAVET_VERSION: 4.0.0 jobs: javet_linux_x86_64: diff --git a/.github/workflows/linux_build_node_v8_image.yml b/.github/workflows/linux_build_node_v8_image.yml index 66a32b236..c4eda1b14 100644 --- a/.github/workflows/linux_build_node_v8_image.yml +++ b/.github/workflows/linux_build_node_v8_image.yml @@ -21,9 +21,9 @@ on: env: DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_REPO_JAVET: ${{ secrets.DOCKERHUB_REPO_JAVET }} - JAVET_NODE_VERSION: 20.17.0 - JAVET_V8_VERSION: 12.9.202.18 - JAVET_VERSION: 3.1.8 + JAVET_NODE_VERSION: 22.9.0 + JAVET_V8_VERSION: 13.0.245.16 + JAVET_VERSION: 4.0.0 # if we skip a job using a job level `if` condition, then any dependent jobs also don't run. # we can skip a step of the job, using a step level `if` condition. diff --git a/.github/workflows/linux_x86_64_build.yml b/.github/workflows/linux_x86_64_build.yml index 751cc5467..e2e00a809 100644 --- a/.github/workflows/linux_x86_64_build.yml +++ b/.github/workflows/linux_x86_64_build.yml @@ -7,14 +7,24 @@ on: workflow_dispatch: env: - JAVET_NODE_VERSION: 20.17.0 - JAVET_V8_VERSION: 12.9.202.18 - JAVET_VERSION: 3.1.8 + JAVET_NODE_VERSION: 22.9.0 + JAVET_V8_VERSION: 13.0.245.16 + JAVET_VERSION: 4.0.0 ROOT: /home/runner/work/Javet jobs: build_javet_v8: - name: Build Javet V8 + strategy: + matrix: + include: + - name: i18n + cmake_flag: -DENABLE_I18N=1 + v8_flag: v8_enable_i18n_support=true + - name: non-i18n + cmake_flag: + v8_flag: v8_enable_i18n_support=false + + name: Build Javet V8 ${{ matrix.name }} runs-on: ubuntu-latest steps: @@ -51,11 +61,18 @@ jobs: cd .. gclient sync -D cd v8 - python3 tools/dev/v8gen.py x64.release -- v8_monolithic=true v8_use_external_startup_data=false is_component_build=false v8_enable_i18n_support=false v8_enable_pointer_compression=false v8_static_library=true symbol_level=0 use_custom_libcxx=false v8_enable_sandbox=false + python3 tools/dev/v8gen.py x64.release -- v8_monolithic=true v8_use_external_startup_data=false is_component_build=false ${{ matrix.v8_flag }} v8_enable_pointer_compression=false v8_static_library=true symbol_level=0 use_custom_libcxx=false v8_enable_sandbox=false sed -i '/#include "src\/libplatform\//a #include ' src/libplatform/default-thread-isolated-allocator.cc sed -i '/bool KernelHasPkruFix()/a const char* env = std::getenv("JAVET_DISABLE_PKU"); if (env && std::strlen(env) > 0) { return false; }' src/libplatform/default-thread-isolated-allocator.cc ninja -C out.gn/x64.release v8_monolith || python3 ${{ env.ROOT }}/Javet/scripts/python/patch_v8_build.py -p ./ ninja -C out.gn/x64.release v8_monolith + mv out.gn out.gn.${{ matrix.name }} + + - name: Copy the i18n + if: matrix.name == 'i18n' + run: | + mkdir icu-v8 + cp ../google/v8/third_party/icu/common/*.dat icu-v8 - name: Setup JDK 8 uses: actions/setup-java@v4 @@ -71,16 +88,33 @@ jobs: - name: Build Javet JNI run: | cd ${{ env.ROOT }}/Javet/cpp - sh ./build-linux-x86_64.sh -DV8_DIR=${{ env.ROOT }}/google/v8 + sh ./build-linux-x86_64.sh -DV8_DIR=${{ env.ROOT }}/google/v8 ${{ matrix.cmake_flag }} - name: Upload the Artifact uses: actions/upload-artifact@v4 with: - name: javet-linux-v8-x86_64-${{ env.JAVET_VERSION }} + name: javet-linux-v8-x86_64-${{ env.JAVET_VERSION }}-${{ matrix.name }} path: src/main/resources/*.so + - name: Upload the i18n + uses: actions/upload-artifact@v4 + if: matrix.name == 'i18n' + with: + name: icu-v8 + path: icu-v8/*.dat + build_javet_node: - name: Build Javet Node + strategy: + matrix: + include: + - name: i18n + cmake_flag: -DENABLE_I18N=1 + node_flag: --with-intl=full-icu + - name: non-i18n + cmake_flag: + node_flag: --without-intl + + name: Build Javet Node ${{ matrix.name }} runs-on: ubuntu-latest steps: @@ -104,9 +138,16 @@ jobs: cd node git checkout v${{ env.JAVET_NODE_VERSION }} python3 ${{ env.ROOT }}/Javet/scripts/python/patch_node_build.py -p ./ - ./configure --enable-static --without-intl + ./configure --enable-static ${{ matrix.node_flag }} python3 ${{ env.ROOT }}/Javet/scripts/python/patch_node_build.py -p ./ make -j4 + mv out out.${{ matrix.name }} + + - name: Copy the i18n + if: matrix.name == 'i18n' + run: | + mkdir icu-node + cp ../node/deps/icu-tmp/*.dat icu-node - name: Setup JDK 8 uses: actions/setup-java@v4 @@ -122,14 +163,21 @@ jobs: - name: Build Javet JNI run: | cd ${{ env.ROOT }}/Javet/cpp - sh ./build-linux-x86_64.sh -DNODE_DIR=${{ env.ROOT }}/node + sh ./build-linux-x86_64.sh -DNODE_DIR=${{ env.ROOT }}/node ${{ matrix.cmake_flag }} - name: Upload the Artifact uses: actions/upload-artifact@v4 with: - name: javet-linux-node-x86_64-${{ env.JAVET_VERSION }} + name: javet-linux-node-x86_64-${{ env.JAVET_VERSION }}-${{ matrix.name }} path: src/main/resources/*.so + - name: Upload the i18n + uses: actions/upload-artifact@v4 + if: matrix.name == 'i18n' + with: + name: icu-node + path: icu-node/*.dat + build_javet_jar: needs: [build_javet_v8, build_javet_node] name: Build Javet Jar @@ -151,25 +199,65 @@ jobs: with: gradle-version: 8.5 - - name: Download Javet V8 + - name: Download Javet Node i18n + uses: actions/download-artifact@v4 + with: + name: javet-linux-node-x86_64-${{ env.JAVET_VERSION }}-i18n + path: src/main/resources/ + + - name: Download Javet Node non-i18n + uses: actions/download-artifact@v4 + with: + name: javet-linux-node-x86_64-${{ env.JAVET_VERSION }}-non-i18n + path: src/main/resources/ + + - name: Download Javet V8 i18n uses: actions/download-artifact@v4 with: - name: javet-linux-v8-x86_64-${{ env.JAVET_VERSION }} + name: javet-linux-v8-x86_64-${{ env.JAVET_VERSION }}-i18n path: src/main/resources/ - - name: Download Javet Node + - name: Download Javet V8 non-i18n uses: actions/download-artifact@v4 with: - name: javet-linux-node-x86_64-${{ env.JAVET_VERSION }} + name: javet-linux-v8-x86_64-${{ env.JAVET_VERSION }}-non-i18n path: src/main/resources/ + - name: Prepare i18n Location + run: | + mkdir -p icu-node + mkdir -p icu-v8 + + - name: Download i18n node + uses: actions/download-artifact@v4 + with: + name: icu-node + path: icu-node + + - name: Download i18n V8 + uses: actions/download-artifact@v4 + with: + name: icu-v8 + path: icu-v8 + + - name: Copy the i18n + run: | + mkdir -p ../node/deps/icu-tmp + mv icu-node/*.dat ../node/deps/icu-tmp + mkdir -p ../google/v8/third_party/icu/common + mv icu-v8/*.dat ../google/v8/third_party/icu/common + - name: Build the Artifact run: | cd ${{ env.ROOT }}/Javet - touch src/main/resources/libjavet-v8* - gradle build test --rerun-tasks --debug - touch src/main/resources/libjavet-node* - gradle test --rerun-tasks --debug + touch src/main/resources/libjavet-v8-*-x86_64.v* + gradle build test --rerun-tasks + touch src/main/resources/libjavet-node-*-x86_64.v* + gradle build test --rerun-tasks + touch src/main/resources/libjavet-v8-*-x86_64-i18n.v* + gradle build test --rerun-tasks + touch src/main/resources/libjavet-node-*-x86_64-i18n.v* + gradle build test --rerun-tasks gradle build generatePomFileForGeneratePomPublication - name: Clear up Source Jar @@ -185,12 +273,22 @@ jobs: build/libs/*.jar build/libs/*.pom - - name: Delete Javet V8 + - name: Delete Javet Node i18n + uses: geekyeggo/delete-artifact@v4 + with: + name: javet-linux-node-x86_64-${{ env.JAVET_VERSION }}-i18n + + - name: Delete Javet Node non-i18n + uses: geekyeggo/delete-artifact@v4 + with: + name: javet-linux-node-x86_64-${{ env.JAVET_VERSION }}-non-i18n + + - name: Delete Javet V8 i18n uses: geekyeggo/delete-artifact@v4 with: - name: javet-linux-v8-x86_64-${{ env.JAVET_VERSION }} + name: javet-linux-v8-x86_64-${{ env.JAVET_VERSION }}-i18n - - name: Delete Javet Node + - name: Delete Javet V8 non-i18n uses: geekyeggo/delete-artifact@v4 with: - name: javet-linux-node-x86_64-${{ env.JAVET_VERSION }} + name: javet-linux-v8-x86_64-${{ env.JAVET_VERSION }}-non-i18n diff --git a/.github/workflows/macos_arm64_build.yml b/.github/workflows/macos_arm64_build.yml index 5c70c1204..a17431678 100644 --- a/.github/workflows/macos_arm64_build.yml +++ b/.github/workflows/macos_arm64_build.yml @@ -7,14 +7,24 @@ on: workflow_dispatch: env: - JAVET_NODE_VERSION: 20.17.0 - JAVET_V8_VERSION: 12.9.202.18 - JAVET_VERSION: 3.1.8 + JAVET_NODE_VERSION: 22.9.0 + JAVET_V8_VERSION: 13.0.245.16 + JAVET_VERSION: 4.0.0 ROOT: /Users/runner/work/Javet jobs: build_javet_v8: - name: Build Javet V8 + strategy: + matrix: + include: + - name: i18n + cmake_flag: -DENABLE_I18N=1 + v8_flag: v8_enable_i18n_support=true + - name: non-i18n + cmake_flag: + v8_flag: v8_enable_i18n_support=false + + name: Build Javet V8 ${{ matrix.name }} runs-on: macos-14 steps: @@ -51,10 +61,17 @@ jobs: cd .. gclient sync -D cd v8 - python3 tools/dev/v8gen.py arm64.release -- v8_monolithic=true 'target_cpu="arm64"' v8_use_external_startup_data=false is_component_build=false v8_enable_i18n_support=false v8_enable_pointer_compression=false v8_static_library=true symbol_level=0 use_custom_libcxx=false v8_enable_sandbox=false + python3 tools/dev/v8gen.py arm64.release -- v8_monolithic=true 'target_cpu="arm64"' v8_use_external_startup_data=false is_component_build=false ${{ matrix.v8_flag }} v8_enable_pointer_compression=false v8_static_library=true symbol_level=0 use_custom_libcxx=false v8_enable_sandbox=false gn gen out.gn/arm64.release ninja -C out.gn/arm64.release v8_monolith || python3 ${{ env.ROOT }}/Javet/scripts/python/patch_v8_build.py -p ./ ninja -C out.gn/arm64.release v8_monolith + mv out.gn out.gn.${{ matrix.name }} + + - name: Copy the i18n + if: matrix.name == 'i18n' + run: | + mkdir -p icu-v8 + cp ../google/v8/third_party/icu/common/*.dat icu-v8 - name: Setup JDK 8 uses: actions/setup-java@v4 @@ -71,16 +88,33 @@ jobs: run: | cd ${{ env.ROOT }}/Javet/cpp sed -i '.bak' 's/`nproc`/2/g' build-macos.sh - sh ./build-macos.sh -DV8_DIR=${{ env.ROOT }}/google/v8 + sh ./build-macos.sh -DV8_DIR=${{ env.ROOT }}/google/v8 ${{ matrix.cmake_flag }} - name: Upload the Artifact uses: actions/upload-artifact@v4 with: - name: javet-macos-v8-arm64-${{ env.JAVET_VERSION }} + name: javet-macos-v8-arm64-${{ env.JAVET_VERSION }}-${{ matrix.name }} path: src/main/resources/*.dylib + - name: Upload the i18n + uses: actions/upload-artifact@v4 + if: matrix.name == 'i18n' + with: + name: icu-v8 + path: icu-v8/*.dat + build_javet_node: - name: Build Javet Node + strategy: + matrix: + include: + - name: i18n + cmake_flag: -DENABLE_I18N=1 + node_flag: --with-intl=full-icu + - name: non-i18n + cmake_flag: + node_flag: --without-intl + + name: Build Javet Node ${{ matrix.name }} runs-on: macos-14 steps: @@ -99,8 +133,15 @@ jobs: git clone https://github.com/nodejs/node.git cd node git checkout v${{ env.JAVET_NODE_VERSION }} - ./configure --enable-static --without-intl + ./configure --enable-static ${{ matrix.node_flag }} make -j4 + mv out out.${{ matrix.name }} + + - name: Copy the i18n + if: matrix.name == 'i18n' + run: | + mkdir -p icu-node + cp ../node/deps/icu-tmp/*.dat icu-node - name: Setup JDK 8 uses: actions/setup-java@v4 @@ -117,14 +158,21 @@ jobs: run: | cd ${{ env.ROOT }}/Javet/cpp sed -i '.bak' 's/`nproc`/2/g' build-macos.sh - sh ./build-macos.sh -DNODE_DIR=${{ env.ROOT }}/node + sh ./build-macos.sh -DNODE_DIR=${{ env.ROOT }}/node ${{ matrix.cmake_flag }} - name: Upload the Artifact uses: actions/upload-artifact@v4 with: - name: javet-macos-node-arm64-${{ env.JAVET_VERSION }} + name: javet-macos-node-arm64-${{ env.JAVET_VERSION }}-${{ matrix.name }} path: src/main/resources/*.dylib + - name: Upload the i18n + uses: actions/upload-artifact@v4 + if: matrix.name == 'i18n' + with: + name: icu-node + path: icu-node/*.dat + build_javet_jar: needs: [build_javet_v8, build_javet_node] name: Build Javet Jar @@ -146,25 +194,65 @@ jobs: with: gradle-version: 8.5 - - name: Download Javet V8 + - name: Download Javet Node i18n + uses: actions/download-artifact@v4 + with: + name: javet-macos-node-arm64-${{ env.JAVET_VERSION }}-i18n + path: src/main/resources/ + + - name: Download Javet Node non-i18n + uses: actions/download-artifact@v4 + with: + name: javet-macos-node-arm64-${{ env.JAVET_VERSION }}-non-i18n + path: src/main/resources/ + + - name: Download Javet V8 i18n uses: actions/download-artifact@v4 with: - name: javet-macos-v8-arm64-${{ env.JAVET_VERSION }} + name: javet-macos-v8-arm64-${{ env.JAVET_VERSION }}-i18n path: src/main/resources/ - - name: Download Javet Node + - name: Download Javet V8 non-i18n uses: actions/download-artifact@v4 with: - name: javet-macos-node-arm64-${{ env.JAVET_VERSION }} + name: javet-macos-v8-arm64-${{ env.JAVET_VERSION }}-non-i18n path: src/main/resources/ + - name: Prepare i18n Location + run: | + mkdir -p icu-node + mkdir -p icu-v8 + + - name: Download i18n node + uses: actions/download-artifact@v4 + with: + name: icu-node + path: icu-node + + - name: Download i18n V8 + uses: actions/download-artifact@v4 + with: + name: icu-v8 + path: icu-v8 + + - name: Copy the i18n + run: | + mkdir -p ../node/deps/icu-tmp + mv icu-node/*.dat ../node/deps/icu-tmp + mkdir -p ../google/v8/third_party/icu/common + mv icu-v8/*.dat ../google/v8/third_party/icu/common + - name: Build the Artifact run: | cd ${{ env.ROOT }}/Javet - touch src/main/resources/libjavet-v8* - gradle build test --rerun-tasks --debug - touch src/main/resources/libjavet-node* - gradle test --rerun-tasks --debug + touch src/main/resources/libjavet-v8-*-arm64.v* + gradle build test --rerun-tasks + touch src/main/resources/libjavet-node-*-arm64.v* + gradle build test --rerun-tasks + touch src/main/resources/libjavet-v8-*-arm64-i18n.v* + gradle build test --rerun-tasks + touch src/main/resources/libjavet-node-*-arm64-i18n.v* + gradle build test --rerun-tasks gradle build generatePomFileForGeneratePomPublication zip -d build/libs/javet-${{ env.JAVET_VERSION }}-sources.jar *.dylib @@ -176,12 +264,22 @@ jobs: build/libs/*.jar build/libs/*.pom - - name: Delete Javet V8 + - name: Delete Javet Node i18n + uses: geekyeggo/delete-artifact@v4 + with: + name: javet-macos-node-arm64-${{ env.JAVET_VERSION }}-i18n + + - name: Delete Javet Node non-i18n + uses: geekyeggo/delete-artifact@v4 + with: + name: javet-macos-node-arm64-${{ env.JAVET_VERSION }}-non-i18n + + - name: Delete Javet V8 i18n uses: geekyeggo/delete-artifact@v4 with: - name: javet-macos-v8-arm64-${{ env.JAVET_VERSION }} + name: javet-macos-v8-arm64-${{ env.JAVET_VERSION }}-i18n - - name: Delete Javet Node + - name: Delete Javet V8 non-i18n uses: geekyeggo/delete-artifact@v4 with: - name: javet-macos-node-arm64-${{ env.JAVET_VERSION }} + name: javet-macos-v8-arm64-${{ env.JAVET_VERSION }}-non-i18n diff --git a/.github/workflows/macos_x86_64_build.yml b/.github/workflows/macos_x86_64_build.yml index 3b3452859..1ce228203 100644 --- a/.github/workflows/macos_x86_64_build.yml +++ b/.github/workflows/macos_x86_64_build.yml @@ -7,14 +7,24 @@ on: workflow_dispatch: env: - JAVET_NODE_VERSION: 20.17.0 - JAVET_V8_VERSION: 12.9.202.18 - JAVET_VERSION: 3.1.8 + JAVET_NODE_VERSION: 22.9.0 + JAVET_V8_VERSION: 13.0.245.16 + JAVET_VERSION: 4.0.0 ROOT: /Users/runner/work/Javet jobs: build_javet_v8: - name: Build Javet V8 + strategy: + matrix: + include: + - name: i18n + cmake_flag: -DENABLE_I18N=1 + v8_flag: v8_enable_i18n_support=true + - name: non-i18n + cmake_flag: + v8_flag: v8_enable_i18n_support=false + + name: Build Javet V8 ${{ matrix.name }} runs-on: macos-13 steps: @@ -51,10 +61,17 @@ jobs: cd .. gclient sync -D cd v8 - python3 tools/dev/v8gen.py x64.release -- v8_monolithic=true v8_use_external_startup_data=false is_component_build=false v8_enable_i18n_support=false v8_enable_pointer_compression=false v8_static_library=true symbol_level=0 use_custom_libcxx=false v8_enable_sandbox=false + python3 tools/dev/v8gen.py x64.release -- v8_monolithic=true v8_use_external_startup_data=false is_component_build=false ${{ matrix.v8_flag }} v8_enable_pointer_compression=false v8_static_library=true symbol_level=0 use_custom_libcxx=false v8_enable_sandbox=false gn gen out.gn/x64.release ninja -C out.gn/x64.release v8_monolith || python3 ${{ env.ROOT }}/Javet/scripts/python/patch_v8_build.py -p ./ ninja -C out.gn/x64.release v8_monolith + mv out.gn out.gn.${{ matrix.name }} + + - name: Copy the i18n + if: matrix.name == 'i18n' + run: | + mkdir -p icu-v8 + cp ../google/v8/third_party/icu/common/*.dat icu-v8 - name: Setup JDK 8 uses: actions/setup-java@v4 @@ -71,16 +88,33 @@ jobs: run: | cd ${{ env.ROOT }}/Javet/cpp sed -i '.bak' 's/`nproc`/2/g' build-macos.sh - sh ./build-macos.sh -DV8_DIR=${{ env.ROOT }}/google/v8 + sh ./build-macos.sh -DV8_DIR=${{ env.ROOT }}/google/v8 ${{ matrix.cmake_flag }} - name: Upload the Artifact uses: actions/upload-artifact@v4 with: - name: javet-macos-v8-x86_64-${{ env.JAVET_VERSION }} + name: javet-macos-v8-x86_64-${{ env.JAVET_VERSION }}-${{ matrix.name }} path: src/main/resources/*.dylib + - name: Upload the i18n + uses: actions/upload-artifact@v4 + if: matrix.name == 'i18n' + with: + name: icu-v8 + path: icu-v8/*.dat + build_javet_node: - name: Build Javet Node + strategy: + matrix: + include: + - name: i18n + cmake_flag: -DENABLE_I18N=1 + node_flag: --with-intl=full-icu + - name: non-i18n + cmake_flag: + node_flag: --without-intl + + name: Build Javet Node ${{ matrix.name }} runs-on: macos-13 steps: @@ -99,8 +133,15 @@ jobs: git clone https://github.com/nodejs/node.git cd node git checkout v${{ env.JAVET_NODE_VERSION }} - ./configure --enable-static --without-intl + ./configure --enable-static ${{ matrix.node_flag }} make -j4 + mv out out.${{ matrix.name }} + + - name: Copy the i18n + if: matrix.name == 'i18n' + run: | + mkdir -p icu-node + cp ../node/deps/icu-tmp/*.dat icu-node - name: Setup JDK 8 uses: actions/setup-java@v4 @@ -117,14 +158,21 @@ jobs: run: | cd ${{ env.ROOT }}/Javet/cpp sed -i '.bak' 's/`nproc`/2/g' build-macos.sh - sh ./build-macos.sh -DNODE_DIR=${{ env.ROOT }}/node + sh ./build-macos.sh -DNODE_DIR=${{ env.ROOT }}/node ${{ matrix.cmake_flag }} - name: Upload the Artifact uses: actions/upload-artifact@v4 with: - name: javet-macos-node-x86_64-${{ env.JAVET_VERSION }} + name: javet-macos-node-x86_64-${{ env.JAVET_VERSION }}-${{ matrix.name }} path: src/main/resources/*.dylib + - name: Upload the i18n + uses: actions/upload-artifact@v4 + if: matrix.name == 'i18n' + with: + name: icu-node + path: icu-node/*.dat + build_javet_jar: needs: [build_javet_v8, build_javet_node] name: Build Javet Jar @@ -146,25 +194,65 @@ jobs: with: gradle-version: 8.5 - - name: Download Javet V8 + - name: Download Javet Node i18n + uses: actions/download-artifact@v4 + with: + name: javet-macos-node-x86_64-${{ env.JAVET_VERSION }}-i18n + path: src/main/resources/ + + - name: Download Javet Node non-i18n + uses: actions/download-artifact@v4 + with: + name: javet-macos-node-x86_64-${{ env.JAVET_VERSION }}-non-i18n + path: src/main/resources/ + + - name: Download Javet V8 i18n uses: actions/download-artifact@v4 with: - name: javet-macos-v8-x86_64-${{ env.JAVET_VERSION }} + name: javet-macos-v8-x86_64-${{ env.JAVET_VERSION }}-i18n path: src/main/resources/ - - name: Download Javet Node + - name: Download Javet V8 non-i18n uses: actions/download-artifact@v4 with: - name: javet-macos-node-x86_64-${{ env.JAVET_VERSION }} + name: javet-macos-v8-x86_64-${{ env.JAVET_VERSION }}-non-i18n path: src/main/resources/ + - name: Prepare i18n Location + run: | + mkdir -p icu-node + mkdir -p icu-v8 + + - name: Download i18n node + uses: actions/download-artifact@v4 + with: + name: icu-node + path: icu-node + + - name: Download i18n V8 + uses: actions/download-artifact@v4 + with: + name: icu-v8 + path: icu-v8 + + - name: Copy the i18n + run: | + mkdir -p ../node/deps/icu-tmp + mv icu-node/*.dat ../node/deps/icu-tmp + mkdir -p ../google/v8/third_party/icu/common + mv icu-v8/*.dat ../google/v8/third_party/icu/common + - name: Build the Artifact run: | cd ${{ env.ROOT }}/Javet - touch src/main/resources/libjavet-v8* - gradle build test --rerun-tasks --debug - touch src/main/resources/libjavet-node* - gradle test --rerun-tasks --debug + touch src/main/resources/libjavet-v8-*-x86_64.v* + gradle build test --rerun-tasks + touch src/main/resources/libjavet-node-*-x86_64.v* + gradle build test --rerun-tasks + touch src/main/resources/libjavet-v8-*-x86_64-i18n.v* + gradle build test --rerun-tasks + touch src/main/resources/libjavet-node-*-x86_64-i18n.v* + gradle build test --rerun-tasks gradle build generatePomFileForGeneratePomPublication zip -d build/libs/javet-${{ env.JAVET_VERSION }}-sources.jar *.dylib @@ -176,12 +264,22 @@ jobs: build/libs/*.jar build/libs/*.pom - - name: Delete Javet V8 + - name: Delete Javet Node i18n + uses: geekyeggo/delete-artifact@v4 + with: + name: javet-macos-node-x86_64-${{ env.JAVET_VERSION }}-i18n + + - name: Delete Javet Node non-i18n + uses: geekyeggo/delete-artifact@v4 + with: + name: javet-macos-node-x86_64-${{ env.JAVET_VERSION }}-non-i18n + + - name: Delete Javet V8 i18n uses: geekyeggo/delete-artifact@v4 with: - name: javet-macos-v8-x86_64-${{ env.JAVET_VERSION }} + name: javet-macos-v8-x86_64-${{ env.JAVET_VERSION }}-i18n - - name: Delete Javet Node + - name: Delete Javet V8 non-i18n uses: geekyeggo/delete-artifact@v4 with: - name: javet-macos-node-x86_64-${{ env.JAVET_VERSION }} + name: javet-macos-v8-x86_64-${{ env.JAVET_VERSION }}-non-i18n diff --git a/.github/workflows/windows_x86_64_build.yml b/.github/workflows/windows_x86_64_build.yml index 0e83e3752..98b080938 100644 --- a/.github/workflows/windows_x86_64_build.yml +++ b/.github/workflows/windows_x86_64_build.yml @@ -7,14 +7,24 @@ on: workflow_dispatch: env: - JAVET_NODE_VERSION: 20.17.0 - JAVET_V8_VERSION: 12.9.202.18 - JAVET_VERSION: 3.1.8 + JAVET_NODE_VERSION: 22.9.0 + JAVET_V8_VERSION: 13.0.245.16 + JAVET_VERSION: 4.0.0 ROOT: D:\a\Javet jobs: build_javet_v8: - name: Build Javet V8 + strategy: + matrix: + include: + - name: i18n + cmake_flag: -DENABLE_I18N=1 + v8_flag: v8_enable_i18n_support=true + - name: non-i18n + cmake_flag: + v8_flag: v8_enable_i18n_support=false + + name: Build Javet V8 ${{ matrix.name }} runs-on: windows-latest steps: @@ -53,10 +63,17 @@ jobs: cd .. .\depot_tools\gclient.bat sync -D cd v8 - python3 tools\dev\v8gen.py x64.release -- v8_monolithic=true v8_use_external_startup_data=false is_component_build=false v8_enable_i18n_support=false v8_enable_pointer_compression=false v8_static_library=true symbol_level=0 use_custom_libcxx=false v8_enable_sandbox=false + python3 tools\dev\v8gen.py x64.release -- v8_monolithic=true v8_use_external_startup_data=false is_component_build=false ${{ matrix.v8_flag }} v8_enable_pointer_compression=false v8_static_library=true symbol_level=0 use_custom_libcxx=false v8_enable_sandbox=false ..\depot_tools\gn.bat gen out.gn/x64.release python3 ${{ env.ROOT }}\Javet\scripts\python\patch_v8_build.py -p .\ ..\depot_tools\ninja.bat -C out.gn/x64.release v8_monolith + move out.gn out.gn.${{ matrix.name }} + + - name: Copy the i18n + if: matrix.name == 'i18n' + run: | + mkdir icu-v8 + copy ..\google\v8\third_party\icu\common\*.dat icu-v8 - name: Setup JDK 8 uses: actions/setup-java@v4 @@ -78,16 +95,33 @@ jobs: - name: Build Javet JNI run: | cd ${{ env.ROOT }}\Javet\cpp - .\build-windows.cmd -DV8_DIR=${{ env.ROOT }}\google\v8 + .\build-windows.cmd -DV8_DIR=${{ env.ROOT }}\google\v8 ${{ matrix.cmake_flag }} - name: Upload the Artifact uses: actions/upload-artifact@v4 with: - name: javet-windows-v8-x86_64-${{ env.JAVET_VERSION }} + name: javet-windows-v8-x86_64-${{ env.JAVET_VERSION }}-${{ matrix.name }} path: src\main\resources\*.dll + - name: Upload the i18n + uses: actions/upload-artifact@v4 + if: matrix.name == 'i18n' + with: + name: icu-v8 + path: icu-v8\*.dat + build_javet_node: - name: Build Javet Node + strategy: + matrix: + include: + - name: i18n + cmake_flag: -DENABLE_I18N=1 + node_flag: full-icu + - name: non-i18n + cmake_flag: + node_flag: without-intl + + name: Build Javet Node ${{ matrix.name }} runs-on: windows-latest steps: @@ -114,7 +148,14 @@ jobs: git clone https://github.com/nodejs/node.git cd node git checkout v${{ env.JAVET_NODE_VERSION }} - .\vcbuild.bat static without-intl vs2022 + .\vcbuild.bat static ${{ matrix.node_flag }} vs2022 + move out out.${{ matrix.name }} + + - name: Copy the i18n + if: matrix.name == 'i18n' + run: | + mkdir icu-node + copy ..\node\deps\icu-tmp\*.dat icu-node - name: Setup JDK 8 uses: actions/setup-java@v4 @@ -129,15 +170,22 @@ jobs: - name: Build Javet JNI run: | - cd ${{ env.ROOT }}/Javet/cpp - .\build-windows.cmd -DNODE_DIR=${{ env.ROOT }}\node + cd ${{ env.ROOT }}\Javet\cpp + .\build-windows.cmd -DNODE_DIR=${{ env.ROOT }}\node ${{ matrix.cmake_flag }} - name: Upload the Artifact uses: actions/upload-artifact@v4 with: - name: javet-windows-node-x86_64-${{ env.JAVET_VERSION }} + name: javet-windows-node-x86_64-${{ env.JAVET_VERSION }}-${{ matrix.name }} path: src\main\resources\*.dll + - name: Upload the i18n + uses: actions/upload-artifact@v4 + if: matrix.name == 'i18n' + with: + name: icu-node + path: icu-node\*.dat + build_javet_jar: needs: [build_javet_v8, build_javet_node] name: Build Javet Jar @@ -164,33 +212,70 @@ jobs: with: gradle-version: 8.5 - - name: Download Javet V8 + - name: Install 7zip + run: choco install 7zip.install + + - name: Download Javet Node i18n uses: actions/download-artifact@v4 with: - name: javet-windows-v8-x86_64-${{ env.JAVET_VERSION }} + name: javet-windows-node-x86_64-${{ env.JAVET_VERSION }}-i18n path: src\main\resources\ - - name: Download Javet Node + - name: Download Javet Node non-i18n uses: actions/download-artifact@v4 with: - name: javet-windows-node-x86_64-${{ env.JAVET_VERSION }} + name: javet-windows-node-x86_64-${{ env.JAVET_VERSION }}-non-i18n path: src\main\resources\ - - name: Build the Artifact - shell: bash + - name: Download Javet V8 i18n + uses: actions/download-artifact@v4 + with: + name: javet-windows-v8-x86_64-${{ env.JAVET_VERSION }}-i18n + path: src\main\resources\ + + - name: Download Javet V8 non-i18n + uses: actions/download-artifact@v4 + with: + name: javet-windows-v8-x86_64-${{ env.JAVET_VERSION }}-non-i18n + path: src\main\resources\ + + - name: Prepare i18n Location run: | - touch src/main/resources/libjavet-v8* - gradle build test --rerun-tasks --debug - touch src/main/resources/libjavet-node* - gradle test --rerun-tasks --debug - gradle build generatePomFileForGeneratePomPublication + mkdir icu-node + mkdir icu-v8 - - name: Install 7zip - run: choco install 7zip.install + - name: Download i18n node + uses: actions/download-artifact@v4 + with: + name: icu-node + path: icu-node - - name: Clear up Source Jar + - name: Download i18n V8 + uses: actions/download-artifact@v4 + with: + name: icu-v8 + path: icu-v8 + + - name: Copy the i18n run: | - 7z d build\libs\javet-${{ env.JAVET_VERSION }}-sources.jar *.dll + mkdir ..\node\deps\icu-tmp + move icu-node\*.dat ..\node\deps\icu-tmp + mkdir ..\google\v8\third_party\icu\common + move icu-v8\*.dat ..\google\v8\third_party\icu\common + + - name: Build the Artifact + shell: bash + run: | + touch src/main/resources/libjavet-v8-*-x86_64.v* + gradle build test --rerun-tasks + touch src/main/resources/libjavet-node-*-x86_64.v* + gradle build test --rerun-tasks + touch src/main/resources/libjavet-v8-*-x86_64-i18n.v* + gradle build test --rerun-tasks + touch src/main/resources/libjavet-node-*-x86_64-i18n.v* + gradle build test --rerun-tasks + gradle build generatePomFileForGeneratePomPublication + 7z d build/libs/javet-${{ env.JAVET_VERSION }}-sources.jar *.dll - name: Upload the Artifact uses: actions/upload-artifact@v4 @@ -200,12 +285,22 @@ jobs: build\libs\*.jar build\libs\*.pom - - name: Delete Javet V8 + - name: Delete Javet Node i18n + uses: geekyeggo/delete-artifact@v4 + with: + name: javet-windows-node-x86_64-${{ env.JAVET_VERSION }}-i18n + + - name: Delete Javet Node non-i18n + uses: geekyeggo/delete-artifact@v4 + with: + name: javet-windows-node-x86_64-${{ env.JAVET_VERSION }}-non-i18n + + - name: Delete Javet V8 i18n uses: geekyeggo/delete-artifact@v4 with: - name: javet-windows-v8-x86_64-${{ env.JAVET_VERSION }} + name: javet-windows-v8-x86_64-${{ env.JAVET_VERSION }}-i18n - - name: Delete Javet Node + - name: Delete Javet V8 non-i18n uses: geekyeggo/delete-artifact@v4 with: - name: javet-windows-node-x86_64-${{ env.JAVET_VERSION }} + name: javet-windows-v8-x86_64-${{ env.JAVET_VERSION }}-non-i18n diff --git a/README.rst b/README.rst index 8bbbe544e..9e190685b 100644 --- a/README.rst +++ b/README.rst @@ -50,7 +50,7 @@ arm ✔️ ❌ ❌ ❌ arm64 ✔️ ✔️ ✔️ ❌ =========== ======= ======= ======= ======= -* Node.js ``v20.17.0`` + V8 ``v12.9.202.18`` +* Node.js ``v22.9.0`` + V8 ``v13.0.245.16`` * Dynamic switch between Node.js and V8 mode * Polyfill V8 mode with `Javenode `_ * V8 API exposure in JVM @@ -78,21 +78,21 @@ Maven com.caoccao.javet javet - 3.1.8 + 4.0.0 com.caoccao.javet javet-linux-arm64 - 3.1.8 + 4.0.0 com.caoccao.javet javet-macos - 3.1.8 + 4.0.0 Gradle Kotlin DSL @@ -100,22 +100,22 @@ Gradle Kotlin DSL .. code-block:: kotlin - implementation("com.caoccao.javet:javet:3.1.8") // Linux and Windows (x86_64) - implementation("com.caoccao.javet:javet-linux-arm64:3.1.8") // Linux (arm64) - implementation("com.caoccao.javet:javet-macos:3.1.8") // Mac OS (x86_64 and arm64) - implementation("com.caoccao.javet:javet-android-node:3.1.8") // Android Node (arm, arm64, x86 and x86_64) - implementation("com.caoccao.javet:javet-android-v8:3.1.8") // Android V8 (arm, arm64, x86 and x86_64) + implementation("com.caoccao.javet:javet:4.0.0") // Linux and Windows (x86_64) + implementation("com.caoccao.javet:javet-linux-arm64:4.0.0") // Linux (arm64) + implementation("com.caoccao.javet:javet-macos:4.0.0") // Mac OS (x86_64 and arm64) + implementation("com.caoccao.javet:javet-android-node:4.0.0") // Android Node (arm, arm64, x86 and x86_64) + implementation("com.caoccao.javet:javet-android-v8:4.0.0") // Android V8 (arm, arm64, x86 and x86_64) Gradle Groovy DSL ^^^^^^^^^^^^^^^^^ .. code-block:: groovy - implementation 'com.caoccao.javet:javet:3.1.8' // Linux and Windows (x86_64) - implementation 'com.caoccao.javet:javet-linux-arm64:3.1.8' // Linux (arm64) - implementation 'com.caoccao.javet:javet-macos:3.1.8' // Mac OS (x86_64 and arm64) - implementation 'com.caoccao.javet:javet-android-node:3.1.8' // Android Node (arm, arm64, x86 and x86_64) - implementation 'com.caoccao.javet:javet-android-v8:3.1.8' // Android V8 (arm, arm64, x86 and x86_64) + implementation 'com.caoccao.javet:javet:4.0.0' // Linux and Windows (x86_64) + implementation 'com.caoccao.javet:javet-linux-arm64:4.0.0' // Linux (arm64) + implementation 'com.caoccao.javet:javet-macos:4.0.0' // Mac OS (x86_64 and arm64) + implementation 'com.caoccao.javet:javet-android-node:4.0.0' // Android Node (arm, arm64, x86 and x86_64) + implementation 'com.caoccao.javet:javet-android-v8:4.0.0' // Android V8 (arm, arm64, x86 and x86_64) Hello Javet ----------- diff --git a/android/javet-android/build.gradle.kts b/android/javet-android/build.gradle.kts index 553f7ed17..61726c6d8 100644 --- a/android/javet-android/build.gradle.kts +++ b/android/javet-android/build.gradle.kts @@ -73,7 +73,7 @@ object Config { const val ANDROIDX_TEST = "1.1.5" const val APPCOMPAT = "1.3.1" const val DESUGAR_JDK_LIBS = "2.0.4" - const val JAVET = "3.1.8" + const val JAVET = "4.0.0" const val JUNIT = "5.10.1" } } diff --git a/android/javet-android/src/main/AndroidManifest.xml b/android/javet-android/src/main/AndroidManifest.xml index a1dc8778a..8c970d229 100644 --- a/android/javet-android/src/main/AndroidManifest.xml +++ b/android/javet-android/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ \ No newline at end of file diff --git a/android/pom.xml b/android/pom.xml index 0b4e5c019..791c1348a 100644 --- a/android/pom.xml +++ b/android/pom.xml @@ -3,7 +3,7 @@ com.caoccao.javet javet-android - 3.1.8 + 4.0.0 javet aar Javet is Java + V8 (JAVa + V + EighT). It is an awesome way of embedding V8 in Java. @@ -29,7 +29,7 @@ scm:git:git://github.com/caoccao/Javet.git scm:git:git@github.com:caoccao/caoccao.git https://github.com/caoccao/Javet - 3.1.8 + 4.0.0 diff --git a/build.gradle.kts b/build.gradle.kts index 7c5061aa1..d6bfe5765 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -45,9 +45,6 @@ object Config { } object Projects { - // https://mvnrepository.com/artifact/net.bytebuddy/byte-buddy - const val BYTE_BUDDY = "net.bytebuddy:byte-buddy:${Versions.BYTE_BUDDY}" - // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind const val JACKSON_DATABIND = "com.fasterxml.jackson.core:jackson-databind:${Versions.JACKSON_DATABIND}" @@ -72,11 +69,10 @@ object Config { } object Versions { - const val BYTE_BUDDY = "1.14.10" const val JACKSON_DATABIND = "2.16.0" const val JAVA_VERSION = "1.8" - const val JAVET = "3.1.8" - const val JAVET_BUDDY = "0.1.0" + const val JAVET = "4.0.0" + const val JAVET_BUDDY = "0.2.0" const val JETTY_WEBSOCKET = "9.4.53.v20231009" const val JUNIT = "5.10.1" } @@ -105,7 +101,6 @@ java { } dependencies { - testImplementation(Config.Projects.BYTE_BUDDY) testImplementation(Config.Projects.JACKSON_DATABIND) testImplementation(Config.Projects.JAVET_BUDDY) testImplementation(Config.Projects.JETTY_JAVAX_WEBSOCKET_SERVER_IMPL) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 625e9dc57..a6ea379f5 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -66,9 +66,12 @@ project(Javet) aux_source_directory("jni" sourceFiles) set(includeDirs $ENV{JAVA_HOME}/include) set(importLibraries) -set(JAVET_LIB_PREFIX) -set(JAVET_LIB_TYPE) -set(JAVET_LIB_SYSTEM) +set(JAVET_LIB_ARCH "") +set(JAVET_LIB_I18N "") +set(JAVET_LIB_PREFIX "") +set(JAVET_LIB_SYSTEM "") +set(JAVET_LIB_TYPE "") +set(OUT_DIR_SUFFIX "") set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "limited configs" FORCE) if(DEFINED ENABLE_LOGGING) @@ -77,22 +80,28 @@ endif() # Preparation set(CMAKE_CXX_STANDARD 20) +if(DEFINED ENABLE_I18N) + set(JAVET_LIB_I18N "-i18n") + set(OUT_DIR_SUFFIX "i18n") +else() + set(OUT_DIR_SUFFIX "non-i18n") +endif() if(DEFINED V8_DIR) if(CMAKE_SYSTEM_NAME STREQUAL "Android") if(CMAKE_ANDROID_ARCH STREQUAL "arm64") - set(V8_RELEASE_DIR ${V8_DIR}/out.gn/arm64.release) + set(V8_RELEASE_DIR ${V8_DIR}/out.gn.${OUT_DIR_SUFFIX}/arm64.release) elseif(CMAKE_ANDROID_ARCH STREQUAL "arm") - set(V8_RELEASE_DIR ${V8_DIR}/out.gn/arm.release) + set(V8_RELEASE_DIR ${V8_DIR}/out.gn.${OUT_DIR_SUFFIX}/arm.release) elseif(CMAKE_ANDROID_ARCH STREQUAL "x86") - set(V8_RELEASE_DIR ${V8_DIR}/out.gn/ia32.release) + set(V8_RELEASE_DIR ${V8_DIR}/out.gn.${OUT_DIR_SUFFIX}/ia32.release) elseif(CMAKE_ANDROID_ARCH STREQUAL "x86_64") - set(V8_RELEASE_DIR ${V8_DIR}/out.gn/x64.release) + set(V8_RELEASE_DIR ${V8_DIR}/out.gn.${OUT_DIR_SUFFIX}/x64.release) endif() else() if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "(arm64|aarch64)") - set(V8_RELEASE_DIR ${V8_DIR}/out.gn/arm64.release) + set(V8_RELEASE_DIR ${V8_DIR}/out.gn.${OUT_DIR_SUFFIX}/arm64.release) else() - set(V8_RELEASE_DIR ${V8_DIR}/out.gn/x64.release) + set(V8_RELEASE_DIR ${V8_DIR}/out.gn.${OUT_DIR_SUFFIX}/x64.release) endif() endif() list(APPEND includeDirs @@ -115,17 +124,18 @@ if(DEFINED NODE_DIR) ${NODE_DIR}/deps/uv/include ${NODE_DIR}/deps/v8 ${NODE_DIR}/deps/v8/include + ${NODE_DIR}/deps/v8/third_party/abseil-cpp + ${NODE_DIR}/deps/ncrypto ${NODE_DIR}/src) + if(DEFINED ENABLE_I18N) + add_definitions(-DENABLE_I18N -DV8_INTL_SUPPORT -DNODE_HAVE_I18N_SUPPORT) + list(APPEND includeDirs + ${NODE_DIR}/deps/icu-small/source/common) + endif() list(APPEND importLibraries - ada base64 brotli cares histogram llhttp nghttp2 nghttp3 ngtcp2 openssl simdutf torque_base uvwasi - v8_base_without_compiler v8_compiler v8_init v8_initializers + ada brotli cares histogram llhttp nbytes ncrypto nghttp2 nghttp3 ngtcp2 openssl simdjson simdutf sqlite torque_base uvwasi + v8_abseil v8_base_without_compiler v8_compiler v8_init v8_initializers v8_initializers_slow v8_libbase v8_libplatform v8_snapshot v8_turboshaft v8_zlib zlib) - # base64 - if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "(arm64|aarch64)" OR CMAKE_ANDROID_ARCH STREQUAL "arm64") - list(APPEND importLibraries base64_neon64) - elseif(NOT CMAKE_ANDROID_ARCH STREQUAL "arm") - list(APPEND importLibraries base64_avx base64_avx2 base64_avx512 base64_sse41 base64_sse42 base64_ssse3) - endif() # node, uv if(CMAKE_SYSTEM_NAME STREQUAL "Windows") list(APPEND importLibraries libnode libuv) @@ -149,6 +159,10 @@ if(DEFINED NODE_DIR) list(APPEND importLibraries zlib_arm_crc32) endif() endif() + # icu + if(DEFINED ENABLE_I18N) + list(APPEND importLibraries icudata icui18n icuucx) + endif() add_definitions(-DENABLE_NODE) set(JAVET_LIB_TYPE "node") endif() @@ -160,8 +174,7 @@ endforeach(importLibrary) if(CMAKE_SYSTEM_NAME STREQUAL "Windows") set(JAVET_LIB_PREFIX "libjavet") set(JAVET_LIB_SYSTEM "windows") - set(JAVET_LIB_ARCH x86_64) - set(JAVET_LIB_ARCH x86_64) + set(JAVET_LIB_ARCH "-x86_64") # Generate PDB file # https://learn.microsoft.com/en-us/cpp/build/reference/zc-cplusplus set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi /MP /O2 /Ob2 /GS- /Zc:__cplusplus") @@ -179,11 +192,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows") endif() if(DEFINED NODE_DIR) list(APPEND includeDirs - ${NODE_DIR}/out/Release/obj/global_intermediate/generate-bytecode-output-root - ${NODE_DIR}/out/Release/obj/global_intermediate/inspector-generated-output-root - ${NODE_DIR}/out/Release/obj/global_intermediate) + ${NODE_DIR}/out.${OUT_DIR_SUFFIX}/Release/obj/global_intermediate/generate-bytecode-output-root + ${NODE_DIR}/out.${OUT_DIR_SUFFIX}/Release/obj/global_intermediate/inspector-generated-output-root + ${NODE_DIR}/out.${OUT_DIR_SUFFIX}/Release/obj/global_intermediate) foreach(importLibrary ${importLibraries}) - set_target_properties(${importLibrary} PROPERTIES IMPORTED_LOCATION ${NODE_DIR}/out/release/lib/${importLibrary}.lib) + set_target_properties(${importLibrary} PROPERTIES IMPORTED_LOCATION ${NODE_DIR}/out.${OUT_DIR_SUFFIX}/Release/lib/${importLibrary}.lib) endforeach(importLibrary) set_target_properties(libnode PROPERTIES LINK_FLAGS "/WHOLEARCHIVE:libnode.lib") add_library(Javet SHARED ${sourceFiles} "jni/javet_resource_node.rc") @@ -204,12 +217,12 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated -Wno-deprecated-declarations ") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -Wno-deprecated-declarations ") if (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64") - set(JAVET_LIB_ARCH x86_64) + set(JAVET_LIB_ARCH "-x86_64") add_definitions(-D__x86_64__) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64 ") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64 ") else() - set(JAVET_LIB_ARCH arm64) + set(JAVET_LIB_ARCH "-arm64") add_definitions(-D__arm64__) endif() add_definitions(-D__linux__) @@ -229,11 +242,11 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android endif() if(DEFINED NODE_DIR) list(APPEND includeDirs - ${NODE_DIR}/out/Release/obj/gen/generate-bytecode-output-root - ${NODE_DIR}/out/Release/obj/gen/inspector-generated-output-root - ${NODE_DIR}/out/Release/obj/gen) + ${NODE_DIR}/out.${OUT_DIR_SUFFIX}/Release/obj/gen/generate-bytecode-output-root + ${NODE_DIR}/out.${OUT_DIR_SUFFIX}/Release/obj/gen/inspector-generated-output-root + ${NODE_DIR}/out.${OUT_DIR_SUFFIX}/Release/obj/gen) foreach(importLibrary ${importLibraries}) - set_target_properties(${importLibrary} PROPERTIES IMPORTED_LOCATION ${NODE_DIR}/out/Release/lib${importLibrary}.a) + set_target_properties(${importLibrary} PROPERTIES IMPORTED_LOCATION ${NODE_DIR}/out.${OUT_DIR_SUFFIX}/Release/lib${importLibrary}.a) endforeach(importLibrary) list(REMOVE_ITEM importLibraries v8_init) target_link_libraries(Javet PUBLIC -Wl,--whole-archive ${importLibraries} -Wl,--no-whole-archive @@ -260,11 +273,11 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android endif() if(DEFINED NODE_DIR) list(APPEND includeDirs - ${NODE_DIR}/out.${CMAKE_ANDROID_ARCH}/Release/obj/gen/generate-bytecode-output-root - ${NODE_DIR}/out.${CMAKE_ANDROID_ARCH}/Release/obj/gen/inspector-generated-output-root - ${NODE_DIR}/out.${CMAKE_ANDROID_ARCH}/Release/obj/gen) + ${NODE_DIR}/out.${CMAKE_ANDROID_ARCH}.${OUT_DIR_SUFFIX}/Release/obj/gen/generate-bytecode-output-root + ${NODE_DIR}/out.${CMAKE_ANDROID_ARCH}.${OUT_DIR_SUFFIX}/Release/obj/gen/inspector-generated-output-root + ${NODE_DIR}/out.${CMAKE_ANDROID_ARCH}.${OUT_DIR_SUFFIX}/Release/obj/gen) foreach(importLibrary ${importLibraries}) - set_target_properties(${importLibrary} PROPERTIES IMPORTED_LOCATION ${NODE_DIR}/out.${CMAKE_ANDROID_ARCH}/Release/lib${importLibrary}.a) + set_target_properties(${importLibrary} PROPERTIES IMPORTED_LOCATION ${NODE_DIR}/out.${CMAKE_ANDROID_ARCH}.${OUT_DIR_SUFFIX}/Release/lib${importLibrary}.a) endforeach(importLibrary) list(REMOVE_ITEM importLibraries v8_init) target_link_libraries(Javet PUBLIC -Wl,--whole-archive ${importLibraries} -Wl,--no-whole-archive @@ -277,10 +290,10 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-ambiguous-reversed-operator ") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-ambiguous-reversed-operator ") if (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64") - set(JAVET_LIB_ARCH arm64) + set(JAVET_LIB_ARCH "-arm64") add_definitions(-D__arm64__) else() - set(JAVET_LIB_ARCH x86_64) + set(JAVET_LIB_ARCH "-x86_64") add_definitions(-D__x86_64__) endif() add_definitions(-D__APPLE__) @@ -299,17 +312,22 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android endif() if(DEFINED NODE_DIR) list(APPEND includeDirs - ${NODE_DIR}/out/Release/obj/gen/generate-bytecode-output-root - ${NODE_DIR}/out/Release/obj/gen/inspector-generated-output-root - ${NODE_DIR}/out/Release/obj/gen) + ${NODE_DIR}/out.${OUT_DIR_SUFFIX}/Release/obj/gen/generate-bytecode-output-root + ${NODE_DIR}/out.${OUT_DIR_SUFFIX}/Release/obj/gen/inspector-generated-output-root + ${NODE_DIR}/out.${OUT_DIR_SUFFIX}/Release/obj/gen) foreach(importLibrary ${importLibraries}) - set_target_properties(${importLibrary} PROPERTIES IMPORTED_LOCATION ${NODE_DIR}/out/Release/lib${importLibrary}.a) + set_target_properties(${importLibrary} PROPERTIES IMPORTED_LOCATION ${NODE_DIR}/out.${OUT_DIR_SUFFIX}/Release/lib${importLibrary}.a) endforeach(importLibrary) list(REMOVE_ITEM importLibraries v8_init) foreach(importLibrary ${importLibraries}) target_link_libraries(Javet PUBLIC -force_load ${importLibrary}) target_link_libraries(JavetStatic PUBLIC -force_load ${importLibrary}) endforeach(importLibrary) + # From V8 v11.7 abseil is somehow not built properly. + # This is a patch build. + # https://github.com/abseil/abseil-cpp/blob/master/CMake/README.md + add_subdirectory(${NODE_DIR}/deps/v8/third_party/abseil-cpp ${NODE_DIR}/out.${OUT_DIR_SUFFIX}/Release/third_party/abseil-cpp) + target_link_libraries(Javet PUBLIC absl::base absl::crc32c absl::time) target_link_libraries(Javet PUBLIC v8_init) target_link_libraries(JavetStatic PUBLIC v8_init) endif() @@ -318,19 +336,11 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android else() message(FATAL_ERROR "Windows (arm64) is not supported.") endif() - if(DEFINED JAVET_LIB_ARCH) - set_target_properties(JavetStatic PROPERTIES OUTPUT_NAME "${JAVET_LIB_PREFIX}-${JAVET_LIB_TYPE}-${JAVET_LIB_SYSTEM}-${JAVET_LIB_ARCH}.v.${JAVET_VERSION}") - else() - set_target_properties(JavetStatic PROPERTIES OUTPUT_NAME "${JAVET_LIB_PREFIX}-${JAVET_LIB_TYPE}-${JAVET_LIB_SYSTEM}.v.${JAVET_VERSION}") - endif() + set_target_properties(JavetStatic PROPERTIES OUTPUT_NAME "${JAVET_LIB_PREFIX}-${JAVET_LIB_TYPE}-${JAVET_LIB_SYSTEM}${JAVET_LIB_ARCH}${JAVET_LIB_I18N}.v.${JAVET_VERSION}") else() message(FATAL_ERROR "Linux (x86-64, arm64), Mac OS (x86-64, arm64), Windows (x86-64) and Android are the only supported Operating Systems.") endif() -if(DEFINED JAVET_LIB_ARCH) - set_target_properties(Javet PROPERTIES OUTPUT_NAME "${JAVET_LIB_PREFIX}-${JAVET_LIB_TYPE}-${JAVET_LIB_SYSTEM}-${JAVET_LIB_ARCH}.v.${JAVET_VERSION}") -else() - set_target_properties(Javet PROPERTIES OUTPUT_NAME "${JAVET_LIB_PREFIX}-${JAVET_LIB_TYPE}-${JAVET_LIB_SYSTEM}.v.${JAVET_VERSION}") -endif() +set_target_properties(Javet PROPERTIES OUTPUT_NAME "${JAVET_LIB_PREFIX}-${JAVET_LIB_TYPE}-${JAVET_LIB_SYSTEM}${JAVET_LIB_ARCH}${JAVET_LIB_I18N}.v.${JAVET_VERSION}") include_directories(${includeDirs}) add_custom_command(TARGET Javet POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ "${JAVA_RESOURCES_DIR}/$") diff --git a/cpp/build-android.sh b/cpp/build-android.sh index 9bb60016c..6dba39fd3 100755 --- a/cpp/build-android.sh +++ b/cpp/build-android.sh @@ -2,7 +2,7 @@ # Usage for V8: sh build-android.sh -DV8_DIR=${HOME}/v8 -DCMAKE_ANDROID_NDK=${HOME}/android -DCMAKE_ANDROID_ARCH=arm64 # Usage for Node: sh build-android.sh -DNODE_DIR=${HOME}/node -DCMAKE_ANDROID_NDK=${HOME}/android -DCMAKE_ANDROID_ARCH=arm64 -JAVET_VERSION=3.1.8 +JAVET_VERSION=4.0.0 rm -rf build_android mkdir build_android cd build_android diff --git a/cpp/build-linux-arm64.sh b/cpp/build-linux-arm64.sh index 68b5ccc26..1118c4a8d 100644 --- a/cpp/build-linux-arm64.sh +++ b/cpp/build-linux-arm64.sh @@ -2,7 +2,7 @@ # Usage for V8: sh build-linux-arm64.sh -DV8_DIR=${HOME}/v8 # Usage for Node: sh build-linux-arm64.sh -DNODE_DIR=${HOME}/node -JAVET_VERSION=3.1.8 +JAVET_VERSION=4.0.0 rm -rf build_linux_arm64 mkdir build_linux_arm64 cd build_linux_arm64 diff --git a/cpp/build-linux-x86_64.sh b/cpp/build-linux-x86_64.sh index dad650e75..25373cfad 100644 --- a/cpp/build-linux-x86_64.sh +++ b/cpp/build-linux-x86_64.sh @@ -2,7 +2,7 @@ # Usage for V8: sh build-linux-x86_64.sh -DV8_DIR=${HOME}/v8 # Usage for Node: sh build-linux-x86_64.sh -DNODE_DIR=${HOME}/node -JAVET_VERSION=3.1.8 +JAVET_VERSION=4.0.0 rm -rf build_linux_x86_64 mkdir build_linux_x86_64 cd build_linux_x86_64 diff --git a/cpp/build-macos.sh b/cpp/build-macos.sh index 5ed953bfd..3aea332d6 100755 --- a/cpp/build-macos.sh +++ b/cpp/build-macos.sh @@ -2,7 +2,7 @@ # Usage for V8: sh build-macos.sh -DV8_DIR=${HOME}/v8 # Usage for Node: sh build-macos.sh -DNODE_DIR=${HOME}/node -JAVET_VERSION=3.1.8 +JAVET_VERSION=4.0.0 rm -rf build_macos mkdir build_macos cd build_macos diff --git a/cpp/build-windows.cmd b/cpp/build-windows.cmd index 07877b419..b05b88b0b 100644 --- a/cpp/build-windows.cmd +++ b/cpp/build-windows.cmd @@ -1,7 +1,7 @@ @echo off REM Usage for V8: build -DV8_DIR=C:\v8 REM Usage for Node: build -DNODE_DIR=C:\node -SET JAVET_VERSION=3.1.8 +SET JAVET_VERSION=4.0.0 rd /s/q build_windows mkdir build_windows cd build_windows diff --git a/cpp/jni/com_caoccao_javet_interop_V8Native.h b/cpp/jni/com_caoccao_javet_interop_V8Native.h index 2670579a3..99537df9d 100644 --- a/cpp/jni/com_caoccao_javet_interop_V8Native.h +++ b/cpp/jni/com_caoccao_javet_interop_V8Native.h @@ -417,34 +417,26 @@ JNIEXPORT jstring JNICALL Java_com_caoccao_javet_interop_V8Native_getVersion /* * Class: com_caoccao_javet_interop_V8Native - * Method: hasInternalType - * Signature: (JJI)Z - */ -JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_hasInternalType - (JNIEnv *, jobject, jlong, jlong, jint); - -/* - * Class: com_caoccao_javet_interop_V8Native - * Method: hasPendingException + * Method: hasException * Signature: (J)Z */ -JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_hasPendingException +JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_hasException (JNIEnv *, jobject, jlong); /* * Class: com_caoccao_javet_interop_V8Native - * Method: hasPendingMessage - * Signature: (J)Z + * Method: hasInternalType + * Signature: (JJI)Z */ -JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_hasPendingMessage - (JNIEnv *, jobject, jlong); +JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_hasInternalType + (JNIEnv *, jobject, jlong, jlong, jint); /* * Class: com_caoccao_javet_interop_V8Native - * Method: hasScheduledException + * Method: hasPendingMessage * Signature: (J)Z */ -JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_hasScheduledException +JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_hasPendingMessage (JNIEnv *, jobject, jlong); /* @@ -471,6 +463,14 @@ JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_integerObjectV JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_isDead (JNIEnv *, jobject, jlong); +/* + * Class: com_caoccao_javet_interop_V8Native + * Method: isI18nEnabled + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_isI18nEnabled + (JNIEnv *, jobject); + /* * Class: com_caoccao_javet_interop_V8Native * Method: isInUse @@ -1143,14 +1143,6 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_promiseResolv JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_promiseThen (JNIEnv *, jobject, jlong, jlong, jint, jlong, jlong); -/* - * Class: com_caoccao_javet_interop_V8Native - * Method: promoteScheduledException - * Signature: (J)Z - */ -JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_promoteScheduledException - (JNIEnv *, jobject, jlong); - /* * Class: com_caoccao_javet_interop_V8Native * Method: proxyCreate diff --git a/cpp/jni/javet_converter.cpp b/cpp/jni/javet_converter.cpp index fcc179fc1..5ff5b87ea 100644 --- a/cpp/jni/javet_converter.cpp +++ b/cpp/jni/javet_converter.cpp @@ -588,26 +588,26 @@ namespace Javet { JNIEnv* jniEnv, const V8Runtime* v8Runtime, const V8LocalContext& v8Context, - const V8InternalObject& v8InternalObject) noexcept { + const v8::internal::Tagged& v8InternalObject) noexcept { auto v8InternalIsolate = reinterpret_cast(v8Context->GetIsolate()); - if (v8InternalObject.IsJSObject() || v8InternalObject.IsPrimitive() - || v8InternalObject.IsJSArray() || v8InternalObject.IsJSTypedArray()) { + if (v8::internal::IsJSObject(v8InternalObject) || v8::internal::IsPrimitive(v8InternalObject) + || v8::internal::IsJSArray(v8InternalObject) || v8::internal::IsJSTypedArray(v8InternalObject)) { auto v8LocalObject = v8::Utils::ToLocal(v8::internal::handle(v8InternalObject, v8InternalIsolate)); return ToExternalV8Value(jniEnv, v8Runtime, v8Context, v8LocalObject); } - else if (v8InternalObject.IsContext()) { - auto v8InternalContext = V8InternalContext::cast(v8InternalObject); + else if (v8::internal::IsContext(v8InternalObject)) { + auto v8InternalContext = V8InternalNativeContext::cast(v8InternalObject); auto v8LocalContext = v8::Utils::ToLocal(v8::internal::handle(v8InternalContext, v8InternalIsolate)); return ToExternalV8Context(jniEnv, v8Runtime, v8Context, v8LocalContext); } - else if (v8InternalObject.IsModule()) { + else if (v8::internal::IsModule(v8InternalObject)) { auto v8LocalModule = v8::Utils::ToLocal(v8::internal::handle(V8InternalModule::cast(v8InternalObject), v8InternalIsolate)); return ToExternalV8Module(jniEnv, v8Runtime, v8Context, v8LocalModule); } - else if (v8InternalObject.IsScript()) { + else if (v8::internal::IsScript(v8InternalObject)) { LOG_DEBUG("Converter: Script is not supported."); } - else if (v8InternalObject.IsCode()) { + else if (v8::internal::IsCode(v8InternalObject)) { LOG_DEBUG("Converter: Code is not supported."); } return ToExternalV8ValueUndefined(jniEnv, v8Runtime); @@ -625,7 +625,7 @@ namespace Javet { return ToExternalV8Value(jniEnv, v8Runtime, v8Context, v8LocalObject); } else if (v8::internal::IsContext(v8InternalObject)) { - auto v8InternalContext = v8::internal::Cast(v8InternalObject); + auto v8InternalContext = v8::internal::Cast(v8InternalObject); auto v8LocalContext = v8::Utils::ToLocal(v8::internal::handle(v8InternalContext, v8InternalIsolate)); return ToExternalV8Context(jniEnv, v8Runtime, v8Context, v8LocalContext); } diff --git a/cpp/jni/javet_converter.h b/cpp/jni/javet_converter.h index f08643b68..c0d29930d 100644 --- a/cpp/jni/javet_converter.h +++ b/cpp/jni/javet_converter.h @@ -152,11 +152,7 @@ namespace Javet { JNIEnv* jniEnv, const V8Runtime* v8Runtime, const V8LocalContext& v8Context, -#ifdef ENABLE_NODE - const V8InternalObject& v8InternalObject) noexcept; -#else const v8::internal::Tagged& v8InternalObject) noexcept; -#endif jobject ToExternalV8Value( JNIEnv* jniEnv, @@ -327,19 +323,19 @@ namespace Javet { const V8LocalContext& v8Context, const jobjectArray mValues) noexcept; - static inline V8InternalContext ToV8InternalContext( + static inline V8InternalNativeContext ToV8InternalContext( const V8LocalContext& v8LocalContext) noexcept { #ifdef ENABLE_NODE - return V8InternalContext::cast(*v8::Utils::OpenHandle(*v8LocalContext)); + return *V8InternalNativeContext::cast(*v8::Utils::OpenHandle(*v8LocalContext)); #else - return *v8::internal::Cast(*v8::Utils::OpenHandle(*v8LocalContext)); + return *v8::internal::Cast(*v8::Utils::OpenHandle(*v8LocalContext)); #endif } static inline V8InternalJSFunction ToV8InternalJSFunction( const V8LocalValue& v8LocalValue) noexcept { #ifdef ENABLE_NODE - return V8InternalJSFunction::cast(*v8::Utils::OpenHandle(*v8LocalValue)); + return *V8InternalJSFunction::cast(*v8::Utils::OpenHandle(*v8LocalValue)); #else return *v8::internal::Cast(*v8::Utils::OpenHandle(*v8LocalValue)); #endif @@ -348,7 +344,7 @@ namespace Javet { static inline V8InternalJSObject ToV8InternalJSObject( const V8LocalValue& v8LocalValue) noexcept { #ifdef ENABLE_NODE - return V8InternalJSObject::cast(*v8::Utils::OpenHandle(*v8LocalValue)); + return *V8InternalJSObject::cast(*v8::Utils::OpenHandle(*v8LocalValue)); #else return *v8::internal::Cast(*v8::Utils::OpenHandle(*v8LocalValue)); #endif @@ -357,7 +353,7 @@ namespace Javet { static inline V8InternalModule ToV8InternalModule( const V8LocalModule& v8LocalModule) noexcept { #ifdef ENABLE_NODE - return V8InternalModule::cast(*v8::Utils::OpenHandle(*v8LocalModule)); + return *V8InternalModule::cast(*v8::Utils::OpenHandle(*v8LocalModule)); #else return *v8::internal::Cast(*v8::Utils::OpenHandle(*v8LocalModule)); #endif @@ -366,7 +362,7 @@ namespace Javet { static inline V8InternalScript ToV8InternalScript( const V8LocalScript& v8LocalScript) noexcept { #ifdef ENABLE_NODE - return V8InternalScript::cast(*v8::Utils::OpenHandle(*v8LocalScript)); + return *V8InternalScript::cast(*v8::Utils::OpenHandle(*v8LocalScript)); #else return *v8::internal::Cast(*v8::Utils::OpenHandle(*v8LocalScript)); #endif diff --git a/cpp/jni/javet_exceptions.cpp b/cpp/jni/javet_exceptions.cpp index 826e29966..105ea17cb 100644 --- a/cpp/jni/javet_exceptions.cpp +++ b/cpp/jni/javet_exceptions.cpp @@ -52,7 +52,7 @@ namespace Javet { const V8LocalContext& v8Context, const char* message) noexcept { auto v8InternalIsolate = reinterpret_cast(v8Context->GetIsolate()); - if (HAS_PENDING_EXCEPTION(v8InternalIsolate)) { + if (HAS_EXCEPTION(v8InternalIsolate)) { V8TryCatch v8TryCatch(v8Context->GetIsolate()); v8InternalIsolate->ReportPendingMessages(); if (v8TryCatch.HasCaught()) { @@ -60,18 +60,6 @@ namespace Javet { return true; } } -#ifdef ENABLE_NODE - else if (v8InternalIsolate->has_scheduled_exception()) { - V8TryCatch v8TryCatch(v8Context->GetIsolate()); - v8InternalIsolate->PromoteScheduledException(); - if (v8InternalIsolate->has_pending_exception()) { - if (v8TryCatch.HasCaught()) { - ThrowJavetExecutionException(jniEnv, v8Runtime, v8Context, v8TryCatch); - return true; - } - } - } -#endif if (message != nullptr) { ThrowJavetOutOfMemoryException(jniEnv, v8Context, message); return true; diff --git a/cpp/jni/javet_jni_context.cpp b/cpp/jni/javet_jni_context.cpp index 27f21f9d6..ab513a248 100644 --- a/cpp/jni/javet_jni_context.cpp +++ b/cpp/jni/javet_jni_context.cpp @@ -22,7 +22,7 @@ JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_contextGet RUNTIME_AND_VALUE_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle, v8ValueHandle); if (IS_V8_CONTEXT(v8ValueType)) { V8LocalContext v8ContextValue = v8LocalValue.As(); - V8InternalContext v8InternalContext = Javet::Converter::ToV8InternalContext(v8ContextValue); + V8InternalNativeContext v8InternalContext = Javet::Converter::ToV8InternalContext(v8ContextValue); if (index >= 0 && index < v8InternalContext.length()) { auto v8InternalIsolate = reinterpret_cast(v8Context->GetIsolate()); auto v8InternalObject = v8InternalContext.get(index); @@ -37,7 +37,7 @@ JNIEXPORT jint JNICALL Java_com_caoccao_javet_interop_V8Native_contextGetLength RUNTIME_AND_VALUE_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle, v8ValueHandle); if (IS_V8_CONTEXT(v8ValueType)) { V8LocalContext v8ContextValue = v8LocalValue.As(); - V8InternalContext v8InternalContext = Javet::Converter::ToV8InternalContext(v8ContextValue); + V8InternalNativeContext v8InternalContext = Javet::Converter::ToV8InternalContext(v8ContextValue); return v8InternalContext.length(); } return 0; @@ -48,7 +48,7 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_contextIsCont RUNTIME_AND_VALUE_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle, v8ValueHandle); if (IS_V8_CONTEXT(v8ValueType)) { V8LocalContext v8ContextValue = v8LocalValue.As(); - V8InternalContext v8InternalContext = Javet::Converter::ToV8InternalContext(v8ContextValue); + V8InternalNativeContext v8InternalContext = Javet::Converter::ToV8InternalContext(v8ContextValue); using namespace Javet::Enums::V8ContextType; switch (contextTypeId) { case Await: return v8InternalContext.IsAwaitContext(); // 0 @@ -73,7 +73,7 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_contextSetLen jboolean success = false; if (IS_V8_CONTEXT(v8ValueType)) { V8LocalContext v8ContextValue = v8LocalValue.As(); - V8InternalContext v8InternalContext = Javet::Converter::ToV8InternalContext(v8ContextValue); + V8InternalNativeContext v8InternalContext = Javet::Converter::ToV8InternalContext(v8ContextValue); v8InternalContext.set_length(length); success = true; } diff --git a/cpp/jni/javet_jni_core_v8.cpp b/cpp/jni/javet_jni_core_v8.cpp index 975c307a4..3cb3d85c2 100644 --- a/cpp/jni/javet_jni_core_v8.cpp +++ b/cpp/jni/javet_jni_core_v8.cpp @@ -232,6 +232,15 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_hasInternalTy return false; } +JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_isI18nEnabled +(JNIEnv* jniEnv, jobject caller) { +#ifdef ENABLE_I18N + return true; +#else + return false; +#endif +} + JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_isDead (JNIEnv* jniEnv, jobject caller, jlong v8RuntimeHandle) { auto v8Runtime = Javet::V8Runtime::FromHandle(v8RuntimeHandle); diff --git a/cpp/jni/javet_jni_error.cpp b/cpp/jni/javet_jni_error.cpp index a9b447782..f99df6a54 100644 --- a/cpp/jni/javet_jni_error.cpp +++ b/cpp/jni/javet_jni_error.cpp @@ -35,11 +35,11 @@ JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_errorCreate return Javet::Converter::ToExternalV8ValueUndefined(jniEnv, v8Runtime); } -JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_hasPendingException +JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_hasException (JNIEnv* jniEnv, jobject caller, jlong v8RuntimeHandle) { RUNTIME_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle); auto v8InternalIsolate = reinterpret_cast(v8Context->GetIsolate()); - return HAS_PENDING_EXCEPTION(v8InternalIsolate); + return HAS_EXCEPTION(v8InternalIsolate); } JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_hasPendingMessage @@ -49,30 +49,6 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_hasPendingMes return v8InternalIsolate->has_pending_message(); } -JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_hasScheduledException -(JNIEnv* jniEnv, jobject caller, jlong v8RuntimeHandle) { -#ifdef ENABLE_NODE - RUNTIME_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle); - auto v8InternalIsolate = reinterpret_cast(v8Context->GetIsolate()); - return v8InternalIsolate->has_scheduled_exception(); -#else - return false; -#endif -} - -JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_promoteScheduledException -(JNIEnv* jniEnv, jobject caller, jlong v8RuntimeHandle) { -#ifdef ENABLE_NODE - RUNTIME_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle); - auto v8InternalIsolate = reinterpret_cast(v8Context->GetIsolate()); - if (v8InternalIsolate->has_scheduled_exception()) { - v8InternalIsolate->PromoteScheduledException(); - return true; - } -#endif - return false; -} - JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_reportPendingMessages (JNIEnv* jniEnv, jobject caller, jlong v8RuntimeHandle) { RUNTIME_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle); diff --git a/cpp/jni/javet_jni_function.cpp b/cpp/jni/javet_jni_function.cpp index 3ae334e99..d6b128605 100644 --- a/cpp/jni/javet_jni_function.cpp +++ b/cpp/jni/javet_jni_function.cpp @@ -73,11 +73,7 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_functionCanDi auto v8InternalFunction = Javet::Converter::ToV8InternalJSFunction(v8LocalValue); auto v8InternalShared = v8InternalFunction.shared(); if (IS_USER_DEFINED_FUNCTION(v8InternalShared)) { -#ifdef ENABLE_NODE - return v8InternalShared.CanDiscardCompiled(); -#else return v8InternalShared->CanDiscardCompiled(); -#endif } } return false; @@ -157,11 +153,11 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_functionCopyS v8::internal::handle(sourceV8InternalShared, v8InternalIsolate)); // Clone the scope info #ifdef ENABLE_NODE - auto sourceScopeInfo = sourceV8InternalShared.scope_info(); + auto sourceScopeInfo = sourceV8InternalShared->scope_info(); auto emptyBlocklistHandle = V8InternalStringSet::New(v8InternalIsolate); auto targetScopeInfo = *V8InternalScopeInfo::RecreateWithBlockList( v8InternalIsolate, v8::internal::handle(sourceScopeInfo, v8InternalIsolate), emptyBlocklistHandle); - targetV8InternalShared.set_raw_scope_info(targetScopeInfo); + targetV8InternalShared->set_raw_scope_info(targetScopeInfo); #else auto sourceScopeInfo = sourceV8InternalShared->scope_info(); const int length = (sourceScopeInfo->AllocatedSize() - V8InternalHeapObject::kHeaderSize) / v8::internal::kTaggedSize; @@ -219,39 +215,30 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_functionDisca auto v8InternalFunction = Javet::Converter::ToV8InternalJSFunction(v8LocalValue); auto v8InternalShared = v8InternalFunction.shared(); if (IS_USER_DEFINED_FUNCTION(v8InternalShared)) { -#ifdef ENABLE_NODE - if (v8InternalShared.CanDiscardCompiled()) { -#else if (v8InternalShared->CanDiscardCompiled()) { -#endif auto v8InternalIsolate = reinterpret_cast(v8Context->GetIsolate()); V8InternalSharedFunctionInfo::DiscardCompiled(v8InternalIsolate, v8::internal::handle(v8InternalShared, v8InternalIsolate)); return true; } - } } - return false; } + return false; +} JNIEXPORT jobjectArray JNICALL Java_com_caoccao_javet_interop_V8Native_functionGetArguments -(JNIEnv * jniEnv, jobject caller, jlong v8RuntimeHandle, jlong v8ValueHandle, jint v8ValueType) { +(JNIEnv* jniEnv, jobject caller, jlong v8RuntimeHandle, jlong v8ValueHandle, jint v8ValueType) { RUNTIME_AND_VALUE_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle, v8ValueHandle); if (IS_V8_FUNCTION(v8ValueType)) { auto v8InternalFunction = Javet::Converter::ToV8InternalJSFunction(v8LocalValue); auto v8InternalShared = v8InternalFunction.shared(); -#ifdef ENABLE_NODE - if (IS_USER_DEFINED_FUNCTION(v8InternalShared) && v8InternalShared.is_wrapped()) { -#else if (IS_USER_DEFINED_FUNCTION(v8InternalShared) && v8InternalShared->is_wrapped()) { -#endif auto v8InternalIsolate = reinterpret_cast(v8Context->GetIsolate()); #ifdef ENABLE_NODE - auto v8InternalScript = V8InternalScript::cast(v8InternalShared.script()); - auto wrappedArguments = v8InternalScript.wrapped_arguments(); + auto v8InternalScript = V8InternalScript::cast(v8InternalShared->script()); #else auto v8InternalScript = v8::internal::Cast(v8InternalShared->script()); - auto wrappedArguments = *v8InternalScript->wrapped_arguments(); #endif + auto wrappedArguments = *v8InternalScript->wrapped_arguments(); auto length = wrappedArguments.length(); if (length > 0) { jobjectArray arguments = jniEnv->NewObjectArray(length, Javet::Converter::jclassString, nullptr); @@ -266,7 +253,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_caoccao_javet_interop_V8Native_functionG } } return nullptr; - } +} JNIEXPORT jbyteArray JNICALL Java_com_caoccao_javet_interop_V8Native_functionGetCachedData (JNIEnv * jniEnv, jobject caller, jlong v8RuntimeHandle, jlong v8ValueHandle, jint v8ValueType) { @@ -276,12 +263,11 @@ JNIEXPORT jbyteArray JNICALL Java_com_caoccao_javet_interop_V8Native_functionGet auto v8InternalShared = v8InternalFunction.shared(); if (IS_USER_DEFINED_FUNCTION(v8InternalShared)) { #ifdef ENABLE_NODE - auto v8InternalScript = V8InternalScript::cast(v8InternalShared.script()); - if (v8InternalScript.is_wrapped()) { + auto v8InternalScript = V8InternalScript::cast(v8InternalShared->script()); #else auto v8InternalScript = v8::internal::Cast(v8InternalShared->script()); - if (v8InternalScript->is_wrapped()) { #endif + if (v8InternalScript->is_wrapped()) { V8TryCatch v8TryCatch(v8Context->GetIsolate()); std::unique_ptr cachedDataPointer; cachedDataPointer.reset(v8::ScriptCompiler::CreateCodeCacheForFunction(v8LocalValue.As())); @@ -293,8 +279,8 @@ JNIEXPORT jbyteArray JNICALL Java_com_caoccao_javet_interop_V8Native_functionGet return Javet::Converter::ToJavaByteArray(jniEnv, cachedDataPointer.get()); } } - } } + } return nullptr; } @@ -338,11 +324,7 @@ JNIEXPORT jint JNICALL Java_com_caoccao_javet_interop_V8Native_functionGetJSFunc using namespace Javet::Enums::JSFunctionType; if (IS_V8_FUNCTION(v8ValueType)) { auto v8InternalFunction = Javet::Converter::ToV8InternalJSFunction(v8LocalValue); -#ifdef ENABLE_NODE - auto v8InternalShared = v8InternalFunction.shared(); -#else auto v8InternalShared = *v8InternalFunction.shared(); -#endif if (v8InternalShared.native()) { return Native; } @@ -361,13 +343,8 @@ JNIEXPORT jint JNICALL Java_com_caoccao_javet_interop_V8Native_functionGetJSScop RUNTIME_AND_VALUE_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle, v8ValueHandle); if (IS_V8_FUNCTION(v8ValueType)) { auto v8InternalFunction = Javet::Converter::ToV8InternalJSFunction(v8LocalValue); -#ifdef ENABLE_NODE - auto v8InternalShared = v8InternalFunction.shared(); - auto v8InternalScopeInfo = v8InternalShared.scope_info(); -#else auto v8InternalShared = *v8InternalFunction.shared(); auto v8InternalScopeInfo = *v8InternalShared.scope_info(); -#endif return v8InternalScopeInfo.scope_type(); } return Javet::Enums::JSScopeType::Unknown; @@ -382,13 +359,8 @@ JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_functionGetSco V8InternalDisallowGarbageCollection disallowGarbageCollection; auto v8InternalIsolate = reinterpret_cast(v8Context->GetIsolate()); auto v8InternalFunction = Javet::Converter::ToV8InternalJSFunction(v8LocalValue); -#ifdef ENABLE_NODE - auto v8InternalShared = v8InternalFunction.shared(); - auto v8InternalScopeInfo = v8InternalShared.scope_info(); -#else auto v8InternalShared = *v8InternalFunction.shared(); auto v8InternalScopeInfo = *v8InternalShared.scope_info(); -#endif V8InternalScopeIterator scopeIterator(v8InternalIsolate, v8::internal::handle(v8InternalFunction, v8InternalIsolate)); uint32_t index = 0; for (; !scopeIterator.Done(); scopeIterator.Next()) { @@ -408,7 +380,7 @@ JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_functionGetSco v8LocalArray->Set(v8Context, index, innerV8LocalArray).ToChecked(); ++index; } -} + } return v8Runtime->SafeToExternalV8Value(jniEnv, v8Context, v8LocalArray); } @@ -421,32 +393,26 @@ JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_functionGetScr auto v8InternalShared = v8InternalFunction.shared(); if (IS_USER_DEFINED_FUNCTION(v8InternalShared)) { #ifdef ENABLE_NODE - auto v8InternalScript = V8InternalScript::cast(v8InternalShared.script()); - auto v8InternalSource = V8InternalString::cast(v8InternalScript.source()); - const int startPosition = v8InternalShared.StartPosition(); - const int endPosition = v8InternalShared.EndPosition(); - const int sourceLength = v8InternalSource.length(); - auto sourceCode = v8InternalSource.ToCString( - V8InternalAllowNullsFlag::DISALLOW_NULLS, V8InternalRobustnessFlag::ROBUST_STRING_TRAVERSAL, - 0, sourceLength); + auto v8InternalScript = V8InternalScript::cast(v8InternalShared->script()); + auto v8InternalSource = V8InternalString::cast(v8InternalScript->source()); #else auto v8InternalScript = v8::internal::Cast(v8InternalShared->script()); auto v8InternalSource = v8::internal::Cast(v8InternalScript->source()); +#endif const int startPosition = v8InternalShared->StartPosition(); const int endPosition = v8InternalShared->EndPosition(); const int sourceLength = v8InternalSource->length(); auto sourceCode = v8InternalSource->ToCString( V8InternalAllowNullsFlag::DISALLOW_NULLS, V8InternalRobustnessFlag::ROBUST_STRING_TRAVERSAL, 0, sourceLength); -#endif return jniEnv->NewObject( Javet::Converter::jclassIV8ValueFunctionScriptSource, Javet::Converter::jmethodIDIV8ValueFunctionScriptSourceConstructor, Javet::Converter::ToJavaString(jniEnv, sourceCode.get()), startPosition, endPosition); -} -} + } + } return nullptr; } @@ -458,25 +424,20 @@ JNIEXPORT jstring JNICALL Java_com_caoccao_javet_interop_V8Native_functionGetSou auto v8InternalShared = v8InternalFunction.shared(); if (IS_USER_DEFINED_FUNCTION(v8InternalShared)) { #ifdef ENABLE_NODE - auto v8InternalScript = V8InternalScript::cast(v8InternalShared.script()); - auto v8InternalSource = V8InternalString::cast(v8InternalScript.source()); - const int startPosition = v8InternalShared.StartPosition(); - const int endPosition = v8InternalShared.EndPosition(); - auto sourceCode = v8InternalSource.ToCString( - V8InternalAllowNullsFlag::DISALLOW_NULLS, V8InternalRobustnessFlag::ROBUST_STRING_TRAVERSAL, - startPosition, endPosition - startPosition); + auto v8InternalScript = V8InternalScript::cast(v8InternalShared->script()); + auto v8InternalSource = V8InternalString::cast(v8InternalScript->source()); #else auto v8InternalScript = v8::internal::Cast(v8InternalShared->script()); auto v8InternalSource = v8::internal::Cast(v8InternalScript->source()); +#endif const int startPosition = v8InternalShared->StartPosition(); const int endPosition = v8InternalShared->EndPosition(); auto sourceCode = v8InternalSource->ToCString( V8InternalAllowNullsFlag::DISALLOW_NULLS, V8InternalRobustnessFlag::ROBUST_STRING_TRAVERSAL, startPosition, endPosition - startPosition); -#endif return Javet::Converter::ToJavaString(jniEnv, sourceCode.get()); + } } -} return nullptr; } @@ -487,11 +448,7 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_functionIsCom auto v8InternalFunction = Javet::Converter::ToV8InternalJSFunction(v8LocalValue); auto v8InternalShared = v8InternalFunction.shared(); if (IS_USER_DEFINED_FUNCTION(v8InternalShared)) { -#ifdef ENABLE_NODE - return v8InternalShared.is_compiled(); -#else return v8InternalShared->is_compiled(); -#endif } } return false; @@ -504,11 +461,7 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_functionIsWra auto v8InternalFunction = Javet::Converter::ToV8InternalJSFunction(v8LocalValue); auto v8InternalShared = v8InternalFunction.shared(); if (IS_USER_DEFINED_FUNCTION(v8InternalShared)) { -#ifdef ENABLE_NODE - return v8InternalShared.is_wrapped(); -#else return v8InternalShared->is_wrapped(); -#endif } } return false; @@ -521,7 +474,7 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_functionSetCo if (IS_V8_FUNCTION(v8ValueType)) { V8InternalDisallowGarbageCollection disallowGarbageCollection; V8LocalContext v8ContextValue = Javet::Converter::ToV8Context(jniEnv, v8Context, mV8ContextValue); - V8InternalContext v8InternalContext = Javet::Converter::ToV8InternalContext(v8ContextValue); + V8InternalNativeContext v8InternalContext = Javet::Converter::ToV8InternalContext(v8ContextValue); auto v8InternalFunction = Javet::Converter::ToV8InternalJSFunction(v8LocalValue); v8InternalFunction.set_context(v8InternalContext); success = true; @@ -538,75 +491,45 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_functionSetSc auto v8InternalFunction = Javet::Converter::ToV8InternalJSFunction(v8LocalValue); auto v8InternalShared = v8InternalFunction.shared(); if (IS_USER_DEFINED_FUNCTION(v8InternalShared)) { -#ifdef ENABLE_NODE - auto v8InternalScopeInfo = v8InternalShared.scope_info(); - if (v8InternalScopeInfo.scope_type() == V8InternalScopeType::FUNCTION_SCOPE) { -#else auto v8InternalScopeInfo = v8InternalShared->scope_info(); if (v8InternalScopeInfo->scope_type() == V8InternalScopeType::FUNCTION_SCOPE) { -#endif auto v8InternalIsolate = reinterpret_cast(v8Context->GetIsolate()); auto mSourceCode = (jstring)jniEnv->CallObjectMethod(mScriptSource, Javet::Converter::jmethodIDIV8ValueFunctionScriptGetCode); auto umSourceCode = Javet::Converter::ToV8String(jniEnv, v8Context, mSourceCode); const int startPosition = jniEnv->CallIntMethod(mScriptSource, Javet::Converter::jmethodIDIV8ValueFunctionScriptGetStartPosition); const int endPosition = jniEnv->CallIntMethod(mScriptSource, Javet::Converter::jmethodIDIV8ValueFunctionScriptGetEndPosition); #ifdef ENABLE_NODE - auto v8InternalScript = V8InternalScript::cast(v8InternalShared.script()); - auto v8InternalSource = v8::Utils::OpenHandle(*umSourceCode); - bool sourceCodeEquals = v8InternalScript.source().StrictEquals(*v8InternalSource); - bool positionEquals = startPosition == v8InternalShared.StartPosition() && endPosition == v8InternalShared.EndPosition(); + auto v8InternalScript = V8InternalScript::cast(v8InternalShared->script()); #else auto v8InternalScript = v8::internal::Cast(v8InternalShared->script()); +#endif auto v8InternalSource = v8::Utils::OpenHandle(*umSourceCode); bool sourceCodeEquals = V8InternalObject::StrictEquals(v8InternalScript->source(), *v8InternalSource); bool positionEquals = startPosition == v8InternalShared->StartPosition() && endPosition == v8InternalShared->EndPosition(); -#endif if (!sourceCodeEquals || !positionEquals) { -#ifdef ENABLE_NODE - if (v8InternalShared.CanDiscardCompiled()) { -#else if (v8InternalShared->CanDiscardCompiled()) { -#endif V8InternalSharedFunctionInfo::DiscardCompiled(v8InternalIsolate, v8::internal::handle(v8InternalShared, v8InternalIsolate)); -#ifdef ENABLE_NODE - v8InternalShared.set_allows_lazy_compilation(true); -#else v8InternalShared->set_allows_lazy_compilation(true); -#endif } if (!sourceCodeEquals) { auto v8InternalScriptHandle = v8::internal::handle(v8InternalScript, v8InternalIsolate); if (mCloneScript) { -#ifdef ENABLE_NODE - auto clonedV8InternalScript = v8InternalIsolate->factory()->CloneScript(v8InternalScriptHandle); - clonedV8InternalScript->set_source(*v8InternalSource, V8InternalWriteBarrierMode::UPDATE_WRITE_BARRIER); - v8InternalShared.set_script(*clonedV8InternalScript); -#else auto clonedV8InternalScript = v8InternalIsolate->factory()->CloneScript(v8InternalScriptHandle, v8InternalSource); v8InternalShared->set_script(*clonedV8InternalScript, v8::kReleaseStore); -#endif } else { -#ifdef ENABLE_NODE - v8InternalScript.set_source(*v8InternalSource, V8InternalWriteBarrierMode::UPDATE_WRITE_BARRIER); -#else V8InternalScript::SetSource(v8InternalIsolate, v8InternalScriptHandle, v8InternalSource); -#endif } } if (!positionEquals) { -#ifdef ENABLE_NODE - v8InternalScopeInfo.SetPositionInfo(startPosition, endPosition); -#else v8InternalScopeInfo->SetPositionInfo(startPosition, endPosition); -#endif } success = true; } DELETE_LOCAL_REF(jniEnv, mSourceCode); } - } } + } return success; } @@ -619,27 +542,19 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_functionSetSo auto v8InternalFunction = Javet::Converter::ToV8InternalJSFunction(v8LocalValue); auto v8InternalShared = v8InternalFunction.shared(); if (IS_USER_DEFINED_FUNCTION(v8InternalShared)) { -#ifdef ENABLE_NODE - auto v8InternalScopeInfo = v8InternalShared.scope_info(); - while (v8InternalScopeInfo.scope_type() == V8InternalScopeType::FUNCTION_SCOPE) { -#else auto v8InternalScopeInfo = v8InternalShared->scope_info(); while (v8InternalScopeInfo->scope_type() == V8InternalScopeType::FUNCTION_SCOPE) { -#endif auto v8InternalIsolate = reinterpret_cast(v8Context->GetIsolate()); #ifdef ENABLE_NODE - auto v8InternalScript = V8InternalScript::cast(v8InternalShared.script()); - auto v8InternalSource = V8InternalString::cast(v8InternalScript.source()); - const int startPosition = v8InternalShared.StartPosition(); - const int endPosition = v8InternalShared.EndPosition(); - const int sourceLength = v8InternalSource.length(); + auto v8InternalScript = V8InternalScript::cast(v8InternalShared->script()); + auto v8InternalSource = V8InternalString::cast(v8InternalScript->source()); #else auto v8InternalScript = v8::internal::Cast(v8InternalShared->script()); auto v8InternalSource = v8::internal::Cast(v8InternalScript->source()); +#endif const int startPosition = v8InternalShared->StartPosition(); const int endPosition = v8InternalShared->EndPosition(); const int sourceLength = v8InternalSource->length(); -#endif // Build the new source code. auto umSourceCode = Javet::Converter::ToV8String(jniEnv, v8Context, mSourceCode); @@ -647,15 +562,9 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_functionSetSo V8LocalString newSourceCode; if (startPosition > 0) { int utf8Length = 0; -#ifdef ENABLE_NODE - auto stdStringHeader(v8InternalSource.ToCString( - V8InternalAllowNullsFlag::DISALLOW_NULLS, V8InternalRobustnessFlag::ROBUST_STRING_TRAVERSAL, - 0, startPosition, &utf8Length)); -#else auto stdStringHeader(v8InternalSource->ToCString( V8InternalAllowNullsFlag::DISALLOW_NULLS, V8InternalRobustnessFlag::ROBUST_STRING_TRAVERSAL, 0, startPosition, &utf8Length)); -#endif auto v8MaybeLocalStringHeader = v8::String::NewFromUtf8( v8Context->GetIsolate(), stdStringHeader.get(), v8::NewStringType::kNormal, utf8Length); if (v8MaybeLocalStringHeader.IsEmpty()) { @@ -673,15 +582,9 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_functionSetSo } if (endPosition < sourceLength) { int utf8Length = 0; -#ifdef ENABLE_NODE - auto stdStringFooter(v8InternalSource.ToCString( - V8InternalAllowNullsFlag::DISALLOW_NULLS, V8InternalRobustnessFlag::ROBUST_STRING_TRAVERSAL, - endPosition, sourceLength - endPosition, &utf8Length)); -#else auto stdStringFooter(v8InternalSource->ToCString( V8InternalAllowNullsFlag::DISALLOW_NULLS, V8InternalRobustnessFlag::ROBUST_STRING_TRAVERSAL, endPosition, sourceLength - endPosition, &utf8Length)); -#endif auto v8MaybeLocalStringFooter = v8::String::NewFromUtf8( v8Context->GetIsolate(), stdStringFooter.get(), v8::NewStringType::kNormal, utf8Length); if (v8MaybeLocalStringFooter.IsEmpty()) { @@ -709,59 +612,33 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_functionSetSo const int newEndPosition = startPosition + newSourceLength; auto newV8InternalSource = v8::Utils::OpenHandle(*newSourceCode); -#ifdef ENABLE_NODE - bool sourceCodeEquals = v8InternalSource.StrictEquals(*newV8InternalSource); - bool positionEquals = newEndPosition == v8InternalShared.EndPosition(); -#else bool sourceCodeEquals = V8InternalObject::StrictEquals(v8InternalSource, *newV8InternalSource); bool positionEquals = newEndPosition == v8InternalShared->EndPosition(); -#endif if (!sourceCodeEquals || !positionEquals) { // Discard compiled data and set lazy compile. -#ifdef ENABLE_NODE - if (v8InternalShared.CanDiscardCompiled()) { - V8InternalSharedFunctionInfo::DiscardCompiled(v8InternalIsolate, v8::internal::handle(v8InternalShared, v8InternalIsolate)); - v8InternalShared.set_allows_lazy_compilation(true); - } -#else if (v8InternalShared->CanDiscardCompiled()) { V8InternalSharedFunctionInfo::DiscardCompiled(v8InternalIsolate, v8::internal::handle(v8InternalShared, v8InternalIsolate)); v8InternalShared->set_allows_lazy_compilation(true); } -#endif if (!sourceCodeEquals) { auto v8InternalScriptHandle = v8::internal::handle(v8InternalScript, v8InternalIsolate); if (mCloneScript) { -#ifdef ENABLE_NODE - auto clonedV8InternalScript = v8InternalIsolate->factory()->CloneScript(v8InternalScriptHandle); - clonedV8InternalScript->set_source(*newV8InternalSource, V8InternalWriteBarrierMode::UPDATE_WRITE_BARRIER); - v8InternalShared.set_script(*clonedV8InternalScript); -#else auto clonedV8InternalScript = v8InternalIsolate->factory()->CloneScript(v8InternalScriptHandle, newV8InternalSource); v8InternalShared->set_script(*clonedV8InternalScript, v8::kReleaseStore); -#endif } else { -#ifdef ENABLE_NODE - v8InternalScript.set_source(*newV8InternalSource, V8InternalWriteBarrierMode::UPDATE_WRITE_BARRIER); -#else V8InternalScript::SetSource(v8InternalIsolate, v8InternalScriptHandle, newV8InternalSource); -#endif } } if (!positionEquals) { -#ifdef ENABLE_NODE - v8InternalScopeInfo.SetPositionInfo(startPosition, newEndPosition); -#else v8InternalScopeInfo->SetPositionInfo(startPosition, newEndPosition); -#endif } success = true; } break; + } } -} } return success; } diff --git a/cpp/jni/javet_jni_module.cpp b/cpp/jni/javet_jni_module.cpp index 42842b74d..8879ec89c 100644 --- a/cpp/jni/javet_jni_module.cpp +++ b/cpp/jni/javet_jni_module.cpp @@ -77,17 +77,11 @@ JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_moduleCreate } } } -#ifndef ENABLE_NODE v8::MemorySpan exportNamesMemorySpan(exportNames.begin(), exportNames.end()); -#endif auto v8LocalModule = v8::Module::CreateSyntheticModule( v8Context->GetIsolate(), Javet::Converter::ToV8String(jniEnv, v8Context, mModuleName), -#ifdef ENABLE_NODE - exportNames, -#else exportNamesMemorySpan, -#endif Javet::Callback::JavetSyntheticModuleEvaluationStepsCallback); std::string stringKey("module:{}" + std::to_string(v8LocalModule->GetIdentityHash())); auto v8LocalStringKey = Javet::Converter::ToV8String(v8Context, stringKey.c_str()); @@ -218,7 +212,7 @@ JNIEXPORT jstring JNICALL Java_com_caoccao_javet_interop_V8Native_moduleGetResou if (v8LocalModule->IsSourceTextModule()) { #ifdef ENABLE_NODE auto v8InternalSourceTextModule = V8InternalSourceTextModule::cast(v8InternalModule); - auto v8InternalScript = v8InternalSourceTextModule.GetScript(); + auto v8InternalScript = *v8InternalSourceTextModule->GetScript(); #else auto v8InternalSourceTextModule = v8::internal::Cast(v8InternalModule); auto v8InternalScript = *((*v8InternalSourceTextModule).GetScript()); @@ -228,7 +222,7 @@ JNIEXPORT jstring JNICALL Java_com_caoccao_javet_interop_V8Native_moduleGetResou } else if (v8LocalModule->IsSyntheticModule()) { #ifdef ENABLE_NODE - auto v8InternalSyntheticModule = V8InternalSyntheticModule::cast(v8InternalModule); + auto v8InternalSyntheticModule = *V8InternalSyntheticModule::cast(v8InternalModule); #else auto v8InternalSyntheticModule = *v8::internal::Cast(v8InternalModule); #endif diff --git a/cpp/jni/javet_jni_object.cpp b/cpp/jni/javet_jni_object.cpp index 104f63dfd..64aaa25b1 100644 --- a/cpp/jni/javet_jni_object.cpp +++ b/cpp/jni/javet_jni_object.cpp @@ -644,7 +644,7 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_objectIsFroze if (v8LocalValue->IsObject()) { auto v8InternalJSObject = Javet::Converter::ToV8InternalJSObject(v8LocalValue); #ifdef ENABLE_NODE - auto elementKind = V8InternalJSObject::cast(v8InternalJSObject).GetElementsKind(); + auto elementKind = V8InternalJSObject::cast(v8InternalJSObject)->GetElementsKind(); #else auto elementKind = v8::internal::Cast(v8InternalJSObject)->GetElementsKind(); #endif @@ -659,7 +659,7 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_objectIsSeale if (v8LocalValue->IsObject()) { auto v8InternalJSObject = Javet::Converter::ToV8InternalJSObject(v8LocalValue); #ifdef ENABLE_NODE - auto elementKind = V8InternalJSObject::cast(v8InternalJSObject).GetElementsKind(); + auto elementKind = V8InternalJSObject::cast(v8InternalJSObject)->GetElementsKind(); #else auto elementKind = v8::internal::Cast(v8InternalJSObject)->GetElementsKind(); #endif diff --git a/cpp/jni/javet_native.cpp b/cpp/jni/javet_native.cpp index 964e58511..3f03d2bc7 100644 --- a/cpp/jni/javet_native.cpp +++ b/cpp/jni/javet_native.cpp @@ -135,9 +135,20 @@ namespace Javet { jmethodIDV8HostIsLibraryReloadable = jniEnv->GetStaticMethodID(jclassV8Host, "isLibraryReloadable", "()Z"); LOG_INFO("V8::Initialize() begins."); +#ifndef ENABLE_NODE #ifdef ENABLE_I18N - LOG_INFO("Calling v8::V8::InitializeICU()."); - v8::V8::InitializeICU(); + jclass jclassV8RuntimeOptions = jniEnv->FindClass("com/caoccao/javet/interop/options/V8RuntimeOptions"); + jfieldID jfieldIDV8RuntimeOptionsV8Flags = jniEnv->GetStaticFieldID(jclassV8RuntimeOptions, "V8_FLAGS", "Lcom/caoccao/javet/interop/options/V8Flags;"); + jclass jclassV8Flags = jniEnv->FindClass("com/caoccao/javet/interop/options/V8Flags"); + jmethodID jmethodIDV8FlagsGetIcuDataFile = jniEnv->GetMethodID(jclassV8Flags, "getIcuDataFile", "()Ljava/lang/String;"); + jobject mV8Flags = jniEnv->GetStaticObjectField(jclassV8RuntimeOptions, jfieldIDV8RuntimeOptionsV8Flags); + jstring mIcuDataFile = (jstring)jniEnv->CallObjectMethod(mV8Flags, jmethodIDV8FlagsGetIcuDataFile); + auto umIcuDataFile = Javet::Converter::ToStdString(jniEnv, mIcuDataFile); + LOG_INFO("Calling v8::V8::InitializeICU(\"" << *umIcuDataFile << "\")."); + v8::V8::InitializeICU(umIcuDataFile->c_str()); + jniEnv->DeleteLocalRef(mIcuDataFile); + jniEnv->DeleteLocalRef(mV8Flags); +#endif #endif if (Javet::V8Native::GlobalV8Platform) { LOG_INFO("V8::Initialize() is skipped."); @@ -146,7 +157,28 @@ namespace Javet { #ifdef ENABLE_NODE uv_setup_args(0, nullptr); std::vector args{ DEFAULT_SCRIPT_NAME }; - std::unique_ptr result = node::InitializeOncePerProcess( + jclass jclassNodeRuntimeOptions = jniEnv->FindClass("com/caoccao/javet/interop/options/NodeRuntimeOptions"); + jfieldID jfieldIDNodeRuntimeOptionsNodeFlags = jniEnv->GetStaticFieldID(jclassNodeRuntimeOptions, "NODE_FLAGS", "Lcom/caoccao/javet/interop/options/NodeFlags;"); + jclass jclassNodeFlags = jniEnv->FindClass("com/caoccao/javet/interop/options/NodeFlags"); + jmethodID jmethodIDNodeFlagsSeal = jniEnv->GetMethodID(jclassNodeFlags, "seal", "()Lcom/caoccao/javet/interop/options/NodeFlags;"); + jmethodID jmethodIDNodeFlagsToArray = jniEnv->GetMethodID(jclassNodeFlags, "toArray", "()[Ljava/lang/String;"); + jobject mNodeFlags = jniEnv->GetStaticObjectField(jclassNodeRuntimeOptions, jfieldIDNodeRuntimeOptionsNodeFlags); + jobjectArray mNodeFlagsStringArray = (jobjectArray)jniEnv->CallObjectMethod(mNodeFlags, jmethodIDNodeFlagsToArray); + if (mNodeFlagsStringArray != nullptr) { + const int nodeFlagCount = jniEnv->GetArrayLength(mNodeFlagsStringArray); + LOG_DEBUG("Node.js flag count is " << nodeFlagCount); + for (int i = 0; i < nodeFlagCount; ++i) { + jstring mFlagString = (jstring)jniEnv->GetObjectArrayElement(mNodeFlagsStringArray, i); + auto umFlagString = Javet::Converter::ToStdString(jniEnv, mFlagString); + LOG_DEBUG(" " << i << ": " << *umFlagString); + args.push_back(*umFlagString); + jniEnv->DeleteLocalRef(mFlagString); + } + jniEnv->DeleteLocalRef(mNodeFlagsStringArray); + } + jniEnv->DeleteLocalRef(jniEnv->CallObjectMethod(mNodeFlags, jmethodIDNodeFlagsSeal)); + jniEnv->DeleteLocalRef(mNodeFlags); + std::shared_ptr result = node::InitializeOncePerProcess( args, { node::ProcessInitializationFlags::kNoFlags, node::ProcessInitializationFlags::kNoStdioInitialization, @@ -160,7 +192,7 @@ namespace Javet { }); if (result->exit_code() != 0) { LOG_ERROR("Failed to call node::InitializeOncePerProcess()."); - } + } Javet::V8Native::GlobalV8Platform = node::MultiIsolatePlatform::Create(4); #else Javet::V8Native::GlobalV8Platform = v8::platform::NewDefaultPlatform(); @@ -176,7 +208,7 @@ namespace Javet { if (!GlobalV8ArrayBufferAllocator) { GlobalV8ArrayBufferAllocator = std::shared_ptr(); GlobalV8ArrayBufferAllocator.reset(V8ArrayBufferAllocator::NewDefaultAllocator()); - } + } #endif LOG_INFO("V8::Initialize() ends."); } diff --git a/cpp/jni/javet_resource_node.rc b/cpp/jni/javet_resource_node.rc index 32a62983c..f01b39af4 100644 --- a/cpp/jni/javet_resource_node.rc +++ b/cpp/jni/javet_resource_node.rc @@ -61,8 +61,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,1,8,0 - PRODUCTVERSION 3,1,8,0 + FILEVERSION 4,0,0,0 + PRODUCTVERSION 4,0,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -79,12 +79,12 @@ BEGIN BEGIN VALUE "CompanyName", "caoccao.com" VALUE "FileDescription", "caoccao.com" - VALUE "FileVersion", "3.1.8.0" - VALUE "InternalName", "libjavet-node-windows-x86_64.v.3.1.8.dll" + VALUE "FileVersion", "4.0.0.0" + VALUE "InternalName", "libjavet-node-windows-x86_64.v.4.0.0.dll" VALUE "LegalCopyright", "Copyright (c) 2021-2024." - VALUE "OriginalFilename", "libjavet-node-windows-x86_64.v.3.1.8.dll" + VALUE "OriginalFilename", "libjavet-node-windows-x86_64.v.4.0.0.dll" VALUE "ProductName", "Javet Windows" - VALUE "ProductVersion", "3.1.8.0" + VALUE "ProductVersion", "4.0.0.0" END END BLOCK "VarFileInfo" diff --git a/cpp/jni/javet_resource_v8.rc b/cpp/jni/javet_resource_v8.rc index 6f518d9d6..4feeae5a4 100644 --- a/cpp/jni/javet_resource_v8.rc +++ b/cpp/jni/javet_resource_v8.rc @@ -61,8 +61,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,1,8,0 - PRODUCTVERSION 3,1,8,0 + FILEVERSION 4,0,0,0 + PRODUCTVERSION 4,0,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -79,12 +79,12 @@ BEGIN BEGIN VALUE "CompanyName", "caoccao.com" VALUE "FileDescription", "caoccao.com" - VALUE "FileVersion", "3.1.8.0" - VALUE "InternalName", "libjavet-v8-windows-x86_64.v.3.1.8.dll" + VALUE "FileVersion", "4.0.0.0" + VALUE "InternalName", "libjavet-v8-windows-x86_64.v.4.0.0.dll" VALUE "LegalCopyright", "Copyright (c) 2021-2024." - VALUE "OriginalFilename", "libjavet-v8-windows-x86_64.v.3.1.8.dll" + VALUE "OriginalFilename", "libjavet-v8-windows-x86_64.v.4.0.0.dll" VALUE "ProductName", "Javet Windows" - VALUE "ProductVersion", "3.1.8.0" + VALUE "ProductVersion", "4.0.0.0" END END BLOCK "VarFileInfo" diff --git a/cpp/jni/javet_v8_internal.h b/cpp/jni/javet_v8_internal.h index 5a43f357f..5b1aa4a40 100644 --- a/cpp/jni/javet_v8_internal.h +++ b/cpp/jni/javet_v8_internal.h @@ -58,11 +58,6 @@ using V8InternalAllowNullsFlag = v8::internal::AllowNullsFlag; using V8internalBlockingBehavior = v8::internal::BlockingBehavior; using V8InternalBuiltin = v8::internal::Builtin; -#ifdef ENABLE_NODE -using V8InternalContext = v8::internal::Context; -#else -using V8InternalContext = v8::internal::NativeContext; -#endif using V8InternalDisallowCompilation = v8::internal::DisallowCompilation; using V8InternalDisallowGarbageCollection = v8::internal::DisallowGarbageCollection; using V8InternalFlagList = v8::internal::FlagList; @@ -72,6 +67,7 @@ using V8InternalIsolate = v8::internal::Isolate; using V8InternalJSFunction = v8::internal::JSFunction; using V8InternalJSObject = v8::internal::JSObject; using V8InternalModule = v8::internal::Module; +using V8InternalNativeContext = v8::internal::NativeContext; using V8InternalObject = v8::internal::Object; using V8InternalRobustnessFlag = v8::internal::RobustnessFlag; using V8InternalScopeInfo = v8::internal::ScopeInfo; @@ -92,19 +88,11 @@ constexpr auto CONVERT_OFFSET_FOR_SCOPE_INFO(T offset) { } template -constexpr auto HAS_PENDING_EXCEPTION(T v8InternalIsolate) { -#ifdef ENABLE_NODE - return v8InternalIsolate->has_pending_exception(); -#else +constexpr auto HAS_EXCEPTION(T v8InternalIsolate) { return v8InternalIsolate->has_exception(); -#endif } template constexpr auto IS_USER_DEFINED_FUNCTION(T v8InternalShared) { -#ifdef ENABLE_NODE - return !v8InternalShared.native() && !v8InternalShared.IsApiFunction() && v8InternalShared.IsUserJavaScript(); -#else return !v8InternalShared->native() && !v8InternalShared->IsApiFunction() && v8InternalShared->IsUserJavaScript(); -#endif } diff --git a/cpp/jni/javet_v8_runtime.cpp b/cpp/jni/javet_v8_runtime.cpp index aeff20cc7..060eaa636 100644 --- a/cpp/jni/javet_v8_runtime.cpp +++ b/cpp/jni/javet_v8_runtime.cpp @@ -280,15 +280,14 @@ namespace Javet { if (mConsoleArguments != nullptr) { int consoleArgumentCount = jniEnv->GetArrayLength(mConsoleArguments); LOG_DEBUG("Node.js console argument count is " << consoleArgumentCount); - for (int i = 0; i < consoleArgumentCount; ++i) { - jstring mConsoleArgument = (jstring)jniEnv->GetObjectArrayElement(mConsoleArguments, i); - auto consoleArgumentPointer = Javet::Converter::ToStdString(jniEnv, mConsoleArgument); - auto umConsoleArgument = *consoleArgumentPointer.get(); - LOG_DEBUG(" " << i << ": " << umConsoleArgument); - if (umConsoleArgument == "-v" || umConsoleArgument == "--version") { - LOG_DIRECT(NODE_VERSION); + if (consoleArgumentCount > 0) { + for (int i = 0; i < consoleArgumentCount; ++i) { + jstring mConsoleArgument = (jstring)jniEnv->GetObjectArrayElement(mConsoleArguments, i); + auto consoleArgumentPointer = Javet::Converter::ToStdString(jniEnv, mConsoleArgument); + auto umConsoleArgument = consoleArgumentPointer.get(); + LOG_DEBUG(" " << i << ": " << *umConsoleArgument); + args.push_back(*umConsoleArgument); } - args.push_back(umConsoleArgument); } } } @@ -391,11 +390,7 @@ namespace Javet { jobject V8Runtime::SafeToExternalV8Value( JNIEnv* jniEnv, const V8LocalContext& v8Context, -#ifdef ENABLE_NODE - const V8InternalObject& v8InternalObject) noexcept { -#else const v8::internal::Tagged& v8InternalObject) noexcept { -#endif V8TryCatch v8TryCatch(v8Context->GetIsolate()); jobject externalV8Value = Javet::Converter::ToExternalV8Value(jniEnv, this, v8Context, v8InternalObject); if (v8TryCatch.HasCaught()) { @@ -403,12 +398,12 @@ namespace Javet { return Javet::Exceptions::ThrowJavetExecutionException(jniEnv, this, v8Context, v8TryCatch); } return externalV8Value; - } + } jobject V8Runtime::SafeToExternalV8Value( - JNIEnv * jniEnv, - const V8LocalContext & v8Context, - const V8LocalValue & v8Value) noexcept { + JNIEnv* jniEnv, + const V8LocalContext& v8Context, + const V8LocalValue& v8Value) noexcept { V8TryCatch v8TryCatch(v8Context->GetIsolate()); jobject externalV8Value = Javet::Converter::ToExternalV8Value(jniEnv, this, v8Context, v8Value); if (v8TryCatch.HasCaught()) { @@ -422,5 +417,5 @@ namespace Javet { CloseV8Context(); CloseV8Isolate(); } -} + } diff --git a/cpp/jni/javet_v8_runtime.h b/cpp/jni/javet_v8_runtime.h index b13df29af..07f800fb8 100644 --- a/cpp/jni/javet_v8_runtime.h +++ b/cpp/jni/javet_v8_runtime.h @@ -152,11 +152,7 @@ namespace Javet { jobject SafeToExternalV8Value( JNIEnv* jniEnv, const V8LocalContext& v8Context, -#ifdef ENABLE_NODE - const V8InternalObject& v8InternalObject) noexcept; -#else const v8::internal::Tagged& v8InternalObject) noexcept; -#endif jobject SafeToExternalV8Value( JNIEnv* jniEnv, diff --git a/docker/android/base.Dockerfile b/docker/android/base.Dockerfile index fa615f082..7a61c9607 100644 --- a/docker/android/base.Dockerfile +++ b/docker/android/base.Dockerfile @@ -13,9 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Usage: docker build -t sjtucaocao/javet-android:3.1.8 -f docker/android/base.Dockerfile . +# Usage: docker build -t sjtucaocao/javet-android:4.0.0 -f docker/android/base.Dockerfile . -ARG JAVET_V8_VERSION=12.9.202.18 +ARG JAVET_V8_VERSION=13.0.245.16 FROM ubuntu:20.04 WORKDIR / diff --git a/docker/android/build.Dockerfile b/docker/android/build.Dockerfile index 8e88f9337..67191b04e 100644 --- a/docker/android/build.Dockerfile +++ b/docker/android/build.Dockerfile @@ -15,7 +15,7 @@ # Usage: docker build -t javet-android:local -f docker/android/build.Dockerfile . -FROM sjtucaocao/javet-android:3.1.8 +FROM sjtucaocao/javet-android:4.0.0 WORKDIR / # Copy Javet diff --git a/docker/linux-arm64/base_all_in_one.Dockerfile b/docker/linux-arm64/base_all_in_one.Dockerfile index 6c338a487..db995639f 100644 --- a/docker/linux-arm64/base_all_in_one.Dockerfile +++ b/docker/linux-arm64/base_all_in_one.Dockerfile @@ -13,10 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Usage: docker build -t sjtucaocao/javet-arm64:3.1.8 -f docker/linux-arm64/base_all_in_one.Dockerfile . +# Usage: docker build -t sjtucaocao/javet-arm64:4.0.0 -f docker/linux-arm64/base_all_in_one.Dockerfile . ARG JAVET_NODE_VERSION=18.15.0 -ARG JAVET_V8_VERSION=12.9.202.18 +ARG JAVET_V8_VERSION=13.0.245.16 FROM ubuntu:20.04 WORKDIR / diff --git a/docker/linux-arm64/base_gradle.Dockerfile b/docker/linux-arm64/base_gradle.Dockerfile index 842a07067..18563dda5 100644 --- a/docker/linux-arm64/base_gradle.Dockerfile +++ b/docker/linux-arm64/base_gradle.Dockerfile @@ -14,7 +14,7 @@ # limitations under the License. # Usage: docker build \ -# -t sjtucaocao/javet:arm64-3.1.8 \ +# -t sjtucaocao/javet:arm64-4.0.0 \ # --build-arg JAVET_REPO=sjtucaocao/javet \ # -f docker/linux-arm64/base_gradle.Dockerfile . diff --git a/docker/linux-arm64/base_v8.Dockerfile b/docker/linux-arm64/base_v8.Dockerfile index 2ce2848f6..7c11d1a73 100644 --- a/docker/linux-arm64/base_v8.Dockerfile +++ b/docker/linux-arm64/base_v8.Dockerfile @@ -14,13 +14,13 @@ # limitations under the License. # Usage: docker build \ -# -t sjtucaocao/javet:arm64-base-v8_12.9.202.18 \ +# -t sjtucaocao/javet:arm64-base-v8_13.0.245.16 \ # --build-arg JAVET_REPO=sjtucaocao/javet \ -# --build-arg JAVET_V8_VERSION=12.9.202.18 \ +# --build-arg JAVET_V8_VERSION=13.0.245.16 \ # -f docker/linux-arm64/base_v8.Dockerfile . ARG JAVET_REPO=sjtucaocao/javet -ARG JAVET_V8_VERSION=12.9.202.18 +ARG JAVET_V8_VERSION=13.0.245.16 FROM ${JAVET_REPO}:arm64-base-jvm diff --git a/docker/linux-arm64/build_artifact.Dockerfile b/docker/linux-arm64/build_artifact.Dockerfile index 0c63f73a9..c1fc33bf9 100644 --- a/docker/linux-arm64/build_artifact.Dockerfile +++ b/docker/linux-arm64/build_artifact.Dockerfile @@ -18,13 +18,13 @@ # --build-arg JAVET_REPO=sjtucaocao/javet \ # --build-arg JAVET_NODE_VERSION=18.12.1 \ # --build-arg JAVET_V8_VERSION=10.8.168.20 \ -# --build-arg JAVET_VERSION=3.1.8 \ +# --build-arg JAVET_VERSION=4.0.0 \ # -f docker/linux-arm64/build_artifact.Dockerfile . ARG JAVET_REPO=sjtucaocao/javet ARG JAVET_NODE_VERSION=18.12.1 ARG JAVET_V8_VERSION=10.8.168.20 -ARG JAVET_VERSION=3.1.8 +ARG JAVET_VERSION=4.0.0 FROM ${JAVET_REPO}:arm64-base-node_${JAVET_NODE_VERSION} as base-node diff --git a/docker/linux-x86_64/base_all_in_one.Dockerfile b/docker/linux-x86_64/base_all_in_one.Dockerfile index 060fa6650..3492bcde0 100644 --- a/docker/linux-x86_64/base_all_in_one.Dockerfile +++ b/docker/linux-x86_64/base_all_in_one.Dockerfile @@ -13,13 +13,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Usage: docker build -t sjtucaocao/javet:3.1.8 -f docker/linux-x86_64/base_all_in_one.Dockerfile . +# Usage: docker build -t sjtucaocao/javet:4.0.0 -f docker/linux-x86_64/base_all_in_one.Dockerfile . FROM ubuntu:20.04 WORKDIR / -ARG JAVET_NODE_VERSION=20.17.0 -ARG JAVET_V8_VERSION=12.9.202.18 +ARG JAVET_NODE_VERSION=22.9.0 +ARG JAVET_V8_VERSION=13.0.245.16 # Update Ubuntu ENV DEBIAN_FRONTEND=noninteractive diff --git a/docker/linux-x86_64/base_gradle.Dockerfile b/docker/linux-x86_64/base_gradle.Dockerfile index ad4939afc..e5c030fdc 100644 --- a/docker/linux-x86_64/base_gradle.Dockerfile +++ b/docker/linux-x86_64/base_gradle.Dockerfile @@ -14,7 +14,7 @@ # limitations under the License. # Usage: docker build \ -# -t sjtucaocao/javet:x86_64-3.1.8 \ +# -t sjtucaocao/javet:x86_64-4.0.0 \ # --build-arg JAVET_REPO=sjtucaocao/javet \ # -f docker/linux-x86_64/base_gradle.Dockerfile . diff --git a/docker/linux-x86_64/base_node.Dockerfile b/docker/linux-x86_64/base_node.Dockerfile index bca767cf8..e480c31d3 100644 --- a/docker/linux-x86_64/base_node.Dockerfile +++ b/docker/linux-x86_64/base_node.Dockerfile @@ -14,13 +14,13 @@ # limitations under the License. # Usage: docker build \ -# -t sjtucaocao/javet:x86_64-base-node_20.17.0 \ +# -t sjtucaocao/javet:x86_64-base-node_22.9.0 \ # --build-arg JAVET_REPO=sjtucaocao/javet \ -# --build-arg JAVET_NODE_VERSION=20.17.0 \ +# --build-arg JAVET_NODE_VERSION=22.9.0 \ # -f docker/linux-x86_64/base_node.Dockerfile . ARG JAVET_REPO=sjtucaocao/javet -ARG JAVET_NODE_VERSION=20.17.0 +ARG JAVET_NODE_VERSION=22.9.0 FROM ${JAVET_REPO}:x86_64-base-jvm diff --git a/docker/linux-x86_64/base_v8.Dockerfile b/docker/linux-x86_64/base_v8.Dockerfile index 4590d9484..7c8565a63 100644 --- a/docker/linux-x86_64/base_v8.Dockerfile +++ b/docker/linux-x86_64/base_v8.Dockerfile @@ -14,13 +14,13 @@ # limitations under the License. # Usage: docker build \ -# -t sjtucaocao/javet:x86_64-base-v8_12.9.202.18 \ +# -t sjtucaocao/javet:x86_64-base-v8_13.0.245.16 \ # --build-arg JAVET_REPO=sjtucaocao/javet \ -# --build-arg JAVET_V8_VERSION=12.9.202.18 \ +# --build-arg JAVET_V8_VERSION=13.0.245.16 \ # -f docker/linux-x86_64/base_v8.Dockerfile . ARG JAVET_REPO=sjtucaocao/javet -ARG JAVET_V8_VERSION=12.9.202.18 +ARG JAVET_V8_VERSION=13.0.245.16 FROM ${JAVET_REPO}:x86_64-base-jvm diff --git a/docker/linux-x86_64/build.env b/docker/linux-x86_64/build.env index c2dee0970..deaeefdd6 100644 --- a/docker/linux-x86_64/build.env +++ b/docker/linux-x86_64/build.env @@ -1,4 +1,4 @@ JAVET_REPO=sjtucaocao/javet -JAVET_VERSION=3.1.8 -JAVET_V8_VERSION=12.9.202.18 -JAVET_NODE_VERSION=20.17.0 +JAVET_VERSION=4.0.0 +JAVET_V8_VERSION=13.0.245.16 +JAVET_NODE_VERSION=22.9.0 diff --git a/docker/linux-x86_64/build_all_in_one.Dockerfile b/docker/linux-x86_64/build_all_in_one.Dockerfile index 3838e320b..a2bb5e965 100644 --- a/docker/linux-x86_64/build_all_in_one.Dockerfile +++ b/docker/linux-x86_64/build_all_in_one.Dockerfile @@ -15,7 +15,7 @@ # Usage: docker build -t javet:local -f docker/linux-x86_64/build_all_in_one.Dockerfile . -FROM sjtucaocao/javet:3.1.8 +FROM sjtucaocao/javet:4.0.0 WORKDIR / # Copy Javet diff --git a/docker/linux-x86_64/build_artifact.Dockerfile b/docker/linux-x86_64/build_artifact.Dockerfile index 6cc5b5a5f..e786b9889 100644 --- a/docker/linux-x86_64/build_artifact.Dockerfile +++ b/docker/linux-x86_64/build_artifact.Dockerfile @@ -18,13 +18,13 @@ # --build-arg JAVET_REPO=sjtucaocao/javet \ # --build-arg JAVET_NODE_VERSION=18.12.1 \ # --build-arg JAVET_V8_VERSION=10.8.168.20 \ -# --build-arg JAVET_VERSION=3.1.8 \ +# --build-arg JAVET_VERSION=4.0.0 \ # -f docker/linux-x86_64/build_artifact.Dockerfile . ARG JAVET_REPO=sjtucaocao/javet ARG JAVET_NODE_VERSION=18.12.1 ARG JAVET_V8_VERSION=10.8.168.20 -ARG JAVET_VERSION=3.1.8 +ARG JAVET_VERSION=4.0.0 FROM ${JAVET_REPO}:x86_64-base-node_${JAVET_NODE_VERSION} as base-v8 diff --git a/docker/windows-x86_64/base.Dockerfile b/docker/windows-x86_64/base.Dockerfile index a010d3827..aa5c5d8da 100644 --- a/docker/windows-x86_64/base.Dockerfile +++ b/docker/windows-x86_64/base.Dockerfile @@ -29,10 +29,10 @@ # The following dockerfile has been out of date because it still uses # Visual Studio 2019 Community. Please contact the maintainer if you want an upgrade. -# Usage: docker build -t sjtucaocao/javet-windows:3.1.8 -m 4G -f docker/windows-x86_64/base.Dockerfile . +# Usage: docker build -t sjtucaocao/javet-windows:4.0.0 -m 4G -f docker/windows-x86_64/base.Dockerfile . -ARG JAVET_NODE_VERSION=20.17.0 -ARG JAVET_V8_VERSION=12.9.202.18 +ARG JAVET_NODE_VERSION=22.9.0 +ARG JAVET_V8_VERSION=13.0.245.16 # https://hub.docker.com/_/microsoft-windows FROM mcr.microsoft.com/windows:20H2-amd64 diff --git a/docker/windows-x86_64/build.Dockerfile b/docker/windows-x86_64/build.Dockerfile index 0ae85516b..ad5c263f8 100644 --- a/docker/windows-x86_64/build.Dockerfile +++ b/docker/windows-x86_64/build.Dockerfile @@ -15,7 +15,7 @@ # Usage: docker build -t javet:local -f docker/windows-x86_64/build.Dockerfile . -FROM sjtucaocao/javet-windows:3.1.8 +FROM sjtucaocao/javet-windows:4.0.0 SHELL ["cmd", "/S", "/C"] WORKDIR / diff --git a/docs/conf.py b/docs/conf.py index b85404084..c407846d6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,7 +22,7 @@ author = 'Sam Cao' # The full version, including alpha/beta/rc tags -release = '3.1.8' +release = '4.0.0' # -- General configuration --------------------------------------------------- diff --git a/docs/development/build_javet_from_scratch.rst b/docs/development/build_javet_from_scratch.rst index 0a0a1f8ae..9f5f1808c 100644 --- a/docs/development/build_javet_from_scratch.rst +++ b/docs/development/build_javet_from_scratch.rst @@ -189,8 +189,8 @@ Build Node.js on Windows cd %NODE_HOME% vcbuild.bat static without-intl vs2022 -Build Javet -=========== +Build Javet JNI Library +======================= Once Node.js and V8 are ready, please navigate to ``${JAVET_HOME}/cpp``, make sure CMake is accessible and execute corresponding build script. @@ -240,12 +240,13 @@ x86 ``x86/libjavet-v8-android.v.*.*.*.so`` x86_64 ``x86_64/libjavet-v8-android.v.*.*.*.so`` ======= ============================================================================================================== -.. note:: +Build Javet JNI Library with i18n +================================= - * To enable i18n support for V8 mode, please append ``-DENABLE_I18N`` to the command. +To enable i18n support, please append ``-DENABLE_I18N=1`` to the command. -Build Javet -=========== +Build Javet Jar +=============== Build Javet for Linux, Mac OS and Windows ----------------------------------------- diff --git a/docs/faq/troubleshooting/can_i18n_be_supported.rst b/docs/faq/troubleshooting/can_i18n_be_supported.rst index be0af4770..aee43e6b3 100644 --- a/docs/faq/troubleshooting/can_i18n_be_supported.rst +++ b/docs/faq/troubleshooting/can_i18n_be_supported.rst @@ -2,10 +2,4 @@ Can i18n be Supported? ====================== -By default, i18n is not supported for the following reasons. - -* To reduce the library size. -* To avoid embedding huge amount of i18n related files. -* To be able to host multiple Node.js runtimes. (Node.js with i18n only allows one runtime and the attempt on creating the second runtime causes the JVM to crash immediately.) - -It can be enabled for V8 mode in private builds. Please contact the maintainer for details. +Yes, please refer to tutorial :doc:`../../tutorial/advanced/internationalization_i18n`. diff --git a/docs/release_notes/index.rst b/docs/release_notes/index.rst index b683d6213..141ddfc30 100644 --- a/docs/release_notes/index.rst +++ b/docs/release_notes/index.rst @@ -5,7 +5,8 @@ Release Notes =========== ============= ========= ============================= Version Status Node.js V8 =========== ============= ========= ============================= -v3 Mainstream v20 v11.8+ +v4 Mainstream v22 v13.0+ +v3 Mainstream v20 v11.8-v12.9 v2 Maintenance v18 v10.6-v11.7 v1 Maintenance v16 v9.4-v10.5 v0 Maintenance v14 v8.9-v9.4 @@ -19,8 +20,9 @@ v0 Maintenance v14 v8.9-v9.4 .. toctree:: :maxdepth: 1 - release_notes_3_1 + release_notes_4_0 +* :doc:`release_notes_3_1` * :doc:`release_notes_3_0` * :doc:`release_notes_2_2` * :doc:`release_notes_2_1` diff --git a/docs/release_notes/release_notes_4_0.rst b/docs/release_notes/release_notes_4_0.rst new file mode 100644 index 000000000..2967f10c2 --- /dev/null +++ b/docs/release_notes/release_notes_4_0.rst @@ -0,0 +1,17 @@ +=================== +Release Notes 4.0.x +=================== + +4.0.0 +----- + +* Upgraded Node.js to ``v22.9.0`` `(2024-09-17) `_ +* Upgraded V8 to ``v13.0.245.16`` (2024-10-08) +* Added ``NodeI18n``, ``V8I18n`` to ``JSRuntimeType`` +* Added ``getNodeI18nInstance()``, ``getV8I18nInstance()`` to ``V8Host`` +* Renamed ``V8Runtime.hasPendingException()`` to ``V8Runtime.hasException()`` +* Removed ``V8Runtime.hasScheduledException()`` and ``V8Runtime.promoteScheduledException()`` +* Moved ``JavetReflectionObjectFactory`` to ``JavetBuddy`` +* Added ``NodeFlags`` +* Added ``NODE_FLAGS`` to ``NodeRuntimeOptions`` +* Supported ``node:sqlite`` diff --git a/docs/tutorial/advanced/cli_options_in_node_js.rst b/docs/tutorial/advanced/cli_options_in_node_js.rst new file mode 100644 index 000000000..74b9e2f03 --- /dev/null +++ b/docs/tutorial/advanced/cli_options_in_node_js.rst @@ -0,0 +1,92 @@ +====================== +CLI Options in Node.js +====================== + +Node.js comes with a variety of `CLI options `_. These options expose built-in debugging, multiple ways to execute scripts, and other helpful runtime options. + +In this tutorial, we are going to learn how to specify CLI options in Javet. + +In Node.js the CLI options consists of the following: + +* Options - ``NodeFlags`` +* V8 options - ``V8Flags`` +* Arguments - ``NodeRuntimeOptions`` + +.. code-block:: sh + + node [options] [V8 options] [ | -e "script" | -] [--] [arguments] + +Options +======= + +Options are often used to turn on some Node.js specific features. Let's take module ``node:sqlite`` for instance. + +Starting from Node.js v22, sqlite has been a built-in module. However, it is not enabled by default. Let's see how to enable it in Javet. + +Step 1: Set Options +------------------- + +* Execute the following Java code before the first ``NodeRuntime`` is created. + +.. code-block:: java + + NodeRuntimeOptions.NODE_FLAGS.setExperimentalSqlite(true); + +Step 2: Let's Go +---------------- + +* Run the following JavaScript code. + +.. code-block:: js + + const sqlite = require("node:sqlite"); + + const db = new sqlite.DatabaseSync(":memory:"); + db.exec(` + CREATE TABLE data( + key INTEGER PRIMARY KEY, + value TEXT + ) STRICT + `); + const insert = db.prepare("INSERT INTO data (key, value) VALUES (?, ?)"); + insert.run(1, "a"); + insert.run(2, "b"); + const query = db.prepare("SELECT * FROM data ORDER BY key"); + console.log(query.all()); + db.close(); + +* It works! + +.. code-block:: js + + [ + [Object: null prototype] { key: 1, value: 'a' }, + [Object: null prototype] { key: 2, value: 'b' } + ] + (node:18204) ExperimentalWarning: SQLite is an experimental feature and might change at any time + (Use `node --trace-warnings ...` to show where the warning was created) + +.. note:: + + ``NodeRuntimeOptions.NODE_FLAGS`` is a global config that applies to all the Node.js runtimes. Once the first Node.js runtime is initialized, ``NodeRuntimeOptions.NODE_FLAGS`` is sealed and no longer accepts further changes. + +More Options +------------ + +There are more options available in ``NodeFlags``, e.g. ``--allow-fs-read``, ``--allow-fs-write``, ``--no-warnings``. And ``NodeFlags`` also support custom flags. + +Arguments +========= + +The arguments can be set as follows. It can be specified per Node.js runtime creation. + +.. code-block:: java + + NodeRuntimeOptions nodeRuntimeOptions = new NodeRuntimeOptions(); + nodeRuntimeOptions.setConsoleArguments(new String[]{"--abc", "--def"}); + try (NodeRuntime testNodeRuntime = v8Host.createV8Runtime(nodeRuntimeOptions)) { + List consoleArguments = testNodeRuntime.getExecutor("process.argv;").executeObject(); + assertEquals(3, consoleArguments.size()); + assertEquals("--abc", consoleArguments.get(1)); + assertEquals("--def", consoleArguments.get(2)); + } diff --git a/docs/tutorial/advanced/index.rst b/docs/tutorial/advanced/index.rst index ea5d41e35..293192763 100644 --- a/docs/tutorial/advanced/index.rst +++ b/docs/tutorial/advanced/index.rst @@ -11,3 +11,5 @@ Advanced java_and_javascript_interop access_the_whole_jvm expose_json_node_in_v8 + cli_options_in_node_js + internationalization_i18n diff --git a/docs/tutorial/advanced/internationalization_i18n.rst b/docs/tutorial/advanced/internationalization_i18n.rst new file mode 100644 index 000000000..d40b4da5d --- /dev/null +++ b/docs/tutorial/advanced/internationalization_i18n.rst @@ -0,0 +1,73 @@ +=========================== +Internationalization (i18n) +=========================== + +Why isn't i18n Supported by Default? +==================================== + +The default Javet releases don't support i18n for the following reasons. + +* Tens of MBs can be saved. +* Performance is slightly better. +* No additional deployment is required. + +How to Enable i18n? +=================== + +* Download the snapshot builds from `Actions `_. +* Reference the snapshot builds in the project. +* Download and save ``icudt*.dat`` files from somewhere to a local directory. E.g. ``v8/third_party/icu``, ``node/deps/icu-tmp``. +* Set a flag as follows before the first Node.js or V8 runtime is created. + +.. code-block:: java + + // Node.js Mode + NodeRuntimeOptions.NODE_FLAGS.setIcuDataDir("/dir/of/the/icudt*.dat"); + // Note: It must be a directory. + + // V8 Mode + V8RuntimeOptions.V8_FLAGS.setIcuDataFile("/path/of/the/icudt*.dat"); + // Note: It must be a file. + +Let's Go! +========= + +Node.js Mode +------------ + +.. code-block:: java + + File icuDataDir = new File(JavetOSUtils.WORKING_DIRECTORY) + .toPath() + .resolve("../node/deps/icu-tmp") + .normalize() + .toFile(); + NodeRuntimeOptions.NODE_FLAGS.setIcuDataDir(icuDataDir.getAbsolutePath()); + try (NodeRuntime nodeRuntime = V8Host.getNodeI18nInstance().createV8Runtime()) { + System.out.println(nodeRuntime.getExecutor("const a = 123456; a.toLocaleString('en-US');").executeString()); + // 123,456 + System.out.println(nodeRuntime.getExecutor("const us = new Intl.Locale('en-US'); us.language;").executeString()); + // en + System.out.println(nodeRuntime.getExecutor("JSON.stringify(['Z', 'a', 'z', 'ä'].sort(new Intl.Collator('de').compare));").executeString()); + // ["a","ä","z","Z"] + } + +V8 Mode +------- + +.. code-block:: java + + File icuDataFile = new File(JavetOSUtils.WORKING_DIRECTORY) + .toPath() + .resolve("../google/v8/third_party/icu/common/icudtl.dat") + .normalize() + .toFile(); + V8RuntimeOptions.V8_FLAGS.setIcuDataFile(icuDataFile.getAbsolutePath()); + try (V8Runtime v8Runtime = V8Host.getV8I18nInstance().createV8Runtime()) { + System.out.println(v8Runtime.getExecutor("const a = 123456; a.toLocaleString('en-US');").executeString()); + // 123,456 + System.out.println(v8Runtime.getExecutor("const us = new Intl.Locale('en-US'); us.language;").executeString()); + // en + System.out.println(v8Runtime.getExecutor("JSON.stringify(['Z', 'a', 'z', 'ä'].sort(new Intl.Collator('de').compare));").executeString()); + // ["a","ä","z","Z"] + } diff --git a/docs/tutorial/basic/installation.rst b/docs/tutorial/basic/installation.rst index 5c4230855..d98b229f4 100644 --- a/docs/tutorial/basic/installation.rst +++ b/docs/tutorial/basic/installation.rst @@ -16,21 +16,21 @@ Maven com.caoccao.javet javet - 3.1.8 + 4.0.0 com.caoccao.javet javet-linux-arm64 - 3.1.8 + 4.0.0 com.caoccao.javet javet-macos - 3.1.8 + 4.0.0 .. tab:: Complete @@ -38,7 +38,7 @@ Maven .. code-block:: xml - 3.1.8 + 4.0.0 @@ -115,11 +115,11 @@ Gradle Kotlin DSL .. code-block:: kotlin - implementation("com.caoccao.javet:javet:3.1.8") // Linux and Windows (x86_64) - implementation("com.caoccao.javet:javet-linux-arm64:3.1.8") // Linux (arm64) - implementation("com.caoccao.javet:javet-macos:3.1.8") // Mac OS (x86_64 and arm64) - implementation("com.caoccao.javet:javet-android-node:3.1.8") // Android Node (arm, arm64, x86 and x86_64) - implementation("com.caoccao.javet:javet-android-v8:3.1.8") // Android V8 (arm, arm64, x86 and x86_64) + implementation("com.caoccao.javet:javet:4.0.0") // Linux and Windows (x86_64) + implementation("com.caoccao.javet:javet-linux-arm64:4.0.0") // Linux (arm64) + implementation("com.caoccao.javet:javet-macos:4.0.0") // Mac OS (x86_64 and arm64) + implementation("com.caoccao.javet:javet-android-node:4.0.0") // Android Node (arm, arm64, x86 and x86_64) + implementation("com.caoccao.javet:javet-android-v8:4.0.0") // Android V8 (arm, arm64, x86 and x86_64) .. tab:: Complete @@ -130,11 +130,11 @@ Gradle Kotlin DSL val os = OperatingSystem.current() val cpuArch = System.getProperty("os.arch") if (os.isMacOsX) { - implementation("com.caoccao.javet:javet:3.1.8") + implementation("com.caoccao.javet:javet:4.0.0") } else if (os.isLinux && (cpuArch == "aarch64" || cpuArch == "arm64")) { - implementation("com.caoccao.javet:javet-linux-arm64:3.1.8") + implementation("com.caoccao.javet:javet-linux-arm64:4.0.0") } else { - implementation("com.caoccao.javet:javet-macos:3.1.8") + implementation("com.caoccao.javet:javet-macos:4.0.0") } Gradle Groovy DSL @@ -142,11 +142,11 @@ Gradle Groovy DSL .. code-block:: groovy - implementation 'com.caoccao.javet:javet:3.1.8' // Linux and Windows (x86_64) - implementation 'com.caoccao.javet:javet-linux-arm64:3.1.8' // Linux (arm64) - implementation 'com.caoccao.javet:javet-macos:3.1.8' // Mac OS (x86_64 and arm64) - implementation 'com.caoccao.javet:javet-android-node:3.1.8' // Android Node (arm, arm64, x86 and x86_64) - implementation 'com.caoccao.javet:javet-android-v8:3.1.8' // Android V8 (arm, arm64, x86 and x86_64) + implementation 'com.caoccao.javet:javet:4.0.0' // Linux and Windows (x86_64) + implementation 'com.caoccao.javet:javet-linux-arm64:4.0.0' // Linux (arm64) + implementation 'com.caoccao.javet:javet-macos:4.0.0' // Mac OS (x86_64 and arm64) + implementation 'com.caoccao.javet:javet-android-node:4.0.0' // Android Node (arm, arm64, x86 and x86_64) + implementation 'com.caoccao.javet:javet-android-v8:4.0.0' // Android V8 (arm, arm64, x86 and x86_64) OS Compatibility ================ @@ -217,3 +217,8 @@ ABI Javet Version V8 Version 23+ v1.1.0 - v2.1.1 v9.7 - v11.2 24+ v2.1.2+ v11.3+ ==== ================== ==================== + +Internationalization (i18n) +=========================== + +The office builds do not support i18n, but there are snapshot builds supporting i18n. Please refer to :doc:`../advanced/internationalization_i18n` for detail. diff --git a/scripts/node/javet-rebuild/rebuild.cmd b/scripts/node/javet-rebuild/rebuild.cmd index 70d92ecbb..5ba26d763 100644 --- a/scripts/node/javet-rebuild/rebuild.cmd +++ b/scripts/node/javet-rebuild/rebuild.cmd @@ -1,5 +1,5 @@ @echo off -SET NODE_LIB_FILE="..\..\..\..\..\..\build\libs\libjavet-node-windows-x86_64.v.3.1.8.lib" +SET NODE_LIB_FILE="..\..\..\..\..\..\build\libs\libjavet-node-windows-x86_64.v.4.0.0.lib" cd %NODE_MODULE_ROOT% call node-gyp clean call node-gyp configure --module_name=%NODE_MODULE_NAME% --module_path=%NODE_MODULE_PATH% --node_lib_file=%NODE_LIB_FILE% diff --git a/scripts/node/javet-rebuild/rebuild.sh b/scripts/node/javet-rebuild/rebuild.sh index f201e9c37..6f5dec264 100755 --- a/scripts/node/javet-rebuild/rebuild.sh +++ b/scripts/node/javet-rebuild/rebuild.sh @@ -1 +1 @@ -patchelf --add-needed libjavet-node-linux-x86_64.v.3.1.8.so ${NODE_MODULE_FILE} +patchelf --add-needed libjavet-node-linux-x86_64.v.4.0.0.so ${NODE_MODULE_FILE} diff --git a/scripts/node/test-node/test-node-module-sqlite3-sync.js b/scripts/node/test-node/test-node-module-sqlite-sync.js similarity index 62% rename from scripts/node/test-node/test-node-module-sqlite3-sync.js rename to scripts/node/test-node/test-node-module-sqlite-sync.js index 6816b7d5a..cdcef16b8 100644 --- a/scripts/node/test-node/test-node-module-sqlite3-sync.js +++ b/scripts/node/test-node/test-node-module-sqlite-sync.js @@ -17,18 +17,19 @@ "use strict"; -const sqlite3 = require('sqlite3'); +const sqlite = require("node:sqlite"); -const db = new sqlite3.Database(':memory:', (e) => { - if (e) { - return console.error(e.message); - } - console.log('Connected to the in-memory sqlite3 database.'); -}); - -db.close((e) => { - if (e) { - return console.error(e.message); - } - console.log('Closed the database connection.'); -}); +const db = new sqlite.DatabaseSync(":memory:"); +db.exec(` + CREATE TABLE data( + key INTEGER PRIMARY KEY, + value TEXT + ) STRICT +`); +const insert = db.prepare("INSERT INTO data (key, value) VALUES (?, ?)"); +insert.run(1, "a"); +insert.run(2, "b"); +const query = db.prepare("SELECT * FROM data ORDER BY key"); +const result = query.all(); +db.close(); +result; diff --git a/scripts/patches/android/node/trap-handler.h.patch b/scripts/patches/android/node/trap-handler.h.patch index 64ef38bfb..2339fef13 100644 --- a/scripts/patches/android/node/trap-handler.h.patch +++ b/scripts/patches/android/node/trap-handler.h.patch @@ -1,8 +1,8 @@ diff --git a/deps/v8/src/trap-handler/trap-handler.h b/deps/v8/src/trap-handler/trap-handler.h -index 77b0b19aa3..c25b90f27f 100644 +index 4bf95b8c22..90bbb3aa36 100644 --- a/deps/v8/src/trap-handler/trap-handler.h +++ b/deps/v8/src/trap-handler/trap-handler.h -@@ -17,29 +17,7 @@ namespace v8 { +@@ -17,44 +17,7 @@ namespace v8 { namespace internal { namespace trap_handler { @@ -11,8 +11,9 @@ index 77b0b19aa3..c25b90f27f 100644 - ((V8_OS_LINUX && !V8_OS_ANDROID) || V8_OS_WIN || V8_OS_DARWIN || \ - V8_OS_FREEBSD) -#define V8_TRAP_HANDLER_SUPPORTED true --// Arm64 (non-simulator) on Mac. --#elif V8_TARGET_ARCH_ARM64 && V8_HOST_ARCH_ARM64 && V8_OS_DARWIN +-// Arm64 (non-simulator) on Mac and Linux. +-#elif V8_TARGET_ARCH_ARM64 && V8_HOST_ARCH_ARM64 && \ +- (V8_OS_DARWIN || (V8_OS_LINUX && !V8_OS_ANDROID)) -#define V8_TRAP_HANDLER_SUPPORTED true -// Arm64 simulator on x64 on Linux, Mac, or Windows. -// @@ -25,6 +26,20 @@ index 77b0b19aa3..c25b90f27f 100644 - (!defined(_MSC_VER) || defined(__clang__)) -#define V8_TRAP_HANDLER_VIA_SIMULATOR -#define V8_TRAP_HANDLER_SUPPORTED true +-// Loong64 (non-simulator) on Linux. +-#elif V8_TARGET_ARCH_LOONG64 && V8_HOST_ARCH_LOONG64 && V8_OS_LINUX +-#define V8_TRAP_HANDLER_SUPPORTED true +-// Loong64 simulator on x64 on Linux +-#elif V8_TARGET_ARCH_LOONG64 && V8_HOST_ARCH_X64 && V8_OS_LINUX +-#define V8_TRAP_HANDLER_VIA_SIMULATOR +-#define V8_TRAP_HANDLER_SUPPORTED true +-// RISCV64 (non-simulator) on Linux. +-#elif V8_TARGET_ARCH_RISCV64 && V8_HOST_ARCH_RISCV64 && V8_OS_LINUX +-#define V8_TRAP_HANDLER_SUPPORTED true +-// RISCV64 simulator on x64 on Linux +-#elif V8_TARGET_ARCH_RISCV64 && V8_HOST_ARCH_X64 && V8_OS_LINUX +-#define V8_TRAP_HANDLER_VIA_SIMULATOR +-#define V8_TRAP_HANDLER_SUPPORTED true -// Everything else is unsupported. -#else #define V8_TRAP_HANDLER_SUPPORTED false diff --git a/scripts/python/change_javet_version.py b/scripts/python/change_javet_version.py index e64172fac..5f3c55554 100644 --- a/scripts/python/change_javet_version.py +++ b/scripts/python/change_javet_version.py @@ -189,7 +189,7 @@ def _update(self, relative_file_path: str, line_separator: str, *patterns: list) logging.info(' Updated.') def main(): - change_javet_version = ChangeJavetVersion('3.1.8') + change_javet_version = ChangeJavetVersion('4.0.0') change_javet_version.update() return 0 diff --git a/scripts/python/change_node_v8_version.py b/scripts/python/change_node_v8_version.py index c84bd94f3..a1884144a 100644 --- a/scripts/python/change_node_v8_version.py +++ b/scripts/python/change_node_v8_version.py @@ -170,9 +170,9 @@ def update(self) -> None: re.compile(r'"(?P\d+\.\d+\.\d+\.\d+)",')) def main(): - change_node_version = ChangeNodeVersion('20.17.0') + change_node_version = ChangeNodeVersion('22.9.0') change_node_version.update() - change_v8_version = ChangeV8Version('12.9.202.18') + change_v8_version = ChangeV8Version('13.0.245.16') change_v8_version.update() return 0 diff --git a/src/main/java/com/caoccao/javet/enums/JSRuntimeType.java b/src/main/java/com/caoccao/javet/enums/JSRuntimeType.java index d506d6315..ac9916955 100644 --- a/src/main/java/com/caoccao/javet/enums/JSRuntimeType.java +++ b/src/main/java/com/caoccao/javet/enums/JSRuntimeType.java @@ -37,7 +37,19 @@ public enum JSRuntimeType { */ Node( "node", - "11.3.244.8-node.23", // node -p process.versions.v8 + false, + "12.4.254.21-node.19", // node -p process.versions.v8 + NodeRuntimeOptions::new, + o -> o instanceof NodeRuntimeOptions), + /** + * Node.js with i18n. + * + * @since 4.0.0 + */ + NodeI18n( + "node", + true, + "12.4.254.21-node.19", // node -p process.versions.v8 NodeRuntimeOptions::new, o -> o instanceof NodeRuntimeOptions), /** @@ -47,10 +59,23 @@ public enum JSRuntimeType { */ V8( "v8", - "12.9.202.18", + false, + "13.0.245.16", + V8RuntimeOptions::new, + o -> o instanceof V8RuntimeOptions), + /** + * V8 with i18n. + * + * @since 4.0.0 + */ + V8I18n( + "v8", + true, + "13.0.245.16", V8RuntimeOptions::new, o -> o instanceof V8RuntimeOptions); + private final boolean i18nEnabled; private final String name; private final IJavaSupplier> runtimeOptionsConstructor; private final IJavaFunction, Boolean> runtimeOptionsValidator; @@ -58,12 +83,14 @@ public enum JSRuntimeType { JSRuntimeType( String name, + boolean i18nEnabled, String version, IJavaSupplier> runtimeOptionsConstructor, IJavaFunction, Boolean> runtimeOptionsValidator) { this.runtimeOptionsConstructor = Objects.requireNonNull(runtimeOptionsConstructor); this.runtimeOptionsValidator = Objects.requireNonNull(runtimeOptionsValidator); this.name = name; + this.i18nEnabled = i18nEnabled; this.version = version; } @@ -99,6 +126,16 @@ public String getVersion() { return version; } + /** + * Is i18n enabled. + * + * @return true : i18n enabled, false : i18n not enabled + * @since 4.0.0 + */ + public boolean isI18nEnabled() { + return i18nEnabled; + } + /** * Is Node.js mode. * @@ -106,7 +143,7 @@ public String getVersion() { * @since 0.8.0 */ public boolean isNode() { - return this == Node; + return this == Node || this == NodeI18n; } /** @@ -127,7 +164,7 @@ public boolean isRuntimeOptionsValid(RuntimeOptions runtimeOptions) { * @since 0.8.0 */ public boolean isV8() { - return this == V8; + return this == V8 || this == V8I18n; } @Override diff --git a/src/main/java/com/caoccao/javet/interop/IV8Native.java b/src/main/java/com/caoccao/javet/interop/IV8Native.java index cf699bed4..e4e936292 100644 --- a/src/main/java/com/caoccao/javet/interop/IV8Native.java +++ b/src/main/java/com/caoccao/javet/interop/IV8Native.java @@ -144,20 +144,20 @@ boolean functionSetSourceCode( String getVersion(); - boolean hasInternalType(long v8RuntimeHandle, long v8ValueHandle, int internalTypeId); + boolean hasException(long v8RuntimeHandle); - boolean hasPendingException(long v8RuntimeHandle); + boolean hasInternalType(long v8RuntimeHandle, long v8ValueHandle, int internalTypeId); boolean hasPendingMessage(long v8RuntimeHandle); - boolean hasScheduledException(long v8RuntimeHandle); - Object integerObjectCreate(long v8RuntimeHandle, int intValue); Object integerObjectValueOf(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType); boolean isDead(long v8RuntimeHandle); + boolean isI18nEnabled(); + boolean isInUse(long v8RuntimeHandle); boolean isWeak(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType); @@ -338,8 +338,6 @@ Object promiseThen( long v8RuntimeHandle, long v8ValueHandle, int v8ValueType, long v8ValueFunctionFulfilledHandle, long v8ValueFunctionRejectedHandle); - boolean promoteScheduledException(long v8RuntimeHandle); - Object proxyCreate(long v8RuntimeHandle, Object target); Object proxyGetHandler(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType); diff --git a/src/main/java/com/caoccao/javet/interop/NodeRuntime.java b/src/main/java/com/caoccao/javet/interop/NodeRuntime.java index 112a6c354..e5b0bd398 100644 --- a/src/main/java/com/caoccao/javet/interop/NodeRuntime.java +++ b/src/main/java/com/caoccao/javet/interop/NodeRuntime.java @@ -73,11 +73,18 @@ public class NodeRuntime extends V8Runtime { * @param handle the handle * @param pooled the pooled * @param v8Native the V8 native + * @param jsRuntimeType the js runtime type * @param runtimeOptions the runtime options * @since 0.8.0 */ - NodeRuntime(V8Host v8Host, long handle, boolean pooled, IV8Native v8Native, RuntimeOptions runtimeOptions) { - super(v8Host, handle, pooled, v8Native, runtimeOptions); + NodeRuntime( + V8Host v8Host, + long handle, + boolean pooled, + IV8Native v8Native, + JSRuntimeType jsRuntimeType, + RuntimeOptions runtimeOptions) { + super(v8Host, handle, pooled, v8Native, jsRuntimeType, runtimeOptions); nodeModuleMap = new HashMap<>(); } @@ -86,11 +93,6 @@ public byte[] createSnapshot() throws JavetException { throw new JavetException(JavetError.RuntimeCreateSnapshotDisabled); } - @Override - public JSRuntimeType getJSRuntimeType() { - return JSRuntimeType.Node; - } - /** * Gets node module. * diff --git a/src/main/java/com/caoccao/javet/interop/V8Host.java b/src/main/java/com/caoccao/javet/interop/V8Host.java index 4b57cb253..f53bfbe8e 100644 --- a/src/main/java/com/caoccao/javet/interop/V8Host.java +++ b/src/main/java/com/caoccao/javet/interop/V8Host.java @@ -33,10 +33,7 @@ import java.lang.management.MemoryType; import java.time.Duration; import java.time.ZonedDateTime; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.PriorityBlockingQueue; @@ -60,6 +57,7 @@ public final class V8Host { private final V8Notifier v8Notifier; private final ConcurrentHashMap v8RuntimeMap; private final V8StatisticsFutureDaemon v8StatisticsFutureDaemon; + private Optional i18nEnabled; private boolean isolateCreated; private JavetClassLoader javetClassLoader; private JavetException lastException; @@ -77,6 +75,7 @@ private V8Host(JSRuntimeType jsRuntimeType) { v8RuntimeMap = new ConcurrentHashMap<>(); v8Native = null; isolateCreated = false; + i18nEnabled = Optional.empty(); this.jsRuntimeType = jsRuntimeType; v8GuardDaemon = new V8GuardDaemon(); v8StatisticsFutureDaemon = new V8StatisticsFutureDaemon(); @@ -94,10 +93,16 @@ private V8Host(JSRuntimeType jsRuntimeType) { * @since 0.7.0 */ public static V8Host getInstance(JSRuntimeType jsRuntimeType) { - if (Objects.requireNonNull(jsRuntimeType).isNode()) { - return getNodeInstance(); + switch (Objects.requireNonNull(jsRuntimeType)) { + case Node: + return getNodeInstance(); + case NodeI18n: + return getNodeI18nInstance(); + case V8I18n: + return getV8I18nInstance(); + default: + return getV8Instance(); } - return getV8Instance(); } /** @@ -110,6 +115,18 @@ public static double getMemoryUsageThresholdRatio() { return memoryUsageThresholdRatio; } + /** + * Gets Node i18n instance. + *

+ * Note: Node runtime library is loaded by a custom class loader. + * + * @return the Node i18n instance + * @since 4.0.0 + */ + public static V8Host getNodeI18nInstance() { + return NodeI18nInstanceHolder.INSTANCE; + } + /** * Gets Node instance. *

@@ -122,6 +139,18 @@ public static V8Host getNodeInstance() { return NodeInstanceHolder.INSTANCE; } + /** + * Gets V8 i18n instance. + *

+ * Note: V8 runtime library is loaded by a custom class loader. + * + * @return the V8 i18n instance + * @since 4.0.0 + */ + public static V8Host getV8I18nInstance() { + return V8I18nInstanceHolder.INSTANCE; + } + /** * Gets V8 instance. *

@@ -292,9 +321,9 @@ public R createV8Runtime( isolateCreated = true; V8Runtime v8Runtime; if (jsRuntimeType.isNode()) { - v8Runtime = new NodeRuntime(this, handle, pooled, v8Native, runtimeOptions); + v8Runtime = new NodeRuntime(this, handle, pooled, v8Native, jsRuntimeType, runtimeOptions); } else { - v8Runtime = new V8Runtime(this, handle, pooled, v8Native, runtimeOptions); + v8Runtime = new V8Runtime(this, handle, pooled, v8Native, jsRuntimeType, runtimeOptions); } v8Native.registerV8Runtime(handle, v8Runtime); v8RuntimeMap.put(handle, v8Runtime); @@ -426,6 +455,19 @@ public V8SharedMemoryStatistics getV8SharedMemoryStatistics() { return (V8SharedMemoryStatistics) v8Native.getV8SharedMemoryStatistics(); } + /** + * Is i18n enabled. + * + * @return true: yes, false: no + * @since 4.0.0 + */ + public boolean isI18nEnabled() { + if (!i18nEnabled.isPresent()) { + i18nEnabled = Optional.of(v8Native.isI18nEnabled()); + } + return i18nEnabled.get(); + } + /** * Is isolate created. * @@ -530,6 +572,10 @@ public synchronized boolean unloadLibrary() { return !libraryLoaded; } + private static class NodeI18nInstanceHolder { + private static final V8Host INSTANCE = new V8Host(JSRuntimeType.NodeI18n); + } + private static class NodeInstanceHolder { private static final V8Host INSTANCE = new V8Host(JSRuntimeType.Node); } @@ -605,6 +651,10 @@ public void setSleepIntervalMillis(long sleepIntervalMillis) { } } + private static class V8I18nInstanceHolder { + private static final V8Host INSTANCE = new V8Host(JSRuntimeType.V8I18n); + } + private static class V8InstanceHolder { private static final V8Host INSTANCE = new V8Host(JSRuntimeType.V8); } diff --git a/src/main/java/com/caoccao/javet/interop/V8Native.java b/src/main/java/com/caoccao/javet/interop/V8Native.java index eaa4e59ce..5365a4bed 100644 --- a/src/main/java/com/caoccao/javet/interop/V8Native.java +++ b/src/main/java/com/caoccao/javet/interop/V8Native.java @@ -207,17 +207,14 @@ public native boolean functionSetSourceCode( public native String getVersion(); @Override - public native boolean hasInternalType(long v8RuntimeHandle, long v8ValueHandle, int internalTypeId); + public native boolean hasException(long v8RuntimeHandle); @Override - public native boolean hasPendingException(long v8RuntimeHandle); + public native boolean hasInternalType(long v8RuntimeHandle, long v8ValueHandle, int internalTypeId); @Override public native boolean hasPendingMessage(long v8RuntimeHandle); - @Override - public native boolean hasScheduledException(long v8RuntimeHandle); - @Override public native Object integerObjectCreate(long v8RuntimeHandle, int intValue); @@ -227,6 +224,9 @@ public native boolean functionSetSourceCode( @Override public native boolean isDead(long v8RuntimeHandle); + @Override + public native boolean isI18nEnabled(); + @Override public native boolean isInUse(long v8RuntimeHandle); @@ -516,9 +516,6 @@ public native Object promiseThen( long v8RuntimeHandle, long v8ValueHandle, int v8ValueType, long v8ValueFunctionFulfilledHandle, long v8ValueFunctionRejectedHandle); - @Override - public native boolean promoteScheduledException(long v8RuntimeHandle); - @Override public native Object proxyCreate(long v8RuntimeHandle, Object target); diff --git a/src/main/java/com/caoccao/javet/interop/V8Runtime.java b/src/main/java/com/caoccao/javet/interop/V8Runtime.java index 0599c1bbe..d34dee935 100644 --- a/src/main/java/com/caoccao/javet/interop/V8Runtime.java +++ b/src/main/java/com/caoccao/javet/interop/V8Runtime.java @@ -195,6 +195,12 @@ public class V8Runtime implements IJavetClosable, IV8Creatable, IV8Convertible { * @since 1.0.3 */ final List gcPrologueCallbacks; + /** + * The JS runtime type. + * + * @since 4.0.0 + */ + final JSRuntimeType jsRuntimeType; /** * The Primitive flags is for passing the calling succession in JNI calls. * Its length is 1. True: success. False: failure. @@ -342,10 +348,17 @@ public class V8Runtime implements IJavetClosable, IV8Creatable, IV8Convertible { * @param handle the handle * @param pooled the pooled * @param v8Native the V8 native + * @param jsRuntimeType the js runtime type * @param runtimeOptions the runtime options * @since 0.7.0 */ - V8Runtime(V8Host v8Host, long handle, boolean pooled, IV8Native v8Native, RuntimeOptions runtimeOptions) { + V8Runtime( + V8Host v8Host, + long handle, + boolean pooled, + IV8Native v8Native, + JSRuntimeType jsRuntimeType, + RuntimeOptions runtimeOptions) { assert handle != INVALID_HANDLE : ERROR_HANDLE_MUST_BE_VALID; callbackContextLock = new Object(); callbackContextMap = new HashMap<>(); @@ -365,6 +378,7 @@ public class V8Runtime implements IJavetClosable, IV8Creatable, IV8Convertible { this.v8Host = Objects.requireNonNull(v8Host); v8Inspector = null; this.v8Native = Objects.requireNonNull(v8Native); + this.jsRuntimeType = Objects.requireNonNull(jsRuntimeType); v8ModuleLock = new Object(); v8ModuleMap = new HashMap<>(); v8ModuleResolver = null; @@ -1508,7 +1522,7 @@ public long getHandle() { * @since 0.9.1 */ public JSRuntimeType getJSRuntimeType() { - return JSRuntimeType.V8; + return jsRuntimeType; } /** @@ -1719,19 +1733,6 @@ public String getVersion() { return v8Native.getVersion(); } - /** - * Has internal type. - * - * @param iV8ValueObject the V8 value object - * @param internalType the internal type - * @return true : yes, false : no - * @since 0.9.13 - */ - boolean hasInternalType(IV8ValueObject iV8ValueObject, V8ValueInternalType internalType) { - return v8Native.hasInternalType( - handle, iV8ValueObject.getHandle(), Objects.requireNonNull(internalType).getId()); - } - /** * Has pending exception. * @@ -1740,32 +1741,33 @@ boolean hasInternalType(IV8ValueObject iV8ValueObject, V8ValueInternalType inter * @since 1.0.4 */ @SuppressWarnings("RedundantThrows") - public boolean hasPendingException() throws JavetException { - return v8Native.hasPendingException(handle); + public boolean hasException() throws JavetException { + return v8Native.hasException(handle); } /** - * Has pending message. + * Has internal type. * + * @param iV8ValueObject the V8 value object + * @param internalType the internal type * @return true : yes, false : no - * @throws JavetException the javet exception - * @since 1.0.4 + * @since 0.9.13 */ - @SuppressWarnings("RedundantThrows") - public boolean hasPendingMessage() throws JavetException { - return v8Native.hasPendingMessage(handle); + boolean hasInternalType(IV8ValueObject iV8ValueObject, V8ValueInternalType internalType) { + return v8Native.hasInternalType( + handle, iV8ValueObject.getHandle(), Objects.requireNonNull(internalType).getId()); } /** - * Has scheduled exception. + * Has pending message. * * @return true : yes, false : no * @throws JavetException the javet exception * @since 1.0.4 */ @SuppressWarnings("RedundantThrows") - public boolean hasScheduledException() throws JavetException { - return v8Native.hasScheduledException(handle); + public boolean hasPendingMessage() throws JavetException { + return v8Native.hasPendingMessage(handle); } /** @@ -3044,18 +3046,6 @@ T promiseThen( functionRejectedHandle == null ? 0L : functionRejectedHandle.getHandle()); } - /** - * Promote scheduled exception. - * - * @return true : success, false : failure - * @throws JavetException the javet exception - * @since 1.0.4 - */ - @SuppressWarnings("RedundantThrows") - public boolean promoteScheduledException() throws JavetException { - return v8Native.promoteScheduledException(handle); - } - /** * Gets a handler from a proxy * diff --git a/src/main/java/com/caoccao/javet/interop/executors/IV8Executor.java b/src/main/java/com/caoccao/javet/interop/executors/IV8Executor.java index ecc38bc05..6439b7586 100644 --- a/src/main/java/com/caoccao/javet/interop/executors/IV8Executor.java +++ b/src/main/java/com/caoccao/javet/interop/executors/IV8Executor.java @@ -227,6 +227,7 @@ default IV8Executor setResourceName(String resourceName) throws JavetException { nodeRuntime.getGlobalObject().set(NodeRuntime.PROPERTY_DIRNAME, parentFile.getAbsolutePath()); nodeRuntime.getGlobalObject().set(NodeRuntime.PROPERTY_FILENAME, resourceFile.getAbsolutePath()); nodeRuntime.getNodeModule(NodeModuleModule.class).setRequireRootDirectory(parentFile.getAbsoluteFile()); + // If --allow-fs-read or --allow-fs-write is set, this call will fail. nodeRuntime.getNodeModule(NodeModuleProcess.class).setWorkingDirectory(parentFile.getAbsolutePath()); } catch (Throwable t) { v8Runtime.getLogger().logError(t, "Failed to set resource name for Node.js runtime."); diff --git a/src/main/java/com/caoccao/javet/interop/loader/JavetLibLoader.java b/src/main/java/com/caoccao/javet/interop/loader/JavetLibLoader.java index 914b0d77f..2f4d0f4fa 100644 --- a/src/main/java/com/caoccao/javet/interop/loader/JavetLibLoader.java +++ b/src/main/java/com/caoccao/javet/interop/loader/JavetLibLoader.java @@ -45,7 +45,7 @@ public final class JavetLibLoader { * * @since 0.8.0 */ - public static final String LIB_VERSION = "3.1.8"; + public static final String LIB_VERSION = "4.0.0"; private static final String ANDROID_ABI_ARM = "armeabi-v7a"; private static final String ANDROID_ABI_ARM64 = "arm64-v8a"; private static final String ANDROID_ABI_X86 = "x86"; @@ -57,12 +57,13 @@ public final class JavetLibLoader { private static final int BUFFER_LENGTH = 4096; private static final String CHMOD = "chmod"; private static final String DOT = "."; + private static final String I18N_SUFFIX = "-i18n"; private static final String LIB_FILE_EXTENSION_ANDROID = "so"; private static final String LIB_FILE_EXTENSION_LINUX = "so"; private static final String LIB_FILE_EXTENSION_MACOS = "dylib"; private static final String LIB_FILE_EXTENSION_WINDOWS = "dll"; - private static final String LIB_FILE_NAME_FORMAT = "libjavet-{0}-{1}-{2}.v.{3}.{4}"; - private static final String LIB_FILE_NAME_FOR_ANDROID_FORMAT = "libjavet-{0}-{1}.v.{2}.{3}"; + private static final String LIB_FILE_NAME_FORMAT = "libjavet-{0}-{1}-{2}{3}.v.{4}.{5}"; + private static final String LIB_FILE_NAME_FOR_ANDROID_FORMAT = "libjavet-{0}-{1}{2}.v.{3}.{4}"; private static final String LIB_FILE_NAME_PREFIX = "lib"; private static final IJavetLogger LOGGER = new JavetDefaultLogger(JavetLibLoader.class.getName()); private static final long MIN_LAST_MODIFIED_GAP_IN_MILLIS = 60L * 1000L; // 1 minute @@ -202,6 +203,7 @@ public String getLibFileName() throws JavetException { LIB_FILE_NAME_FOR_ANDROID_FORMAT, jsRuntimeType.getName(), osName, + jsRuntimeType.isI18nEnabled() ? I18N_SUFFIX : StringUtils.EMPTY, LIB_VERSION, fileExtension); } else { @@ -216,6 +218,7 @@ public String getLibFileName() throws JavetException { jsRuntimeType.getName(), osName, osArch, + jsRuntimeType.isI18nEnabled() ? I18N_SUFFIX : StringUtils.EMPTY, LIB_VERSION, fileExtension); } diff --git a/src/main/java/com/caoccao/javet/interop/options/NodeFlags.java b/src/main/java/com/caoccao/javet/interop/options/NodeFlags.java new file mode 100644 index 000000000..c6cf52134 --- /dev/null +++ b/src/main/java/com/caoccao/javet/interop/options/NodeFlags.java @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2024. caoccao.com Sam Cao + * + * 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. + */ + +package com.caoccao.javet.interop.options; + +import com.caoccao.javet.utils.ArrayUtils; +import com.caoccao.javet.utils.StringUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; + +/** + * The type Node flags defines some built-in Node command line options. + * The complete command line options are at https://nodejs.org/docs/latest/api/cli.html#options + * + * @since 4.0.0 + */ +public final class NodeFlags { + /** + * The constant ALLOW_FS_READ. + * + * @since 4.0.0 + */ + public static final String ALLOW_FS_READ = "--allow-fs-read"; + /** + * The constant ALLOW_FS_WRITE. + * + * @since 4.0.0 + */ + public static final String ALLOW_FS_WRITE = "--allow-fs-write"; + /** + * The constant EXPERIMENTAL_PERMISSION. + * + * @since 4.0.0 + */ + public static final String EXPERIMENTAL_PERMISSION = "--experimental-permission"; + /** + * The constant EXPERIMENTAL_REQUIRE_MODULE. + * + * @since 4.0.0 + */ + public static final String EXPERIMENTAL_REQUIRE_MODULE = "--experimental-require-module"; + /** + * The constant EXPERIMENTAL_SQLITE. + * + * @since 4.0.0 + */ + public static final String EXPERIMENTAL_SQLITE = "--experimental-sqlite"; + + /** + * The constant ICU_DATA_DIR. + * + * @since 4.0.0 + */ + public static final String ICU_DATA_DIR = "--icu-data-dir"; + /** + * The constant NO_WARNINGS. + * + * @since 4.0.0 + */ + public static final String NO_WARNINGS = "--no-warnings"; + private static final String EQUAL = "="; + private static final String SPACE = " "; + private String[] allowFsRead; + private String[] allowFsWrite; + private String[] customFlags; + private boolean experimentalPermission; + private boolean experimentalRequireModule; + private boolean experimentalSqlite; + private String icuDataDir; + private boolean noWarnings; + private boolean sealed; + + /** + * Instantiates a new Node flags. + * + * @since 4.0.0 + */ + NodeFlags() { + allowFsRead = null; + allowFsWrite = null; + customFlags = null; + experimentalPermission = false; + experimentalRequireModule = false; + experimentalSqlite = false; + noWarnings = false; + sealed = false; + } + + /** + * This flag configures file system read permissions using the Permission Model. + *

+ * The valid arguments for the --allow-fs-read flag are: + *

+ * - To allow all FileSystemRead operations. + * Multiple paths can be allowed using multiple --allow-fs-read flags. + * Example --allow-fs-read=/folder1/ --allow-fs-read=/folder1/ + * + * @return the string[] + * @since 4.0.0 + */ + public String[] getAllowFsRead() { + return allowFsRead; + } + + /** + * This flag configures file system write permissions using the Permission Model. + *

+ * The valid arguments for the --allow-fs-write flag are: + *

+ * - To allow all FileSystemWrite operations. + * Multiple paths can be allowed using multiple --allow-fs-write flags. + * Example --allow-fs-write=/folder1/ --allow-fs-write=/folder1/ + * + * @return the string[] + * @since 4.0.0 + */ + public String[] getAllowFsWrite() { + return allowFsWrite; + } + + /** + * Gets custom flags. + * + * @return the custom flags + * @since 4.0.0 + */ + public String[] getCustomFlags() { + return customFlags; + } + + /** + * Gets icu data dir that contains icudt*.dat files. + * + * @return the icu data dir + * @since 4.0.0 + */ + public String getIcuDataDir() { + return icuDataDir; + } + + /** + * Enable the Permission Model for current process. When enabled, the following permissions are restricted: + *

+ * File System - manageable through --allow-fs-read, --allow-fs-write flags + * Child Process - manageable through --allow-child-process flag + * Worker Threads - manageable through --allow-worker flag + * WASI - manageable through --allow-wasi flag + * + * @return true : yes, false: no + * @since 4.0.0 + */ + public boolean isExperimentalPermission() { + return experimentalPermission; + } + + /** + * Supports loading a synchronous ES module graph in require(). + * + * @return true : yes, false: no + * @since 4.0.0 + */ + public boolean isExperimentalRequireModule() { + return experimentalRequireModule; + } + + /** + * Is the experimental node:sqlite module enabled. + * + * @return true : yes, false: no + * @since 4.0.0 + */ + public boolean isExperimentalSqlite() { + return experimentalSqlite; + } + + /** + * Silence all process warnings (including deprecations). + * + * @return true : yes, false: no + * @since 4.0.0 + */ + public boolean isNoWarnings() { + return noWarnings; + } + + /** + * Is sealed. + * + * @return true : yes, false: no + * @since 4.0.0 + */ + public boolean isSealed() { + return sealed; + } + + /** + * Seal the Node flags so that it is read-only. + * + * @return the self + * @since 4.0.0 + */ + public NodeFlags seal() { + if (!sealed) { + sealed = true; + } + return this; + } + + /** + * Sets allow fs read. + * + * @param allowFsRead the allow fs read + * @return the self + * @since 4.0.0 + */ + public NodeFlags setAllowFsRead(String[] allowFsRead) { + if (!sealed) { + if (ArrayUtils.isEmpty(allowFsRead)) { + this.allowFsRead = null; + } else { + this.allowFsRead = Stream.of(allowFsRead) + .filter(StringUtils::isNotBlank) + .toArray(String[]::new); + this.experimentalPermission = true; + } + } + return this; + } + + /** + * Sets allow fs write. + * + * @param allowFsWrite the allow fs write + * @return the self + * @since 4.0.0 + */ + public NodeFlags setAllowFsWrite(String[] allowFsWrite) { + if (!sealed) { + if (ArrayUtils.isEmpty(allowFsWrite)) { + this.allowFsWrite = null; + } else { + this.allowFsWrite = Stream.of(allowFsWrite) + .filter(StringUtils::isNotBlank) + .toArray(String[]::new); + this.experimentalPermission = true; + } + } + return this; + } + + /** + * Sets custom flags (space separated). + * + * @param customFlags the custom flags + * @return the self + * @since 4.0.0 + */ + public NodeFlags setCustomFlags(String[] customFlags) { + if (!sealed) { + if (ArrayUtils.isEmpty(customFlags)) { + this.customFlags = null; + } else { + this.customFlags = Stream.of(customFlags) + .filter(StringUtils::isNotBlank) + .toArray(String[]::new); + } + } + return this; + } + + /** + * Sets experimental permission. + * + * @param experimentalPermission the experimental permission + * @return the self + * @since 4.0.0 + */ + public NodeFlags setExperimentalPermission(boolean experimentalPermission) { + if (!sealed) { + this.experimentalPermission = experimentalPermission; + } + return this; + } + + /** + * Sets experimental require module. + * + * @param experimentalRequireModule the experimental require module + * @return the self + * @since 4.0.0 + */ + public NodeFlags setExperimentalRequireModule(boolean experimentalRequireModule) { + if (!sealed) { + this.experimentalRequireModule = experimentalRequireModule; + } + return this; + } + + /** + * Sets experimental sqlite. + * + * @param experimentalSqlite the experimental sqlite + * @return the self + * @since 4.0.0 + */ + public NodeFlags setExperimentalSqlite(boolean experimentalSqlite) { + if (!sealed) { + this.experimentalSqlite = experimentalSqlite; + } + return this; + } + + /** + * Sets icu data dir. + * + * @param icuDataDir the icu data dir + * @return the icu data dir + * @since 4.0.0 + */ + public NodeFlags setIcuDataDir(String icuDataDir) { + if (!sealed) { + this.icuDataDir = icuDataDir; + } + return this; + } + + /** + * Sets no warnings. + * + * @param noWarnings the no warnings + * @return the self + * @since 4.0.0 + */ + public NodeFlags setNoWarnings(boolean noWarnings) { + if (!sealed) { + this.noWarnings = noWarnings; + } + return this; + } + + /** + * To string array. + * + * @return the string array + */ + public String[] toArray() { + List tokens = new ArrayList<>(); + if (ArrayUtils.isNotEmpty(allowFsRead)) { + Stream.of(allowFsRead) + .filter(StringUtils::isNotBlank) + .map(path -> ALLOW_FS_READ + EQUAL + path.trim()) + .forEach(tokens::add); + } + if (ArrayUtils.isNotEmpty(allowFsWrite)) { + Stream.of(allowFsWrite) + .filter(StringUtils::isNotBlank) + .map(path -> ALLOW_FS_WRITE + EQUAL + path.trim()) + .forEach(tokens::add); + } + if (experimentalPermission) { + tokens.add(EXPERIMENTAL_PERMISSION); + } + if (experimentalRequireModule) { + tokens.add(EXPERIMENTAL_REQUIRE_MODULE); + } + if (experimentalSqlite) { + tokens.add(EXPERIMENTAL_SQLITE); + } + if (StringUtils.isNotBlank(icuDataDir)) { + tokens.add(ICU_DATA_DIR + EQUAL + icuDataDir.trim()); + } + if (noWarnings) { + tokens.add(NO_WARNINGS); + } + tokens.sort(String::compareTo); + if (ArrayUtils.isNotEmpty(customFlags)) { + Collections.addAll(tokens, customFlags); + } + return tokens.toArray(new String[0]); + } + + @Override + public String toString() { + return StringUtils.join(SPACE, toArray()); + } +} diff --git a/src/main/java/com/caoccao/javet/interop/options/NodeRuntimeOptions.java b/src/main/java/com/caoccao/javet/interop/options/NodeRuntimeOptions.java index 001a6953a..4b79ee694 100644 --- a/src/main/java/com/caoccao/javet/interop/options/NodeRuntimeOptions.java +++ b/src/main/java/com/caoccao/javet/interop/options/NodeRuntimeOptions.java @@ -16,12 +16,23 @@ package com.caoccao.javet.interop.options; +import com.caoccao.javet.utils.ArrayUtils; +import com.caoccao.javet.utils.StringUtils; + +import java.util.stream.Stream; + /** * The type Node runtime options. * * @since 1.0.0 */ public final class NodeRuntimeOptions extends RuntimeOptions { + /** + * The constant NODE_FLAGS. + * + * @since 4.0.0 + */ + public static final NodeFlags NODE_FLAGS = new NodeFlags(); /** * The constant V8_FLAGS. * @@ -58,7 +69,13 @@ public String[] getConsoleArguments() { * @since 1.0.0 */ public NodeRuntimeOptions setConsoleArguments(String[] consoleArguments) { - this.consoleArguments = consoleArguments; + if (ArrayUtils.isEmpty(consoleArguments)) { + this.consoleArguments = null; + } else { + this.consoleArguments = Stream.of(consoleArguments) + .filter(StringUtils::isNotBlank) + .toArray(String[]::new); + } return this; } } diff --git a/src/main/java/com/caoccao/javet/interop/options/V8Flags.java b/src/main/java/com/caoccao/javet/interop/options/V8Flags.java index 80015dd3e..2c71dbbf7 100644 --- a/src/main/java/com/caoccao/javet/interop/options/V8Flags.java +++ b/src/main/java/com/caoccao/javet/interop/options/V8Flags.java @@ -20,7 +20,6 @@ import java.text.MessageFormat; import java.util.ArrayList; -import java.util.Collections; import java.util.List; /** @@ -77,6 +76,7 @@ public final class V8Flags { private String customFlags; private boolean exposeGC; private boolean exposeInspectorScripts; + private String icuDataFile; private int initialHeapSize; private int maxHeapSize; private int maxOldSpaceSize; @@ -93,6 +93,7 @@ public final class V8Flags { customFlags = null; exposeGC = false; exposeInspectorScripts = false; + icuDataFile = null; initialHeapSize = 0; maxHeapSize = 0; maxOldSpaceSize = 0; @@ -114,6 +115,16 @@ public String getCustomFlags() { return customFlags; } + /** + * Gets icu data file. + * + * @return the icu data file + * @since 4.0.0 + */ + public String getIcuDataFile() { + return icuDataFile; + } + /** * Gets initial heap size. * @@ -263,6 +274,20 @@ public V8Flags setExposeInspectorScripts(boolean exposeInspectorScripts) { return this; } + /** + * Sets icu data file. + * + * @param icuDataFile the icu data file + * @return the icu data file + * @since 4.0.0 + */ + public V8Flags setIcuDataFile(String icuDataFile) { + if (!sealed) { + this.icuDataFile = icuDataFile; + } + return this; + } + /** * Sets initial heap size. * @@ -355,7 +380,7 @@ public String toString() { if (useStrict) { tokens.add(FLAG_USE_STRICT); } - Collections.sort(tokens, String::compareTo); + tokens.sort(String::compareTo); if (StringUtils.isNotEmpty(customFlags)) { tokens.add(customFlags); } diff --git a/src/main/java/com/caoccao/javet/utils/StringUtils.java b/src/main/java/com/caoccao/javet/utils/StringUtils.java index bf03342b8..034b6a9a7 100644 --- a/src/main/java/com/caoccao/javet/utils/StringUtils.java +++ b/src/main/java/com/caoccao/javet/utils/StringUtils.java @@ -86,6 +86,17 @@ public static boolean isEmpty(String str) { return str == null || str.isEmpty(); } + /** + * Is not blank. + * + * @param str the str + * @return true : not blank, false : blank + * @since 4.0.0 + */ + public static boolean isNotBlank(String str) { + return !isBlank(str); + } + /** * Is not empty. * diff --git a/src/test/java/com/caoccao/javet/BaseTestJavet.java b/src/test/java/com/caoccao/javet/BaseTestJavet.java index cc15e23a2..81f9a123a 100644 --- a/src/test/java/com/caoccao/javet/BaseTestJavet.java +++ b/src/test/java/com/caoccao/javet/BaseTestJavet.java @@ -17,14 +17,17 @@ package com.caoccao.javet; import com.caoccao.javet.enums.JSRuntimeType; +import com.caoccao.javet.exceptions.JavetException; import com.caoccao.javet.interfaces.IJavetLogger; import com.caoccao.javet.interop.V8Host; import com.caoccao.javet.interop.loader.JavetLibLoader; +import com.caoccao.javet.interop.options.NodeFlags; import com.caoccao.javet.interop.options.NodeRuntimeOptions; import com.caoccao.javet.interop.options.V8Flags; import com.caoccao.javet.interop.options.V8RuntimeOptions; import com.caoccao.javet.utils.JavetDefaultLogger; import com.caoccao.javet.utils.JavetOSUtils; +import com.caoccao.javet.utils.StringUtils; import java.io.File; import java.time.ZonedDateTime; @@ -37,6 +40,11 @@ public abstract class BaseTestJavet { public static final double DELTA = 0.001; public static final long DEFAULT_INTERVAL_IN_MILLISECONDS = 10; + + static { + setIcuData(); + } + protected IJavetLogger logger; protected V8Host v8Host; @@ -48,16 +56,13 @@ public BaseTestJavet(JSRuntimeType jsRuntimeType) { try { logger = new JavetDefaultLogger(getClass().getName()); if (jsRuntimeType == null) { - JavetLibLoader javetLibLoaderNode = new JavetLibLoader(JSRuntimeType.Node); - JavetLibLoader javetLibLoaderV8 = new JavetLibLoader(JSRuntimeType.V8); - String resourceDirPath = new File( - JavetOSUtils.WORKING_DIRECTORY, "src/main/resources").getAbsolutePath(); - File nodeLibFile = new File(resourceDirPath, javetLibLoaderNode.getResourceFileName()); - File v8LibFile = new File(resourceDirPath, javetLibLoaderV8.getResourceFileName()); - if (nodeLibFile.lastModified() > v8LibFile.lastModified()) { - jsRuntimeType = JSRuntimeType.Node; - } else { - jsRuntimeType = JSRuntimeType.V8; + long lastModified = 0; + for (JSRuntimeType type : JSRuntimeType.values()) { + File libFile = getLibFile(type); + if (libFile != null && libFile.exists() && libFile.lastModified() > lastModified) { + lastModified = libFile.lastModified(); + jsRuntimeType = type; + } } } for (V8Flags v8Flags : new V8Flags[]{NodeRuntimeOptions.V8_FLAGS, V8RuntimeOptions.V8_FLAGS}) { @@ -70,19 +75,73 @@ public BaseTestJavet(JSRuntimeType jsRuntimeType) { v8Flags.setUseStrict(true); } } + assertNotNull(jsRuntimeType); + v8Host = V8Host.getInstance(jsRuntimeType); if (jsRuntimeType.isNode()) { - v8Host = V8Host.getNodeInstance(); - assertTrue(NodeRuntimeOptions.V8_FLAGS.isSealed()); + assertTrue(NodeRuntimeOptions.NODE_FLAGS.isSealed()); } else { - v8Host = V8Host.getV8Instance(); assertTrue(V8RuntimeOptions.V8_FLAGS.isSealed()); } assertEquals(jsRuntimeType, v8Host.getJSRuntimeType()); + assertEquals(jsRuntimeType.isI18nEnabled(), v8Host.isI18nEnabled()); } catch (Exception e) { fail(e.getMessage()); } } + public static File getLibFile(JSRuntimeType jsRuntimeType) { + JavetLibLoader javetLibLoader = new JavetLibLoader(jsRuntimeType); + String resourceDirPath = new File( + JavetOSUtils.WORKING_DIRECTORY, "src/main/resources").getAbsolutePath(); + try { + return new File(resourceDirPath, javetLibLoader.getResourceFileName()); + } catch (JavetException e) { + return null; + } + } + + public static void setIcuData() { + if (!V8RuntimeOptions.V8_FLAGS.isSealed()) { + File icuDataFile = new File(JavetOSUtils.WORKING_DIRECTORY) + .toPath() + .resolve("../google/v8/third_party/icu/common/icudtl.dat") + .normalize() + .toFile(); + if (icuDataFile.exists() && icuDataFile.isFile()) { + V8RuntimeOptions.V8_FLAGS.setIcuDataFile(icuDataFile.getAbsolutePath()); + } + } + if (!NodeRuntimeOptions.NODE_FLAGS.isSealed()) { + File icuDataDir = new File(JavetOSUtils.WORKING_DIRECTORY) + .toPath() + .resolve("../node/deps/icu-tmp") + .normalize() + .toFile(); + if (icuDataDir.exists() && icuDataDir.isDirectory()) { + NodeRuntimeOptions.NODE_FLAGS.setIcuDataDir(icuDataDir.getAbsolutePath()); + } + } + } + + public boolean isI18nEnabled() { + if (v8Host.isI18nEnabled()) { + if (v8Host.getJSRuntimeType().isNode()) { + if (StringUtils.isNotBlank(NodeRuntimeOptions.NODE_FLAGS.getIcuDataDir())) { + return true; + } else { + fail(NodeFlags.ICU_DATA_DIR + " is not set."); + } + } else { + if (StringUtils.isNotBlank(V8RuntimeOptions.V8_FLAGS.getIcuDataFile())) { + return true; + } else { + fail("Icu data file is not set."); + } + } + } + return false; + } + public int runAndWait( long timeOutInMilliseconds, long intervalInMilliseconds, diff --git a/src/test/java/com/caoccao/javet/BaseTestJavetRuntime.java b/src/test/java/com/caoccao/javet/BaseTestJavetRuntime.java index 48ef27253..82b09961c 100644 --- a/src/test/java/com/caoccao/javet/BaseTestJavetRuntime.java +++ b/src/test/java/com/caoccao/javet/BaseTestJavetRuntime.java @@ -23,6 +23,7 @@ import org.junit.jupiter.api.BeforeEach; import java.util.Arrays; +import java.util.concurrent.TimeUnit; import static org.junit.jupiter.api.Assertions.*; @@ -91,4 +92,16 @@ protected void resetContext() { fail(e.getMessage()); } } + + protected void runGC() throws InterruptedException { + for (int i = 0; i < 10; i++) { + System.gc(); + System.runFinalization(); + if (v8Runtime.getReferenceCount() == 0) { + break; + } else { + TimeUnit.MILLISECONDS.sleep(50); + } + } + } } diff --git a/src/test/java/com/caoccao/javet/interception/jvm/TestJavetJVMInterceptor.java b/src/test/java/com/caoccao/javet/interception/jvm/TestJavetJVMInterceptor.java index d5615674c..5d8ad702b 100644 --- a/src/test/java/com/caoccao/javet/interception/jvm/TestJavetJVMInterceptor.java +++ b/src/test/java/com/caoccao/javet/interception/jvm/TestJavetJVMInterceptor.java @@ -109,9 +109,6 @@ public void testThread() throws JavetException, InterruptedException { thread.join(); assertEquals(1, v8Runtime.getExecutor("count").executeInteger()); v8Runtime.getExecutor("java = undefined; thread = undefined;").executeVoid(); - System.gc(); - System.runFinalization(); - System.gc(); - System.runFinalization(); + runGC(); } } diff --git a/src/test/java/com/caoccao/javet/interop/TestJavetLibLoader.java b/src/test/java/com/caoccao/javet/interop/TestJavetLibLoader.java index 9e7f990dd..d05880b46 100644 --- a/src/test/java/com/caoccao/javet/interop/TestJavetLibLoader.java +++ b/src/test/java/com/caoccao/javet/interop/TestJavetLibLoader.java @@ -16,6 +16,7 @@ package com.caoccao.javet.interop; +import com.caoccao.javet.BaseTestJavet; import com.caoccao.javet.enums.JSRuntimeType; import com.caoccao.javet.exceptions.JavetError; import com.caoccao.javet.exceptions.JavetException; @@ -24,9 +25,16 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import java.io.File; +import java.util.stream.Stream; + import static org.junit.jupiter.api.Assertions.*; public class TestJavetLibLoader { + static { + BaseTestJavet.setIcuData(); + } + @AfterAll public static void afterAll() { V8Host.setLibraryReloadable(false); @@ -39,8 +47,12 @@ public static void beforeAll() { @Test public void testCustomClassLoader() { - testCustomClassLoader(JSRuntimeType.Node); - testCustomClassLoader(JSRuntimeType.V8); + Stream.of(JSRuntimeType.values()) + .filter(type -> { + File libFile = BaseTestJavet.getLibFile(type); + return libFile != null && libFile.exists(); + }) + .forEach(this::testCustomClassLoader); } protected void testCustomClassLoader(JSRuntimeType jsRuntimeType) { @@ -59,33 +71,40 @@ protected void testCustomClassLoader(JSRuntimeType jsRuntimeType) { } @Test - public void testLoadAndUnload() throws JavetException { + public void testLoadAndUnload() { if (JavetOSUtils.IS_WINDOWS) { - testLoadAndUnload(JSRuntimeType.Node); - testLoadAndUnload(JSRuntimeType.V8); + Stream.of(JSRuntimeType.values()) + .filter(type -> { + File libFile = BaseTestJavet.getLibFile(type); + return libFile != null && libFile.exists(); + }) + .forEach(this::testLoadAndUnload); } } - protected void testLoadAndUnload(JSRuntimeType jsRuntimeType) throws JavetException { - V8Host v8Host = V8Host.getInstance(jsRuntimeType); - assertNotNull(v8Host); - assertTrue(v8Host.isLibraryLoaded()); - try (V8Runtime v8Runtime = v8Host.createV8Runtime()) { - assertEquals(2, v8Runtime.getExecutor("1 + 1").executeInteger()); - } - assertEquals(0, v8Host.getV8RuntimeCount()); - assertTrue(v8Host.unloadLibrary()); - assertFalse(v8Host.isLibraryLoaded()); + protected void testLoadAndUnload(JSRuntimeType jsRuntimeType) { try { - v8Host.createV8Runtime(); + V8Host v8Host = V8Host.getInstance(jsRuntimeType); + assertNotNull(v8Host); + assertTrue(v8Host.isLibraryLoaded()); + try (V8Runtime v8Runtime = v8Host.createV8Runtime()) { + assertEquals(2, v8Runtime.getExecutor("1 + 1").executeInteger()); + } + assertEquals(0, v8Host.getV8RuntimeCount()); + assertTrue(v8Host.unloadLibrary()); + assertFalse(v8Host.isLibraryLoaded()); + try (V8Runtime v8Runtime = v8Host.createV8Runtime()) { + } catch (JavetException e) { + assertEquals(JavetError.LibraryNotLoaded, e.getError()); + } + assertTrue(v8Host.loadLibrary()); + assertTrue(v8Host.isLibraryLoaded()); + try (V8Runtime v8Runtime = v8Host.createV8Runtime()) { + assertEquals(2, v8Runtime.getExecutor("1 + 1").executeInteger()); + } + assertEquals(0, v8Host.getV8RuntimeCount()); } catch (JavetException e) { - assertEquals(JavetError.LibraryNotLoaded, e.getError()); - } - assertTrue(v8Host.loadLibrary()); - assertTrue(v8Host.isLibraryLoaded()); - try (V8Runtime v8Runtime = v8Host.createV8Runtime()) { - assertEquals(2, v8Runtime.getExecutor("1 + 1").executeInteger()); + fail(e); } - assertEquals(0, v8Host.getV8RuntimeCount()); } } diff --git a/src/test/java/com/caoccao/javet/interop/TestNodeRuntime.java b/src/test/java/com/caoccao/javet/interop/TestNodeRuntime.java index 203d18f8c..7ac0cd5be 100644 --- a/src/test/java/com/caoccao/javet/interop/TestNodeRuntime.java +++ b/src/test/java/com/caoccao/javet/interop/TestNodeRuntime.java @@ -19,7 +19,6 @@ import com.caoccao.javet.BaseTestJavet; import com.caoccao.javet.enums.JSRuntimeType; import com.caoccao.javet.enums.V8AwaitMode; -import com.caoccao.javet.exceptions.JavetError; import com.caoccao.javet.exceptions.JavetException; import com.caoccao.javet.interop.converters.JavetProxyConverter; import com.caoccao.javet.interop.options.NodeRuntimeOptions; @@ -33,11 +32,9 @@ import org.junit.jupiter.api.Test; import java.io.File; -import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardOpenOption; import java.text.MessageFormat; +import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.IntStream; @@ -48,7 +45,9 @@ public class TestNodeRuntime extends BaseTestJavet { protected NodeRuntime nodeRuntime; public TestNodeRuntime() { - super(JSRuntimeType.Node); + super(getLibFile(JSRuntimeType.Node) != null && getLibFile(JSRuntimeType.Node).exists() + ? JSRuntimeType.Node + : JSRuntimeType.NodeI18n); } @AfterEach @@ -164,10 +163,13 @@ public void testAwaitRunTillNoMoreTasks() { @Test public void testConsoleArguments() throws JavetException { - NodeRuntimeOptions runtimeOptions = new NodeRuntimeOptions(); - runtimeOptions.setConsoleArguments(new String[]{"--version"}); - try (NodeRuntime testNodeRuntime = v8Host.createV8Runtime(runtimeOptions)) { - assertNotNull(testNodeRuntime); + NodeRuntimeOptions nodeRuntimeOptions = new NodeRuntimeOptions(); + nodeRuntimeOptions.setConsoleArguments(new String[]{"--abc", "--def"}); + try (NodeRuntime testNodeRuntime = v8Host.createV8Runtime(nodeRuntimeOptions)) { + List consoleArguments = testNodeRuntime.getExecutor("process.argv;").executeObject(); + assertEquals(3, consoleArguments.size()); + assertEquals("--abc", consoleArguments.get(1)); + assertEquals("--def", consoleArguments.get(2)); } } @@ -210,7 +212,7 @@ public void testModuleProcess() throws JavetException { Path path4 = nodeModuleProcess.getWorkingDirectory().toPath(); assertNotEquals(path1.toAbsolutePath().toString(), path3.toAbsolutePath().toString()); assertEquals(path1.toAbsolutePath().toString(), path4.toAbsolutePath().toString()); - assertEquals("v20.17.0", nodeModuleProcess.getVersion()); + assertEquals("v22.9.0", nodeModuleProcess.getVersion()); } @Test @@ -241,79 +243,6 @@ public void testSWC() throws JavetException { } } - @Test - public void testSqlite3InRootDirectoryWithDoubleDots() throws JavetException, IOException { - File sqlite3File = getScriptFile("../node_modules/sqlite3/sqlite3.js"); - if (sqlite3File.exists()) { - File scriptFile = getScriptFile("test-node-module-sqlite3-sync.js"); - File testModuleModeFile = getScriptFile("../test-module-mode.js"); - try { - if (testModuleModeFile.exists()) { - assertTrue(testModuleModeFile.delete()); - } - Files.write( - testModuleModeFile.toPath(), - Files.readAllBytes(scriptFile.toPath()), - StandardOpenOption.CREATE); - // It should pass in module mode. - try { - nodeRuntime.getExecutor(testModuleModeFile).executeVoid(); - } catch (Throwable t) { - t.printStackTrace(System.err); - fail(MessageFormat.format( - "{0} should pass in module mode.", - testModuleModeFile.getAbsolutePath())); - } - } finally { - assertTrue(testModuleModeFile.delete()); - } - } - } - - @Test - public void testSqlite3InRootDirectoryWithoutDoubleDots() throws JavetException, IOException { - File sqlite3File = getScriptFile("../node_modules/sqlite3/sqlite3.js"); - if (sqlite3File.exists()) { - File scriptFile = getScriptFile("test-node-module-sqlite3-sync.js"); - File testModuleModeFile = new File(JavetOSUtils.WORKING_DIRECTORY, "scripts/node/test-module-mode.js"); - try { - if (testModuleModeFile.exists()) { - assertTrue(testModuleModeFile.delete()); - } - Files.write( - testModuleModeFile.toPath(), - Files.readAllBytes(scriptFile.toPath()), - StandardOpenOption.CREATE); - // It should fail in module mode. - try { - nodeRuntime.getExecutor(testModuleModeFile).executeVoid(); - fail(MessageFormat.format( - "{0} should fail in module mode.", - testModuleModeFile.getAbsolutePath())); - } catch (JavetException e) { - assertEquals(JavetError.ExecutionFailure, e.getError()); - assertTrue(e.getMessage().startsWith("Error: Cannot find module 'sqlite3'")); - } - } finally { - assertTrue(testModuleModeFile.delete()); - } - } - } - - @Test - public void testSqlite3InSubDirectory() throws JavetException { - File sqlite3File = getScriptFile("../node_modules/sqlite3/sqlite3.js"); - if (sqlite3File.exists()) { - File scriptFile = getScriptFile("test-node-module-sqlite3-sync.js"); - try { - nodeRuntime.getExecutor(scriptFile).executeVoid(); - } catch (Throwable t) { - t.printStackTrace(System.err); - fail(MessageFormat.format("{0} should pass.", scriptFile.getAbsolutePath())); - } - } - } - @Test public void testStopping() throws JavetException { IntStream.range(0, 5).forEach(i -> assertFalse(nodeRuntime.isStopping())); diff --git a/src/test/java/com/caoccao/javet/interop/TestV8Host.java b/src/test/java/com/caoccao/javet/interop/TestV8Host.java index 4046a13f9..694c487fa 100644 --- a/src/test/java/com/caoccao/javet/interop/TestV8Host.java +++ b/src/test/java/com/caoccao/javet/interop/TestV8Host.java @@ -22,20 +22,27 @@ import com.caoccao.javet.interop.options.V8RuntimeOptions; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.File; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; public class TestV8Host extends BaseTestJavet { @Test - public void testBothNodeAndV8() throws JavetException { - try (V8Runtime v8Runtime = V8Host.getNodeInstance().createV8Runtime()) { - assertNotNull(v8Runtime); - assertTrue(v8Runtime.getJSRuntimeType().isNode()); - } - try (V8Runtime v8Runtime = V8Host.getV8Instance().createV8Runtime()) { - assertNotNull(v8Runtime); - assertTrue(v8Runtime.getJSRuntimeType().isV8()); - } + public void testAllRuntimes() { + Stream.of(JSRuntimeType.values()) + .filter(type -> { + File libFile = BaseTestJavet.getLibFile(type); + return libFile != null && libFile.exists(); + }) + .forEach(type -> { + try (V8Runtime v8Runtime = V8Host.getInstance(type).createV8Runtime()) { + assertNotNull(v8Runtime); + assertEquals(type, v8Runtime.getJSRuntimeType()); + } catch (JavetException e) { + fail(e); + } + }); } @Test diff --git a/src/test/java/com/caoccao/javet/interop/TestV8Native.java b/src/test/java/com/caoccao/javet/interop/TestV8Native.java index a9ded912f..9cf2849f7 100644 --- a/src/test/java/com/caoccao/javet/interop/TestV8Native.java +++ b/src/test/java/com/caoccao/javet/interop/TestV8Native.java @@ -20,8 +20,9 @@ import com.caoccao.javet.enums.JSRuntimeType; import org.junit.jupiter.api.Test; -import java.util.Arrays; +import java.io.File; import java.util.Objects; +import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -36,16 +37,21 @@ public TestV8Native() { @Test public void testGetVersion() { - assertEquals(JSRuntimeType.Node.getVersion(), V8Host.getNodeInstance().getV8Native().getVersion()); - assertEquals(JSRuntimeType.V8.getVersion(), V8Host.getV8Instance().getV8Native().getVersion()); - Arrays.stream(JSRuntimeType.values()).forEach(jsRuntimeType -> assertEquals( - jsRuntimeType.getVersion(), - Objects.requireNonNull(V8Host.getInstance(jsRuntimeType)).getV8Native().getVersion())); + Stream.of(JSRuntimeType.values()) + .filter(type -> { + File libFile = BaseTestJavet.getLibFile(type); + return libFile != null && libFile.exists(); + }) + .forEach(type -> + assertEquals( + type.getVersion(), + Objects.requireNonNull(V8Host.getInstance(type)).getV8Native().getVersion()) + ); } @Test public void testLockAndUnlock() { - final long handle = v8Native.createV8Runtime(JSRuntimeType.V8.getRuntimeOptions()); + final long handle = v8Native.createV8Runtime(v8Host.getJSRuntimeType().getRuntimeOptions()); try { final int iterations = 3; for (int i = 0; i < iterations; ++i) { diff --git a/src/test/java/com/caoccao/javet/interop/TestV8Runtime.java b/src/test/java/com/caoccao/javet/interop/TestV8Runtime.java index b9748ad2d..3303d8d95 100644 --- a/src/test/java/com/caoccao/javet/interop/TestV8Runtime.java +++ b/src/test/java/com/caoccao/javet/interop/TestV8Runtime.java @@ -162,10 +162,8 @@ public void testOutOfMemoryException() throws JavetException { @Test public void testPending() throws JavetException { try (V8Runtime v8Runtime = v8Host.createV8Runtime()) { - assertFalse(v8Runtime.hasPendingException()); + assertFalse(v8Runtime.hasException()); assertFalse(v8Runtime.hasPendingMessage()); - assertFalse(v8Runtime.hasScheduledException()); - assertFalse(v8Runtime.promoteScheduledException()); assertFalse(v8Runtime.reportPendingMessages()); } } diff --git a/src/test/java/com/caoccao/javet/interop/converters/TestJavetBridgeConverter.java b/src/test/java/com/caoccao/javet/interop/converters/TestJavetBridgeConverter.java index 44e3e7b9b..08ef79619 100644 --- a/src/test/java/com/caoccao/javet/interop/converters/TestJavetBridgeConverter.java +++ b/src/test/java/com/caoccao/javet/interop/converters/TestJavetBridgeConverter.java @@ -72,7 +72,11 @@ public void testBigInteger() throws JavetException { // valueOf() assertEquals(bigInteger, v8Runtime.getExecutor("l.valueOf()").executeBigInteger()); // toLocaleString() - assertEquals("36893488147419103232", v8Runtime.getExecutor("l.toLocaleString()").executeString()); + if (isI18nEnabled()) { + assertEquals("36,893,488,147,419,103,232", v8Runtime.getExecutor("l.toLocaleString('en-US')").executeString()); + } else { + assertEquals("36893488147419103232", v8Runtime.getExecutor("l.toLocaleString('en-US')").executeString()); + } // Symbol.toPrimitive assertEquals(bigInteger, v8Runtime.getExecutor("l[Symbol.toPrimitive]()").executeBigInteger()); // + @@ -132,7 +136,7 @@ public void testDouble() throws JavetException { // toFixed() assertEquals("1.2300", v8Runtime.getExecutor("d.toFixed(4)").executeString()); // toLocaleString() - assertEquals("1.23", v8Runtime.getExecutor("d.toLocaleString()").executeString()); + assertEquals("1.23", v8Runtime.getExecutor("d.toLocaleString('en-US')").executeString()); // toPrecision() assertEquals("1.2300", v8Runtime.getExecutor("d.toPrecision(5)").executeString()); // Symbol.toPrimitive @@ -184,7 +188,11 @@ public void testInteger() throws JavetException { // toFixed() assertEquals("12345.00", v8Runtime.getExecutor("i.toFixed(2)").executeString()); // toLocaleString() - assertEquals("12345", v8Runtime.getExecutor("i.toLocaleString()").executeString()); + if (isI18nEnabled()) { + assertEquals("12,345", v8Runtime.getExecutor("i.toLocaleString('en-US')").executeString()); + } else { + assertEquals("12345", v8Runtime.getExecutor("i.toLocaleString('en-US')").executeString()); + } // toPrecision() assertEquals("1.23e+4", v8Runtime.getExecutor("i.toPrecision(3)").executeString()); // Symbol.toPrimitive @@ -252,7 +260,11 @@ public void testLong() throws JavetException { // valueOf() assertEquals(12345L, v8Runtime.getExecutor("l.valueOf()").executeLong()); // toLocaleString() - assertEquals("12345", v8Runtime.getExecutor("l.toLocaleString()").executeString()); + if (isI18nEnabled()) { + assertEquals("12,345", v8Runtime.getExecutor("l.toLocaleString('en-US')").executeString()); + } else { + assertEquals("12345", v8Runtime.getExecutor("l.toLocaleString('en-US')").executeString()); + } // Symbol.toPrimitive assertEquals(12345L, v8Runtime.getExecutor("l[Symbol.toPrimitive]()").executeLong()); // + @@ -368,8 +380,12 @@ public void testString() throws JavetException { // lastIndexOf() assertEquals(1, v8Runtime.getExecutor("s.lastIndexOf('e')").executeInteger()); // localeCompare() - assertEquals(0, v8Runtime.getExecutor("s.localeCompare('test')").executeInteger()); - assertEquals(-132, v8Runtime.getExecutor("s.localeCompare('tést')").executeInteger()); + assertEquals(0, v8Runtime.getExecutor("s.localeCompare('test', 'en-US')").executeInteger()); + if (isI18nEnabled()) { + assertEquals(-1, v8Runtime.getExecutor("s.localeCompare('tést', 'en-US')").executeInteger()); + } else { + assertEquals(-132, v8Runtime.getExecutor("s.localeCompare('tést', 'en-US')").executeInteger()); + } // match() assertTrue(v8Runtime.getExecutor("s.match(/^t/)").executeBoolean()); assertFalse(v8Runtime.getExecutor("s.match(/123/)").executeBoolean()); diff --git a/src/test/java/com/caoccao/javet/interop/converters/TestJavetProxyConverter.java b/src/test/java/com/caoccao/javet/interop/converters/TestJavetProxyConverter.java index 77b5be0b2..4db0c5558 100644 --- a/src/test/java/com/caoccao/javet/interop/converters/TestJavetProxyConverter.java +++ b/src/test/java/com/caoccao/javet/interop/converters/TestJavetProxyConverter.java @@ -1330,7 +1330,7 @@ public void testList() throws JavetException { } @Test - public void testListOfStrings() throws JavetException { + public void testListOfStrings() throws JavetException, InterruptedException { v8Runtime.getGlobalObject().set("a", anonymous); String codeStringWithCast = "a.expectListOfStrings({\n" + " get: (index) => index == 0? 'a': null,\n" + @@ -1340,10 +1340,7 @@ public void testListOfStrings() throws JavetException { String codeStringWithoutCast = "a.expectListOfStrings(['a', null]);"; v8Runtime.getExecutor(codeStringWithoutCast).executeVoid(); v8Runtime.getGlobalObject().delete("a"); - System.gc(); - System.runFinalization(); - System.gc(); - System.runFinalization(); + runGC(); } @Test diff --git a/src/test/java/com/caoccao/javet/interop/options/TestI18n.java b/src/test/java/com/caoccao/javet/interop/options/TestI18n.java new file mode 100644 index 000000000..695a3ae42 --- /dev/null +++ b/src/test/java/com/caoccao/javet/interop/options/TestI18n.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024. caoccao.com Sam Cao + * + * 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. + */ + +package com.caoccao.javet.interop.options; + +import com.caoccao.javet.BaseTestJavetRuntime; +import com.caoccao.javet.exceptions.JavetException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TestI18n extends BaseTestJavetRuntime { + @Test + public void testToLocalString() throws JavetException { + if (isI18nEnabled()) { + assertEquals( + "123,456,789", + v8Runtime.getExecutor("let a = 123456789; a.toLocaleString('en-US');").executeString()); + assertEquals( + "2/2/2000, 3:04:05 AM", + v8Runtime.getExecutor("a = new Date(Date.UTC(2000, 1, 2, 3, 4, 5)); a.toLocaleString('en-US', { timeZone: 'UTC' });").executeString()); + } else { + assertEquals( + "123456789", + v8Runtime.getExecutor("let a = 123456789; a.toLocaleString('en-US');").executeString()); + } + } +} diff --git a/src/test/java/com/caoccao/javet/interop/options/TestNodeFlags.java b/src/test/java/com/caoccao/javet/interop/options/TestNodeFlags.java new file mode 100644 index 000000000..ccf7f5489 --- /dev/null +++ b/src/test/java/com/caoccao/javet/interop/options/TestNodeFlags.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2024. caoccao.com Sam Cao + * + * 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. + */ + +package com.caoccao.javet.interop.options; + +import com.caoccao.javet.utils.SimpleList; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.*; + +public class TestNodeFlags { + protected static final List SWITCHES = SimpleList.of( + new GetterAndSetter(NodeFlags::isExperimentalRequireModule, NodeFlags::setExperimentalRequireModule), + new GetterAndSetter(NodeFlags::isExperimentalSqlite, NodeFlags::setExperimentalSqlite), + new GetterAndSetter(NodeFlags::isNoWarnings, NodeFlags::setNoWarnings) + ); + + @Test + public void testSeal() { + final NodeFlags nodeFlags = new NodeFlags(); + // Open + assertFalse(nodeFlags.isSealed()); + SWITCHES.forEach(getterAndSetter -> { + assertFalse(getterAndSetter.getter.apply(nodeFlags)); + assertTrue(getterAndSetter.getter.apply(getterAndSetter.setter.apply(nodeFlags, true))); + }); + assertFalse(nodeFlags.isExperimentalPermission()); + assertNull(nodeFlags.getAllowFsRead()); + assertArrayEquals(new String[]{"/a", "/b"}, nodeFlags.setAllowFsRead(new String[]{"/a", "/b"}).getAllowFsRead()); + assertTrue(nodeFlags.isExperimentalPermission()); + assertFalse(nodeFlags.setExperimentalPermission(false).isExperimentalPermission()); + assertNull(nodeFlags.getAllowFsWrite()); + assertArrayEquals(new String[]{"/a", "/b"}, nodeFlags.setAllowFsWrite(new String[]{"/a", "/b"}).getAllowFsWrite()); + assertTrue(nodeFlags.isExperimentalPermission()); + assertNull(nodeFlags.getCustomFlags()); + assertNull(nodeFlags.getIcuDataDir()); + assertEquals("abc", nodeFlags.setIcuDataDir("abc").getIcuDataDir()); + assertArrayEquals(new String[]{"abc", "def"}, nodeFlags.setCustomFlags(new String[]{"abc", "def"}).getCustomFlags()); + // Sealed + assertTrue(nodeFlags.seal().isSealed()); + assertNotNull(nodeFlags.setAllowFsRead(null).getAllowFsRead()); + assertArrayEquals(new String[]{"abc", "def"}, nodeFlags.setCustomFlags(new String[]{"123", "456"}).getCustomFlags()); + assertEquals("abc", nodeFlags.setIcuDataDir("def").getIcuDataDir()); + SWITCHES.forEach(getterAndSetter -> { + assertTrue(getterAndSetter.getter.apply(getterAndSetter.setter.apply(nodeFlags, false))); + }); + } + + @Test + public void testToString() { + NodeFlags nodeFlags = new NodeFlags(); + assertEquals( + "--experimental-sqlite", + nodeFlags.setExperimentalSqlite(true).toString()); + assertEquals( + "--allow-fs-read=/a --allow-fs-read=/b --experimental-permission --experimental-sqlite", + nodeFlags.setAllowFsRead(new String[]{"/a", "/b"}).toString()); + nodeFlags.setAllowFsRead(null).setExperimentalSqlite(false); + assertEquals( + "--allow-fs-write=/a --allow-fs-write=/b --experimental-permission", + nodeFlags.setAllowFsWrite(new String[]{"/a", "/b"}).toString()); + nodeFlags.setAllowFsWrite(null).setExperimentalPermission(false); + assertEquals("--no-warnings", nodeFlags.setNoWarnings(true).toString()); + nodeFlags.setNoWarnings(false); + assertEquals( + "--experimental-require-module", + nodeFlags.setExperimentalRequireModule(true).toString()); + nodeFlags.setExperimentalRequireModule(false); + assertEquals("--icu-data-dir=abc", nodeFlags.setIcuDataDir("abc").toString()); + nodeFlags.setIcuDataDir(null); + } + + protected static class GetterAndSetter { + public Function getter; + public BiFunction setter; + + public GetterAndSetter(Function getter, BiFunction setter) { + this.getter = getter; + this.setter = setter; + } + } +} diff --git a/src/test/java/com/caoccao/javet/interop/options/TestNodeRuntimeOptions.java b/src/test/java/com/caoccao/javet/interop/options/TestNodeRuntimeOptions.java new file mode 100644 index 000000000..2a2e7aaa8 --- /dev/null +++ b/src/test/java/com/caoccao/javet/interop/options/TestNodeRuntimeOptions.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024. caoccao.com Sam Cao + * + * 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. + */ + +package com.caoccao.javet.interop.options; + +import com.caoccao.javet.exceptions.JavetException; +import com.caoccao.javet.interop.NodeRuntime; +import com.caoccao.javet.interop.V8Host; +import com.caoccao.javet.utils.JavetOSUtils; +import com.caoccao.javet.utils.SimpleMap; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +public class TestNodeRuntimeOptions { + protected static boolean testEnabled = false; + + @BeforeAll + public static void beforeAll() { + if (!NodeRuntimeOptions.NODE_FLAGS.isSealed()) { + NodeRuntimeOptions.NODE_FLAGS + .setAllowFsRead(new String[]{"/a", "/b"}) + .setExperimentalSqlite(true) + .seal(); + testEnabled = true; + } + } + + protected File getScriptFile(String relativePath) { + return new File(JavetOSUtils.WORKING_DIRECTORY) + .toPath() + .resolve("scripts/node/test-node") + .resolve(relativePath) + .toFile(); + } + + @Test + public void testExperimentalSqlite() throws JavetException { + if (testEnabled) { + try (NodeRuntime nodeRuntime = V8Host.getNodeInstance().createV8Runtime()) { + File scriptFile = getScriptFile("test-node-module-sqlite-sync.js"); + List> result = null; + try { + result = nodeRuntime.getExecutor(scriptFile).executeObject(); + } catch (Throwable t) { + t.printStackTrace(System.err); + fail("The sqlite test should pass."); + } + assertEquals(2, result.size()); + assertEquals(SimpleMap.of("key", 1, "value", "a"), result.get(0)); + assertEquals(SimpleMap.of("key", 2, "value", "b"), result.get(1)); + } + } + } +} diff --git a/src/test/java/com/caoccao/javet/tutorial/TestI18nInNode.java b/src/test/java/com/caoccao/javet/tutorial/TestI18nInNode.java new file mode 100644 index 000000000..45c5febc1 --- /dev/null +++ b/src/test/java/com/caoccao/javet/tutorial/TestI18nInNode.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024. caoccao.com Sam Cao + * + * 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. + */ + +package com.caoccao.javet.tutorial; + +import com.caoccao.javet.exceptions.JavetException; +import com.caoccao.javet.interop.NodeRuntime; +import com.caoccao.javet.interop.V8Host; +import com.caoccao.javet.interop.options.NodeRuntimeOptions; +import com.caoccao.javet.utils.JavetOSUtils; + +import java.io.File; + +public class TestI18nInNode { + public static void main(String[] args) throws JavetException { + File icuDataDir = new File(JavetOSUtils.WORKING_DIRECTORY) + .toPath() + .resolve("../node/deps/icu-tmp") + .normalize() + .toFile(); + NodeRuntimeOptions.NODE_FLAGS.setIcuDataDir(icuDataDir.getAbsolutePath()); + try (NodeRuntime nodeRuntime = V8Host.getNodeI18nInstance().createV8Runtime()) { + System.out.println(nodeRuntime.getExecutor("const a = 123456; a.toLocaleString('en-US');").executeString()); + // 123,456 + System.out.println(nodeRuntime.getExecutor("const us = new Intl.Locale('en-US'); us.language;").executeString()); + // en + System.out.println(nodeRuntime.getExecutor("JSON.stringify(['Z', 'a', 'z', 'ä'].sort(new Intl.Collator('de').compare));").executeString()); + // ["a","ä","z","Z"] + } + } +} diff --git a/src/test/java/com/caoccao/javet/tutorial/TestI18nInV8.java b/src/test/java/com/caoccao/javet/tutorial/TestI18nInV8.java new file mode 100644 index 000000000..cdf88b0d4 --- /dev/null +++ b/src/test/java/com/caoccao/javet/tutorial/TestI18nInV8.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024. caoccao.com Sam Cao + * + * 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. + */ + +package com.caoccao.javet.tutorial; + +import com.caoccao.javet.exceptions.JavetException; +import com.caoccao.javet.interop.V8Host; +import com.caoccao.javet.interop.V8Runtime; +import com.caoccao.javet.interop.options.V8RuntimeOptions; +import com.caoccao.javet.utils.JavetOSUtils; + +import java.io.File; + +public class TestI18nInV8 { + public static void main(String[] args) throws JavetException { + File icuDataFile = new File(JavetOSUtils.WORKING_DIRECTORY) + .toPath() + .resolve("../google/v8/third_party/icu/common/icudtl.dat") + .normalize() + .toFile(); + V8RuntimeOptions.V8_FLAGS.setIcuDataFile(icuDataFile.getAbsolutePath()); + try (V8Runtime v8Runtime = V8Host.getV8I18nInstance().createV8Runtime()) { + System.out.println(v8Runtime.getExecutor("const a = 123456; a.toLocaleString('en-US');").executeString()); + // 123,456 + System.out.println(v8Runtime.getExecutor("const us = new Intl.Locale('en-US'); us.language;").executeString()); + // en + System.out.println(v8Runtime.getExecutor("JSON.stringify(['Z', 'a', 'z', 'ä'].sort(new Intl.Collator('de').compare));").executeString()); + // ["a","ä","z","Z"] + } + } +} diff --git a/src/test/java/com/caoccao/javet/values/reference/TestV8ValueFunction.java b/src/test/java/com/caoccao/javet/values/reference/TestV8ValueFunction.java index 32a4dba2f..9690d00a8 100644 --- a/src/test/java/com/caoccao/javet/values/reference/TestV8ValueFunction.java +++ b/src/test/java/com/caoccao/javet/values/reference/TestV8ValueFunction.java @@ -1655,14 +1655,14 @@ public void testGetScopeInfosWith1Closure() throws JavetException { assertEquals(3, scopeInfos.size()); assertTrue(scopeInfos.hasVariablesInClosure()); IV8ValueFunction.ScopeInfo scopeInfo2 = scopeInfos.get(2); - List keys = scopeInfo2.getScopeObject().getOwnPropertyNameStrings(); + Set keys = new HashSet<>(scopeInfo2.getScopeObject().getOwnPropertyNameStrings()); if (v8Runtime.getJSRuntimeType().isNode()) { - Set globalVariables = SimpleSet.of(( - "global,queueMicrotask,clearImmediate,setImmediate," + - "structuredClone,clearInterval,clearTimeout,setInterval," + - "setTimeout,atob,btoa,crypto,performance,fetch,require").split(",")); - assertEquals(globalVariables.size(), keys.size()); - keys.forEach(key -> assertTrue(globalVariables.contains(key), key + " is not found")); + Set globalVariables = SimpleSet.of( + "global", "clearImmediate", "setImmediate", "clearInterval", "clearTimeout", + "setInterval", "setTimeout", "queueMicrotask", "structuredClone", "atob", + "btoa", "performance", "fetch", "navigator", "crypto", + "require"); + assertEquals(globalVariables, keys); } else { assertEquals(0, keys.size()); }