From aacf18e2153ec823ef7807b00c38cb48fd8f939e Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Thu, 3 Oct 2024 15:49:30 +0200 Subject: [PATCH 1/9] Add test to build on macos using v8 from brew Change GitHub actions to include more and more detailed tests Rename other workflow targets to better explain the differences between the runs Add more php versions to default build test to ensure complete range is tested Add macos to self-built tests Make artifact names unique per step Extract v8 cache building to run less often to reduce computation costs Ensure to use right architecture on built-target Speed up v8 fetch --- .github/workflows/build-test.yml | 168 +++++++++++++++++++++++++------ 1 file changed, 138 insertions(+), 30 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index e60dcfee..42f1eccb 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -12,22 +12,17 @@ permissions: contents: read jobs: - build: + self-built-v8-cache-warmup: strategy: # set in accordance with number of v8-versions, so caching can kick in properly max-parallel: 2 matrix: - operating-system: + operating-system: # &self-built-v8-operating-systems - ubuntu-latest # - windows-latest -# - macos-latest - php-versions: -# - '8.1' -# - '8.2' - - '8.3' - - '8.4' - v8-versions: + - macos-latest + v8-versions: # &self-built-v8-v8-versions - 10.9.194 # - 11.9.172 - 12.9.203 @@ -36,14 +31,10 @@ jobs: runs-on: ${{ matrix.operating-system }} steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-versions }} - coverage: none + - name: Prepare cache folder v8 ${{ matrix.v8-versions }} + run: | + sudo mkdir -p /opt/v8/self-built/{lib,include} + sudo chown -R $(id -u):$(id -g) /opt/v8/self-built - name: Restore cache v8 ${{ matrix.v8-versions }} build id: v8-build-cache @@ -57,29 +48,57 @@ jobs: if: steps.v8-build-cache.outputs.cache-hit != 'true' uses: newkdev/setup-depot-tools@v1.0.1 + - name: Set up Clang + if: ${{ matrix.operating-system == 'ubuntu-latest' }} + run: | + sudo apt update + sudo apt install -y clang-19 lld-19 + sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-19 100 + sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-19 100 + - name: Build v8 ${{ matrix.v8-versions }} if: steps.v8-build-cache.outputs.cache-hit != 'true' run: | # Store extra tools somewhere undisturbing + set -x cd "$(mktemp -d)" - fetch v8 + ARCH=$(uname -m) + if [[ "$ARCH" == "x86_64" ]]; then + V8CONFIG="x64.release" + ARCH_SHORT="x64" + elif [[ "$ARCH" == "arm64" ]]; then + V8CONFIG="arm64.release" + ARCH_SHORT="arm64" + else + echo "Unknown architecture: $ARCH" >&2 + exit 1 + fi + fetch --nohooks --no-history v8 cd v8 - - git checkout ${{ matrix.v8-versions }} - gclient sync -D + git fetch --tag origin refs/tags/${{ matrix.v8-versions }} 1>&2 > /dev/null + git checkout ${{ matrix.v8-versions }} 1>&2 > /dev/null + gclient sync -D 1>&2 > /dev/null # Setup GN # Warnings are no errors - @see https://issues.chromium.org/issues/42203398#comment9 - tools/dev/v8gen.py -vv x64.release -- is_component_build=true use_custom_libcxx=false treat_warnings_as_errors=false + if [[ "${{ runner.os }}" == "macOS" ]]; then + # Run gn gen with args as v8gen does not override target_cpu properly + gn gen out.gn/$V8CONFIG --args='target_cpu="'$ARCH_SHORT'" v8_target_cpu="'$ARCH_SHORT'" is_component_build=true use_custom_libcxx=true treat_warnings_as_errors=false' + else + tools/dev/v8gen.py -vv $V8CONFIG -- is_component_build=true use_custom_libcxx=true treat_warnings_as_errors=false + fi # Build - ninja -C out.gn/x64.release/ + ninja -C out.gn/$V8CONFIG/ - # Install to /opt/v8/self-built - sudo mkdir -p /opt/v8/self-built/{lib,include} - sudo cp out.gn/x64.release/lib*.so out.gn/x64.release/*_blob.bin out.gn/x64.release/icudtl.dat /opt/v8/self-built/lib/ - sudo cp -R include/* /opt/v8/self-built/include/ + if [[ "${{ runner.os }}" == "macOS" ]]; then + LIB_EXT=dylib + else + LIB_EXT=so + fi + cp out.gn/$V8CONFIG/lib*.${LIB_EXT} out.gn/$V8CONFIG/*_blob.bin out.gn/$V8CONFIG/icudtl.dat /opt/v8/self-built/lib/ + cp -R include/* /opt/v8/self-built/include/ # Go back to origin cd "${GITHUB_WORKSPACE}" @@ -91,6 +110,52 @@ jobs: path: /opt/v8/self-built key: ${{ steps.v8-build-cache.outputs.cache-primary-key }} + self-built-v8: + needs: self-built-v8-cache-warmup + + strategy: + matrix: + operating-system: # *self-built-v8-operating-systems + - ubuntu-latest +# - windows-latest + - macos-latest + v8-versions: # *self-built-v8-v8-versions + - 10.9.194 +# - 11.9.172 + - 12.9.203 +# - 13.1.104 + php-versions: +# - '8.1' + - '8.2' + - '8.3' + - '8.4' + + runs-on: ${{ matrix.operating-system }} + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + coverage: none + + - name: Set up Clang + if: ${{ matrix.operating-system == 'ubuntu-latest' }} + run: | + sudo apt update + sudo apt install -y clang-19 lld-19 + sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-19 100 + sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-19 100 + + - name: Download cache v8 ${{ matrix.v8-versions }} build + uses: actions/cache/restore@v4 + with: + path: /opt/v8/self-built + key: ${{ runner.os }}-${{ matrix.v8-versions }}-v8-build + - name: Build extension run: | phpize @@ -102,12 +167,12 @@ jobs: if: failure() uses: actions/upload-artifact@v4 with: - name: phpt-test-results + name: phpt-test-results-on-${{ runner.os }}-${{ matrix.v8-versions }}-${{ matrix.php-versions }} path: | php_test_results*.txt tests/*.out - alpine: + alpine-package-manager-apk: runs-on: ubuntu-latest steps: @@ -135,7 +200,50 @@ jobs: if: failure() uses: actions/upload-artifact@v4 with: - name: phpt-test-results + name: phpt-test-results-on-alpine + path: | + php_test_results*.txt + tests/*.out + + macos-package-manager-brew: + strategy: + matrix: + php-versions: + - '8.2' + - '8.3' + - '8.4' + + runs-on: macos-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + coverage: none + + - name: Set up Homebrew + uses: Homebrew/actions/setup-homebrew@master + + - name: Install dependencies + run: | + brew install v8 + + - name: Build extension + run: | + phpize + ./configure --with-v8js=/opt/homebrew CPPFLAGS="-DV8_COMPRESS_POINTERS -DV8_ENABLE_SANDBOX" + make + make test + + - name: Archive test results + if: failure() + uses: actions/upload-artifact@v4 + with: + name: phpt-test-results-on-macos-brew-${{ matrix.php-versions }} path: | php_test_results*.txt tests/*.out From 78645a8bc182ce31590e2cc52181669a0460282f Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Thu, 3 Oct 2024 15:49:40 +0200 Subject: [PATCH 2/9] Amend setup hints in README --- README.MacOS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.MacOS.md b/README.MacOS.md index 9a11c82a..2ee44059 100644 --- a/README.MacOS.md +++ b/README.MacOS.md @@ -16,7 +16,7 @@ cd /tmp git clone https://github.com/phpv8/v8js.git cd v8js phpize -./configure --with-v8js=/opt/homebrew CPPFLAGS="-DV8_COMPRESS_POINTERS" +./configure --with-v8js=/opt/homebrew CPPFLAGS="-DV8_COMPRESS_POINTERS -DV8_ENABLE_SANDBOX" make -j4 make test make install From d53df2b471a2cffbd86ec32703ff71e7982d7ff4 Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Sat, 10 May 2025 03:35:09 +0200 Subject: [PATCH 3/9] Fix timezone issues --- .github/workflows/build-test.yml | 2 ++ README.Linux.md | 10 ++++++---- README.MacOS.md | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 42f1eccb..4802e4ad 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -231,6 +231,8 @@ jobs: - name: Install dependencies run: | brew install v8 + # Symlink icudtl.dat to the default location + ln -sf /opt/homebrew/Cellar/v8/$(brew list --versions v8 | awk '{print $2}')/libexec/icudtl.dat /opt/homebrew/lib/icudtl.dat - name: Build extension run: | diff --git a/README.Linux.md b/README.Linux.md index 6bc69625..d45ce147 100644 --- a/README.Linux.md +++ b/README.Linux.md @@ -96,16 +96,18 @@ cd v8 git checkout 12.0.267.36 gclient sync -D +ARCH=$(uname -m) + # Setup GN -tools/dev/v8gen.py -vv x64.release -- is_component_build=true use_custom_libcxx=false +tools/dev/v8gen.py -vv ${ARCH}.release -- is_component_build=true use_custom_libcxx=false # Build -ninja -C out.gn/x64.release/ +ninja -C out.gn/${ARCH}.release/ # Install to /opt/v8/ sudo mkdir -p /opt/v8/{lib,include} -sudo cp out.gn/x64.release/lib*.so out.gn/x64.release/*_blob.bin \ - out.gn/x64.release/icudtl.dat /opt/v8/lib/ +sudo cp out.gn/${ARCH}.release/lib*.so out.gn/${ARCH}.release/*_blob.bin \ + out.gn/${ARCH}.release/icudtl.dat /opt/v8/lib/ sudo cp -R include/* /opt/v8/include/ ``` diff --git a/README.MacOS.md b/README.MacOS.md index 2ee44059..098ff2fd 100644 --- a/README.MacOS.md +++ b/README.MacOS.md @@ -21,3 +21,19 @@ make -j4 make test make install ``` + +V8Js' build system assumes that the `icudtl.dat` file is located next to the `libv8.so` +library file and compiles the path into the library itself. If for whatever reason the +`icudtl.dat` file is stored at a different place during runtime, you need to set the +php.ini variable `v8js.icudtl_dat_path` to point to the file. Otherwise locale-aware +features of V8 will not work as expected. + +To avoid having to configure `v8js.icudtl_dat_path` manually, you can symlink or copy the ICU data file into the default library location. For Homebrew users, run: + +In case of a brew installed v8, run: + +``` +ln -sf /opt/homebrew/Cellar/v8/$(brew list --versions v8 | awk '{print $2}')/libexec/icudtl.dat /opt/homebrew/lib/icudtl.dat +``` + +This ensures V8Js will find `icudtl.dat` automatically and timezone/i18n support will work out of the box. From 70c4b13287bd82cd79b6badc0c460320d0e98aab Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Sat, 10 May 2025 03:35:26 +0200 Subject: [PATCH 4/9] Improve timelimit test to always take up 2 seconds time --- tests/time_limit.phpt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/time_limit.phpt b/tests/time_limit.phpt index 7d5dc994..60e9b73a 100644 --- a/tests/time_limit.phpt +++ b/tests/time_limit.phpt @@ -12,8 +12,12 @@ if (getenv("SKIP_SLOW_TESTS")) { 2000) { // 2 seconds safety valve + break; + } var encoded = encodeURI(text); } EOT; From 252bc6ab46ae9a5edb88963e40f22ac649edcf9c Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Sat, 10 May 2025 03:35:36 +0200 Subject: [PATCH 5/9] Amend gclient usage in linux readme --- README.Linux.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.Linux.md b/README.Linux.md index d45ce147..37f6c2f1 100644 --- a/README.Linux.md +++ b/README.Linux.md @@ -89,10 +89,12 @@ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git export PATH=`pwd`/depot_tools:"$PATH" # Download v8 -fetch v8 +fetch --nohooks --no-history v8 +gclient sync -D --no-history cd v8 # (optional) If you'd like to build a certain version: +git fetch --tag origin refs/tags/12.0.267.36 git checkout 12.0.267.36 gclient sync -D From e2b14ce35f58527f2b0a01b540353c715ce535bd Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Sat, 10 May 2025 03:54:52 +0200 Subject: [PATCH 6/9] Add support for v8 v13 See https://github.com/v8/v8/commit/8c53487b1bc411e8d319acdd1eaa065c5b089efe --- .github/workflows/build-test.yml | 4 +- v8js_array_access.cc | 52 ++++++++++++++++++++++---- v8js_object_export.cc | 64 ++++++++++++++++++++++++++++---- 3 files changed, 103 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 4802e4ad..a4556d18 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -26,7 +26,7 @@ jobs: - 10.9.194 # - 11.9.172 - 12.9.203 -# - 13.1.104 + - 13.5.212 runs-on: ${{ matrix.operating-system }} @@ -123,7 +123,7 @@ jobs: - 10.9.194 # - 11.9.172 - 12.9.203 -# - 13.1.104 + - 13.5.212 php-versions: # - '8.1' - '8.2' diff --git a/v8js_array_access.cc b/v8js_array_access.cc index 36752136..e6c0e0d2 100644 --- a/v8js_array_access.cc +++ b/v8js_array_access.cc @@ -59,7 +59,12 @@ static zval v8js_array_access_dispatch(zend_object *object, const char *method_n V8JS_INTERCEPTED v8js_array_access_getter(uint32_t index, const v8::PropertyCallbackInfo& info) /* {{{ */ { v8::Isolate *isolate = info.GetIsolate(); - v8::Local self = info.Holder(); + v8::Local self; + #if PHP_V8_API_VERSION >= 13000000 + self = info.This(); + #else + self = info.Holder(); + #endif zend_object *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); @@ -83,7 +88,12 @@ V8JS_INTERCEPTED v8js_array_access_setter(uint32_t index, v8::Local v const V8JS_SETTER_PROPERTY_CALLBACK_INFO &info) /* {{{ */ { v8::Isolate *isolate = info.GetIsolate(); - v8::Local self = info.Holder(); + v8::Local self; + #if PHP_V8_API_VERSION >= 13000000 + self = info.This(); + #else + self = info.Holder(); + #endif zend_object *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); @@ -157,7 +167,12 @@ static bool v8js_array_access_isset_p(zend_object *object, int index) /* {{{ */ static void v8js_array_access_length(v8::Local property, const v8::PropertyCallbackInfo& info) /* {{{ */ { v8::Isolate *isolate = info.GetIsolate(); - v8::Local self = info.Holder(); + v8::Local self; + #if PHP_V8_API_VERSION >= 13000000 + self = info.This(); + #else + self = info.Holder(); + #endif zend_object *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); @@ -169,7 +184,12 @@ static void v8js_array_access_length(v8::Local property, const v8::P V8JS_INTERCEPTED v8js_array_access_deleter(uint32_t index, const v8::PropertyCallbackInfo& info) /* {{{ */ { v8::Isolate *isolate = info.GetIsolate(); - v8::Local self = info.Holder(); + v8::Local self; + #if PHP_V8_API_VERSION >= 13000000 + self = info.This(); + #else + self = info.Holder(); + #endif zend_object *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); @@ -187,7 +207,12 @@ V8JS_INTERCEPTED v8js_array_access_deleter(uint32_t index, const v8::PropertyCal V8JS_INTERCEPTED v8js_array_access_query(uint32_t index, const v8::PropertyCallbackInfo& info) /* {{{ */ { v8::Isolate *isolate = info.GetIsolate(); - v8::Local self = info.Holder(); + v8::Local self; + #if PHP_V8_API_VERSION >= 13000000 + self = info.This(); + #else + self = info.Holder(); + #endif zend_object *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); @@ -206,7 +231,13 @@ V8JS_INTERCEPTED v8js_array_access_query(uint32_t index, const v8::PropertyCallb void v8js_array_access_enumerator(const v8::PropertyCallbackInfo& info) /* {{{ */ { v8::Isolate *isolate = info.GetIsolate(); - v8::Local self = info.Holder(); + v8::Local self; + + #if PHP_V8_API_VERSION >= 13000000 + self = info.This(); + #else + self = info.Holder(); + #endif zend_object *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); @@ -240,7 +271,14 @@ V8JS_INTERCEPTED v8js_array_access_named_getter(v8::Local property_nam return V8JS_INTERCEPTED_YES; } - v8::Local ret_value = v8js_named_property_callback(info.GetIsolate(), info.Holder(), property, V8JS_PROP_GETTER); + v8::Local holder; + #if PHP_V8_API_VERSION >= 13000000 + holder = info.This(); + #else + holder = info.Holder(); + #endif + + v8::Local ret_value = v8js_named_property_callback(info.GetIsolate(), holder, property, V8JS_PROP_GETTER); if(ret_value.IsEmpty()) { v8::Local arr = v8::Array::New(isolate); diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 8027d380..46163b90 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -212,7 +212,11 @@ static void v8js_call_php_func(zend_object *object, zend_function *method_ptr, c return_value = v8js_propagate_exception(ctx); } else if (Z_TYPE(retval) == IS_OBJECT && Z_OBJ(retval) == object) { // special case: "return $this" + #if PHP_V8_API_VERSION >= 13000000 + return_value = info.This(); + #else return_value = info.Holder(); + #endif } else { return_value = zval_to_v8js(&retval, isolate); } @@ -227,7 +231,12 @@ static void v8js_call_php_func(zend_object *object, zend_function *method_ptr, c /* Callback for PHP methods and functions */ void v8js_php_callback(const v8::FunctionCallbackInfo& info) /* {{{ */ { - v8::Local self = info.Holder(); + v8::Local self; + #if PHP_V8_API_VERSION >= 13000000 + self = info.This(); + #else + self = info.Holder(); + #endif zend_object *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); zend_function *method_ptr; @@ -364,7 +373,12 @@ static void v8js_named_property_enumerator(const v8::PropertyCallbackInfo v8_context = isolate->GetEnteredOrMicrotaskContext(); - v8::Local self = info.Holder(); + v8::Local self; + #if PHP_V8_API_VERSION >= 13000000 + self = info.This(); + #else + self = info.Holder(); + #endif v8::Local result = v8::Array::New(isolate, 0); uint32_t result_len = 0; @@ -466,7 +480,12 @@ static void v8js_invoke_callback(const v8::FunctionCallbackInfo& info v8::Isolate *isolate = info.GetIsolate(); v8::Local v8_context = isolate->GetEnteredOrMicrotaskContext(); - v8::Local self = info.Holder(); + v8::Local self; + #if PHP_V8_API_VERSION >= 13000000 + self = info.This(); + #else + self = info.Holder(); + #endif v8::Local cb = v8::Local::Cast(info.Data()); int argc = info.Length(), i; v8::Local *argv = static_cast *>(alloca(sizeof(v8::Local) * argc)); @@ -511,7 +530,12 @@ static void v8js_fake_call_impl(const v8::FunctionCallbackInfo& info) v8::Isolate *isolate = info.GetIsolate(); v8::Local v8_context = isolate->GetEnteredOrMicrotaskContext(); - v8::Local self = info.Holder(); + v8::Local self; + #if PHP_V8_API_VERSION >= 13000000 + self = info.This(); + #else + self = info.Holder(); + #endif v8::Local return_value = V8JS_NULL; char *error; @@ -859,7 +883,13 @@ v8::Local v8js_named_property_callback(v8::Isolate *isolate, v8::Loca static V8JS_INTERCEPTED v8js_named_property_getter(v8::Local property, const v8::PropertyCallbackInfo &info) /* {{{ */ { - v8::Local r = v8js_named_property_callback(info.GetIsolate(), info.Holder(), property, V8JS_PROP_GETTER); + v8::Local self; + #if PHP_V8_API_VERSION >= 13000000 + self = info.This(); + #else + self = info.Holder(); + #endif + v8::Local r = v8js_named_property_callback(info.GetIsolate(), self, property, V8JS_PROP_GETTER); if (r.IsEmpty()) { return V8JS_INTERCEPTED_NO; @@ -872,7 +902,13 @@ static V8JS_INTERCEPTED v8js_named_property_getter(v8::Local property, static V8JS_INTERCEPTED v8js_named_property_setter(v8::Local property, v8::Local value, const V8JS_SETTER_PROPERTY_CALLBACK_INFO &info) /* {{{ */ { - v8::Local r = v8js_named_property_callback(info.GetIsolate(), info.Holder(), property, V8JS_PROP_SETTER, value); + v8::Local self; + #if PHP_V8_API_VERSION >= 13000000 + self = info.This(); + #else + self = info.Holder(); + #endif + v8::Local r = v8js_named_property_callback(info.GetIsolate(), self, property, V8JS_PROP_SETTER, value); #if PHP_V8_HAS_INTERCEPTED return r.IsEmpty() ? v8::Intercepted::kNo : v8::Intercepted::kYes; #else @@ -883,7 +919,13 @@ static V8JS_INTERCEPTED v8js_named_property_setter(v8::Local property, static V8JS_INTERCEPTED v8js_named_property_query(v8::Local property, const v8::PropertyCallbackInfo &info) /* {{{ */ { - v8::Local r = v8js_named_property_callback(info.GetIsolate(), info.Holder(), property, V8JS_PROP_QUERY); + v8::Local self; + #if PHP_V8_API_VERSION >= 13000000 + self = info.This(); + #else + self = info.Holder(); + #endif + v8::Local r = v8js_named_property_callback(info.GetIsolate(), self, property, V8JS_PROP_QUERY); if (r.IsEmpty()) { return V8JS_INTERCEPTED_NO; } @@ -901,7 +943,13 @@ static V8JS_INTERCEPTED v8js_named_property_query(v8::Local property, static V8JS_INTERCEPTED v8js_named_property_deleter(v8::Local property, const v8::PropertyCallbackInfo &info) /* {{{ */ { - v8::Local r = v8js_named_property_callback(info.GetIsolate(), info.Holder(), property, V8JS_PROP_DELETER); + v8::Local self; + #if PHP_V8_API_VERSION >= 13000000 + self = info.This(); + #else + self = info.Holder(); + #endif + v8::Local r = v8js_named_property_callback(info.GetIsolate(), self, property, V8JS_PROP_DELETER); if (r.IsEmpty()) { return V8JS_INTERCEPTED_NO; } From 2b0a386dcedade502f5dc438a0f38e140207e90a Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Sat, 10 May 2025 17:30:14 +0200 Subject: [PATCH 7/9] Improve memory test --- tests/set_memory_limit_001.phpt | 15 ++++++----- tests/set_memory_limit_002.phpt | 48 +++++++++++++++++++++++++++++++++ tests/set_memory_limit_003.phpt | 15 ++++++----- 3 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 tests/set_memory_limit_002.phpt diff --git a/tests/set_memory_limit_001.phpt b/tests/set_memory_limit_001.phpt index b20b753e..d35a2cdc 100644 --- a/tests/set_memory_limit_001.phpt +++ b/tests/set_memory_limit_001.phpt @@ -13,20 +13,23 @@ if (getenv("SKIP_SLOW_TESTS")) { $JS = <<< EOT var jsfunc = function() { - var text = "abcdefghijklmnopqrstuvwyxz0123456789"; + var text = "abcdefghijklmnopqrstuvwyxz0123456789"; // 36 bytes var memory = ""; - for (var i = 0; i < 100; ++i) { - for (var j = 0; j < 10000; ++j) { + // should generate 360 MB + for (var i = 0; i < 10_000; ++i) { + for (var j = 0; j < 1000; ++j) { memory += text; - } - sleep(0); + } + sleep(0); } + + return memory; }; jsfunc; EOT; $v8 = new V8Js(); -$v8->setMemoryLimit(10000000); +$v8->setMemoryLimit(10_000_000); $func = $v8->executeString($JS); var_dump($func); diff --git a/tests/set_memory_limit_002.phpt b/tests/set_memory_limit_002.phpt new file mode 100644 index 00000000..78bbd9db --- /dev/null +++ b/tests/set_memory_limit_002.phpt @@ -0,0 +1,48 @@ +--TEST-- +Test V8::setMemoryLimit() : Memory limit can be set but does not trigger when not exceeded +--SKIPIF-- + +--FILE-- +setMemoryLimit(10_000_000); + +$func = $v8->executeString($JS); +var_dump($func); + +try { + $func(); +} catch (V8JsMemoryLimitException $e) { + print get_class($e); print PHP_EOL; + print $e->getMessage(); print PHP_EOL; +} +?> +===EOF=== +--EXPECTF-- +object(V8Function)#%d (0) { +} +===EOF=== diff --git a/tests/set_memory_limit_003.phpt b/tests/set_memory_limit_003.phpt index 179dfe2e..e10669fb 100644 --- a/tests/set_memory_limit_003.phpt +++ b/tests/set_memory_limit_003.phpt @@ -14,14 +14,17 @@ if (getenv("SKIP_SLOW_TESTS")) { $JS = <<< EOT var jsfunc = function() { PHP.imposeMemoryLimit(); - var text = "abcdefghijklmnopqrstuvwyxz0123456789"; + var text = "abcdefghijklmnopqrstuvwyxz0123456789"; // 36 bytes var memory = ""; - for (var i = 0; i < 100; ++i) { - for (var j = 0; j < 10000; ++j) { + // should generate 360 MB + for (var i = 0; i < 10_000; ++i) { + for (var j = 0; j < 1000; ++j) { memory += text; - } - sleep(0); + } + sleep(0); } + + return memory; }; jsfunc; EOT; @@ -29,7 +32,7 @@ EOT; $v8 = new V8Js(); $v8->imposeMemoryLimit = function() use ($v8) { - $v8->setMemoryLimit(10000000); + $v8->setMemoryLimit(10_000_000); }; $func = $v8->executeString($JS); From 0d8c89fe316e95cd7eaf41556e303d7ff936ee98 Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Sun, 11 May 2025 13:07:42 +0200 Subject: [PATCH 8/9] Add missing LIBS override to search for v8 in compilation test --- config.m4 | 1 + 1 file changed, 1 insertion(+) diff --git a/config.m4 b/config.m4 index 835eedf9..edb11c12 100644 --- a/config.m4 +++ b/config.m4 @@ -118,6 +118,7 @@ if test "$PHP_V8JS" != "no"; then CPPFLAGS="$CPPFLAGS -I$V8_INCLUDE_DIR -std=$ac_cv_v8_cstd" LDFLAGS="$LDFLAGS -L$V8_LIBRARY_DIR" + LIBS="-L$V8_LIBRARY_DIR $LIBS" if test "$libname" = "v8"; then AC_MSG_CHECKING([for libv8_libplatform]) From 7518995cc0adc20e118240f85d5a8b5e642f2d14 Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Sun, 11 May 2025 00:01:05 +0200 Subject: [PATCH 9/9] debug pipeline --- .github/workflows/build-test.yml | 65 +++++++++++++++++++++- config.m4 | 94 +++++++++++++++++++++++++------- 2 files changed, 135 insertions(+), 24 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index a4556d18..1e15d24c 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -97,8 +97,30 @@ jobs: else LIB_EXT=so fi - cp out.gn/$V8CONFIG/lib*.${LIB_EXT} out.gn/$V8CONFIG/*_blob.bin out.gn/$V8CONFIG/icudtl.dat /opt/v8/self-built/lib/ + # Copy all V8 libraries and support files + cp -v out.gn/$V8CONFIG/lib*.${LIB_EXT}* out.gn/$V8CONFIG/*_blob.bin out.gn/$V8CONFIG/icudtl.dat /opt/v8/self-built/lib/ + # Copy all V8 static libraries as well + cp -v out.gn/$V8CONFIG/obj/libv8_*.a /opt/v8/self-built/lib/ 2>/dev/null || true + # Copy headers cp -R include/* /opt/v8/self-built/include/ + # Create symlinks for libraries without version numbers + cd /opt/v8/self-built/lib/ + for lib in lib*.${LIB_EXT}.*; do + if [[ $lib == *\.${LIB_EXT}.* ]]; then + ln -sf $lib ${lib%%.*} 2>/dev/null || true + fi + done + # Set library search path + if [[ "${{ runner.os }}" == "Linux" ]]; then + echo "/opt/v8/self-built/lib" | sudo tee /etc/ld.so.conf.d/v8.conf + sudo ldconfig + elif [[ "${{ runner.os }}" == "macOS" ]]; then + # On macOS, update DYLD_LIBRARY_PATH for the current session + echo "DYLD_LIBRARY_PATH=/opt/v8/self-built/lib" >> $GITHUB_ENV + # Also create symlinks in /usr/local/lib for system-wide access + sudo mkdir -p /usr/local/lib/v8 + sudo ln -sf /opt/v8/self-built/lib/*.dylib* /usr/local/lib/v8/ + fi # Go back to origin cd "${GITHUB_WORKSPACE}" @@ -158,9 +180,46 @@ jobs: - name: Build extension run: | + # Set library paths based on OS + if [[ "${{ runner.os }}" == "Linux" ]]; then + export LD_LIBRARY_PATH="/opt/v8/self-built/lib:${LD_LIBRARY_PATH:-}" + # Ensure linker can find the libraries + echo "/opt/v8/self-built/lib" | sudo tee /etc/ld.so.conf.d/v8js.conf + sudo ldconfig + echo "=== Library search paths ===" + ldconfig -p | grep v8 || true + elif [[ "${{ runner.os }}" == "macOS" ]]; then + export DYLD_LIBRARY_PATH="/opt/v8/self-built/lib:${DYLD_LIBRARY_PATH:-}" + fi + + # List V8 libraries for debugging + echo "=== Available V8 libraries ===" + ls -la /opt/v8/self-built/lib/ + + # Build the extension phpize - ./configure --with-v8js=/opt/v8/self-built LDFLAGS="-lstdc++" CPPFLAGS="-DV8_COMPRESS_POINTERS -DV8_ENABLE_SANDBOX" - make + + # Configure with explicit library paths + echo "=== Running configure ===" + ./configure \ + --with-v8js=/opt/v8/self-built \ + LDFLAGS="-L/opt/v8/self-built/lib -Wl,-rpath=/opt/v8/self-built/lib" \ + CPPFLAGS="-I/opt/v8/self-built/include -DV8_COMPRESS_POINTERS -DV8_ENABLE_SANDBOX" \ + LIBS="-lstdc++" \ + V8_LIBS="-L/opt/v8/self-built/lib -lv8 -lv8_libplatform -lv8_libbase -lstdc++ -lpthread -ldl" + + # Build with verbose output + echo "=== Building extension ===" + make -j$(nproc) V=1 + + # Verify the linked libraries + if [[ "${{ runner.os }}" == "Linux" ]]; then + echo "=== Checking linked libraries ===" + ldd modules/v8js.so | grep -i v8 || true + fi + + # Run tests + echo "=== Running tests ===" make test - name: Archive test results diff --git a/config.m4 b/config.m4 index edb11c12..0490bc71 100644 --- a/config.m4 +++ b/config.m4 @@ -24,31 +24,78 @@ if test "$PHP_V8JS" != "no"; then AC_MSG_CHECKING([for V8 files in default path]) ARCH=$(uname -m) - + + AC_MSG_NOTICE([Searching for V8 in: $SEARCH_PATH]) + AC_MSG_NOTICE([Looking for library: $SEARCH_FOR]) + AC_MSG_NOTICE([System architecture: $ARCH]) + AC_MSG_NOTICE([PHP library directory: $PHP_LIBDIR]) + + found_v8=no + for i in $SEARCH_PATH ; do - if test -r "$i/$PHP_LIBDIR/$SEARCH_FOR" -a -r "$i/include/$libname/v8.h"; then - V8_INCLUDE_DIR="$i/include/$libname" - V8_LIBRARY_DIR="$i/$PHP_LIBDIR" - AC_MSG_RESULT(found in $i) - break 2 + AC_MSG_NOTICE([Checking path: $i]) + + # Check for standard installation + if test -r "$i/$PHP_LIBDIR/$SEARCH_FOR"; then + AC_MSG_NOTICE([ Found library: $i/$PHP_LIBDIR/$SEARCH_FOR]) + + if test -r "$i/include/$libname/v8.h"; then + AC_MSG_NOTICE([ Found include file: $i/include/$libname/v8.h]) + V8_INCLUDE_DIR="$i/include/$libname" + V8_LIBRARY_DIR="$i/$PHP_LIBDIR" + AC_MSG_RESULT([found standard installation in $i]) + found_v8=yes + break 2 + else + AC_MSG_NOTICE([ Missing include file: $i/include/$libname/v8.h]) + fi + else + AC_MSG_NOTICE([ Missing library: $i/$PHP_LIBDIR/$SEARCH_FOR]) fi - # Debian installations - if test -r "$i/$PHP_LIBDIR/$ARCH-linux-gnu/$SEARCH_FOR"; then - V8_INCLUDE_DIR="$i/include/$libname" - V8_LIBRARY_DIR="$i/$PHP_LIBDIR/$ARCH-linux-gnu" - AC_MSG_RESULT(found in $i) - break 2 + # Check for Debian installations + DEBIAN_PATH="$i/$PHP_LIBDIR/$ARCH-linux-gnu" + if test -r "$DEBIAN_PATH/$SEARCH_FOR"; then + AC_MSG_NOTICE([ Found Debian library: $DEBIAN_PATH/$SEARCH_FOR]) + + if test -r "$i/include/$libname/v8.h"; then + AC_MSG_NOTICE([ Found include file: $i/include/$libname/v8.h]) + V8_INCLUDE_DIR="$i/include/$libname" + V8_LIBRARY_DIR="$DEBIAN_PATH" + AC_MSG_RESULT([found Debian installation in $i]) + found_v8=yes + break 2 + else + AC_MSG_NOTICE([ Missing Debian include file: $i/include/$libname/v8.h]) + fi + else + AC_MSG_NOTICE([ Missing Debian library: $DEBIAN_PATH/$SEARCH_FOR]) fi - # Manual installations - if test -r "$i/$PHP_LIBDIR/$SEARCH_FOR" -a -r "$i/include/libplatform/libplatform.h"; then - V8_INCLUDE_DIR="$i/include" - V8_LIBRARY_DIR="$i/$PHP_LIBDIR" - AC_MSG_RESULT(found in $i) - break 2 + # Check for manual installations + if test -r "$i/$PHP_LIBDIR/$SEARCH_FOR"; then + AC_MSG_NOTICE([ Found manual library: $i/$PHP_LIBDIR/$SEARCH_FOR]) + + if test -r "$i/include/libplatform/libplatform.h"; then + AC_MSG_NOTICE([ Found manual include file: $i/include/libplatform/libplatform.h]) + V8_INCLUDE_DIR="$i/include" + V8_LIBRARY_DIR="$i/$PHP_LIBDIR" + AC_MSG_RESULT([found manual installation in $i]) + found_v8=yes + break 2 + else + AC_MSG_NOTICE([ Missing manual include file: $i/include/libplatform/libplatform.h]) + fi fi + + AC_MSG_NOTICE([No V8 found in $i]) done + + if test "$found_v8" = "no"; then + AC_MSG_NOTICE([V8 not found in any search path]) + AC_MSG_NOTICE([Searched for library: $SEARCH_FOR]) + AC_MSG_NOTICE([Searched paths: $SEARCH_PATH]) + fi done AC_DEFINE_UNQUOTED([PHP_V8_EXEC_PATH], "$V8_LIBRARY_DIR/$SEARCH_FOR", [Full path to libv8 library file]) @@ -117,8 +164,13 @@ if test "$PHP_V8JS" != "no"; then AC_LANG_PUSH([C++]) CPPFLAGS="$CPPFLAGS -I$V8_INCLUDE_DIR -std=$ac_cv_v8_cstd" - LDFLAGS="$LDFLAGS -L$V8_LIBRARY_DIR" - LIBS="-L$V8_LIBRARY_DIR $LIBS" + LDFLAGS="-L$V8_LIBRARY_DIR -Wl,-rpath,$V8_LIBRARY_DIR $LDFLAGS" + # Try both libc++ and libstdc++ + LIBS="-L$V8_LIBRARY_DIR -lv8_libbase -lc++ -lstdc++ -lpthread -ldl $LIBS" + + AC_MSG_NOTICE([LIBS for v8_libplatform check: $LIBS]) + AC_MSG_NOTICE([LDFLAGS for v8_libplatform check: $LDFLAGS]) + AC_MSG_NOTICE([CPPFLAGS for v8_libplatform check: $CPPFLAGS]) if test "$libname" = "v8"; then AC_MSG_CHECKING([for libv8_libplatform]) @@ -137,7 +189,7 @@ if test "$PHP_V8JS" != "no"; then ]) V8_CHECK_LINK([], [], [], [ - V8_CHECK_LINK([-lv8_libbase], [], [], [ + V8_CHECK_LINK([-lv8_libbase -lc++ -lstdc++ -lpthread -ldl], [], [], [ AC_MSG_ERROR([could not find libv8_libplatform library]) ]) ])