diff --git a/.github/workflows/annocheck.yml b/.github/workflows/annocheck.yml index e839cddc179b0b..1400dcc38bc546 100644 --- a/.github/workflows/annocheck.yml +++ b/.github/workflows/annocheck.yml @@ -73,7 +73,7 @@ jobs: builddir: build makeup: true - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: '3.1' bundler: none diff --git a/.github/workflows/auto_review_pr.yml b/.github/workflows/auto_review_pr.yml index 93ef85f4963d73..b3f73a206afeda 100644 --- a/.github/workflows/auto_review_pr.yml +++ b/.github/workflows/auto_review_pr.yml @@ -29,7 +29,7 @@ jobs: with: persist-credentials: false - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: '3.4' bundler: none diff --git a/.github/workflows/baseruby.yml b/.github/workflows/baseruby.yml index 413e5d7ee7ec17..ce517b25c586b7 100644 --- a/.github/workflows/baseruby.yml +++ b/.github/workflows/baseruby.yml @@ -48,7 +48,7 @@ jobs: - ruby-3.3 steps: - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: ${{ matrix.ruby }} bundler: none diff --git a/.github/workflows/bundled_gems.yml b/.github/workflows/bundled_gems.yml index 5621e5bc7a8a1f..28df5172ca037a 100644 --- a/.github/workflows/bundled_gems.yml +++ b/.github/workflows/bundled_gems.yml @@ -38,7 +38,7 @@ jobs: with: token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_AUTO_UPDATE_TOKEN || secrets.GITHUB_TOKEN }} - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: 4.0 diff --git a/.github/workflows/check_dependencies.yml b/.github/workflows/check_dependencies.yml index 327734c9e21363..7f142eb6a3bb1a 100644 --- a/.github/workflows/check_dependencies.yml +++ b/.github/workflows/check_dependencies.yml @@ -42,7 +42,7 @@ jobs: - uses: ./.github/actions/setup/directories - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: '3.1' bundler: none diff --git a/.github/workflows/check_misc.yml b/.github/workflows/check_misc.yml index e50ebb3f9961d6..4cde7b8e294b6a 100644 --- a/.github/workflows/check_misc.yml +++ b/.github/workflows/check_misc.yml @@ -23,7 +23,7 @@ jobs: token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_AUTO_UPDATE_TOKEN || secrets.GITHUB_TOKEN }} persist-credentials: false - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: head diff --git a/.github/workflows/check_sast.yml b/.github/workflows/check_sast.yml index 3b4eb17646bb66..291cc37a1ff257 100644 --- a/.github/workflows/check_sast.yml +++ b/.github/workflows/check_sast.yml @@ -78,14 +78,14 @@ jobs: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + uses: github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 with: languages: ${{ matrix.language }} build-mode: none config-file: .github/codeql/codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + uses: github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 with: category: '/language:${{ matrix.language }}' upload: False @@ -127,7 +127,7 @@ jobs: continue-on-error: true - name: Upload SARIF - uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + uses: github/codeql-action/upload-sarif@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 with: sarif_file: sarif-results/${{ matrix.language }}.sarif continue-on-error: true diff --git a/.github/workflows/modgc.yml b/.github/workflows/modgc.yml index 2cc77eefed2f6f..7e423bc7d139af 100644 --- a/.github/workflows/modgc.yml +++ b/.github/workflows/modgc.yml @@ -67,7 +67,7 @@ jobs: uses: ./.github/actions/setup/ubuntu if: ${{ contains(matrix.os, 'ubuntu') }} - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: '3.1' bundler: none diff --git a/.github/workflows/parse_y.yml b/.github/workflows/parse_y.yml index 7f355d3d0cc0e7..13610a9bad46f9 100644 --- a/.github/workflows/parse_y.yml +++ b/.github/workflows/parse_y.yml @@ -59,7 +59,7 @@ jobs: - uses: ./.github/actions/setup/ubuntu - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: '3.1' bundler: none diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4ce3fd0476ad73..8ec6c75e5e5b1d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -22,7 +22,7 @@ jobs: with: persist-credentials: false - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: 3.3.4 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index d2c8b7a4f1a929..dae9640a9d0f36 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -73,6 +73,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + uses: github/codeql-action/upload-sarif@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 with: sarif_file: results.sarif diff --git a/.github/workflows/spec_guards.yml b/.github/workflows/spec_guards.yml index d3a497ea8cbacd..128b96887e030c 100644 --- a/.github/workflows/spec_guards.yml +++ b/.github/workflows/spec_guards.yml @@ -49,7 +49,7 @@ jobs: with: persist-credentials: false - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: ${{ matrix.ruby }} bundler: none diff --git a/.github/workflows/sync_default_gems.yml b/.github/workflows/sync_default_gems.yml index 3b1e5e191ed11a..a5a5f4243840a2 100644 --- a/.github/workflows/sync_default_gems.yml +++ b/.github/workflows/sync_default_gems.yml @@ -39,7 +39,7 @@ jobs: with: token: ${{ github.repository == 'ruby/ruby' && secrets.MATZBOT_AUTO_UPDATE_TOKEN || secrets.GITHUB_TOKEN }} - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: '3.4' bundler: none diff --git a/.github/workflows/tarball-ubuntu.yml b/.github/workflows/tarball-ubuntu.yml index 88782a801c7c4a..e458c9f8079517 100644 --- a/.github/workflows/tarball-ubuntu.yml +++ b/.github/workflows/tarball-ubuntu.yml @@ -43,7 +43,7 @@ jobs: set -x sudo apt-get update -q sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev zlib1g-dev libffi-dev libgmp-dev bison- autoconf- - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: '3.2' # test-bundled-gems requires executable host ruby diff --git a/.github/workflows/tarball-windows.yml b/.github/workflows/tarball-windows.yml index 7e32faa3b9395e..75661eef71f469 100644 --- a/.github/workflows/tarball-windows.yml +++ b/.github/workflows/tarball-windows.yml @@ -48,7 +48,7 @@ jobs: - run: md build working-directory: - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: '3.2' bundler: none diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 19f89eae6f5c86..b3ff647df679a4 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -79,7 +79,7 @@ jobs: with: arch: ${{ matrix.arch }} - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: '3.1' bundler: none diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index cba593d1c0d6e0..e9841ac95e95a4 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -65,7 +65,7 @@ jobs: sparse-checkout: /.github persist-credentials: false - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: '3.1' bundler: none diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index d83fa0144ebc54..5e6282c36dcbed 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -63,7 +63,7 @@ jobs: - run: md build working-directory: - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: # windows-11-arm has only 3.4.1, 3.4.2, 3.4.3, head ruby-version: ${{ !endsWith(matrix.os, 'arm') && '3.1' || '3.4' }} diff --git a/.github/workflows/yjit-ubuntu.yml b/.github/workflows/yjit-ubuntu.yml index 8385cbd9b112f7..c52bc40f215bdf 100644 --- a/.github/workflows/yjit-ubuntu.yml +++ b/.github/workflows/yjit-ubuntu.yml @@ -138,7 +138,7 @@ jobs: - uses: ./.github/actions/setup/ubuntu - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: '3.1' bundler: none diff --git a/.github/workflows/zjit-macos.yml b/.github/workflows/zjit-macos.yml index 5517985c1c153c..925e4a96e8eebb 100644 --- a/.github/workflows/zjit-macos.yml +++ b/.github/workflows/zjit-macos.yml @@ -98,7 +98,7 @@ jobs: rustup install ${{ matrix.rust_version }} --profile minimal rustup default ${{ matrix.rust_version }} - - uses: taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 # v2.83.2 + - uses: taiki-e/install-action@ed67fa35ac944f3a9b33f12c4dd43b6f31a47e20 # v2.83.3 with: tool: nextest@0.9 if: ${{ matrix.test_task == 'zjit-check' }} diff --git a/.github/workflows/zjit-ubuntu.yml b/.github/workflows/zjit-ubuntu.yml index 25bde6b8b2a16c..73909e0cbca6a2 100644 --- a/.github/workflows/zjit-ubuntu.yml +++ b/.github/workflows/zjit-ubuntu.yml @@ -136,12 +136,12 @@ jobs: - uses: ./.github/actions/setup/ubuntu - - uses: ruby/setup-ruby@8e41b362d2589a22a44c1cfa214b3c83052c195b # v1.318.0 + - uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1.319.0 with: ruby-version: '3.1' bundler: none - - uses: taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 # v2.83.2 + - uses: taiki-e/install-action@ed67fa35ac944f3a9b33f12c4dd43b6f31a47e20 # v2.83.3 with: tool: nextest@0.9 if: ${{ matrix.test_task == 'zjit-check' }} diff --git a/NEWS.md b/NEWS.md index 0e29b862a39b05..0e1ecf093f4381 100644 --- a/NEWS.md +++ b/NEWS.md @@ -120,7 +120,7 @@ releases. * bundler 4.1.0.dev * 4.0.3 to [v4.0.4][bundler-v4.0.4], [v4.0.5][bundler-v4.0.5], [v4.0.6][bundler-v4.0.6], [v4.0.7][bundler-v4.0.7], [v4.0.8][bundler-v4.0.8], [v4.0.9][bundler-v4.0.9], [v4.0.10][bundler-v4.0.10], [v4.0.11][bundler-v4.0.11], [v4.0.12][bundler-v4.0.12], [v4.0.13][bundler-v4.0.13], [v4.0.14][bundler-v4.0.14], [v4.0.15][bundler-v4.0.15], [v4.0.16][bundler-v4.0.16] * erb 6.0.5 - * 6.0.1 to [v6.0.1.1][erb-v6.0.1.1], [v6.0.2][erb-v6.0.2], [v6.0.3][erb-v6.0.3], [v6.0.4][erb-v6.0.4] + * 6.0.1 to [v6.0.1.1][erb-v6.0.1.1], [v6.0.2][erb-v6.0.2], [v6.0.3][erb-v6.0.3], [v6.0.4][erb-v6.0.4], [v6.0.5][erb-v6.0.5] * error_highlight 0.7.2 * ipaddr 1.2.9 * 1.2.8 to [v1.2.9][ipaddr-v1.2.9] @@ -286,6 +286,7 @@ A lot of work has gone into making Ractors more stable, performant, and usable. [erb-v6.0.2]: https://github.com/ruby/erb/releases/tag/v6.0.2 [erb-v6.0.3]: https://github.com/ruby/erb/releases/tag/v6.0.3 [erb-v6.0.4]: https://github.com/ruby/erb/releases/tag/v6.0.4 +[erb-v6.0.5]: https://github.com/ruby/erb/releases/tag/v6.0.5 [ipaddr-v1.2.9]: https://github.com/ruby/ipaddr/releases/tag/v1.2.9 [json-v2.18.1]: https://github.com/ruby/json/releases/tag/v2.18.1 [json-v2.19.0]: https://github.com/ruby/json/releases/tag/v2.19.0 diff --git a/array.c b/array.c index 35892be43e5ecf..8c87b3018b888e 100644 --- a/array.c +++ b/array.c @@ -34,6 +34,7 @@ #include "shape.h" #include "vm_core.h" #include "builtin.h" +#include "zjit.h" #if !ARRAY_DEBUG # undef NDEBUG @@ -2925,6 +2926,25 @@ rb_ary_resurrect(VALUE ary) return ary_make_partial(ary, rb_cArray, 0, RARRAY_LEN(ary)); } +#if USE_ZJIT +bool +rb_zjit_array_dup_can_fastpath(VALUE ary, size_t *alloc_size_out, VALUE *flags_out, long *len_out) +{ + long len = RARRAY_LEN(ary); + long embed_capa = (sizeof(struct RArray) - offsetof(struct RArray, as.ary)) / sizeof(VALUE); + + if (len > embed_capa) return false; + + size_t size = sizeof(struct RArray); + shape_id_t shape_id = rb_shape_transition_slot_size(ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER, + rb_gc_size_slot_size(size)); + *alloc_size_out = size; + *flags_out = T_ARRAY | RARRAY_EMBED_FLAG | ((VALUE)len << RARRAY_EMBED_LEN_SHIFT) | ((VALUE)shape_id << SHAPE_FLAG_SHIFT); + *len_out = len; + return true; +} +#endif + extern VALUE rb_output_fs; static void ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result, int *first); diff --git a/configure.ac b/configure.ac index 9ae8acee9b6b95..a37bdce0749a09 100644 --- a/configure.ac +++ b/configure.ac @@ -3143,7 +3143,7 @@ STATIC= # mkmf.rb's have_header() to fail if the desired resource happens to be # installed in the /usr/local tree. RUBY_APPEND_OPTION(CCDLFLAGS, -fno-common)], - [cygwin*|msys*|mingw*|aix*|interix*], [ ], + [cygwin*|msys*|mingw*|aix*], [ ], [ RUBY_APPEND_OPTION(CCDLFLAGS, -fPIC)]) ], [ @@ -3205,9 +3205,6 @@ AC_SUBST(EXTOBJS) LDFLAGS="$LDFLAGS -Wl,-export-dynamic" ]) rb_cv_dlopen=yes], - [interix*], [ : ${LDSHARED='$(CC) -shared'} - XLDFLAGS="$XLDFLAGS -Wl,-E" - rb_cv_dlopen=yes], [freebsd*|dragonfly*], [ : ${LDSHARED='$(CC) -shared'} AS_IF([test "$rb_cv_binary_elf" = yes], [ @@ -3730,9 +3727,6 @@ AS_CASE("$enable_shared", [yes], [ ]) LIBRUBY_DLDFLAGS="$LIBRUBY_DLDFLAGS "' $(XLDFLAGS)' ], - [interix*], [ - LIBRUBYARG_SHARED='-L. -L${libdir} -l$(RUBY_SO_NAME)' - ], [cygwin*|msys*|mingw*|mswin*], [ LIBRUBY_RELATIVE=yes ]) @@ -3810,6 +3804,13 @@ AS_CASE(["${enable_dtrace}"], ], [ rb_cv_dtrace_available=no ]) +AS_CASE(["$target_cpu-$target_os"], [aarch64-freebsd* | arm64-freebsd*], [dnl + # FreeBSD's libdtrace mishandles is-enabled probes on aarch64: dt_modtext() + # rewrites the call site to a bare nop without clearing the return register, + # so RUBY_DTRACE_*_ENABLED() returns a garbage value and fires probes even + # when no consumer is attached. See dt_link.c dt_modtext() for __aarch64__. + rb_cv_dtrace_available=no +]) AS_IF([test "${enable_dtrace}" = yes], [dnl AS_IF([test -z "$DTRACE"], [dnl AC_MSG_ERROR([dtrace(1) is missing]) diff --git a/depend b/depend index fc1960615068c6..e9e8bdc3fed063 100644 --- a/depend +++ b/depend @@ -279,6 +279,7 @@ array.$(OBJEXT): {$(VPATH)}thread_native.h array.$(OBJEXT): {$(VPATH)}util.h array.$(OBJEXT): {$(VPATH)}vm_core.h array.$(OBJEXT): {$(VPATH)}vm_opts.h +array.$(OBJEXT): {$(VPATH)}zjit.h ast.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h ast.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h ast.$(OBJEXT): $(CCAN_DIR)/list/list.h diff --git a/dln.c b/dln.c index d3b03e3e87c954..35f097218a7d58 100644 --- a/dln.c +++ b/dln.c @@ -384,9 +384,6 @@ dln_open(const char *file) # ifndef RTLD_LAZY # define RTLD_LAZY 1 # endif -# ifdef __INTERIX -# undef RTLD_GLOBAL -# endif # ifndef RTLD_GLOBAL # define RTLD_GLOBAL 0 # endif diff --git a/gc/default/default.c b/gc/default/default.c index e4889a007a19eb..1f1446036b38d2 100644 --- a/gc/default/default.c +++ b/gc/default/default.c @@ -74,8 +74,11 @@ rb_hrtime_sub(rb_hrtime_t a, rb_hrtime_t b) #include "probes.h" +/* cl.exe's traditional preprocessor passes __VA_ARGS__ to a nested macro as + * a single argument; the extra expansion re-scans it into separate ones. */ +#define RUBY_DTRACE_GC_HOOK_EXPAND(expr) expr #define RUBY_DTRACE_GC_HOOK(name, ...) \ - do {if (RUBY_DTRACE_GC_##name##_ENABLED()) RUBY_DTRACE_GC_##name(__VA_ARGS__);} while (0) + do {if (RUBY_DTRACE_GC_##name##_ENABLED()) RUBY_DTRACE_GC_HOOK_EXPAND(RUBY_DTRACE_GC_##name(__VA_ARGS__));} while (0) #if USE_ZJIT # include "gc/default/zjit_fastpath.h" diff --git a/random.c b/random.c index 1eaeacfe21dd92..5e89a44de8807e 100644 --- a/random.c +++ b/random.c @@ -41,7 +41,6 @@ #ifdef _WIN32 # include # include -# include # include #endif @@ -555,64 +554,8 @@ fill_random_bytes_lib(void *buf, size_t size) return 0; } #elif defined(_WIN32) - -#ifndef DWORD_MAX -# define DWORD_MAX (~(DWORD)0UL) -#endif - -# if defined(CRYPT_VERIFYCONTEXT) -/* Although HCRYPTPROV is not a HANDLE, it looks like - * INVALID_HANDLE_VALUE is not a valid value */ -static const HCRYPTPROV INVALID_HCRYPTPROV = (HCRYPTPROV)INVALID_HANDLE_VALUE; - -static void -release_crypt(VALUE arg) -{ - HCRYPTPROV *ptr = (void *)arg; - HCRYPTPROV prov = (HCRYPTPROV)ATOMIC_PTR_EXCHANGE(*ptr, INVALID_HCRYPTPROV); - if (prov && prov != INVALID_HCRYPTPROV) { - CryptReleaseContext(prov, 0); - } -} - -static int -fill_random_bytes_crypt(void *seed, size_t size) -{ - static HCRYPTPROV perm_prov; - HCRYPTPROV prov = perm_prov, old_prov; - if (!prov) { - if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { - prov = INVALID_HCRYPTPROV; - } - old_prov = (HCRYPTPROV)ATOMIC_PTR_CAS(perm_prov, 0, prov); - if (LIKELY(!old_prov)) { /* no other threads acquired */ - if (prov != INVALID_HCRYPTPROV) { - /* register only once; perm_prov == 0 at the first call only */ - rb_set_end_proc(release_crypt, (VALUE)&perm_prov); - } - } - else { /* another thread acquired */ - if (prov != INVALID_HCRYPTPROV) { - CryptReleaseContext(prov, 0); - } - prov = old_prov; - } - } - if (prov == INVALID_HCRYPTPROV) return -1; - while (size > 0) { - DWORD n = (size > (size_t)DWORD_MAX) ? DWORD_MAX/2+1 : (DWORD)size; - if (!CryptGenRandom(prov, n, seed)) return -1; - seed = (char *)seed + n; - size -= n; - } - return 0; -} -# else -# define fill_random_bytes_crypt(seed, size) -1 -# endif - static int -fill_random_bytes_bcrypt(void *seed, size_t size) +fill_random_bytes_lib(void *seed, size_t size) { while (size > 0) { ULONG n = (size > (size_t)ULONG_MAX) ? ULONG_MAX/2+1 : (ULONG)size; @@ -623,13 +566,6 @@ fill_random_bytes_bcrypt(void *seed, size_t size) } return 0; } - -static int -fill_random_bytes_lib(void *seed, size_t size) -{ - if (fill_random_bytes_bcrypt(seed, size) == 0) return 0; - return fill_random_bytes_crypt(seed, size); -} #else # define fill_random_bytes_lib(seed, size) -1 #endif diff --git a/test/-ext-/bug_reporter/test_bug_reporter.rb b/test/-ext-/bug_reporter/test_bug_reporter.rb index 83fdba22829e97..eb557e9a8c5cd8 100644 --- a/test/-ext-/bug_reporter/test_bug_reporter.rb +++ b/test/-ext-/bug_reporter/test_bug_reporter.rb @@ -19,12 +19,12 @@ def test_bug_reporter_add tmpdir = Dir.mktmpdir no_core = "Process.setrlimit(Process::RLIMIT_CORE, 0); " if defined?(Process.setrlimit) && defined?(Process::RLIMIT_CORE) - args = ["-r-test-/bug_reporter", "-C", tmpdir] + args = ["-r-test-/bug_reporter", "-r-test-/fatal", "-C", tmpdir] # We want the printed description to match this process's RUBY_DESCRIPTION args.push("--yjit") if JITSupport.yjit_enabled? args.push("--zjit") if JITSupport.zjit_enabled? args.unshift({"RUBY_ON_BUG" => nil, "RUBY_CRASH_REPORT" => nil}) - stdin = "#{no_core}register_sample_bug_reporter(12345); Process.kill :SEGV, $$" + stdin = "#{no_core}register_sample_bug_reporter(12345); Bug.segv" assert_in_out_err(args, stdin, [], expected_stderr, encoding: "ASCII-8BIT") ensure FileUtils.rm_rf(tmpdir) if tmpdir diff --git a/thread.c b/thread.c index e9c67aa7793449..3b32ddb2cf8a6c 100644 --- a/thread.c +++ b/thread.c @@ -713,7 +713,7 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start) // Ensure that we are not joinable. VM_ASSERT(UNDEF_P(th->value)); - int fiber_scheduler_closed = 0, event_thread_end_hooked = 0; + volatile int fiber_scheduler_closed = 0, event_thread_end_hooked = 0; VALUE result = Qundef; EC_PUSH_TAG(th->ec); diff --git a/vm_trace.c b/vm_trace.c index 746f43038ab7e0..66ff0c301e7495 100644 --- a/vm_trace.c +++ b/vm_trace.c @@ -1972,7 +1972,7 @@ rb_postponed_job_flush(rb_vm_t *vm) ccan_list_append_list(&tmp, &vm->workqueue); rb_nativethread_lock_unlock(&vm->workqueue_lock); - rb_atomic_t triggered_bits = RUBY_ATOMIC_EXCHANGE(pjq->triggered_bitset, 0); + volatile rb_atomic_t triggered_bits = RUBY_ATOMIC_EXCHANGE(pjq->triggered_bitset, 0); /* jobs targeted at this Ractor (rb_postponed_job_trigger_for_ractor) */ triggered_bits |= RUBY_ATOMIC_EXCHANGE(rb_ec_ractor_ptr(ec)->postponed_job_triggered_bits, 0); diff --git a/zjit.h b/zjit.h index fb189537ba8370..ac6af1a9de2f4c 100644 --- a/zjit.h +++ b/zjit.h @@ -95,6 +95,7 @@ void rb_zjit_materialize_frames(const rb_execution_context_t *ec, rb_control_fra size_t rb_zjit_hash_new_size(void); bool rb_zjit_class_allocate_instance_fastpath(VALUE klass, size_t *size_out, shape_id_t *shape_id_out); bool rb_zjit_str_resurrect_fastpath(VALUE str, bool chilled, size_t *size_out, VALUE *flags_out, long *len_out, size_t *byte_size_out); +bool rb_zjit_array_dup_can_fastpath(VALUE ary, size_t *alloc_size_out, VALUE *flags_out, long *len_out); // Special value for cfp->jit_return that means "this is a C method frame, use // rb_zjit_c_frame as the JITFrame". We don't control the native stack layout diff --git a/zjit/bindgen/src/main.rs b/zjit/bindgen/src/main.rs index 14dfea5c297a59..27ce2f5e4a642a 100644 --- a/zjit/bindgen/src/main.rs +++ b/zjit/bindgen/src/main.rs @@ -115,6 +115,7 @@ fn main() { .allowlist_function("rb_zjit_hash_new_size") .allowlist_function("rb_zjit_class_allocate_instance_fastpath") .allowlist_function("rb_zjit_str_resurrect_fastpath") + .allowlist_function("rb_zjit_array_dup_can_fastpath") // For crashing .allowlist_function("rb_bug") diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index a731aa4c99e878..f34f57e3afb80e 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -622,7 +622,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio } Insn::NewRange { low, high, flag, state } => gen_new_range(jit, asm, function, opnd!(low), opnd!(high), *flag, &function.frame_state(*state)), Insn::NewRangeFixnum { low, high, flag, state } => gen_new_range_fixnum(asm, opnd!(low), opnd!(high), *flag, &function.frame_state(*state)), - Insn::ArrayDup { val, state } => gen_array_dup(asm, opnd!(val), &function.frame_state(*state)), + Insn::ArrayDup { val, state } => gen_array_dup(jit, asm, function, *val, opnd!(val), &function.frame_state(*state)), Insn::AdjustBounds { index, length } => gen_adjust_bounds(asm, opnd!(index), opnd!(length)), Insn::ArrayAref { array, index, .. } => gen_array_aref(asm, opnd!(array), opnd!(index)), Insn::ArrayAset { array, index, val } => { @@ -2127,12 +2127,38 @@ fn gen_string_equal(asm: &mut Assembler, left: Opnd, right: Opnd) -> lir::Opnd { /// Compile an array duplication instruction fn gen_array_dup( + jit: &mut JITState, asm: &mut Assembler, + function: &Function, + val_id: InsnId, val: lir::Opnd, state: &FrameState, ) -> lir::Opnd { - gen_prepare_leaf_call_with_gc(asm, state); + // duparray resurrects a frozen literal array baked into the ISEQ, so its elements are known + // here. When the resurrected copy would be embedded, bump-allocate it inline and store the + // elements directly; the fresh object is young and white, so those writes need no write + // barrier (elements may be heap objects). + if let Some(src) = function.type_of(val_id).ruby_object() { + let mut alloc_size: usize = 0; + let mut flags = VALUE(0); + let mut len: std::os::raw::c_long = 0; + if unsafe { rb_zjit_array_dup_can_fastpath(src, &mut alloc_size, &mut flags, &mut len) } { + let klass = unsafe { rb_cArray }; + return gc_fastpath::gc_fastpath_new_obj(jit, asm, alloc_size, flags.as_u64(), klass, &|asm, obj| { + for i in 0..len { + let elem = unsafe { rb_ary_entry(src, i) }; + let offset = RUBY_OFFSET_RARRAY_AS_ARY + (i as i32) * SIZEOF_VALUE_I32; + asm.store(Opnd::mem(VALUE_BITS, obj, offset), Opnd::Value(elem)); + } + }, + |asm| { + gen_prepare_leaf_call_with_gc(asm, state); + asm_ccall!(asm, rb_ary_resurrect, val) + }); + } + } + gen_prepare_leaf_call_with_gc(asm, state); asm_ccall!(asm, rb_ary_resurrect, val) } diff --git a/zjit/src/codegen_tests.rs b/zjit/src/codegen_tests.rs index a0ba848f677bed..6995daa2df489f 100644 --- a/zjit/src/codegen_tests.rs +++ b/zjit/src/codegen_tests.rs @@ -3713,6 +3713,43 @@ fn test_array_dup() { "), @"[1, 2, 3]"); } +#[test] +fn test_array_dup_embedded_gc_stress() { + eval(r#" + def make = [1, 100000000000000000000, :sym] + "#); + assert_contains_opcode("make", YARVINSN_duparray); + assert_snapshot!(assert_compiles(r#" + begin + GC.stress = true + make + a = make + a << :extra + [a.frozen?, a.class, a] + ensure + GC.stress = false + end + "#), @r#"[false, Array, [1, 100000000000000000000, :sym, :extra]]"#); +} + +#[test] +fn test_array_dup_non_embedded_gc_stress() { + eval(" + def make = [10, 20, 30, 40, 50] + "); + assert_contains_opcode("make", YARVINSN_duparray); + assert_snapshot!(assert_compiles(r#" + begin + GC.stress = true + make + m = make + [m.frozen?, m] + ensure + GC.stress = false + end + "#), @"[false, [10, 20, 30, 40, 50]]"); +} + #[test] fn test_array_fixnum_aref() { eval(" diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs index 3a401fdef3bf03..4df8911d3497c3 100644 --- a/zjit/src/cruby_bindings.inc.rs +++ b/zjit/src/cruby_bindings.inc.rs @@ -2286,6 +2286,12 @@ unsafe extern "C" { len_out: *mut ::std::os::raw::c_long, byte_size_out: *mut usize, ) -> bool; + pub fn rb_zjit_array_dup_can_fastpath( + ary: VALUE, + alloc_size_out: *mut usize, + flags_out: *mut VALUE, + len_out: *mut ::std::os::raw::c_long, + ) -> bool; pub fn rb_profile_frames( start: ::std::os::raw::c_int, limit: ::std::os::raw::c_int, diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 55c07731f27f36..45ab7300b3e830 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -2238,13 +2238,13 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> { Insn::FixnumBitCheck {val, index} => { write!(f, "FixnumBitCheck {val}, {index}") }, Insn::CCall { cfunc, recv, args, name, owner, return_type: _, elidable: _ } => { let display_name = if *owner == Qnil { name.contents_lossy().to_string() } else { qualified_method_name(*owner, *name) }; - write!(f, "CCall {recv}, :{}@{:p}", display_name, self.ptr_map.map_ptr(cfunc))?; + write!(f, "CCall {recv}, :{}@{:p}", display_name, self.ptr_map.map_ptr(*cfunc))?; write_separated!(f, ", ", ", ", args); Ok(()) }, Insn::CCallWithFrame(insn) => { let CCallWithFrameData { cfunc, recv, args, name, cme, block, .. } = &**insn; - write!(f, "CCallWithFrame {recv}, :{}@{:p}", qualified_method_name(unsafe { (**cme).owner }, *name), self.ptr_map.map_ptr(cfunc))?; + write!(f, "CCallWithFrame {recv}, :{}@{:p}", qualified_method_name(unsafe { (**cme).owner }, *name), self.ptr_map.map_ptr(*cfunc))?; write_separated!(f, ", ", ", ", args); match block { Some(BlockHandler::BlockIseq(blockiseq)) => @@ -2257,7 +2257,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> { }, Insn::CCallVariadic(insn) => { let CCallVariadicData { cfunc, recv, args, name, cme, .. } = &**insn; - write!(f, "CCallVariadic {recv}, :{}@{:p}", qualified_method_name(unsafe { (**cme).owner }, *name), self.ptr_map.map_ptr(cfunc))?; + write!(f, "CCallVariadic {recv}, :{}@{:p}", qualified_method_name(unsafe { (**cme).owner }, *name), self.ptr_map.map_ptr(*cfunc))?; write_separated!(f, ", ", ", ", args); Ok(()) }, diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs index 0cee95a35629e2..376080b560951c 100644 --- a/zjit/src/hir/opt_tests.rs +++ b/zjit/src/hir/opt_tests.rs @@ -5543,7 +5543,7 @@ mod hir_opt_tests { Jump bb6(v22, v22) bb5(): v24:BasicObject = LoadField v18, :VM_ENV_DATA_INDEX_SPECVAL@0x1003 - v25:BasicObject = CCall v24, :rb_obj_is_proc@0x1008 + v25:BasicObject = CCall v24, :rb_obj_is_proc@0x1004 v26:TrueClass = GuardBitEquals v25, Value(true) recompile Jump bb6(v24, v10) bb6(v16:BasicObject, v17:BasicObject): @@ -5817,7 +5817,7 @@ mod hir_opt_tests { bb5(): v24:CInt64 = LoadField v18, :VM_ENV_DATA_INDEX_SPECVAL@0x1003 v26:BasicObject = LoadField v18, :VM_ENV_DATA_INDEX_SPECVAL@0x1003 - v27:BasicObject = CCall v26, :rb_obj_is_proc@0x1008 + v27:BasicObject = CCall v26, :rb_obj_is_proc@0x1004 v28:TrueClass = Const Value(true) v29:CBool = IsBitEqual v27, v28 CondBranch v29, bb7(), bb11() @@ -5836,7 +5836,7 @@ mod hir_opt_tests { v39:CBool = IsBitEqual v38, v37 CondBranch v39, bb9(), bb13() bb9(): - v41:ObjectSubclass[BlockParamProxy] = Const Value(VALUE(0x1010)) + v41:ObjectSubclass[BlockParamProxy] = Const Value(VALUE(0x1008)) Jump bb6(v41, v10) bb6(v16:BasicObject, v17:BasicObject): v45:BasicObject = Send v14, &block, :then, v16 # SendFallbackReason: Send: block argument is not nil @@ -9353,7 +9353,7 @@ mod hir_opt_tests { v12:CShape = LoadField v11, :shape_id@0x1000 v13:CShape[0x1001] = GuardBitEquals v12, CShape(0x1001) recompile v14:CAttrIndex[0] = Const CAttrIndex(0) - v15:BasicObject = CCall v11, :rb_ivar_get_at_no_ractor_check@0x1008, v14 + v15:BasicObject = CCall v11, :rb_ivar_get_at_no_ractor_check@0x1002, v14 CheckInterrupts Return v15 "); @@ -11648,7 +11648,7 @@ mod hir_opt_tests { v25:CallableMethodEntry[VALUE(0x1048)] = GuardBitEquals v24, Value(VALUE(0x1048)) v26:RubyValue = LoadField v23, :VM_ENV_DATA_INDEX_SPECVAL@0x1050 v27:FalseClass = GuardBitEquals v26, Value(false) - v28:BasicObject = CCallVariadic v9, :Array#[]@0x1058, v10 + v28:BasicObject = CCallVariadic v9, :Array#[]@0x1051, v10 CheckInterrupts Return v28 "); @@ -16250,7 +16250,7 @@ mod hir_opt_tests { v20:CallableMethodEntry[VALUE(0x1040)] = GuardBitEquals v19, Value(VALUE(0x1040)) v21:RubyValue = LoadField v18, :VM_ENV_DATA_INDEX_SPECVAL@0x1048 v22:FalseClass = GuardBitEquals v21, Value(false) - v23:Fixnum = CCall v6, :Hash#size@0x1050 + v23:Fixnum = CCall v6, :Hash#size@0x1049 CheckInterrupts Return v23 "); @@ -16288,7 +16288,7 @@ mod hir_opt_tests { v20:CallableMethodEntry[VALUE(0x1040)] = GuardBitEquals v19, Value(VALUE(0x1040)) v21:RubyValue = LoadField v18, :VM_ENV_DATA_INDEX_SPECVAL@0x1048 v22:FalseClass = GuardBitEquals v21, Value(false) - v23:ArrayExact = CCallWithFrame v6, :Array#reverse@0x1050 + v23:ArrayExact = CCallWithFrame v6, :Array#reverse@0x1049 CheckInterrupts Return v23 "); @@ -16341,7 +16341,7 @@ mod hir_opt_tests { v40:CallableMethodEntry[VALUE(0x1048)] = GuardBitEquals v39, Value(VALUE(0x1048)) v41:RubyValue = LoadField v38, :VM_ENV_DATA_INDEX_SPECVAL@0x1050 v42:FalseClass = GuardBitEquals v41, Value(false) - v43:StringExact = CCallVariadic v24, :Array#join@0x1058, v25 + v43:StringExact = CCallVariadic v24, :Array#join@0x1051, v25 CheckInterrupts Return v43 "); @@ -16471,7 +16471,7 @@ mod hir_opt_tests { v46:CallableMethodEntry[VALUE(0x1048)] = GuardBitEquals v45, Value(VALUE(0x1048)) v47:RubyValue = LoadField v44, :VM_ENV_DATA_INDEX_SPECVAL@0x1050 v48:FalseClass = GuardBitEquals v47, Value(false) - v49:BasicObject = CCallVariadic v28, :String#byteindex@0x1058, v29, v30 + v49:BasicObject = CCallVariadic v28, :String#byteindex@0x1051, v29, v30 CheckInterrupts Return v49 "); diff --git a/zjit/src/hir/tests.rs b/zjit/src/hir/tests.rs index d6557c05244f0a..22a6a6440d2058 100644 --- a/zjit/src/hir/tests.rs +++ b/zjit/src/hir/tests.rs @@ -16,6 +16,74 @@ mod size_tests { } } +#[cfg(test)] +mod printer_tests { + use super::*; + + fn print_same_cfunc_twice(make_insn: impl Fn() -> Insn) -> (String, String) { + let mut ptr_map = PtrPrintMap::identity(); + ptr_map.map_ptrs = true; + + // Keep both printers alive so their cloned instructions cannot reuse storage. + let first = make_insn().print(&ptr_map, None); + let second = make_insn().print(&ptr_map, None); + (format!("{first}"), format!("{second}")) + } + + #[test] + fn cfunc_pointer_printing_uses_the_pointer_value() { + let printed = crate::cruby::with_rubyvm(|| { + let cfunc = std::ptr::without_provenance::(0x1234); + let name = ID!(to_s); + let cme = unsafe { rb_callable_method_entry(rb_cInteger, name) }; + assert!(!cme.is_null()); + + let ccall = print_same_cfunc_twice(|| Insn::CCall { + cfunc, + recv: InsnId(0), + args: vec![], + name, + owner: Qnil, + return_type: types::Any, + elidable: false, + }); + let ccall_with_frame = print_same_cfunc_twice(|| { + Insn::CCallWithFrame(Box::new(CCallWithFrameData { + cd: std::ptr::null(), + cfunc, + recv: InsnId(0), + args: vec![], + cme, + name, + state: InsnId(0), + return_type: types::Any, + elidable: false, + block: None, + })) + }); + let ccall_variadic = print_same_cfunc_twice(|| { + Insn::CCallVariadic(Box::new(CCallVariadicData { + cfunc, + recv: InsnId(0), + args: vec![], + cme, + name, + state: InsnId(0), + return_type: types::Any, + elidable: false, + block: None, + })) + }); + + [ccall, ccall_with_frame, ccall_variadic] + }); + + for (first, second) in printed { + assert_eq!(first, second); + } + } +} + #[cfg(test)] mod snapshot_tests { use super::*; @@ -3790,7 +3858,7 @@ pub(crate) mod hir_build_tests { Jump bb6(v22, v22) bb5(): v24:BasicObject = LoadField v18, :VM_ENV_DATA_INDEX_SPECVAL@0x1003 - v25:BasicObject = CCall v24, :rb_obj_is_proc@0x1008 + v25:BasicObject = CCall v24, :rb_obj_is_proc@0x1004 v26:TrueClass = GuardBitEquals v25, Value(true) recompile Jump bb6(v24, v10) bb6(v16:BasicObject, v17:BasicObject): @@ -4007,7 +4075,7 @@ pub(crate) mod hir_build_tests { Jump bb10() bb10(): v26:BasicObject = LoadField v18, :VM_ENV_DATA_INDEX_SPECVAL@0x1003 - v27:BasicObject = CCall v26, :rb_obj_is_proc@0x1008 + v27:BasicObject = CCall v26, :rb_obj_is_proc@0x1004 v28:TrueClass = Const Value(true) v29:CBool = IsBitEqual v27, v28 CondBranch v29, bb7(), bb11() @@ -4026,7 +4094,7 @@ pub(crate) mod hir_build_tests { v39:CBool = IsBitEqual v38, v37 CondBranch v39, bb9(), bb13() bb9(): - v41:ObjectSubclass[BlockParamProxy] = Const Value(VALUE(0x1010)) + v41:ObjectSubclass[BlockParamProxy] = Const Value(VALUE(0x1008)) Jump bb6(v41, v10) bb6(v16:BasicObject, v17:BasicObject): v45:BasicObject = Send v14, &block, :then, v16 # SendFallbackReason: Uncategorized(send) @@ -4264,7 +4332,7 @@ pub(crate) mod hir_build_tests { Jump bb6(v25, v25) bb5(): v27:BasicObject = LoadField v21, :VM_ENV_DATA_INDEX_SPECVAL@0x1004 - v28:BasicObject = CCall v27, :rb_obj_is_proc@0x1008 + v28:BasicObject = CCall v27, :rb_obj_is_proc@0x1005 v29:TrueClass = GuardBitEquals v28, Value(true) recompile Jump bb6(v27, v13) bb6(v19:BasicObject, v20:BasicObject): @@ -4308,7 +4376,7 @@ pub(crate) mod hir_build_tests { Jump bb6(v25, v25) bb5(): v27:BasicObject = LoadField v21, :VM_ENV_DATA_INDEX_SPECVAL@0x1004 - v28:BasicObject = CCall v27, :rb_obj_is_proc@0x1008 + v28:BasicObject = CCall v27, :rb_obj_is_proc@0x1005 v29:TrueClass = GuardBitEquals v28, Value(true) recompile Jump bb6(v27, v13) bb6(v19:BasicObject, v20:BasicObject):