diff --git a/.appveyor.yml b/.appveyor.yml index 1ea5e592104a31..4eca17a210ded3 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,15 +19,12 @@ skip_commits: - '**/.document' environment: ruby_version: "24-%Platform%" - zlib_version: "1.2.12" matrix: + # Test only the oldest supported version because AppVeyor is unstable, its concurrency + # is limited, and compatibility issues that happen only in newer versions are rare. + # You may test some other stuff on GitHub Actions instead. - build: vs vs: 120 - ssl: OpenSSL - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - GEMS_FOR_TEST: "" - - build: vs - vs: 140 ssl: OpenSSL-v111 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 GEMS_FOR_TEST: "" @@ -49,7 +46,7 @@ for: - git pull -q - .\bootstrap-vcpkg.bat - cd %APPVEYOR_BUILD_FOLDER% - - vcpkg --triplet %Platform%-windows install libffi libyaml readline zlib + - vcpkg --triplet %Platform%-windows install --x-use-aria2 libffi libyaml readline zlib - CALL SET vcvars=%%^VS%VS%COMNTOOLS^%%..\..\VC\vcvarsall.bat - SET vcvars - '"%vcvars%" %Platform:x64=amd64%' @@ -69,9 +66,6 @@ for: - mkdir \usr\local\bin - mkdir \usr\local\include - mkdir \usr\local\lib - - SET ZLIB_ZIP=.downloaded-cache\zlib%zlib_version:.=%.zip - - if not exist %ZLIB_ZIP% curl -fsSL -o %ZLIB_ZIP% --retry 10 https://zlib.net/zlib%zlib_version:.=%.zip - - 7z x -aos -o%APPVEYOR_BUILD_FOLDER%\ext\zlib %ZLIB_ZIP% - for %%I in (%OPENSSL_DIR%\*.dll) do mklink /h \usr\local\bin\%%~nxI %%I - for %%I in (c:\Tools\vcpkg\installed\%Platform%-windows\bin\*.dll) do ( if not %%~nI == readline mklink \usr\local\bin\%%~nxI %%I @@ -124,7 +118,7 @@ notifications: {{^isPullRequest}} { "ci": "AppVeyor CI", - "env": "Visual Studio 2013 / 2015", + "env": "Visual Studio 2013", "url": "{{buildUrl}}", "commit": "{{commitId}}", "branch": "{{branch}}" diff --git a/.cirrus.yml b/.cirrus.yml index 854a3df98201fb..cd1654857148a2 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -39,9 +39,8 @@ task: # the `make` environment variable used in compilers.yml causes some rubygems # tests to fail. # https://github.com/rubygems/rubygems/issues/4921 - - echo "GNUMAKEFLAGS=-s -j$((1 + $CIRRUS_CPU))" >> $CIRRUS_ENV - print_env_script: - - echo "GNUMAKEFLAGS=$GNUMAKEFLAGS" + - echo "GNUMAKEFLAGS=-s -j$((1 + $CIRRUS_CPU))" >> "$CIRRUS_ENV" + - cat "$CIRRUS_ENV" # Arm containers are executed in AWS's EKS, and it's not yet supporting IPv6 # See https://github.com/aws/containers-roadmap/issues/835 disable_ipv6_script: sudo ./tool/disable_ipv6.sh @@ -99,9 +98,9 @@ yjit_task: # the `make` environment variable used in compilers.yml causes some rubygems # tests to fail. # https://github.com/rubygems/rubygems/issues/4921 - - echo "GNUMAKEFLAGS=-s -j$((1 + $CIRRUS_CPU))" >> $CIRRUS_ENV - print_env_script: - - echo "GNUMAKEFLAGS=$GNUMAKEFLAGS" + - echo "GNUMAKEFLAGS=-s -j$((1 + $CIRRUS_CPU))" >> "$CIRRUS_ENV" + - echo RUST_BACKTRACE=1 >> "$CIRRUS_ENV" + - cat "$CIRRUS_ENV" # Arm containers are executed in AWS's EKS, and it's not yet supporting IPv6 # See https://github.com/aws/containers-roadmap/issues/835 disable_ipv6_script: sudo ./tool/disable_ipv6.sh @@ -124,9 +123,9 @@ yjit_task: else echo "only running bindgen on clang image" fi - boot_miniruby_script: RUST_BACKTRACE=1 ./miniruby --yjit-call-threshold=1 -e0 - test_dump_insns_script: RUST_BACKTRACE=1 ./miniruby --yjit-call-threshold=1 --yjit-dump-insns -e0 - output_stats_script: RUST_BACKTRACE=1 ./miniruby --yjit-call-threshold=1 --yjit-stats -e0 + boot_miniruby_script: ./miniruby --yjit-call-threshold=1 -e0 + test_dump_insns_script: ./miniruby --yjit-call-threshold=1 --yjit-dump-insns -e0 + output_stats_script: ./miniruby --yjit-call-threshold=1 --yjit-stats -e0 full_build_script: source $HOME/.cargo/env && make cargo_test_script: source $HOME/.cargo/env && cd yjit && cargo test make_test_script: source $HOME/.cargo/env && make test RUN_OPTS="--yjit-call-threshold=1 --yjit-verify-ctx" diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b18fd293573676..97adcabffe111f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,3 +4,6 @@ updates: directory: '/' schedule: interval: 'weekly' + ignore: + # It doesn't update the version comment for us + - dependency-name: 'necojackarc/auto-request-review' diff --git a/.github/workflows/auto_request_review.yml b/.github/workflows/auto_request_review.yml index 7e163de6978893..8275927fd337a2 100644 --- a/.github/workflows/auto_request_review.yml +++ b/.github/workflows/auto_request_review.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Request review based on files changes and/or groups the author belongs to - uses: necojackarc/auto-request-review@e08cdffa277d50854744de3f76230260e61c67f4 # v0.7.0, checking sha + uses: necojackarc/auto-request-review@b5e81876454003a4ccb9b89cb205c67d77d7035b # v0.8.0, checking sha with: # scope: public_repo token: ${{ secrets.MATZBOT_GITHUB_TOKEN }} diff --git a/.github/workflows/baseruby.yml b/.github/workflows/baseruby.yml index 1c314da9117e45..65d2813ac23a5c 100644 --- a/.github/workflows/baseruby.yml +++ b/.github/workflows/baseruby.yml @@ -6,11 +6,17 @@ on: - 'doc/**' - '**.md' - '**.rdoc' + - '**/.document' + - '**.[1-8]' + - '**.ronn' pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rdoc' + - '**/.document' + - '**.[1-8]' + - '**.ronn' concurrency: group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }} diff --git a/.github/workflows/bundled_gems.yml b/.github/workflows/bundled_gems.yml index f6f8b9a45b14cf..471f32b25f018d 100644 --- a/.github/workflows/bundled_gems.yml +++ b/.github/workflows/bundled_gems.yml @@ -11,6 +11,7 @@ on: - 'gems/bundled_gems' schedule: - cron: '45 6 * * *' + workflow_dispatch: jobs: update: diff --git a/.github/workflows/check_dependencies.yml b/.github/workflows/check_dependencies.yml index fab198933518ad..1753f4657409cb 100644 --- a/.github/workflows/check_dependencies.yml +++ b/.github/workflows/check_dependencies.yml @@ -6,12 +6,16 @@ on: - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' concurrency: group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index f9fa0a74490162..85b11e90e72ea2 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -7,12 +7,16 @@ on: - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' schedule: - cron: '0 12 * * 4' @@ -25,7 +29,8 @@ jobs: # CodeQL runs on ubuntu-latest and windows-latest runs-on: ubuntu-latest - if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }} + # CodeQL fails to run pull requests from dependabot due to missing write access to upload results. + if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') && github.event.head_commit.pusher.name != 'dependabot[bot]' }} env: enable_install_doc: no diff --git a/.github/workflows/compilers.yml b/.github/workflows/compilers.yml index 70d0e3ae6ca08b..8080963fa6303a 100644 --- a/.github/workflows/compilers.yml +++ b/.github/workflows/compilers.yml @@ -7,12 +7,16 @@ on: - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' concurrency: group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }} diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 72f28a7b615baf..04446d3f053bcd 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -6,12 +6,16 @@ on: - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' concurrency: group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }} diff --git a/.github/workflows/mingw.yml b/.github/workflows/mingw.yml index 020295baa12189..5c8189428ca177 100644 --- a/.github/workflows/mingw.yml +++ b/.github/workflows/mingw.yml @@ -6,12 +6,16 @@ on: - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' concurrency: group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }} @@ -37,10 +41,7 @@ jobs: strategy: matrix: include: - - msystem: "MINGW64" - base_ruby: 2.6 - test_task: "check" - test-all-opts: "--name=!/TestObjSpace#test_reachable_objects_during_iteration/" + # To mitigate flakiness of MinGW CI, we test only one runtime that newer MSYS2 uses. - msystem: "UCRT64" base_ruby: head test_task: "check" diff --git a/.github/workflows/mjit-bindgen.yml b/.github/workflows/mjit-bindgen.yml index 04c9ac4a9f2ade..e1d22d91f2d92f 100644 --- a/.github/workflows/mjit-bindgen.yml +++ b/.github/workflows/mjit-bindgen.yml @@ -6,12 +6,16 @@ on: - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' concurrency: group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }} diff --git a/.github/workflows/mjit.yml b/.github/workflows/mjit.yml index b5065288c70c88..89bc0a226becff 100644 --- a/.github/workflows/mjit.yml +++ b/.github/workflows/mjit.yml @@ -6,12 +6,16 @@ on: - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' concurrency: group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }} diff --git a/.github/workflows/spec_guards.yml b/.github/workflows/spec_guards.yml index 7bffe25bb26610..6d51320c2f969e 100644 --- a/.github/workflows/spec_guards.yml +++ b/.github/workflows/spec_guards.yml @@ -7,12 +7,16 @@ on: - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' concurrency: group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }} diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index a1818182a34beb..1a5b6661fe1f8a 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -6,12 +6,16 @@ on: - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' concurrency: group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }} diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 553347d727ad86..6999ea5882b219 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -6,12 +6,16 @@ on: - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' concurrency: group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index ab9e35d5a303ba..6f5106e815639c 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -6,12 +6,16 @@ on: - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' concurrency: group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }} diff --git a/.github/workflows/yjit-ubuntu.yml b/.github/workflows/yjit-ubuntu.yml index ae108d72a5bbbc..176181f11c5b3e 100644 --- a/.github/workflows/yjit-ubuntu.yml +++ b/.github/workflows/yjit-ubuntu.yml @@ -6,12 +6,16 @@ on: - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rdoc' - '**/.document' + - '**.[1-8]' + - '**.ronn' concurrency: group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }} diff --git a/NEWS.md b/NEWS.md index a355d91d7d43d2..3d618c5abb230d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -102,6 +102,9 @@ Note that each entry is kept to a minimum, see links for details. Note: We're only listing outstanding class updates. +* Fiber::Scheduler + * Introduce `Fiber::Scheduler#io_select` for non-blocking `IO.select`. [[Feature #19060]] + * IO * Introduce `IO#timeout=` and `IO#timeout` which can cause `IO::TimeoutError` to be raised if a blocking operation exceeds the @@ -212,6 +215,7 @@ Note: We're only listing outstanding class updates. * date 3.2.3 * error_highlight 0.4.0 * etc 1.4.0 + * fiddle 1.1.1 * io-console 0.5.11 * io-nonblock 0.1.1 * io-wait 0.3.0.pre @@ -221,6 +225,7 @@ Note: We're only listing outstanding class updates. * logger 1.5.1 * net-http 0.2.2 * net-protocol 0.1.3 + * openssl 3.1.0.pre * ostruct 0.5.5 * psych 5.0.0.dev * reline 0.3.1 @@ -231,6 +236,7 @@ Note: We're only listing outstanding class updates. * timeout 0.3.0 * The following bundled gems are updated. * minitest 5.16.3 + * power_assert 2.0.2 * test-unit 3.5.5 * net-ftp 0.2.0 * net-imap 0.3.1 @@ -354,3 +360,4 @@ The following deprecated APIs are removed. [Feature #16122]: https://bugs.ruby-lang.org/issues/16122 [Feature #18630]: https://bugs.ruby-lang.org/issues/18630 [Feature #18589]: https://bugs.ruby-lang.org/issues/18589 +[Feature #19060]: https://bugs.ruby-lang.org/issues/19060 diff --git a/array.c b/array.c index 73e8a3c9ce4c6d..a33c43bdbf258e 100644 --- a/array.c +++ b/array.c @@ -1389,7 +1389,7 @@ ary_make_partial_step(VALUE ary, VALUE klass, long offset, long len, long step) } long ustep = (step < 0) ? -step : step; - len = (len + ustep - 1) / ustep; + len = roomof(len, ustep); long i; long j = offset + ((step > 0) ? 0 : (orig_len - 1)); diff --git a/bignum.c b/bignum.c index 9901a807b1936d..4f8349dd17d457 100644 --- a/bignum.c +++ b/bignum.c @@ -977,7 +977,7 @@ integer_unpack_num_bdigits_small(size_t numwords, size_t wordsize, size_t nails, { /* nlp_bits stands for number of leading padding bits */ size_t num_bits = (wordsize * CHAR_BIT - nails) * numwords; - size_t num_bdigits = (num_bits + BITSPERDIG - 1) / BITSPERDIG; + size_t num_bdigits = roomof(num_bits, BITSPERDIG); *nlp_bits_ret = (int)(num_bdigits * BITSPERDIG - num_bits); return num_bdigits; } @@ -987,7 +987,7 @@ integer_unpack_num_bdigits_generic(size_t numwords, size_t wordsize, size_t nail { /* BITSPERDIG = SIZEOF_BDIGIT * CHAR_BIT */ /* num_bits = (wordsize * CHAR_BIT - nails) * numwords */ - /* num_bdigits = (num_bits + BITSPERDIG - 1) / BITSPERDIG */ + /* num_bdigits = roomof(num_bits, BITSPERDIG) */ /* num_bits = CHAR_BIT * (wordsize * numwords) - nails * numwords = CHAR_BIT * num_bytes1 - nails * numwords */ size_t num_bytes1 = wordsize * numwords; diff --git a/bootstraptest/test_attr.rb b/bootstraptest/test_attr.rb index 721a847145a797..3cb9d3eb39541c 100644 --- a/bootstraptest/test_attr.rb +++ b/bootstraptest/test_attr.rb @@ -34,3 +34,19 @@ class A print "ok" end }, '[ruby-core:15120]' + +assert_equal %{ok}, %{ + class Big + attr_reader :foo + def initialize + @foo = "ok" + end + end + + obj = Big.new + 100.times do |i| + obj.instance_variable_set(:"@ivar_\#{i}", i) + end + + Big.new.foo +} diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb index 12d0fff5a642e1..bfe245116eabd2 100644 --- a/bootstraptest/test_ractor.rb +++ b/bootstraptest/test_ractor.rb @@ -1581,4 +1581,43 @@ def foo((x), (y)); ->{ super }; end end } +assert_equal "ok", %q{ + module M + def foo + @foo + end + end + + class A + include M + + def initialize + 100.times { |i| instance_variable_set(:"@var_#{i}", "bad: #{i}") } + @foo = 2 + end + end + + class B + include M + + def initialize + @foo = 1 + end + end + + Ractor.new do + b = B.new + 100_000.times do + raise unless b.foo == 1 + end + end + + a = A.new + 100_000.times do + raise unless a.foo == 2 + end + + "ok" +} + end # if !ENV['GITHUB_WORKFLOW'] diff --git a/class.c b/class.c index 3a83a7f052e0f2..7a32951e601ffc 100644 --- a/class.c +++ b/class.c @@ -1639,10 +1639,7 @@ ins_methods_pub_i(st_data_t name, st_data_t type, st_data_t ary) static int ins_methods_undef_i(st_data_t name, st_data_t type, st_data_t ary) { - if ((rb_method_visibility_t)type == METHOD_VISI_UNDEF) { - ins_methods_push(name, ary); - } - return ST_CONTINUE; + return ins_methods_type_i(name, type, ary, METHOD_VISI_UNDEF); } struct method_entry_arg { diff --git a/common.mk b/common.mk index e674fd7d5e5f93..b547c0f30a50f8 100644 --- a/common.mk +++ b/common.mk @@ -136,6 +136,7 @@ COMMONOBJS = array.$(OBJEXT) \ regsyntax.$(OBJEXT) \ ruby.$(OBJEXT) \ scheduler.$(OBJEXT) \ + shape.$(OBJEXT) \ signal.$(OBJEXT) \ sprintf.$(OBJEXT) \ st.$(OBJEXT) \ @@ -1832,6 +1833,7 @@ array.$(OBJEXT): $(top_srcdir)/internal/proc.h array.$(OBJEXT): $(top_srcdir)/internal/rational.h array.$(OBJEXT): $(top_srcdir)/internal/serial.h array.$(OBJEXT): $(top_srcdir)/internal/static_assert.h +array.$(OBJEXT): $(top_srcdir)/internal/variable.h array.$(OBJEXT): $(top_srcdir)/internal/vm.h array.$(OBJEXT): $(top_srcdir)/internal/warnings.h array.$(OBJEXT): {$(VPATH)}array.c @@ -1848,6 +1850,7 @@ array.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h array.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h array.$(OBJEXT): {$(VPATH)}builtin.h array.$(OBJEXT): {$(VPATH)}config.h +array.$(OBJEXT): {$(VPATH)}constant.h array.$(OBJEXT): {$(VPATH)}debug_counter.h array.$(OBJEXT): {$(VPATH)}defines.h array.$(OBJEXT): {$(VPATH)}encoding.h @@ -2010,6 +2013,7 @@ array.$(OBJEXT): {$(VPATH)}oniguruma.h array.$(OBJEXT): {$(VPATH)}probes.dmyh array.$(OBJEXT): {$(VPATH)}probes.h array.$(OBJEXT): {$(VPATH)}ruby_assert.h +array.$(OBJEXT): {$(VPATH)}shape.h array.$(OBJEXT): {$(VPATH)}st.h array.$(OBJEXT): {$(VPATH)}subst.h array.$(OBJEXT): {$(VPATH)}transient_heap.h @@ -2028,6 +2032,7 @@ ast.$(OBJEXT): $(top_srcdir)/internal/parse.h ast.$(OBJEXT): $(top_srcdir)/internal/serial.h ast.$(OBJEXT): $(top_srcdir)/internal/static_assert.h ast.$(OBJEXT): $(top_srcdir)/internal/symbol.h +ast.$(OBJEXT): $(top_srcdir)/internal/variable.h ast.$(OBJEXT): $(top_srcdir)/internal/vm.h ast.$(OBJEXT): $(top_srcdir)/internal/warnings.h ast.$(OBJEXT): {$(VPATH)}assert.h @@ -2045,9 +2050,11 @@ ast.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h ast.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h ast.$(OBJEXT): {$(VPATH)}builtin.h ast.$(OBJEXT): {$(VPATH)}config.h +ast.$(OBJEXT): {$(VPATH)}constant.h ast.$(OBJEXT): {$(VPATH)}defines.h ast.$(OBJEXT): {$(VPATH)}encoding.h ast.$(OBJEXT): {$(VPATH)}id.h +ast.$(OBJEXT): {$(VPATH)}id_table.h ast.$(OBJEXT): {$(VPATH)}intern.h ast.$(OBJEXT): {$(VPATH)}internal.h ast.$(OBJEXT): {$(VPATH)}internal/abi.h @@ -2207,6 +2214,7 @@ ast.$(OBJEXT): {$(VPATH)}onigmo.h ast.$(OBJEXT): {$(VPATH)}oniguruma.h ast.$(OBJEXT): {$(VPATH)}ruby_assert.h ast.$(OBJEXT): {$(VPATH)}ruby_atomic.h +ast.$(OBJEXT): {$(VPATH)}shape.h ast.$(OBJEXT): {$(VPATH)}st.h ast.$(OBJEXT): {$(VPATH)}subst.h ast.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -2390,6 +2398,7 @@ bignum.$(OBJEXT): {$(VPATH)}internal/warning_push.h bignum.$(OBJEXT): {$(VPATH)}internal/xmalloc.h bignum.$(OBJEXT): {$(VPATH)}missing.h bignum.$(OBJEXT): {$(VPATH)}ruby_assert.h +bignum.$(OBJEXT): {$(VPATH)}shape.h bignum.$(OBJEXT): {$(VPATH)}st.h bignum.$(OBJEXT): {$(VPATH)}subst.h bignum.$(OBJEXT): {$(VPATH)}thread.h @@ -2405,6 +2414,7 @@ builtin.$(OBJEXT): $(top_srcdir)/internal/gc.h builtin.$(OBJEXT): $(top_srcdir)/internal/imemo.h builtin.$(OBJEXT): $(top_srcdir)/internal/serial.h builtin.$(OBJEXT): $(top_srcdir)/internal/static_assert.h +builtin.$(OBJEXT): $(top_srcdir)/internal/variable.h builtin.$(OBJEXT): $(top_srcdir)/internal/vm.h builtin.$(OBJEXT): $(top_srcdir)/internal/warnings.h builtin.$(OBJEXT): {$(VPATH)}assert.h @@ -2422,8 +2432,10 @@ builtin.$(OBJEXT): {$(VPATH)}builtin.c builtin.$(OBJEXT): {$(VPATH)}builtin.h builtin.$(OBJEXT): {$(VPATH)}builtin_binary.inc builtin.$(OBJEXT): {$(VPATH)}config.h +builtin.$(OBJEXT): {$(VPATH)}constant.h builtin.$(OBJEXT): {$(VPATH)}defines.h builtin.$(OBJEXT): {$(VPATH)}id.h +builtin.$(OBJEXT): {$(VPATH)}id_table.h builtin.$(OBJEXT): {$(VPATH)}intern.h builtin.$(OBJEXT): {$(VPATH)}internal.h builtin.$(OBJEXT): {$(VPATH)}internal/abi.h @@ -2572,6 +2584,7 @@ builtin.$(OBJEXT): {$(VPATH)}missing.h builtin.$(OBJEXT): {$(VPATH)}node.h builtin.$(OBJEXT): {$(VPATH)}ruby_assert.h builtin.$(OBJEXT): {$(VPATH)}ruby_atomic.h +builtin.$(OBJEXT): {$(VPATH)}shape.h builtin.$(OBJEXT): {$(VPATH)}st.h builtin.$(OBJEXT): {$(VPATH)}subst.h builtin.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -2774,6 +2787,7 @@ class.$(OBJEXT): {$(VPATH)}onigmo.h class.$(OBJEXT): {$(VPATH)}oniguruma.h class.$(OBJEXT): {$(VPATH)}ruby_assert.h class.$(OBJEXT): {$(VPATH)}ruby_atomic.h +class.$(OBJEXT): {$(VPATH)}shape.h class.$(OBJEXT): {$(VPATH)}st.h class.$(OBJEXT): {$(VPATH)}subst.h class.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -3177,6 +3191,7 @@ compile.$(OBJEXT): {$(VPATH)}re.h compile.$(OBJEXT): {$(VPATH)}regex.h compile.$(OBJEXT): {$(VPATH)}ruby_assert.h compile.$(OBJEXT): {$(VPATH)}ruby_atomic.h +compile.$(OBJEXT): {$(VPATH)}shape.h compile.$(OBJEXT): {$(VPATH)}st.h compile.$(OBJEXT): {$(VPATH)}subst.h compile.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -3201,6 +3216,7 @@ complex.$(OBJEXT): $(top_srcdir)/internal/object.h complex.$(OBJEXT): $(top_srcdir)/internal/rational.h complex.$(OBJEXT): $(top_srcdir)/internal/serial.h complex.$(OBJEXT): $(top_srcdir)/internal/static_assert.h +complex.$(OBJEXT): $(top_srcdir)/internal/variable.h complex.$(OBJEXT): $(top_srcdir)/internal/vm.h complex.$(OBJEXT): $(top_srcdir)/internal/warnings.h complex.$(OBJEXT): {$(VPATH)}assert.h @@ -3215,6 +3231,7 @@ complex.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h complex.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h complex.$(OBJEXT): {$(VPATH)}complex.c complex.$(OBJEXT): {$(VPATH)}config.h +complex.$(OBJEXT): {$(VPATH)}constant.h complex.$(OBJEXT): {$(VPATH)}defines.h complex.$(OBJEXT): {$(VPATH)}id.h complex.$(OBJEXT): {$(VPATH)}id_table.h @@ -3362,6 +3379,7 @@ complex.$(OBJEXT): {$(VPATH)}internal/warning_push.h complex.$(OBJEXT): {$(VPATH)}internal/xmalloc.h complex.$(OBJEXT): {$(VPATH)}missing.h complex.$(OBJEXT): {$(VPATH)}ruby_assert.h +complex.$(OBJEXT): {$(VPATH)}shape.h complex.$(OBJEXT): {$(VPATH)}st.h complex.$(OBJEXT): {$(VPATH)}subst.h cont.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h @@ -3379,6 +3397,7 @@ cont.$(OBJEXT): $(top_srcdir)/internal/proc.h cont.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h cont.$(OBJEXT): $(top_srcdir)/internal/serial.h cont.$(OBJEXT): $(top_srcdir)/internal/static_assert.h +cont.$(OBJEXT): $(top_srcdir)/internal/variable.h cont.$(OBJEXT): $(top_srcdir)/internal/vm.h cont.$(OBJEXT): $(top_srcdir)/internal/warnings.h cont.$(OBJEXT): {$(VPATH)}$(COROUTINE_H) @@ -3394,6 +3413,7 @@ cont.$(OBJEXT): {$(VPATH)}backward/2/long_long.h cont.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h cont.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h cont.$(OBJEXT): {$(VPATH)}config.h +cont.$(OBJEXT): {$(VPATH)}constant.h cont.$(OBJEXT): {$(VPATH)}cont.c cont.$(OBJEXT): {$(VPATH)}debug_counter.h cont.$(OBJEXT): {$(VPATH)}defines.h @@ -3544,6 +3564,7 @@ cont.$(OBJEXT): {$(VPATH)}internal/value_type.h cont.$(OBJEXT): {$(VPATH)}internal/variable.h cont.$(OBJEXT): {$(VPATH)}internal/warning_push.h cont.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +cont.$(OBJEXT): {$(VPATH)}iseq.h cont.$(OBJEXT): {$(VPATH)}method.h cont.$(OBJEXT): {$(VPATH)}missing.h cont.$(OBJEXT): {$(VPATH)}mjit.h @@ -3552,6 +3573,7 @@ cont.$(OBJEXT): {$(VPATH)}ractor.h cont.$(OBJEXT): {$(VPATH)}ractor_core.h cont.$(OBJEXT): {$(VPATH)}ruby_assert.h cont.$(OBJEXT): {$(VPATH)}ruby_atomic.h +cont.$(OBJEXT): {$(VPATH)}shape.h cont.$(OBJEXT): {$(VPATH)}st.h cont.$(OBJEXT): {$(VPATH)}subst.h cont.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -3559,6 +3581,8 @@ cont.$(OBJEXT): {$(VPATH)}thread_native.h cont.$(OBJEXT): {$(VPATH)}vm_core.h cont.$(OBJEXT): {$(VPATH)}vm_debug.h cont.$(OBJEXT): {$(VPATH)}vm_opts.h +cont.$(OBJEXT): {$(VPATH)}vm_sync.h +cont.$(OBJEXT): {$(VPATH)}yjit.h debug.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h debug.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h debug.$(OBJEXT): $(CCAN_DIR)/list/list.h @@ -3572,6 +3596,7 @@ debug.$(OBJEXT): $(top_srcdir)/internal/imemo.h debug.$(OBJEXT): $(top_srcdir)/internal/serial.h debug.$(OBJEXT): $(top_srcdir)/internal/signal.h debug.$(OBJEXT): $(top_srcdir)/internal/static_assert.h +debug.$(OBJEXT): $(top_srcdir)/internal/variable.h debug.$(OBJEXT): $(top_srcdir)/internal/vm.h debug.$(OBJEXT): $(top_srcdir)/internal/warnings.h debug.$(OBJEXT): {$(VPATH)}assert.h @@ -3586,6 +3611,7 @@ debug.$(OBJEXT): {$(VPATH)}backward/2/long_long.h debug.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h debug.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h debug.$(OBJEXT): {$(VPATH)}config.h +debug.$(OBJEXT): {$(VPATH)}constant.h debug.$(OBJEXT): {$(VPATH)}debug.c debug.$(OBJEXT): {$(VPATH)}debug_counter.h debug.$(OBJEXT): {$(VPATH)}defines.h @@ -3756,6 +3782,7 @@ debug.$(OBJEXT): {$(VPATH)}ractor.h debug.$(OBJEXT): {$(VPATH)}ractor_core.h debug.$(OBJEXT): {$(VPATH)}ruby_assert.h debug.$(OBJEXT): {$(VPATH)}ruby_atomic.h +debug.$(OBJEXT): {$(VPATH)}shape.h debug.$(OBJEXT): {$(VPATH)}st.h debug.$(OBJEXT): {$(VPATH)}subst.h debug.$(OBJEXT): {$(VPATH)}symbol.h @@ -3940,6 +3967,7 @@ dir.$(OBJEXT): $(top_srcdir)/internal/object.h dir.$(OBJEXT): $(top_srcdir)/internal/serial.h dir.$(OBJEXT): $(top_srcdir)/internal/static_assert.h dir.$(OBJEXT): $(top_srcdir)/internal/string.h +dir.$(OBJEXT): $(top_srcdir)/internal/variable.h dir.$(OBJEXT): $(top_srcdir)/internal/vm.h dir.$(OBJEXT): $(top_srcdir)/internal/warnings.h dir.$(OBJEXT): {$(VPATH)}assert.h @@ -3954,6 +3982,7 @@ dir.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h dir.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h dir.$(OBJEXT): {$(VPATH)}builtin.h dir.$(OBJEXT): {$(VPATH)}config.h +dir.$(OBJEXT): {$(VPATH)}constant.h dir.$(OBJEXT): {$(VPATH)}defines.h dir.$(OBJEXT): {$(VPATH)}dir.c dir.$(OBJEXT): {$(VPATH)}dir.rbinc @@ -4116,6 +4145,7 @@ dir.$(OBJEXT): {$(VPATH)}io.h dir.$(OBJEXT): {$(VPATH)}missing.h dir.$(OBJEXT): {$(VPATH)}onigmo.h dir.$(OBJEXT): {$(VPATH)}oniguruma.h +dir.$(OBJEXT): {$(VPATH)}shape.h dir.$(OBJEXT): {$(VPATH)}st.h dir.$(OBJEXT): {$(VPATH)}subst.h dir.$(OBJEXT): {$(VPATH)}thread.h @@ -5441,6 +5471,7 @@ encoding.$(OBJEXT): $(top_srcdir)/internal/object.h encoding.$(OBJEXT): $(top_srcdir)/internal/serial.h encoding.$(OBJEXT): $(top_srcdir)/internal/static_assert.h encoding.$(OBJEXT): $(top_srcdir)/internal/string.h +encoding.$(OBJEXT): $(top_srcdir)/internal/variable.h encoding.$(OBJEXT): $(top_srcdir)/internal/vm.h encoding.$(OBJEXT): $(top_srcdir)/internal/warnings.h encoding.$(OBJEXT): {$(VPATH)}assert.h @@ -5454,6 +5485,7 @@ encoding.$(OBJEXT): {$(VPATH)}backward/2/long_long.h encoding.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h encoding.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h encoding.$(OBJEXT): {$(VPATH)}config.h +encoding.$(OBJEXT): {$(VPATH)}constant.h encoding.$(OBJEXT): {$(VPATH)}debug_counter.h encoding.$(OBJEXT): {$(VPATH)}defines.h encoding.$(OBJEXT): {$(VPATH)}encindex.h @@ -5616,6 +5648,7 @@ encoding.$(OBJEXT): {$(VPATH)}onigmo.h encoding.$(OBJEXT): {$(VPATH)}oniguruma.h encoding.$(OBJEXT): {$(VPATH)}regenc.h encoding.$(OBJEXT): {$(VPATH)}ruby_assert.h +encoding.$(OBJEXT): {$(VPATH)}shape.h encoding.$(OBJEXT): {$(VPATH)}st.h encoding.$(OBJEXT): {$(VPATH)}subst.h encoding.$(OBJEXT): {$(VPATH)}util.h @@ -5640,6 +5673,7 @@ enum.$(OBJEXT): $(top_srcdir)/internal/rational.h enum.$(OBJEXT): $(top_srcdir)/internal/re.h enum.$(OBJEXT): $(top_srcdir)/internal/serial.h enum.$(OBJEXT): $(top_srcdir)/internal/static_assert.h +enum.$(OBJEXT): $(top_srcdir)/internal/variable.h enum.$(OBJEXT): $(top_srcdir)/internal/vm.h enum.$(OBJEXT): $(top_srcdir)/internal/warnings.h enum.$(OBJEXT): {$(VPATH)}assert.h @@ -5653,6 +5687,7 @@ enum.$(OBJEXT): {$(VPATH)}backward/2/long_long.h enum.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h enum.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h enum.$(OBJEXT): {$(VPATH)}config.h +enum.$(OBJEXT): {$(VPATH)}constant.h enum.$(OBJEXT): {$(VPATH)}defines.h enum.$(OBJEXT): {$(VPATH)}encoding.h enum.$(OBJEXT): {$(VPATH)}enum.c @@ -5813,6 +5848,7 @@ enum.$(OBJEXT): {$(VPATH)}missing.h enum.$(OBJEXT): {$(VPATH)}onigmo.h enum.$(OBJEXT): {$(VPATH)}oniguruma.h enum.$(OBJEXT): {$(VPATH)}ruby_assert.h +enum.$(OBJEXT): {$(VPATH)}shape.h enum.$(OBJEXT): {$(VPATH)}st.h enum.$(OBJEXT): {$(VPATH)}subst.h enum.$(OBJEXT): {$(VPATH)}symbol.h @@ -6212,6 +6248,7 @@ error.$(OBJEXT): {$(VPATH)}onigmo.h error.$(OBJEXT): {$(VPATH)}oniguruma.h error.$(OBJEXT): {$(VPATH)}ruby_assert.h error.$(OBJEXT): {$(VPATH)}ruby_atomic.h +error.$(OBJEXT): {$(VPATH)}shape.h error.$(OBJEXT): {$(VPATH)}st.h error.$(OBJEXT): {$(VPATH)}subst.h error.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -6228,6 +6265,7 @@ eval.$(OBJEXT): $(hdrdir)/ruby/ruby.h eval.$(OBJEXT): $(top_srcdir)/internal/array.h eval.$(OBJEXT): $(top_srcdir)/internal/class.h eval.$(OBJEXT): $(top_srcdir)/internal/compilers.h +eval.$(OBJEXT): $(top_srcdir)/internal/cont.h eval.$(OBJEXT): $(top_srcdir)/internal/error.h eval.$(OBJEXT): $(top_srcdir)/internal/eval.h eval.$(OBJEXT): $(top_srcdir)/internal/gc.h @@ -6433,6 +6471,7 @@ eval.$(OBJEXT): {$(VPATH)}ractor.h eval.$(OBJEXT): {$(VPATH)}ractor_core.h eval.$(OBJEXT): {$(VPATH)}ruby_assert.h eval.$(OBJEXT): {$(VPATH)}ruby_atomic.h +eval.$(OBJEXT): {$(VPATH)}shape.h eval.$(OBJEXT): {$(VPATH)}st.h eval.$(OBJEXT): {$(VPATH)}subst.h eval.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -6473,6 +6512,7 @@ file.$(OBJEXT): $(top_srcdir)/internal/serial.h file.$(OBJEXT): $(top_srcdir)/internal/static_assert.h file.$(OBJEXT): $(top_srcdir)/internal/string.h file.$(OBJEXT): $(top_srcdir)/internal/thread.h +file.$(OBJEXT): $(top_srcdir)/internal/variable.h file.$(OBJEXT): $(top_srcdir)/internal/vm.h file.$(OBJEXT): $(top_srcdir)/internal/warnings.h file.$(OBJEXT): {$(VPATH)}assert.h @@ -6486,6 +6526,7 @@ file.$(OBJEXT): {$(VPATH)}backward/2/long_long.h file.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h file.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h file.$(OBJEXT): {$(VPATH)}config.h +file.$(OBJEXT): {$(VPATH)}constant.h file.$(OBJEXT): {$(VPATH)}defines.h file.$(OBJEXT): {$(VPATH)}dln.h file.$(OBJEXT): {$(VPATH)}encindex.h @@ -6648,6 +6689,7 @@ file.$(OBJEXT): {$(VPATH)}io.h file.$(OBJEXT): {$(VPATH)}missing.h file.$(OBJEXT): {$(VPATH)}onigmo.h file.$(OBJEXT): {$(VPATH)}oniguruma.h +file.$(OBJEXT): {$(VPATH)}shape.h file.$(OBJEXT): {$(VPATH)}st.h file.$(OBJEXT): {$(VPATH)}subst.h file.$(OBJEXT): {$(VPATH)}thread.h @@ -6864,6 +6906,7 @@ gc.$(OBJEXT): {$(VPATH)}internal/variable.h gc.$(OBJEXT): {$(VPATH)}internal/warning_push.h gc.$(OBJEXT): {$(VPATH)}internal/xmalloc.h gc.$(OBJEXT): {$(VPATH)}io.h +gc.$(OBJEXT): {$(VPATH)}iseq.h gc.$(OBJEXT): {$(VPATH)}method.h gc.$(OBJEXT): {$(VPATH)}missing.h gc.$(OBJEXT): {$(VPATH)}mjit.h @@ -6880,6 +6923,7 @@ gc.$(OBJEXT): {$(VPATH)}regex.h gc.$(OBJEXT): {$(VPATH)}regint.h gc.$(OBJEXT): {$(VPATH)}ruby_assert.h gc.$(OBJEXT): {$(VPATH)}ruby_atomic.h +gc.$(OBJEXT): {$(VPATH)}shape.h gc.$(OBJEXT): {$(VPATH)}st.h gc.$(OBJEXT): {$(VPATH)}subst.h gc.$(OBJEXT): {$(VPATH)}symbol.h @@ -6905,6 +6949,7 @@ goruby.$(OBJEXT): $(top_srcdir)/internal/gc.h goruby.$(OBJEXT): $(top_srcdir)/internal/imemo.h goruby.$(OBJEXT): $(top_srcdir)/internal/serial.h goruby.$(OBJEXT): $(top_srcdir)/internal/static_assert.h +goruby.$(OBJEXT): $(top_srcdir)/internal/variable.h goruby.$(OBJEXT): $(top_srcdir)/internal/vm.h goruby.$(OBJEXT): $(top_srcdir)/internal/warnings.h goruby.$(OBJEXT): {$(VPATH)}assert.h @@ -6920,11 +6965,13 @@ goruby.$(OBJEXT): {$(VPATH)}backward/2/long_long.h goruby.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h goruby.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h goruby.$(OBJEXT): {$(VPATH)}config.h +goruby.$(OBJEXT): {$(VPATH)}constant.h goruby.$(OBJEXT): {$(VPATH)}defines.h goruby.$(OBJEXT): {$(VPATH)}golf_prelude.c goruby.$(OBJEXT): {$(VPATH)}golf_prelude.rb goruby.$(OBJEXT): {$(VPATH)}goruby.c goruby.$(OBJEXT): {$(VPATH)}id.h +goruby.$(OBJEXT): {$(VPATH)}id_table.h goruby.$(OBJEXT): {$(VPATH)}intern.h goruby.$(OBJEXT): {$(VPATH)}internal.h goruby.$(OBJEXT): {$(VPATH)}internal/abi.h @@ -7074,6 +7121,7 @@ goruby.$(OBJEXT): {$(VPATH)}missing.h goruby.$(OBJEXT): {$(VPATH)}node.h goruby.$(OBJEXT): {$(VPATH)}ruby_assert.h goruby.$(OBJEXT): {$(VPATH)}ruby_atomic.h +goruby.$(OBJEXT): {$(VPATH)}shape.h goruby.$(OBJEXT): {$(VPATH)}st.h goruby.$(OBJEXT): {$(VPATH)}subst.h goruby.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -7081,6 +7129,10 @@ goruby.$(OBJEXT): {$(VPATH)}thread_native.h goruby.$(OBJEXT): {$(VPATH)}vm_core.h goruby.$(OBJEXT): {$(VPATH)}vm_debug.h goruby.$(OBJEXT): {$(VPATH)}vm_opts.h +hash.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h +hash.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h +hash.$(OBJEXT): $(CCAN_DIR)/list/list.h +hash.$(OBJEXT): $(CCAN_DIR)/str/str.h hash.$(OBJEXT): $(hdrdir)/ruby/ruby.h hash.$(OBJEXT): $(top_srcdir)/internal/array.h hash.$(OBJEXT): $(top_srcdir)/internal/bignum.h @@ -7091,6 +7143,7 @@ hash.$(OBJEXT): $(top_srcdir)/internal/cont.h hash.$(OBJEXT): $(top_srcdir)/internal/error.h hash.$(OBJEXT): $(top_srcdir)/internal/gc.h hash.$(OBJEXT): $(top_srcdir)/internal/hash.h +hash.$(OBJEXT): $(top_srcdir)/internal/imemo.h hash.$(OBJEXT): $(top_srcdir)/internal/object.h hash.$(OBJEXT): $(top_srcdir)/internal/proc.h hash.$(OBJEXT): $(top_srcdir)/internal/serial.h @@ -7099,9 +7152,11 @@ hash.$(OBJEXT): $(top_srcdir)/internal/string.h hash.$(OBJEXT): $(top_srcdir)/internal/symbol.h hash.$(OBJEXT): $(top_srcdir)/internal/thread.h hash.$(OBJEXT): $(top_srcdir)/internal/time.h +hash.$(OBJEXT): $(top_srcdir)/internal/variable.h hash.$(OBJEXT): $(top_srcdir)/internal/vm.h hash.$(OBJEXT): $(top_srcdir)/internal/warnings.h hash.$(OBJEXT): {$(VPATH)}assert.h +hash.$(OBJEXT): {$(VPATH)}atomic.h hash.$(OBJEXT): {$(VPATH)}backward/2/assume.h hash.$(OBJEXT): {$(VPATH)}backward/2/attributes.h hash.$(OBJEXT): {$(VPATH)}backward/2/bool.h @@ -7112,6 +7167,7 @@ hash.$(OBJEXT): {$(VPATH)}backward/2/long_long.h hash.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h hash.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h hash.$(OBJEXT): {$(VPATH)}config.h +hash.$(OBJEXT): {$(VPATH)}constant.h hash.$(OBJEXT): {$(VPATH)}debug_counter.h hash.$(OBJEXT): {$(VPATH)}defines.h hash.$(OBJEXT): {$(VPATH)}encoding.h @@ -7269,20 +7325,28 @@ hash.$(OBJEXT): {$(VPATH)}internal/value_type.h hash.$(OBJEXT): {$(VPATH)}internal/variable.h hash.$(OBJEXT): {$(VPATH)}internal/warning_push.h hash.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +hash.$(OBJEXT): {$(VPATH)}iseq.h +hash.$(OBJEXT): {$(VPATH)}method.h hash.$(OBJEXT): {$(VPATH)}missing.h +hash.$(OBJEXT): {$(VPATH)}node.h hash.$(OBJEXT): {$(VPATH)}onigmo.h hash.$(OBJEXT): {$(VPATH)}oniguruma.h hash.$(OBJEXT): {$(VPATH)}probes.dmyh hash.$(OBJEXT): {$(VPATH)}probes.h hash.$(OBJEXT): {$(VPATH)}ractor.h hash.$(OBJEXT): {$(VPATH)}ruby_assert.h +hash.$(OBJEXT): {$(VPATH)}ruby_atomic.h +hash.$(OBJEXT): {$(VPATH)}shape.h hash.$(OBJEXT): {$(VPATH)}st.h hash.$(OBJEXT): {$(VPATH)}subst.h hash.$(OBJEXT): {$(VPATH)}symbol.h +hash.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h hash.$(OBJEXT): {$(VPATH)}thread_native.h hash.$(OBJEXT): {$(VPATH)}transient_heap.h hash.$(OBJEXT): {$(VPATH)}util.h +hash.$(OBJEXT): {$(VPATH)}vm_core.h hash.$(OBJEXT): {$(VPATH)}vm_debug.h +hash.$(OBJEXT): {$(VPATH)}vm_opts.h hash.$(OBJEXT): {$(VPATH)}vm_sync.h inits.$(OBJEXT): $(hdrdir)/ruby.h inits.$(OBJEXT): $(hdrdir)/ruby/ruby.h @@ -7660,6 +7724,7 @@ io.$(OBJEXT): {$(VPATH)}oniguruma.h io.$(OBJEXT): {$(VPATH)}ractor.h io.$(OBJEXT): {$(VPATH)}ruby_assert.h io.$(OBJEXT): {$(VPATH)}ruby_atomic.h +io.$(OBJEXT): {$(VPATH)}shape.h io.$(OBJEXT): {$(VPATH)}st.h io.$(OBJEXT): {$(VPATH)}subst.h io.$(OBJEXT): {$(VPATH)}thread.h @@ -7670,12 +7735,17 @@ io.$(OBJEXT): {$(VPATH)}vm_core.h io.$(OBJEXT): {$(VPATH)}vm_opts.h io_buffer.$(OBJEXT): $(hdrdir)/ruby/ruby.h io_buffer.$(OBJEXT): $(top_srcdir)/internal/array.h +io_buffer.$(OBJEXT): $(top_srcdir)/internal/bignum.h io_buffer.$(OBJEXT): $(top_srcdir)/internal/bits.h io_buffer.$(OBJEXT): $(top_srcdir)/internal/compilers.h io_buffer.$(OBJEXT): $(top_srcdir)/internal/error.h +io_buffer.$(OBJEXT): $(top_srcdir)/internal/fixnum.h +io_buffer.$(OBJEXT): $(top_srcdir)/internal/numeric.h +io_buffer.$(OBJEXT): $(top_srcdir)/internal/serial.h io_buffer.$(OBJEXT): $(top_srcdir)/internal/static_assert.h io_buffer.$(OBJEXT): $(top_srcdir)/internal/string.h io_buffer.$(OBJEXT): $(top_srcdir)/internal/thread.h +io_buffer.$(OBJEXT): $(top_srcdir)/internal/vm.h io_buffer.$(OBJEXT): {$(VPATH)}assert.h io_buffer.$(OBJEXT): {$(VPATH)}backward/2/assume.h io_buffer.$(OBJEXT): {$(VPATH)}backward/2/attributes.h @@ -8062,6 +8132,7 @@ iseq.$(OBJEXT): {$(VPATH)}oniguruma.h iseq.$(OBJEXT): {$(VPATH)}ractor.h iseq.$(OBJEXT): {$(VPATH)}ruby_assert.h iseq.$(OBJEXT): {$(VPATH)}ruby_atomic.h +iseq.$(OBJEXT): {$(VPATH)}shape.h iseq.$(OBJEXT): {$(VPATH)}st.h iseq.$(OBJEXT): {$(VPATH)}subst.h iseq.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -8274,6 +8345,7 @@ load.$(OBJEXT): {$(VPATH)}probes.dmyh load.$(OBJEXT): {$(VPATH)}probes.h load.$(OBJEXT): {$(VPATH)}ruby_assert.h load.$(OBJEXT): {$(VPATH)}ruby_atomic.h +load.$(OBJEXT): {$(VPATH)}shape.h load.$(OBJEXT): {$(VPATH)}st.h load.$(OBJEXT): {$(VPATH)}subst.h load.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -8792,6 +8864,7 @@ marshal.$(OBJEXT): $(top_srcdir)/internal/string.h marshal.$(OBJEXT): $(top_srcdir)/internal/struct.h marshal.$(OBJEXT): $(top_srcdir)/internal/symbol.h marshal.$(OBJEXT): $(top_srcdir)/internal/util.h +marshal.$(OBJEXT): $(top_srcdir)/internal/variable.h marshal.$(OBJEXT): $(top_srcdir)/internal/vm.h marshal.$(OBJEXT): $(top_srcdir)/internal/warnings.h marshal.$(OBJEXT): {$(VPATH)}assert.h @@ -8806,6 +8879,7 @@ marshal.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h marshal.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h marshal.$(OBJEXT): {$(VPATH)}builtin.h marshal.$(OBJEXT): {$(VPATH)}config.h +marshal.$(OBJEXT): {$(VPATH)}constant.h marshal.$(OBJEXT): {$(VPATH)}defines.h marshal.$(OBJEXT): {$(VPATH)}encindex.h marshal.$(OBJEXT): {$(VPATH)}encoding.h @@ -8967,6 +9041,7 @@ marshal.$(OBJEXT): {$(VPATH)}marshal.rbinc marshal.$(OBJEXT): {$(VPATH)}missing.h marshal.$(OBJEXT): {$(VPATH)}onigmo.h marshal.$(OBJEXT): {$(VPATH)}oniguruma.h +marshal.$(OBJEXT): {$(VPATH)}shape.h marshal.$(OBJEXT): {$(VPATH)}st.h marshal.$(OBJEXT): {$(VPATH)}subst.h marshal.$(OBJEXT): {$(VPATH)}util.h @@ -8980,6 +9055,7 @@ math.$(OBJEXT): $(top_srcdir)/internal/math.h math.$(OBJEXT): $(top_srcdir)/internal/object.h math.$(OBJEXT): $(top_srcdir)/internal/serial.h math.$(OBJEXT): $(top_srcdir)/internal/static_assert.h +math.$(OBJEXT): $(top_srcdir)/internal/variable.h math.$(OBJEXT): $(top_srcdir)/internal/vm.h math.$(OBJEXT): $(top_srcdir)/internal/warnings.h math.$(OBJEXT): {$(VPATH)}assert.h @@ -8993,6 +9069,7 @@ math.$(OBJEXT): {$(VPATH)}backward/2/long_long.h math.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h math.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h math.$(OBJEXT): {$(VPATH)}config.h +math.$(OBJEXT): {$(VPATH)}constant.h math.$(OBJEXT): {$(VPATH)}defines.h math.$(OBJEXT): {$(VPATH)}id_table.h math.$(OBJEXT): {$(VPATH)}intern.h @@ -9139,6 +9216,7 @@ math.$(OBJEXT): {$(VPATH)}internal/warning_push.h math.$(OBJEXT): {$(VPATH)}internal/xmalloc.h math.$(OBJEXT): {$(VPATH)}math.c math.$(OBJEXT): {$(VPATH)}missing.h +math.$(OBJEXT): {$(VPATH)}shape.h math.$(OBJEXT): {$(VPATH)}st.h math.$(OBJEXT): {$(VPATH)}subst.h memory_view.$(OBJEXT): $(hdrdir)/ruby/ruby.h @@ -9320,6 +9398,7 @@ miniinit.$(OBJEXT): $(top_srcdir)/internal/gc.h miniinit.$(OBJEXT): $(top_srcdir)/internal/imemo.h miniinit.$(OBJEXT): $(top_srcdir)/internal/serial.h miniinit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h +miniinit.$(OBJEXT): $(top_srcdir)/internal/variable.h miniinit.$(OBJEXT): $(top_srcdir)/internal/vm.h miniinit.$(OBJEXT): $(top_srcdir)/internal/warnings.h miniinit.$(OBJEXT): {$(VPATH)}array.rb @@ -9337,12 +9416,14 @@ miniinit.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h miniinit.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h miniinit.$(OBJEXT): {$(VPATH)}builtin.h miniinit.$(OBJEXT): {$(VPATH)}config.h +miniinit.$(OBJEXT): {$(VPATH)}constant.h miniinit.$(OBJEXT): {$(VPATH)}defines.h miniinit.$(OBJEXT): {$(VPATH)}dir.rb miniinit.$(OBJEXT): {$(VPATH)}encoding.h miniinit.$(OBJEXT): {$(VPATH)}gc.rb miniinit.$(OBJEXT): {$(VPATH)}gem_prelude.rb miniinit.$(OBJEXT): {$(VPATH)}id.h +miniinit.$(OBJEXT): {$(VPATH)}id_table.h miniinit.$(OBJEXT): {$(VPATH)}intern.h miniinit.$(OBJEXT): {$(VPATH)}internal.h miniinit.$(OBJEXT): {$(VPATH)}internal/abi.h @@ -9516,6 +9597,7 @@ miniinit.$(OBJEXT): {$(VPATH)}prelude.rb miniinit.$(OBJEXT): {$(VPATH)}ractor.rb miniinit.$(OBJEXT): {$(VPATH)}ruby_assert.h miniinit.$(OBJEXT): {$(VPATH)}ruby_atomic.h +miniinit.$(OBJEXT): {$(VPATH)}shape.h miniinit.$(OBJEXT): {$(VPATH)}st.h miniinit.$(OBJEXT): {$(VPATH)}subst.h miniinit.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -9547,6 +9629,7 @@ mjit.$(OBJEXT): $(top_srcdir)/internal/imemo.h mjit.$(OBJEXT): $(top_srcdir)/internal/process.h mjit.$(OBJEXT): $(top_srcdir)/internal/serial.h mjit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h +mjit.$(OBJEXT): $(top_srcdir)/internal/variable.h mjit.$(OBJEXT): $(top_srcdir)/internal/vm.h mjit.$(OBJEXT): $(top_srcdir)/internal/warnings.h mjit.$(OBJEXT): {$(VPATH)}assert.h @@ -9741,6 +9824,7 @@ mjit.$(OBJEXT): {$(VPATH)}ractor.h mjit.$(OBJEXT): {$(VPATH)}ractor_core.h mjit.$(OBJEXT): {$(VPATH)}ruby_assert.h mjit.$(OBJEXT): {$(VPATH)}ruby_atomic.h +mjit.$(OBJEXT): {$(VPATH)}shape.h mjit.$(OBJEXT): {$(VPATH)}st.h mjit.$(OBJEXT): {$(VPATH)}subst.h mjit.$(OBJEXT): {$(VPATH)}thread.h @@ -9951,6 +10035,7 @@ mjit_compiler.$(OBJEXT): {$(VPATH)}mjit_unit.h mjit_compiler.$(OBJEXT): {$(VPATH)}node.h mjit_compiler.$(OBJEXT): {$(VPATH)}ruby_assert.h mjit_compiler.$(OBJEXT): {$(VPATH)}ruby_atomic.h +mjit_compiler.$(OBJEXT): {$(VPATH)}shape.h mjit_compiler.$(OBJEXT): {$(VPATH)}st.h mjit_compiler.$(OBJEXT): {$(VPATH)}subst.h mjit_compiler.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -10140,6 +10225,7 @@ node.$(OBJEXT): {$(VPATH)}node.c node.$(OBJEXT): {$(VPATH)}node.h node.$(OBJEXT): {$(VPATH)}ruby_assert.h node.$(OBJEXT): {$(VPATH)}ruby_atomic.h +node.$(OBJEXT): {$(VPATH)}shape.h node.$(OBJEXT): {$(VPATH)}st.h node.$(OBJEXT): {$(VPATH)}subst.h node.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -10342,6 +10428,7 @@ numeric.$(OBJEXT): {$(VPATH)}numeric.rbinc numeric.$(OBJEXT): {$(VPATH)}onigmo.h numeric.$(OBJEXT): {$(VPATH)}oniguruma.h numeric.$(OBJEXT): {$(VPATH)}ruby_assert.h +numeric.$(OBJEXT): {$(VPATH)}shape.h numeric.$(OBJEXT): {$(VPATH)}st.h numeric.$(OBJEXT): {$(VPATH)}subst.h numeric.$(OBJEXT): {$(VPATH)}util.h @@ -10543,6 +10630,7 @@ object.$(OBJEXT): {$(VPATH)}onigmo.h object.$(OBJEXT): {$(VPATH)}oniguruma.h object.$(OBJEXT): {$(VPATH)}probes.dmyh object.$(OBJEXT): {$(VPATH)}probes.h +object.$(OBJEXT): {$(VPATH)}shape.h object.$(OBJEXT): {$(VPATH)}st.h object.$(OBJEXT): {$(VPATH)}subst.h object.$(OBJEXT): {$(VPATH)}util.h @@ -10961,6 +11049,7 @@ proc.$(OBJEXT): $(top_srcdir)/internal/serial.h proc.$(OBJEXT): $(top_srcdir)/internal/static_assert.h proc.$(OBJEXT): $(top_srcdir)/internal/string.h proc.$(OBJEXT): $(top_srcdir)/internal/symbol.h +proc.$(OBJEXT): $(top_srcdir)/internal/variable.h proc.$(OBJEXT): $(top_srcdir)/internal/vm.h proc.$(OBJEXT): $(top_srcdir)/internal/warnings.h proc.$(OBJEXT): {$(VPATH)}assert.h @@ -10975,6 +11064,7 @@ proc.$(OBJEXT): {$(VPATH)}backward/2/long_long.h proc.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h proc.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h proc.$(OBJEXT): {$(VPATH)}config.h +proc.$(OBJEXT): {$(VPATH)}constant.h proc.$(OBJEXT): {$(VPATH)}defines.h proc.$(OBJEXT): {$(VPATH)}encoding.h proc.$(OBJEXT): {$(VPATH)}eval_intern.h @@ -11141,6 +11231,7 @@ proc.$(OBJEXT): {$(VPATH)}oniguruma.h proc.$(OBJEXT): {$(VPATH)}proc.c proc.$(OBJEXT): {$(VPATH)}ruby_assert.h proc.$(OBJEXT): {$(VPATH)}ruby_atomic.h +proc.$(OBJEXT): {$(VPATH)}shape.h proc.$(OBJEXT): {$(VPATH)}st.h proc.$(OBJEXT): {$(VPATH)}subst.h proc.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -11360,6 +11451,7 @@ process.$(OBJEXT): {$(VPATH)}process.c process.$(OBJEXT): {$(VPATH)}ractor.h process.$(OBJEXT): {$(VPATH)}ruby_assert.h process.$(OBJEXT): {$(VPATH)}ruby_atomic.h +process.$(OBJEXT): {$(VPATH)}shape.h process.$(OBJEXT): {$(VPATH)}st.h process.$(OBJEXT): {$(VPATH)}subst.h process.$(OBJEXT): {$(VPATH)}thread.h @@ -11390,6 +11482,7 @@ ractor.$(OBJEXT): $(top_srcdir)/internal/static_assert.h ractor.$(OBJEXT): $(top_srcdir)/internal/string.h ractor.$(OBJEXT): $(top_srcdir)/internal/struct.h ractor.$(OBJEXT): $(top_srcdir)/internal/thread.h +ractor.$(OBJEXT): $(top_srcdir)/internal/variable.h ractor.$(OBJEXT): $(top_srcdir)/internal/vm.h ractor.$(OBJEXT): $(top_srcdir)/internal/warnings.h ractor.$(OBJEXT): {$(VPATH)}assert.h @@ -11405,6 +11498,7 @@ ractor.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h ractor.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h ractor.$(OBJEXT): {$(VPATH)}builtin.h ractor.$(OBJEXT): {$(VPATH)}config.h +ractor.$(OBJEXT): {$(VPATH)}constant.h ractor.$(OBJEXT): {$(VPATH)}debug_counter.h ractor.$(OBJEXT): {$(VPATH)}defines.h ractor.$(OBJEXT): {$(VPATH)}encoding.h @@ -11574,6 +11668,7 @@ ractor.$(OBJEXT): {$(VPATH)}ractor.rbinc ractor.$(OBJEXT): {$(VPATH)}ractor_core.h ractor.$(OBJEXT): {$(VPATH)}ruby_assert.h ractor.$(OBJEXT): {$(VPATH)}ruby_atomic.h +ractor.$(OBJEXT): {$(VPATH)}shape.h ractor.$(OBJEXT): {$(VPATH)}st.h ractor.$(OBJEXT): {$(VPATH)}subst.h ractor.$(OBJEXT): {$(VPATH)}thread.h @@ -11971,6 +12066,7 @@ rational.$(OBJEXT): $(top_srcdir)/internal/object.h rational.$(OBJEXT): $(top_srcdir)/internal/rational.h rational.$(OBJEXT): $(top_srcdir)/internal/serial.h rational.$(OBJEXT): $(top_srcdir)/internal/static_assert.h +rational.$(OBJEXT): $(top_srcdir)/internal/variable.h rational.$(OBJEXT): $(top_srcdir)/internal/vm.h rational.$(OBJEXT): $(top_srcdir)/internal/warnings.h rational.$(OBJEXT): {$(VPATH)}assert.h @@ -11984,6 +12080,7 @@ rational.$(OBJEXT): {$(VPATH)}backward/2/long_long.h rational.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h rational.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h rational.$(OBJEXT): {$(VPATH)}config.h +rational.$(OBJEXT): {$(VPATH)}constant.h rational.$(OBJEXT): {$(VPATH)}defines.h rational.$(OBJEXT): {$(VPATH)}id.h rational.$(OBJEXT): {$(VPATH)}id_table.h @@ -12132,6 +12229,7 @@ rational.$(OBJEXT): {$(VPATH)}internal/xmalloc.h rational.$(OBJEXT): {$(VPATH)}missing.h rational.$(OBJEXT): {$(VPATH)}rational.c rational.$(OBJEXT): {$(VPATH)}ruby_assert.h +rational.$(OBJEXT): {$(VPATH)}shape.h rational.$(OBJEXT): {$(VPATH)}st.h rational.$(OBJEXT): {$(VPATH)}subst.h re.$(OBJEXT): $(hdrdir)/ruby.h @@ -12329,6 +12427,7 @@ re.$(OBJEXT): {$(VPATH)}re.h re.$(OBJEXT): {$(VPATH)}regenc.h re.$(OBJEXT): {$(VPATH)}regex.h re.$(OBJEXT): {$(VPATH)}regint.h +re.$(OBJEXT): {$(VPATH)}shape.h re.$(OBJEXT): {$(VPATH)}st.h re.$(OBJEXT): {$(VPATH)}subst.h re.$(OBJEXT): {$(VPATH)}util.h @@ -13327,6 +13426,7 @@ ruby.$(OBJEXT): $(top_srcdir)/internal/array.h ruby.$(OBJEXT): $(top_srcdir)/internal/class.h ruby.$(OBJEXT): $(top_srcdir)/internal/cmdlineopt.h ruby.$(OBJEXT): $(top_srcdir)/internal/compilers.h +ruby.$(OBJEXT): $(top_srcdir)/internal/cont.h ruby.$(OBJEXT): $(top_srcdir)/internal/error.h ruby.$(OBJEXT): $(top_srcdir)/internal/file.h ruby.$(OBJEXT): $(top_srcdir)/internal/gc.h @@ -13517,6 +13617,7 @@ ruby.$(OBJEXT): {$(VPATH)}internal/variable.h ruby.$(OBJEXT): {$(VPATH)}internal/warning_push.h ruby.$(OBJEXT): {$(VPATH)}internal/xmalloc.h ruby.$(OBJEXT): {$(VPATH)}io.h +ruby.$(OBJEXT): {$(VPATH)}iseq.h ruby.$(OBJEXT): {$(VPATH)}method.h ruby.$(OBJEXT): {$(VPATH)}missing.h ruby.$(OBJEXT): {$(VPATH)}mjit.h @@ -13526,6 +13627,7 @@ ruby.$(OBJEXT): {$(VPATH)}oniguruma.h ruby.$(OBJEXT): {$(VPATH)}ruby.c ruby.$(OBJEXT): {$(VPATH)}ruby_assert.h ruby.$(OBJEXT): {$(VPATH)}ruby_atomic.h +ruby.$(OBJEXT): {$(VPATH)}shape.h ruby.$(OBJEXT): {$(VPATH)}st.h ruby.$(OBJEXT): {$(VPATH)}subst.h ruby.$(OBJEXT): {$(VPATH)}thread.h @@ -13547,6 +13649,7 @@ scheduler.$(OBJEXT): $(top_srcdir)/internal/imemo.h scheduler.$(OBJEXT): $(top_srcdir)/internal/serial.h scheduler.$(OBJEXT): $(top_srcdir)/internal/static_assert.h scheduler.$(OBJEXT): $(top_srcdir)/internal/thread.h +scheduler.$(OBJEXT): $(top_srcdir)/internal/variable.h scheduler.$(OBJEXT): $(top_srcdir)/internal/vm.h scheduler.$(OBJEXT): $(top_srcdir)/internal/warnings.h scheduler.$(OBJEXT): {$(VPATH)}assert.h @@ -13561,10 +13664,12 @@ scheduler.$(OBJEXT): {$(VPATH)}backward/2/long_long.h scheduler.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h scheduler.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h scheduler.$(OBJEXT): {$(VPATH)}config.h +scheduler.$(OBJEXT): {$(VPATH)}constant.h scheduler.$(OBJEXT): {$(VPATH)}defines.h scheduler.$(OBJEXT): {$(VPATH)}encoding.h scheduler.$(OBJEXT): {$(VPATH)}fiber/scheduler.h scheduler.$(OBJEXT): {$(VPATH)}id.h +scheduler.$(OBJEXT): {$(VPATH)}id_table.h scheduler.$(OBJEXT): {$(VPATH)}intern.h scheduler.$(OBJEXT): {$(VPATH)}internal.h scheduler.$(OBJEXT): {$(VPATH)}internal/abi.h @@ -13726,6 +13831,7 @@ scheduler.$(OBJEXT): {$(VPATH)}oniguruma.h scheduler.$(OBJEXT): {$(VPATH)}ruby_assert.h scheduler.$(OBJEXT): {$(VPATH)}ruby_atomic.h scheduler.$(OBJEXT): {$(VPATH)}scheduler.c +scheduler.$(OBJEXT): {$(VPATH)}shape.h scheduler.$(OBJEXT): {$(VPATH)}st.h scheduler.$(OBJEXT): {$(VPATH)}subst.h scheduler.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -13891,6 +13997,208 @@ setproctitle.$(OBJEXT): {$(VPATH)}setproctitle.c setproctitle.$(OBJEXT): {$(VPATH)}st.h setproctitle.$(OBJEXT): {$(VPATH)}subst.h setproctitle.$(OBJEXT): {$(VPATH)}util.h +shape.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h +shape.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h +shape.$(OBJEXT): $(CCAN_DIR)/list/list.h +shape.$(OBJEXT): $(CCAN_DIR)/str/str.h +shape.$(OBJEXT): $(hdrdir)/ruby/ruby.h +shape.$(OBJEXT): $(top_srcdir)/internal/array.h +shape.$(OBJEXT): $(top_srcdir)/internal/class.h +shape.$(OBJEXT): $(top_srcdir)/internal/compilers.h +shape.$(OBJEXT): $(top_srcdir)/internal/gc.h +shape.$(OBJEXT): $(top_srcdir)/internal/imemo.h +shape.$(OBJEXT): $(top_srcdir)/internal/serial.h +shape.$(OBJEXT): $(top_srcdir)/internal/static_assert.h +shape.$(OBJEXT): $(top_srcdir)/internal/symbol.h +shape.$(OBJEXT): $(top_srcdir)/internal/variable.h +shape.$(OBJEXT): $(top_srcdir)/internal/vm.h +shape.$(OBJEXT): $(top_srcdir)/internal/warnings.h +shape.$(OBJEXT): {$(VPATH)}assert.h +shape.$(OBJEXT): {$(VPATH)}atomic.h +shape.$(OBJEXT): {$(VPATH)}backward/2/assume.h +shape.$(OBJEXT): {$(VPATH)}backward/2/attributes.h +shape.$(OBJEXT): {$(VPATH)}backward/2/bool.h +shape.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h +shape.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h +shape.$(OBJEXT): {$(VPATH)}backward/2/limits.h +shape.$(OBJEXT): {$(VPATH)}backward/2/long_long.h +shape.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h +shape.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h +shape.$(OBJEXT): {$(VPATH)}config.h +shape.$(OBJEXT): {$(VPATH)}constant.h +shape.$(OBJEXT): {$(VPATH)}debug_counter.h +shape.$(OBJEXT): {$(VPATH)}defines.h +shape.$(OBJEXT): {$(VPATH)}encoding.h +shape.$(OBJEXT): {$(VPATH)}id.h +shape.$(OBJEXT): {$(VPATH)}id_table.h +shape.$(OBJEXT): {$(VPATH)}intern.h +shape.$(OBJEXT): {$(VPATH)}internal.h +shape.$(OBJEXT): {$(VPATH)}internal/abi.h +shape.$(OBJEXT): {$(VPATH)}internal/anyargs.h +shape.$(OBJEXT): {$(VPATH)}internal/arithmetic.h +shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h +shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h +shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h +shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h +shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h +shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h +shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h +shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h +shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h +shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h +shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h +shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h +shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h +shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h +shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h +shape.$(OBJEXT): {$(VPATH)}internal/assume.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/cold.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/const.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/error.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/format.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/pure.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/warning.h +shape.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h +shape.$(OBJEXT): {$(VPATH)}internal/cast.h +shape.$(OBJEXT): {$(VPATH)}internal/compiler_is.h +shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h +shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h +shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h +shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h +shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h +shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h +shape.$(OBJEXT): {$(VPATH)}internal/compiler_since.h +shape.$(OBJEXT): {$(VPATH)}internal/config.h +shape.$(OBJEXT): {$(VPATH)}internal/constant_p.h +shape.$(OBJEXT): {$(VPATH)}internal/core.h +shape.$(OBJEXT): {$(VPATH)}internal/core/rarray.h +shape.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h +shape.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h +shape.$(OBJEXT): {$(VPATH)}internal/core/rclass.h +shape.$(OBJEXT): {$(VPATH)}internal/core/rdata.h +shape.$(OBJEXT): {$(VPATH)}internal/core/rfile.h +shape.$(OBJEXT): {$(VPATH)}internal/core/rhash.h +shape.$(OBJEXT): {$(VPATH)}internal/core/robject.h +shape.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h +shape.$(OBJEXT): {$(VPATH)}internal/core/rstring.h +shape.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h +shape.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h +shape.$(OBJEXT): {$(VPATH)}internal/ctype.h +shape.$(OBJEXT): {$(VPATH)}internal/dllexport.h +shape.$(OBJEXT): {$(VPATH)}internal/dosish.h +shape.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h +shape.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h +shape.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h +shape.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h +shape.$(OBJEXT): {$(VPATH)}internal/encoding/re.h +shape.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h +shape.$(OBJEXT): {$(VPATH)}internal/encoding/string.h +shape.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h +shape.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h +shape.$(OBJEXT): {$(VPATH)}internal/error.h +shape.$(OBJEXT): {$(VPATH)}internal/eval.h +shape.$(OBJEXT): {$(VPATH)}internal/event.h +shape.$(OBJEXT): {$(VPATH)}internal/fl_type.h +shape.$(OBJEXT): {$(VPATH)}internal/gc.h +shape.$(OBJEXT): {$(VPATH)}internal/glob.h +shape.$(OBJEXT): {$(VPATH)}internal/globals.h +shape.$(OBJEXT): {$(VPATH)}internal/has/attribute.h +shape.$(OBJEXT): {$(VPATH)}internal/has/builtin.h +shape.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h +shape.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h +shape.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h +shape.$(OBJEXT): {$(VPATH)}internal/has/extension.h +shape.$(OBJEXT): {$(VPATH)}internal/has/feature.h +shape.$(OBJEXT): {$(VPATH)}internal/has/warning.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/array.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/class.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/compar.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/complex.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/cont.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/dir.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/enum.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/error.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/eval.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/file.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/gc.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/hash.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/io.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/load.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/object.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/parse.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/proc.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/process.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/random.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/range.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/rational.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/re.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/select.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/signal.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/string.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/struct.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/thread.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/time.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/variable.h +shape.$(OBJEXT): {$(VPATH)}internal/intern/vm.h +shape.$(OBJEXT): {$(VPATH)}internal/interpreter.h +shape.$(OBJEXT): {$(VPATH)}internal/iterator.h +shape.$(OBJEXT): {$(VPATH)}internal/memory.h +shape.$(OBJEXT): {$(VPATH)}internal/method.h +shape.$(OBJEXT): {$(VPATH)}internal/module.h +shape.$(OBJEXT): {$(VPATH)}internal/newobj.h +shape.$(OBJEXT): {$(VPATH)}internal/rgengc.h +shape.$(OBJEXT): {$(VPATH)}internal/scan_args.h +shape.$(OBJEXT): {$(VPATH)}internal/special_consts.h +shape.$(OBJEXT): {$(VPATH)}internal/static_assert.h +shape.$(OBJEXT): {$(VPATH)}internal/stdalign.h +shape.$(OBJEXT): {$(VPATH)}internal/stdbool.h +shape.$(OBJEXT): {$(VPATH)}internal/symbol.h +shape.$(OBJEXT): {$(VPATH)}internal/value.h +shape.$(OBJEXT): {$(VPATH)}internal/value_type.h +shape.$(OBJEXT): {$(VPATH)}internal/variable.h +shape.$(OBJEXT): {$(VPATH)}internal/warning_push.h +shape.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +shape.$(OBJEXT): {$(VPATH)}method.h +shape.$(OBJEXT): {$(VPATH)}missing.h +shape.$(OBJEXT): {$(VPATH)}node.h +shape.$(OBJEXT): {$(VPATH)}onigmo.h +shape.$(OBJEXT): {$(VPATH)}oniguruma.h +shape.$(OBJEXT): {$(VPATH)}ruby_assert.h +shape.$(OBJEXT): {$(VPATH)}ruby_atomic.h +shape.$(OBJEXT): {$(VPATH)}shape.c +shape.$(OBJEXT): {$(VPATH)}shape.h +shape.$(OBJEXT): {$(VPATH)}st.h +shape.$(OBJEXT): {$(VPATH)}subst.h +shape.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h +shape.$(OBJEXT): {$(VPATH)}thread_native.h +shape.$(OBJEXT): {$(VPATH)}vm_core.h +shape.$(OBJEXT): {$(VPATH)}vm_debug.h +shape.$(OBJEXT): {$(VPATH)}vm_opts.h +shape.$(OBJEXT): {$(VPATH)}vm_sync.h signal.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h signal.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h signal.$(OBJEXT): $(CCAN_DIR)/list/list.h @@ -13907,6 +14215,7 @@ signal.$(OBJEXT): $(top_srcdir)/internal/signal.h signal.$(OBJEXT): $(top_srcdir)/internal/static_assert.h signal.$(OBJEXT): $(top_srcdir)/internal/string.h signal.$(OBJEXT): $(top_srcdir)/internal/thread.h +signal.$(OBJEXT): $(top_srcdir)/internal/variable.h signal.$(OBJEXT): $(top_srcdir)/internal/vm.h signal.$(OBJEXT): $(top_srcdir)/internal/warnings.h signal.$(OBJEXT): {$(VPATH)}assert.h @@ -13921,6 +14230,7 @@ signal.$(OBJEXT): {$(VPATH)}backward/2/long_long.h signal.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h signal.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h signal.$(OBJEXT): {$(VPATH)}config.h +signal.$(OBJEXT): {$(VPATH)}constant.h signal.$(OBJEXT): {$(VPATH)}debug_counter.h signal.$(OBJEXT): {$(VPATH)}defines.h signal.$(OBJEXT): {$(VPATH)}encoding.h @@ -14087,6 +14397,7 @@ signal.$(OBJEXT): {$(VPATH)}ractor.h signal.$(OBJEXT): {$(VPATH)}ractor_core.h signal.$(OBJEXT): {$(VPATH)}ruby_assert.h signal.$(OBJEXT): {$(VPATH)}ruby_atomic.h +signal.$(OBJEXT): {$(VPATH)}shape.h signal.$(OBJEXT): {$(VPATH)}signal.c signal.$(OBJEXT): {$(VPATH)}st.h signal.$(OBJEXT): {$(VPATH)}subst.h @@ -14111,6 +14422,7 @@ sprintf.$(OBJEXT): $(top_srcdir)/internal/serial.h sprintf.$(OBJEXT): $(top_srcdir)/internal/static_assert.h sprintf.$(OBJEXT): $(top_srcdir)/internal/string.h sprintf.$(OBJEXT): $(top_srcdir)/internal/symbol.h +sprintf.$(OBJEXT): $(top_srcdir)/internal/variable.h sprintf.$(OBJEXT): $(top_srcdir)/internal/vm.h sprintf.$(OBJEXT): $(top_srcdir)/internal/warnings.h sprintf.$(OBJEXT): {$(VPATH)}assert.h @@ -14124,6 +14436,7 @@ sprintf.$(OBJEXT): {$(VPATH)}backward/2/long_long.h sprintf.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h sprintf.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h sprintf.$(OBJEXT): {$(VPATH)}config.h +sprintf.$(OBJEXT): {$(VPATH)}constant.h sprintf.$(OBJEXT): {$(VPATH)}defines.h sprintf.$(OBJEXT): {$(VPATH)}encoding.h sprintf.$(OBJEXT): {$(VPATH)}id.h @@ -14285,6 +14598,7 @@ sprintf.$(OBJEXT): {$(VPATH)}onigmo.h sprintf.$(OBJEXT): {$(VPATH)}oniguruma.h sprintf.$(OBJEXT): {$(VPATH)}re.h sprintf.$(OBJEXT): {$(VPATH)}regex.h +sprintf.$(OBJEXT): {$(VPATH)}shape.h sprintf.$(OBJEXT): {$(VPATH)}sprintf.c sprintf.$(OBJEXT): {$(VPATH)}st.h sprintf.$(OBJEXT): {$(VPATH)}subst.h @@ -14653,6 +14967,7 @@ string.$(OBJEXT): $(top_srcdir)/internal/serial.h string.$(OBJEXT): $(top_srcdir)/internal/static_assert.h string.$(OBJEXT): $(top_srcdir)/internal/string.h string.$(OBJEXT): $(top_srcdir)/internal/transcode.h +string.$(OBJEXT): $(top_srcdir)/internal/variable.h string.$(OBJEXT): $(top_srcdir)/internal/vm.h string.$(OBJEXT): $(top_srcdir)/internal/warnings.h string.$(OBJEXT): {$(VPATH)}assert.h @@ -14667,6 +14982,7 @@ string.$(OBJEXT): {$(VPATH)}backward/2/long_long.h string.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h string.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h string.$(OBJEXT): {$(VPATH)}config.h +string.$(OBJEXT): {$(VPATH)}constant.h string.$(OBJEXT): {$(VPATH)}debug_counter.h string.$(OBJEXT): {$(VPATH)}defines.h string.$(OBJEXT): {$(VPATH)}encindex.h @@ -14834,6 +15150,7 @@ string.$(OBJEXT): {$(VPATH)}probes.h string.$(OBJEXT): {$(VPATH)}re.h string.$(OBJEXT): {$(VPATH)}regex.h string.$(OBJEXT): {$(VPATH)}ruby_assert.h +string.$(OBJEXT): {$(VPATH)}shape.h string.$(OBJEXT): {$(VPATH)}st.h string.$(OBJEXT): {$(VPATH)}string.c string.$(OBJEXT): {$(VPATH)}subst.h @@ -14890,6 +15207,7 @@ struct.$(OBJEXT): $(top_srcdir)/internal/static_assert.h struct.$(OBJEXT): $(top_srcdir)/internal/string.h struct.$(OBJEXT): $(top_srcdir)/internal/struct.h struct.$(OBJEXT): $(top_srcdir)/internal/symbol.h +struct.$(OBJEXT): $(top_srcdir)/internal/variable.h struct.$(OBJEXT): $(top_srcdir)/internal/vm.h struct.$(OBJEXT): $(top_srcdir)/internal/warnings.h struct.$(OBJEXT): {$(VPATH)}assert.h @@ -14905,6 +15223,7 @@ struct.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h struct.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h struct.$(OBJEXT): {$(VPATH)}builtin.h struct.$(OBJEXT): {$(VPATH)}config.h +struct.$(OBJEXT): {$(VPATH)}constant.h struct.$(OBJEXT): {$(VPATH)}defines.h struct.$(OBJEXT): {$(VPATH)}encoding.h struct.$(OBJEXT): {$(VPATH)}id.h @@ -15067,6 +15386,7 @@ struct.$(OBJEXT): {$(VPATH)}onigmo.h struct.$(OBJEXT): {$(VPATH)}oniguruma.h struct.$(OBJEXT): {$(VPATH)}ruby_assert.h struct.$(OBJEXT): {$(VPATH)}ruby_atomic.h +struct.$(OBJEXT): {$(VPATH)}shape.h struct.$(OBJEXT): {$(VPATH)}st.h struct.$(OBJEXT): {$(VPATH)}struct.c struct.$(OBJEXT): {$(VPATH)}subst.h @@ -15086,6 +15406,7 @@ symbol.$(OBJEXT): $(top_srcdir)/internal/serial.h symbol.$(OBJEXT): $(top_srcdir)/internal/static_assert.h symbol.$(OBJEXT): $(top_srcdir)/internal/string.h symbol.$(OBJEXT): $(top_srcdir)/internal/symbol.h +symbol.$(OBJEXT): $(top_srcdir)/internal/variable.h symbol.$(OBJEXT): $(top_srcdir)/internal/vm.h symbol.$(OBJEXT): $(top_srcdir)/internal/warnings.h symbol.$(OBJEXT): {$(VPATH)}assert.h @@ -15099,6 +15420,7 @@ symbol.$(OBJEXT): {$(VPATH)}backward/2/long_long.h symbol.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h symbol.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h symbol.$(OBJEXT): {$(VPATH)}config.h +symbol.$(OBJEXT): {$(VPATH)}constant.h symbol.$(OBJEXT): {$(VPATH)}debug_counter.h symbol.$(OBJEXT): {$(VPATH)}defines.h symbol.$(OBJEXT): {$(VPATH)}encoding.h @@ -15264,6 +15586,7 @@ symbol.$(OBJEXT): {$(VPATH)}oniguruma.h symbol.$(OBJEXT): {$(VPATH)}probes.dmyh symbol.$(OBJEXT): {$(VPATH)}probes.h symbol.$(OBJEXT): {$(VPATH)}ruby_assert.h +symbol.$(OBJEXT): {$(VPATH)}shape.h symbol.$(OBJEXT): {$(VPATH)}st.h symbol.$(OBJEXT): {$(VPATH)}subst.h symbol.$(OBJEXT): {$(VPATH)}symbol.c @@ -15294,6 +15617,7 @@ thread.$(OBJEXT): $(top_srcdir)/internal/static_assert.h thread.$(OBJEXT): $(top_srcdir)/internal/string.h thread.$(OBJEXT): $(top_srcdir)/internal/thread.h thread.$(OBJEXT): $(top_srcdir)/internal/time.h +thread.$(OBJEXT): $(top_srcdir)/internal/variable.h thread.$(OBJEXT): $(top_srcdir)/internal/vm.h thread.$(OBJEXT): $(top_srcdir)/internal/warnings.h thread.$(OBJEXT): {$(VPATH)}assert.h @@ -15309,6 +15633,7 @@ thread.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h thread.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h thread.$(OBJEXT): {$(VPATH)}builtin.h thread.$(OBJEXT): {$(VPATH)}config.h +thread.$(OBJEXT): {$(VPATH)}constant.h thread.$(OBJEXT): {$(VPATH)}debug.h thread.$(OBJEXT): {$(VPATH)}debug_counter.h thread.$(OBJEXT): {$(VPATH)}defines.h @@ -15482,6 +15807,7 @@ thread.$(OBJEXT): {$(VPATH)}ractor.h thread.$(OBJEXT): {$(VPATH)}ractor_core.h thread.$(OBJEXT): {$(VPATH)}ruby_assert.h thread.$(OBJEXT): {$(VPATH)}ruby_atomic.h +thread.$(OBJEXT): {$(VPATH)}shape.h thread.$(OBJEXT): {$(VPATH)}st.h thread.$(OBJEXT): {$(VPATH)}subst.h thread.$(OBJEXT): {$(VPATH)}thread.c @@ -15702,6 +16028,7 @@ transcode.$(OBJEXT): $(top_srcdir)/internal/serial.h transcode.$(OBJEXT): $(top_srcdir)/internal/static_assert.h transcode.$(OBJEXT): $(top_srcdir)/internal/string.h transcode.$(OBJEXT): $(top_srcdir)/internal/transcode.h +transcode.$(OBJEXT): $(top_srcdir)/internal/variable.h transcode.$(OBJEXT): $(top_srcdir)/internal/warnings.h transcode.$(OBJEXT): {$(VPATH)}assert.h transcode.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -15714,6 +16041,7 @@ transcode.$(OBJEXT): {$(VPATH)}backward/2/long_long.h transcode.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h transcode.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h transcode.$(OBJEXT): {$(VPATH)}config.h +transcode.$(OBJEXT): {$(VPATH)}constant.h transcode.$(OBJEXT): {$(VPATH)}defines.h transcode.$(OBJEXT): {$(VPATH)}encoding.h transcode.$(OBJEXT): {$(VPATH)}id.h @@ -15872,6 +16200,7 @@ transcode.$(OBJEXT): {$(VPATH)}internal/xmalloc.h transcode.$(OBJEXT): {$(VPATH)}missing.h transcode.$(OBJEXT): {$(VPATH)}onigmo.h transcode.$(OBJEXT): {$(VPATH)}oniguruma.h +transcode.$(OBJEXT): {$(VPATH)}shape.h transcode.$(OBJEXT): {$(VPATH)}st.h transcode.$(OBJEXT): {$(VPATH)}subst.h transcode.$(OBJEXT): {$(VPATH)}transcode.c @@ -16421,6 +16750,7 @@ variable.$(OBJEXT): {$(VPATH)}ractor.h variable.$(OBJEXT): {$(VPATH)}ractor_core.h variable.$(OBJEXT): {$(VPATH)}ruby_assert.h variable.$(OBJEXT): {$(VPATH)}ruby_atomic.h +variable.$(OBJEXT): {$(VPATH)}shape.h variable.$(OBJEXT): {$(VPATH)}st.h variable.$(OBJEXT): {$(VPATH)}subst.h variable.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -16446,6 +16776,7 @@ version.$(OBJEXT): $(top_srcdir)/internal/gc.h version.$(OBJEXT): $(top_srcdir)/internal/imemo.h version.$(OBJEXT): $(top_srcdir)/internal/serial.h version.$(OBJEXT): $(top_srcdir)/internal/static_assert.h +version.$(OBJEXT): $(top_srcdir)/internal/variable.h version.$(OBJEXT): $(top_srcdir)/internal/vm.h version.$(OBJEXT): $(top_srcdir)/internal/warnings.h version.$(OBJEXT): $(top_srcdir)/revision.h @@ -16462,9 +16793,11 @@ version.$(OBJEXT): {$(VPATH)}backward/2/long_long.h version.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h version.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h version.$(OBJEXT): {$(VPATH)}config.h +version.$(OBJEXT): {$(VPATH)}constant.h version.$(OBJEXT): {$(VPATH)}debug_counter.h version.$(OBJEXT): {$(VPATH)}defines.h version.$(OBJEXT): {$(VPATH)}id.h +version.$(OBJEXT): {$(VPATH)}id_table.h version.$(OBJEXT): {$(VPATH)}intern.h version.$(OBJEXT): {$(VPATH)}internal.h version.$(OBJEXT): {$(VPATH)}internal/abi.h @@ -16613,6 +16946,7 @@ version.$(OBJEXT): {$(VPATH)}mjit.h version.$(OBJEXT): {$(VPATH)}node.h version.$(OBJEXT): {$(VPATH)}ruby_assert.h version.$(OBJEXT): {$(VPATH)}ruby_atomic.h +version.$(OBJEXT): {$(VPATH)}shape.h version.$(OBJEXT): {$(VPATH)}st.h version.$(OBJEXT): {$(VPATH)}subst.h version.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -16848,6 +17182,7 @@ vm.$(OBJEXT): {$(VPATH)}ractor.h vm.$(OBJEXT): {$(VPATH)}ractor_core.h vm.$(OBJEXT): {$(VPATH)}ruby_assert.h vm.$(OBJEXT): {$(VPATH)}ruby_atomic.h +vm.$(OBJEXT): {$(VPATH)}shape.h vm.$(OBJEXT): {$(VPATH)}st.h vm.$(OBJEXT): {$(VPATH)}subst.h vm.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -16884,6 +17219,7 @@ vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/imemo.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/serial.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/static_assert.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/string.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/variable.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/vm.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/warnings.h vm_backtrace.$(OBJEXT): {$(VPATH)}assert.h @@ -16898,11 +17234,13 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/long_long.h vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h vm_backtrace.$(OBJEXT): {$(VPATH)}config.h +vm_backtrace.$(OBJEXT): {$(VPATH)}constant.h vm_backtrace.$(OBJEXT): {$(VPATH)}debug.h vm_backtrace.$(OBJEXT): {$(VPATH)}defines.h vm_backtrace.$(OBJEXT): {$(VPATH)}encoding.h vm_backtrace.$(OBJEXT): {$(VPATH)}eval_intern.h vm_backtrace.$(OBJEXT): {$(VPATH)}id.h +vm_backtrace.$(OBJEXT): {$(VPATH)}id_table.h vm_backtrace.$(OBJEXT): {$(VPATH)}intern.h vm_backtrace.$(OBJEXT): {$(VPATH)}internal.h vm_backtrace.$(OBJEXT): {$(VPATH)}internal/abi.h @@ -17062,6 +17400,7 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}onigmo.h vm_backtrace.$(OBJEXT): {$(VPATH)}oniguruma.h vm_backtrace.$(OBJEXT): {$(VPATH)}ruby_assert.h vm_backtrace.$(OBJEXT): {$(VPATH)}ruby_atomic.h +vm_backtrace.$(OBJEXT): {$(VPATH)}shape.h vm_backtrace.$(OBJEXT): {$(VPATH)}st.h vm_backtrace.$(OBJEXT): {$(VPATH)}subst.h vm_backtrace.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -17252,6 +17591,7 @@ vm_dump.$(OBJEXT): {$(VPATH)}ractor.h vm_dump.$(OBJEXT): {$(VPATH)}ractor_core.h vm_dump.$(OBJEXT): {$(VPATH)}ruby_assert.h vm_dump.$(OBJEXT): {$(VPATH)}ruby_atomic.h +vm_dump.$(OBJEXT): {$(VPATH)}shape.h vm_dump.$(OBJEXT): {$(VPATH)}st.h vm_dump.$(OBJEXT): {$(VPATH)}subst.h vm_dump.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -17271,6 +17611,7 @@ vm_sync.$(OBJEXT): $(top_srcdir)/internal/gc.h vm_sync.$(OBJEXT): $(top_srcdir)/internal/imemo.h vm_sync.$(OBJEXT): $(top_srcdir)/internal/serial.h vm_sync.$(OBJEXT): $(top_srcdir)/internal/static_assert.h +vm_sync.$(OBJEXT): $(top_srcdir)/internal/variable.h vm_sync.$(OBJEXT): $(top_srcdir)/internal/vm.h vm_sync.$(OBJEXT): $(top_srcdir)/internal/warnings.h vm_sync.$(OBJEXT): {$(VPATH)}assert.h @@ -17285,6 +17626,7 @@ vm_sync.$(OBJEXT): {$(VPATH)}backward/2/long_long.h vm_sync.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h vm_sync.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h vm_sync.$(OBJEXT): {$(VPATH)}config.h +vm_sync.$(OBJEXT): {$(VPATH)}constant.h vm_sync.$(OBJEXT): {$(VPATH)}debug_counter.h vm_sync.$(OBJEXT): {$(VPATH)}defines.h vm_sync.$(OBJEXT): {$(VPATH)}gc.h @@ -17439,6 +17781,7 @@ vm_sync.$(OBJEXT): {$(VPATH)}ractor.h vm_sync.$(OBJEXT): {$(VPATH)}ractor_core.h vm_sync.$(OBJEXT): {$(VPATH)}ruby_assert.h vm_sync.$(OBJEXT): {$(VPATH)}ruby_atomic.h +vm_sync.$(OBJEXT): {$(VPATH)}shape.h vm_sync.$(OBJEXT): {$(VPATH)}st.h vm_sync.$(OBJEXT): {$(VPATH)}subst.h vm_sync.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -17462,6 +17805,7 @@ vm_trace.$(OBJEXT): $(top_srcdir)/internal/imemo.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/serial.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/static_assert.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/symbol.h +vm_trace.$(OBJEXT): $(top_srcdir)/internal/variable.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/vm.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/warnings.h vm_trace.$(OBJEXT): {$(VPATH)}assert.h @@ -17477,12 +17821,14 @@ vm_trace.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h vm_trace.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h vm_trace.$(OBJEXT): {$(VPATH)}builtin.h vm_trace.$(OBJEXT): {$(VPATH)}config.h +vm_trace.$(OBJEXT): {$(VPATH)}constant.h vm_trace.$(OBJEXT): {$(VPATH)}debug.h vm_trace.$(OBJEXT): {$(VPATH)}debug_counter.h vm_trace.$(OBJEXT): {$(VPATH)}defines.h vm_trace.$(OBJEXT): {$(VPATH)}encoding.h vm_trace.$(OBJEXT): {$(VPATH)}eval_intern.h vm_trace.$(OBJEXT): {$(VPATH)}id.h +vm_trace.$(OBJEXT): {$(VPATH)}id_table.h vm_trace.$(OBJEXT): {$(VPATH)}intern.h vm_trace.$(OBJEXT): {$(VPATH)}internal.h vm_trace.$(OBJEXT): {$(VPATH)}internal/abi.h @@ -17644,6 +17990,7 @@ vm_trace.$(OBJEXT): {$(VPATH)}oniguruma.h vm_trace.$(OBJEXT): {$(VPATH)}ractor.h vm_trace.$(OBJEXT): {$(VPATH)}ruby_assert.h vm_trace.$(OBJEXT): {$(VPATH)}ruby_atomic.h +vm_trace.$(OBJEXT): {$(VPATH)}shape.h vm_trace.$(OBJEXT): {$(VPATH)}st.h vm_trace.$(OBJEXT): {$(VPATH)}subst.h vm_trace.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h diff --git a/compile.c b/compile.c index a5da919c0ae4e9..9051ecfcd69ea1 100644 --- a/compile.c +++ b/compile.c @@ -2058,20 +2058,7 @@ cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr) static inline VALUE get_ivar_ic_value(rb_iseq_t *iseq,ID id) { - VALUE val; - struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table; - if (tbl) { - if (rb_id_table_lookup(tbl,id,&val)) { - return val; - } - } - else { - tbl = rb_id_table_create(1); - ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl; - } - val = INT2FIX(ISEQ_BODY(iseq)->ivc_size++); - rb_id_table_insert(tbl,id,val); - return val; + return INT2FIX(ISEQ_BODY(iseq)->ivc_size++); } static inline VALUE @@ -2472,9 +2459,13 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) generated_iseq[code_index + 1 + j] = (VALUE)ic; } break; + case TS_IVC: /* inline ivar cache */ + { + unsigned int ic_index = FIX2UINT(operands[j]); + vm_ic_attr_index_initialize(((IVC)&body->is_entries[ic_index]), INVALID_SHAPE_ID); + } case TS_ISE: /* inline storage entry: `once` insn */ case TS_ICVARC: /* inline cvar cache */ - case TS_IVC: /* inline ivar cache */ { unsigned int ic_index = FIX2UINT(operands[j]); IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache; @@ -11514,6 +11505,11 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op; code[code_index] = (VALUE)ic; + + if (operand_type == TS_IVC) { + vm_ic_attr_index_initialize(((IVC)code[code_index]), INVALID_SHAPE_ID); + } + } break; case TS_CALLDATA: diff --git a/complex.c b/complex.c index 07e5914d54ca26..18d61b206f29a1 100644 --- a/complex.c +++ b/complex.c @@ -2026,6 +2026,12 @@ string_to_c_strict(VALUE self, int raise) * '1/2+3/4i'.to_c #=> ((1/2)+(3/4)*i) * 'ruby'.to_c #=> (0+0i) * + * Polar form: + * include Math + * "1.0@0".to_c #=> (1+0.0i) + * "1.0@#{PI/2}".to_c #=> (0.0+1i) + * "1.0@#{PI}".to_c #=> (-1+0.0i) + * * See Kernel.Complex. */ static VALUE diff --git a/configure.ac b/configure.ac index a6c170b4871d26..cf88fca4f1b642 100644 --- a/configure.ac +++ b/configure.ac @@ -3071,7 +3071,7 @@ AS_IF([test "$rb_cv_dlopen" = yes], [ "-undefined dynamic_lookup" \ ; do test "x${linker_flag}" = x || flag="${linker_flag}`echo ${flag} | tr ' ' ,`" - RUBY_TRY_LDFLAGS([$flag], [], [$flag=]) + RUBY_TRY_LDFLAGS([$flag], [], [flag=]) AS_IF([test x"$flag" = x], [continue]) AC_MSG_CHECKING([whether $flag is accepted for bundle]) diff --git a/cont.c b/cont.c index 499e1e79109990..1ce60811d229fd 100644 --- a/cont.c +++ b/cont.c @@ -34,7 +34,9 @@ extern int madvise(caddr_t, size_t, int); #include "internal/warnings.h" #include "ruby/fiber/scheduler.h" #include "mjit.h" +#include "yjit.h" #include "vm_core.h" +#include "vm_sync.h" #include "id_table.h" #include "ractor_core.h" @@ -67,6 +69,8 @@ static VALUE rb_cFiberPool; #define FIBER_POOL_ALLOCATION_FREE #endif +#define jit_cont_enabled mjit_enabled // To be used by YJIT later + enum context_type { CONTINUATION_CONTEXT = 0, FIBER_CONTEXT = 1 @@ -195,6 +199,15 @@ struct fiber_pool { size_t vm_stack_size; }; +// Continuation contexts used by JITs +struct rb_jit_cont { + rb_execution_context_t *ec; // continuation ec + struct rb_jit_cont *prev, *next; // used to form lists +}; + +// Doubly linked list for enumerating all on-stack ISEQs. +static struct rb_jit_cont *first_jit_cont; + typedef struct rb_context_struct { enum context_type type; int argc; @@ -212,8 +225,7 @@ typedef struct rb_context_struct { rb_execution_context_t saved_ec; rb_jmpbuf_t jmpbuf; rb_ensure_entry_t *ensure_array; - /* Pointer to MJIT info about the continuation. */ - struct mjit_cont *mjit_cont; + struct rb_jit_cont *jit_cont; // Continuation contexts for JITs } rb_context_t; @@ -1000,6 +1012,8 @@ fiber_is_root_p(const rb_fiber_t *fiber) } #endif +static void jit_cont_free(struct rb_jit_cont *cont); + static void cont_free(void *ptr) { @@ -1020,9 +1034,9 @@ cont_free(void *ptr) RUBY_FREE_UNLESS_NULL(cont->saved_vm_stack.ptr); - if (mjit_enabled) { - VM_ASSERT(cont->mjit_cont != NULL); - mjit_cont_free(cont->mjit_cont); + if (jit_cont_enabled) { + VM_ASSERT(cont->jit_cont != NULL); + jit_cont_free(cont->jit_cont); } /* free rb_cont_t or rb_fiber_t */ ruby_xfree(ptr); @@ -1187,12 +1201,98 @@ cont_save_thread(rb_context_t *cont, rb_thread_t *th) sec->machine.stack_end = NULL; } +// Register a new continuation with execution context `ec`. Return JIT info about +// the continuation. +static struct rb_jit_cont * +jit_cont_new(rb_execution_context_t *ec) +{ + struct rb_jit_cont *cont; + + // We need to use calloc instead of something like ZALLOC to avoid triggering GC here. + // When this function is called from rb_thread_alloc through rb_threadptr_root_fiber_setup, + // the thread is still being prepared and marking it causes SEGV. + cont = calloc(1, sizeof(struct rb_jit_cont)); + if (cont == NULL) + rb_memerror(); + cont->ec = ec; + + RB_VM_LOCK_ENTER(); + if (first_jit_cont == NULL) { + cont->next = cont->prev = NULL; + } + else { + cont->prev = NULL; + cont->next = first_jit_cont; + first_jit_cont->prev = cont; + } + first_jit_cont = cont; + RB_VM_LOCK_LEAVE(); + + return cont; +} + +// Unregister continuation `cont`. +static void +jit_cont_free(struct rb_jit_cont *cont) +{ + RB_VM_LOCK_ENTER(); + if (cont == first_jit_cont) { + first_jit_cont = cont->next; + if (first_jit_cont != NULL) + first_jit_cont->prev = NULL; + } + else { + cont->prev->next = cont->next; + if (cont->next != NULL) + cont->next->prev = cont->prev; + } + RB_VM_LOCK_LEAVE(); + + free(cont); +} + +// Call a given callback against all on-stack ISEQs. +void +rb_jit_cont_each_iseq(rb_iseq_callback callback) +{ + struct rb_jit_cont *cont; + for (cont = first_jit_cont; cont != NULL; cont = cont->next) { + if (cont->ec->vm_stack == NULL) + continue; + + const rb_control_frame_t *cfp; + for (cfp = RUBY_VM_END_CONTROL_FRAME(cont->ec) - 1; ; cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) { + const rb_iseq_t *iseq; + if (cfp->pc && (iseq = cfp->iseq) != NULL && imemo_type((VALUE)iseq) == imemo_iseq) { + callback(iseq); + } + + if (cfp == cont->ec->cfp) + break; // reached the most recent cfp + } + } +} + +// Finish working with continuation info. +void +rb_jit_cont_finish(void) +{ + if (!jit_cont_enabled) + return; + + struct rb_jit_cont *cont, *next; + for (cont = first_jit_cont; cont != NULL; cont = next) { + next = cont->next; + xfree(cont); + } +} + static void -cont_init_mjit_cont(rb_context_t *cont) +cont_init_jit_cont(rb_context_t *cont) { - VM_ASSERT(cont->mjit_cont == NULL); - if (mjit_enabled) { - cont->mjit_cont = mjit_cont_new(&(cont->saved_ec)); + VM_ASSERT(cont->jit_cont == NULL); + if (jit_cont_enabled) { + cont->jit_cont = jit_cont_new(&(cont->saved_ec)); } } @@ -1211,7 +1311,7 @@ cont_init(rb_context_t *cont, rb_thread_t *th) cont->saved_ec.local_storage = NULL; cont->saved_ec.local_storage_recursive_hash = Qnil; cont->saved_ec.local_storage_recursive_hash_for_trace = Qnil; - cont_init_mjit_cont(cont); + cont_init_jit_cont(cont); } static rb_context_t * @@ -1242,9 +1342,9 @@ rb_fiberptr_blocking(struct rb_fiber_struct *fiber) // This is used for root_fiber because other fibers call cont_init_mjit_cont through cont_new. void -rb_fiber_init_mjit_cont(struct rb_fiber_struct *fiber) +rb_fiber_init_jit_cont(struct rb_fiber_struct *fiber) { - cont_init_mjit_cont(&fiber->cont); + cont_init_jit_cont(&fiber->cont); } #if 0 @@ -1991,7 +2091,7 @@ rb_fiber_s_schedule_kw(int argc, VALUE* argv, int kw_splat) VALUE fiber = Qnil; if (scheduler != Qnil) { - fiber = rb_funcall_passing_block_kw(scheduler, rb_intern("fiber"), argc, argv, kw_splat); + fiber = rb_fiber_scheduler_fiber(scheduler, argc, argv, kw_splat); } else { rb_raise(rb_eRuntimeError, "No scheduler is available!"); @@ -2187,9 +2287,10 @@ rb_threadptr_root_fiber_setup(rb_thread_t *th) fiber->blocking = 1; fiber_status_set(fiber, FIBER_RESUMED); /* skip CREATED */ th->ec = &fiber->cont.saved_ec; - // This skips mjit_cont_new for the initial thread because mjit_enabled is always false - // at this point. mjit_init calls rb_fiber_init_mjit_cont again for this root_fiber. - rb_fiber_init_mjit_cont(fiber); + // This skips jit_cont_new for the initial thread because rb_yjit_enabled_p() and + // mjit_enabled are false at this point. ruby_opt_init will call rb_fiber_init_jit_cont + // again for this root_fiber. + rb_fiber_init_jit_cont(fiber); } void @@ -2410,20 +2511,34 @@ rb_fiber_transfer(VALUE fiber_value, int argc, const VALUE *argv) VALUE rb_fiber_blocking_p(VALUE fiber) { - return RBOOL(fiber_ptr(fiber)->blocking != 0); + return RBOOL(fiber_ptr(fiber)->blocking); } static VALUE -fiber_blocking_yield(VALUE fiber) +fiber_blocking_yield(VALUE fiber_value) { - fiber_ptr(fiber)->blocking += 1; - return rb_yield(fiber); + rb_fiber_t *fiber = fiber_ptr(fiber_value); + rb_thread_t * volatile th = fiber->cont.saved_ec.thread_ptr; + + // fiber->blocking is `unsigned int : 1`, so we use it as a boolean: + fiber->blocking = 1; + + // Once the fiber is blocking, and current, we increment the thread blocking state: + th->blocking += 1; + + return rb_yield(fiber_value); } static VALUE -fiber_blocking_ensure(VALUE fiber) +fiber_blocking_ensure(VALUE fiber_value) { - fiber_ptr(fiber)->blocking -= 1; + rb_fiber_t *fiber = fiber_ptr(fiber_value); + rb_thread_t * volatile th = fiber->cont.saved_ec.thread_ptr; + + // We are no longer blocking: + fiber->blocking = 0; + th->blocking -= 1; + return Qnil; } @@ -2440,8 +2555,15 @@ fiber_blocking_ensure(VALUE fiber) VALUE rb_fiber_blocking(VALUE class) { - VALUE fiber = rb_fiber_current(); - return rb_ensure(fiber_blocking_yield, fiber, fiber_blocking_ensure, fiber); + VALUE fiber_value = rb_fiber_current(); + rb_fiber_t *fiber = fiber_ptr(fiber_value); + + // If we are already blocking, this is essentially a no-op: + if (fiber->blocking) { + return rb_yield(fiber_value); + } else { + return rb_ensure(fiber_blocking_yield, fiber_value, fiber_blocking_ensure, fiber_value); + } } /* @@ -2979,329 +3101,6 @@ rb_fiber_pool_initialize(int argc, VALUE* argv, VALUE self) * fiber.resume #=> FiberError: dead fiber called */ -/* - * Document-class: Fiber::SchedulerInterface - * - * This is not an existing class, but documentation of the interface that Scheduler - * object should comply to in order to be used as argument to Fiber.scheduler and handle non-blocking - * fibers. See also the "Non-blocking fibers" section in Fiber class docs for explanations - * of some concepts. - * - * Scheduler's behavior and usage are expected to be as follows: - * - * * When the execution in the non-blocking Fiber reaches some blocking operation (like - * sleep, wait for a process, or a non-ready I/O), it calls some of the scheduler's - * hook methods, listed below. - * * Scheduler somehow registers what the current fiber is waiting on, and yields control - * to other fibers with Fiber.yield (so the fiber would be suspended while expecting its - * wait to end, and other fibers in the same thread can perform) - * * At the end of the current thread execution, the scheduler's method #close is called - * * The scheduler runs into a wait loop, checking all the blocked fibers (which it has - * registered on hook calls) and resuming them when the awaited resource is ready - * (e.g. I/O ready or sleep time elapsed). - * - * A typical implementation would probably rely for this closing loop on a gem like - * EventMachine[https://github.com/eventmachine/eventmachine] or - * Async[https://github.com/socketry/async]. - * - * This way concurrent execution will be achieved transparently for every - * individual Fiber's code. - * - * Hook methods are: - * - * * #io_wait, #io_read, and #io_write - * * #process_wait - * * #kernel_sleep - * * #timeout_after - * * #address_resolve - * * #block and #unblock - * * (the list is expanded as Ruby developers make more methods having non-blocking calls) - * - * When not specified otherwise, the hook implementations are mandatory: if they are not - * implemented, the methods trying to call hook will fail. To provide backward compatibility, - * in the future hooks will be optional (if they are not implemented, due to the scheduler - * being created for the older Ruby version, the code which needs this hook will not fail, - * and will just behave in a blocking fashion). - * - * It is also strongly recommended that the scheduler implements the #fiber method, which is - * delegated to by Fiber.schedule. - * - * Sample _toy_ implementation of the scheduler can be found in Ruby's code, in - * test/fiber/scheduler.rb - * - */ - -#if 0 /* for RDoc */ -/* - * - * Document-method: Fiber::SchedulerInterface#close - * - * Called when the current thread exits. The scheduler is expected to implement this - * method in order to allow all waiting fibers to finalize their execution. - * - * The suggested pattern is to implement the main event loop in the #close method. - * - */ -static VALUE -rb_fiber_scheduler_interface_close(VALUE self) -{ -} - -/* - * Document-method: SchedulerInterface#process_wait - * call-seq: process_wait(pid, flags) - * - * Invoked by Process::Status.wait in order to wait for a specified process. - * See that method description for arguments description. - * - * Suggested minimal implementation: - * - * Thread.new do - * Process::Status.wait(pid, flags) - * end.value - * - * This hook is optional: if it is not present in the current scheduler, - * Process::Status.wait will behave as a blocking method. - * - * Expected to return a Process::Status instance. - */ -static VALUE -rb_fiber_scheduler_interface_process_wait(VALUE self) -{ -} - -/* - * Document-method: SchedulerInterface#io_wait - * call-seq: io_wait(io, events, timeout) - * - * Invoked by IO#wait, IO#wait_readable, IO#wait_writable to ask whether the - * specified descriptor is ready for specified events within - * the specified +timeout+. - * - * +events+ is a bit mask of IO::READABLE, IO::WRITABLE, and - * IO::PRIORITY. - * - * Suggested implementation should register which Fiber is waiting for which - * resources and immediately calling Fiber.yield to pass control to other - * fibers. Then, in the #close method, the scheduler might dispatch all the - * I/O resources to fibers waiting for it. - * - * Expected to return the subset of events that are ready immediately. - * - */ -static VALUE -rb_fiber_scheduler_interface_io_wait(VALUE self) -{ -} - -/* - * Document-method: SchedulerInterface#io_read - * call-seq: io_read(io, buffer, length) -> read length or -errno - * - * Invoked by IO#read to read +length+ bytes from +io+ into a specified - * +buffer+ (see IO::Buffer). - * - * The +length+ argument is the "minimum length to be read". - * If the IO buffer size is 8KiB, but the +length+ is +1024+ (1KiB), up to - * 8KiB might be read, but at least 1KiB will be. - * Generally, the only case where less data than +length+ will be read is if - * there is an error reading the data. - * - * Specifying a +length+ of 0 is valid and means try reading at least once - * and return any available data. - * - * Suggested implementation should try to read from +io+ in a non-blocking - * manner and call #io_wait if the +io+ is not ready (which will yield control - * to other fibers). - * - * See IO::Buffer for an interface available to return data. - * - * Expected to return number of bytes read, or, in case of an error, -errno - * (negated number corresponding to system's error code). - * - * The method should be considered _experimental_. - */ -static VALUE -rb_fiber_scheduler_interface_io_read(VALUE self) -{ -} - -/* - * Document-method: SchedulerInterface#io_write - * call-seq: io_write(io, buffer, length) -> written length or -errno - * - * Invoked by IO#write to write +length+ bytes to +io+ from - * from a specified +buffer+ (see IO::Buffer). - * - * The +length+ argument is the "(minimum) length to be written". - * If the IO buffer size is 8KiB, but the +length+ specified is 1024 (1KiB), - * at most 8KiB will be written, but at least 1KiB will be. - * Generally, the only case where less data than +length+ will be written is if - * there is an error writing the data. - * - * Specifying a +length+ of 0 is valid and means try writing at least once, - * as much data as possible. - * - * Suggested implementation should try to write to +io+ in a non-blocking - * manner and call #io_wait if the +io+ is not ready (which will yield control - * to other fibers). - * - * See IO::Buffer for an interface available to get data from buffer efficiently. - * - * Expected to return number of bytes written, or, in case of an error, -errno - * (negated number corresponding to system's error code). - * - * The method should be considered _experimental_. - */ -static VALUE -rb_fiber_scheduler_interface_io_write(VALUE self) -{ -} - -/* - * Document-method: SchedulerInterface#kernel_sleep - * call-seq: kernel_sleep(duration = nil) - * - * Invoked by Kernel#sleep and Mutex#sleep and is expected to provide - * an implementation of sleeping in a non-blocking way. Implementation might - * register the current fiber in some list of "which fiber wait until what - * moment", call Fiber.yield to pass control, and then in #close resume - * the fibers whose wait period has elapsed. - * - */ -static VALUE -rb_fiber_scheduler_interface_kernel_sleep(VALUE self) -{ -} - -/* - * Document-method: SchedulerInterface#address_resolve - * call-seq: address_resolve(hostname) -> array_of_strings or nil - * - * Invoked by any method that performs a non-reverse DNS lookup. The most - * notable method is Addrinfo.getaddrinfo, but there are many other. - * - * The method is expected to return an array of strings corresponding to ip - * addresses the +hostname+ is resolved to, or +nil+ if it can not be resolved. - * - * Fairly exhaustive list of all possible call-sites: - * - * - Addrinfo.getaddrinfo - * - Addrinfo.tcp - * - Addrinfo.udp - * - Addrinfo.ip - * - Addrinfo.new - * - Addrinfo.marshal_load - * - SOCKSSocket.new - * - TCPServer.new - * - TCPSocket.new - * - IPSocket.getaddress - * - TCPSocket.gethostbyname - * - UDPSocket#connect - * - UDPSocket#bind - * - UDPSocket#send - * - Socket.getaddrinfo - * - Socket.gethostbyname - * - Socket.pack_sockaddr_in - * - Socket.sockaddr_in - * - Socket.unpack_sockaddr_in - */ -static VALUE -rb_fiber_scheduler_interface_address_resolve(VALUE self) -{ -} - -/* - * Document-method: SchedulerInterface#timeout_after - * call-seq: timeout_after(duration, exception_class, *exception_arguments, &block) -> result of block - * - * Invoked by Timeout.timeout to execute the given +block+ within the given - * +duration+. It can also be invoked directly by the scheduler or user code. - * - * Attempt to limit the execution time of a given +block+ to the given - * +duration+ if possible. When a non-blocking operation causes the +block+'s - * execution time to exceed the specified +duration+, that non-blocking - * operation should be interrupted by raising the specified +exception_class+ - * constructed with the given +exception_arguments+. - * - * General execution timeouts are often considered risky. This implementation - * will only interrupt non-blocking operations. This is by design because it's - * expected that non-blocking operations can fail for a variety of - * unpredictable reasons, so applications should already be robust in handling - * these conditions and by implication timeouts. - * - * However, as a result of this design, if the +block+ does not invoke any - * non-blocking operations, it will be impossible to interrupt it. If you - * desire to provide predictable points for timeouts, consider adding - * +sleep(0)+. - * - * If the block is executed successfully, its result will be returned. - * - * The exception will typically be raised using Fiber#raise. - */ -static VALUE -rb_fiber_scheduler_interface_timeout_after(VALUE self) -{ -} - -/* - * Document-method: SchedulerInterface#block - * call-seq: block(blocker, timeout = nil) - * - * Invoked by methods like Thread.join, and by Mutex, to signify that current - * Fiber is blocked until further notice (e.g. #unblock) or until +timeout+ has - * elapsed. - * - * +blocker+ is what we are waiting on, informational only (for debugging and - * logging). There are no guarantee about its value. - * - * Expected to return boolean, specifying whether the blocking operation was - * successful or not. - */ -static VALUE -rb_fiber_scheduler_interface_block(VALUE self) -{ -} - -/* - * Document-method: SchedulerInterface#unblock - * call-seq: unblock(blocker, fiber) - * - * Invoked to wake up Fiber previously blocked with #block (for example, Mutex#lock - * calls #block and Mutex#unlock calls #unblock). The scheduler should use - * the +fiber+ parameter to understand which fiber is unblocked. - * - * +blocker+ is what was awaited for, but it is informational only (for debugging - * and logging), and it is not guaranteed to be the same value as the +blocker+ for - * #block. - * - */ -static VALUE -rb_fiber_scheduler_interface_unblock(VALUE self) -{ -} - -/* - * Document-method: SchedulerInterface#fiber - * call-seq: fiber(&block) - * - * Implementation of the Fiber.schedule. The method is expected to immediately - * run the given block of code in a separate non-blocking fiber, and to return that Fiber. - * - * Minimal suggested implementation is: - * - * def fiber(&block) - * fiber = Fiber.new(blocking: false, &block) - * fiber.resume - * fiber - * end - */ -static VALUE -rb_fiber_scheduler_interface_fiber(VALUE self) -{ -} -#endif - void Init_Cont(void) { @@ -3353,21 +3152,6 @@ Init_Cont(void) rb_define_singleton_method(rb_cFiber, "schedule", rb_fiber_s_schedule, -1); -#if 0 /* for RDoc */ - rb_cFiberScheduler = rb_define_class_under(rb_cFiber, "SchedulerInterface", rb_cObject); - rb_define_method(rb_cFiberScheduler, "close", rb_fiber_scheduler_interface_close, 0); - rb_define_method(rb_cFiberScheduler, "process_wait", rb_fiber_scheduler_interface_process_wait, 0); - rb_define_method(rb_cFiberScheduler, "io_wait", rb_fiber_scheduler_interface_io_wait, 0); - rb_define_method(rb_cFiberScheduler, "io_read", rb_fiber_scheduler_interface_io_read, 0); - rb_define_method(rb_cFiberScheduler, "io_write", rb_fiber_scheduler_interface_io_write, 0); - rb_define_method(rb_cFiberScheduler, "kernel_sleep", rb_fiber_scheduler_interface_kernel_sleep, 0); - rb_define_method(rb_cFiberScheduler, "address_resolve", rb_fiber_scheduler_interface_address_resolve, 0); - rb_define_method(rb_cFiberScheduler, "timeout_after", rb_fiber_scheduler_interface_timeout_after, 0); - rb_define_method(rb_cFiberScheduler, "block", rb_fiber_scheduler_interface_block, 0); - rb_define_method(rb_cFiberScheduler, "unblock", rb_fiber_scheduler_interface_unblock, 0); - rb_define_method(rb_cFiberScheduler, "fiber", rb_fiber_scheduler_interface_fiber, 0); -#endif - #ifdef RB_EXPERIMENTAL_FIBER_POOL rb_cFiberPool = rb_define_class_under(rb_cFiber, "Pool", rb_cObject); rb_define_alloc_func(rb_cFiberPool, fiber_pool_alloc); diff --git a/debug_counter.h b/debug_counter.h index c6f4176e9752de..f3a799913b5291 100644 --- a/debug_counter.h +++ b/debug_counter.h @@ -130,7 +130,6 @@ RB_DEBUG_COUNTER(frame_C2R) /* instance variable counts * * * ivar_get_ic_hit/miss: ivar_get inline cache (ic) hit/miss counts (VM insn) - * * ivar_get_ic_miss_serial: ivar_get ic miss reason by serial (VM insn) * * ivar_get_ic_miss_unset: ... by unset (VM insn) * * ivar_get_ic_miss_noobject: ... by "not T_OBJECT" (VM insn) * * ivar_set_...: same counts with ivar_set (VM insn) @@ -140,17 +139,17 @@ RB_DEBUG_COUNTER(frame_C2R) */ RB_DEBUG_COUNTER(ivar_get_ic_hit) RB_DEBUG_COUNTER(ivar_get_ic_miss) -RB_DEBUG_COUNTER(ivar_get_ic_miss_serial) -RB_DEBUG_COUNTER(ivar_get_ic_miss_unset) RB_DEBUG_COUNTER(ivar_get_ic_miss_noobject) RB_DEBUG_COUNTER(ivar_set_ic_hit) RB_DEBUG_COUNTER(ivar_set_ic_miss) -RB_DEBUG_COUNTER(ivar_set_ic_miss_serial) -RB_DEBUG_COUNTER(ivar_set_ic_miss_unset) RB_DEBUG_COUNTER(ivar_set_ic_miss_iv_hit) RB_DEBUG_COUNTER(ivar_set_ic_miss_noobject) RB_DEBUG_COUNTER(ivar_get_base) RB_DEBUG_COUNTER(ivar_set_base) +RB_DEBUG_COUNTER(ivar_get_ic_miss_set) +RB_DEBUG_COUNTER(ivar_get_cc_miss_set) +RB_DEBUG_COUNTER(ivar_get_ic_miss_unset) +RB_DEBUG_COUNTER(ivar_get_cc_miss_unset) /* local variable counts * diff --git a/dir.c b/dir.c index a3ea5eea50a6b3..a35aace6f1d3c6 100644 --- a/dir.c +++ b/dir.c @@ -2305,7 +2305,7 @@ glob_helper( #endif break; case BRACE: - if (!recursive) { + if (!recursive || strchr(p->str, '/')) { brace = 1; } break; diff --git a/dln.c b/dln.c index b14ba63c44c67c..bf87251bb6b4d1 100644 --- a/dln.c +++ b/dln.c @@ -298,15 +298,15 @@ COMPILER_WARNING_POP /* assume others than old Mac OS X have no problem */ # define dln_disable_dlclose() false -#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11 -/* targeting newer versions only */ -# define dln_disable_dlclose() false - #elif !defined(MAC_OS_X_VERSION_10_11) || \ (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11) /* targeting older versions only */ # define dln_disable_dlclose() true +#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11 +/* targeting newer versions only */ +# define dln_disable_dlclose() false + #else /* support both versions, and check at runtime */ # include diff --git a/doc/packed_data.rdoc b/doc/packed_data.rdoc new file mode 100644 index 00000000000000..252fae3c85cbaf --- /dev/null +++ b/doc/packed_data.rdoc @@ -0,0 +1,586 @@ +== Packed Data + +Certain Ruby core methods deal with packing and unpacking data: + +- \Method Array#pack: + Formats each element in array +self+ into a binary string; + returns that string. +- \Method String#unpack: + Extracts data from string +self+, + forming objects that become the elements of a new array; + returns that array. +- \Method String#unpack1: + Does the same, but returns only the first extracted object. + +Each of these methods accepts a string +template+, +consisting of zero or more _directive_ characters, +each followed by zero or more _modifier_ characters. + +Examples (directive 'C' specifies 'unsigned character'): + + [65].pack('C') # => "A" # One element, one directive. + [65, 66].pack('CC') # => "AB" # Two elements, two directives. + [65, 66].pack('C') # => "A" # Extra element is ignored. + [65].pack('') # => "" # No directives. + [65].pack('CC') # Extra directive raises ArgumentError. + + 'A'.unpack('C') # => [65] # One character, one directive. + 'AB'.unpack('CC') # => [65, 66] # Two characters, two directives. + 'AB'.unpack('C') # => [65] # Extra character is ignored. + 'A'.unpack('CC') # => [65, nil] # Extra directive generates nil. + 'AB'.unpack('') # => [] # No directives. + +The string +template+ may contain any mixture of valid directives +(directive 'c' specifies 'signed character'): + + [65, -1].pack('cC') # => "A\xFF" + "A\xFF".unpack('cC') # => [65, 255] + +The string +template+ may contain whitespace (which is ignored) +and comments, each of which begins with character '#' +and continues up to and including the next following newline: + + [0,1].pack(" C #foo \n C ") # => "\x00\x01" + "\0\1".unpack(" C #foo \n C ") # => [0, 1] + +Any directive may be followed by either of these modifiers: + +- '*' - The directive is to be applied as many times as needed: + + [65, 66].pack('C*') # => "AB" + 'AB'.unpack('C*') # => [65, 66] + +- Integer +count+ - The directive is to be applied +count+ times: + + [65, 66].pack('C2') # => "AB" + [65, 66].pack('C3') # Raises ArgumentError. + 'AB'.unpack('C2') # => [65, 66] + 'AB'.unpack('C3') # => [65, 66, nil] + + Note: Directives in %w[A a Z m] use +count+ differently; + see {String Directives}[rdoc-ref:packed_data.rdoc@String+Directives]. + +=== Packing \Method + +\Method Array#pack accepts optional keyword argument ++buffer+ that specifies the target string (instead of a new string): + + [65, 66].pack('C*', buffer: 'foo') # => "fooAB" + +The method can accept a block: + + # Packed string is passed to the block. + [65, 66].pack('C*') {|s| p s } # => "AB" + +=== Unpacking Methods + +Methods String#unpack and String#unpack1 each accept +an optional keyword argument +offset+ that specifies an offset +into the string: + + 'ABC'.unpack('C*', offset: 1) # => [66, 67] + 'ABC'.unpack1('C*', offset: 1) # => 66 + +Both methods can accept a block: + + # Each unpacked object is passed to the block. + ret = [] + "ABCD".unpack("C*") {|c| ret << c } + ret # => [65, 66, 67, 68] + + # The single unpacked object is passed to the block. + 'AB'.unpack1('C*') {|ele| p ele } # => 65 + +=== \Integer Directives + +Each integer directive specifies the packing or unpacking +for one element in the input or output array. + +==== 8-Bit \Integer Directives + +- 'c' - 8-bit signed integer + (like C signed char): + + [0, 1, 255].pack('c*') # => "\x00\x01\xFF" + s = [0, 1, -1].pack('c*') # => "\x00\x01\xFF" + s.unpack('c*') # => [0, 1, -1] + +- 'C' - 8-bit signed integer + (like C unsigned char): + + [0, 1, 255].pack('C*') # => "\x00\x01\xFF" + s = [0, 1, -1].pack('C*') # => "\x00\x01\xFF" + s.unpack('C*') # => [0, 1, 255] + +==== 16-Bit \Integer Directives + +- 's' - 16-bit signed integer, native-endian + (like C int16_t): + + [513, -514].pack('s*') # => "\x01\x02\xFE\xFD" + s = [513, 65022].pack('s*') # => "\x01\x02\xFE\xFD" + s.unpack('s*') # => [513, -514] + +- 'S' - 16-bit unsigned integer, native-endian + (like C uint16_t): + + [513, -514].pack('S*') # => "\x01\x02\xFE\xFD" + s = [513, 65022].pack('S*') # => "\x01\x02\xFE\xFD" + s.unpack('S*') # => [513, 65022] + +- 'n' - 16-bit network integer, big-endian: + + s = [0, 1, -1, 32767, -32768, 65535].pack('n*') + # => "\x00\x00\x00\x01\xFF\xFF\x7F\xFF\x80\x00\xFF\xFF" + s.unpack('n*') + # => [0, 1, 65535, 32767, 32768, 65535] + +- 'v' - 16-bit VAX integer, little-endian: + + s = [0, 1, -1, 32767, -32768, 65535].pack('v*') + # => "\x00\x00\x01\x00\xFF\xFF\xFF\x7F\x00\x80\xFF\xFF" + s.unpack('v*') + # => [0, 1, 65535, 32767, 32768, 65535] + +==== 32-Bit \Integer Directives + +- 'l' - 32-bit signed integer, native-endian + (like C int32_t): + + s = [67305985, -50462977].pack('l*') + # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC" + s.unpack('l*') + # => [67305985, -50462977] + +- 'L' - 32-bit unsigned integer, native-endian + (like C uint32_t): + + s = [67305985, 4244504319].pack('L*') + # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC" + s.unpack('L*') + # => [67305985, 4244504319] + +- 'N' - 32-bit network integer, big-endian: + + s = [0,1,-1].pack('N*') + # => "\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFF\xFF\xFF" + s.unpack('N*') + # => [0, 1, 4294967295] + +- 'V' - 32-bit VAX integer, little-endian: + + s = [0,1,-1].pack('V*') + # => "\x00\x00\x00\x00\x01\x00\x00\x00\xFF\xFF\xFF\xFF" + s.unpack('v*') + # => [0, 0, 1, 0, 65535, 65535] + +==== 64-Bit \Integer Directives + +- 'q' - 64-bit signed integer, native-endian + (like C int64_t): + + s = [578437695752307201, -506097522914230529].pack('q*') + # => "\x01\x02\x03\x04\x05\x06\a\b\xFF\xFE\xFD\xFC\xFB\xFA\xF9\xF8" + s.unpack('q*') + # => [578437695752307201, -506097522914230529] + +- 'Q' - 64-bit unsigned integer, native-endian + (like C uint64_t): + + s = [578437695752307201, 17940646550795321087].pack('Q*') + # => "\x01\x02\x03\x04\x05\x06\a\b\xFF\xFE\xFD\xFC\xFB\xFA\xF9\xF8" + s.unpack('Q*') + # => [578437695752307201, 17940646550795321087] + +==== Platform-Dependent \Integer Directives + +- 'i' - Platform-dependent width signed integer, + native-endian (like C int): + + s = [67305985, -50462977].pack('i*') + # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC" + s.unpack('i*') + # => [67305985, -50462977] + +- 'I' - Platform-dependent width unsigned integer, + native-endian (like C unsigned int): + + s = [67305985, -50462977].pack('I*') + # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC" + s.unpack('I*') + # => [67305985, 4244504319] + +==== Pointer Directives + +- 'j' - 64-bit pointer-width signed integer, + native-endian (like C intptr_t): + + s = [67305985, -50462977].pack('j*') + # => "\x01\x02\x03\x04\x00\x00\x00\x00\xFF\xFE\xFD\xFC\xFF\xFF\xFF\xFF" + s.unpack('j*') + # => [67305985, -50462977] + +- 'j' - 64-bit pointer-width unsigned integer, + native-endian (like C uintptr_t): + + s = [67305985, 4244504319].pack('J*') + # => "\x01\x02\x03\x04\x00\x00\x00\x00\xFF\xFE\xFD\xFC\x00\x00\x00\x00" + s.unpack('J*') + # => [67305985, 4244504319] + +==== Other \Integer Directives +: +- 'U' - UTF-8 character: + + s = [4194304].pack('U*') + # => "\xF8\x90\x80\x80\x80" + s.unpack('U*') + # => [4194304] + +- 'w' - BER-encoded integer + (see {BER enocding}[https://en.wikipedia.org/wiki/X.690#BER_encoding]): + + s = [1073741823].pack('w*') + # => "\x83\xFF\xFF\xFF\x7F" + s.unpack('w*') + # => [1073741823] + +==== Modifiers for \Integer Directives + +For directives in +'i', +'I', +'s', +'S', +'l', +'L', +'q', +'Q', +'j', and +'J', +these modifiers may be suffixed: + +- '!' or '_' - Underlying platform’s native size. +- '>' - Big-endian. +- '<' - Little-endian. + +=== \Float Directives + +Each float directive specifies the packing or unpacking +for one element in the input or output array. + +==== Single-Precision \Float Directives + +- 'F' or 'f' - Native format: + + s = [3.0].pack('F') # => "\x00\x00@@" + s.unpack('F') # => [3.0] + +- 'e' - Little-endian: + + s = [3.0].pack('e') # => "\x00\x00@@" + s.unpack('e') # => [3.0] + +- 'g' - Big-endian: + + s = [3.0].pack('g') # => "@@\x00\x00" + s.unpack('g') # => [3.0] + +==== Double-Precision \Float Directives + +- 'D' or 'd' - Native format: + + s = [3.0].pack('D') # => "\x00\x00\x00\x00\x00\x00\b@" + s.unpack('D') # => [3.0] + +- 'E' - Little-endian: + + s = [3.0].pack('E') # => "\x00\x00\x00\x00\x00\x00\b@" + s.unpack('E') # => [3.0] + +- 'G' - Big-endian: + + s = [3.0].pack('G') # => "@\b\x00\x00\x00\x00\x00\x00" + s.unpack('G') # => [3.0] + +A float directive may be infinity or not-a-number: + + inf = 1.0/0.0 # => Infinity + [inf].pack('f') # => "\x00\x00\x80\x7F" + "\x00\x00\x80\x7F".unpack('f') # => [Infinity] + + nan = inf/inf # => NaN + [nan].pack('f') # => "\x00\x00\xC0\x7F" + "\x00\x00\xC0\x7F".unpack('f') # => [NaN] + +=== \String Directives + +Each string directive specifies the packing or unpacking +for one byte in the input or output string. + +==== Binary \String Directives + +- 'A' - Arbitrary binary string (space padded; count is width); + +nil+ is treated as the empty string: + + ['foo'].pack('A') # => "f" + ['foo'].pack('A*') # => "foo" + ['foo'].pack('A2') # => "fo" + ['foo'].pack('A4') # => "foo " + [nil].pack('A') # => " " + [nil].pack('A*') # => "" + [nil].pack('A2') # => " " + [nil].pack('A4') # => " " + + "foo\0".unpack('A') # => ["f"] + "foo\0".unpack('A4') # => ["foo"] + "foo\0bar".unpack('A10') # => ["foo\x00bar"] # Reads past "\0". + "foo ".unpack('A') # => ["f"] + "foo ".unpack('A4') # => ["foo"] + "foo".unpack('A4') # => ["foo"] + + russian = "\u{442 435 441 442}" # => "тест" + russian.size # => 4 + russian.bytesize # => 8 + [russian].pack('A') # => "\xD1" + [russian].pack('A*') # => "\xD1\x82\xD0\xB5\xD1\x81\xD1\x82" + russian.unpack('A') # => ["\xD1"] + russian.unpack('A2') # => ["\xD1\x82"] + russian.unpack('A4') # => ["\xD1\x82\xD0\xB5"] + russian.unpack('A*') # => ["\xD1\x82\xD0\xB5\xD1\x81\xD1\x82"] + +- 'a' - Arbitrary binary string (null padded; count is width): + + ["foo"].pack('a') # => "f" + ["foo"].pack('a*') # => "foo" + ["foo"].pack('a2') # => "fo" + ["foo\0"].pack('a4') # => "foo\x00" + [nil].pack('a') # => "\x00" + [nil].pack('a*') # => "" + [nil].pack('a2') # => "\x00\x00" + [nil].pack('a4') # => "\x00\x00\x00\x00" + + "foo\0".unpack('a') # => ["f"] + "foo\0".unpack('a4') # => ["foo\x00"] + "foo ".unpack('a4') # => ["foo "] + "foo".unpack('a4') # => ["foo"] + "foo\0bar".unpack('a4') # => ["foo\x00"] # Reads past "\0". + +- 'Z' - Same as 'a', + except that null is added or ignored with '*': + + ["foo"].pack('Z*') # => "foo\x00" + [nil].pack('Z*') # => "\x00" + + "foo\0".unpack('Z*') # => ["foo"] + "foo".unpack('Z*') # => ["foo"] + "foo\0bar".unpack('Z*') # => ["foo"] # Does not read past "\0". + +==== Bit \String Directives + +- 'B' - Bit string (high byte first): + + ['11111111' + '00000000'].pack('B*') # => "\xFF\x00" + ['10000000' + '01000000'].pack('B*') # => "\x80@" + + ['1'].pack('B0') # => "" + ['1'].pack('B1') # => "\x80" + ['1'].pack('B2') # => "\x80\x00" + ['1'].pack('B3') # => "\x80\x00" + ['1'].pack('B4') # => "\x80\x00\x00" + ['1'].pack('B5') # => "\x80\x00\x00" + ['1'].pack('B6') # => "\x80\x00\x00\x00" + + "\xff\x00".unpack("B*") # => ["1111111100000000"] + "\x01\x02".unpack("B*") # => ["0000000100000010"] + + "".unpack("B0") # => [""] + "\x80".unpack("B1") # => ["1"] + "\x80".unpack("B2") # => ["10"] + "\x80".unpack("B3") # => ["100"] + +- 'b' - Bit string (low byte first): + + ['11111111' + '00000000'].pack('b*') # => "\xFF\x00" + ['10000000' + '01000000'].pack('b*') # => "\x01\x02" + + ['1'].pack('b0') # => "" + ['1'].pack('b1') # => "\x01" + ['1'].pack('b2') # => "\x01\x00" + ['1'].pack('b3') # => "\x01\x00" + ['1'].pack('b4') # => "\x01\x00\x00" + ['1'].pack('b5') # => "\x01\x00\x00" + ['1'].pack('b6') # => "\x01\x00\x00\x00" + + "\xff\x00".unpack("b*") # => ["1111111100000000"] + "\x01\x02".unpack("b*") # => ["1000000001000000"] + + "".unpack("b0") # => [""] + "\x01".unpack("b1") # => ["1"] + "\x01".unpack("b2") # => ["10"] + "\x01".unpack("b3") # => ["100"] + +==== Hex \String Directives + +- 'H' - Hex string (high nibble first): + + ['10ef'].pack('H*') # => "\x10\xEF" + ['10ef'].pack('H0') # => "" + ['10ef'].pack('H3') # => "\x10\xE0" + ['10ef'].pack('H5') # => "\x10\xEF\x00" + + ['fff'].pack('H3') # => "\xFF\xF0" + ['fff'].pack('H4') # => "\xFF\xF0" + ['fff'].pack('H5') # => "\xFF\xF0\x00" + ['fff'].pack('H6') # => "\xFF\xF0\x00" + ['fff'].pack('H7') # => "\xFF\xF0\x00\x00" + ['fff'].pack('H8') # => "\xFF\xF0\x00\x00" + + "\x10\xef".unpack('H*') # => ["10ef"] + "\x10\xef".unpack('H0') # => [""] + "\x10\xef".unpack('H1') # => ["1"] + "\x10\xef".unpack('H2') # => ["10"] + "\x10\xef".unpack('H3') # => ["10e"] + "\x10\xef".unpack('H4') # => ["10ef"] + "\x10\xef".unpack('H5') # => ["10ef"] + +- 'h' - Hex string (low nibble first): + + ['10ef'].pack('h*') # => "\x01\xFE" + ['10ef'].pack('h0') # => "" + ['10ef'].pack('h3') # => "\x01\x0E" + ['10ef'].pack('h5') # => "\x01\xFE\x00" + + ['fff'].pack('h3') # => "\xFF\x0F" + ['fff'].pack('h4') # => "\xFF\x0F" + ['fff'].pack('h5') # => "\xFF\x0F\x00" + ['fff'].pack('h6') # => "\xFF\x0F\x00" + ['fff'].pack('h7') # => "\xFF\x0F\x00\x00" + ['fff'].pack('h8') # => "\xFF\x0F\x00\x00" + + "\x01\xfe".unpack('h*') # => ["10ef"] + "\x01\xfe".unpack('h0') # => [""] + "\x01\xfe".unpack('h1') # => ["1"] + "\x01\xfe".unpack('h2') # => ["10"] + "\x01\xfe".unpack('h3') # => ["10e"] + "\x01\xfe".unpack('h4') # => ["10ef"] + "\x01\xfe".unpack('h5') # => ["10ef"] + +==== Pointer \String Directives + +- 'P' - Pointer to a structure (fixed-length string): + + s = ['abc'].pack('P') # => "\xE0O\x7F\xE5\xA1\x01\x00\x00" + s.unpack('P*') # => ["abc"] + ".".unpack("P") # => [] + ("\0" * 8).unpack("P") # => [nil] + [nil].pack("P") # => "\x00\x00\x00\x00\x00\x00\x00\x00" + +- 'p' - Pointer to a null-terminated string: + + s = ['abc'].pack('p') # => "(\xE4u\xE5\xA1\x01\x00\x00" + s.unpack('p*') # => ["abc"] + ".".unpack("p") # => [] + ("\0" * 8).unpack("p") # => [nil] + [nil].pack("p") # => "\x00\x00\x00\x00\x00\x00\x00\x00" + +==== Other \String Directives + +- 'M' - Quoted printable, MIME encoding; + text mode, but input must use LF and output LF; + (see {RFC 2045}[https://www.ietf.org/rfc/rfc2045.txt]): + + ["a b c\td \ne"].pack('M') # => "a b c\td =\n\ne=\n" + ["\0"].pack('M') # => "=00=\n" + + ["a"*1023].pack('M') == ("a"*73+"=\n")*14+"a=\n" # => true + ("a"*73+"=\na=\n").unpack('M') == ["a"*74] # => true + (("a"*73+"=\n")*14+"a=\n").unpack('M') == ["a"*1023] # => true + + "a b c\td =\n\ne=\n".unpack('M') # => ["a b c\td \ne"] + "=00=\n".unpack('M') # => ["\x00"] + + "pre=31=32=33after".unpack('M') # => ["pre123after"] + "pre=\nafter".unpack('M') # => ["preafter"] + "pre=\r\nafter".unpack('M') # => ["preafter"] + "pre=".unpack('M') # => ["pre="] + "pre=\r".unpack('M') # => ["pre=\r"] + "pre=hoge".unpack('M') # => ["pre=hoge"] + "pre==31after".unpack('M') # => ["pre==31after"] + "pre===31after".unpack('M') # => ["pre===31after"] + +- 'm' - Base64 encoded string; + count specifies input bytes between each newline, + rounded down to nearest multiple of 3; + if count is zero, no newlines are added; + (see {RFC 4648}[https://www.ietf.org/rfc/rfc4648.txt]): + + [""].pack('m') # => "" + ["\0"].pack('m') # => "AA==\n" + ["\0\0"].pack('m') # => "AAA=\n" + ["\0\0\0"].pack('m') # => "AAAA\n" + ["\377"].pack('m') # => "/w==\n" + ["\377\377"].pack('m') # => "//8=\n" + ["\377\377\377"].pack('m') # => "////\n" + + "".unpack('m') # => [""] + "AA==\n".unpack('m') # => ["\x00"] + "AAA=\n".unpack('m') # => ["\x00\x00"] + "AAAA\n".unpack('m') # => ["\x00\x00\x00"] + "/w==\n".unpack('m') # => ["\xFF"] + "//8=\n".unpack('m') # => ["\xFF\xFF"] + "////\n".unpack('m') # => ["\xFF\xFF\xFF"] + "A\n".unpack('m') # => [""] + "AA\n".unpack('m') # => ["\x00"] + "AA=\n".unpack('m') # => ["\x00"] + "AAA\n".unpack('m') # => ["\x00\x00"] + + [""].pack('m0') # => "" + ["\0"].pack('m0') # => "AA==" + ["\0\0"].pack('m0') # => "AAA=" + ["\0\0\0"].pack('m0') # => "AAAA" + ["\377"].pack('m0') # => "/w==" + ["\377\377"].pack('m0') # => "//8=" + ["\377\377\377"].pack('m0') # => "////" + + "".unpack('m0') # => [""] + "AA==".unpack('m0') # => ["\x00"] + "AAA=".unpack('m0') # => ["\x00\x00"] + "AAAA".unpack('m0') # => ["\x00\x00\x00"] + "/w==".unpack('m0') # => ["\xFF"] + "//8=".unpack('m0') # => ["\xFF\xFF"] + "////".unpack('m0') # => ["\xFF\xFF\xFF"] + +- 'u' - UU-encoded string: + + [0].pack("U") # => "\u0000" + [0x3fffffff].pack("U") # => "\xFC\xBF\xBF\xBF\xBF\xBF" + [0x40000000].pack("U") # => "\xFD\x80\x80\x80\x80\x80" + [0x7fffffff].pack("U") # => "\xFD\xBF\xBF\xBF\xBF\xBF" + +=== Offset Directives + +- '@' - Begin packing at the given byte offset; + for packing, null fill if necessary: + + [1, 2].pack("C@0C") # => "\x02" + [1, 2].pack("C@1C") # => "\x01\x02" + [1, 2].pack("C@5C") # => "\x01\x00\x00\x00\x00\x02" + + "\x01\x00\x00\x02".unpack("C@3C") # => [1, 2] + "\x00".unpack("@1C") # => [nil] + +- 'X' - Back up a byte: + + [0, 1, 2].pack("CCXC") # => "\x00\x02" + [0, 1, 2].pack("CCX2C") # => "\x02" + "\x00\x02".unpack("CCXC") # => [0, 2, 2] + +=== Null Byte Direcive + +- 'x' - Null byte: + + [].pack("x0") # => "" + [].pack("x") # => "\x00" + [].pack("x8") # => "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x02".unpack("CxC") # => [0, 2] diff --git a/doc/yjit/yjit.md b/doc/yjit/yjit.md index c2521eba426bf9..d4a15d0c7795e7 100644 --- a/doc/yjit/yjit.md +++ b/doc/yjit/yjit.md @@ -13,8 +13,7 @@ YJIT - Yet Another Ruby JIT YJIT is a lightweight, minimalistic Ruby JIT built inside CRuby. It lazily compiles code using a Basic Block Versioning (BBV) architecture. The target use case is that of servers running Ruby on Rails, an area where MJIT has not yet managed to deliver speedups. -To simplify development, we currently support only macOS and Linux on x86-64, but an ARM64 backend -is part of future plans. +YJIT is currently supported for macOS and Linux on x86-64 and arm64/aarch64 CPUs. This project is open source and falls under the same license as CRuby. If you wish to learn more about the approach taken, here are some conference talks and publications: @@ -105,10 +104,12 @@ make -j install ``` Typically configure will choose the default C compiler. To specify the C compiler, use + ``` # Choosing a specific c compiler export CC=/path/to/my/chosen/c/compiler ``` + before running `./configure`. You can test that YJIT works correctly by running: @@ -141,15 +142,15 @@ You can dump statistics about compilation and execution by running YJIT with the The machine code generated for a given method can be printed by adding `puts RubyVM::YJIT.disasm(method(:method_name))` to a Ruby script. Note that no code will be generated if the method is not compiled. - ### Command-Line Options YJIT supports all command-line options supported by upstream CRuby, but also adds a few YJIT-specific options: - `--yjit`: enable YJIT (disabled by default) -- `--yjit-call-threshold=N`: number of calls after which YJIT begins to compile a function (default 2) +- `--yjit-call-threshold=N`: number of calls after which YJIT begins to compile a function (default 10) - `--yjit-exec-mem-size=N`: size of the executable memory block to allocate, in MiB (default 256 MiB) - `--yjit-stats`: produce statistics after the execution of a program (must compile with `cppflags=-DRUBY_DEBUG` to use this) +- `--yjit-trace-exits`: produce a Marshal dump of backtraces from specific exits. Automatically enables `--yjit-stats` (must compile with `cppflags=-DRUBY_DEBUG` to use this) - `--yjit-max-versions=N`: maximum number of versions to generate per basic block (default 4) - `--yjit-greedy-versioning`: greedy versioning mode (disabled by default, may increase code size) @@ -176,7 +177,7 @@ You can also compile YJIT in debug mode and use the `--yjit-stats` command-line ### Memory Statistics -YJIT, including in production configuration, keeps track of the size of generated code. If you check YJIT.runtime_stats you can see them: +YJIT, including in production configuration, keeps track of the size of generated code. If you check `YJIT.runtime_stats` you can see them: ``` $ RUBYOPT="--yjit" irb @@ -188,11 +189,11 @@ These are the size in bytes of generated inlined code and generated outlined cod ### Other Statistics -If you compile Ruby with RUBY_DEBUG and/or YJIT_STATS defined and run with "--yjit --yjit-stats", YJIT will track and return performance statistics in RubyVM::YJIT.runtime_stats. +If you compile Ruby with `RUBY_DEBUG` and/or `YJIT_STATS` defined and run with `--yjit --yjit-stats`, YJIT will track and return performance statistics in `RubyVM::YJIT.runtime_stats`. ``` $ RUBYOPT="--yjit --yjit-stats" irb -irb(main):001:0> YJIT.runtime_stats +irb(main):001:0> RubyVM::YJIT.runtime_stats => {:inline_code_size=>340745, :outlined_code_size=>297664, diff --git a/error.c b/error.c index b37d139b7cba8a..ceea1c55d1f6c7 100644 --- a/error.c +++ b/error.c @@ -666,6 +666,11 @@ bug_important_message(FILE *out, const char *const msg, size_t len) fwrite(p, 1, endmsg - p, out); } +#undef CRASH_REPORTER_MAY_BE_CREATED +#if defined(__APPLE__) && \ + (!defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6) +# define CRASH_REPORTER_MAY_BE_CREATED +#endif static void preface_dump(FILE *out) { @@ -674,7 +679,7 @@ preface_dump(FILE *out) "-- Crash Report log information " "--------------------------------------------\n" " See Crash Report log file in one of the following locations:\n" -# if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 +# ifdef CRASH_REPORTER_MAY_BE_CREATED " * ~/Library/Logs/CrashReporter\n" " * /Library/Logs/CrashReporter\n" # endif @@ -699,7 +704,7 @@ postscript_dump(FILE *out) "[IMPORTANT]" /*" ------------------------------------------------"*/ "\n""Don't forget to include the Crash Report log file under\n" -# if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 +# ifdef CRASH_REPORTER_MAY_BE_CREATED "CrashReporter or " # endif "DiagnosticReports directory in bug reports.\n" diff --git a/eval.c b/eval.c index 9567f801501d86..f5c9c0f087075e 100644 --- a/eval.c +++ b/eval.c @@ -21,6 +21,7 @@ #include "gc.h" #include "internal.h" #include "internal/class.h" +#include "internal/cont.h" #include "internal/error.h" #include "internal/eval.h" #include "internal/hash.h" @@ -251,7 +252,8 @@ rb_ec_cleanup(rb_execution_context_t *ec, int ex0) } } - mjit_finish(true); // We still need ISeqs here. + mjit_finish(true); // We still need ISeqs here, so it's before rb_ec_finalize(). + rb_jit_cont_finish(); rb_ec_finalize(ec); diff --git a/ext/coverage/depend b/ext/coverage/depend index 57d368d3f53660..719c6c6e791551 100644 --- a/ext/coverage/depend +++ b/ext/coverage/depend @@ -165,7 +165,9 @@ coverage.o: $(top_srcdir)/ccan/check_type/check_type.h coverage.o: $(top_srcdir)/ccan/container_of/container_of.h coverage.o: $(top_srcdir)/ccan/list/list.h coverage.o: $(top_srcdir)/ccan/str/str.h +coverage.o: $(top_srcdir)/constant.h coverage.o: $(top_srcdir)/gc.h +coverage.o: $(top_srcdir)/id_table.h coverage.o: $(top_srcdir)/internal.h coverage.o: $(top_srcdir)/internal/array.h coverage.o: $(top_srcdir)/internal/compilers.h @@ -176,12 +178,14 @@ coverage.o: $(top_srcdir)/internal/sanitizers.h coverage.o: $(top_srcdir)/internal/serial.h coverage.o: $(top_srcdir)/internal/static_assert.h coverage.o: $(top_srcdir)/internal/thread.h +coverage.o: $(top_srcdir)/internal/variable.h coverage.o: $(top_srcdir)/internal/vm.h coverage.o: $(top_srcdir)/internal/warnings.h coverage.o: $(top_srcdir)/method.h coverage.o: $(top_srcdir)/node.h coverage.o: $(top_srcdir)/ruby_assert.h coverage.o: $(top_srcdir)/ruby_atomic.h +coverage.o: $(top_srcdir)/shape.h coverage.o: $(top_srcdir)/thread_pthread.h coverage.o: $(top_srcdir)/vm_core.h coverage.o: $(top_srcdir)/vm_opts.h diff --git a/ext/date/date_core.c b/ext/date/date_core.c index 83d493c794842a..96653e0a7879e2 100644 --- a/ext/date/date_core.c +++ b/ext/date/date_core.c @@ -4377,7 +4377,7 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass, * Date._strptime('2001-02-03', '%Y-%m-%d') # => {:year=>2001, :mon=>2, :mday=>3} * * For other formats, see - * {Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html]. + * {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]. * (Unlike Date.strftime, does not support flags and width.) * * See also {strptime(3)}[https://man7.org/linux/man-pages/man3/strptime.3.html]. @@ -4406,7 +4406,7 @@ date_s__strptime(int argc, VALUE *argv, VALUE klass) * Date.strptime('sat3feb01', '%a%d%b%y') # => # * * For other formats, see - * {Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html]. + * {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]. * (Unlike Date.strftime, does not support flags and width.) * * See argument {start}[rdoc-ref:calendars.rdoc@Argument+start]. @@ -4506,7 +4506,7 @@ date_s__parse_internal(int argc, VALUE *argv, VALUE klass) * This method recognizes many forms in +string+, * but it is not a validator. * For formats, see - * {"Specialized Format Strings" in Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-Specialized+Format+Strings] + * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc@Specialized+Format+Strings] * * If +string+ does not specify a valid date, * the result is unpredictable; @@ -4541,7 +4541,7 @@ date_s__parse(int argc, VALUE *argv, VALUE klass) * This method recognizes many forms in +string+, * but it is not a validator. * For formats, see - * {"Specialized Format Strings" in Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-Specialized+Format+Strings] + * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc@Specialized+Format+Strings] * If +string+ does not specify a valid date, * the result is unpredictable; * consider using Date._strptime instead. @@ -4606,7 +4606,7 @@ VALUE date__jisx0301(VALUE); * Date._iso8601(string, limit: 128) -> hash * * Returns a hash of values parsed from +string+, which should contain - * an {ISO 8601 formatted date}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-ISO+8601+Format+Specifications]: + * an {ISO 8601 formatted date}[rdoc-ref:strftime_formatting.rdoc@ISO+8601+Format+Specifications]: * * d = Date.new(2001, 2, 3) * s = d.iso8601 # => "2001-02-03" @@ -4633,7 +4633,7 @@ date_s__iso8601(int argc, VALUE *argv, VALUE klass) * * Returns a new \Date object with values parsed from +string+, * which should contain - * an {ISO 8601 formatted date}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-ISO+8601+Format+Specifications]: + * an {ISO 8601 formatted date}[rdoc-ref:strftime_formatting.rdoc@ISO+8601+Format+Specifications]: * * d = Date.new(2001, 2, 3) * s = d.iso8601 # => "2001-02-03" @@ -4676,7 +4676,7 @@ date_s_iso8601(int argc, VALUE *argv, VALUE klass) * Date._rfc3339(string, limit: 128) -> hash * * Returns a hash of values parsed from +string+, which should be a valid - * {RFC 3339 format}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-RFC+3339+Format]: + * {RFC 3339 format}[rdoc-ref:strftime_formatting.rdoc@RFC+3339+Format]: * * d = Date.new(2001, 2, 3) * s = d.rfc3339 # => "2001-02-03T00:00:00+00:00" @@ -4704,7 +4704,7 @@ date_s__rfc3339(int argc, VALUE *argv, VALUE klass) * * Returns a new \Date object with values parsed from +string+, * which should be a valid - * {RFC 3339 format}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-RFC+3339+Format]: + * {RFC 3339 format}[rdoc-ref:strftime_formatting.rdoc@RFC+3339+Format]: * * d = Date.new(2001, 2, 3) * s = d.rfc3339 # => "2001-02-03T00:00:00+00:00" @@ -4816,7 +4816,7 @@ date_s_xmlschema(int argc, VALUE *argv, VALUE klass) * Date._rfc2822(string, limit: 128) -> hash * * Returns a hash of values parsed from +string+, which should be a valid - * {RFC 2822 date format}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-RFC+2822+Format]: + * {RFC 2822 date format}[rdoc-ref:strftime_formatting.rdoc@RFC+2822+Format]: * * d = Date.new(2001, 2, 3) * s = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000" @@ -4846,7 +4846,7 @@ date_s__rfc2822(int argc, VALUE *argv, VALUE klass) * * Returns a new \Date object with values parsed from +string+, * which should be a valid - * {RFC 2822 date format}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-RFC+2822+Format]: + * {RFC 2822 date format}[rdoc-ref:strftime_formatting.rdoc@RFC+2822+Format]: * * d = Date.new(2001, 2, 3) * s = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000" @@ -4890,7 +4890,7 @@ date_s_rfc2822(int argc, VALUE *argv, VALUE klass) * Date._httpdate(string, limit: 128) -> hash * * Returns a hash of values parsed from +string+, which should be a valid - * {HTTP date format}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-HTTP+Format]: + * {HTTP date format}[rdoc-ref:strftime_formatting.rdoc@HTTP+Format]: * * d = Date.new(2001, 2, 3) * s = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT" @@ -4916,7 +4916,7 @@ date_s__httpdate(int argc, VALUE *argv, VALUE klass) * * Returns a new \Date object with values parsed from +string+, * which should be a valid - * {HTTP date format}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-HTTP+Format]: + * {HTTP date format}[rdoc-ref:strftime_formatting.rdoc@HTTP+Format]: * * d = Date.new(2001, 2, 3) s = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT" @@ -4958,7 +4958,7 @@ date_s_httpdate(int argc, VALUE *argv, VALUE klass) * Date._jisx0301(string, limit: 128) -> hash * * Returns a hash of values parsed from +string+, which should be a valid - * {JIS X 0301 date format}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-JIS+X+0301+Format]: + * {JIS X 0301 date format}[rdoc-ref:strftime_formatting.rdoc@JIS+X+0301+Format]: * * d = Date.new(2001, 2, 3) * s = d.jisx0301 # => "H13.02.03" @@ -4984,7 +4984,7 @@ date_s__jisx0301(int argc, VALUE *argv, VALUE klass) * Date.jisx0301(string = '-4712-01-01', start = Date::ITALY, limit: 128) -> date * * Returns a new \Date object with values parsed from +string+, - * which should be a valid {JIS X 0301 format}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-JIS+X+0301+Format]: + * which should be a valid {JIS X 0301 format}[rdoc-ref:strftime_formatting.rdoc@JIS+X+0301+Format]: * * d = Date.new(2001, 2, 3) * s = d.jisx0301 # => "H13.02.03" @@ -6971,7 +6971,7 @@ static VALUE strftimev(const char *, VALUE, * to_s -> string * * Returns a string representation of the date in +self+ - * in {ISO 8601 extended date format}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-ISO+8601+Format+Specifications] + * in {ISO 8601 extended date format}[rdoc-ref:strftime_formatting.rdoc@ISO+8601+Format+Specifications] * ('%Y-%m-%d'): * * Date.new(2001, 2, 3).to_s # => "2001-02-03" @@ -7252,7 +7252,7 @@ date_strftime_internal(int argc, VALUE *argv, VALUE self, * Date.new(2001, 2, 3).strftime # => "2001-02-03" * * For other formats, see - * {Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html]. + * {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]. * */ static VALUE @@ -7284,7 +7284,7 @@ strftimev(const char *fmt, VALUE self, * asctime -> string * * Equivalent to #strftime with argument '%a %b %e %T %Y' - * (or its {shorthand form}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-Shorthand+Conversion+Specifiers] + * (or its {shorthand form}[rdoc-ref:strftime_formatting.rdoc@Shorthand+Conversion+Specifiers] * '%c'): * * Date.new(2001, 2, 3).asctime # => "Sat Feb 3 00:00:00 2001" @@ -7304,7 +7304,7 @@ d_lite_asctime(VALUE self) * iso8601 -> string * * Equivalent to #strftime with argument '%Y-%m-%d' - * (or its {shorthand form}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-Shorthand+Conversion+Specifiers] + * (or its {shorthand form}[rdoc-ref:strftime_formatting.rdoc@Shorthand+Conversion+Specifiers] * '%F'); * * Date.new(2001, 2, 3).iso8601 # => "2001-02-03" @@ -7322,7 +7322,7 @@ d_lite_iso8601(VALUE self) * rfc3339 -> string * * Equivalent to #strftime with argument '%FT%T%:z'; - * see {Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html]: + * see {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]: * * Date.new(2001, 2, 3).rfc3339 # => "2001-02-03T00:00:00+00:00" * @@ -7338,7 +7338,7 @@ d_lite_rfc3339(VALUE self) * rfc2822 -> string * * Equivalent to #strftime with argument '%a, %-d %b %Y %T %z'; - * see {Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html]: + * see {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]: * * Date.new(2001, 2, 3).rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000" * @@ -7355,7 +7355,7 @@ d_lite_rfc2822(VALUE self) * httpdate -> string * * Equivalent to #strftime with argument '%a, %d %b %Y %T GMT'; - * see {Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html]: + * see {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]: * * Date.new(2001, 2, 3).httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT" * @@ -9392,7 +9392,7 @@ Init_date_core(void) * calendar dates. * * Consider using - * {class Time}[https://docs.ruby-lang.org/en/master/Time.html] + * {class Time}[rdoc-ref:Time] * instead of class \Date if: * * - You need both dates and times; \Date handles only dates. @@ -9444,7 +9444,7 @@ Init_date_core(void) * Date.strptime('fri31dec99', '%a%d%b%y') # => # * * See also the specialized methods in - * {"Specialized Format Strings" in Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-Specialized+Format+Strings] + * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc@Specialized+Format+Strings] * * == Argument +limit+ * diff --git a/ext/fiddle/closure.c b/ext/fiddle/closure.c index 6770162b9408a6..892f522a620e27 100644 --- a/ext/fiddle/closure.c +++ b/ext/fiddle/closure.c @@ -56,6 +56,8 @@ closure_memsize(const void * ptr) const rb_data_type_t closure_data_type = { "fiddle/closure", {0, dealloc, closure_memsize,}, + 0, 0, + RUBY_TYPED_FREE_IMMEDIATELY, }; struct callback_args { @@ -74,7 +76,7 @@ with_gvl_callback(void *ptr) VALUE rbargs = rb_iv_get(self, "@args"); VALUE ctype = rb_iv_get(self, "@ctype"); int argc = RARRAY_LENINT(rbargs); - VALUE params = rb_ary_hidden_new(argc); + VALUE params = rb_ary_tmp_new(argc); VALUE ret; VALUE cPointer; int i, type; diff --git a/ext/fiddle/lib/fiddle.rb b/ext/fiddle/lib/fiddle.rb index 09262c43fff3f4..6137c487c67887 100644 --- a/ext/fiddle/lib/fiddle.rb +++ b/ext/fiddle/lib/fiddle.rb @@ -58,7 +58,36 @@ def self.last_error= error # # See Fiddle::Handle.new for more. def dlopen library - Fiddle::Handle.new library + begin + Fiddle::Handle.new(library) + rescue DLError => error + case RUBY_PLATFORM + when /linux/ + case error.message + when /\A(\/.+?): (?:invalid ELF header|file too short)/ + # This may be a linker script: + # https://sourceware.org/binutils/docs/ld.html#Scripts + path = $1 + else + raise + end + else + raise + end + + File.open(path) do |input| + input.each_line do |line| + case line + when /\A\s*(?:INPUT|GROUP)\s*\(\s*([^\s,\)]+)/ + # TODO: Should we support multiple files? + return dlopen($1) + end + end + end + + # Not found + raise + end end module_function :dlopen diff --git a/ext/fiddle/lib/fiddle/version.rb b/ext/fiddle/lib/fiddle/version.rb index db6504b65080f4..719dc62e37c24c 100644 --- a/ext/fiddle/lib/fiddle/version.rb +++ b/ext/fiddle/lib/fiddle/version.rb @@ -1,3 +1,3 @@ module Fiddle - VERSION = "1.1.0" + VERSION = "1.1.1" end diff --git a/ext/objspace/depend b/ext/objspace/depend index c4da8031cc7087..88c66a232b7f57 100644 --- a/ext/objspace/depend +++ b/ext/objspace/depend @@ -350,6 +350,7 @@ objspace.o: $(top_srcdir)/internal/serial.h objspace.o: $(top_srcdir)/internal/static_assert.h objspace.o: $(top_srcdir)/internal/warnings.h objspace.o: $(top_srcdir)/node.h +objspace.o: $(top_srcdir)/shape.h objspace.o: $(top_srcdir)/symbol.h objspace.o: objspace.c objspace.o: {$(VPATH)}id.h @@ -533,7 +534,9 @@ objspace_dump.o: $(top_srcdir)/ccan/check_type/check_type.h objspace_dump.o: $(top_srcdir)/ccan/container_of/container_of.h objspace_dump.o: $(top_srcdir)/ccan/list/list.h objspace_dump.o: $(top_srcdir)/ccan/str/str.h +objspace_dump.o: $(top_srcdir)/constant.h objspace_dump.o: $(top_srcdir)/gc.h +objspace_dump.o: $(top_srcdir)/id_table.h objspace_dump.o: $(top_srcdir)/internal.h objspace_dump.o: $(top_srcdir)/internal/array.h objspace_dump.o: $(top_srcdir)/internal/compilers.h @@ -544,12 +547,14 @@ objspace_dump.o: $(top_srcdir)/internal/sanitizers.h objspace_dump.o: $(top_srcdir)/internal/serial.h objspace_dump.o: $(top_srcdir)/internal/static_assert.h objspace_dump.o: $(top_srcdir)/internal/string.h +objspace_dump.o: $(top_srcdir)/internal/variable.h objspace_dump.o: $(top_srcdir)/internal/vm.h objspace_dump.o: $(top_srcdir)/internal/warnings.h objspace_dump.o: $(top_srcdir)/method.h objspace_dump.o: $(top_srcdir)/node.h objspace_dump.o: $(top_srcdir)/ruby_assert.h objspace_dump.o: $(top_srcdir)/ruby_atomic.h +objspace_dump.o: $(top_srcdir)/shape.h objspace_dump.o: $(top_srcdir)/thread_pthread.h objspace_dump.o: $(top_srcdir)/vm_core.h objspace_dump.o: $(top_srcdir)/vm_opts.h diff --git a/ext/openssl/History.md b/ext/openssl/History.md index 479ec3b4a25b11..a4f6bd7fd6123f 100644 --- a/ext/openssl/History.md +++ b/ext/openssl/History.md @@ -1,3 +1,27 @@ +Version 3.0.1 +============= + +Merged changes in 2.1.4 and 2.2.2. Additionally, the following issues are fixed +by this release. + +Bug fixes +--------- + +* Add missing type check in OpenSSL::PKey::PKey#sign's optional parameters. + [[GitHub #531]](https://github.com/ruby/openssl/pull/531) +* Work around OpenSSL 3.0's HMAC issues with a zero-length key. + [[GitHub #538]](https://github.com/ruby/openssl/pull/538) +* Fix a regression in OpenSSL::PKey::DSA.generate's default of 'q' size. + [[GitHub #483]](https://github.com/ruby/openssl/issues/483) + [[GitHub #539]](https://github.com/ruby/openssl/pull/539) +* Restore OpenSSL::PKey.read's ability to decode "openssl ecparam -genkey" + output when linked against OpenSSL 3.0. + [[GitHub #535]](https://github.com/ruby/openssl/pull/535) + [[GitHub #540]](https://github.com/ruby/openssl/pull/540) +* Restore error checks in OpenSSL::PKey::EC#{to_der,to_pem}. + [[GitHub #541]](https://github.com/ruby/openssl/pull/541) + + Version 3.0.0 ============= @@ -100,6 +124,12 @@ Notable changes [[GitHub #342]](https://github.com/ruby/openssl/issues/342) +Version 2.2.2 +============= + +Merged changes in 2.1.4. + + Version 2.2.1 ============= @@ -194,6 +224,16 @@ Notable changes [[GitHub #297]](https://github.com/ruby/openssl/pull/297) +Version 2.1.4 +============= + +Bug fixes +--------- + +* Do not use pkg-config if --with-openssl-dir option is specified. + [[GitHub #486]](https://github.com/ruby/openssl/pull/486) + + Version 2.1.3 ============= diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb index cc2b1f8ba2383b..fd96533569454a 100644 --- a/ext/openssl/extconf.rb +++ b/ext/openssl/extconf.rb @@ -120,8 +120,13 @@ def find_openssl_library end Logging::message "=== Checking for OpenSSL features... ===\n" +evp_h = "openssl/evp.h".freeze +x509_h = "openssl/x509.h".freeze +ts_h = "openssl/ts.h".freeze +ssl_h = "openssl/ssl.h".freeze + # compile options -have_func("RAND_egd") +have_func("RAND_egd", "openssl/rand.h") engines = %w{dynamic 4758cca aep atalla chil cswift nuron sureware ubsec padlock capi gmp gost cryptodev} engines.each { |name| @@ -132,56 +137,57 @@ def find_openssl_library if !have_struct_member("SSL", "ctx", "openssl/ssl.h") || is_libressl $defs.push("-DHAVE_OPAQUE_OPENSSL") end -have_func("EVP_MD_CTX_new") -have_func("EVP_MD_CTX_free") -have_func("EVP_MD_CTX_pkey_ctx") -have_func("X509_STORE_get_ex_data") -have_func("X509_STORE_set_ex_data") -have_func("X509_STORE_get_ex_new_index") -have_func("X509_CRL_get0_signature") -have_func("X509_REQ_get0_signature") -have_func("X509_REVOKED_get0_serialNumber") -have_func("X509_REVOKED_get0_revocationDate") -have_func("X509_get0_tbs_sigalg") -have_func("X509_STORE_CTX_get0_untrusted") -have_func("X509_STORE_CTX_get0_cert") -have_func("X509_STORE_CTX_get0_chain") -have_func("OCSP_SINGLERESP_get0_id") -have_func("SSL_CTX_get_ciphers") -have_func("X509_up_ref") -have_func("X509_CRL_up_ref") -have_func("X509_STORE_up_ref") -have_func("SSL_SESSION_up_ref") -have_func("EVP_PKEY_up_ref") -have_func("SSL_CTX_set_min_proto_version(NULL, 0)", "openssl/ssl.h") -have_func("SSL_CTX_get_security_level") -have_func("X509_get0_notBefore") -have_func("SSL_SESSION_get_protocol_version") -have_func("TS_STATUS_INFO_get0_status") -have_func("TS_STATUS_INFO_get0_text") -have_func("TS_STATUS_INFO_get0_failure_info") -have_func("TS_VERIFY_CTS_set_certs(NULL, NULL)", "openssl/ts.h") -have_func("TS_VERIFY_CTX_set_store") -have_func("TS_VERIFY_CTX_add_flags") -have_func("TS_RESP_CTX_set_time_cb") -have_func("EVP_PBE_scrypt") -have_func("SSL_CTX_set_post_handshake_auth") +have_func("EVP_MD_CTX_new", evp_h) +have_func("EVP_MD_CTX_free", evp_h) +have_func("EVP_MD_CTX_pkey_ctx", evp_h) +have_func("X509_STORE_get_ex_data", x509_h) +have_func("X509_STORE_set_ex_data", x509_h) +have_func("X509_STORE_get_ex_new_index(0, NULL, NULL, NULL, NULL)", x509_h) +have_func("X509_CRL_get0_signature", x509_h) +have_func("X509_REQ_get0_signature", x509_h) +have_func("X509_REVOKED_get0_serialNumber", x509_h) +have_func("X509_REVOKED_get0_revocationDate", x509_h) +have_func("X509_get0_tbs_sigalg", x509_h) +have_func("X509_STORE_CTX_get0_untrusted", x509_h) +have_func("X509_STORE_CTX_get0_cert", x509_h) +have_func("X509_STORE_CTX_get0_chain", x509_h) +have_func("OCSP_SINGLERESP_get0_id", "openssl/ocsp.h") +have_func("SSL_CTX_get_ciphers", ssl_h) +have_func("X509_up_ref", x509_h) +have_func("X509_CRL_up_ref", x509_h) +have_func("X509_STORE_up_ref", x509_h) +have_func("SSL_SESSION_up_ref", ssl_h) +have_func("EVP_PKEY_up_ref", evp_h) +have_func("SSL_CTX_set_min_proto_version(NULL, 0)", ssl_h) +have_func("SSL_CTX_get_security_level", ssl_h) +have_func("X509_get0_notBefore", x509_h) +have_func("SSL_SESSION_get_protocol_version", ssl_h) +have_func("TS_STATUS_INFO_get0_status", ts_h) +have_func("TS_STATUS_INFO_get0_text", ts_h) +have_func("TS_STATUS_INFO_get0_failure_info", ts_h) +have_func("TS_VERIFY_CTS_set_certs(NULL, NULL)", ts_h) +have_func("TS_VERIFY_CTX_set_store", ts_h) +have_func("TS_VERIFY_CTX_add_flags", ts_h) +have_func("TS_RESP_CTX_set_time_cb", ts_h) +have_func("EVP_PBE_scrypt", evp_h) +have_func("SSL_CTX_set_post_handshake_auth", ssl_h) # added in 1.1.1 -have_func("EVP_PKEY_check") -have_func("SSL_CTX_set_ciphersuites") +have_func("EVP_PKEY_check", evp_h) +have_func("EVP_PKEY_new_raw_private_key", evp_h) +have_func("SSL_CTX_set_ciphersuites", ssl_h) # added in 3.0.0 openssl_3 = -have_func("SSL_set0_tmp_dh_pkey") -have_func("ERR_get_error_all") -have_func("TS_VERIFY_CTX_set_certs(NULL, NULL)", "openssl/ts.h") -have_func("SSL_CTX_load_verify_file") -have_func("BN_check_prime") -have_func("EVP_MD_CTX_get0_md") -have_func("EVP_MD_CTX_get_pkey_ctx") -have_func("EVP_PKEY_eq") -have_func("EVP_PKEY_dup") +have_func("SSL_set0_tmp_dh_pkey", ssl_h) +have_func("ERR_get_error_all", "openssl/err.h") +have_func("TS_VERIFY_CTX_set_certs(NULL, NULL)", ts_h) +have_func("SSL_CTX_load_verify_file", ssl_h) +have_func("BN_check_prime", "openssl/bn.h") +have_func("EVP_MD_CTX_get0_md", evp_h) +have_func("EVP_MD_CTX_get_pkey_ctx", evp_h) +have_func("EVP_PKEY_eq", evp_h) +have_func("EVP_PKEY_dup", evp_h) Logging::message "=== Checking done. ===\n" diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb index c3e06290910de1..0414658a106134 100644 --- a/ext/openssl/lib/openssl/pkey.rb +++ b/ext/openssl/lib/openssl/pkey.rb @@ -167,8 +167,16 @@ class << self # +size+:: # The desired key size in bits. def generate(size, &blk) + # FIPS 186-4 specifies four (L,N) pairs: (1024,160), (2048,224), + # (2048,256), and (3072,256). + # + # q size is derived here with compatibility with + # DSA_generator_parameters_ex() which previous versions of ruby/openssl + # used to call. + qsize = size >= 2048 ? 256 : 160 dsaparams = OpenSSL::PKey.generate_parameters("DSA", { "dsa_paramgen_bits" => size, + "dsa_paramgen_q_bits" => qsize, }, &blk) OpenSSL::PKey.generate_key(dsaparams) end @@ -355,7 +363,8 @@ def new(*args, &blk) # :nodoc: # rsa.private_encrypt(string, padding) -> String # # Encrypt +string+ with the private key. +padding+ defaults to - # PKCS1_PADDING. The encrypted string output can be decrypted using + # PKCS1_PADDING, which is known to be insecure but is kept for backwards + # compatibility. The encrypted string output can be decrypted using # #public_decrypt. # # Deprecated in version 3.0. @@ -378,7 +387,8 @@ def private_encrypt(string, padding = PKCS1_PADDING) # rsa.public_decrypt(string, padding) -> String # # Decrypt +string+, which has been encrypted with the private key, with the - # public key. +padding+ defaults to PKCS1_PADDING. + # public key. +padding+ defaults to PKCS1_PADDING which is known to be + # insecure but is kept for backwards compatibility. # # Deprecated in version 3.0. # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and @@ -399,7 +409,8 @@ def public_decrypt(string, padding = PKCS1_PADDING) # rsa.public_encrypt(string, padding) -> String # # Encrypt +string+ with the public key. +padding+ defaults to - # PKCS1_PADDING. The encrypted string output can be decrypted using + # PKCS1_PADDING, which is known to be insecure but is kept for backwards + # compatibility. The encrypted string output can be decrypted using # #private_decrypt. # # Deprecated in version 3.0. @@ -420,7 +431,8 @@ def public_encrypt(data, padding = PKCS1_PADDING) # rsa.private_decrypt(string, padding) -> String # # Decrypt +string+, which has been encrypted with the public key, with the - # private key. +padding+ defaults to PKCS1_PADDING. + # private key. +padding+ defaults to PKCS1_PADDING, which is known to be + # insecure but is kept for backwards compatibility. # # Deprecated in version 3.0. # Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead. diff --git a/ext/openssl/lib/openssl/version.rb b/ext/openssl/lib/openssl/version.rb index 5e60604353ef85..80597c074366bd 100644 --- a/ext/openssl/lib/openssl/version.rb +++ b/ext/openssl/lib/openssl/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module OpenSSL - VERSION = "3.0.0" + VERSION = "3.1.0.pre" end diff --git a/ext/openssl/openssl.gemspec b/ext/openssl/openssl.gemspec index c6cd818336908a..d3d8be05db2acb 100644 --- a/ext/openssl/openssl.gemspec +++ b/ext/openssl/openssl.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |spec| spec.name = "openssl" - spec.version = "3.0.0" + spec.version = "3.1.0.pre" spec.authors = ["Martin Bosslet", "SHIBATA Hiroshi", "Zachary Scott", "Kazuki Yamaguchi"] spec.email = ["ruby-core@ruby-lang.org"] spec.summary = %q{OpenSSL provides SSL, TLS and general purpose cryptography.} diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c index 56fa0ec30214f0..bf2bac36798373 100644 --- a/ext/openssl/ossl_bn.c +++ b/ext/openssl/ossl_bn.c @@ -577,22 +577,33 @@ BIGNUM_2c(gcd) */ BIGNUM_2c(mod_sqr) +#define BIGNUM_2cr(func) \ + static VALUE \ + ossl_bn_##func(VALUE self, VALUE other) \ + { \ + BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \ + VALUE obj; \ + GetBN(self, bn1); \ + obj = NewBN(rb_obj_class(self)); \ + if (!(result = BN_##func(NULL, bn1, bn2, ossl_bn_ctx))) \ + ossl_raise(eBNError, NULL); \ + SetBN(obj, result); \ + return obj; \ + } + /* + * Document-method: OpenSSL::BN#mod_sqrt + * call-seq: + * bn.mod_sqrt(bn2) => aBN + */ +BIGNUM_2cr(mod_sqrt) + +/* + * Document-method: OpenSSL::BN#mod_inverse * call-seq: * bn.mod_inverse(bn2) => aBN */ -static VALUE -ossl_bn_mod_inverse(VALUE self, VALUE other) -{ - BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; - VALUE obj; - GetBN(self, bn1); - obj = NewBN(rb_obj_class(self)); - if (!(result = BN_mod_inverse(NULL, bn1, bn2, ossl_bn_ctx))) - ossl_raise(eBNError, "BN_mod_inverse"); - SetBN(obj, result); - return obj; -} +BIGNUM_2cr(mod_inverse) /* * call-seq: @@ -1234,6 +1245,7 @@ Init_ossl_bn(void) rb_define_method(cBN, "mod_sub", ossl_bn_mod_sub, 2); rb_define_method(cBN, "mod_mul", ossl_bn_mod_mul, 2); rb_define_method(cBN, "mod_sqr", ossl_bn_mod_sqr, 1); + rb_define_method(cBN, "mod_sqrt", ossl_bn_mod_sqrt, 1); rb_define_method(cBN, "**", ossl_bn_exp, 1); rb_define_method(cBN, "mod_exp", ossl_bn_mod_exp, 2); rb_define_method(cBN, "gcd", ossl_bn_gcd, 1); diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c index bfe3a74b126b00..1a5f471a27d3f3 100644 --- a/ext/openssl/ossl_hmac.c +++ b/ext/openssl/ossl_hmac.c @@ -97,11 +97,19 @@ ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest) GetHMAC(self, ctx); StringValue(key); +#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY + pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, + (unsigned char *)RSTRING_PTR(key), + RSTRING_LENINT(key)); + if (!pkey) + ossl_raise(eHMACError, "EVP_PKEY_new_raw_private_key"); +#else pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, (unsigned char *)RSTRING_PTR(key), RSTRING_LENINT(key)); if (!pkey) ossl_raise(eHMACError, "EVP_PKEY_new_mac_key"); +#endif if (EVP_DigestSignInit(ctx, NULL, ossl_evp_get_digestbyname(digest), NULL, pkey) != 1) { EVP_PKEY_free(pkey); diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index 24d0da46833256..ec39e8bd771093 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -99,17 +99,56 @@ ossl_pkey_read_generic(BIO *bio, VALUE pass) /* First check DER */ if (OSSL_DECODER_from_bio(dctx, bio) == 1) goto out; + OSSL_BIO_reset(bio); /* Then check PEM; multiple OSSL_DECODER_from_bio() calls may be needed */ - OSSL_BIO_reset(bio); if (OSSL_DECODER_CTX_set_input_type(dctx, "PEM") != 1) goto out; - while (OSSL_DECODER_from_bio(dctx, bio) != 1) { - if (BIO_eof(bio)) + /* + * First check for private key formats. This is to keep compatibility with + * ruby/openssl < 3.0 which decoded the following as a private key. + * + * $ openssl ecparam -name prime256v1 -genkey -outform PEM + * -----BEGIN EC PARAMETERS----- + * BggqhkjOPQMBBw== + * -----END EC PARAMETERS----- + * -----BEGIN EC PRIVATE KEY----- + * MHcCAQEEIAG8ugBbA5MHkqnZ9ujQF93OyUfL9tk8sxqM5Wv5tKg5oAoGCCqGSM49 + * AwEHoUQDQgAEVcjhJfkwqh5C7kGuhAf8XaAjVuG5ADwb5ayg/cJijCgs+GcXeedj + * 86avKpGH84DXUlB23C/kPt+6fXYlitUmXQ== + * -----END EC PRIVATE KEY----- + * + * While the first PEM block is a proper encoding of ECParameters, thus + * OSSL_DECODER_from_bio() would pick it up, ruby/openssl used to return + * the latter instead. Existing applications expect this behavior. + * + * Note that normally, the input is supposed to contain a single decodable + * PEM block only, so this special handling should not create a new problem. + */ + OSSL_DECODER_CTX_set_selection(dctx, EVP_PKEY_KEYPAIR); + while (1) { + if (OSSL_DECODER_from_bio(dctx, bio) == 1) goto out; + if (BIO_eof(bio)) + break; pos2 = BIO_tell(bio); if (pos2 < 0 || pos2 <= pos) + break; + ossl_clear_error(); + pos = pos2; + } + + OSSL_BIO_reset(bio); + OSSL_DECODER_CTX_set_selection(dctx, 0); + while (1) { + if (OSSL_DECODER_from_bio(dctx, bio) == 1) goto out; + if (BIO_eof(bio)) + break; + pos2 = BIO_tell(bio); + if (pos2 < 0 || pos2 <= pos) + break; + ossl_clear_error(); pos = pos2; } @@ -200,6 +239,7 @@ static VALUE pkey_ctx_apply_options0(VALUE args_v) { VALUE *args = (VALUE *)args_v; + Check_Type(args[1], T_HASH); rb_block_call(args[1], rb_intern("each"), 0, NULL, pkey_ctx_apply_options_i, args[0]); diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c index 08972e92a135cb..06d59c2a4f69d1 100644 --- a/ext/openssl/ossl_pkey_ec.c +++ b/ext/openssl/ossl_pkey_ec.c @@ -414,6 +414,8 @@ ossl_ec_key_export(int argc, VALUE *argv, VALUE self) EC_KEY *ec; GetEC(self, ec); + if (EC_KEY_get0_public_key(ec) == NULL) + ossl_raise(eECError, "can't export - no public key set"); if (EC_KEY_get0_private_key(ec)) return ossl_pkey_export_traditional(argc, argv, self, 0); else @@ -432,6 +434,8 @@ ossl_ec_key_to_der(VALUE self) EC_KEY *ec; GetEC(self, ec); + if (EC_KEY_get0_public_key(ec) == NULL) + ossl_raise(eECError, "can't export - no public key set"); if (EC_KEY_get0_private_key(ec)) return ossl_pkey_export_traditional(0, NULL, self, 1); else @@ -1462,7 +1466,7 @@ static VALUE ossl_ec_point_mul(int argc, VALUE *argv, VALUE self) "use #mul(bn) form instead"); num = RARRAY_LEN(arg1); - bns_tmp = rb_ary_hidden_new(num); + bns_tmp = rb_ary_tmp_new(num); bignums = ALLOCV_N(const BIGNUM *, tmp_b, num); for (i = 0; i < num; i++) { VALUE item = RARRAY_AREF(arg1, i); diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 319ba5840e67ac..478ff869a43cbe 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -49,7 +49,7 @@ static ID id_i_cert_store, id_i_ca_file, id_i_ca_path, id_i_verify_mode, id_i_session_id_context, id_i_session_get_cb, id_i_session_new_cb, id_i_session_remove_cb, id_i_npn_select_cb, id_i_npn_protocols, id_i_alpn_select_cb, id_i_alpn_protocols, id_i_servername_cb, - id_i_verify_hostname; + id_i_verify_hostname, id_i_keylog_cb; static ID id_i_io, id_i_context, id_i_hostname; static int ossl_ssl_ex_vcb_idx; @@ -441,6 +441,54 @@ ossl_sslctx_session_new_cb(SSL *ssl, SSL_SESSION *sess) return 0; } +#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER) +/* + * It is only compatible with OpenSSL >= 1.1.1. Even if LibreSSL implements + * SSL_CTX_set_keylog_callback() from v3.4.2, it does nothing (see + * https://github.com/libressl-portable/openbsd/commit/648d39f0f035835d0653342d139883b9661e9cb6). + */ + +struct ossl_call_keylog_cb_args { + VALUE ssl_obj; + const char * line; +}; + +static VALUE +ossl_call_keylog_cb(VALUE args_v) +{ + VALUE sslctx_obj, cb, line_v; + struct ossl_call_keylog_cb_args *args = (struct ossl_call_keylog_cb_args *) args_v; + + sslctx_obj = rb_attr_get(args->ssl_obj, id_i_context); + + cb = rb_attr_get(sslctx_obj, id_i_keylog_cb); + if (NIL_P(cb)) return Qnil; + + line_v = rb_str_new_cstr(args->line); + + return rb_funcall(cb, id_call, 2, args->ssl_obj, line_v); +} + +static void +ossl_sslctx_keylog_cb(const SSL *ssl, const char *line) +{ + VALUE ssl_obj; + struct ossl_call_keylog_cb_args args; + int state = 0; + + OSSL_Debug("SSL keylog callback entered"); + + ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); + args.ssl_obj = ssl_obj; + args.line = line; + + rb_protect(ossl_call_keylog_cb, (VALUE)&args, &state); + if (state) { + rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state)); + } +} +#endif + static VALUE ossl_call_session_remove_cb(VALUE ary) { @@ -911,6 +959,18 @@ ossl_sslctx_setup(VALUE self) OSSL_Debug("SSL TLSEXT servername callback added"); } +#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER) + /* + * It is only compatible with OpenSSL >= 1.1.1. Even if LibreSSL implements + * SSL_CTX_set_keylog_callback() from v3.4.2, it does nothing (see + * https://github.com/libressl-portable/openbsd/commit/648d39f0f035835d0653342d139883b9661e9cb6). + */ + if (RTEST(rb_attr_get(self, id_i_keylog_cb))) { + SSL_CTX_set_keylog_callback(ctx, ossl_sslctx_keylog_cb); + OSSL_Debug("SSL keylog callback added"); + } +#endif + return Qtrue; } @@ -1641,15 +1701,16 @@ no_exception_p(VALUE opts) return 0; } -#ifndef RB_IO_TIMEOUT_DEFAULT -#define RB_IO_TIMEOUT_DEFAULT Qnil +// Provided by Ruby 3.2.0 and later in order to support the default IO#timeout. +#ifndef RUBY_IO_TIMEOUT_DEFAULT +#define RUBY_IO_TIMEOUT_DEFAULT Qnil #endif static void io_wait_writable(rb_io_t *fptr) { #ifdef HAVE_RB_IO_MAYBE_WAIT - rb_io_maybe_wait_writable(errno, fptr->self, RB_IO_TIMEOUT_DEFAULT); + rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT); #else rb_io_wait_writable(fptr->fd); #endif @@ -1659,7 +1720,7 @@ static void io_wait_readable(rb_io_t *fptr) { #ifdef HAVE_RB_IO_MAYBE_WAIT - rb_io_maybe_wait_readable(errno, fptr->self, RB_IO_TIMEOUT_DEFAULT); + rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT); #else rb_io_wait_readable(fptr->fd); #endif @@ -2433,6 +2494,49 @@ ossl_ssl_alpn_protocol(VALUE self) return rb_str_new((const char *) out, outlen); } +/* + * call-seq: + * session.export_keying_material(label, length) -> String + * + * Enables use of shared session key material in accordance with RFC 5705. + */ +static VALUE +ossl_ssl_export_keying_material(int argc, VALUE *argv, VALUE self) +{ + SSL *ssl; + VALUE str; + VALUE label; + VALUE length; + VALUE context; + unsigned char *p; + size_t len; + int use_ctx = 0; + unsigned char *ctx = NULL; + size_t ctx_len = 0; + int ret; + + rb_scan_args(argc, argv, "21", &label, &length, &context); + StringValue(label); + + GetSSL(self, ssl); + + len = (size_t)NUM2LONG(length); + str = rb_str_new(0, len); + p = (unsigned char *)RSTRING_PTR(str); + if (!NIL_P(context)) { + use_ctx = 1; + StringValue(context); + ctx = (unsigned char *)RSTRING_PTR(context); + ctx_len = RSTRING_LEN(context); + } + ret = SSL_export_keying_material(ssl, p, len, (char *)RSTRING_PTR(label), + RSTRING_LENINT(label), ctx, ctx_len, use_ctx); + if (ret == 0 || ret == -1) { + ossl_raise(eSSLError, "SSL_export_keying_material"); + } + return str; +} + /* * call-seq: * ssl.tmp_key => PKey or nil @@ -2740,6 +2844,29 @@ Init_ossl_ssl(void) */ rb_attr(cSSLContext, rb_intern_const("alpn_select_cb"), 1, 1, Qfalse); + /* + * A callback invoked when TLS key material is generated or received, in + * order to allow applications to store this keying material for debugging + * purposes. + * + * The callback is invoked with an SSLSocket and a string containing the + * key material in the format used by NSS for its SSLKEYLOGFILE debugging + * output. + * + * It is only compatible with OpenSSL >= 1.1.1. Even if LibreSSL implements + * SSL_CTX_set_keylog_callback() from v3.4.2, it does nothing (see + * https://github.com/libressl-portable/openbsd/commit/648d39f0f035835d0653342d139883b9661e9cb6). + * + * === Example + * + * context.keylog_cb = proc do |_sock, line| + * File.open('ssl_keylog_file', "a") do |f| + * f.write("#{line}\n") + * end + * end + */ + rb_attr(cSSLContext, rb_intern_const("keylog_cb"), 1, 1, Qfalse); + rb_define_alias(cSSLContext, "ssl_timeout", "timeout"); rb_define_alias(cSSLContext, "ssl_timeout=", "timeout="); rb_define_private_method(cSSLContext, "set_minmax_proto_version", @@ -2860,6 +2987,7 @@ Init_ossl_ssl(void) rb_define_method(cSSLSocket, "peer_finished_message", ossl_ssl_get_peer_finished, 0); rb_define_method(cSSLSocket, "tmp_key", ossl_ssl_tmp_key, 0); rb_define_method(cSSLSocket, "alpn_protocol", ossl_ssl_alpn_protocol, 0); + rb_define_method(cSSLSocket, "export_keying_material", ossl_ssl_export_keying_material, -1); # ifndef OPENSSL_NO_NEXTPROTONEG rb_define_method(cSSLSocket, "npn_protocol", ossl_ssl_npn_protocol, 0); # endif @@ -3020,6 +3148,7 @@ Init_ossl_ssl(void) DefIVarID(alpn_select_cb); DefIVarID(servername_cb); DefIVarID(verify_hostname); + DefIVarID(keylog_cb); DefIVarID(io); DefIVarID(context); diff --git a/ext/openssl/ossl_x509cert.c b/ext/openssl/ossl_x509cert.c index 996f184170b446..9443541645fbe4 100644 --- a/ext/openssl/ossl_x509cert.c +++ b/ext/openssl/ossl_x509cert.c @@ -642,12 +642,12 @@ ossl_x509_set_extensions(VALUE self, VALUE ary) OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext); } GetX509(self, x509); - while ((ext = X509_delete_ext(x509, 0))) - X509_EXTENSION_free(ext); + for (i = X509_get_ext_count(x509); i > 0; i--) + X509_EXTENSION_free(X509_delete_ext(x509, 0)); for (i=0; i 0; i--) + X509_EXTENSION_free(X509_CRL_delete_ext(crl, 0)); for (i=0; i 0; i--) + X509_ATTRIBUTE_free(X509_REQ_delete_attr(req, 0)); for (i=0;i 0; i--) + X509_EXTENSION_free(X509_REVOKED_delete_ext(rev, 0)); for (i=0; inum_entries; + uint32_t index_tbl_num_entries = RCLASS_EXT(klass)->max_iv_count; size_t size; bool embed = true; @@ -3124,7 +3123,7 @@ rb_class_instance_allocate_internal(VALUE klass, VALUE flags, bool wb_protected) #endif } else { - rb_init_iv_list(obj); + rb_ensure_iv_list_size(obj, 0, index_tbl_num_entries); } return obj; @@ -3428,20 +3427,6 @@ rb_free_const_table(struct rb_id_table *tbl) rb_id_table_free(tbl); } -static int -free_iv_index_tbl_free_i(st_data_t key, st_data_t value, st_data_t data) -{ - xfree((void *)value); - return ST_CONTINUE; -} - -static void -iv_index_tbl_free(struct st_table *tbl) -{ - st_foreach(tbl, free_iv_index_tbl_free_i, 0); - st_free_table(tbl); -} - // alive: if false, target pointers can be freed already. // To check it, we need objspace parameter. static void @@ -3690,6 +3675,16 @@ obj_free(rb_objspace_t *objspace, VALUE obj) RB_DEBUG_COUNTER_INC(obj_obj_transient); } else { + rb_shape_t *shape = rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj)); + if (shape) { + VALUE klass = RBASIC_CLASS(obj); + + // Increment max_iv_count if applicable, used to determine size pool allocation + uint32_t num_of_ivs = shape->iv_count; + if (RCLASS_EXT(klass)->max_iv_count < num_of_ivs) { + RCLASS_EXT(klass)->max_iv_count = num_of_ivs; + } + } xfree(RANY(obj)->as.object.as.heap.ivptr); RB_DEBUG_COUNTER_INC(obj_obj_ptr); } @@ -3704,9 +3699,6 @@ obj_free(rb_objspace_t *objspace, VALUE obj) if (RCLASS_CONST_TBL(obj)) { rb_free_const_table(RCLASS_CONST_TBL(obj)); } - if (RCLASS_IV_INDEX_TBL(obj)) { - iv_index_tbl_free(RCLASS_IV_INDEX_TBL(obj)); - } if (RCLASS_CVC_TBL(obj)) { rb_id_table_foreach_values(RCLASS_CVC_TBL(obj), cvar_table_free_i, NULL); rb_id_table_free(RCLASS_CVC_TBL(obj)); @@ -5239,10 +5231,6 @@ obj_memsize_of(VALUE obj, int use_all_types) if (RCLASS_CVC_TBL(obj)) { size += rb_id_table_memsize(RCLASS_CVC_TBL(obj)); } - if (RCLASS_IV_INDEX_TBL(obj)) { - // TODO: more correct value - size += st_memsize(RCLASS_IV_INDEX_TBL(obj)); - } if (RCLASS_EXT(obj)->iv_tbl) { size += st_memsize(RCLASS_EXT(obj)->iv_tbl); } @@ -7688,7 +7676,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj) { const VALUE * const ptr = ROBJECT_IVPTR(obj); - uint32_t i, len = ROBJECT_NUMIV(obj); + uint32_t i, len = ROBJECT_IV_COUNT(obj); for (i = 0; i < len; i++) { gc_mark(objspace, ptr[i]); } @@ -10493,7 +10481,7 @@ gc_ref_update_object(rb_objspace_t *objspace, VALUE v) } #endif - for (uint32_t i = 0; i < numiv; i++) { + for (uint32_t i = 0; i < ROBJECT_IV_COUNT(v); i++) { UPDATE_IF_MOVED(objspace, ptr[i]); } } @@ -10870,15 +10858,6 @@ update_subclass_entries(rb_objspace_t *objspace, rb_subclass_entry_t *entry) } } -static int -update_iv_index_tbl_i(st_data_t key, st_data_t value, st_data_t arg) -{ - rb_objspace_t *objspace = (rb_objspace_t *)arg; - struct rb_iv_index_tbl_entry *ent = (struct rb_iv_index_tbl_entry *)value; - UPDATE_IF_MOVED(objspace, ent->class_value); - return ST_CONTINUE; -} - static void update_class_ext(rb_objspace_t *objspace, rb_classext_t *ext) { @@ -10886,11 +10865,6 @@ update_class_ext(rb_objspace_t *objspace, rb_classext_t *ext) UPDATE_IF_MOVED(objspace, ext->includer); UPDATE_IF_MOVED(objspace, ext->refined_class); update_subclass_entries(objspace, ext->subclasses); - - // ext->iv_index_tbl - if (ext->iv_index_tbl) { - st_foreach(ext->iv_index_tbl, update_iv_index_tbl_i, (st_data_t)objspace); - } } static void diff --git a/gems/bundled_gems b/gems/bundled_gems index 3b8ca4791db205..18c7eb8b1fce2a 100644 --- a/gems/bundled_gems +++ b/gems/bundled_gems @@ -1,6 +1,6 @@ # gem-name version-to-bundle repository-url [optional-commit-hash-to-test-or-defaults-to-v-version] minitest 5.16.3 https://github.com/seattlerb/minitest -power_assert 2.0.1 https://github.com/ruby/power_assert +power_assert 2.0.2 https://github.com/ruby/power_assert rake 13.0.6 https://github.com/ruby/rake test-unit 3.5.5 https://github.com/test-unit/test-unit rexml 3.2.5 https://github.com/ruby/rexml diff --git a/include/ruby/fiber/scheduler.h b/include/ruby/fiber/scheduler.h index d38651da5c9109..250b39b6df5782 100644 --- a/include/ruby/fiber/scheduler.h +++ b/include/ruby/fiber/scheduler.h @@ -23,6 +23,8 @@ RBIMPL_SYMBOL_EXPORT_BEGIN() +#define RUBY_FIBER_SCHEDULER_VERSION 2 + struct timeval; /** @@ -144,7 +146,7 @@ VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout); VALUE rb_fiber_scheduler_close(VALUE scheduler); /** - * Nonblocking `sleep`. Depending on scheduler implementation, this for + * Non-blocking `sleep`. Depending on scheduler implementation, this for * instance switches to another fiber etc. * * @param[in] scheduler Target scheduler. @@ -172,7 +174,7 @@ int rb_fiber_scheduler_supports_process_wait(VALUE scheduler); #endif /** - * Nonblocking `waitpid`. Depending on scheduler implementation, this for + * Non-blocking `waitpid`. Depending on scheduler implementation, this for * instance switches to another fiber etc. * * @param[in] scheduler Target scheduler. @@ -183,7 +185,7 @@ int rb_fiber_scheduler_supports_process_wait(VALUE scheduler); VALUE rb_fiber_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags); /** - * Nonblocking wait for the passed "blocker", which is for instance + * Non-blocking wait for the passed "blocker", which is for instance * `Thread.join` or `Mutex.lock`. Depending on scheduler implementation, this * for instance switches to another fiber etc. * @@ -205,8 +207,8 @@ VALUE rb_fiber_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout); VALUE rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber); /** - * Nonblocking version of rb_io_wait(). Depending on scheduler implementation, - * this for instance switches to another fiber etc. + * Non-blocking version of rb_io_wait(). Depending on scheduler + * implementation, this for instance switches to another fiber etc. * * The "events" here is a Ruby level integer, which is an OR-ed value of * `IO::READABLE`, `IO::WRITABLE`, and `IO::PRIORITY`. @@ -220,7 +222,7 @@ VALUE rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber); VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout); /** - * Nonblocking wait until the passed IO is ready for reading. This is a + * Non-blocking wait until the passed IO is ready for reading. This is a * special case of rb_fiber_scheduler_io_wait(), where the interest is * `IO::READABLE` and timeout is never. * @@ -231,7 +233,7 @@ VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io); /** - * Nonblocking wait until the passed IO is ready for writing. This is a + * Non-blocking wait until the passed IO is ready for writing. This is a * special case of rb_fiber_scheduler_io_wait(), where the interest is * `IO::WRITABLE` and timeout is never. * @@ -242,57 +244,81 @@ VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io); VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io); /** - * Nonblocking read from the passed IO. + * Non-blocking version of `IO.select`. + * + * It's possible that this will be emulated using a thread, so you should not + * rely on it for high performance. + * + * @param[in] scheduler Target scheduler. + * @param[in] readables An array of readable objects. + * @param[in] writables An array of writable objects. + * @param[in] exceptables An array of objects that might encounter exceptional conditions. + * @param[in] timeout Numeric timeout or nil. + * @return What `scheduler.io_select` returns, normally a 3-tuple of arrays of ready objects. + */ +VALUE rb_fiber_scheduler_io_select(VALUE scheduler, VALUE readables, VALUE writables, VALUE exceptables, VALUE timeout); + +/** + * Non-blocking version of `IO.select`, `argv` variant. + */ +VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv); + +/** + * Non-blocking read from the passed IO. * * @param[in] scheduler Target scheduler. * @param[out] io An io object to read from. * @param[out] buffer Return buffer. * @param[in] length Requested number of bytes to read. + * @param[in] offset The offset in the buffer to read to. * @retval RUBY_Qundef `scheduler` doesn't have `#io_read`. * @return otherwise What `scheduler.io_read` returns `[-errno, size]`. */ -VALUE rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t length); +VALUE rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t length, size_t offset); /** - * Nonblocking write to the passed IO. + * Non-blocking write to the passed IO. * * @param[in] scheduler Target scheduler. * @param[out] io An io object to write to. * @param[in] buffer What to write. * @param[in] length Number of bytes to write. + * @param[in] offset The offset in the buffer to write from. * @retval RUBY_Qundef `scheduler` doesn't have `#io_write`. * @return otherwise What `scheduler.io_write` returns `[-errno, size]`. */ -VALUE rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t length); +VALUE rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t length, size_t offset); /** - * Nonblocking read from the passed IO at the specified offset. + * Non-blocking read from the passed IO at the specified offset. * * @param[in] scheduler Target scheduler. * @param[out] io An io object to read from. - * @param[out] buffer Return buffer. + * @param[in] from The offset in the given IO to read the data from. + * @param[out] buffer The buffer to read the data to. * @param[in] length Requested number of bytes to read. - * @param[in] offset The offset in the given IO to read the data from. + * @param[in] offset The offset in the buffer to read to. * @retval RUBY_Qundef `scheduler` doesn't have `#io_read`. * @return otherwise What `scheduler.io_read` returns. */ -VALUE rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, VALUE buffer, size_t length, rb_off_t offset); +VALUE rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset); /** - * Nonblocking write to the passed IO at the specified offset. + * Non-blocking write to the passed IO at the specified offset. * * @param[in] scheduler Target scheduler. * @param[out] io An io object to write to. - * @param[in] buffer What to write. + * @param[in] from The offset in the given IO to write the data to. + * @param[in] buffer The buffer to write the data from. * @param[in] length Number of bytes to write. - * @param[in] offset The offset in the given IO to write the data to. + * @param[in] offset The offset in the buffer to write from. * @retval RUBY_Qundef `scheduler` doesn't have `#io_write`. * @return otherwise What `scheduler.io_write` returns. */ -VALUE rb_fiber_scheduler_io_pwrite(VALUE scheduler, VALUE io, VALUE buffer, size_t length, rb_off_t offset); +VALUE rb_fiber_scheduler_io_pwrite(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset); /** - * Nonblocking read from the passed IO using a native buffer. + * Non-blocking read from the passed IO using a native buffer. * * @param[in] scheduler Target scheduler. * @param[out] io An io object to read from. @@ -305,7 +331,7 @@ VALUE rb_fiber_scheduler_io_pwrite(VALUE scheduler, VALUE io, VALUE buffer, size VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *buffer, size_t size, size_t length); /** - * Nonblocking write to the passed IO using a native buffer. + * Non-blocking write to the passed IO using a native buffer. * * @param[in] scheduler Target scheduler. * @param[out] io An io object to write to. @@ -318,7 +344,7 @@ VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *buffer, VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *buffer, size_t size, size_t length); /** - * Nonblocking close the given IO. + * Non-blocking close the given IO. * * @param[in] scheduler Target scheduler. * @param[in] io An io object to close. @@ -328,7 +354,7 @@ VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void * VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io); /** - * Nonblocking DNS lookup. + * Non-blocking DNS lookup. * * @param[in] scheduler Target scheduler. * @param[in] hostname A host name to query. @@ -337,6 +363,12 @@ VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io); */ VALUE rb_fiber_scheduler_address_resolve(VALUE scheduler, VALUE hostname); +/** + * Create and schedule a non-blocking fiber. + * + */ +VALUE rb_fiber_scheduler_fiber(VALUE scheduler, int argc, VALUE *argv, int kw_splat); + RBIMPL_SYMBOL_EXPORT_END() #endif /* RUBY_FIBER_SCHEDULER_H */ diff --git a/include/ruby/internal/core/robject.h b/include/ruby/internal/core/robject.h index 7823061d8ffbf7..bec0b45fd4e566 100644 --- a/include/ruby/internal/core/robject.h +++ b/include/ruby/internal/core/robject.h @@ -46,7 +46,6 @@ #define ROBJECT_EMBED ROBJECT_EMBED #define ROBJECT_NUMIV ROBJECT_NUMIV #define ROBJECT_IVPTR ROBJECT_IVPTR -#define ROBJECT_IV_INDEX_TBL ROBJECT_IV_INDEX_TBL /** @endcond */ /** @@ -132,7 +131,7 @@ struct RObject { * * This is a shortcut for `RCLASS_IV_INDEX_TBL(rb_obj_class(obj))`. */ - struct st_table *iv_index_tbl; + struct rb_id_table *iv_index_tbl; } heap; #if USE_RVARGC diff --git a/include/ruby/internal/fl_type.h b/include/ruby/internal/fl_type.h index c51bd2e9d946f2..7383426b2358a2 100644 --- a/include/ruby/internal/fl_type.h +++ b/include/ruby/internal/fl_type.h @@ -941,21 +941,8 @@ RB_OBJ_FREEZE_RAW(VALUE obj) RB_FL_SET_RAW(obj, RUBY_FL_FREEZE); } -/** - * Prevents further modifications to the given object. ::rb_eFrozenError shall - * be raised if modification is attempted. - * - * @param[out] x Object in question. - */ -static inline void -rb_obj_freeze_inline(VALUE x) -{ - if (RB_FL_ABLE(x)) { - RB_OBJ_FREEZE_RAW(x); - if (RBASIC_CLASS(x) && !(RBASIC(x)->flags & RUBY_FL_SINGLETON)) { - rb_freeze_singleton_class(x); - } - } -} +RUBY_SYMBOL_EXPORT_BEGIN +void rb_obj_freeze_inline(VALUE obj); +RUBY_SYMBOL_EXPORT_END #endif /* RBIMPL_FL_TYPE_H */ diff --git a/include/ruby/io/buffer.h b/include/ruby/io/buffer.h index 16b23ec6290871..dd92db5bbe647d 100644 --- a/include/ruby/io/buffer.h +++ b/include/ruby/io/buffer.h @@ -21,6 +21,8 @@ RBIMPL_SYMBOL_EXPORT_BEGIN() // WARNING: This entire interface is experimental and may change in the future! #define RB_IO_BUFFER_EXPERIMENTAL 1 +#define RUBY_IO_BUFFER_VERSION 2 + RUBY_EXTERN VALUE rb_cIOBuffer; RUBY_EXTERN size_t RUBY_IO_BUFFER_PAGE_SIZE; RUBY_EXTERN size_t RUBY_IO_BUFFER_DEFAULT_SIZE; @@ -81,10 +83,10 @@ void rb_io_buffer_resize(VALUE self, size_t size); void rb_io_buffer_clear(VALUE self, uint8_t value, size_t offset, size_t length); // The length is the minimum required length. -VALUE rb_io_buffer_read(VALUE self, VALUE io, size_t length); -VALUE rb_io_buffer_pread(VALUE self, VALUE io, size_t length, rb_off_t offset); -VALUE rb_io_buffer_write(VALUE self, VALUE io, size_t length); -VALUE rb_io_buffer_pwrite(VALUE self, VALUE io, size_t length, rb_off_t offset); +VALUE rb_io_buffer_read(VALUE self, VALUE io, size_t length, size_t offset); +VALUE rb_io_buffer_pread(VALUE self, VALUE io, rb_off_t from, size_t length, size_t offset); +VALUE rb_io_buffer_write(VALUE self, VALUE io, size_t length, size_t offset); +VALUE rb_io_buffer_pwrite(VALUE self, VALUE io, rb_off_t from, size_t length, size_t offset); RBIMPL_SYMBOL_EXPORT_END() diff --git a/inits.c b/inits.c index 9decba3c11006a..d1204c1324f73b 100644 --- a/inits.c +++ b/inits.c @@ -77,6 +77,7 @@ rb_call_inits(void) CALL(vm_stack_canary); CALL(ast); CALL(gc_stress); + CALL(shape); // enable builtin loading CALL(builtin); diff --git a/internal.h b/internal.h index 0740ae99e5e3d3..695c9cfb7e76f2 100644 --- a/internal.h +++ b/internal.h @@ -48,9 +48,6 @@ #undef RHASH_TBL #undef RHASH_EMPTY_P -/* internal/object.h */ -#undef ROBJECT_IV_INDEX_TBL - /* internal/struct.h */ #undef RSTRUCT_LEN #undef RSTRUCT_PTR diff --git a/internal/class.h b/internal/class.h index ae680564a6c317..4a3e09ddc7156c 100644 --- a/internal/class.h +++ b/internal/class.h @@ -14,6 +14,7 @@ #include "ruby/internal/stdbool.h" /* for bool */ #include "ruby/intern.h" /* for rb_alloc_func_t */ #include "ruby/ruby.h" /* for struct RBasic */ +#include "shape.h" #ifdef RCLASS_SUPER # undef RCLASS_SUPER @@ -27,8 +28,8 @@ struct rb_subclass_entry { struct rb_iv_index_tbl_entry { uint32_t index; - rb_serial_t class_serial; - VALUE class_value; + shape_id_t source_shape_id; + shape_id_t dest_shape_id; }; struct rb_cvar_class_tbl_entry { @@ -38,7 +39,6 @@ struct rb_cvar_class_tbl_entry { }; struct rb_classext_struct { - struct st_table *iv_index_tbl; // ID -> struct rb_iv_index_tbl_entry struct st_table *iv_tbl; #if SIZEOF_SERIAL_T == SIZEOF_VALUE /* otherwise m_tbl is in struct RClass */ struct rb_id_table *m_tbl; @@ -64,6 +64,10 @@ struct rb_classext_struct { const VALUE refined_class; rb_alloc_func_t allocator; const VALUE includer; + uint32_t max_iv_count; +#if !SHAPE_IN_BASIC_FLAGS + shape_id_t shape_id; +#endif }; struct RClass { @@ -102,7 +106,6 @@ typedef struct rb_classext_struct rb_classext_t; #define RCLASS_CALLABLE_M_TBL(c) (RCLASS_EXT(c)->callable_m_tbl) #define RCLASS_CC_TBL(c) (RCLASS_EXT(c)->cc_tbl) #define RCLASS_CVC_TBL(c) (RCLASS_EXT(c)->cvc_tbl) -#define RCLASS_IV_INDEX_TBL(c) (RCLASS_EXT(c)->iv_index_tbl) #define RCLASS_ORIGIN(c) (RCLASS_EXT(c)->origin_) #define RCLASS_REFINED_CLASS(c) (RCLASS_EXT(c)->refined_class) #if SIZEOF_SERIAL_T == SIZEOF_VALUE diff --git a/internal/cont.h b/internal/cont.h index abffc97104422f..0b669f0ad58ada 100644 --- a/internal/cont.h +++ b/internal/cont.h @@ -9,6 +9,7 @@ * @brief Internal header for Fiber. */ #include "ruby/ruby.h" /* for VALUE */ +#include "iseq.h" struct rb_thread_struct; /* in vm_core.h */ struct rb_fiber_struct; /* in cont.c */ @@ -17,7 +18,9 @@ struct rb_execution_context_struct; /* in vm_core.c */ /* cont.c */ void rb_fiber_reset_root_local_storage(struct rb_thread_struct *); void ruby_register_rollback_func_for_ensure(VALUE (*ensure_func)(VALUE), VALUE (*rollback_func)(VALUE)); -void rb_fiber_init_mjit_cont(struct rb_fiber_struct *fiber); +void rb_fiber_init_jit_cont(struct rb_fiber_struct *fiber); +void rb_jit_cont_each_iseq(rb_iseq_callback callback); +void rb_jit_cont_finish(void); VALUE rb_fiberptr_self(struct rb_fiber_struct *fiber); unsigned int rb_fiberptr_blocking(struct rb_fiber_struct *fiber); diff --git a/internal/numeric.h b/internal/numeric.h index 19069cb3bc7ee1..89bc54b307ff6a 100644 --- a/internal/numeric.h +++ b/internal/numeric.h @@ -35,12 +35,16 @@ enum ruby_num_rounding_mode { RUBY_NUM_ROUND_DEFAULT = ROUND_DEFAULT, }; +/* same as internal.h */ +#define numberof(array) ((int)(sizeof(array) / sizeof((array)[0]))) +#define roomof(x, y) (((x) + (y) - 1) / (y)) +#define type_roomof(x, y) roomof(sizeof(x), sizeof(y)) + #if SIZEOF_DOUBLE <= SIZEOF_VALUE typedef double rb_float_value_type; #else typedef struct { - VALUE values[(SIZEOF_DOUBLE + SIZEOF_VALUE - 1) / SIZEOF_VALUE]; - /* roomof() needs internal.h, and the order of some macros may matter */ + VALUE values[roomof(SIZEOF_DOUBLE, SIZEOF_VALUE)]; } rb_float_value_type; #endif diff --git a/internal/object.h b/internal/object.h index 88f3a44bc6f866..7b54e13dd2ae32 100644 --- a/internal/object.h +++ b/internal/object.h @@ -9,11 +9,6 @@ * @brief Internal header for Object. */ #include "ruby/ruby.h" /* for VALUE */ -#include "internal/class.h" /* for RCLASS_IV_INDEX_TBL */ - -#ifdef ROBJECT_IV_INDEX_TBL -# undef ROBJECT_IV_INDEX_TBL -#endif /* object.c */ VALUE rb_class_search_ancestor(VALUE klass, VALUE super); @@ -26,7 +21,6 @@ int rb_bool_expected(VALUE, const char *, int raise); static inline void RBASIC_CLEAR_CLASS(VALUE obj); static inline void RBASIC_SET_CLASS_RAW(VALUE obj, VALUE klass); static inline void RBASIC_SET_CLASS(VALUE obj, VALUE klass); -static inline struct st_table *ROBJECT_IV_INDEX_TBL_inline(VALUE obj); RUBY_SYMBOL_EXPORT_BEGIN /* object.c (export) */ @@ -64,20 +58,4 @@ RBASIC_SET_CLASS(VALUE obj, VALUE klass) RBASIC_SET_CLASS_RAW(obj, klass); RB_OBJ_WRITTEN(obj, oldv, klass); } - -RBIMPL_ATTR_PURE() -static inline struct st_table * -ROBJECT_IV_INDEX_TBL_inline(VALUE obj) -{ - if (RB_FL_ANY_RAW(obj, ROBJECT_EMBED)) { - VALUE klass = rb_obj_class(obj); - return RCLASS_IV_INDEX_TBL(klass); - } - else { - const struct RObject *const ptr = ROBJECT(obj); - return ptr->as.heap.iv_index_tbl; - } -} -#define ROBJECT_IV_INDEX_TBL ROBJECT_IV_INDEX_TBL_inline - #endif /* INTERNAL_OBJECT_H */ diff --git a/internal/variable.h b/internal/variable.h index 1a19e8964b9f8e..bb24f5129ff6a3 100644 --- a/internal/variable.h +++ b/internal/variable.h @@ -35,7 +35,9 @@ void rb_gvar_ractor_local(const char *name); static inline bool ROBJ_TRANSIENT_P(VALUE obj); static inline void ROBJ_TRANSIENT_SET(VALUE obj); static inline void ROBJ_TRANSIENT_UNSET(VALUE obj); -uint32_t rb_obj_ensure_iv_index_mapping(VALUE obj, ID id); + +struct gen_ivtbl; +int rb_gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl); RUBY_SYMBOL_EXPORT_BEGIN /* variable.c (export) */ @@ -52,6 +54,8 @@ VALUE rb_gvar_set(ID, VALUE); VALUE rb_gvar_defined(ID); void rb_const_warn_if_deprecated(const rb_const_entry_t *, VALUE, ID); void rb_init_iv_list(VALUE obj); +void rb_ensure_iv_list_size(VALUE obj, uint32_t len, uint32_t newsize); +struct gen_ivtbl * rb_ensure_generic_iv_list_size(VALUE obj, uint32_t newsize); MJIT_SYMBOL_EXPORT_END static inline bool diff --git a/io.c b/io.c index 99513573d78b30..a7da551a6a0a98 100644 --- a/io.c +++ b/io.c @@ -8407,6 +8407,7 @@ rb_io_init_copy(VALUE dest, VALUE io) fptr->encs = orig->encs; fptr->pid = orig->pid; fptr->lineno = orig->lineno; + fptr->timeout = orig->timeout; if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv; fptr_copy_finalizer(fptr, orig); @@ -10850,6 +10851,13 @@ rb_io_advise(int argc, VALUE *argv, VALUE io) static VALUE rb_f_select(int argc, VALUE *argv, VALUE obj) { + VALUE scheduler = rb_fiber_scheduler_current(); + if (scheduler != Qnil) { + // It's optionally supported. + VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv); + if (result != Qundef) return result; + } + VALUE timeout; struct select_args args; struct timeval timerec; diff --git a/io_buffer.c b/io_buffer.c index 4326d21defcb7e..bc5fac8118c3cc 100644 --- a/io_buffer.c +++ b/io_buffer.c @@ -14,6 +14,7 @@ #include "internal/array.h" #include "internal/bits.h" #include "internal/error.h" +#include "internal/numeric.h" #include "internal/string.h" #include "internal/thread.h" @@ -439,27 +440,29 @@ rb_io_buffer_map(VALUE io, size_t size, rb_off_t offset, enum rb_io_buffer_flags * mapping, you need to open a file in read-write mode, and explicitly pass * +flags+ argument without IO::Buffer::IMMUTABLE. * - * File.write('test.txt', 'test') + * Example: * - * buffer = IO::Buffer.map(File.open('test.txt'), nil, 0, IO::Buffer::READONLY) - * # => # + * File.write('test.txt', 'test') * - * buffer.readonly? # => true + * buffer = IO::Buffer.map(File.open('test.txt'), nil, 0, IO::Buffer::READONLY) + * # => # * - * buffer.get_string - * # => "test" + * buffer.readonly? # => true * - * buffer.set_string('b', 0) - * # `set_string': Buffer is not writable! (IO::Buffer::AccessError) + * buffer.get_string + * # => "test" * - * # create read/write mapping: length 4 bytes, offset 0, flags 0 - * buffer = IO::Buffer.map(File.open('test.txt', 'r+'), 4, 0) - * buffer.set_string('b', 0) - * # => 1 + * buffer.set_string('b', 0) + * # `set_string': Buffer is not writable! (IO::Buffer::AccessError) * - * # Check it - * File.read('test.txt') - * # => "best" + * # create read/write mapping: length 4 bytes, offset 0, flags 0 + * buffer = IO::Buffer.map(File.open('test.txt', 'r+'), 4, 0) + * buffer.set_string('b', 0) + * # => 1 + * + * # Check it + * File.read('test.txt') + * # => "best" * * Note that some operating systems may not have cache coherency between mapped * buffers and file reads. @@ -467,9 +470,7 @@ rb_io_buffer_map(VALUE io, size_t size, rb_off_t offset, enum rb_io_buffer_flags static VALUE io_buffer_map(int argc, VALUE *argv, VALUE klass) { - if (argc < 1 || argc > 4) { - rb_error_arity(argc, 2, 4); - } + rb_check_arity(argc, 1, 4); // We might like to handle a string path? VALUE io = argv[0]; @@ -534,14 +535,14 @@ io_flags_for_size(size_t size) * * buffer = IO::Buffer.new(4) * # => - * # # - * # 0x00000000 00 00 00 00 .... + * # # + * # 0x00000000 00 00 00 00 .... * * buffer.get_string(0, 1) # => "\x00" * * buffer.set_string("test") * buffer - * # => + * # => * # # * # 0x00000000 74 65 73 74 test */ @@ -550,9 +551,7 @@ rb_io_buffer_initialize(int argc, VALUE *argv, VALUE self) { io_buffer_experimental(); - if (argc < 0 || argc > 2) { - rb_error_arity(argc, 0, 2); - } + rb_check_arity(argc, 0, 2); struct rb_io_buffer *data = NULL; TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data); @@ -890,6 +889,8 @@ rb_io_buffer_mapped_p(VALUE self) * Locking is not thread safe, but is a semantic used to ensure buffers don't * move while being used by a system call. * + * Example: + * * buffer.locked do * buffer.write(io) # theoretical system call interface * end @@ -978,6 +979,14 @@ rb_io_buffer_try_unlock(VALUE self) * can enter the lock. Also, locked buffer can't be changed with #resize or * #free. * + * The following operations acquire a lock: #resize, #free. + * + * Locking is not thread safe. It is designed as a safety net around + * non-blocking system calls. You can only share a buffer between threads with + * appropriate synchronisation techniques. + * + * Example: + * * buffer = IO::Buffer.new(4) * buffer.locked? #=> false * @@ -993,12 +1002,6 @@ rb_io_buffer_try_unlock(VALUE self) * buffer.set_string("test", 0) * end * end - * - * The following operations acquire a lock: #resize, #free. - * - * Locking is not thread safe. It is designed as a safety net around - * non-blocking system calls. You can only share a buffer between threads with - * appropriate synchronisation techniques. */ VALUE rb_io_buffer_locked(VALUE self) @@ -1029,20 +1032,22 @@ rb_io_buffer_locked(VALUE self) * * After the buffer is freed, no further operations can't be performed on it. * - * buffer = IO::Buffer.for('test') - * buffer.free - * # => # + * You can resize a freed buffer to re-allocate it. * - * buffer.get_value(:U8, 0) - * # in `get_value': The buffer is not allocated! (IO::Buffer::AllocationError) + * Example: * - * buffer.get_string - * # in `get_string': The buffer is not allocated! (IO::Buffer::AllocationError) + * buffer = IO::Buffer.for('test') + * buffer.free + * # => # * - * buffer.null? - * # => true + * buffer.get_value(:U8, 0) + * # in `get_value': The buffer is not allocated! (IO::Buffer::AllocationError) * - * You can resize a freed buffer to re-allocate it. + * buffer.get_string + * # in `get_string': The buffer is not allocated! (IO::Buffer::AllocationError) + * + * buffer.null? + * # => true */ VALUE rb_io_buffer_free(VALUE self) @@ -1068,7 +1073,7 @@ io_buffer_validate_range(struct rb_io_buffer *data, size_t offset, size_t length } /* - * call-seq: slice(offset, length) -> io_buffer + * call-seq: slice([offset = 0, [length]]) -> io_buffer * * Produce another IO::Buffer which is a slice (or view into) the current one * starting at +offset+ bytes and going for +length+ bytes. @@ -1076,45 +1081,56 @@ io_buffer_validate_range(struct rb_io_buffer *data, size_t offset, size_t length * The slicing happens without copying of memory, and the slice keeps being * associated with the original buffer's source (string, or file), if any. * - * Raises RuntimeError if the offset+length is out of the current + * If the offset is not given, it will be zero. If the offset is negative, it + * will raise an ArgumentError. + * + * If the length is not given, the slice will be as long as the original + * buffer minus the specified offset. If the length is negative, it will raise + * an ArgumentError. + * + * Raises RuntimeError if the offset+length is out of the current * buffer's bounds. * - * string = 'test' - * buffer = IO::Buffer.for(string) + * Example: * - * slice = buffer.slice(1, 2) - * # => - * # # - * # 0x00000000 65 73 es + * string = 'test' + * buffer = IO::Buffer.for(string) * - * # Put "o" into 0s position of the slice - * slice.set_string('o', 0) - * slice - * # => - * # # - * # 0x00000000 6f 73 os + * slice = buffer.slice + * # => + * # # + * # 0x00000000 74 65 73 74 test * + * buffer.slice(2) + * # => + * # # + * # 0x00000000 73 74 st + * + * slice = buffer.slice(1, 2) + * # => + * # # + * # 0x00000000 65 73 es + * + * # Put "o" into 0s position of the slice + * slice.set_string('o', 0) + * slice + * # => + * # # + * # 0x00000000 6f 73 os * - * # it is also visible at position 1 of the original buffer - * buffer - * # => - * # # - * # 0x00000000 74 6f 73 74 tost + * # it is also visible at position 1 of the original buffer + * buffer + * # => + * # # + * # 0x00000000 74 6f 73 74 tost * - * # ...and original string - * string - * # => tost + * # ...and original string + * string + * # => tost */ -VALUE -rb_io_buffer_slice(VALUE self, VALUE _offset, VALUE _length) +static VALUE +rb_io_buffer_slice(struct rb_io_buffer *data, VALUE self, size_t offset, size_t length) { - // TODO fail on negative offets/lengths. - size_t offset = NUM2SIZET(_offset); - size_t length = NUM2SIZET(_length); - - struct rb_io_buffer *data = NULL; - TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data); - io_buffer_validate_range(data, offset, length); VALUE instance = rb_io_buffer_type_allocate(rb_class_of(self)); @@ -1133,6 +1149,37 @@ rb_io_buffer_slice(VALUE self, VALUE _offset, VALUE _length) return instance; } +static VALUE +io_buffer_slice(int argc, VALUE *argv, VALUE self) +{ + rb_check_arity(argc, 0, 2); + + struct rb_io_buffer *data = NULL; + TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data); + + size_t offset = 0, length = 0; + + if (argc > 0) { + if (rb_int_negative_p(argv[0])) { + rb_raise(rb_eArgError, "Offset can't be negative!"); + } + + offset = NUM2SIZET(argv[0]); + } + + if (argc > 1) { + if (rb_int_negative_p(argv[1])) { + rb_raise(rb_eArgError, "Length can't be negative!"); + } + + length = NUM2SIZET(argv[1]); + } else { + length = data->size - offset; + } + + return rb_io_buffer_slice(data, self, offset, length); +} + int rb_io_buffer_get_bytes(VALUE self, void **base, size_t *size) { @@ -1154,7 +1201,7 @@ rb_io_buffer_get_bytes(VALUE self, void **base, size_t *size) return 0; } -inline static void +static inline void io_buffer_get_bytes_for_writing(struct rb_io_buffer *data, void **base, size_t *size) { if (data->flags & RB_IO_BUFFER_READONLY) { @@ -1215,17 +1262,19 @@ rb_io_buffer_get_bytes_for_reading(VALUE self, const void **base, size_t *size) * * Transfers ownership to a new buffer, deallocating the current one. * - * buffer = IO::Buffer.new('test') - * other = buffer.transfer - * other - * # => - * # # - * # 0x00000000 74 65 73 74 test - * buffer - * # => - * # # - * buffer.null? - * # => true + * Example: + * + * buffer = IO::Buffer.new('test') + * other = buffer.transfer + * other + * # => + * # # + * # 0x00000000 74 65 73 74 test + * buffer + * # => + * # # + * buffer.null? + * # => true */ VALUE rb_io_buffer_transfer(VALUE self) @@ -1339,7 +1388,7 @@ rb_io_buffer_resize(VALUE self, size_t size) * buffer = IO::Buffer.new(4) * buffer.set_string("test", 0) * buffer.resize(8) # resize to 8 bytes - * # => + * # => * # # * # 0x00000000 74 65 73 74 00 00 00 00 test.... * @@ -1811,7 +1860,7 @@ io_buffer_each_byte(int argc, VALUE *argv, VALUE self) return self; } -inline static void +static inline void rb_io_buffer_set_value(const void* base, size_t size, ID data_type, size_t *offset, VALUE value) { #define IO_BUFFER_SET_VALUE(name) if (data_type == RB_IO_BUFFER_DATA_TYPE_##name) {io_buffer_write_##name(base, size, offset, value); return;} @@ -1849,13 +1898,15 @@ rb_io_buffer_set_value(const void* base, size_t size, ID data_type, size_t *offs * symbols described in #get_value. * * buffer = IO::Buffer.new(8) - * # => + * # => * # # * # 0x00000000 00 00 00 00 00 00 00 00 + * * buffer.set_value(:U8, 1, 111) * # => 1 + * * buffer - * # => + * # => * # # * # 0x00000000 00 6f 00 00 00 00 00 00 .o...... * @@ -1863,11 +1914,12 @@ rb_io_buffer_set_value(const void* base, size_t size, ID data_type, size_t *offs * * buffer = IO::Buffer.new(8) * buffer.set_value(:U32, 0, 2.5) + * * buffer - * # => - * # # - * # 0x00000000 00 00 00 02 00 00 00 00 - * # ^^ the same as if we'd pass just integer 2 + * # => + * # # + * # 0x00000000 00 00 00 02 00 00 00 00 + * # ^^ the same as if we'd pass just integer 2 */ static VALUE io_buffer_set_value(VALUE self, VALUE type, VALUE _offset, VALUE value) @@ -1895,7 +1947,7 @@ io_buffer_set_value(VALUE self, VALUE type, VALUE _offset, VALUE value) * buffer = IO::Buffer.new(8) * buffer.set_values([:U8, :U16], 0, [1, 2]) * buffer - * # => + * # => * # # * # 0x00000000 01 00 02 00 00 00 00 00 ........ */ @@ -2028,7 +2080,7 @@ rb_io_buffer_initialize_copy(VALUE self, VALUE source) * at +offset+ using +memcpy+. For copying String instances, see #set_string. * * buffer = IO::Buffer.new(32) - * # => + * # => * # # * # 0x00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ * # 0x00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ * @@ -2036,7 +2088,7 @@ rb_io_buffer_initialize_copy(VALUE self, VALUE source) * buffer.copy(IO::Buffer.for("test"), 8) * # => 4 -- size of data copied * buffer - * # => + * # => * # # * # 0x00000000 00 00 00 00 00 00 00 00 74 65 73 74 00 00 00 00 ........test.... * # 0x00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ * @@ -2077,7 +2129,7 @@ rb_io_buffer_initialize_copy(VALUE self, VALUE source) static VALUE io_buffer_copy(int argc, VALUE *argv, VALUE self) { - if (argc < 1 || argc > 4) rb_error_arity(argc, 1, 4); + rb_check_arity(argc, 1, 4); struct rb_io_buffer *data = NULL; TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data); @@ -2097,18 +2149,18 @@ io_buffer_copy(int argc, VALUE *argv, VALUE self) * Read a chunk or all of the buffer into a string, in the specified * +encoding+. If no encoding is provided +Encoding::BINARY+ is used. * - * buffer = IO::Buffer.for('test') - * buffer.get_string - * # => "test" - * buffer.get_string(2) - * # => "st" - * buffer.get_string(2, 1) - * # => "s" + * buffer = IO::Buffer.for('test') + * buffer.get_string + * # => "test" + * buffer.get_string(2) + * # => "st" + * buffer.get_string(2, 1) + * # => "s" */ static VALUE io_buffer_get_string(int argc, VALUE *argv, VALUE self) { - if (argc > 3) rb_error_arity(argc, 0, 3); + rb_check_arity(argc, 0, 3); struct rb_io_buffer *data = NULL; TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data); @@ -2167,7 +2219,7 @@ io_buffer_get_string(int argc, VALUE *argv, VALUE self) static VALUE io_buffer_set_string(int argc, VALUE *argv, VALUE self) { - if (argc < 1 || argc > 4) rb_error_arity(argc, 1, 4); + rb_check_arity(argc, 1, 4); struct rb_io_buffer *data = NULL; TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data); @@ -2229,7 +2281,7 @@ rb_io_buffer_clear(VALUE self, uint8_t value, size_t offset, size_t length) static VALUE io_buffer_clear(int argc, VALUE *argv, VALUE self) { - if (argc > 3) rb_error_arity(argc, 0, 3); + rb_check_arity(argc, 0, 3); struct rb_io_buffer *data = NULL; TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data); @@ -2297,11 +2349,11 @@ io_buffer_read_internal(void *_argument) } VALUE -rb_io_buffer_read(VALUE self, VALUE io, size_t length) +rb_io_buffer_read(VALUE self, VALUE io, size_t length, size_t offset) { VALUE scheduler = rb_fiber_scheduler_current(); if (scheduler != Qnil) { - VALUE result = rb_fiber_scheduler_io_read(scheduler, io, self, length); + VALUE result = rb_fiber_scheduler_io_read(scheduler, io, self, SIZET2NUM(length), SIZET2NUM(offset)); if (result != Qundef) { return result; @@ -2311,7 +2363,7 @@ rb_io_buffer_read(VALUE self, VALUE io, size_t length) struct rb_io_buffer *data = NULL; TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data); - io_buffer_validate_range(data, 0, length); + io_buffer_validate_range(data, offset, length); int descriptor = rb_io_descriptor(io); @@ -2319,6 +2371,8 @@ rb_io_buffer_read(VALUE self, VALUE io, size_t length) size_t size; io_buffer_get_bytes_for_writing(data, &base, &size); + base = (unsigned char*)base + offset; + struct io_buffer_read_internal_argument argument = { .descriptor = descriptor, .base = base, @@ -2328,10 +2382,55 @@ rb_io_buffer_read(VALUE self, VALUE io, size_t length) return rb_thread_io_blocking_region(io_buffer_read_internal, &argument, descriptor); } +/* + * call-seq: read(io, [length, [offset]]) -> self + * + * Read at most +length+ bytes from +io+ into the buffer, starting at + * +offset+. + * + * If +length+ is not given, read until the end of the buffer. + * + * If +offset+ is not given, read from the beginning of the buffer. + * + * If +length+ is 0, read nothing. + * + * Example: + * + * buffer = IO::Buffer.for('test') + * # => + * # + * # 0x00000000 74 65 73 74 test + * buffer.read(File.open('/dev/urandom', 'rb'), 4) + * # => + * # + * # 0x00000000 2a 0e 0e 0e *... + */ static VALUE -io_buffer_read(VALUE self, VALUE io, VALUE length) +io_buffer_read(int argc, VALUE *argv, VALUE self) { - return rb_io_buffer_read(self, io, RB_NUM2SIZE(length)); + rb_check_arity(argc, 2, 3); + + VALUE io = argv[0]; + + size_t length; + if (argc >= 2) { + if (rb_int_negative_p(argv[1])) { + rb_raise(rb_eArgError, "Length can't be negative!"); + } + + length = NUM2SIZET(argv[1]); + } + + size_t offset = 0; + if (argc >= 3) { + if (rb_int_negative_p(argv[2])) { + rb_raise(rb_eArgError, "Offset can't be negative!"); + } + + offset = NUM2SIZET(argv[2]); + } + + return rb_io_buffer_read(self, io, length, offset); } struct io_buffer_pread_internal_argument { @@ -2367,11 +2466,11 @@ io_buffer_pread_internal(void *_argument) } VALUE -rb_io_buffer_pread(VALUE self, VALUE io, size_t length, rb_off_t offset) +rb_io_buffer_pread(VALUE self, VALUE io, rb_off_t from, size_t length, size_t offset) { VALUE scheduler = rb_fiber_scheduler_current(); if (scheduler != Qnil) { - VALUE result = rb_fiber_scheduler_io_pread(scheduler, io, self, length, offset); + VALUE result = rb_fiber_scheduler_io_pread(scheduler, io, OFFT2NUM(from), self, SIZET2NUM(length), SIZET2NUM(offset)); if (result != Qundef) { return result; @@ -2393,16 +2492,36 @@ rb_io_buffer_pread(VALUE self, VALUE io, size_t length, rb_off_t offset) .descriptor = descriptor, .base = base, .size = length, - .offset = offset, + .offset = from, }; return rb_thread_io_blocking_region(io_buffer_pread_internal, &argument, descriptor); } static VALUE -io_buffer_pread(VALUE self, VALUE io, VALUE length, VALUE offset) +io_buffer_pread(int argc, VALUE *argv, VALUE self) { - return rb_io_buffer_pread(self, io, RB_NUM2SIZE(length), NUM2OFFT(offset)); + rb_check_arity(argc, 3, 4); + + VALUE io = argv[0]; + rb_off_t from = NUM2OFFT(argv[1]); + + size_t length; + if (rb_int_negative_p(argv[2])) { + rb_raise(rb_eArgError, "Length can't be negative!"); + } + length = NUM2SIZET(argv[2]); + + size_t offset = 0; + if (argc >= 4) { + if (rb_int_negative_p(argv[3])) { + rb_raise(rb_eArgError, "Offset can't be negative!"); + } + + offset = NUM2SIZET(argv[3]); + } + + return rb_io_buffer_pread(self, io, from, length, offset); } struct io_buffer_write_internal_argument { @@ -2420,11 +2539,11 @@ io_buffer_write_internal(void *_argument) } VALUE -rb_io_buffer_write(VALUE self, VALUE io, size_t length) +rb_io_buffer_write(VALUE self, VALUE io, size_t length, size_t offset) { VALUE scheduler = rb_fiber_scheduler_current(); if (scheduler != Qnil) { - VALUE result = rb_fiber_scheduler_io_write(scheduler, io, self, length); + VALUE result = rb_fiber_scheduler_io_write(scheduler, io, self, SIZET2NUM(length), SIZET2NUM(offset)); if (result != Qundef) { return result; @@ -2434,7 +2553,7 @@ rb_io_buffer_write(VALUE self, VALUE io, size_t length) struct rb_io_buffer *data = NULL; TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data); - io_buffer_validate_range(data, 0, length); + io_buffer_validate_range(data, offset, length); int descriptor = rb_io_descriptor(io); @@ -2442,6 +2561,8 @@ rb_io_buffer_write(VALUE self, VALUE io, size_t length) size_t size; io_buffer_get_bytes_for_reading(data, &base, &size); + base = (unsigned char *)base + offset; + struct io_buffer_write_internal_argument argument = { .descriptor = descriptor, .base = base, @@ -2452,9 +2573,31 @@ rb_io_buffer_write(VALUE self, VALUE io, size_t length) } static VALUE -io_buffer_write(VALUE self, VALUE io, VALUE length) +io_buffer_write(int argc, VALUE *argv, VALUE self) { - return rb_io_buffer_write(self, io, RB_NUM2SIZE(length)); + rb_check_arity(argc, 2, 3); + + VALUE io = argv[0]; + + size_t length; + if (argc >= 2) { + if (rb_int_negative_p(argv[1])) { + rb_raise(rb_eArgError, "Length can't be negative!"); + } + + length = NUM2SIZET(argv[1]); + } + + size_t offset = 0; + if (argc >= 3) { + if (rb_int_negative_p(argv[2])) { + rb_raise(rb_eArgError, "Offset can't be negative!"); + } + + offset = NUM2SIZET(argv[2]); + } + + return rb_io_buffer_write(self, io, length, offset); } struct io_buffer_pwrite_internal_argument { @@ -2490,11 +2633,11 @@ io_buffer_pwrite_internal(void *_argument) } VALUE -rb_io_buffer_pwrite(VALUE self, VALUE io, size_t length, rb_off_t offset) +rb_io_buffer_pwrite(VALUE self, VALUE io, rb_off_t from, size_t length, size_t offset) { VALUE scheduler = rb_fiber_scheduler_current(); if (scheduler != Qnil) { - VALUE result = rb_fiber_scheduler_io_pwrite(scheduler, io, self, length, OFFT2NUM(offset)); + VALUE result = rb_fiber_scheduler_io_pwrite(scheduler, io, OFFT2NUM(from), self, SIZET2NUM(length), SIZET2NUM(offset)); if (result != Qundef) { return result; @@ -2516,16 +2659,36 @@ rb_io_buffer_pwrite(VALUE self, VALUE io, size_t length, rb_off_t offset) .descriptor = descriptor, .base = base, .size = length, - .offset = offset, + .offset = from, }; return rb_thread_io_blocking_region(io_buffer_pwrite_internal, &argument, descriptor); } static VALUE -io_buffer_pwrite(VALUE self, VALUE io, VALUE length, VALUE offset) +io_buffer_pwrite(int argc, VALUE *argv, VALUE self) { - return rb_io_buffer_pwrite(self, io, RB_NUM2SIZE(length), NUM2OFFT(offset)); + rb_check_arity(argc, 3, 4); + + VALUE io = argv[0]; + rb_off_t from = NUM2OFFT(argv[1]); + + size_t length; + if (rb_int_negative_p(argv[2])) { + rb_raise(rb_eArgError, "Length can't be negative!"); + } + length = NUM2SIZET(argv[2]); + + size_t offset = 0; + if (argc >= 4) { + if (rb_int_negative_p(argv[3])) { + rb_raise(rb_eArgError, "Offset can't be negative!"); + } + + offset = NUM2SIZET(argv[3]); + } + + return rb_io_buffer_pwrite(self, io, from, length, offset); } static inline void @@ -2910,11 +3073,11 @@ io_buffer_not_inplace(VALUE self) * Empty buffer: * * buffer = IO::Buffer.new(8) # create empty 8-byte buffer - * # => + * # => * # # * # ... * buffer - * # => + * # => * # * # 0x00000000 00 00 00 00 00 00 00 00 * buffer.set_string('test', 2) # put there bytes of the "test" string, starting from offset 2 @@ -2926,11 +3089,11 @@ io_buffer_not_inplace(VALUE self) * * string = 'data' * buffer = IO::Buffer.for(string) - * # => + * # => * # # * # ... * buffer - * # => + * # => * # # * # 0x00000000 64 61 74 61 data * @@ -2939,7 +3102,7 @@ io_buffer_not_inplace(VALUE self) * buffer.set_string('---', 1) # write content, starting from offset 1 * # => 3 * buffer - * # => + * # => * # # * # 0x00000000 64 2d 2d 2d d--- * string # original string changed, too @@ -2950,7 +3113,7 @@ io_buffer_not_inplace(VALUE self) * File.write('test.txt', 'test data') * # => 9 * buffer = IO::Buffer.map(File.open('test.txt')) - * # => + * # => * # # * # ... * buffer.get_string(5, 2) # read 2 bytes, starting from offset 5 @@ -3037,7 +3200,7 @@ Init_IO_Buffer(void) rb_define_method(rb_cIOBuffer, "locked", rb_io_buffer_locked, 0); // Manipulation: - rb_define_method(rb_cIOBuffer, "slice", rb_io_buffer_slice, 2); + rb_define_method(rb_cIOBuffer, "slice", io_buffer_slice, -1); rb_define_method(rb_cIOBuffer, "<=>", rb_io_buffer_compare, 1); rb_define_method(rb_cIOBuffer, "resize", io_buffer_resize, 1); rb_define_method(rb_cIOBuffer, "clear", io_buffer_clear, -1); @@ -3098,8 +3261,8 @@ Init_IO_Buffer(void) rb_define_method(rb_cIOBuffer, "not!", io_buffer_not_inplace, 0); // IO operations: - rb_define_method(rb_cIOBuffer, "read", io_buffer_read, 2); - rb_define_method(rb_cIOBuffer, "pread", io_buffer_pread, 3); - rb_define_method(rb_cIOBuffer, "write", io_buffer_write, 2); - rb_define_method(rb_cIOBuffer, "pwrite", io_buffer_pwrite, 3); + rb_define_method(rb_cIOBuffer, "read", io_buffer_read, -1); + rb_define_method(rb_cIOBuffer, "pread", io_buffer_pread, -1); + rb_define_method(rb_cIOBuffer, "write", io_buffer_write, -1); + rb_define_method(rb_cIOBuffer, "pwrite", io_buffer_pwrite, -1); } diff --git a/iseq.c b/iseq.c index aea781038ba8ea..5b1d9de106c47a 100644 --- a/iseq.c +++ b/iseq.c @@ -230,18 +230,8 @@ rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data) union iseq_inline_storage_entry *is_entries = body->is_entries; if (body->is_entries) { - // IVC entries - for (unsigned int i = 0; i < body->ivc_size; i++, is_entries++) { - IVC ivc = (IVC)is_entries; - if (ivc->entry) { - RUBY_ASSERT(!RB_TYPE_P(ivc->entry->class_value, T_NONE)); - - VALUE nv = func(data, ivc->entry->class_value); - if (ivc->entry->class_value != nv) { - ivc->entry->class_value = nv; - } - } - } + // Skip iterating over ivc caches + is_entries += body->ivc_size; // ICVARC entries for (unsigned int i = 0; i < body->icvarc_size; i++, is_entries++) { diff --git a/iseq.h b/iseq.h index 98cf71d52cd90b..d771874c2fd7f0 100644 --- a/iseq.h +++ b/iseq.h @@ -31,6 +31,7 @@ RUBY_EXTERN const int ruby_api_version[]; typedef struct rb_iseq_struct rb_iseq_t; #define rb_iseq_t rb_iseq_t #endif +typedef void (*rb_iseq_callback)(const rb_iseq_t *); extern const ID rb_iseq_shared_exc_local_tbl[]; diff --git a/lib/bundler.rb b/lib/bundler.rb index dc88bbdcb93771..1a94e0c963e6f3 100644 --- a/lib/bundler.rb +++ b/lib/bundler.rb @@ -41,7 +41,6 @@ module Bundler autoload :Definition, File.expand_path("bundler/definition", __dir__) autoload :Dependency, File.expand_path("bundler/dependency", __dir__) - autoload :DepProxy, File.expand_path("bundler/dep_proxy", __dir__) autoload :Deprecate, File.expand_path("bundler/deprecate", __dir__) autoload :Digest, File.expand_path("bundler/digest", __dir__) autoload :Dsl, File.expand_path("bundler/dsl", __dir__) diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 21db42f7726ef2..95be7a7e273930 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -139,7 +139,7 @@ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, opti if @unlock[:conservative] @unlock[:gems] ||= @dependencies.map(&:name) else - eager_unlock = expand_dependencies(@unlock[:gems] || [], true) + eager_unlock = (@unlock[:gems] || []).map {|name| Dependency.new(name, ">= 0") } @unlock[:gems] = @locked_specs.for(eager_unlock, false, platforms).map(&:name).uniq end @@ -224,7 +224,7 @@ def requested_dependencies def current_dependencies dependencies.select do |d| - d.should_include? && !d.gem_platforms(@platforms).empty? + d.should_include? && !d.gem_platforms([generic_local_platform]).empty? end end @@ -248,10 +248,9 @@ def specs_for(groups) def dependencies_for(groups) groups.map!(&:to_sym) - deps = current_dependencies.reject do |d| + current_dependencies.reject do |d| (d.groups & groups).empty? end - expand_dependencies(deps) end # Resolve all the dependencies specified in Gemfile. It ensures that @@ -474,17 +473,17 @@ def unlocking? def resolver @resolver ||= begin last_resolve = converge_locked_specs - remove_ruby_from_platforms_if_necessary!(dependencies) + remove_ruby_from_platforms_if_necessary!(current_dependencies) Resolver.new(source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve(last_resolve), platforms) end end def expanded_dependencies - @expanded_dependencies ||= expand_dependencies(dependencies + metadata_dependencies, true) + @expanded_dependencies ||= dependencies + metadata_dependencies end def filter_specs(specs, deps) - SpecSet.new(specs).for(expand_dependencies(deps, true), false, platforms) + SpecSet.new(specs).for(deps, false, platforms) end def materialize(dependencies) @@ -578,8 +577,8 @@ def change_reason ].select(&:first).map(&:last).join(", ") end - def pretty_dep(dep, source = false) - SharedHelpers.pretty_dependency(dep, source) + def pretty_dep(dep) + SharedHelpers.pretty_dependency(dep) end # Check if the specs of the given source changed @@ -792,23 +791,6 @@ def metadata_dependencies ] end - def expand_dependencies(dependencies, remote = false) - deps = [] - dependencies.each do |dep| - dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name) - next unless remote || dep.current_platform? - target_platforms = dep.gem_platforms(remote ? @platforms : [generic_local_platform]) - deps += expand_dependency_with_platforms(dep, target_platforms) - end - deps - end - - def expand_dependency_with_platforms(dep, platforms) - platforms.map do |p| - DepProxy.get_proxy(dep, p) - end - end - def source_requirements # Record the specs available in each gem's source, so that those # specs will be available later when the resolver knows where to @@ -880,7 +862,7 @@ def remove_ruby_from_platforms_if_necessary!(dependencies) Bundler.local_platform == Gem::Platform::RUBY || !platforms.include?(Gem::Platform::RUBY) || (@new_platform && platforms.last == Gem::Platform::RUBY) || - !@originally_locked_specs.incomplete_ruby_specs?(expand_dependencies(dependencies)) + !@originally_locked_specs.incomplete_ruby_specs?(dependencies) remove_platform(Gem::Platform::RUBY) add_current_platform diff --git a/lib/bundler/dep_proxy.rb b/lib/bundler/dep_proxy.rb deleted file mode 100644 index a32dc37b492d65..00000000000000 --- a/lib/bundler/dep_proxy.rb +++ /dev/null @@ -1,55 +0,0 @@ -# frozen_string_literal: true - -module Bundler - class DepProxy - attr_reader :__platform, :dep - - @proxies = {} - - def self.get_proxy(dep, platform) - @proxies[[dep, platform]] ||= new(dep, platform).freeze - end - - def initialize(dep, platform) - @dep = dep - @__platform = platform - end - - private_class_method :new - - alias_method :eql?, :== - - def type - @dep.type - end - - def name - @dep.name - end - - def requirement - @dep.requirement - end - - def to_s - s = name.dup - s << " (#{requirement})" unless requirement == Gem::Requirement.default - s << " #{__platform}" unless __platform == Gem::Platform::RUBY - s - end - - def dup - raise NoMethodError.new("DepProxy cannot be duplicated") - end - - def clone - raise NoMethodError.new("DepProxy cannot be cloned") - end - - private - - def method_missing(*args, &blk) - @dep.send(*args, &blk) - end - end -end diff --git a/lib/bundler/endpoint_specification.rb b/lib/bundler/endpoint_specification.rb index 863544b1f926db..d315d1cc68de9b 100644 --- a/lib/bundler/endpoint_specification.rb +++ b/lib/bundler/endpoint_specification.rb @@ -26,6 +26,10 @@ def fetch_platform @platform end + def identifier + @__identifier ||= [name, version, platform.to_s] + end + # needed for standalone, load required_paths from local gemspec # after the gem is installed def require_paths diff --git a/lib/bundler/gem_helpers.rb b/lib/bundler/gem_helpers.rb index 0d50d8687b90b5..2e6d788f9c6f0a 100644 --- a/lib/bundler/gem_helpers.rb +++ b/lib/bundler/gem_helpers.rb @@ -5,7 +5,6 @@ module GemHelpers GENERIC_CACHE = { Gem::Platform::RUBY => Gem::Platform::RUBY } # rubocop:disable Style/MutableConstant GENERICS = [ [Gem::Platform.new("java"), Gem::Platform.new("java")], - [Gem::Platform.new("universal-java"), Gem::Platform.new("java")], [Gem::Platform.new("mswin32"), Gem::Platform.new("mswin32")], [Gem::Platform.new("mswin64"), Gem::Platform.new("mswin64")], [Gem::Platform.new("universal-mingw32"), Gem::Platform.new("universal-mingw32")], diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb index d3743adb688553..ed16c90a3a1681 100644 --- a/lib/bundler/index.rb +++ b/lib/bundler/index.rb @@ -71,7 +71,6 @@ def local_search(query) when Gem::Specification, RemoteSpecification, LazySpecification, EndpointSpecification then search_by_spec(query) when String then specs_by_name(query) when Gem::Dependency then search_by_dependency(query) - when DepProxy then search_by_dependency(query.dep) else raise "You can't search for a #{query.inspect}." end diff --git a/lib/bundler/injector.rb b/lib/bundler/injector.rb index 82d5bd588012c8..81465cec19f616 100644 --- a/lib/bundler/injector.rb +++ b/lib/bundler/injector.rb @@ -70,7 +70,7 @@ def remove(gemfile_path, lockfile_path) show_warning("No gems were removed from the gemfile.") if deps.empty? - deps.each {|dep| Bundler.ui.confirm "#{SharedHelpers.pretty_dependency(dep, false)} was removed." } + deps.each {|dep| Bundler.ui.confirm "#{SharedHelpers.pretty_dependency(dep)} was removed." } end # Invalidate the cached Bundler.definition. diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb index ec141cfa27da29..f5fe2e64aec527 100644 --- a/lib/bundler/lazy_specification.rb +++ b/lib/bundler/lazy_specification.rb @@ -77,7 +77,7 @@ def materialize_for_installation source.local! candidates = if source.is_a?(Source::Path) || !ruby_platform_materializes_to_ruby_platform? - target_platform = ruby_platform_materializes_to_ruby_platform? ? platform : Bundler.local_platform + target_platform = ruby_platform_materializes_to_ruby_platform? ? platform : local_platform source.specs.search(Dependency.new(name, version)).select do |spec| MatchPlatform.platforms_match?(spec.platform, target_platform) @@ -120,7 +120,7 @@ def to_s end def identifier - @__identifier ||= [name, version, platform_string] + @__identifier ||= [name, version, platform.to_s] end def git_version @@ -128,13 +128,6 @@ def git_version " #{source.revision[0..6]}" end - protected - - def platform_string - platform_string = platform.to_s - platform_string == Index::RUBY ? Index::NULL : platform_string - end - private def to_ary @@ -151,7 +144,8 @@ def method_missing(method, *args, &blk) # # For backwards compatibility with existing lockfiles, if the most specific - # locked platform is RUBY, we keep the previous behaviour of resolving the + # locked platform is not a specific platform like x86_64-linux or + # universal-java-11, then we keep the previous behaviour of resolving the # best platform variant at materiliazation time. For previous bundler # versions (before 2.2.0) this was always the case (except when the lockfile # only included non-ruby platforms), but we're also keeping this behaviour @@ -159,7 +153,9 @@ def method_missing(method, *args, &blk) # explicitly add a more specific platform. # def ruby_platform_materializes_to_ruby_platform? - !Bundler.most_specific_locked_platform?(generic_local_platform) || force_ruby_platform || Bundler.settings[:force_ruby_platform] + generic_platform = generic_local_platform == Gem::Platform::JAVA ? Gem::Platform::JAVA : Gem::Platform::RUBY + + !Bundler.most_specific_locked_platform?(generic_platform) || force_ruby_platform || Bundler.settings[:force_ruby_platform] end end end diff --git a/lib/bundler/man/bundle-add.1 b/lib/bundler/man/bundle-add.1 index fd49dd084f5711..ba4b76f7dff372 100644 --- a/lib/bundler/man/bundle-add.1 +++ b/lib/bundler/man/bundle-add.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-ADD" "1" "September 2022" "" "" +.TH "BUNDLE\-ADD" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install diff --git a/lib/bundler/man/bundle-binstubs.1 b/lib/bundler/man/bundle-binstubs.1 index 59bb6a44470336..152aec9dd07953 100644 --- a/lib/bundler/man/bundle-binstubs.1 +++ b/lib/bundler/man/bundle-binstubs.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-BINSTUBS" "1" "September 2022" "" "" +.TH "BUNDLE\-BINSTUBS" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-binstubs\fR \- Install the binstubs of the listed gems diff --git a/lib/bundler/man/bundle-cache.1 b/lib/bundler/man/bundle-cache.1 index 4346aa00f82cbd..9eb2e1d7cc899b 100644 --- a/lib/bundler/man/bundle-cache.1 +++ b/lib/bundler/man/bundle-cache.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CACHE" "1" "September 2022" "" "" +.TH "BUNDLE\-CACHE" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application diff --git a/lib/bundler/man/bundle-check.1 b/lib/bundler/man/bundle-check.1 index bb91ed90d5167b..f6aa6988c432c9 100644 --- a/lib/bundler/man/bundle-check.1 +++ b/lib/bundler/man/bundle-check.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CHECK" "1" "September 2022" "" "" +.TH "BUNDLE\-CHECK" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems diff --git a/lib/bundler/man/bundle-clean.1 b/lib/bundler/man/bundle-clean.1 index eaa8ea35fb4465..f89ae3a1b006eb 100644 --- a/lib/bundler/man/bundle-clean.1 +++ b/lib/bundler/man/bundle-clean.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CLEAN" "1" "September 2022" "" "" +.TH "BUNDLE\-CLEAN" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index 1582e3c464d93d..08e08ecca9ffa8 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CONFIG" "1" "September 2022" "" "" +.TH "BUNDLE\-CONFIG" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-config\fR \- Set bundler configuration options diff --git a/lib/bundler/man/bundle-console.1 b/lib/bundler/man/bundle-console.1 index 6359f442313c7e..c9463e372c78b0 100644 --- a/lib/bundler/man/bundle-console.1 +++ b/lib/bundler/man/bundle-console.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CONSOLE" "1" "September 2022" "" "" +.TH "BUNDLE\-CONSOLE" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-console\fR \- Deprecated way to open an IRB session with the bundle pre\-loaded diff --git a/lib/bundler/man/bundle-doctor.1 b/lib/bundler/man/bundle-doctor.1 index 92f5c80df932c7..dc5f5cf27e3268 100644 --- a/lib/bundler/man/bundle-doctor.1 +++ b/lib/bundler/man/bundle-doctor.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-DOCTOR" "1" "September 2022" "" "" +.TH "BUNDLE\-DOCTOR" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-doctor\fR \- Checks the bundle for common problems diff --git a/lib/bundler/man/bundle-exec.1 b/lib/bundler/man/bundle-exec.1 index 158a9e0bf644cc..1b3ad113953f0e 100644 --- a/lib/bundler/man/bundle-exec.1 +++ b/lib/bundler/man/bundle-exec.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-EXEC" "1" "September 2022" "" "" +.TH "BUNDLE\-EXEC" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-exec\fR \- Execute a command in the context of the bundle diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1 index 2c36627559899a..b70cfbccd80eaf 100644 --- a/lib/bundler/man/bundle-gem.1 +++ b/lib/bundler/man/bundle-gem.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-GEM" "1" "September 2022" "" "" +.TH "BUNDLE\-GEM" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem diff --git a/lib/bundler/man/bundle-help.1 b/lib/bundler/man/bundle-help.1 index ed72024e06b6a8..bf378b09504b9e 100644 --- a/lib/bundler/man/bundle-help.1 +++ b/lib/bundler/man/bundle-help.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-HELP" "1" "September 2022" "" "" +.TH "BUNDLE\-HELP" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-help\fR \- Displays detailed help for each subcommand diff --git a/lib/bundler/man/bundle-info.1 b/lib/bundler/man/bundle-info.1 index f1ef32b758c108..9445aece25f26b 100644 --- a/lib/bundler/man/bundle-info.1 +++ b/lib/bundler/man/bundle-info.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INFO" "1" "September 2022" "" "" +.TH "BUNDLE\-INFO" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-info\fR \- Show information for the given gem in your bundle diff --git a/lib/bundler/man/bundle-init.1 b/lib/bundler/man/bundle-init.1 index 83f8d75324f54d..b80652d189ab7b 100644 --- a/lib/bundler/man/bundle-init.1 +++ b/lib/bundler/man/bundle-init.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INIT" "1" "September 2022" "" "" +.TH "BUNDLE\-INIT" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-init\fR \- Generates a Gemfile into the current working directory diff --git a/lib/bundler/man/bundle-inject.1 b/lib/bundler/man/bundle-inject.1 index d675dba79b889a..bd440eee658997 100644 --- a/lib/bundler/man/bundle-inject.1 +++ b/lib/bundler/man/bundle-inject.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INJECT" "1" "September 2022" "" "" +.TH "BUNDLE\-INJECT" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile diff --git a/lib/bundler/man/bundle-install.1 b/lib/bundler/man/bundle-install.1 index 858f56e673692e..34bb58b53d1c10 100644 --- a/lib/bundler/man/bundle-install.1 +++ b/lib/bundler/man/bundle-install.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INSTALL" "1" "September 2022" "" "" +.TH "BUNDLE\-INSTALL" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-install\fR \- Install the dependencies specified in your Gemfile diff --git a/lib/bundler/man/bundle-list.1 b/lib/bundler/man/bundle-list.1 index bf15769eaf8c25..d82093ad4ab0e5 100644 --- a/lib/bundler/man/bundle-list.1 +++ b/lib/bundler/man/bundle-list.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-LIST" "1" "September 2022" "" "" +.TH "BUNDLE\-LIST" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-list\fR \- List all the gems in the bundle diff --git a/lib/bundler/man/bundle-lock.1 b/lib/bundler/man/bundle-lock.1 index af805f34d32b17..65586c89c594a5 100644 --- a/lib/bundler/man/bundle-lock.1 +++ b/lib/bundler/man/bundle-lock.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-LOCK" "1" "September 2022" "" "" +.TH "BUNDLE\-LOCK" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-lock\fR \- Creates / Updates a lockfile without installing diff --git a/lib/bundler/man/bundle-open.1 b/lib/bundler/man/bundle-open.1 index f2b10b8808b754..b2327fa9f1552c 100644 --- a/lib/bundler/man/bundle-open.1 +++ b/lib/bundler/man/bundle-open.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-OPEN" "1" "September 2022" "" "" +.TH "BUNDLE\-OPEN" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-open\fR \- Opens the source directory for a gem in your bundle diff --git a/lib/bundler/man/bundle-outdated.1 b/lib/bundler/man/bundle-outdated.1 index 699416583857d8..896155212f3558 100644 --- a/lib/bundler/man/bundle-outdated.1 +++ b/lib/bundler/man/bundle-outdated.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-OUTDATED" "1" "September 2022" "" "" +.TH "BUNDLE\-OUTDATED" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-outdated\fR \- List installed gems with newer versions available diff --git a/lib/bundler/man/bundle-platform.1 b/lib/bundler/man/bundle-platform.1 index 848c3024cd2564..2d2450780a766c 100644 --- a/lib/bundler/man/bundle-platform.1 +++ b/lib/bundler/man/bundle-platform.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PLATFORM" "1" "September 2022" "" "" +.TH "BUNDLE\-PLATFORM" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-platform\fR \- Displays platform compatibility information diff --git a/lib/bundler/man/bundle-plugin.1 b/lib/bundler/man/bundle-plugin.1 index 1508b85b38036a..3a08bf8c4693fc 100644 --- a/lib/bundler/man/bundle-plugin.1 +++ b/lib/bundler/man/bundle-plugin.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PLUGIN" "1" "September 2022" "" "" +.TH "BUNDLE\-PLUGIN" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-plugin\fR \- Manage Bundler plugins diff --git a/lib/bundler/man/bundle-pristine.1 b/lib/bundler/man/bundle-pristine.1 index 9a3a26bbfae144..5f562a2e0773b9 100644 --- a/lib/bundler/man/bundle-pristine.1 +++ b/lib/bundler/man/bundle-pristine.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PRISTINE" "1" "September 2022" "" "" +.TH "BUNDLE\-PRISTINE" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-pristine\fR \- Restores installed gems to their pristine condition diff --git a/lib/bundler/man/bundle-remove.1 b/lib/bundler/man/bundle-remove.1 index f9d7d574d30d8a..128ac64f9fa0cc 100644 --- a/lib/bundler/man/bundle-remove.1 +++ b/lib/bundler/man/bundle-remove.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-REMOVE" "1" "September 2022" "" "" +.TH "BUNDLE\-REMOVE" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-remove\fR \- Removes gems from the Gemfile diff --git a/lib/bundler/man/bundle-show.1 b/lib/bundler/man/bundle-show.1 index ff860c64cc9d8a..1d747fd5f4770d 100644 --- a/lib/bundler/man/bundle-show.1 +++ b/lib/bundler/man/bundle-show.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-SHOW" "1" "September 2022" "" "" +.TH "BUNDLE\-SHOW" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem diff --git a/lib/bundler/man/bundle-update.1 b/lib/bundler/man/bundle-update.1 index 608ad744367875..15e0517737ccab 100644 --- a/lib/bundler/man/bundle-update.1 +++ b/lib/bundler/man/bundle-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-UPDATE" "1" "September 2022" "" "" +.TH "BUNDLE\-UPDATE" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-update\fR \- Update your gems to the latest available versions diff --git a/lib/bundler/man/bundle-version.1 b/lib/bundler/man/bundle-version.1 index 68fc24c4483bbc..3721cf9c7a67fa 100644 --- a/lib/bundler/man/bundle-version.1 +++ b/lib/bundler/man/bundle-version.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-VERSION" "1" "September 2022" "" "" +.TH "BUNDLE\-VERSION" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-version\fR \- Prints Bundler version information diff --git a/lib/bundler/man/bundle-viz.1 b/lib/bundler/man/bundle-viz.1 index 4d108a2aea98d3..3508c09bcc079a 100644 --- a/lib/bundler/man/bundle-viz.1 +++ b/lib/bundler/man/bundle-viz.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-VIZ" "1" "September 2022" "" "" +.TH "BUNDLE\-VIZ" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile diff --git a/lib/bundler/man/bundle.1 b/lib/bundler/man/bundle.1 index 1898b15647703f..c2e7e4c5c4b674 100644 --- a/lib/bundler/man/bundle.1 +++ b/lib/bundler/man/bundle.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE" "1" "September 2022" "" "" +.TH "BUNDLE" "1" "October 2022" "" "" . .SH "NAME" \fBbundle\fR \- Ruby Dependency Management diff --git a/lib/bundler/man/gemfile.5 b/lib/bundler/man/gemfile.5 index e793500517a93c..957ba19ff16a61 100644 --- a/lib/bundler/man/gemfile.5 +++ b/lib/bundler/man/gemfile.5 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "GEMFILE" "5" "September 2022" "" "" +.TH "GEMFILE" "5" "October 2022" "" "" . .SH "NAME" \fBGemfile\fR \- A format for describing gem dependencies for Ruby programs @@ -497,7 +497,7 @@ Are both equivalent to . .nf -gem "rails", git: "git://github\.com/rails/rails\.git" +gem "rails", git: "https://github\.com/rails/rails\.git" . .fi . diff --git a/lib/bundler/man/gemfile.5.ronn b/lib/bundler/man/gemfile.5.ronn index 89ebcc7214d342..d27849ae6aa34f 100644 --- a/lib/bundler/man/gemfile.5.ronn +++ b/lib/bundler/man/gemfile.5.ronn @@ -369,7 +369,7 @@ same, you can omit one. Are both equivalent to - gem "rails", git: "git://github.com/rails/rails.git" + gem "rails", git: "https://github.com/rails/rails.git" Since the `github` method is a specialization of `git_source`, it accepts a `:branch` named argument. diff --git a/lib/bundler/remote_specification.rb b/lib/bundler/remote_specification.rb index 601957746f3af6..34d7fd116c576f 100644 --- a/lib/bundler/remote_specification.rb +++ b/lib/bundler/remote_specification.rb @@ -29,11 +29,15 @@ def fetch_platform @platform = _remote_specification.platform end + def identifier + @__identifier ||= [name, version, @platform.to_s] + end + def full_name - if @original_platform == Gem::Platform::RUBY + if @platform == Gem::Platform::RUBY "#{@name}-#{@version}" else - "#{@name}-#{@version}-#{@original_platform}" + "#{@name}-#{@version}-#{@platform}" end end diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 161a3c0518c639..115c5cfcc4aa14 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -8,22 +8,6 @@ class Resolver include GemHelpers - # Figures out the best possible configuration of gems that satisfies - # the list of passed dependencies and any child dependencies without - # causing any gem activation errors. - # - # ==== Parameters - # *dependencies:: The list of dependencies to resolve - # - # ==== Returns - # ,nil:: If the list of dependencies can be resolved, a - # collection of gemspecs is returned. Otherwise, nil is returned. - def self.resolve(requirements, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil) - base = SpecSet.new(base) unless base.is_a?(SpecSet) - resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) - resolver.start(requirements) - end - def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) @source_requirements = source_requirements @base = Resolver::Base.new(base, additional_base_requirements) @@ -116,41 +100,35 @@ def dependencies_for(specification) specification.dependencies_for_activated_platforms end - def search_for(dependency_proxy) - platform = dependency_proxy.__platform - dependency = dependency_proxy.dep - name = dependency.name - @search_for[dependency_proxy] ||= begin + def search_for(dependency) + @search_for[dependency] ||= begin + name = dependency.name locked_results = @base[name].select {|spec| requirement_satisfied_by?(dependency, nil, spec) } locked_requirement = base_requirements[name] results = results_for(dependency) + locked_results results = results.select {|spec| requirement_satisfied_by?(locked_requirement, nil, spec) } if locked_requirement + dep_platforms = dependency.gem_platforms(@platforms) - if results.any? - results = @gem_version_promoter.sort_versions(dependency, results) + @gem_version_promoter.sort_versions(dependency, results).group_by(&:version).reduce([]) do |groups, (_, specs)| + relevant_platforms = dep_platforms.select {|platform| specs.any? {|spec| spec.match_platform(platform) } } + next groups unless relevant_platforms.any? - results.group_by(&:version).reduce([]) do |groups, (_, specs)| - next groups unless specs.any? {|spec| spec.match_platform(platform) } - - specs_by_platform = Hash.new do |current_specs, current_platform| - current_specs[current_platform] = select_best_platform_match(specs, current_platform) - end + ruby_specs = select_best_platform_match(specs, Gem::Platform::RUBY) + if ruby_specs.any? + spec_group_ruby = SpecGroup.new(ruby_specs, [Gem::Platform::RUBY]) + spec_group_ruby.force_ruby_platform = dependency.force_ruby_platform + groups << spec_group_ruby + end - spec_group_ruby = SpecGroup.create_for(specs_by_platform, [Gem::Platform::RUBY], Gem::Platform::RUBY) - if spec_group_ruby - spec_group_ruby.force_ruby_platform = dependency.force_ruby_platform - groups << spec_group_ruby - end + next groups if @resolving_only_for_ruby || dependency.force_ruby_platform - next groups if @resolving_only_for_ruby || dependency.force_ruby_platform + platform_specs = relevant_platforms.flat_map {|platform| select_best_platform_match(specs, platform) } + next groups if platform_specs == ruby_specs - spec_group = SpecGroup.create_for(specs_by_platform, @platforms, platform) - groups << spec_group + spec_group = SpecGroup.new(platform_specs, relevant_platforms) + groups << spec_group - groups - end - else - [] + groups end end end @@ -181,10 +159,6 @@ def requirement_satisfied_by?(requirement, activated, spec) requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec) end - def dependencies_equal?(dependencies, other_dependencies) - dependencies.map(&:dep) == other_dependencies.map(&:dep) - end - def sort_dependencies(dependencies, activated, conflicts) dependencies.sort_by do |dependency| name = name_for(dependency) @@ -196,17 +170,10 @@ def sort_dependencies(dependencies, activated, conflicts) amount_constrained(dependency), conflicts[name] ? 0 : 1, vertex.payload ? 0 : search_for(dependency).count, - self.class.platform_sort_key(dependency.__platform), ] end end - def self.platform_sort_key(platform) - # Prefer specific platform to not specific platform - return ["99-LAST", "", "", ""] if Gem::Platform::RUBY == platform - ["00", *platform.to_a.map {|part| part || "" }] - end - private def base_requirements @@ -261,21 +228,11 @@ def verify_gemfile_dependencies_are_found!(requirements) requirements.map! do |requirement| name = requirement.name next requirement if name == "bundler" + next if requirement.gem_platforms(@platforms).empty? next requirement unless search_for(requirement).empty? next unless requirement.current_platform? - if (base = @base[name]) && !base.empty? - version = base.first.version - message = "You have requested:\n" \ - " #{name} #{requirement.requirement}\n\n" \ - "The bundle currently has #{name} locked at #{version}.\n" \ - "Try running `bundle update #{name}`\n\n" \ - "If you are updating multiple gems in your Gemfile at once,\n" \ - "try passing them all to `bundle update`" - else - message = gem_not_found_message(name, requirement, source_for(name)) - end - raise GemNotFound, message + raise GemNotFound, gem_not_found_message(name, requirement, source_for(name)) end.compact! end @@ -293,7 +250,9 @@ def gem_not_found_message(name, requirement, source, extra_message = "") if specs_matching_requirement.any? specs = specs_matching_requirement matching_part = requirement_label - requirement_label = "#{requirement_label}' with platform '#{requirement.__platform}" + platforms = requirement.gem_platforms(@platforms) + platform_label = platforms.size == 1 ? "platform '#{platforms.first}" : "platforms '#{platforms.join("', '")}" + requirement_label = "#{requirement_label}' with #{platform_label}" end message = String.new("Could not find gem '#{requirement_label}'#{extra_message} in #{source}#{cache_message}.\n") diff --git a/lib/bundler/resolver/base.rb b/lib/bundler/resolver/base.rb index 84e087b0ae9931..a8f42dc994e418 100644 --- a/lib/bundler/resolver/base.rb +++ b/lib/bundler/resolver/base.rb @@ -40,7 +40,7 @@ def build_base_requirements base_requirements = {} @base.each do |ls| dep = Dependency.new(ls.name, ls.version) - base_requirements[ls.name] = DepProxy.get_proxy(dep, ls.platform) + base_requirements[ls.name] = dep end @additional_base_requirements.each {|d| base_requirements[d.name] = d } base_requirements diff --git a/lib/bundler/resolver/spec_group.rb b/lib/bundler/resolver/spec_group.rb index 4e5b0082d3d316..ac32c3c1190a42 100644 --- a/lib/bundler/resolver/spec_group.rb +++ b/lib/bundler/resolver/spec_group.rb @@ -6,40 +6,23 @@ class SpecGroup attr_accessor :name, :version, :source attr_accessor :activated_platforms, :force_ruby_platform - def self.create_for(specs, all_platforms, specific_platform) - specific_platform_specs = specs[specific_platform] - return unless specific_platform_specs.any? - - platforms = all_platforms.select {|p| specs[p].any? } - - new(specific_platform_specs.first, specs, platforms) - end - - def initialize(exemplary_spec, specs, relevant_platforms) - @exemplary_spec = exemplary_spec - @name = exemplary_spec.name - @version = exemplary_spec.version - @source = exemplary_spec.source + def initialize(specs, relevant_platforms) + @exemplary_spec = specs.first + @name = @exemplary_spec.name + @version = @exemplary_spec.version + @source = @exemplary_spec.source @activated_platforms = relevant_platforms - @dependencies = Hash.new do |dependencies, platforms| - dependencies[platforms] = dependencies_for(platforms) - end @specs = specs end def to_specs - activated_platforms.map do |p| - specs = @specs[p] - next unless specs.any? - - specs.map do |s| - lazy_spec = LazySpecification.new(name, version, s.platform, source) - lazy_spec.force_ruby_platform = force_ruby_platform - lazy_spec.dependencies.replace s.dependencies - lazy_spec - end - end.flatten.compact.uniq + @specs.map do |s| + lazy_spec = LazySpecification.new(name, version, s.platform, source) + lazy_spec.force_ruby_platform = force_ruby_platform + lazy_spec.dependencies.replace s.dependencies + lazy_spec + end end def to_s @@ -48,7 +31,9 @@ def to_s end def dependencies_for_activated_platforms - @dependencies[activated_platforms] + @dependencies_for_activated_platforms ||= @specs.map do |spec| + __dependencies(spec) + metadata_dependencies(spec) + end.flatten.uniq end def ==(other) @@ -79,35 +64,28 @@ def sorted_activated_platforms private - def dependencies_for(platforms) - platforms.map do |platform| - __dependencies(platform) + metadata_dependencies(platform) - end.flatten - end - - def __dependencies(platform) + def __dependencies(spec) dependencies = [] - @specs[platform].first.dependencies.each do |dep| + spec.dependencies.each do |dep| next if dep.type == :development - dependencies << DepProxy.get_proxy(Dependency.new(dep.name, dep.requirement), platform) + dependencies << Dependency.new(dep.name, dep.requirement) end dependencies end - def metadata_dependencies(platform) - spec = @specs[platform].first + def metadata_dependencies(spec) return [] if spec.is_a?(LazySpecification) [ - metadata_dependency("Ruby", spec.required_ruby_version, platform), - metadata_dependency("RubyGems", spec.required_rubygems_version, platform), + metadata_dependency("Ruby", spec.required_ruby_version), + metadata_dependency("RubyGems", spec.required_rubygems_version), ].compact end - def metadata_dependency(name, requirement, platform) + def metadata_dependency(name, requirement) return if requirement.nil? || requirement.none? - DepProxy.get_proxy(Dependency.new("#{name}\0", requirement), platform) + Dependency.new("#{name}\0", requirement) end end end diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb index 8c4e26f074ec4c..899eb68e0a86ce 100644 --- a/lib/bundler/shared_helpers.rb +++ b/lib/bundler/shared_helpers.rb @@ -163,7 +163,7 @@ def ensure_same_dependencies(spec, old_deps, new_deps) "\nEither installing with `--full-index` or running `bundle update #{spec.name}` should fix the problem." end - def pretty_dependency(dep, print_source = false) + def pretty_dependency(dep) msg = String.new(dep.name) msg << " (#{dep.requirement})" unless dep.requirement == Gem::Requirement.default @@ -172,7 +172,6 @@ def pretty_dependency(dep, print_source = false) msg << " " << platform_string if !platform_string.empty? && platform_string != Gem::Platform::RUBY end - msg << " from the `#{dep.source}` source" if print_source && dep.source msg end diff --git a/lib/csv/row.rb b/lib/csv/row.rb index 0f465ea2a31dac..7f2e7e780784a2 100644 --- a/lib/csv/row.rb +++ b/lib/csv/row.rb @@ -570,7 +570,7 @@ def to_csv(**options) # by +index_or_header+ and +specifiers+. # # The nested objects may be instances of various classes. - # See {Dig Methods}[https://docs.ruby-lang.org/en/master/doc/dig_methods_rdoc.html]. + # See {Dig Methods}[rdoc-ref:dig_methods.rdoc]. # # Examples: # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" diff --git a/lib/csv/table.rb b/lib/csv/table.rb index 1ce0dd6daf62c6..0b62ae89ae75d4 100644 --- a/lib/csv/table.rb +++ b/lib/csv/table.rb @@ -172,7 +172,7 @@ def headers # # Raises an exception if the access mode is :row # and +n+ is not an - # {Integer-convertible object}[https://docs.ruby-lang.org/en/master/implicit_conversion_rdoc.html#label-Integer-Convertible+Objects]. + # {Integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects]. # table.by_row! # => # # # Raises TypeError (no implicit conversion of String into Integer): # table['Name'] diff --git a/lib/delegate.rb b/lib/delegate.rb index 70d4e4ad1d04cd..af95c866f3e795 100644 --- a/lib/delegate.rb +++ b/lib/delegate.rb @@ -412,10 +412,12 @@ def __setobj__(obj) # :nodoc: end protected_instance_methods.each do |method| define_method(method, Delegator.delegating_block(method)) + alias_method(method, method) protected method end public_instance_methods.each do |method| define_method(method, Delegator.delegating_block(method)) + alias_method(method, method) end end klass.define_singleton_method :public_instance_methods do |all=true| diff --git a/lib/fileutils.rb b/lib/fileutils.rb index 74bb904e28143a..745170a121c1bf 100644 --- a/lib/fileutils.rb +++ b/lib/fileutils.rb @@ -12,8 +12,8 @@ # # First, what’s elsewhere. \Module \FileUtils: # -# - Inherits from {class Object}[https://docs.ruby-lang.org/en/master/Object.html]. -# - Supplements {class File}[https://docs.ruby-lang.org/en/master/File.html] +# - Inherits from {class Object}[rdoc-ref:Object]. +# - Supplements {class File}[rdoc-ref:File] # (but is not included or extended there). # # Here, module \FileUtils provides methods that are useful for: @@ -162,8 +162,8 @@ # by applying a special pre-process: # # - If the target path points to a directory, this method uses methods -# {File#chown}[https://docs.ruby-lang.org/en/master/File.html#method-i-chown] -# and {File#chmod}[https://docs.ruby-lang.org/en/master/File.html#method-i-chmod] +# {File#chown}[rdoc-ref:File#chown] +# and {File#chmod}[rdoc-ref:File#chmod] # in removing directories. # - The owner of the target directory should be either the current process # or the super user (root). @@ -291,7 +291,7 @@ def remove_trailing_slash(dir) #:nodoc: # # With no keyword arguments, creates a directory at each +path+ in +list+ # by calling: Dir.mkdir(path, mode); - # see {Dir.mkdir}[https://docs.ruby-lang.org/en/master/Dir.html#method-c-mkdir]: + # see {Dir.mkdir}[rdoc-ref:Dir.mkdir]: # # FileUtils.mkdir(%w[tmp0 tmp1]) # => ["tmp0", "tmp1"] # FileUtils.mkdir('tmp4') # => ["tmp4"] @@ -299,7 +299,7 @@ def remove_trailing_slash(dir) #:nodoc: # Keyword arguments: # # - mode: mode - also calls File.chmod(mode, path); - # see {File.chmod}[https://docs.ruby-lang.org/en/master/File.html#method-c-chmod]. + # see {File.chmod}[rdoc-ref:File.chmod]. # - noop: true - does not create directories. # - verbose: true - prints an equivalent command: # @@ -339,7 +339,7 @@ def mkdir(list, mode: nil, noop: nil, verbose: nil) # With no keyword arguments, creates a directory at each +path+ in +list+, # along with any needed ancestor directories, # by calling: Dir.mkdir(path, mode); - # see {Dir.mkdir}[https://docs.ruby-lang.org/en/master/Dir.html#method-c-mkdir]: + # see {Dir.mkdir}[rdoc-ref:Dir.mkdir]: # # FileUtils.mkdir_p(%w[tmp0/tmp1 tmp2/tmp3]) # => ["tmp0/tmp1", "tmp2/tmp3"] # FileUtils.mkdir_p('tmp4/tmp5') # => ["tmp4/tmp5"] @@ -347,7 +347,7 @@ def mkdir(list, mode: nil, noop: nil, verbose: nil) # Keyword arguments: # # - mode: mode - also calls File.chmod(mode, path); - # see {File.chmod}[https://docs.ruby-lang.org/en/master/File.html#method-c-chmod]. + # see {File.chmod}[rdoc-ref:File.chmod]. # - noop: true - does not create directories. # - verbose: true - prints an equivalent command: # @@ -417,7 +417,7 @@ def fu_mkdir(path, mode) #:nodoc: # # With no keyword arguments, removes the directory at each +path+ in +list+, # by calling: Dir.rmdir(path); - # see {Dir.rmdir}[https://docs.ruby-lang.org/en/master/Dir.html#method-c-rmdir]: + # see {Dir.rmdir}[rdoc-ref:Dir.rmdir]: # # FileUtils.rmdir(%w[tmp0/tmp1 tmp2/tmp3]) # => ["tmp0/tmp1", "tmp2/tmp3"] # FileUtils.rmdir('tmp4/tmp5') # => ["tmp4/tmp5"] @@ -1044,7 +1044,7 @@ def copy_file(src, dest, preserve = false, dereference = true) module_function :copy_file # Copies \IO stream +src+ to \IO stream +dest+ via - # {IO.copy_stream}[https://docs.ruby-lang.org/en/master/IO.html#method-c-copy_stream]. + # {IO.copy_stream}[rdoc-ref:IO.copy_stream]. # # Related: {methods for copying}[rdoc-ref:FileUtils@Copying]. # @@ -1560,14 +1560,14 @@ def compare_stream(a, b) # Keyword arguments: # # - group: group - changes the group if not +nil+, - # using {File.chown}[https://docs.ruby-lang.org/en/master/File.html#method-c-chown]. + # using {File.chown}[rdoc-ref:File.chown]. # - mode: permissions - changes the permissions. - # using {File.chmod}[https://docs.ruby-lang.org/en/master/File.html#method-c-chmod]. + # using {File.chmod}[rdoc-ref:File.chmod]. # - noop: true - does not copy entries; returns +nil+. # - owner: owner - changes the owner if not +nil+, - # using {File.chown}[https://docs.ruby-lang.org/en/master/File.html#method-c-chown]. + # using {File.chown}[rdoc-ref:File.chown]. # - preserve: true - preserve timestamps - # using {File.utime}[https://docs.ruby-lang.org/en/master/File.html#method-c-utime]. + # using {File.utime}[rdoc-ref:File.utime]. # - verbose: true - prints an equivalent command: # # FileUtils.install('src0.txt', 'dest0.txt', noop: true, verbose: true) @@ -1704,9 +1704,9 @@ def mode_to_s(mode) #:nodoc: # returns +list+ if it is an array, [list] otherwise: # # - Modifies each entry that is a regular file using - # {File.chmod}[https://docs.ruby-lang.org/en/master/File.html#method-c-chmod]. + # {File.chmod}[rdoc-ref:File.chmod]. # - Modifies each entry that is a symbolic link using - # {File.lchmod}[https://docs.ruby-lang.org/en/master/File.html#method-c-lchmod]. + # {File.lchmod}[rdoc-ref:File.lchmod]. # # Argument +list+ or its elements # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments]. @@ -1806,9 +1806,9 @@ def chmod_R(mode, list, noop: nil, verbose: nil, force: nil) # returns +list+ if it is an array, [list] otherwise: # # - Modifies each entry that is a regular file using - # {File.chown}[https://docs.ruby-lang.org/en/master/File.html#method-c-chown]. + # {File.chown}[rdoc-ref:File.chown]. # - Modifies each entry that is a symbolic link using - # {File.lchown}[https://docs.ruby-lang.org/en/master/File.html#method-c-lchown]. + # {File.lchown}[rdoc-ref:File.lchown]. # # Argument +list+ or its elements # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments]. diff --git a/lib/irb.rb b/lib/irb.rb index 0c145069c06668..749f3ee167efc0 100644 --- a/lib/irb.rb +++ b/lib/irb.rb @@ -506,13 +506,15 @@ def eval_input @scanner.set_auto_indent(@context) if @context.auto_indent_mode - @scanner.each_top_level_statement do |line, line_no| + @scanner.each_top_level_statement(@context) do |line, line_no| signal_status(:IN_EVAL) do begin line.untaint if RUBY_VERSION < '2.7' if IRB.conf[:MEASURE] && IRB.conf[:MEASURE_CALLBACKS].empty? IRB.set_measure_callback end + # Assignment expression check should be done before @context.evaluate to handle code like `a /2#/ if false; a = 1` + is_assignment = assignment_expression?(line) if IRB.conf[:MEASURE] && !IRB.conf[:MEASURE_CALLBACKS].empty? result = nil last_proc = proc{ result = @context.evaluate(line, line_no, exception: exc) } @@ -529,7 +531,7 @@ def eval_input @context.evaluate(line, line_no, exception: exc) end if @context.echo? - if assignment_expression?(line) + if is_assignment if @context.echo_on_assignment? output_value(@context.echo_on_assignment? == :truncate) end @@ -827,9 +829,12 @@ def assignment_expression?(line) # array of parsed expressions. The first element of each expression is the # expression's type. verbose, $VERBOSE = $VERBOSE, nil - result = ASSIGNMENT_NODE_TYPES.include?(Ripper.sexp(line)&.dig(1,-1,0)) + code = "#{RubyLex.generate_local_variables_assign_code(@context.local_variables) || 'nil;'}\n#{line}" + # Get the last node_type of the line. drop(1) is to ignore the local_variables_assign_code part. + node_type = Ripper.sexp(code)&.dig(1)&.drop(1)&.dig(-1, 0) + ASSIGNMENT_NODE_TYPES.include?(node_type) + ensure $VERBOSE = verbose - result end ATTR_TTY = "\e[%sm" diff --git a/lib/irb/color.rb b/lib/irb/color.rb index 7071696cb29c7c..6378e14856aa22 100644 --- a/lib/irb/color.rb +++ b/lib/irb/color.rb @@ -123,13 +123,15 @@ def colorize(text, seq, colorable: colorable?) # If `complete` is false (code is incomplete), this does not warn compile_error. # This option is needed to avoid warning a user when the compile_error is happening # because the input is not wrong but just incomplete. - def colorize_code(code, complete: true, ignore_error: false, colorable: colorable?) + def colorize_code(code, complete: true, ignore_error: false, colorable: colorable?, local_variables: []) return code unless colorable symbol_state = SymbolState.new colored = +'' + lvars_code = RubyLex.generate_local_variables_assign_code(local_variables) + code_with_lvars = lvars_code ? "#{lvars_code}\n#{code}" : code - scan(code, allow_last_error: !complete) do |token, str, expr| + scan(code_with_lvars, allow_last_error: !complete) do |token, str, expr| # handle uncolorable code if token.nil? colored << Reline::Unicode.escape_for_print(str) @@ -152,6 +154,11 @@ def colorize_code(code, complete: true, ignore_error: false, colorable: colorabl end end end + + if lvars_code + raise "#{lvars_code.dump} should have no \\n" if lvars_code.include?("\n") + colored.sub!(/\A.+\n/, '') # delete_prefix lvars_code with colors + end colored end diff --git a/lib/irb/context.rb b/lib/irb/context.rb index 5e07f5dfb0ef87..d238da9350b0ef 100644 --- a/lib/irb/context.rb +++ b/lib/irb/context.rb @@ -518,5 +518,9 @@ def inspect # :nodoc: end alias __to_s__ to_s alias to_s inspect + + def local_variables # :nodoc: + workspace.binding.local_variables + end end end diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb index aa5cb5adb97e01..b0110dd09b295c 100644 --- a/lib/irb/input-method.rb +++ b/lib/irb/input-method.rb @@ -286,7 +286,8 @@ def initialize if IRB.conf[:USE_COLORIZE] proc do |output, complete: | next unless IRB::Color.colorable? - IRB::Color.colorize_code(output, complete: complete) + lvars = IRB.CurrentContext&.local_variables || [] + IRB::Color.colorize_code(output, complete: complete, local_variables: lvars) end else proc do |output| diff --git a/lib/irb/ruby-lex.rb b/lib/irb/ruby-lex.rb index 8f629331dba3b8..54ea2a9e7b390a 100644 --- a/lib/irb/ruby-lex.rb +++ b/lib/irb/ruby-lex.rb @@ -136,16 +136,18 @@ def set_prompt(p = nil, &block) :on_param_error ] + def self.generate_local_variables_assign_code(local_variables) + "#{local_variables.join('=')}=nil;" unless local_variables.empty? + end + def self.ripper_lex_without_warning(code, context: nil) verbose, $VERBOSE = $VERBOSE, nil - if context - lvars = context.workspace&.binding&.local_variables - if lvars && !lvars.empty? - code = "#{lvars.join('=')}=nil\n#{code}" - line_no = 0 - else - line_no = 1 - end + lvars_code = generate_local_variables_assign_code(context&.local_variables || []) + if lvars_code + code = "#{lvars_code}\n#{code}" + line_no = 0 + else + line_no = 1 end compile_with_errors_suppressed(code, line_no: line_no) do |inner_code, line_no| @@ -162,7 +164,7 @@ def self.ripper_lex_without_warning(code, context: nil) end end else - lexer.parse.reject { |it| it.pos.first == 0 } + lexer.parse.reject { |it| it.pos.first == 0 }.sort_by(&:pos) end end ensure @@ -214,6 +216,8 @@ def check_state(code, tokens = nil, context: nil) ltype = process_literal_type(tokens) indent = process_nesting_level(tokens) continue = process_continue(tokens) + lvars_code = self.class.generate_local_variables_assign_code(context&.local_variables || []) + code = "#{lvars_code}\n#{code}" if lvars_code code_block_open = check_code_block(code, tokens) [ltype, indent, continue, code_block_open] end @@ -233,13 +237,13 @@ def initialize_input @code_block_open = false end - def each_top_level_statement + def each_top_level_statement(context) initialize_input catch(:TERM_INPUT) do loop do begin prompt - unless l = lex + unless l = lex(context) throw :TERM_INPUT if @line == '' else @line_no += l.count("\n") @@ -269,18 +273,15 @@ def each_top_level_statement end end - def lex + def lex(context) line = @input.call if @io.respond_to?(:check_termination) return line # multiline end code = @line + (line.nil? ? '' : line) code.gsub!(/\s*\z/, '').concat("\n") - @tokens = self.class.ripper_lex_without_warning(code) - @continue = process_continue - @code_block_open = check_code_block(code) - @indent = process_nesting_level - @ltype = process_literal_type + @tokens = self.class.ripper_lex_without_warning(code, context: context) + @ltype, @indent, @continue, @code_block_open = check_state(code, @tokens, context: context) line end @@ -706,6 +707,7 @@ def check_string_literal(tokens) i = 0 start_token = [] end_type = [] + pending_heredocs = [] while i < tokens.size t = tokens[i] case t.event @@ -729,18 +731,27 @@ def check_string_literal(tokens) end end when :on_backtick - start_token << t - end_type << :on_tstring_end + if t.state.allbits?(Ripper::EXPR_BEG) + start_token << t + end_type << :on_tstring_end + end when :on_qwords_beg, :on_words_beg, :on_qsymbols_beg, :on_symbols_beg start_token << t end_type << :on_tstring_end when :on_heredoc_beg - start_token << t - end_type << :on_heredoc_end + pending_heredocs << t + end + + if pending_heredocs.any? && t.tok.include?("\n") + pending_heredocs.reverse_each do |t| + start_token << t + end_type << :on_heredoc_end + end + pending_heredocs = [] end i += 1 end - start_token.last.nil? ? nil : start_token.last + pending_heredocs.first || start_token.last end def process_literal_type(tokens = @tokens) diff --git a/lib/logger.rb b/lib/logger.rb index cafebc510a7cc0..7e4dacc911f7d4 100644 --- a/lib/logger.rb +++ b/lib/logger.rb @@ -147,7 +147,7 @@ # when the entry is created. # # The logged timestamp is formatted by method -# {Time#strftime}[https://docs.ruby-lang.org/en/master/Time.html#method-i-strftime] +# {Time#strftime}[rdoc-ref:Time#strftime] # using this format string: # # '%Y-%m-%dT%H:%M:%S.%6N' @@ -365,7 +365,7 @@ # You can set a different format using create-time option # +shift_period_suffix+; # see details and suggestions at -# {Time#strftime}[https://docs.ruby-lang.org/en/master/Time.html#method-i-strftime]. +# {Time#strftime}[rdoc-ref:Time#strftime]. # class Logger _, name, rev = %w$Id$ @@ -425,7 +425,7 @@ def level=(severity) # Argument +datetime_format+ should be either of these: # # - A string suitable for use as a format for method - # {Time#strftime}[https://docs.ruby-lang.org/en/master/Time.html#method-i-strftime]. + # {Time#strftime}[rdoc-ref:Time#strftime]. # - +nil+: the logger uses '%Y-%m-%dT%H:%M:%S.%6N'. # def datetime_format=(datetime_format) @@ -453,7 +453,7 @@ def datetime_format # The proc should return a string containing the formatted entry. # # This custom formatter uses - # {String#dump}[https://docs.ruby-lang.org/en/master/String.html#method-i-dump] + # {String#dump}[rdoc-ref:String#dump] # to escape the message string: # # logger = Logger.new($stdout, progname: 'mung') diff --git a/lib/mjit/compiler.rb b/lib/mjit/compiler.rb index 49f28ab6908612..55fcee6b877fcf 100644 --- a/lib/mjit/compiler.rb +++ b/lib/mjit/compiler.rb @@ -73,23 +73,6 @@ def compile_body(f, iseq, status) src << "#undef GET_SELF\n" src << "#define GET_SELF() cfp_self\n" - # Generate merged ivar guards first if needed - if !status.compile_info.disable_ivar_cache && status.merge_ivar_guards_p - src << " if (UNLIKELY(!(RB_TYPE_P(GET_SELF(), T_OBJECT) && (rb_serial_t)#{status.ivar_serial} == RCLASS_SERIAL(RBASIC(GET_SELF())->klass) &&" - if USE_RVARGC - src << "#{status.max_ivar_index} < ROBJECT_NUMIV(GET_SELF())" # index < ROBJECT_NUMIV(obj) - else - if status.max_ivar_index >= ROBJECT_EMBED_LEN_MAX - src << "#{status.max_ivar_index} < ROBJECT_NUMIV(GET_SELF())" # index < ROBJECT_NUMIV(obj) && !RB_FL_ANY_RAW(obj, ROBJECT_EMBED) - else - src << "ROBJECT_EMBED_LEN_MAX == ROBJECT_NUMIV(GET_SELF())" # index < ROBJECT_NUMIV(obj) && RB_FL_ANY_RAW(obj, ROBJECT_EMBED) - end - end - src << "))) {\n" - src << " goto ivar_cancel;\n" - src << " }\n" - end - # Simulate `opt_pc` in setup_parameters_complex. Other PCs which may be passed by catch tables # are not considered since vm_exec doesn't call jit_exec for catch tables. if iseq.body.param.flags.has_opt @@ -103,6 +86,13 @@ def compile_body(f, iseq, status) src << " }\n" end + # Generate merged ivar guards first if needed + if !status.compile_info.disable_ivar_cache && status.merge_ivar_guards_p + src << " if (UNLIKELY(!(RB_TYPE_P(GET_SELF(), T_OBJECT)))) {" + src << " goto ivar_cancel;\n" + src << " }\n" + end + C.fprintf(f, src) compile_insns(0, 0, status, iseq.body, f) compile_cancel_handler(f, iseq.body, status) @@ -361,54 +351,51 @@ def compile_send(insn, stack_size, sp_inc, local_stack_p, pos, next_pos, status, # _mjit_compile_ivar.erb def compile_ivar(insn_name, stack_size, pos, status, operands, body) ic_copy = (status.is_entries + (C.iseq_inline_storage_entry.new(operands[1]) - body.is_entries)).iv_cache + dest_shape_id = ic_copy.value >> C.SHAPE_FLAG_SHIFT + attr_index = ic_copy.value & ((1 << C.SHAPE_FLAG_SHIFT) - 1) + source_shape_id = if dest_shape_id == C.INVALID_SHAPE_ID + dest_shape_id + else + C.rb_shape_get_shape_by_id(dest_shape_id).parent_id + end src = +'' - if !status.compile_info.disable_ivar_cache && ic_copy.entry + if !status.compile_info.disable_ivar_cache && source_shape_id != C.INVALID_SHAPE_ID # JIT: optimize away motion of sp and pc. This path does not call rb_warning() and so it's always leaf and not `handles_sp`. # compile_pc_and_sp(src, insn, stack_size, sp_inc, local_stack_p, next_pos) # JIT: prepare vm_getivar/vm_setivar arguments and variables src << "{\n" src << " VALUE obj = GET_SELF();\n" - src << " const uint32_t index = #{ic_copy.entry.index};\n" - if status.merge_ivar_guards_p - # JIT: Access ivar without checking these VM_ASSERTed prerequisites as we checked them in the beginning of `mjit_compile_body` - src << " VM_ASSERT(RB_TYPE_P(obj, T_OBJECT));\n" - src << " VM_ASSERT((rb_serial_t)#{ic_copy.entry.class_serial} == RCLASS_SERIAL(RBASIC(obj)->klass));\n" - src << " VM_ASSERT(index < ROBJECT_NUMIV(obj));\n" - if insn_name == :setinstancevariable - if USE_RVARGC - src << " if (LIKELY(!RB_OBJ_FROZEN_RAW(obj) && index < ROBJECT_NUMIV(obj))) {\n" - src << " RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[index], stack[#{stack_size - 1}]);\n" - else - heap_ivar_p = status.max_ivar_index >= ROBJECT_EMBED_LEN_MAX - src << " if (LIKELY(!RB_OBJ_FROZEN_RAW(obj) && #{heap_ivar_p ? 'true' : 'RB_FL_ANY_RAW(obj, ROBJECT_EMBED)'})) {\n" - src << " RB_OBJ_WRITE(obj, &ROBJECT(obj)->as.#{heap_ivar_p ? 'heap.ivptr[index]' : 'ary[index]'}, stack[#{stack_size - 1}]);\n" - end - src << " }\n" - else - src << " VALUE val;\n" - if USE_RVARGC - src << " if (LIKELY(index < ROBJECT_NUMIV(obj) && (val = ROBJECT_IVPTR(obj)[index]) != Qundef)) {\n" - else - heap_ivar_p = status.max_ivar_index >= ROBJECT_EMBED_LEN_MAX - src << " if (LIKELY(#{heap_ivar_p ? 'true' : 'RB_FL_ANY_RAW(obj, ROBJECT_EMBED)'} && (val = ROBJECT(obj)->as.#{heap_ivar_p ? 'heap.ivptr[index]' : 'ary[index]'}) != Qundef)) {\n" - end - src << " stack[#{stack_size}] = val;\n" - src << " }\n" - end + # JIT: cache hit path of vm_getivar/vm_setivar, or cancel JIT (recompile it with exivar) + if insn_name == :setinstancevariable + src << " const shape_id_t source_shape_id = (shape_id_t)#{source_shape_id};\n" + src << " const uint32_t index = #{attr_index - 1};\n" + src << " const shape_id_t dest_shape_id = (shape_id_t)#{dest_shape_id};\n" + src << " if (source_shape_id == ROBJECT_SHAPE_ID(obj) && \n" + src << " dest_shape_id != ROBJECT_SHAPE_ID(obj)) {\n" + src << " if (UNLIKELY(index >= ROBJECT_NUMIV(obj))) {\n" + src << " rb_init_iv_list(obj);\n" + src << " }\n" + src << " ROBJECT_SET_SHAPE_ID(obj, dest_shape_id);\n" + src << " VALUE *ptr = ROBJECT_IVPTR(obj);\n" + src << " RB_OBJ_WRITE(obj, &ptr[index], stack[#{stack_size - 1}]);\n" + src << " }\n" + src << " else if (dest_shape_id == ROBJECT_SHAPE_ID(obj)) {\n" + src << " VALUE *ptr = ROBJECT_IVPTR(obj);\n" + src << " RB_OBJ_WRITE(obj, &ptr[index], stack[#{stack_size - 1}]);\n" + src << " }\n" else - src << " const rb_serial_t ic_serial = (rb_serial_t)#{ic_copy.entry.class_serial};\n" - # JIT: cache hit path of vm_getivar/vm_setivar, or cancel JIT (recompile it with exivar) - if insn_name == :setinstancevariable - src << " if (LIKELY(RB_TYPE_P(obj, T_OBJECT) && ic_serial == RCLASS_SERIAL(RBASIC(obj)->klass) && index < ROBJECT_NUMIV(obj) && !RB_OBJ_FROZEN_RAW(obj))) {\n" - src << " VALUE *ptr = ROBJECT_IVPTR(obj);\n" - src << " RB_OBJ_WRITE(obj, &ptr[index], stack[#{stack_size - 1}]);\n" + src << " const shape_id_t source_shape_id = (shape_id_t)#{dest_shape_id};\n" + if attr_index == 0 # cache hit, but uninitialized iv + src << " /* Uninitialized instance variable */\n" + src << " if (source_shape_id == ROBJECT_SHAPE_ID(obj)) {\n" + src << " stack[#{stack_size}] = Qnil;\n" src << " }\n" else - src << " VALUE val;\n" - src << " if (LIKELY(RB_TYPE_P(obj, T_OBJECT) && ic_serial == RCLASS_SERIAL(RBASIC(obj)->klass) && index < ROBJECT_NUMIV(obj) && (val = ROBJECT_IVPTR(obj)[index]) != Qundef)) {\n" - src << " stack[#{stack_size}] = val;\n" + src << " const uint32_t index = #{attr_index - 1};\n" + src << " if (source_shape_id == ROBJECT_SHAPE_ID(obj)) {\n" + src << " stack[#{stack_size}] = ROBJECT_IVPTR(obj)[index];\n" src << " }\n" end end @@ -419,20 +406,19 @@ def compile_ivar(insn_name, stack_size, pos, status, operands, body) src << " }\n" src << "}\n" return src - elsif insn_name == :getinstancevariable && !status.compile_info.disable_exivar_cache && ic_copy.entry + elsif insn_name == :getinstancevariable && !status.compile_info.disable_exivar_cache && source_shape_id != C.INVALID_SHAPE_ID # JIT: optimize away motion of sp and pc. This path does not call rb_warning() and so it's always leaf and not `handles_sp`. # compile_pc_and_sp(src, insn, stack_size, sp_inc, local_stack_p, next_pos) # JIT: prepare vm_getivar's arguments and variables src << "{\n" src << " VALUE obj = GET_SELF();\n" - src << " const rb_serial_t ic_serial = (rb_serial_t)#{ic_copy.entry.class_serial};\n" - src << " const uint32_t index = #{ic_copy.entry.index};\n" + src << " const shape_id_t source_shape_id = (shape_id_t)#{dest_shape_id};\n" + src << " const uint32_t index = #{attr_index - 1};\n" # JIT: cache hit path of vm_getivar, or cancel JIT (recompile it without any ivar optimization) src << " struct gen_ivtbl *ivtbl;\n" - src << " VALUE val;\n" - src << " if (LIKELY(FL_TEST_RAW(obj, FL_EXIVAR) && ic_serial == RCLASS_SERIAL(RBASIC(obj)->klass) && rb_ivar_generic_ivtbl_lookup(obj, &ivtbl) && index < ivtbl->numiv && (val = ivtbl->ivptr[index]) != Qundef)) {\n" - src << " stack[#{stack_size}] = val;\n" + src << " if (LIKELY(FL_TEST_RAW(obj, FL_EXIVAR) && source_shape_id == rb_shape_get_shape_id(obj) && rb_ivar_generic_ivtbl_lookup(obj, &ivtbl))) {\n" + src << " stack[#{stack_size}] = ivtbl->ivptr[index];\n" src << " }\n" src << " else {\n" src << " reg_cfp->pc = original_body_iseq + #{pos};\n" @@ -832,35 +818,16 @@ def init_compile_status(status, body, compile_root_p) def init_ivar_compile_status(body, status) C.mjit_capture_is_entries(body, status.is_entries) - num_ivars = 0 pos = 0 - status.max_ivar_index = 0 - status.ivar_serial = 0 while pos < body.iseq_size insn = INSNS.fetch(C.rb_vm_insn_decode(body.iseq_encoded[pos])) if insn.name == :getinstancevariable || insn.name == :setinstancevariable - ic = body.iseq_encoded[pos+2] - ic_copy = (status.is_entries + (C.iseq_inline_storage_entry.new(ic) - body.is_entries)).iv_cache - if ic_copy.entry # Only initialized (ic_serial > 0) IVCs are optimized - num_ivars += 1 - - if status.max_ivar_index < ic_copy.entry.index - status.max_ivar_index = ic_copy.entry.index - end - - if status.ivar_serial == 0 - status.ivar_serial = ic_copy.entry.class_serial - elsif status.ivar_serial != ic_copy.entry.class_serial - # Multiple classes have used this ISeq. Give up assuming one serial. - status.merge_ivar_guards_p = false - return - end - end + status.merge_ivar_guards_p = true + return end pos += insn.len end - status.merge_ivar_guards_p = status.ivar_serial > 0 && num_ivars >= 2 end # Expand simple macro that doesn't require dynamic C code. diff --git a/lib/net/http/generic_request.rb b/lib/net/http/generic_request.rb index 313de6ac92337c..d56835c76ffb80 100644 --- a/lib/net/http/generic_request.rb +++ b/lib/net/http/generic_request.rb @@ -15,7 +15,8 @@ def initialize(m, reqbody, resbody, uri_or_path, initheader = nil) if URI === uri_or_path then raise ArgumentError, "not an HTTP URI" unless URI::HTTP === uri_or_path - raise ArgumentError, "no host component for URI" unless uri_or_path.hostname + hostname = uri_or_path.hostname + raise ArgumentError, "no host component for URI" unless (hostname && hostname.length > 0) @uri = uri_or_path.dup host = @uri.hostname.dup host << ":".freeze << @uri.port.to_s if @uri.port != @uri.default_port diff --git a/lib/open-uri.rb b/lib/open-uri.rb index 2f7371039220cd..93e8cfcdb78aeb 100644 --- a/lib/open-uri.rb +++ b/lib/open-uri.rb @@ -99,7 +99,8 @@ module OpenURI :open_timeout => true, :ssl_ca_cert => nil, :ssl_verify_mode => nil, - :ssl_version => nil, + :ssl_min_version => nil, + :ssl_max_version => nil, :ftp_active_mode => false, :redirect => true, :encoding => nil, @@ -299,8 +300,8 @@ def OpenURI.open_http(buf, target, proxy, options) # :nodoc: require 'net/https' http.use_ssl = true http.verify_mode = options[:ssl_verify_mode] || OpenSSL::SSL::VERIFY_PEER - http.ssl_version = options[:ssl_version] if options[:ssl_version] && - OpenSSL::SSL::SSLContext::METHODS.include?(options[:ssl_version]) + http.min_version = options[:ssl_min_version] + http.max_version = options[:ssl_max_version] store = OpenSSL::X509::Store.new if options[:ssl_ca_cert] Array(options[:ssl_ca_cert]).each do |cert| @@ -702,6 +703,20 @@ module OpenRead # # :ssl_verify_mode is used to specify openssl verify mode. # + # [:ssl_min_version] + # Synopsis: + # :ssl_min_version=>:TLS1_2 + # + # :ssl_min_version option specifies the minimum allowed SSL/TLS protocol + # version. See also OpenSSL::SSL::SSLContext#min_version=. + # + # [:ssl_max_version] + # Synopsis: + # :ssl_max_version=>:TLS1_2 + # + # :ssl_max_version option specifies the maximum allowed SSL/TLS protocol + # version. See also OpenSSL::SSL::SSLContext#max_version=. + # # [:ftp_active_mode] # Synopsis: # :ftp_active_mode=>bool diff --git a/lib/pp.rb b/lib/pp.rb index f43356a3dfaaab..81551aa116d7dc 100644 --- a/lib/pp.rb +++ b/lib/pp.rb @@ -416,6 +416,26 @@ def pretty_print_cycle(q) # :nodoc: end end +class Data # :nodoc: + def pretty_print(q) # :nodoc: + q.group(1, sprintf("#') { + q.seplist(PP.mcall(self, Data, :members), lambda { q.text "," }) {|member| + q.breakable + q.text member.to_s + q.text '=' + q.group(1) { + q.breakable '' + q.pp public_send(member) + } + } + } + end + + def pretty_print_cycle(q) # :nodoc: + q.text sprintf("#", PP.mcall(self, Kernel, :class).name) + end +end if "3.2" <= RUBY_VERSION + class Range # :nodoc: def pretty_print(q) # :nodoc: q.pp self.begin diff --git a/lib/pstore.rb b/lib/pstore.rb index 8d7137aa39e7fb..99be1d48496337 100644 --- a/lib/pstore.rb +++ b/lib/pstore.rb @@ -71,7 +71,7 @@ # when the store is created (see PStore.new). # The objects are stored and retrieved using # module Marshal, which means that certain objects cannot be added to the store; -# see {Marshal::dump}[https://docs.ruby-lang.org/en/master/Marshal.html#method-c-dump]. +# see {Marshal::dump}[rdoc-ref:Marshal.dump]. # # == Entries # @@ -79,11 +79,11 @@ # Each entry has a key and a value, just as in a hash: # # - Key: as in a hash, the key can be (almost) any object; -# see {Hash Keys}[https://docs.ruby-lang.org/en/master/Hash.html#class-Hash-label-Hash+Keys]. +# see {Hash Keys}[rdoc-ref:Hash@Hash+Keys]. # You may find it convenient to keep it simple by using only # symbols or strings as keys. # - Value: the value may be any object that can be marshalled by \Marshal -# (see {Marshal::dump}[https://docs.ruby-lang.org/en/master/Marshal.html#method-c-dump]) +# (see {Marshal::dump}[rdoc-ref:Marshal.dump]) # and in fact may be a collection # (e.g., an array, a hash, a set, a range, etc). # That collection may in turn contain nested objects, @@ -194,7 +194,7 @@ # end # # And recall that you can use -# {dig methods}[https://docs.ruby-lang.org/en/master/dig_methods_rdoc.html] +# {dig methods}[rdoc-ref:dig_methods.rdoc] # in a returned hierarchy of objects. # # == Working with the Store diff --git a/lib/set.rb b/lib/set.rb index 0490654183a450..df1e68d0817364 100644 --- a/lib/set.rb +++ b/lib/set.rb @@ -66,8 +66,8 @@ # # First, what's elsewhere. \Class \Set: # -# - Inherits from {class Object}[https://docs.ruby-lang.org/en/master/Object.html#class-Object-label-What-27s+Here]. -# - Includes {module Enumerable}[https://docs.ruby-lang.org/en/master/Enumerable.html#module-Enumerable-label-What-27s+Here], +# - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here]. +# - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here], # which provides dozens of additional methods. # # In particular, class \Set does not have many methods of its own diff --git a/lib/tempfile.rb b/lib/tempfile.rb index 8a6bcc3e14f47d..c3263ed3c68201 100644 --- a/lib/tempfile.rb +++ b/lib/tempfile.rb @@ -104,7 +104,7 @@ class Tempfile < DelegateClass(File) # - Directory is the system temporary directory (system-dependent). # - Generated filename is unique in that directory. # - Permissions are 0600; - # see {File Permissions}[https://docs.ruby-lang.org/en/master/File.html#label-File+Permissions]. + # see {File Permissions}[rdoc-ref:File@File+Permissions]. # - Mode is 'w+' (read/write mode, positioned at the end). # # The underlying file is removed when the \Tempfile object dies @@ -136,12 +136,12 @@ class Tempfile < DelegateClass(File) # Tempfile.new('foo', '.') # => # # # Keyword arguments +mode+ and +options+ are passed directly to method - # {File.open}[https://docs.ruby-lang.org/en/master/File.html#method-c-open]: + # {File.open}[rdoc-ref:File.open]: # # - The value given with +mode+ must be an integer, # and may be expressed as the logical OR of constants defined in - # {File::Constants}[https://docs.ruby-lang.org/en/master/File/Constants.html]. - # - For +options+, see {Open Options}[https://docs.ruby-lang.org/en/master/IO.html#class-IO-label-Open+Options]. + # {File::Constants}[rdoc-ref:File::Constants]. + # - For +options+, see {Open Options}[rdoc-ref:IO@Open+Options]. # # Related: Tempfile.create. # @@ -344,11 +344,11 @@ def open(*args, **kw) # # With no block given and no arguments, creates and returns file whose: # -# - Class is {File}[https://docs.ruby-lang.org/en/master/File.html] (not \Tempfile). +# - Class is {File}[rdoc-ref:File] (not \Tempfile). # - Directory is the system temporary directory (system-dependent). # - Generated filename is unique in that directory. # - Permissions are 0600; -# see {File Permissions}[https://docs.ruby-lang.org/en/master/File.html#label-File+Permissions]. +# see {File Permissions}[rdoc-ref:File@File+Permissions]. # - Mode is 'w+' (read/write mode, positioned at the end). # # With no block, the file is not removed automatically, @@ -380,12 +380,12 @@ def open(*args, **kw) # Tempfile.create('foo', '.') # => # # # Keyword arguments +mode+ and +options+ are passed directly to method -# {File.open}[https://docs.ruby-lang.org/en/master/File.html#method-c-open]: +# {File.open}[rdoc-ref:File.open]: # # - The value given with +mode+ must be an integer, # and may be expressed as the logical OR of constants defined in -# {File::Constants}[https://docs.ruby-lang.org/en/master/File/Constants.html]. -# - For +options+, see {Open Options}[https://docs.ruby-lang.org/en/master/IO.html#class-IO-label-Open+Options]. +# {File::Constants}[rdoc-ref:File::Constants]. +# - For +options+, see {Open Options}[rdoc-ref:IO@Open+Options]. # # With a block given, creates the file as above, passes it to the block, # and returns the block's value; diff --git a/lib/uri/rfc3986_parser.rb b/lib/uri/rfc3986_parser.rb index 3e07de4805c374..f3816d9ae5ea2f 100644 --- a/lib/uri/rfc3986_parser.rb +++ b/lib/uri/rfc3986_parser.rb @@ -2,9 +2,8 @@ module URI class RFC3986_Parser # :nodoc: # URI defined in RFC3986 - # this regexp is modified not to host is not empty string - RFC3986_URI = /\A(?(?[A-Za-z][+\-.0-9A-Za-z]*):(?\/\/(?(?:(?(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?(?\[(?:(?(?:\h{1,4}:){6}(?\h{1,4}:\h{1,4}|(?(?[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g\.\g\.\g))|::(?:\h{1,4}:){5}\g|\h{1,4}?::(?:\h{1,4}:){4}\g|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g|(?(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])+))?(?::(?\d*))?)(?(?:\/(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?\/(?:(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g)*)?)|(?\g(?:\/\g)*)|(?))(?:\?(?[^#]*))?(?:\#(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/ - RFC3986_relative_ref = /\A(?(?\/\/(?(?:(?(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?(?\[(?(?:\h{1,4}:){6}(?\h{1,4}:\h{1,4}|(?(?[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g\.\g\.\g))|::(?:\h{1,4}:){5}\g|\h{1,4}?::(?:\h{1,4}:){4}\g|(?:(?:\h{1,4}:){,1}\h{1,4})?::(?:\h{1,4}:){3}\g|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?v\h+\.[!$&-.0-;=A-Z_a-z~]+)\])|\g|(?(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])+))?(?::(?\d*))?)(?(?:\/(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?\/(?:(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g)*)?)|(?(?(?:%\h\h|[!$&-.0-9;=@-Z_a-z~])+)(?:\/\g)*)|(?))(?:\?(?[^#]*))?(?:\#(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/ + RFC3986_URI = /\A(?(?[A-Za-z][+\-.0-9A-Za-z]*):(?\/\/(?(?:(?(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?(?\[(?:(?(?:\h{1,4}:){6}(?\h{1,4}:\h{1,4}|(?(?[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g\.\g\.\g))|::(?:\h{1,4}:){5}\g|\h{1,4}?::(?:\h{1,4}:){4}\g|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g|(?(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*))(?::(?\d*))?)(?(?:\/(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?\/(?:(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g)*)?)|(?\g(?:\/\g)*)|(?))(?:\?(?[^#]*))?(?:\#(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/ + RFC3986_relative_ref = /\A(?(?\/\/(?(?:(?(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?(?\[(?:(?(?:\h{1,4}:){6}(?\h{1,4}:\h{1,4}|(?(?[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g\.\g\.\g))|::(?:\h{1,4}:){5}\g|\h{1,4}?::(?:\h{1,4}:){4}\g|(?:(?:\h{1,4}:){,1}\h{1,4})?::(?:\h{1,4}:){3}\g|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g|(?(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])+))?(?::(?\d*))?)(?(?:\/(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?\/(?:(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g)*)?)|(?(?(?:%\h\h|[!$&-.0-9;=@-Z_a-z~])+)(?:\/\g)*)|(?))(?:\?(?[^#]*))?(?:\#(?(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/ attr_reader :regexp def initialize diff --git a/marshal.c b/marshal.c index e4b40c0607b608..59edbfe53a2a88 100644 --- a/marshal.c +++ b/marshal.c @@ -39,6 +39,7 @@ #include "ruby/st.h" #include "ruby/util.h" #include "builtin.h" +#include "shape.h" #define BITSPERSHORT (2*CHAR_BIT) #define SHORTMASK ((1<num_ivar) { - rb_raise(rb_eRuntimeError, "instance variable added to %"PRIsVALUE" instance", - CLASS_OF(arg->obj)); - } --ivarg->num_ivar; w_symbol(ID2SYM(id), arg->arg); w_object(value, arg->arg, arg->limit); @@ -720,6 +717,7 @@ has_ivars(VALUE obj, VALUE encname, VALUE *ivobj) static void w_ivar_each(VALUE obj, st_index_t num, struct dump_call_arg *arg) { + shape_id_t shape_id = rb_shape_get_shape_id(arg->obj); struct w_ivar_arg ivarg = {arg, num}; if (!num) return; rb_ivar_foreach(obj, w_obj_each, (st_data_t)&ivarg); @@ -727,6 +725,10 @@ w_ivar_each(VALUE obj, st_index_t num, struct dump_call_arg *arg) rb_raise(rb_eRuntimeError, "instance variable removed from %"PRIsVALUE" instance", CLASS_OF(arg->obj)); } + if (shape_id != rb_shape_get_shape_id(arg->obj)) { + rb_raise(rb_eRuntimeError, "instance variable added to %"PRIsVALUE" instance", + CLASS_OF(arg->obj)); + } } static void diff --git a/misc/lldb_cruby.py b/misc/lldb_cruby.py index 595d54dfab3dde..9ef9d3967b6e86 100755 --- a/misc/lldb_cruby.py +++ b/misc/lldb_cruby.py @@ -418,6 +418,7 @@ def lldb_inspect(debugger, target, result, val): elif flType == RUBY_T_IMEMO: # I'm not sure how to get IMEMO_MASK out of lldb. It's not in globals() imemo_type = (flags >> RUBY_FL_USHIFT) & 0x0F # IMEMO_MASK + print("T_IMEMO: ", file=result) append_command_output(debugger, "p (enum imemo_type) %d" % imemo_type, result) append_command_output(debugger, "p *(struct MEMO *) %0#x" % val.GetValueAsUnsigned(), result) diff --git a/mjit.c b/mjit.c index 80743a150bdba3..22da5fd45fb501 100644 --- a/mjit.c +++ b/mjit.c @@ -951,42 +951,19 @@ mjit_capture_cc_entries(const struct rb_iseq_constant_body *compiled_iseq, const // Set up field `used_code_p` for unit iseqs whose iseq on the stack of ec. static void -mark_ec_units(rb_execution_context_t *ec) +mark_iseq_units(const rb_iseq_t *iseq) { - const rb_control_frame_t *cfp; - - if (ec->vm_stack == NULL) - return; - for (cfp = RUBY_VM_END_CONTROL_FRAME(ec) - 1; ; cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) { - const rb_iseq_t *iseq; - if (cfp->pc && (iseq = cfp->iseq) != NULL - && imemo_type((VALUE) iseq) == imemo_iseq - && (ISEQ_BODY(iseq)->jit_unit) != NULL) { - ISEQ_BODY(iseq)->jit_unit->used_code_p = true; - } - - if (cfp == ec->cfp) - break; // reached the most recent cfp + if (ISEQ_BODY(iseq)->jit_unit != NULL) { + ISEQ_BODY(iseq)->jit_unit->used_code_p = true; } } -// MJIT info related to an existing continutaion. -struct mjit_cont { - rb_execution_context_t *ec; // continuation ec - struct mjit_cont *prev, *next; // used to form lists -}; - -// Double linked list of registered continuations. This is used to detect -// units which are in use in unload_units. -static struct mjit_cont *first_cont; - // Unload JIT code of some units to satisfy the maximum permitted // number of units with a loaded code. static void unload_units(void) { struct rb_mjit_unit *unit = 0, *next; - struct mjit_cont *cont; int units_num = active_units.length; // For now, we don't unload units when ISeq is GCed. We should @@ -1005,9 +982,7 @@ unload_units(void) } // All threads have a root_fiber which has a mjit_cont. Other normal fibers also // have a mjit_cont. Thus we can check ISeqs in use by scanning ec of mjit_conts. - for (cont = first_cont; cont != NULL; cont = cont->next) { - mark_ec_units(cont->ec); - } + rb_jit_cont_each_iseq(mark_iseq_units); // TODO: check stale_units and unload unused ones! (note that the unit is not associated to ISeq anymore) // Unload units whose total_calls is smaller than any total_calls in unit_queue. @@ -1163,68 +1138,6 @@ free_list(struct rb_mjit_unit_list *list, bool close_handle_p) list->length = 0; } -// Register a new continuation with execution context `ec`. Return MJIT info about -// the continuation. -struct mjit_cont * -mjit_cont_new(rb_execution_context_t *ec) -{ - struct mjit_cont *cont; - - // We need to use calloc instead of something like ZALLOC to avoid triggering GC here. - // When this function is called from rb_thread_alloc through rb_threadptr_root_fiber_setup, - // the thread is still being prepared and marking it causes SEGV. - cont = calloc(1, sizeof(struct mjit_cont)); - if (cont == NULL) - rb_memerror(); - cont->ec = ec; - - CRITICAL_SECTION_START(3, "in mjit_cont_new"); - if (first_cont == NULL) { - cont->next = cont->prev = NULL; - } - else { - cont->prev = NULL; - cont->next = first_cont; - first_cont->prev = cont; - } - first_cont = cont; - CRITICAL_SECTION_FINISH(3, "in mjit_cont_new"); - - return cont; -} - -// Unregister continuation `cont`. -void -mjit_cont_free(struct mjit_cont *cont) -{ - CRITICAL_SECTION_START(3, "in mjit_cont_new"); - if (cont == first_cont) { - first_cont = cont->next; - if (first_cont != NULL) - first_cont->prev = NULL; - } - else { - cont->prev->next = cont->next; - if (cont->next != NULL) - cont->next->prev = cont->prev; - } - CRITICAL_SECTION_FINISH(3, "in mjit_cont_new"); - - free(cont); -} - -// Finish work with continuation info. -static void -finish_conts(void) -{ - struct mjit_cont *cont, *next; - - for (cont = first_cont; cont != NULL; cont = next) { - next = cont->next; - xfree(cont); - } -} - static void mjit_wait(struct rb_iseq_constant_body *body); // Check the unit queue and start mjit_compile if nothing is in progress. @@ -1889,13 +1802,6 @@ mjit_init(const struct mjit_options *opts) rb_native_cond_initialize(&mjit_worker_wakeup); rb_native_cond_initialize(&mjit_gc_wakeup); - // Make sure the saved_ec of the initial thread's root_fiber is scanned by mark_ec_units. - // - // rb_threadptr_root_fiber_setup for the initial thread is called before mjit_init, - // meaning mjit_cont_new is skipped for the root_fiber. Therefore we need to call - // rb_fiber_init_mjit_cont again with mjit_enabled=true to set the root_fiber's mjit_cont. - rb_fiber_init_mjit_cont(GET_EC()->fiber_ptr); - // If --mjit=pause is given, lazily start MJIT when RubyVM::MJIT.resume is called. // You can use it to control MJIT warmup, or to customize the JIT implementation. if (!mjit_opts.pause) { @@ -2052,7 +1958,6 @@ mjit_finish(bool close_handle_p) free_list(&active_units, close_handle_p); free_list(&compact_units, close_handle_p); free_list(&stale_units, close_handle_p); - finish_conts(); mjit_enabled = false; verbose(1, "Successful MJIT finish"); diff --git a/mjit.h b/mjit.h index ed696b3ff7cd9e..7211e460ab42fb 100644 --- a/mjit.h +++ b/mjit.h @@ -101,8 +101,6 @@ extern void mjit_init(const struct mjit_options *opts); extern void mjit_free_iseq(const rb_iseq_t *iseq); extern void mjit_update_references(const rb_iseq_t *iseq); extern void mjit_mark(void); -extern struct mjit_cont *mjit_cont_new(rb_execution_context_t *ec); -extern void mjit_cont_free(struct mjit_cont *cont); extern void mjit_mark_cc_entries(const struct rb_iseq_constant_body *const body); extern void mjit_notify_waitpid(int exit_code); @@ -120,8 +118,6 @@ void mjit_finish(bool close_handle_p); # else // USE_MJIT static inline void mjit_cancel_all(const char *reason){} -static inline struct mjit_cont *mjit_cont_new(rb_execution_context_t *ec){return NULL;} -static inline void mjit_cont_free(struct mjit_cont *cont){} static inline void mjit_free_iseq(const rb_iseq_t *iseq){} static inline void mjit_mark(void){} static inline VALUE jit_exec(rb_execution_context_t *ec) { return Qundef; /* unreachable */ } diff --git a/mjit_c.rb b/mjit_c.rb index d8e5628bda57d4..4a68ec12ae5c4b 100644 --- a/mjit_c.rb +++ b/mjit_c.rb @@ -5,6 +5,14 @@ module RubyVM::MJIT C = Object.new class << C + def SHAPE_BITS + Primitive.cexpr! 'UINT2NUM(SHAPE_BITS)' + end + + def SHAPE_FLAG_SHIFT + Primitive.cexpr! 'UINT2NUM(SHAPE_FLAG_SHIFT)' + end + def ROBJECT_EMBED_LEN_MAX Primitive.cexpr! 'INT2NUM(RBIMPL_EMBED_LEN_MAX_OF(VALUE))' end @@ -21,6 +29,12 @@ def has_cache_for_send(cc, insn) Primitive.has_cache_for_send(cc.to_i, insn) end + def rb_shape_get_shape_by_id(shape_id) + _shape_id = shape_id.to_i + shape_addr = Primitive.cexpr! 'PTR2NUM((VALUE)rb_shape_get_shape_by_id((shape_id_t)NUM2UINT(_shape_id)))' + rb_shape_t.new(shape_addr) + end + def rb_iseq_check(iseq) _iseq_addr = iseq.to_i iseq_addr = Primitive.cexpr! 'PTR2NUM((VALUE)rb_iseq_check((rb_iseq_t *)NUM2PTR(_iseq_addr)))' @@ -165,6 +179,14 @@ def C.VM_METHOD_TYPE_ISEQ Primitive.cexpr! %q{ INT2NUM(VM_METHOD_TYPE_ISEQ) } end + def C.INVALID_SHAPE_ID + Primitive.cexpr! %q{ ULONG2NUM(INVALID_SHAPE_ID) } + end + + def C.SHAPE_MASK + Primitive.cexpr! %q{ ULONG2NUM(SHAPE_MASK) } + end + def C.CALL_DATA @CALL_DATA ||= self.rb_call_data end @@ -181,6 +203,10 @@ def C.RB_BUILTIN @RB_BUILTIN ||= self.rb_builtin_function end + def C.attr_index_t + @attr_index_t ||= CType::Immediate.parse("uint32_t") + end + def C.compile_branch @compile_branch ||= CType::Struct.new( "compile_branch", Primitive.cexpr!("SIZEOF(struct compile_branch)"), @@ -201,7 +227,6 @@ def C.compile_status compiled_id: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), compiled_id)")], compile_info: [CType::Pointer.new { self.rb_mjit_compile_info }, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), compile_info)")], merge_ivar_guards_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), merge_ivar_guards_p)")], - ivar_serial: [self.rb_serial_t, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), ivar_serial)")], max_ivar_index: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), max_ivar_index)")], inlined_iseqs: [CType::Pointer.new { CType::Pointer.new { self.rb_iseq_constant_body } }, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), inlined_iseqs)")], inline_context: [self.inlined_call_context, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), inline_context)")], @@ -240,7 +265,7 @@ def C.iseq_inline_constant_cache_entry def C.iseq_inline_iv_cache_entry @iseq_inline_iv_cache_entry ||= CType::Struct.new( "iseq_inline_iv_cache_entry", Primitive.cexpr!("SIZEOF(struct iseq_inline_iv_cache_entry)"), - entry: [CType::Pointer.new { self.rb_iv_index_tbl_entry }, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_iv_cache_entry *)NULL)), entry)")], + value: [CType::Immediate.parse("uintptr_t"), Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_iv_cache_entry *)NULL)), value)")], ) end @@ -313,7 +338,10 @@ def C.rb_callcache call_: [self.vm_call_handler, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), call_)")], aux_: [CType::Union.new( "", Primitive.cexpr!("SIZEOF(((struct rb_callcache *)NULL)->aux_)"), - attr_index: CType::Immediate.parse("unsigned int"), + attr: CType::Struct.new( + "", Primitive.cexpr!("SIZEOF(((struct rb_callcache *)NULL)->aux_.attr)"), + value: [CType::Immediate.parse("uintptr_t"), Primitive.cexpr!("OFFSETOF(((struct rb_callcache *)NULL)->aux_.attr, value)")], + ), method_missing_reason: self.method_missing_reason, v: self.VALUE, ), Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), aux_)")], @@ -503,8 +531,8 @@ def C.rb_iv_index_tbl_entry @rb_iv_index_tbl_entry ||= CType::Struct.new( "rb_iv_index_tbl_entry", Primitive.cexpr!("SIZEOF(struct rb_iv_index_tbl_entry)"), index: [CType::Immediate.parse("uint32_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_iv_index_tbl_entry *)NULL)), index)")], - class_serial: [self.rb_serial_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iv_index_tbl_entry *)NULL)), class_serial)")], - class_value: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iv_index_tbl_entry *)NULL)), class_value)")], + source_shape_id: [self.shape_id_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iv_index_tbl_entry *)NULL)), source_shape_id)")], + dest_shape_id: [self.shape_id_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iv_index_tbl_entry *)NULL)), dest_shape_id)")], ) end @@ -573,10 +601,29 @@ def C.rb_serial_t @rb_serial_t ||= CType::Immediate.parse("unsigned long long") end + def C.rb_shape + @rb_shape ||= CType::Struct.new( + "rb_shape", Primitive.cexpr!("SIZEOF(struct rb_shape)"), + edges: [CType::Pointer.new { self.rb_id_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), edges)")], + edge_name: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), edge_name)")], + iv_count: [self.attr_index_t, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), iv_count)")], + type: [CType::Immediate.parse("uint8_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), type)")], + parent_id: [self.shape_id_t, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), parent_id)")], + ) + end + + def C.rb_shape_t + @rb_shape_t ||= self.rb_shape + end + def C.VALUE @VALUE ||= CType::Immediate.find(Primitive.cexpr!("SIZEOF(VALUE)"), Primitive.cexpr!("SIGNED_TYPE_P(VALUE)")) end + def C.shape_id_t + @shape_id_t ||= CType::Immediate.find(Primitive.cexpr!("SIZEOF(shape_id_t)"), Primitive.cexpr!("SIGNED_TYPE_P(shape_id_t)")) + end + def C._Bool CType::Bool.new end diff --git a/mjit_compiler.h b/mjit_compiler.h index da7905442025f5..b465be00fd678a 100644 --- a/mjit_compiler.h +++ b/mjit_compiler.h @@ -8,6 +8,7 @@ #include "builtin.h" #include "mjit.h" #include "mjit_unit.h" +#include "shape.h" // Macros to check if a position is already compiled using compile_status.stack_size_for_pos #define NOT_COMPILED_STACK_SIZE -1 @@ -48,7 +49,6 @@ struct compile_status { // Mutated optimization levels struct rb_mjit_compile_info *compile_info; bool merge_ivar_guards_p; // If true, merge guards of ivar accesses - rb_serial_t ivar_serial; // ic_serial of IVC in is_entries (used only when merge_ivar_guards_p) size_t max_ivar_index; // Max IVC index in is_entries (used only when merge_ivar_guards_p) // If `inlined_iseqs[pos]` is not NULL, `mjit_compile_body` tries to inline ISeq there. const struct rb_iseq_constant_body **inlined_iseqs; diff --git a/numeric.c b/numeric.c index 4f927f00fb655b..8607d697942a3a 100644 --- a/numeric.c +++ b/numeric.c @@ -1055,7 +1055,7 @@ flo_to_s(VALUE flt) { enum {decimal_mant = DBL_MANT_DIG-DBL_DIG}; enum {float_dig = DBL_DIG+1}; - char buf[float_dig + (decimal_mant + CHAR_BIT - 1) / CHAR_BIT + 10]; + char buf[float_dig + roomof(decimal_mant, CHAR_BIT) + 10]; double value = RFLOAT_VALUE(flt); VALUE s; char *p, *e; diff --git a/object.c b/object.c index 1349dacd52ad3c..11f6e9b842e48a 100644 --- a/object.c +++ b/object.c @@ -39,6 +39,7 @@ #include "ruby/util.h" #include "ruby/assert.h" #include "builtin.h" +#include "shape.h" #if USE_MMTK #include "gc.h" @@ -271,13 +272,21 @@ rb_obj_singleton_class(VALUE obj) MJIT_FUNC_EXPORTED void rb_obj_copy_ivar(VALUE dest, VALUE obj) { - VALUE *dest_buf = ROBJECT_IVPTR(dest); - VALUE *src_buf = ROBJECT_IVPTR(obj); uint32_t dest_len = ROBJECT_NUMIV(dest); uint32_t src_len = ROBJECT_NUMIV(obj); - uint32_t len = dest_len < src_len ? dest_len : src_len; - MEMCPY(dest_buf, src_buf, VALUE, len); + if (dest_len < src_len) { + rb_ensure_iv_list_size(dest, dest_len, src_len); + RUBY_ASSERT(!(RBASIC(dest)->flags & ROBJECT_EMBED)); + } + else { + RUBY_ASSERT((RBASIC(dest)->flags & ROBJECT_EMBED)); + } + + VALUE * dest_buf = ROBJECT_IVPTR(dest); + VALUE * src_buf = ROBJECT_IVPTR(obj); + + MEMCPY(dest_buf, src_buf, VALUE, ROBJECT_IV_COUNT(obj)); } static void @@ -287,6 +296,7 @@ init_copy(VALUE dest, VALUE obj) rb_raise(rb_eTypeError, "[bug] frozen object (%s) allocated", rb_obj_classname(dest)); } RBASIC(dest)->flags &= ~(T_MASK|FL_EXIVAR); + // Copies the shape id from obj to dest RBASIC(dest)->flags |= RBASIC(obj)->flags & (T_MASK|FL_EXIVAR); #if USE_MMTK if (!rb_mmtk_enabled_p()) { @@ -297,6 +307,18 @@ init_copy(VALUE dest, VALUE obj) #endif rb_copy_generic_ivar(dest, obj); rb_gc_copy_finalizer(dest, obj); + + rb_shape_t *shape_to_set = rb_shape_get_shape(obj); + + // If the object is frozen, the "dup"'d object will *not* be frozen, + // so we need to copy the frozen shape's parent to the new object. + if (rb_shape_frozen_shape_p(shape_to_set)) { + shape_to_set = rb_shape_get_shape_by_id(shape_to_set->parent_id); + } + + // shape ids are different + rb_shape_set_shape(dest, shape_to_set); + if (RB_TYPE_P(obj, T_OBJECT)) { rb_obj_copy_ivar(dest, obj); } @@ -402,6 +424,9 @@ mutable_obj_clone(VALUE obj, VALUE kwfreeze) case Qnil: rb_funcall(clone, id_init_clone, 1, obj); RBASIC(clone)->flags |= RBASIC(obj)->flags & FL_FREEZE; + if (RB_OBJ_FROZEN(obj)) { + rb_shape_transition_shape_frozen(clone); + } break; case Qtrue: { @@ -417,6 +442,7 @@ mutable_obj_clone(VALUE obj, VALUE kwfreeze) argv[1] = freeze_true_hash; rb_funcallv_kw(clone, id_init_clone, 2, argv, RB_PASS_KEYWORDS); RBASIC(clone)->flags |= FL_FREEZE; + rb_shape_transition_shape_frozen(clone); break; } case Qfalse: diff --git a/ractor.c b/ractor.c index 3bd6c04af00b35..7fea312ab0e31b 100644 --- a/ractor.c +++ b/ractor.c @@ -2312,7 +2312,7 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data) case T_OBJECT: { - uint32_t len = ROBJECT_NUMIV(obj); + uint32_t len = ROBJECT_IV_COUNT(obj); VALUE *ptr = ROBJECT_IVPTR(obj); for (uint32_t i=0; imove) rb_obj_transient_heap_evacuate(obj, TRUE); #endif - uint32_t len = ROBJECT_NUMIV(obj); + uint32_t len = ROBJECT_IV_COUNT(obj); VALUE *ptr = ROBJECT_IVPTR(obj); for (uint32_t i=0; i 0 uint32_t rb_ractor_current_id(void); +// If ractor check mode is enabled, shape bits needs to be smaller +STATIC_ASSERT(shape_bits, SHAPE_BITS == 16); static inline void rb_ractor_setup_belonging_to(VALUE obj, uint32_t rid) { - VALUE flags = RBASIC(obj)->flags & 0xffffffff; // 4B + VALUE flags = RBASIC(obj)->flags & 0xffff0000ffffffff; // 4B RBASIC(obj)->flags = flags | ((VALUE)rid << 32); } @@ -310,7 +312,7 @@ rb_ractor_belonging(VALUE obj) return 0; } else { - return RBASIC(obj)->flags >> 32; + return RBASIC(obj)->flags >> 32 & 0xFFFF; } } diff --git a/random.c b/random.c index 9476de0d4afc03..f8879cfb88a836 100644 --- a/random.c +++ b/random.c @@ -487,28 +487,35 @@ fill_random_bytes_urandom(void *seed, size_t size) #if 0 #elif defined MAC_OS_X_VERSION_10_7 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7 -# if defined MAC_OS_X_VERSION_10_10 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10 +# if defined(USE_COMMON_RANDOM) +# elif defined MAC_OS_X_VERSION_10_10 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10 +# define USE_COMMON_RANDOM 1 +# else +# define USE_COMMON_RANDOM 0 +# endif +# if USE_COMMON_RANDOM # include /* for old Xcode */ # include -# define USE_COMMON_RANDOM 1 # else # include -# define USE_COMMON_RANDOM 0 # endif static int fill_random_bytes_syscall(void *seed, size_t size, int unused) { #if USE_COMMON_RANDOM - int failed = CCRandomGenerateBytes(seed, size) != kCCSuccess; + CCRNGStatus status = CCRandomGenerateBytes(seed, size); + int failed = status != kCCSuccess; #else - int failed = SecRandomCopyBytes(kSecRandomDefault, size, seed) != errSecSuccess; + int status = SecRandomCopyBytes(kSecRandomDefault, size, seed); + int failed = status != errSecSuccess; #endif if (failed) { # if 0 # if USE_COMMON_RANDOM /* How to get the error message? */ + fprintf(stderr, "CCRandomGenerateBytes failed: %d\n", status); # else CFStringRef s = SecCopyErrorMessageString(status, NULL); const char *m = s ? CFStringGetCStringPtr(s, kCFStringEncodingUTF8) : NULL; diff --git a/regcomp.c b/regcomp.c index 94640639d8b87f..be85d85f93d476 100644 --- a/regcomp.c +++ b/regcomp.c @@ -341,7 +341,7 @@ static int select_str_opcode(int mb_len, OnigDistance byte_len, int ignore_case) { int op; - OnigDistance str_len = (byte_len + mb_len - 1) / mb_len; + OnigDistance str_len = roomof(byte_len, mb_len); if (ignore_case) { switch (str_len) { diff --git a/regenc.h b/regenc.h index 8c4ff0483b380e..1c409010545530 100644 --- a/regenc.h +++ b/regenc.h @@ -125,10 +125,9 @@ typedef struct { #define POSIX_BRACKET_ENTRY_INIT(name, ctype) \ {(short int )(sizeof(name) - 1), name, (ctype)} -#ifndef numberof -# define numberof(array) (int )(sizeof(array) / sizeof((array)[0])) -#endif - +#define numberof(array) ((int)(sizeof(array) / sizeof((array)[0]))) +#define roomof(x, y) (((x) + (y) - 1) / (y)) +#define type_roomof(x, y) roomof(sizeof(x), sizeof(y)) #define USE_CRNL_AS_LINE_TERMINATOR #define USE_UNICODE_PROPERTIES diff --git a/ruby.c b/ruby.c index 53a1cc6bfd88aa..16d2f7abb952dd 100644 --- a/ruby.c +++ b/ruby.c @@ -44,6 +44,7 @@ #include "eval_intern.h" #include "internal.h" #include "internal/cmdlineopt.h" +#include "internal/cont.h" #include "internal/error.h" #include "internal/file.h" #include "internal/inits.h" @@ -1654,6 +1655,12 @@ ruby_opt_init(ruby_cmdline_options_t *opt) rb_call_builtin_inits(); ruby_init_prelude(); + // Make sure the saved_ec of the initial thread's root_fiber is scanned by rb_jit_cont_each_ec. + // + // rb_threadptr_root_fiber_setup for the initial thread is called before rb_yjit_enabled_p() + // or mjit_enabled becomes true, meaning jit_cont_new is skipped for the root_fiber. + // Therefore we need to call this again here to set the root_fiber's jit_cont. + rb_fiber_init_jit_cont(GET_EC()->fiber_ptr); #if USE_MJIT // mjit_init is safe only after rb_call_builtin_inits defines RubyVM::MJIT::Compiler if (opt->mjit.on) diff --git a/scheduler.c b/scheduler.c index 675a0a6768efcd..611182741c664b 100644 --- a/scheduler.c +++ b/scheduler.c @@ -28,10 +28,63 @@ static ID id_process_wait; static ID id_io_read, id_io_pread; static ID id_io_write, id_io_pwrite; static ID id_io_wait; +static ID id_io_select; static ID id_io_close; static ID id_address_resolve; +static ID id_fiber_schedule; + +/* + * Document-class: Fiber::Scheduler + * + * This is not an existing class, but documentation of the interface that Scheduler + * object should comply to in order to be used as argument to Fiber.scheduler and handle non-blocking + * fibers. See also the "Non-blocking fibers" section in Fiber class docs for explanations + * of some concepts. + * + * Scheduler's behavior and usage are expected to be as follows: + * + * * When the execution in the non-blocking Fiber reaches some blocking operation (like + * sleep, wait for a process, or a non-ready I/O), it calls some of the scheduler's + * hook methods, listed below. + * * Scheduler somehow registers what the current fiber is waiting on, and yields control + * to other fibers with Fiber.yield (so the fiber would be suspended while expecting its + * wait to end, and other fibers in the same thread can perform) + * * At the end of the current thread execution, the scheduler's method #scheduler_close is called + * * The scheduler runs into a wait loop, checking all the blocked fibers (which it has + * registered on hook calls) and resuming them when the awaited resource is ready + * (e.g. I/O ready or sleep time elapsed). + * + * This way concurrent execution will be achieved transparently for every + * individual Fiber's code. + * + * Scheduler implementations are provided by gems, like + * Async[https://github.com/socketry/async]. + * + * Hook methods are: + * + * * #io_wait, #io_read, #io_write, #io_pread, #io_pwrite, and #io_select, #io_close + * * #process_wait + * * #kernel_sleep + * * #timeout_after + * * #address_resolve + * * #block and #unblock + * * (the list is expanded as Ruby developers make more methods having non-blocking calls) + * + * When not specified otherwise, the hook implementations are mandatory: if they are not + * implemented, the methods trying to call hook will fail. To provide backward compatibility, + * in the future hooks will be optional (if they are not implemented, due to the scheduler + * being created for the older Ruby version, the code which needs this hook will not fail, + * and will just behave in a blocking fashion). + * + * It is also strongly recommended that the scheduler implements the #fiber method, which is + * delegated to by Fiber.schedule. + * + * Sample _toy_ implementation of the scheduler can be found in Ruby's code, in + * test/fiber/scheduler.rb + * + */ void Init_Fiber_Scheduler(void) { @@ -51,9 +104,27 @@ Init_Fiber_Scheduler(void) id_io_pwrite = rb_intern_const("io_pwrite"); id_io_wait = rb_intern_const("io_wait"); + id_io_select = rb_intern_const("io_select"); id_io_close = rb_intern_const("io_close"); id_address_resolve = rb_intern_const("address_resolve"); + + id_fiber_schedule = rb_intern_const("fiber"); + +#if 0 /* for RDoc */ + rb_cFiberScheduler = rb_define_class_under(rb_cFiber, "Scheduler", rb_cObject); + rb_define_method(rb_cFiberScheduler, "close", rb_fiber_scheduler_close, 0); + rb_define_method(rb_cFiberScheduler, "process_wait", rb_fiber_scheduler_process_wait, 2); + rb_define_method(rb_cFiberScheduler, "io_wait", rb_fiber_scheduler_io_wait, 3); + rb_define_method(rb_cFiberScheduler, "io_read", rb_fiber_scheduler_io_read, 4); + rb_define_method(rb_cFiberScheduler, "io_write", rb_fiber_scheduler_io_write, 4); + rb_define_method(rb_cFiberScheduler, "kernel_sleep", rb_fiber_scheduler_kernel_sleep, 1); + rb_define_method(rb_cFiberScheduler, "address_resolve", rb_fiber_scheduler_address_resolve, 1); + rb_define_method(rb_cFiberScheduler, "timeout_after", rb_fiber_scheduler_timeout_after, 3); + rb_define_method(rb_cFiberScheduler, "block", rb_fiber_scheduler_block, 2); + rb_define_method(rb_cFiberScheduler, "unblock", rb_fiber_scheduler_unblock, 2); + rb_define_method(rb_cFiberScheduler, "fiber", rb_fiber_scheduler, -2); +#endif } VALUE @@ -99,7 +170,10 @@ rb_fiber_scheduler_set(VALUE scheduler) verify_interface(scheduler); } - // We invoke Scheduler#close when setting it to something else, to ensure the previous scheduler runs to completion before changing the scheduler. That way, we do not need to consider interactions, e.g., of a Fiber from the previous scheduler with the new scheduler. + // We invoke Scheduler#close when setting it to something else, to ensure + // the previous scheduler runs to completion before changing the scheduler. + // That way, we do not need to consider interactions, e.g., of a Fiber from + // the previous scheduler with the new scheduler. if (thread->scheduler != Qnil) { rb_fiber_scheduler_close(thread->scheduler); } @@ -133,6 +207,16 @@ VALUE rb_fiber_scheduler_current_for_thread(VALUE thread) return rb_fiber_scheduler_current_for_threadptr(rb_thread_ptr(thread)); } +/* + * + * Document-method: Fiber::Scheduler#close + * + * Called when the current thread exits. The scheduler is expected to implement this + * method in order to allow all waiting fibers to finalize their execution. + * + * The suggested pattern is to implement the main event loop in the #close method. + * + */ VALUE rb_fiber_scheduler_close(VALUE scheduler) { @@ -140,6 +224,12 @@ rb_fiber_scheduler_close(VALUE scheduler) VALUE result; + // The reason for calling `scheduler_close` before calling `close` is for + // legacy schedulers which implement `close` and expect the user to call + // it. Subsequently, that method would call `Fiber.set_scheduler(nil)` + // which should call `scheduler_close`. If it were to call `close`, it + // would create an infinite loop. + result = rb_check_funcall(scheduler, id_scheduler_close, 0, NULL); if (result != Qundef) return result; @@ -159,6 +249,17 @@ rb_fiber_scheduler_make_timeout(struct timeval *timeout) return Qnil; } +/* + * Document-method: Fiber::Scheduler#kernel_sleep + * call-seq: kernel_sleep(duration = nil) + * + * Invoked by Kernel#sleep and Mutex#sleep and is expected to provide + * an implementation of sleeping in a non-blocking way. Implementation might + * register the current fiber in some list of "which fiber wait until what + * moment", call Fiber.yield to pass control, and then in #close resume + * the fibers whose wait period has elapsed. + * + */ VALUE rb_fiber_scheduler_kernel_sleep(VALUE scheduler, VALUE timeout) { @@ -172,6 +273,34 @@ rb_fiber_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE * argv) } #if 0 +/* + * Document-method: Fiber::Scheduler#timeout_after + * call-seq: timeout_after(duration, exception_class, *exception_arguments, &block) -> result of block + * + * Invoked by Timeout.timeout to execute the given +block+ within the given + * +duration+. It can also be invoked directly by the scheduler or user code. + * + * Attempt to limit the execution time of a given +block+ to the given + * +duration+ if possible. When a non-blocking operation causes the +block+'s + * execution time to exceed the specified +duration+, that non-blocking + * operation should be interrupted by raising the specified +exception_class+ + * constructed with the given +exception_arguments+. + * + * General execution timeouts are often considered risky. This implementation + * will only interrupt non-blocking operations. This is by design because it's + * expected that non-blocking operations can fail for a variety of + * unpredictable reasons, so applications should already be robust in handling + * these conditions and by implication timeouts. + * + * However, as a result of this design, if the +block+ does not invoke any + * non-blocking operations, it will be impossible to interrupt it. If you + * desire to provide predictable points for timeouts, consider adding + * +sleep(0)+. + * + * If the block is executed successfully, its result will be returned. + * + * The exception will typically be raised using Fiber#raise. + */ VALUE rb_fiber_scheduler_timeout_after(VALUE scheduler, VALUE timeout, VALUE exception, VALUE message) { @@ -189,6 +318,24 @@ rb_fiber_scheduler_timeout_afterv(VALUE scheduler, int argc, VALUE * argv) } #endif +/* + * Document-method: Fiber::Scheduler#process_wait + * call-seq: process_wait(pid, flags) + * + * Invoked by Process::Status.wait in order to wait for a specified process. + * See that method description for arguments description. + * + * Suggested minimal implementation: + * + * Thread.new do + * Process::Status.wait(pid, flags) + * end.value + * + * This hook is optional: if it is not present in the current scheduler, + * Process::Status.wait will behave as a blocking method. + * + * Expected to return a Process::Status instance. + */ VALUE rb_fiber_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags) { @@ -199,12 +346,39 @@ rb_fiber_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags) return rb_check_funcall(scheduler, id_process_wait, 2, arguments); } +/* + * Document-method: Fiber::Scheduler#block + * call-seq: block(blocker, timeout = nil) + * + * Invoked by methods like Thread.join, and by Mutex, to signify that current + * Fiber is blocked until further notice (e.g. #unblock) or until +timeout+ has + * elapsed. + * + * +blocker+ is what we are waiting on, informational only (for debugging and + * logging). There are no guarantee about its value. + * + * Expected to return boolean, specifying whether the blocking operation was + * successful or not. + */ VALUE rb_fiber_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout) { return rb_funcall(scheduler, id_block, 2, blocker, timeout); } +/* + * Document-method: Fiber::Scheduler#unblock + * call-seq: unblock(blocker, fiber) + * + * Invoked to wake up Fiber previously blocked with #block (for example, Mutex#lock + * calls #block and Mutex#unlock calls #unblock). The scheduler should use + * the +fiber+ parameter to understand which fiber is unblocked. + * + * +blocker+ is what was awaited for, but it is informational only (for debugging + * and logging), and it is not guaranteed to be the same value as the +blocker+ for + * #block. + * + */ VALUE rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber) { @@ -213,6 +387,25 @@ rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber) return rb_funcall(scheduler, id_unblock, 2, blocker, fiber); } +/* + * Document-method: Fiber::Scheduler#io_wait + * call-seq: io_wait(io, events, timeout) + * + * Invoked by IO#wait, IO#wait_readable, IO#wait_writable to ask whether the + * specified descriptor is ready for specified events within + * the specified +timeout+. + * + * +events+ is a bit mask of IO::READABLE, IO::WRITABLE, and + * IO::PRIORITY. + * + * Suggested implementation should register which Fiber is waiting for which + * resources and immediately calling Fiber.yield to pass control to other + * fibers. Then, in the #close method, the scheduler might dispatch all the + * I/O resources to fibers waiting for it. + * + * Expected to return the subset of events that are ready immediately. + * + */ VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout) { @@ -231,44 +424,127 @@ rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io) return rb_fiber_scheduler_io_wait(scheduler, io, RB_UINT2NUM(RUBY_IO_WRITABLE), rb_io_timeout(io)); } +/* + * Document-method: Fiber::Scheduler#io_select + * call-seq: io_select(readables, writables, exceptables, timeout) + * + * Invoked by IO.select to ask whether the specified descriptors are ready for + * specified events within the specified +timeout+. + * + * Expected to return the 3-tuple of Array of IOs that are ready. + * + */ +VALUE rb_fiber_scheduler_io_select(VALUE scheduler, VALUE readables, VALUE writables, VALUE exceptables, VALUE timeout) +{ + VALUE arguments[] = { + readables, writables, exceptables, timeout + }; + + return rb_fiber_scheduler_io_selectv(scheduler, 4, arguments); +} + +VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv) +{ + // I wondered about extracting argv, and checking if there is only a single + // IO instance, and instead calling `io_wait`. However, it would require a + // decent amount of work and it would be hard to preserve the exact + // semantics of IO.select. + + return rb_check_funcall(scheduler, id_io_select, argc, argv); +} + +/* + * Document-method: Fiber::Scheduler#io_read + * call-seq: io_read(io, buffer, length) -> read length or -errno + * + * Invoked by IO#read to read +length+ bytes from +io+ into a specified + * +buffer+ (see IO::Buffer). + * + * The +length+ argument is the "minimum length to be read". + * If the IO buffer size is 8KiB, but the +length+ is +1024+ (1KiB), up to + * 8KiB might be read, but at least 1KiB will be. + * Generally, the only case where less data than +length+ will be read is if + * there is an error reading the data. + * + * Specifying a +length+ of 0 is valid and means try reading at least once + * and return any available data. + * + * Suggested implementation should try to read from +io+ in a non-blocking + * manner and call #io_wait if the +io+ is not ready (which will yield control + * to other fibers). + * + * See IO::Buffer for an interface available to return data. + * + * Expected to return number of bytes read, or, in case of an error, -errno + * (negated number corresponding to system's error code). + * + * The method should be considered _experimental_. + */ VALUE -rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t length) +rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t length, size_t offset) { VALUE arguments[] = { - io, buffer, SIZET2NUM(length) + io, buffer, SIZET2NUM(length), SIZET2NUM(offset) }; - return rb_check_funcall(scheduler, id_io_read, 3, arguments); + return rb_check_funcall(scheduler, id_io_read, 4, arguments); } VALUE -rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, VALUE buffer, size_t length, rb_off_t offset) +rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset) { VALUE arguments[] = { - io, buffer, SIZET2NUM(length), OFFT2NUM(offset) + io, buffer, OFFT2NUM(from), SIZET2NUM(length), SIZET2NUM(offset) }; - return rb_check_funcall(scheduler, id_io_pread, 4, arguments); + return rb_check_funcall(scheduler, id_io_pread, 5, arguments); } +/* + * Document-method: Scheduler#io_write + * call-seq: io_write(io, buffer, length) -> written length or -errno + * + * Invoked by IO#write to write +length+ bytes to +io+ from + * from a specified +buffer+ (see IO::Buffer). + * + * The +length+ argument is the "(minimum) length to be written". + * If the IO buffer size is 8KiB, but the +length+ specified is 1024 (1KiB), + * at most 8KiB will be written, but at least 1KiB will be. + * Generally, the only case where less data than +length+ will be written is if + * there is an error writing the data. + * + * Specifying a +length+ of 0 is valid and means try writing at least once, + * as much data as possible. + * + * Suggested implementation should try to write to +io+ in a non-blocking + * manner and call #io_wait if the +io+ is not ready (which will yield control + * to other fibers). + * + * See IO::Buffer for an interface available to get data from buffer efficiently. + * + * Expected to return number of bytes written, or, in case of an error, -errno + * (negated number corresponding to system's error code). + * + * The method should be considered _experimental_. + */ VALUE -rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t length) +rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t length, size_t offset) { VALUE arguments[] = { - io, buffer, SIZET2NUM(length) + io, buffer, SIZET2NUM(length), SIZET2NUM(offset) }; - return rb_check_funcall(scheduler, id_io_write, 3, arguments); + return rb_check_funcall(scheduler, id_io_write, 4, arguments); } VALUE -rb_fiber_scheduler_io_pwrite(VALUE scheduler, VALUE io, VALUE buffer, size_t length, rb_off_t offset) +rb_fiber_scheduler_io_pwrite(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset) { VALUE arguments[] = { - io, buffer, SIZET2NUM(length), OFFT2NUM(offset) + io, buffer, OFFT2NUM(from), SIZET2NUM(length), SIZET2NUM(offset) }; - return rb_check_funcall(scheduler, id_io_pwrite, 4, arguments); + return rb_check_funcall(scheduler, id_io_pwrite, 5, arguments); } VALUE @@ -276,7 +552,7 @@ rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t { VALUE buffer = rb_io_buffer_new(base, size, RB_IO_BUFFER_LOCKED); - VALUE result = rb_fiber_scheduler_io_read(scheduler, io, buffer, length); + VALUE result = rb_fiber_scheduler_io_read(scheduler, io, buffer, length, 0); rb_io_buffer_unlock(buffer); rb_io_buffer_free(buffer); @@ -289,7 +565,7 @@ rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, { VALUE buffer = rb_io_buffer_new((void*)base, size, RB_IO_BUFFER_LOCKED|RB_IO_BUFFER_READONLY); - VALUE result = rb_fiber_scheduler_io_write(scheduler, io, buffer, length); + VALUE result = rb_fiber_scheduler_io_write(scheduler, io, buffer, length, 0); rb_io_buffer_unlock(buffer); rb_io_buffer_free(buffer); @@ -305,6 +581,38 @@ rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io) return rb_check_funcall(scheduler, id_io_close, 1, arguments); } +/* + * Document-method: Fiber::Scheduler#address_resolve + * call-seq: address_resolve(hostname) -> array_of_strings or nil + * + * Invoked by any method that performs a non-reverse DNS lookup. The most + * notable method is Addrinfo.getaddrinfo, but there are many other. + * + * The method is expected to return an array of strings corresponding to ip + * addresses the +hostname+ is resolved to, or +nil+ if it can not be resolved. + * + * Fairly exhaustive list of all possible call-sites: + * + * - Addrinfo.getaddrinfo + * - Addrinfo.tcp + * - Addrinfo.udp + * - Addrinfo.ip + * - Addrinfo.new + * - Addrinfo.marshal_load + * - SOCKSSocket.new + * - TCPServer.new + * - TCPSocket.new + * - IPSocket.getaddress + * - TCPSocket.gethostbyname + * - UDPSocket#connect + * - UDPSocket#bind + * - UDPSocket#send + * - Socket.getaddrinfo + * - Socket.gethostbyname + * - Socket.pack_sockaddr_in + * - Socket.sockaddr_in + * - Socket.unpack_sockaddr_in + */ VALUE rb_fiber_scheduler_address_resolve(VALUE scheduler, VALUE hostname) { @@ -314,3 +622,24 @@ rb_fiber_scheduler_address_resolve(VALUE scheduler, VALUE hostname) return rb_check_funcall(scheduler, id_address_resolve, 1, arguments); } + +/* + * Document-method: Fiber::Scheduler#fiber + * call-seq: fiber(&block) + * + * Implementation of the Fiber.schedule. The method is expected to immediately + * run the given block of code in a separate non-blocking fiber, and to return that Fiber. + * + * Minimal suggested implementation is: + * + * def fiber(&block) + * fiber = Fiber.new(blocking: false, &block) + * fiber.resume + * fiber + * end + */ +VALUE +rb_fiber_scheduler_fiber(VALUE scheduler, int argc, VALUE *argv, int kw_splat) +{ + return rb_funcall_passing_block_kw(scheduler, id_fiber_schedule, argc, argv, kw_splat); +} diff --git a/shape.c b/shape.c new file mode 100644 index 00000000000000..1b0f1a5dc9511c --- /dev/null +++ b/shape.c @@ -0,0 +1,555 @@ +#include "vm_core.h" +#include "vm_sync.h" +#include "shape.h" +#include "internal/class.h" +#include "internal/symbol.h" +#include "internal/variable.h" +#include + +/* + * Shape getters + */ +static rb_shape_t* +rb_shape_get_root_shape(void) +{ + return GET_VM()->root_shape; +} + +shape_id_t +rb_shape_id(rb_shape_t * shape) +{ + return (shape_id_t)(shape - GET_VM()->shape_list); +} + +static rb_shape_t* +rb_shape_get_frozen_root_shape(void) +{ + return GET_VM()->frozen_root_shape; +} + +bool +rb_shape_root_shape_p(rb_shape_t* shape) +{ + return shape == rb_shape_get_root_shape(); +} + +rb_shape_t* +rb_shape_get_shape_by_id(shape_id_t shape_id) +{ + RUBY_ASSERT(shape_id != INVALID_SHAPE_ID); + + rb_vm_t *vm = GET_VM(); + rb_shape_t *shape = &vm->shape_list[shape_id]; + return shape; +} + +rb_shape_t* +rb_shape_get_shape_by_id_without_assertion(shape_id_t shape_id) +{ + RUBY_ASSERT(shape_id != INVALID_SHAPE_ID); + + rb_vm_t *vm = GET_VM(); + rb_shape_t *shape = &vm->shape_list[shape_id]; + return shape; +} + +#if !SHAPE_IN_BASIC_FLAGS +static inline shape_id_t +RCLASS_SHAPE_ID(VALUE obj) +{ + return RCLASS_EXT(obj)->shape_id; +} + +shape_id_t rb_generic_shape_id(VALUE obj); +#endif + +shape_id_t +rb_shape_get_shape_id(VALUE obj) +{ + if (RB_SPECIAL_CONST_P(obj)) { + return FROZEN_ROOT_SHAPE_ID; + } + +#if SHAPE_IN_BASIC_FLAGS + return RBASIC_SHAPE_ID(obj); +#else + switch (BUILTIN_TYPE(obj)) { + case T_OBJECT: + return ROBJECT_SHAPE_ID(obj); + break; + case T_CLASS: + case T_MODULE: + return RCLASS_SHAPE_ID(obj); + default: + return rb_generic_shape_id(obj); + } +#endif +} + +rb_shape_t* +rb_shape_get_shape(VALUE obj) +{ + return rb_shape_get_shape_by_id(rb_shape_get_shape_id(obj)); +} + +static rb_shape_t * +rb_shape_lookup_id(rb_shape_t* shape, ID id, enum shape_type shape_type) +{ + while (shape->parent_id != INVALID_SHAPE_ID) { + if (shape->edge_name == id) { + // If the shape type is different, we don't + // want this to count as a "found" ID + if (shape_type == (enum shape_type)shape->type) { + return shape; + } + else { + return NULL; + } + } + shape = rb_shape_get_shape_by_id(shape->parent_id); + } + return NULL; +} + +static rb_shape_t* +get_next_shape_internal(rb_shape_t* shape, ID id, VALUE obj, enum shape_type shape_type) +{ + rb_shape_t *res = NULL; + RUBY_ASSERT(SHAPE_FROZEN != (enum shape_type)shape->type); + RB_VM_LOCK_ENTER(); + { + if (rb_shape_lookup_id(shape, id, shape_type)) { + // If shape already contains the ivar that is being set, we'll return shape + res = shape; + } + else { + if (!shape->edges) { + shape->edges = rb_id_table_create(0); + } + + // Lookup the shape in edges - if there's already an edge and a corresponding shape for it, + // we can return that. Otherwise, we'll need to get a new shape + if (!rb_id_table_lookup(shape->edges, id, (VALUE *)&res)) { + // In this case, the shape exists, but the shape is garbage, so we need to recreate it + if (res) { + rb_id_table_delete(shape->edges, id); + res->parent_id = INVALID_SHAPE_ID; + } + + rb_shape_t * new_shape = rb_shape_alloc(id, shape); + + new_shape->type = (uint8_t)shape_type; + + switch (shape_type) { + case SHAPE_IVAR: + new_shape->iv_count = rb_shape_get_shape_by_id(new_shape->parent_id)->iv_count + 1; + + // Check if we should update max_iv_count on the object's class + if (BUILTIN_TYPE(obj) == T_OBJECT) { + VALUE klass = rb_obj_class(obj); + if (new_shape->iv_count > RCLASS_EXT(klass)->max_iv_count) { + RCLASS_EXT(klass)->max_iv_count = new_shape->iv_count; + } + } + break; + case SHAPE_IVAR_UNDEF: + case SHAPE_FROZEN: + new_shape->iv_count = rb_shape_get_shape_by_id(new_shape->parent_id)->iv_count; + break; + case SHAPE_ROOT: + rb_bug("Unreachable"); + break; + } + + rb_id_table_insert(shape->edges, id, (VALUE)new_shape); + + res = new_shape; + } + } + } + RB_VM_LOCK_LEAVE(); + return res; +} + +MJIT_FUNC_EXPORTED int +rb_shape_frozen_shape_p(rb_shape_t* shape) +{ + return SHAPE_FROZEN == (enum shape_type)shape->type; +} + +void +rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape) +{ + rb_shape_t* next_shape = get_next_shape_internal(shape, id, obj, SHAPE_IVAR_UNDEF); + + if (shape == next_shape) { + return; + } + + rb_shape_set_shape(obj, next_shape); +} + +void +rb_shape_transition_shape_frozen(VALUE obj) +{ + rb_shape_t* shape = rb_shape_get_shape(obj); + RUBY_ASSERT(shape); + RUBY_ASSERT(RB_OBJ_FROZEN(obj)); + + if (rb_shape_frozen_shape_p(shape)) { + return; + } + + rb_shape_t* next_shape; + + if (shape == rb_shape_get_root_shape()) { + switch (BUILTIN_TYPE(obj)) { + case T_OBJECT: + case T_CLASS: + case T_MODULE: + break; + default: + return; + } + next_shape = rb_shape_get_frozen_root_shape(); + } + else { + static ID id_frozen; + if (!id_frozen) { + id_frozen = rb_make_internal_id(); + } + + next_shape = get_next_shape_internal(shape, (ID)id_frozen, obj, SHAPE_FROZEN); + } + + RUBY_ASSERT(next_shape); + rb_shape_set_shape(obj, next_shape); +} + +void +rb_shape_transition_shape(VALUE obj, ID id, rb_shape_t *shape) +{ + rb_shape_t* next_shape = rb_shape_get_next(shape, obj, id); + if (shape == next_shape) { + return; + } + rb_shape_set_shape(obj, next_shape); +} + +rb_shape_t* +rb_shape_get_next(rb_shape_t* shape, VALUE obj, ID id) +{ + return get_next_shape_internal(shape, id, obj, SHAPE_IVAR); +} + +bool +rb_shape_get_iv_index(rb_shape_t * shape, ID id, attr_index_t *value) +{ + while (shape->parent_id != INVALID_SHAPE_ID) { + if (shape->edge_name == id) { + enum shape_type shape_type; + shape_type = (enum shape_type)shape->type; + + switch (shape_type) { + case SHAPE_IVAR: + RUBY_ASSERT(shape->iv_count > 0); + *value = shape->iv_count - 1; + return true; + case SHAPE_IVAR_UNDEF: + case SHAPE_ROOT: + return false; + case SHAPE_FROZEN: + rb_bug("Ivar should not exist on frozen transition\n"); + } + } + shape = rb_shape_get_shape_by_id(shape->parent_id); + } + return false; +} + +static rb_shape_t * +shape_alloc(void) +{ + rb_vm_t *vm = GET_VM(); + shape_id_t shape_id = vm->next_shape_id; + vm->next_shape_id++; + + if (shape_id == MAX_SHAPE_ID) { + // TODO: Make an OutOfShapesError ?? + rb_bug("Out of shapes\n"); + } + + return &GET_VM()->shape_list[shape_id]; +} + +rb_shape_t * +rb_shape_alloc_with_parent_id(ID edge_name, shape_id_t parent_id) +{ + rb_shape_t * shape = shape_alloc(); + + shape->edge_name = edge_name; + shape->iv_count = 0; + shape->parent_id = parent_id; + + return shape; +} + +rb_shape_t * +rb_shape_alloc(ID edge_name, rb_shape_t * parent) +{ + return rb_shape_alloc_with_parent_id(edge_name, rb_shape_id(parent)); +} + +MJIT_FUNC_EXPORTED void +rb_shape_set_shape(VALUE obj, rb_shape_t* shape) +{ + rb_shape_set_shape_id(obj, rb_shape_id(shape)); +} + +VALUE +rb_shape_flags_mask(void) +{ + return SHAPE_FLAG_MASK; +} + +#if VM_CHECK_MODE > 0 +VALUE rb_cShape; + +/* + * Exposing Shape to Ruby via RubyVM.debug_shape + */ +static const rb_data_type_t shape_data_type = { + "Shape", + {NULL, NULL, NULL,}, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED +}; + +static VALUE +rb_wrapped_shape_id(VALUE self) +{ + rb_shape_t * shape; + TypedData_Get_Struct(self, rb_shape_t, &shape_data_type, shape); + return INT2NUM(rb_shape_id(shape)); +} + +static VALUE +rb_shape_type(VALUE self) +{ + rb_shape_t * shape; + TypedData_Get_Struct(self, rb_shape_t, &shape_data_type, shape); + return INT2NUM(shape->type); +} + +static VALUE +rb_shape_parent_id(VALUE self) +{ + rb_shape_t * shape; + TypedData_Get_Struct(self, rb_shape_t, &shape_data_type, shape); + if (shape->parent_id != INVALID_SHAPE_ID) { + return INT2NUM(shape->parent_id); + } + else { + return Qnil; + } +} + +static VALUE +parse_key(ID key) +{ + if ((key & RUBY_ID_INTERNAL) == RUBY_ID_INTERNAL) { + return LONG2NUM(key); + } + else { + return ID2SYM(key); + } +} + +static VALUE +rb_shape_t_to_rb_cShape(rb_shape_t *shape) +{ + union { const rb_shape_t *in; void *out; } deconst; + VALUE res; + deconst.in = shape; + res = TypedData_Wrap_Struct(rb_cShape, &shape_data_type, deconst.out); + + return res; +} + +static enum rb_id_table_iterator_result +rb_edges_to_hash(ID key, VALUE value, void *ref) +{ + rb_hash_aset(*(VALUE *)ref, parse_key(key), rb_shape_t_to_rb_cShape((rb_shape_t*)value)); + return ID_TABLE_CONTINUE; +} + +static VALUE +rb_shape_edges(VALUE self) +{ + rb_shape_t* shape; + TypedData_Get_Struct(self, rb_shape_t, &shape_data_type, shape); + + VALUE hash = rb_hash_new(); + + if (shape->edges) { + rb_id_table_foreach(shape->edges, rb_edges_to_hash, &hash); + } + + return hash; +} + +static VALUE +rb_shape_edge_name(VALUE self) +{ + rb_shape_t* shape; + TypedData_Get_Struct(self, rb_shape_t, &shape_data_type, shape); + + if (shape->edge_name) { + return ID2SYM(shape->edge_name); + } + else { + return Qnil; + } +} + +static VALUE +rb_shape_iv_count(VALUE self) +{ + rb_shape_t* shape; + TypedData_Get_Struct(self, rb_shape_t, &shape_data_type, shape); + + return INT2NUM(shape->iv_count); +} + +static VALUE +rb_shape_export_depth(VALUE self) +{ + rb_shape_t* shape; + TypedData_Get_Struct(self, rb_shape_t, &shape_data_type, shape); + + unsigned int depth = 0; + while (shape->parent_id != INVALID_SHAPE_ID) { + depth++; + shape = rb_shape_get_shape_by_id(shape->parent_id); + } + return INT2NUM(depth); +} + +static VALUE +rb_shape_parent(VALUE self) +{ + rb_shape_t * shape; + TypedData_Get_Struct(self, rb_shape_t, &shape_data_type, shape); + if (shape->parent_id != INVALID_SHAPE_ID) { + return rb_shape_t_to_rb_cShape(rb_shape_get_shape_by_id(shape->parent_id)); + } + else { + return Qnil; + } +} + +static VALUE +rb_shape_debug_shape(VALUE self, VALUE obj) +{ + return rb_shape_t_to_rb_cShape(rb_shape_get_shape(obj)); +} + +static VALUE +rb_shape_root_shape(VALUE self) +{ + return rb_shape_t_to_rb_cShape(rb_shape_get_root_shape()); +} + +static VALUE +rb_shape_frozen_root_shape(VALUE self) +{ + return rb_shape_t_to_rb_cShape(rb_shape_get_frozen_root_shape()); +} + +VALUE rb_obj_shape(rb_shape_t* shape); + +static enum rb_id_table_iterator_result collect_keys_and_values(ID key, VALUE value, void *ref) +{ + rb_hash_aset(*(VALUE *)ref, parse_key(key), rb_obj_shape((rb_shape_t*)value)); + return ID_TABLE_CONTINUE; +} + +static VALUE edges(struct rb_id_table* edges) +{ + VALUE hash = rb_hash_new(); + if (edges) + rb_id_table_foreach(edges, collect_keys_and_values, &hash); + return hash; +} + +VALUE +rb_obj_shape(rb_shape_t* shape) +{ + VALUE rb_shape = rb_hash_new(); + + rb_hash_aset(rb_shape, ID2SYM(rb_intern("id")), INT2NUM(rb_shape_id(shape))); + rb_hash_aset(rb_shape, ID2SYM(rb_intern("edges")), edges(shape->edges)); + + if (shape == rb_shape_get_root_shape()) { + rb_hash_aset(rb_shape, ID2SYM(rb_intern("parent_id")), INT2NUM(ROOT_SHAPE_ID)); + } + else { + rb_hash_aset(rb_shape, ID2SYM(rb_intern("parent_id")), INT2NUM(shape->parent_id)); + } + + rb_hash_aset(rb_shape, ID2SYM(rb_intern("edge_name")), rb_id2str(shape->edge_name)); + return rb_shape; +} + +static VALUE +shape_transition_tree(VALUE self) +{ + return rb_obj_shape(rb_shape_get_root_shape()); +} + +static VALUE +next_shape_id(VALUE self) +{ + return INT2NUM(GET_VM()->next_shape_id); +} + +static VALUE +rb_shape_find_by_id(VALUE mod, VALUE id) +{ + shape_id_t shape_id = NUM2UINT(id); + if (shape_id >= GET_VM()->next_shape_id) { + rb_raise(rb_eArgError, "Shape ID %d is out of bounds\n", shape_id); + } + return rb_shape_t_to_rb_cShape(rb_shape_get_shape_by_id(shape_id)); +} +#endif + +void +Init_shape(void) +{ +#if VM_CHECK_MODE > 0 + rb_cShape = rb_define_class_under(rb_cRubyVM, "Shape", rb_cObject); + rb_undef_alloc_func(rb_cShape); + + rb_define_method(rb_cShape, "parent_id", rb_shape_parent_id, 0); + rb_define_method(rb_cShape, "parent", rb_shape_parent, 0); + rb_define_method(rb_cShape, "edges", rb_shape_edges, 0); + rb_define_method(rb_cShape, "edge_name", rb_shape_edge_name, 0); + rb_define_method(rb_cShape, "iv_count", rb_shape_iv_count, 0); + rb_define_method(rb_cShape, "depth", rb_shape_export_depth, 0); + rb_define_method(rb_cShape, "id", rb_wrapped_shape_id, 0); + rb_define_method(rb_cShape, "type", rb_shape_type, 0); + rb_define_const(rb_cShape, "SHAPE_ROOT", INT2NUM(SHAPE_ROOT)); + rb_define_const(rb_cShape, "SHAPE_IVAR", INT2NUM(SHAPE_IVAR)); + rb_define_const(rb_cShape, "SHAPE_IVAR_UNDEF", INT2NUM(SHAPE_IVAR_UNDEF)); + rb_define_const(rb_cShape, "SHAPE_FROZEN", INT2NUM(SHAPE_FROZEN)); + rb_define_const(rb_cShape, "SHAPE_BITS", INT2NUM(SHAPE_BITS)); + rb_define_const(rb_cShape, "SHAPE_FLAG_SHIFT", INT2NUM(SHAPE_FLAG_SHIFT)); + + rb_define_singleton_method(rb_cShape, "transition_tree", shape_transition_tree, 0); + rb_define_singleton_method(rb_cShape, "find_by_id", rb_shape_find_by_id, 1); + rb_define_singleton_method(rb_cShape, "next_shape_id", next_shape_id, 0); + rb_define_singleton_method(rb_cShape, "of", rb_shape_debug_shape, 1); + rb_define_singleton_method(rb_cShape, "root_shape", rb_shape_root_shape, 0); + rb_define_singleton_method(rb_cShape, "frozen_root_shape", rb_shape_frozen_root_shape, 0); +#endif +} diff --git a/shape.h b/shape.h new file mode 100644 index 00000000000000..e978bac1213bc6 --- /dev/null +++ b/shape.h @@ -0,0 +1,145 @@ +#ifndef RUBY_SHAPE_H +#define RUBY_SHAPE_H +#if (SIZEOF_UINT64_T == SIZEOF_VALUE) +#define SIZEOF_SHAPE_T 4 +#define SHAPE_IN_BASIC_FLAGS 1 +typedef uint32_t attr_index_t; +#else +#define SIZEOF_SHAPE_T 2 +#define SHAPE_IN_BASIC_FLAGS 0 +typedef uint16_t attr_index_t; +#endif + +#define MAX_IVARS (attr_index_t)(-1) + +#if RUBY_DEBUG || (defined(VM_CHECK_MODE) && VM_CHECK_MODE > 0) +# if SIZEOF_SHAPE_T == 4 +typedef uint32_t shape_id_t; +# define SHAPE_BITS 16 +# else +typedef uint16_t shape_id_t; +# define SHAPE_BITS 16 +# endif +#else +# if SIZEOF_SHAPE_T == 4 +typedef uint32_t shape_id_t; +# define SHAPE_BITS 32 +# else +typedef uint16_t shape_id_t; +# define SHAPE_BITS 16 +# endif +#endif + +# define SHAPE_MASK (((uintptr_t)1 << SHAPE_BITS) - 1) +# define SHAPE_FLAG_MASK (((VALUE)-1) >> SHAPE_BITS) + +# define SHAPE_FLAG_SHIFT ((SIZEOF_VALUE * 8) - SHAPE_BITS) + +# define SHAPE_BITMAP_SIZE 16384 + +# define MAX_SHAPE_ID (SHAPE_MASK - 1) +# define INVALID_SHAPE_ID SHAPE_MASK +# define ROOT_SHAPE_ID 0x0 +# define FROZEN_ROOT_SHAPE_ID 0x1 + +struct rb_shape { + struct rb_id_table * edges; // id_table from ID (ivar) to next shape + ID edge_name; // ID (ivar) for transition from parent to rb_shape + attr_index_t iv_count; + uint8_t type; + shape_id_t parent_id; +}; + +typedef struct rb_shape rb_shape_t; + +enum shape_type { + SHAPE_ROOT, + SHAPE_IVAR, + SHAPE_FROZEN, + SHAPE_IVAR_UNDEF, +}; + +#if SHAPE_IN_BASIC_FLAGS +static inline shape_id_t +RBASIC_SHAPE_ID(VALUE obj) +{ + RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj)); + return (shape_id_t)(SHAPE_MASK & ((RBASIC(obj)->flags) >> SHAPE_FLAG_SHIFT)); +} + +static inline void +RBASIC_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id) +{ + // Ractors are occupying the upper 32 bits of flags, but only in debug mode + // Object shapes are occupying top bits + RBASIC(obj)->flags &= SHAPE_FLAG_MASK; + RBASIC(obj)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT); +} + +static inline shape_id_t +ROBJECT_SHAPE_ID(VALUE obj) +{ + RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); + return RBASIC_SHAPE_ID(obj); +} + +static inline void +ROBJECT_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id) +{ + RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); + RBASIC_SET_SHAPE_ID(obj, shape_id); +} + +#else + +static inline shape_id_t +ROBJECT_SHAPE_ID(VALUE obj) +{ + RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); + return (shape_id_t)(SHAPE_MASK & (RBASIC(obj)->flags >> SHAPE_FLAG_SHIFT)); +} + +static inline void +ROBJECT_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id) +{ + RBASIC(obj)->flags &= SHAPE_FLAG_MASK; + RBASIC(obj)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT); +} +#endif + +bool rb_shape_root_shape_p(rb_shape_t* shape); + +rb_shape_t* rb_shape_get_shape_by_id_without_assertion(shape_id_t shape_id); + +MJIT_SYMBOL_EXPORT_BEGIN +rb_shape_t* rb_shape_get_shape_by_id(shape_id_t shape_id); +void rb_shape_set_shape(VALUE obj, rb_shape_t* shape); +shape_id_t rb_shape_get_shape_id(VALUE obj); +rb_shape_t* rb_shape_get_shape(VALUE obj); +int rb_shape_frozen_shape_p(rb_shape_t* shape); +void rb_shape_transition_shape_frozen(VALUE obj); +void rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape); +void rb_shape_transition_shape(VALUE obj, ID id, rb_shape_t *shape); +rb_shape_t* rb_shape_get_next(rb_shape_t* shape, VALUE obj, ID id); +bool rb_shape_get_iv_index(rb_shape_t * shape, ID id, attr_index_t * value); +shape_id_t rb_shape_id(rb_shape_t * shape); +MJIT_SYMBOL_EXPORT_END + +static inline uint32_t +ROBJECT_IV_COUNT(VALUE obj) +{ + RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); + uint32_t ivc = rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj))->iv_count; + RUBY_ASSERT(ivc <= ROBJECT_NUMIV(obj)); + return ivc; +} + +rb_shape_t * rb_shape_alloc(ID edge_name, rb_shape_t * parent); +rb_shape_t * rb_shape_alloc_with_parent_id(ID edge_name, shape_id_t parent_id); + +bool rb_shape_set_shape_id(VALUE obj, shape_id_t shape_id); + +VALUE rb_obj_debug_shape(VALUE self, VALUE obj); +VALUE rb_shape_flags_mask(void); + +#endif diff --git a/spec/bundler/bundler/dep_proxy_spec.rb b/spec/bundler/bundler/dep_proxy_spec.rb deleted file mode 100644 index 8d02a337250d3b..00000000000000 --- a/spec/bundler/bundler/dep_proxy_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe Bundler::DepProxy do - let(:dep) { Bundler::Dependency.new("rake", ">= 0") } - subject { described_class.get_proxy(dep, Gem::Platform::RUBY) } - let(:same) { subject } - let(:other) { described_class.get_proxy(dep, Gem::Platform::RUBY) } - let(:different) { described_class.get_proxy(dep, Gem::Platform::JAVA) } - - describe "#eql?" do - it { expect(subject.eql?(same)).to be true } - it { expect(subject.eql?(other)).to be true } - it { expect(subject.eql?(different)).to be false } - it { expect(subject.eql?(nil)).to be false } - it { expect(subject.eql?("foobar")).to be false } - end - - describe "must use factory methods" do - it { expect { described_class.new(dep, Gem::Platform::RUBY) }.to raise_error NoMethodError } - it { expect { subject.dup }.to raise_error NoMethodError } - it { expect { subject.clone }.to raise_error NoMethodError } - end - - describe "frozen" do - if Gem.ruby_version >= Gem::Version.new("2.5.0") - error = Object.const_get("FrozenError") - else - error = RuntimeError - end - it { expect { subject.instance_variable_set(:@__platform, {}) }.to raise_error error } - end -end diff --git a/spec/bundler/bundler/gem_version_promoter_spec.rb b/spec/bundler/bundler/gem_version_promoter_spec.rb index 99e008bfbc9b65..54c559c1d8591e 100644 --- a/spec/bundler/bundler/gem_version_promoter_spec.rb +++ b/spec/bundler/bundler/gem_version_promoter_spec.rb @@ -28,7 +28,7 @@ def keep_locked(options) def build_spec_groups(name, versions) versions.map do |v| - Bundler::Resolver::SpecGroup.create_for({ Gem::Platform::RUBY => build_spec(name, v) }, [Gem::Platform::RUBY], Gem::Platform::RUBY) + Bundler::Resolver::SpecGroup.new(build_spec(name, v), [Gem::Platform::RUBY]) end end diff --git a/spec/bundler/bundler/remote_specification_spec.rb b/spec/bundler/bundler/remote_specification_spec.rb index 8115e026d8f588..921a47a2d3b849 100644 --- a/spec/bundler/bundler/remote_specification_spec.rb +++ b/spec/bundler/bundler/remote_specification_spec.rb @@ -45,7 +45,7 @@ let(:platform) { "jruby" } it "should return the spec name, version, and platform" do - expect(subject.full_name).to eq("foo-1.0.0-jruby") + expect(subject.full_name).to eq("foo-1.0.0-java") end end end diff --git a/spec/bundler/install/gems/resolving_spec.rb b/spec/bundler/install/gems/resolving_spec.rb index 9f4da23162671f..7a5307720f227c 100644 --- a/spec/bundler/install/gems/resolving_spec.rb +++ b/spec/bundler/install/gems/resolving_spec.rb @@ -187,7 +187,7 @@ bundle :install, :env => { "DEBUG_RESOLVER_TREE" => "1", "DEBUG" => "1" } - activated_groups = "net_b (1.0) (ruby), net_b (1.0) (#{specific_local_platform})" + activated_groups = "net_b (1.0) (ruby)" expect(out).to include(" net_b"). and include("BUNDLER: Starting resolution"). @@ -305,7 +305,7 @@ end end - context "in a transitive dependencies in a lockfile" do + context "with transitive dependencies in a lockfile" do before do build_repo2 do build_gem "rubocop", "1.28.2" do |s| diff --git a/spec/bundler/install/yanked_spec.rb b/spec/bundler/install/yanked_spec.rb index 09a5ba0be1fa60..78b701e4887c49 100644 --- a/spec/bundler/install/yanked_spec.rb +++ b/spec/bundler/install/yanked_spec.rb @@ -30,6 +30,72 @@ expect(err).to include("Your bundle is locked to foo (10.0.0)") end + context "when a re-resolve is necessary, and a yanked version is considered by the resolver" do + before do + skip "Materialization on Windows is not yet strict, so the example does not detect the gem has been yanked" if Gem.win_platform? + + build_repo4 do + build_gem "foo", "1.0.0", "1.0.1" + build_gem "actiontext", "6.1.7" do |s| + s.add_dependency "nokogiri", ">= 1.8" + end + build_gem "actiontext", "6.1.6" do |s| + s.add_dependency "nokogiri", ">= 1.8" + end + build_gem "actiontext", "6.1.7" do |s| + s.add_dependency "nokogiri", ">= 1.8" + end + build_gem "nokogiri", "1.13.8" + end + + gemfile <<~G + source "#{source_uri}" + gem "foo", "1.0.1" + gem "actiontext", "6.1.6" + G + + lockfile <<~L + GEM + remote: #{source_uri}/ + specs: + actiontext (6.1.6) + nokogiri (>= 1.8) + foo (1.0.0) + nokogiri (1.13.8-#{Bundler.local_platform}) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + actiontext (= 6.1.6) + foo (= 1.0.0) + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + context "and the old index is used" do + let(:source_uri) { file_uri_for(gem_repo4) } + + it "reports the yanked gem properly" do + bundle "install", :raise_on_error => false + + expect(err).to include("Your bundle is locked to nokogiri (1.13.8-#{Bundler.local_platform})") + end + end + + context "and the compact index API is used" do + let(:source_uri) { "https://gem.repo4" } + + it "reports the yanked gem properly" do + bundle "install", :artifice => "compact_index", :raise_on_error => false + + expect(err).to include("Your bundle is locked to nokogiri (1.13.8-#{Bundler.local_platform})") + end + end + end + it "throws the original error when only the Gemfile specifies a gem version that doesn't exist" do bundle "config set force_ruby_platform true" diff --git a/spec/bundler/realworld/slow_perf_spec.rb b/spec/bundler/realworld/slow_perf_spec.rb index 9f11821bf58f08..3ef537be0a5071 100644 --- a/spec/bundler/realworld/slow_perf_spec.rb +++ b/spec/bundler/realworld/slow_perf_spec.rb @@ -11,12 +11,23 @@ gem "mongoid", ">= 0.10.2" G - start_time = Time.now + expect { bundle "lock" }.to take_less_than(18) # seconds + end + + it "resolves quickly (case 2)" do + gemfile <<-G + source "https://rubygems.org" - bundle "lock" + gem 'metasploit-erd' + gem 'rails-erd' + gem 'yard' - duration = Time.now - start_time + gem 'coveralls' + gem 'rails' + gem 'simplecov' + gem 'rspec-rails' + G - expect(duration.to_f).to be < 18 # seconds + expect { bundle "lock" }.to take_less_than(18) # seconds end end diff --git a/spec/bundler/resolver/basic_spec.rb b/spec/bundler/resolver/basic_spec.rb index ee62dc3577aba8..b583fb871501ef 100644 --- a/spec/bundler/resolver/basic_spec.rb +++ b/spec/bundler/resolver/basic_spec.rb @@ -174,12 +174,7 @@ dep "foo" dep "Ruby\0", "1.8.7" - deps = [] - @deps.each do |d| - deps << Bundler::DepProxy.get_proxy(d, "ruby") - end - - should_resolve_and_include %w[foo-1.0.0 bar-1.0.0], [[]] + should_resolve_and_include %w[foo-1.0.0 bar-1.0.0] end context "conservative" do diff --git a/spec/bundler/support/indexes.rb b/spec/bundler/support/indexes.rb index c496679ee63562..e20059429c5ee1 100644 --- a/spec/bundler/support/indexes.rb +++ b/spec/bundler/support/indexes.rb @@ -16,21 +16,17 @@ def platform(*args) def resolve(args = []) @platforms ||= ["ruby"] - deps = [] default_source = instance_double("Bundler::Source::Rubygems", :specs => @index, :to_s => "locally install gems") source_requirements = { :default => default_source } @deps.each do |d| source_requirements[d.name] = d.source = default_source - @platforms.each do |p| - deps << Bundler::DepProxy.get_proxy(d, p) - end end - args[0] ||= [] # base + args[0] ||= Bundler::SpecSet.new([]) # base args[0].each {|ls| ls.source = default_source } args[1] ||= Bundler::GemVersionPromoter.new # gem_version_promoter args[2] ||= [] # additional_base_requirements args[3] ||= @platforms # platforms - Bundler::Resolver.resolve(deps, source_requirements, *args) + Bundler::Resolver.new(source_requirements, *args).start(@deps) end def should_not_resolve diff --git a/spec/bundler/support/matchers.rb b/spec/bundler/support/matchers.rb index ce6b2166191e9f..8b22e7dbc3dbff 100644 --- a/spec/bundler/support/matchers.rb +++ b/spec/bundler/support/matchers.rb @@ -97,6 +97,18 @@ def self.define_compound_matcher(matcher, preconditions, &declarations) end end + RSpec::Matchers.define :take_less_than do |seconds| + match do |actual| + start_time = Time.now + + actual.call + + (Time.now - start_time).to_f < seconds + end + + supports_block_expectations + end + define_compound_matcher :read_as, [exist] do |file_contents| diffable diff --git a/spec/ruby/core/process/times_spec.rb b/spec/ruby/core/process/times_spec.rb index b47189a7e7f4d1..d114061eb67d2c 100644 --- a/spec/ruby/core/process/times_spec.rb +++ b/spec/ruby/core/process/times_spec.rb @@ -5,12 +5,16 @@ Process.times.should be_kind_of(Process::Tms) end - it "returns current cpu times" do - t = Process.times - user = t.utime + # TODO: Intel C Compiler does not work this example + # http://rubyci.s3.amazonaws.com/icc-x64/ruby-master/log/20221013T030005Z.fail.html.gz + unless RbConfig::CONFIG['CC'].include?("icx") + it "returns current cpu times" do + t = Process.times + user = t.utime - 1 until Process.times.utime > user - Process.times.utime.should > user + 1 until Process.times.utime > user + Process.times.utime.should > user + end end platform_is_not :windows do diff --git a/spec/ruby/shared/queue/deque.rb b/spec/ruby/shared/queue/deque.rb index ed32bd29c88b61..616e56ec8a1a37 100644 --- a/spec/ruby/shared/queue/deque.rb +++ b/spec/ruby/shared/queue/deque.rb @@ -87,6 +87,13 @@ t.join end + it "immediately returns nil if no item is available and the timeout is 0" do + q = @object.call + q << 1 + q.send(@method, timeout: 0).should == 1 + q.send(@method, timeout: 0).should == nil + end + it "raise TypeError if timeout is not a valid numeric" do q = @object.call -> { q.send(@method, timeout: "1") }.should raise_error( diff --git a/spec/ruby/shared/sizedqueue/enque.rb b/spec/ruby/shared/sizedqueue/enque.rb index 126470594a43c4..059f1025a75b90 100644 --- a/spec/ruby/shared/sizedqueue/enque.rb +++ b/spec/ruby/shared/sizedqueue/enque.rb @@ -73,7 +73,13 @@ t.join end - it "returns nil if no item is available in time" do + it "returns nil if no space is avialable and timeout is 0" do + q = @object.call(1) + q.send(@method, 1, timeout: 0).should == q + q.send(@method, 2, timeout: 0).should == nil + end + + it "returns nil if no space is available in time" do q = @object.call(1) q << 1 t = Thread.new { diff --git a/symbol.c b/symbol.c index 6aceab72c1434d..adcc1275e3e30c 100644 --- a/symbol.c +++ b/symbol.c @@ -1112,6 +1112,28 @@ rb_check_id(volatile VALUE *namep) return lookup_str_id(name); } +// Used by yjit for handling .send without throwing exceptions +ID +rb_get_symbol_id(VALUE name) +{ + if (STATIC_SYM_P(name)) { + return STATIC_SYM2ID(name); + } + else if (DYNAMIC_SYM_P(name)) { + if (SYMBOL_PINNED_P(name)) { + return RSYMBOL(name)->id; + } + else { + return 0; + } + } + else { + RUBY_ASSERT_ALWAYS(RB_TYPE_P(name, T_STRING)); + return lookup_str_id(name); + } +} + + VALUE rb_check_symbol(volatile VALUE *namep) { diff --git a/test/-ext-/marshal/test_internal_ivar.rb b/test/-ext-/marshal/test_internal_ivar.rb index a32138f6e8f50d..9359c7f11320c3 100644 --- a/test/-ext-/marshal/test_internal_ivar.rb +++ b/test/-ext-/marshal/test_internal_ivar.rb @@ -7,6 +7,7 @@ module Bug end module Bug::Marshal class TestInternalIVar < Test::Unit::TestCase def test_marshal + pend "We don't support IVs with ID of 0" v = InternalIVar.new("hello", "world", "bye") assert_equal("hello", v.normal) assert_equal("world", v.internal) diff --git a/test/coverage/test_coverage.rb b/test/coverage/test_coverage.rb index 211faa0cbc215e..1a21235d0a983d 100644 --- a/test/coverage/test_coverage.rb +++ b/test/coverage/test_coverage.rb @@ -207,19 +207,19 @@ def test_coverage_optimized_branch def test_coverage_ensure_if_return result = { :branches => { - [:if, 0, 3, 1, 6, 4] => { - [:then, 1, 3, 6, 3, 6] => 0, - [:else, 2, 5, 3, 5, 9] => 1, - }, + [:if, 0, 3, 2, 6, 5] => { + [:then, 1, 3, 7, 3, 7] => 0, + [:else, 2, 5, 4, 5, 10] => 1, + }, }, } assert_coverage(<<~"end;", { branches: true }, result) def flush ensure - if $! - else - return - end + if $! + else + return + end end flush end; diff --git a/test/fiber/scheduler.rb b/test/fiber/scheduler.rb index 96b22856d1a3d5..3fd41ef6f161c5 100644 --- a/test/fiber/scheduler.rb +++ b/test/fiber/scheduler.rb @@ -197,6 +197,13 @@ def io_wait(io, events, duration) @writable.delete(io) end + def io_select(...) + # Emulate the operation using a non-blocking thread: + Thread.new do + IO.select(...) + end.value + end + # Used for Kernel#sleep and Thread::Mutex#sleep def kernel_sleep(duration = nil) # $stderr.puts [__method__, duration, Fiber.current].inspect @@ -263,81 +270,66 @@ def address_resolve(hostname) end class IOBufferScheduler < Scheduler - EAGAIN = Errno::EAGAIN::Errno + EAGAIN = -Errno::EAGAIN::Errno - def io_read(io, buffer, length) - offset = 0 + def io_read(io, buffer, length, offset) + total = 0 + io.nonblock = true while true maximum_size = buffer.size - offset - result = blocking{io.read_nonblock(maximum_size, exception: false)} - - # blocking{pp read: maximum_size, result: result, length: length} + result = blocking{buffer.read(io, maximum_size, offset)} - case result - when :wait_readable + if result > 0 + total += result + offset += result + break if total >= length + elsif result == 0 + break + elsif result == EAGAIN if length > 0 self.io_wait(io, IO::READABLE, nil) else - return -EAGAIN + return result end - when :wait_writable - if length > 0 - self.io_wait(io, IO::WRITABLE, nil) - else - return -EAGAIN - end - else - break unless result - - buffer.set_string(result, offset) - - size = result.bytesize - offset += size - break if size >= length - length -= size + elsif result < 0 + return result end end - return offset + return total end - def io_write(io, buffer, length) - offset = 0 + def io_write(io, buffer, length, offset) + total = 0 + io.nonblock = true while true maximum_size = buffer.size - offset + result = blocking{buffer.write(io, maximum_size, offset)} - chunk = buffer.get_string(offset, maximum_size) - result = blocking{io.write_nonblock(chunk, exception: false)} - - # blocking{pp write: maximum_size, result: result, length: length} - - case result - when :wait_readable - if length > 0 - self.io_wait(io, IO::READABLE, nil) - else - return -EAGAIN - end - when :wait_writable + if result > 0 + total += result + offset += result + break if total >= length + elsif result == 0 + break + elsif result == EAGAIN if length > 0 self.io_wait(io, IO::WRITABLE, nil) else - return -EAGAIN + return result end - else - offset += result - break if result >= length - length -= result + elsif result < 0 + return result end end - return offset + return total end def blocking(&block) - Fiber.new(blocking: true, &block).resume + Fiber.blocking(&block) end end diff --git a/test/fiber/test_io.rb b/test/fiber/test_io.rb index 4252641cde14ef..821a169e44af72 100644 --- a/test/fiber/test_io.rb +++ b/test/fiber/test_io.rb @@ -172,4 +172,26 @@ def test_read_write_blocking assert_predicate(i, :closed?) assert_predicate(o, :closed?) end + + def test_io_select + omit "UNIXSocket is not defined!" unless defined?(UNIXSocket) + + UNIXSocket.pair do |r, w| + result = nil + + thread = Thread.new do + scheduler = Scheduler.new + Fiber.set_scheduler scheduler + + Fiber.schedule do + w.write("Hello World") + result = IO.select([r], [w]) + end + end + + thread.join + + assert_equal [[r], [w], []], result + end + end end diff --git a/test/fiber/test_scheduler.rb b/test/fiber/test_scheduler.rb index 1d5881e2334148..5a24bff04fe4be 100644 --- a/test/fiber/test_scheduler.rb +++ b/test/fiber/test_scheduler.rb @@ -36,6 +36,7 @@ def test_fiber_blocking assert fiber.blocking? end end + f.resume end def test_closed_at_thread_exit diff --git a/test/fiddle/helper.rb b/test/fiddle/helper.rb index 0ea3bf57f47073..e470f5a2764396 100644 --- a/test/fiddle/helper.rb +++ b/test/fiddle/helper.rb @@ -49,8 +49,14 @@ libm_so = libc_so else # glibc - libc_so = "libc.so.6" - libm_so = "libm.so.6" + case RUBY_PLATFORM + when /alpha-linux/, /ia64-linux/ + libc_so = "libc.so.6.1" + libm_so = "libm.so.6.1" + else + libc_so = "libc.so.6" + libm_so = "libm.so.6" + end end when /mingw/, /mswin/ require "rbconfig" diff --git a/test/fiddle/test_fiddle.rb b/test/fiddle/test_fiddle.rb index 8751d969203d35..2792897074dfb3 100644 --- a/test/fiddle/test_fiddle.rb +++ b/test/fiddle/test_fiddle.rb @@ -14,4 +14,38 @@ def test_windows_constant end end + def test_dlopen_linker_script_input_linux + omit("This is only for Linux") unless RUBY_PLATFORM.match?("linux") + if Dir.glob("/usr/lib/*/libncurses.so").empty? + omit("libncurses.so is needed") + end + # libncurses.so uses INPUT() on Debian GNU/Linux + # $ cat /usr/lib/x86_64-linux-gnu/libncurses.so + # INPUT(libncurses.so.6 -ltinfo) + handle = Fiddle.dlopen("libncurses.so") + begin + assert_equal("libncurses.so", + File.basename(handle.file_name, ".*")) + ensure + handle.close + end + end + + def test_dlopen_linker_script_group_linux + omit("This is only for Linux") unless RUBY_PLATFORM.match?("linux") + # libc.so uses GROUP() on Debian GNU/Linux + # $ cat /usr/lib/x86_64-linux-gnu/libc.so + # /* GNU ld script + # Use the shared library, but some functions are only in + # the static library, so try that secondarily. */ + # OUTPUT_FORMAT(elf64-x86-64) + # GROUP ( /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED ( /lib64/ld-linux-x86-64.so.2 ) ) + handle = Fiddle.dlopen("libc.so") + begin + assert_equal("libc.so", + File.basename(handle.file_name, ".*")) + ensure + handle.close + end + end end if defined?(Fiddle) diff --git a/test/irb/test_color.rb b/test/irb/test_color.rb index 8de03a5e8e509e..02c79e344376f4 100644 --- a/test/irb/test_color.rb +++ b/test/irb/test_color.rb @@ -140,26 +140,33 @@ def test_colorize_code end tests.each do |code, result| - if colorize_code_supported? - assert_equal_with_term(result, code, complete: true) - assert_equal_with_term(result, code, complete: false) + assert_equal_with_term(result, code, complete: true) + assert_equal_with_term(result, code, complete: false) - assert_equal_with_term(code, code, complete: true, tty: false) - assert_equal_with_term(code, code, complete: false, tty: false) + assert_equal_with_term(code, code, complete: true, tty: false) + assert_equal_with_term(code, code, complete: false, tty: false) - assert_equal_with_term(code, code, complete: true, colorable: false) + assert_equal_with_term(code, code, complete: true, colorable: false) - assert_equal_with_term(code, code, complete: false, colorable: false) + assert_equal_with_term(code, code, complete: false, colorable: false) - assert_equal_with_term(result, code, complete: true, tty: false, colorable: true) + assert_equal_with_term(result, code, complete: true, tty: false, colorable: true) - assert_equal_with_term(result, code, complete: false, tty: false, colorable: true) - else - assert_equal_with_term(code, code) - end + assert_equal_with_term(result, code, complete: false, tty: false, colorable: true) end end + def test_colorize_code_with_local_variables + code = "a /(b +1)/i" + result_without_lvars = "a #{RED}#{BOLD}/#{CLEAR}#{RED}(b +1)#{CLEAR}#{RED}#{BOLD}/i#{CLEAR}" + result_with_lvar = "a /(b #{BLUE}#{BOLD}+1#{CLEAR})/i" + result_with_lvars = "a /(b +#{BLUE}#{BOLD}1#{CLEAR})/i" + + assert_equal_with_term(result_without_lvars, code) + assert_equal_with_term(result_with_lvar, code, local_variables: ['a']) + assert_equal_with_term(result_with_lvars, code, local_variables: ['a', 'b']) + end + def test_colorize_code_complete_true unless complete_option_supported? pend '`complete: true` is the same as `complete: false` in Ruby 2.6-' @@ -186,26 +193,22 @@ def test_colorize_code_complete_false "'foo' + 'bar" => "#{RED}#{BOLD}'#{CLEAR}#{RED}foo#{CLEAR}#{RED}#{BOLD}'#{CLEAR} + #{RED}#{BOLD}'#{CLEAR}#{RED}bar#{CLEAR}", "('foo" => "(#{RED}#{BOLD}'#{CLEAR}#{RED}foo#{CLEAR}", }.each do |code, result| - if colorize_code_supported? - assert_equal_with_term(result, code, complete: false) + assert_equal_with_term(result, code, complete: false) - assert_equal_with_term(code, code, complete: false, tty: false) + assert_equal_with_term(code, code, complete: false, tty: false) - assert_equal_with_term(code, code, complete: false, colorable: false) + assert_equal_with_term(code, code, complete: false, colorable: false) - assert_equal_with_term(result, code, complete: false, tty: false, colorable: true) + assert_equal_with_term(result, code, complete: false, tty: false, colorable: true) - unless complete_option_supported? - assert_equal_with_term(result, code, complete: true) + unless complete_option_supported? + assert_equal_with_term(result, code, complete: true) - assert_equal_with_term(code, code, complete: true, tty: false) + assert_equal_with_term(code, code, complete: true, tty: false) - assert_equal_with_term(code, code, complete: true, colorable: false) + assert_equal_with_term(code, code, complete: true, colorable: false) - assert_equal_with_term(result, code, complete: true, tty: false, colorable: true) - end - else - assert_equal_with_term(code, code) + assert_equal_with_term(result, code, complete: true, tty: false, colorable: true) end end end @@ -232,11 +235,6 @@ def test_inspect_colorable private - # `#colorize_code` is supported only for Ruby 2.5+. It just returns the original code in 2.4-. - def colorize_code_supported? - Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.5.0') - end - # `complete: true` is the same as `complete: false` in Ruby 2.6- def complete_option_supported? Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7.0') diff --git a/test/irb/test_context.rb b/test/irb/test_context.rb index b3fc49e7e33c1b..998cdd8591d0f7 100644 --- a/test/irb/test_context.rb +++ b/test/irb/test_context.rb @@ -225,6 +225,16 @@ def test_assignment_expression end end + def test_assignment_expression_with_local_variable + input = TestInputMethod.new + irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) + code = "a /1;x=1#/" + refute(irb.assignment_expression?(code), "#{code}: should not be an assignment expression") + irb.context.workspace.binding.eval('a = 1') + assert(irb.assignment_expression?(code), "#{code}: should be an assignment expression") + refute(irb.assignment_expression?(""), "empty code should not be an assignment expression") + end + def test_echo_on_assignment input = TestInputMethod.new([ "a = 1\n", diff --git a/test/irb/test_ruby_lex.rb b/test/irb/test_ruby_lex.rb index 2c94a36a5d91d9..1388d0896204c8 100644 --- a/test/irb/test_ruby_lex.rb +++ b/test/irb/test_ruby_lex.rb @@ -34,13 +34,27 @@ def assert_indenting(lines, correct_space_count, add_new_line) ruby_lex.set_auto_indent(context) end - def assert_nesting_level(lines, expected) + def assert_nesting_level(lines, expected, local_variables: []) + ruby_lex = ruby_lex_for_lines(lines, local_variables: local_variables) + error_message = "Calculated the wrong number of nesting level for:\n #{lines.join("\n")}" + assert_equal(expected, ruby_lex.instance_variable_get(:@indent), error_message) + end + + def assert_code_block_open(lines, expected, local_variables: []) + ruby_lex = ruby_lex_for_lines(lines, local_variables: local_variables) + error_message = "Wrong result of code_block_open for:\n #{lines.join("\n")}" + assert_equal(expected, ruby_lex.instance_variable_get(:@code_block_open), error_message) + end + + def ruby_lex_for_lines(lines, local_variables: []) ruby_lex = RubyLex.new() io = proc{ lines.join("\n") } ruby_lex.set_input(io, io) - ruby_lex.lex - error_message = "Calculated the wrong number of nesting level for:\n #{lines.join("\n")}" - assert_equal(expected, ruby_lex.instance_variable_get(:@indent), error_message) + unless local_variables.empty? + context = OpenStruct.new(local_variables: local_variables) + end + ruby_lex.lex(context) + ruby_lex end def test_auto_indent @@ -170,6 +184,40 @@ def test_endless_range_at_end_of_line assert_dynamic_prompt(lines, expected_prompt_list) end + def test_heredoc_with_embexpr + input_with_prompt = [ + PromptRow.new('001:0:":* ', %q(< ', %q(])), + PromptRow.new('012:0: :* ', %q()), + ] + + lines = input_with_prompt.map(&:content) + expected_prompt_list = input_with_prompt.map(&:prompt) + assert_dynamic_prompt(lines, expected_prompt_list) + end + + def test_backtick_method + input_with_prompt = [ + PromptRow.new('001:0: :> ', %q(self.`(arg))), + PromptRow.new('002:0: :* ', %q()), + PromptRow.new('003:0: :> ', %q(def `(); end)), + PromptRow.new('004:0: :* ', %q()), + ] + + lines = input_with_prompt.map(&:content) + expected_prompt_list = input_with_prompt.map(&:prompt) + assert_dynamic_prompt(lines, expected_prompt_list) + end + def test_incomplete_coding_magic_comment input_with_correct_indents = [ Row.new(%q(#coding:u), nil, 0), @@ -480,6 +528,15 @@ def test_do_corresponding_to_loop end end + def test_local_variables_dependent_code + pend if RUBY_ENGINE == 'truffleruby' + lines = ["a /1#/ do", "2"] + assert_nesting_level(lines, 1) + assert_code_block_open(lines, true) + assert_nesting_level(lines, 0, local_variables: ['a']) + assert_code_block_open(lines, false, local_variables: ['a']) + end + def test_heredoc_with_indent input_with_correct_indents = [ Row.new(%q(<<~Q), 0, 0, 0), @@ -632,5 +689,13 @@ def test_unterminated_code assert_empty(error_tokens, 'Error tokens must be ignored if there is corresponding non-error token') end end + + def test_unterminated_heredoc_string_literal + ['< #{code} + => + [0, + ... + irb(main):002:0> + EOC + end + private def write_irbrc(content) File.open(@irbrc_file, 'w') do |f| f.write content diff --git a/test/open-uri/test_ssl.rb b/test/open-uri/test_ssl.rb index 2d6149e6543fc4..3f94cab40fe82f 100644 --- a/test/open-uri/test_ssl.rb +++ b/test/open-uri/test_ssl.rb @@ -92,38 +92,37 @@ def test_validation_noverify } end - def test_validation_ssl_version - with_https {|srv, dr, url| - setup_validation(srv, dr) - URI.open("#{url}/data", :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE, :ssl_version => :TLSv1_2) {|f| - assert_equal("200", f.status[0]) - assert_equal("ddd", f.read) + def test_validation_failure + unless /mswin|mingw/ =~ RUBY_PLATFORM + # on Windows, Errno::ECONNRESET will be raised, and it'll be eaten by + # WEBrick + log_tester = lambda {|server_log| + assert_equal(1, server_log.length) + assert_match(/ERROR OpenSSL::SSL::SSLError:/, server_log[0]) } + end + with_https(log_tester) {|srv, dr, url, server_thread, server_log| + setup_validation(srv, dr) + assert_raise(OpenSSL::SSL::SSLError) { URI.open("#{url}/data") {} } } end - def test_validate_bad_ssl_version_silently + def test_ssl_min_version with_https {|srv, dr, url| setup_validation(srv, dr) - URI.open("#{url}/data", :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE, :ssl_version => :TLS_no_such_version) {|f| + URI.open("#{url}/data", :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE, :ssl_min_version => :TLS1_2) {|f| assert_equal("200", f.status[0]) assert_equal("ddd", f.read) } } end - def test_validation_failure - unless /mswin|mingw/ =~ RUBY_PLATFORM - # on Windows, Errno::ECONNRESET will be raised, and it'll be eaten by - # WEBrick - log_tester = lambda {|server_log| - assert_equal(1, server_log.length) - assert_match(/ERROR OpenSSL::SSL::SSLError:/, server_log[0]) - } - end - with_https(log_tester) {|srv, dr, url, server_thread, server_log| + def test_bad_ssl_version + with_https(nil) {|srv, dr, url| setup_validation(srv, dr) - assert_raise(OpenSSL::SSL::SSLError) { URI.open("#{url}/data") {} } + assert_raise(ArgumentError) { + URI.open("#{url}/data", :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE, :ssl_min_version => :TLS_no_such_version) {} + } } end diff --git a/test/openssl/test_bn.rb b/test/openssl/test_bn.rb index 346602dada21ef..77af14091e3a55 100644 --- a/test/openssl/test_bn.rb +++ b/test/openssl/test_bn.rb @@ -174,6 +174,12 @@ def test_mod_sqr assert_equal(0, 59.to_bn.mod_sqr(59)) end + def test_mod_sqrt + assert_equal(3, 4.to_bn.mod_sqrt(5)) + assert_equal(0, 5.to_bn.mod_sqrt(5)) + assert_raise(OpenSSL::BNError) { 3.to_bn.mod_sqrt(5) } + end + def test_mod_inverse assert_equal(2, 3.to_bn.mod_inverse(5)) assert_raise(OpenSSL::BNError) { 3.to_bn.mod_inverse(6) } diff --git a/test/openssl/test_hmac.rb b/test/openssl/test_hmac.rb index 47cb3718dff547..3cb707448a5f37 100644 --- a/test/openssl/test_hmac.rb +++ b/test/openssl/test_hmac.rb @@ -21,7 +21,6 @@ def test_hmac end def test_dup - pend "HMAC#initialize_copy is currently broken on OpenSSL 3.0.0" if openssl?(3, 0, 0) h1 = OpenSSL::HMAC.new("KEY", "MD5") h1.update("DATA") h = h1.dup @@ -63,6 +62,14 @@ def test_singleton_methods b64digest = OpenSSL::HMAC.base64digest("MD5", key, "Hi There") assert_equal "kpRyejY4uxwT9I74FYv8nQ==", b64digest end + + def test_zero_length_key + # Empty string as the key + hexdigest = OpenSSL::HMAC.hexdigest("SHA256", "\0"*32, "test") + assert_equal "43b0cef99265f9e34c10ea9d3501926d27b39f57c6d674561d8ba236e7a819fb", hexdigest + hexdigest = OpenSSL::HMAC.hexdigest("SHA256", "", "test") + assert_equal "43b0cef99265f9e34c10ea9d3501926d27b39f57c6d674561d8ba236e7a819fb", hexdigest + end end end diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb index 726b7dbf7e6114..de6aa63e23b2c7 100644 --- a/test/openssl/test_pkey_dsa.rb +++ b/test/openssl/test_pkey_dsa.rb @@ -28,6 +28,25 @@ def test_new_break end end + def test_generate + # DSA.generate used to call DSA_generate_parameters_ex(), which adjusts the + # size of q according to the size of p + key1024 = OpenSSL::PKey::DSA.generate(1024) + assert_predicate key1024, :private? + assert_equal 1024, key1024.p.num_bits + assert_equal 160, key1024.q.num_bits + + key2048 = OpenSSL::PKey::DSA.generate(2048) + assert_equal 2048, key2048.p.num_bits + assert_equal 256, key2048.q.num_bits + + if ENV["OSSL_TEST_ALL"] == "1" # slow + key3072 = OpenSSL::PKey::DSA.generate(3072) + assert_equal 3072, key3072.p.num_bits + assert_equal 256, key3072.q.num_bits + end + end + def test_sign_verify dsa512 = Fixtures.pkey("dsa512") data = "Sign me!" diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb index ffe5a94e5b1b2a..9a4818de8ede49 100644 --- a/test/openssl/test_pkey_ec.rb +++ b/test/openssl/test_pkey_ec.rb @@ -61,8 +61,10 @@ def test_generate def test_generate_key ec = OpenSSL::PKey::EC.new("prime256v1") assert_equal false, ec.private? + assert_raise(OpenSSL::PKey::ECError) { ec.to_der } ec.generate_key! assert_equal true, ec.private? + assert_nothing_raised { ec.to_der } end if !openssl?(3, 0, 0) def test_marshal @@ -199,6 +201,29 @@ def test_ECPrivateKey assert_equal pem, p256.export end + def test_ECPrivateKey_with_parameters + p256 = Fixtures.pkey("p256") + + # The format used by "openssl ecparam -name prime256v1 -genkey -outform PEM" + # + # "EC PARAMETERS" block should be ignored if it is followed by an + # "EC PRIVATE KEY" block + in_pem = <<~EOF + -----BEGIN EC PARAMETERS----- + BggqhkjOPQMBBw== + -----END EC PARAMETERS----- + -----BEGIN EC PRIVATE KEY----- + MHcCAQEEIID49FDqcf1O1eO8saTgG70UbXQw9Fqwseliit2aWhH1oAoGCCqGSM49 + AwEHoUQDQgAEFglk2c+oVUIKQ64eZG9bhLNPWB7lSZ/ArK41eGy5wAzU/0G51Xtt + CeBUl+MahZtn9fO1JKdF4qJmS39dXnpENg== + -----END EC PRIVATE KEY----- + EOF + + key = OpenSSL::PKey::EC.new(in_pem) + assert_same_ec p256, key + assert_equal p256.to_der, key.to_der + end + def test_ECPrivateKey_encrypted p256 = Fixtures.pkey("p256") # key = abcdef diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb index 4bb39ed4a6411a..fa84b76f4b1c6d 100644 --- a/test/openssl/test_pkey_rsa.rb +++ b/test/openssl/test_pkey_rsa.rb @@ -108,6 +108,11 @@ def test_sign_verify_options salt_length: 20, mgf1_hash: "SHA1") # Defaults to PKCS #1 v1.5 padding => verification failure assert_equal false, key.verify("SHA256", sig_pss, data) + + # option type check + assert_raise_with_message(TypeError, /expected Hash/) { + key.sign("SHA256", data, ["x"]) + } end def test_sign_verify_raw diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb index 5679ae77d781d3..945cc7c48e7cc1 100644 --- a/test/openssl/test_ssl.rb +++ b/test/openssl/test_ssl.rb @@ -804,6 +804,54 @@ def socketpair end end + def test_keylog_cb + pend "Keylog callback is not supported" if !openssl?(1, 1, 1) || libressl? + + prefix = 'CLIENT_RANDOM' + context = OpenSSL::SSL::SSLContext.new + context.min_version = context.max_version = OpenSSL::SSL::TLS1_2_VERSION + + cb_called = false + context.keylog_cb = proc do |_sock, line| + cb_called = true + assert_equal(prefix, line.split.first) + end + + start_server do |port| + server_connect(port, context) do |ssl| + ssl.puts "abc" + assert_equal("abc\n", ssl.gets) + assert_equal(true, cb_called) + end + end + + if tls13_supported? + prefixes = [ + 'SERVER_HANDSHAKE_TRAFFIC_SECRET', + 'EXPORTER_SECRET', + 'SERVER_TRAFFIC_SECRET_0', + 'CLIENT_HANDSHAKE_TRAFFIC_SECRET', + 'CLIENT_TRAFFIC_SECRET_0', + ] + context = OpenSSL::SSL::SSLContext.new + context.min_version = context.max_version = OpenSSL::SSL::TLS1_3_VERSION + cb_called = false + context.keylog_cb = proc do |_sock, line| + cb_called = true + assert_not_nil(prefixes.delete(line.split.first)) + end + + start_server do |port| + server_connect(port, context) do |ssl| + ssl.puts "abc" + assert_equal("abc\n", ssl.gets) + assert_equal(true, cb_called) + end + assert_equal(0, prefixes.size) + end + end + end + def test_tlsext_hostname fooctx = OpenSSL::SSL::SSLContext.new fooctx.cert = @cli_cert @@ -1817,6 +1865,19 @@ def test_fileno sock2.close end + def test_export_keying_material + start_server do |port| + cli_ctx = OpenSSL::SSL::SSLContext.new + server_connect(port, cli_ctx) do |ssl| + assert_instance_of(String, ssl.export_keying_material('ttls keying material', 64)) + assert_operator(64, :==, ssl.export_keying_material('ttls keying material', 64).b.length) + assert_operator(8, :==, ssl.export_keying_material('ttls keying material', 8).b.length) + assert_operator(5, :==, ssl.export_keying_material('test', 5, 'context').b.length) + ssl.puts "abc"; ssl.gets # workaround to make tests work on windows + end + end + end + private def start_server_version(version, ctx_proc = nil, diff --git a/test/ruby/test_ast.rb b/test/ruby/test_ast.rb index b91880be6d8e96..aaf626e801f6b4 100644 --- a/test/ruby/test_ast.rb +++ b/test/ruby/test_ast.rb @@ -568,6 +568,7 @@ def test_e_option end def test_error_tolerant + verbose_bak, $VERBOSE = $VERBOSE, false node = RubyVM::AbstractSyntaxTree.parse(<<~STR, error_tolerant: true) class A def m @@ -579,6 +580,8 @@ def m assert_nil($!) assert_equal(:SCOPE, node.type) + ensure + $VERBOSE = verbose_bak end def test_error_tolerant_end_is_short_for_method_define @@ -965,7 +968,12 @@ def m end def assert_error_tolerant(src, expected) - node = RubyVM::AbstractSyntaxTree.parse(src, error_tolerant: true) + begin + verbose_bak, $VERBOSE = $VERBOSE, false + node = RubyVM::AbstractSyntaxTree.parse(src, error_tolerant: true) + ensure + $VERBOSE = verbose_bak + end assert_nil($!) str = "" PP.pp(node, str, 80) diff --git a/test/ruby/test_dir.rb b/test/ruby/test_dir.rb index 514c6e5921ed56..ebbed754457841 100644 --- a/test/ruby/test_dir.rb +++ b/test/ruby/test_dir.rb @@ -259,6 +259,20 @@ def test_glob_starts_with_brace end end + def test_glob_recursive_with_brace + Dir.chdir(@root) do + bug19042 = '[ruby-core:110220] [Bug #19042]' + %w"c/dir_a c/dir_b c/dir_b/dir".each do |d| + Dir.mkdir(d) + end + expected = %w"c/dir_a/file c/dir_b/dir/file" + expected.each do |f| + File.write(f, "") + end + assert_equal(expected, Dir.glob("**/{dir_a,dir_b/dir}/file"), bug19042) + end + end + def test_glob_order Dir.chdir(@root) do assert_equal(["#{@root}/a", "#{@root}/b"], Dir.glob("#{@root}/[ba]")) diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb index 0c8beb2f955c9a..6313e111791977 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -1441,6 +1441,16 @@ def test_dup_many End end + def test_dup_timeout + with_pipe do |r, w| + r.timeout = 0.1 + r2 = r.dup + assert_equal(0.1, r2.timeout) + ensure + r2&.close + end + end + def test_inspect with_pipe do |r, w| assert_match(/^#$/, r.inspect) diff --git a/test/ruby/test_io_buffer.rb b/test/ruby/test_io_buffer.rb index 88b0a0280ae3c6..95ed98e1f4d9a2 100644 --- a/test/ruby/test_io_buffer.rb +++ b/test/ruby/test_io_buffer.rb @@ -169,16 +169,26 @@ def test_slice assert_equal("Hello World", buffer.get_string(8, 11)) end - def test_slice_bounds + def test_slice_arguments + buffer = IO::Buffer.for("Hello World") + + slice = buffer.slice + assert_equal "Hello World", slice.get_string + + slice = buffer.slice(2) + assert_equal("llo World", slice.get_string) + end + + def test_slice_bounds_error buffer = IO::Buffer.new(128) assert_raise ArgumentError do buffer.slice(128, 10) end - # assert_raise RuntimeError do - # pp buffer.slice(-10, 10) - # end + assert_raise ArgumentError do + buffer.slice(-10, 10) + end end def test_locked @@ -351,7 +361,7 @@ def test_pread io.seek(0) buffer = IO::Buffer.new(128) - buffer.pread(io, 5, 6) + buffer.pread(io, 6, 5) assert_equal "World", buffer.get_string(0, 5) assert_equal 0, io.tell @@ -364,7 +374,7 @@ def test_pwrite buffer = IO::Buffer.new(128) buffer.set_string("World") - buffer.pwrite(io, 5, 6) + buffer.pwrite(io, 6, 5) assert_equal 0, io.tell diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb index b1eee7381a69d9..d2c7b6e1dd5c4c 100644 --- a/test/ruby/test_method.rb +++ b/test/ruby/test_method.rb @@ -1314,6 +1314,7 @@ def foo m2 = c2.instance_method(:foo) c1.class_exec do + remove_method :foo def foo [:bar2] end diff --git a/test/ruby/test_mjit.rb b/test/ruby/test_mjit.rb index e49195f7631c67..4c6cc6f39fdfd9 100644 --- a/test/ruby/test_mjit.rb +++ b/test/ruby/test_mjit.rb @@ -831,7 +831,7 @@ def test(obj, recursive: nil) end def test_inlined_exivar - assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "aaa", success_count: 3, recompile_count: 1, min_calls: 2) + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "aaa", success_count: 4, recompile_count: 2, min_calls: 2) begin; class Foo < Hash def initialize @@ -850,7 +850,7 @@ def bar end def test_inlined_undefined_ivar - assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "bbb", success_count: 3, min_calls: 3) + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "bbb", success_count: 2, min_calls: 2) begin; class Foo def initialize diff --git a/test/ruby/test_object.rb b/test/ruby/test_object.rb index 83208bbcdb5c64..a9d5d4b13e48d7 100644 --- a/test/ruby/test_object.rb +++ b/test/ruby/test_object.rb @@ -993,4 +993,13 @@ def test_clone_object_should_not_be_old end EOS end + + def test_frozen_inspect + obj = Object.new + obj.instance_variable_set(:@a, "a") + ins = obj.inspect + obj.freeze + + assert_equal(ins, obj.inspect) + end end diff --git a/test/ruby/test_shapes.rb b/test/ruby/test_shapes.rb new file mode 100644 index 00000000000000..0f947bcd479433 --- /dev/null +++ b/test/ruby/test_shapes.rb @@ -0,0 +1,207 @@ +# frozen_string_literal: false +require 'test/unit' + +# These test the functionality of object shapes +class TestShapes < Test::Unit::TestCase + class ShapeOrder + def initialize + @b = :b # 5 => 6 + end + + def set_b + @b = :b # 5 => 6 + end + + def set_c + @c = :c # 5 => 7 + end + end + + class Example + def initialize + @a = 1 + end + end + + class RemoveAndAdd + def add_foo + @foo = 1 + end + + def remove + remove_instance_variable(:@foo) + end + + def add_bar + @bar = 1 + end + end + + # RubyVM::Shape.of returns new instances of shape objects for + # each call. This helper method allows us to define equality for + # shapes + def assert_shape_equal(shape1, shape2) + assert_equal(shape1.id, shape2.id) + assert_equal(shape1.parent_id, shape2.parent_id) + assert_equal(shape1.depth, shape2.depth) + assert_equal(shape1.type, shape2.type) + end + + def refute_shape_equal(shape1, shape2) + refute_equal(shape1.id, shape2.id) + end + + def test_shape_order + bar = ShapeOrder.new # 0 => 1 + bar.set_c # 1 => 2 + bar.set_b # 2 => 2 + + foo = ShapeOrder.new # 0 => 1 + shape_id = RubyVM::Shape.of(foo).id + foo.set_b # should not transition + assert_equal shape_id, RubyVM::Shape.of(foo).id + end + + def test_iv_index + example = RemoveAndAdd.new + shape = RubyVM::Shape.of(example) + assert_equal 0, shape.iv_count + + example.add_foo # makes a transition + new_shape = RubyVM::Shape.of(example) + assert_equal([:@foo], example.instance_variables) + assert_equal(shape.id, new_shape.parent.id) + assert_equal(1, new_shape.iv_count) + + example.remove # makes a transition + remove_shape = RubyVM::Shape.of(example) + assert_equal([], example.instance_variables) + assert_equal(new_shape.id, remove_shape.parent.id) + assert_equal(1, remove_shape.iv_count) + + example.add_bar # makes a transition + bar_shape = RubyVM::Shape.of(example) + assert_equal([:@bar], example.instance_variables) + assert_equal(remove_shape.id, bar_shape.parent.id) + assert_equal(2, bar_shape.iv_count) + end + + def test_new_obj_has_root_shape + assert_shape_equal(RubyVM::Shape.root_shape, RubyVM::Shape.of(Object.new)) + end + + def test_frozen_new_obj_has_frozen_root_shape + assert_shape_equal( + RubyVM::Shape.frozen_root_shape, + RubyVM::Shape.of(Object.new.freeze) + ) + end + + def test_str_has_root_shape + assert_shape_equal(RubyVM::Shape.root_shape, RubyVM::Shape.of("")) + end + + def test_array_has_root_shape + assert_shape_equal(RubyVM::Shape.root_shape, RubyVM::Shape.of([])) + end + + def test_hash_has_root_shape + assert_shape_equal(RubyVM::Shape.root_shape, RubyVM::Shape.of({})) + end + + def test_true_has_frozen_root_shape + assert_shape_equal(RubyVM::Shape.frozen_root_shape, RubyVM::Shape.of(true)) + end + + def test_nil_has_frozen_root_shape + assert_shape_equal(RubyVM::Shape.frozen_root_shape, RubyVM::Shape.of(nil)) + end + + def test_basic_shape_transition + obj = Example.new + refute_equal(RubyVM::Shape.root_shape, RubyVM::Shape.of(obj)) + assert_shape_equal(RubyVM::Shape.root_shape.edges[:@a], RubyVM::Shape.of(obj)) + assert_equal(obj.instance_variable_get(:@a), 1) + end + + def test_different_objects_make_same_transition + obj = Example.new + obj2 = "" + obj2.instance_variable_set(:@a, 1) + assert_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2)) + end + + def test_duplicating_objects + obj = Example.new + obj2 = obj.dup + assert_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2)) + end + + def test_freezing_and_duplicating_object + obj = Object.new.freeze + obj2 = obj.dup + refute_predicate(obj2, :frozen?) + # dup'd objects shouldn't be frozen, and the shape should be the + # parent shape of the copied object + assert_equal(RubyVM::Shape.of(obj).parent.id, RubyVM::Shape.of(obj2).id) + end + + def test_freezing_and_duplicating_object_with_ivars + obj = Example.new.freeze + obj2 = obj.dup + refute_predicate(obj2, :frozen?) + refute_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2)) + assert_equal(obj2.instance_variable_get(:@a), 1) + end + + def test_freezing_and_duplicating_string_with_ivars + str = "str" + str.instance_variable_set(:@a, 1) + str.freeze + str2 = str.dup + refute_predicate(str2, :frozen?) + refute_equal(RubyVM::Shape.of(str).id, RubyVM::Shape.of(str2).id) + assert_equal(str2.instance_variable_get(:@a), 1) + end + + def test_freezing_and_cloning_objects + obj = Object.new.freeze + obj2 = obj.clone(freeze: true) + assert_predicate(obj2, :frozen?) + assert_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2)) + end + + def test_freezing_and_cloning_object_with_ivars + obj = Example.new.freeze + obj2 = obj.clone(freeze: true) + assert_predicate(obj2, :frozen?) + assert_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2)) + assert_equal(obj2.instance_variable_get(:@a), 1) + end + + def test_freezing_and_cloning_string + str = "str".freeze + str2 = str.clone(freeze: true) + assert_predicate(str2, :frozen?) + assert_shape_equal(RubyVM::Shape.of(str), RubyVM::Shape.of(str2)) + end + + def test_freezing_and_cloning_string_with_ivars + str = "str" + str.instance_variable_set(:@a, 1) + str.freeze + str2 = str.clone(freeze: true) + assert_predicate(str2, :frozen?) + assert_shape_equal(RubyVM::Shape.of(str), RubyVM::Shape.of(str2)) + assert_equal(str2.instance_variable_get(:@a), 1) + end + + def test_out_of_bounds_shape + assert_raise ArgumentError do + RubyVM::Shape.find_by_id(RubyVM::Shape.next_shape_id) + end + assert_raise ArgumentError do + RubyVM::Shape.find_by_id(-1) + end + end +end if defined?(RubyVM::Shape) diff --git a/test/rubygems/alternate_cert.pem b/test/rubygems/alternate_cert.pem index 54a34441b1ad28..55303190f5d81d 100644 --- a/test/rubygems/alternate_cert.pem +++ b/test/rubygems/alternate_cert.pem @@ -1,19 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDFjCCAf6gAwIBAgIBBDANBgkqhkiG9w0BAQUFADAtMRIwEAYDVQQDDAlhbHRl +MIIDFjCCAf6gAwIBAgIBBDANBgkqhkiG9w0BAQsFADAtMRIwEAYDVQQDDAlhbHRl cm5hdGUxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMCAXDTEyMDEwMTAwMDAwMFoY Dzk5OTkxMjMxMjM1OTU5WjAtMRIwEAYDVQQDDAlhbHRlcm5hdGUxFzAVBgoJkiaJ k/IsZAEZFgdleGFtcGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA -vZQipBa1xH3M9OonkrUYhGZeX9UHAcJhe6jJbUr/uHXkh1Tu2ERWNnblm85upqBf -jyZEnKer7uBcwwkkvmisVgC8uBECymsBxuEIw0rfiKYEnLu0B6SiWFYz3dYPS92b -BK7Vks2/kNyXUmLLGoZ3id2K0eK5C/AJ0j+p84OqPnVhylsjrZmXfIZrh7lkHhgC -IrzPefjE3pOloi/tz6fh2ktb0FYKQMfweT3Ba2TMeflG13PEOW80AD5w0THxDutG -G0zPNCDyDEoT7UU1a3B3RMHYuUxEk1GUEYWq9L6a6SMpZISWTSpCp0Ww1QB55PON -iCCn+o6vcIy46jI71dATAQIDAQABoz8wPTAcBgNVHREEFTATgRFhbHRlcm5hdGVA -ZXhhbXBsZTAdBgNVHQ4EFgQUyvn/FwcZnA7AkzPjmoooB4/tKgcwDQYJKoZIhvcN -AQEFBQADggEBAHilxCg0dmOn3hxPjWMf/tAvG/S25iAIZZPuWo71DSSsn/zPRWDZ -OkDNL7syJ7S2jjrWWCIyLxhj89ZI7Oyd3elOB2zd4RsDij1y9Gv0ZPqNoTp0Repk -aPtRRLEwk9j2C37Tv+qA2PnTLp8MA0DVkb1/yuSd03b2K/AZEHT8Jtf3WC3RqGSK -A1+M8CvPSSgPY7oveFFerpqAzfC4tlgyPZjSqBjZucEIlxBD2lA/3JQ8Ys8+0705 -j2jGMl5r1Y22nl0A0+cHGtPX3irtR8bcEAO+rpEfpHNF2APaYsCT7Frk1CtuAHYB -mEwqWPQKU5ZJOV4uu69Hw5Po2bfgyjKV+N8= +pebGm7NOnx+DtWG1xQsJBfTfwNlZvfzY61nlZccrhU6vx0AnYNiDZAG3J/gFQmYZ +9gJ98rzEwfLMCGq9R/TZM+lAEaLhzYZCu3X4QdhKxr1xZ/SFC+1f8KVuH4tLXORW +30DwayPhNxnrOvup4pWLiYuXUSZpV9CGMvPSUCW2odhMkBMKqaTTPjxoXJIcgacy +prkNgIq48cSvqWG/e/HrMRtkqvFbD5ta00uO1mlpajYYw1RRftEwktFo8vQgDBo9 +NT/EqoE72tffaDnLq6rQrVtw4Kr9fy775DjNAWXyiCBjnJgOQSXCGPsM/AEdFrh/ +LKQQv2M/M7WNevnEUgsEIwIDAQABoz8wPTAcBgNVHREEFTATgRFhbHRlcm5hdGVA +ZXhhbXBsZTAdBgNVHQ4EFgQUYPwS8g98+4Tq/8gcEK1iilkGXH4wDQYJKoZIhvcN +AQELBQADggEBABSKUFmTk53+yrVFT3TvX5iGgXudNdACQqcnknAg66Q8+wMA8WT1 +M2oZJIH4SWSKUGMYubpYuc53tTtMnR594LPidyNbxo8KXMYoNfEkZCk6hh0eKVdx +zPJSZ4fOQ4mKFCd7HrycOr4bxuGPTVQERYJ45vZnhvVJDIRMgshnQuivP3VBwXkQ +gKLTCh2ew2ZJgPi1dfqdNMMSw7k4OQtQVhwbAkHgwL1TUShAO9lHzxFHlQgssfR0 +f6c89eB035Vn9s21StjerTOlC9+v4hOO7QhvbsCcUs2wWiE1BWo1QqnVBCjGKyVE +fISkJd1Sn5j+Vx/NJ7EfZcOGGQMdxHC+c90= -----END CERTIFICATE----- diff --git a/test/rubygems/alternate_cert_32.pem b/test/rubygems/alternate_cert_32.pem index adeffda24aa2b2..e727189470e0da 100644 --- a/test/rubygems/alternate_cert_32.pem +++ b/test/rubygems/alternate_cert_32.pem @@ -1,19 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDFDCCAfygAwIBAgIBBTANBgkqhkiG9w0BAQUFADAtMRIwEAYDVQQDDAlhbHRl +MIIDFDCCAfygAwIBAgIBBTANBgkqhkiG9w0BAQsFADAtMRIwEAYDVQQDDAlhbHRl cm5hdGUxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMB4XDTEyMDEwMTAwMDAwMFoX DTM4MDExOTAzMTQwN1owLTESMBAGA1UEAwwJYWx0ZXJuYXRlMRcwFQYKCZImiZPy -LGQBGRYHZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL2U -IqQWtcR9zPTqJ5K1GIRmXl/VBwHCYXuoyW1K/7h15IdU7thEVjZ25ZvObqagX48m -RJynq+7gXMMJJL5orFYAvLgRAsprAcbhCMNK34imBJy7tAekolhWM93WD0vdmwSu -1ZLNv5Dcl1JiyxqGd4nditHiuQvwCdI/qfODqj51YcpbI62Zl3yGa4e5ZB4YAiK8 -z3n4xN6TpaIv7c+n4dpLW9BWCkDH8Hk9wWtkzHn5RtdzxDlvNAA+cNEx8Q7rRhtM -zzQg8gxKE+1FNWtwd0TB2LlMRJNRlBGFqvS+mukjKWSElk0qQqdFsNUAeeTzjYgg -p/qOr3CMuOoyO9XQEwECAwEAAaM/MD0wHAYDVR0RBBUwE4ERYWx0ZXJuYXRlQGV4 -YW1wbGUwHQYDVR0OBBYEFMr5/xcHGZwOwJMz45qKKAeP7SoHMA0GCSqGSIb3DQEB -BQUAA4IBAQA1Vs3lcPpqnbsdtFDgrzApZuNgtyCRbbSrshq37dem9wSI4aFjAPLx -QGgf3c+XZczK9FkR3VUHcK8yZFrCKpv9giZDvzCUOMB/HSBAzNiNbhgUC1S0THir -xFriDITPoY7mrdJlX41Ssqk6tIKZsYP63UVghy7f9wxqXJvyfJZSB9UeM+0baQVL -tGTKXmvzLw1Pc/LHTrt7jcZT9UbBsxNNy0Wk9FPPePCUUlegRjInd/sNevywzL/T -1DL0BefqF6iyWcu86Udo+eli1JDzeUsfHOL7oqJGlWhlZHRDJ1M89n5KwPg8SCx5 -TpemV2Wy0nRTzITnmggexlMibSJ0iOvC +LGQBGRYHZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKXm +xpuzTp8fg7VhtcULCQX038DZWb382OtZ5WXHK4VOr8dAJ2DYg2QBtyf4BUJmGfYC +ffK8xMHyzAhqvUf02TPpQBGi4c2GQrt1+EHYSsa9cWf0hQvtX/Clbh+LS1zkVt9A +8Gsj4TcZ6zr7qeKVi4mLl1EmaVfQhjLz0lAltqHYTJATCqmk0z48aFySHIGnMqa5 +DYCKuPHEr6lhv3vx6zEbZKrxWw+bWtNLjtZpaWo2GMNUUX7RMJLRaPL0IAwaPTU/ +xKqBO9rX32g5y6uq0K1bcOCq/X8u++Q4zQFl8oggY5yYDkElwhj7DPwBHRa4fyyk +EL9jPzO1jXr5xFILBCMCAwEAAaM/MD0wHAYDVR0RBBUwE4ERYWx0ZXJuYXRlQGV4 +YW1wbGUwHQYDVR0OBBYEFGD8EvIPfPuE6v/IHBCtYopZBlx+MA0GCSqGSIb3DQEB +CwUAA4IBAQBJeq9kniAdddOY2r9MhRYb8/rzWL1mcCgbIzkwXCTeOyVt0nWZZwAy +arEy8ofkXt1O3Bm+59+dPORnG5WJeBGVmGDHo9HxDjm4dgTramYqgtxbthmB/pu+ +QhJ5DQg59odomoRRG7dkqacd8GMdcJVYcb3OzV3Fe5v2gtvnVPZ711APtjZ7sZUR +4XBA+ok95QFeSUYo4WIOCHh16pPtZ9ium5SZ7ChVVNj5rthr+sS+rQKjEdjG510w +UOkg8rUjEvXPGjM80/DnOvzyRJvbcCWBWWHquft3wqbjTomnQtqHne2SwRFEyfpd +JLEuY9QtEUCUy7obccN39+nT9jUOyg3B -----END CERTIFICATE----- diff --git a/test/rubygems/alternate_key.pem b/test/rubygems/alternate_key.pem index 14ca734aba9fa8..ae587b34258050 100644 --- a/test/rubygems/alternate_key.pem +++ b/test/rubygems/alternate_key.pem @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/test/rubygems/child_cert.pem b/test/rubygems/child_cert.pem index 9293cfc966d320..26c916cf96ad64 100644 --- a/test/rubygems/child_cert.pem +++ b/test/rubygems/child_cert.pem @@ -1,20 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDTTCCAjWgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAqMQ8wDQYDVQQDDAZub2Jv +MIIDLDCCAhSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAqMQ8wDQYDVQQDDAZub2Jv ZHkxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMCAXDTEyMDEwMTAwMDAwMFoYDzk5 OTkxMjMxMjM1OTU5WjApMQ4wDAYDVQQDDAVjaGlsZDEXMBUGCgmSJomT8ixkARkW -B2V4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKf7+1q0cR -MhC/RM6Whpon/5IxuSve3CCxxdN0LcSbUisFMlf28Zj+S545SKFc6gHFcnYLZZsy -Gm4FWEd4DhNpg/kgoDPuPGwQp2DEOvKnnneB/Shj8V+6oLrjXaZFAu8Q916c5/BL -z+PlHIIsO/Q865XOK+5z1sZi0xval8QT7u4Usrcy86gevflCbpBAWkNPa/DZDqA9 -nk0vB2XDSHvhavcrYLfDrYAnFz3wiZ70LYQrmdeOqkPpaiw//Qpzqp+vtuF2br6U -iYWpN+dhdFsIxAwIE5kWZ1kk6OBJ4kHvr+Sh8Oqbf6WFBhW/lQa9wldA0xhNwhGr -1FDEfC+0g/BvAgMBAAGjfTB7MBgGA1UdEQQRMA+BDWNoaWxkQGV4YW1wbGUwHQYD -VR0OBBYEFHzVU9N7sklKBPrHElxoZ32Fg64IMB8GA1UdIwQYMBaAFF9DbvaajkUl -6SLjfTdepNU2AoUbMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMA0G -CSqGSIb3DQEBBQUAA4IBAQAKRUboW7dwIHuzOp+7Nbx+ltWLUgwMkDLjjXjJE1Tv -L+NNmAx2iv0WghyoKaUBYW+SgIcenQoMfIA+K8Z6a4dUruJ0TKsUgLW8sx3wx9h8 -NwjjybsUh8mN+7EtQ5HtkLKp4F1eOqb+eTIPpCPYP8GyzUGDcFG0pdzhcHvqOKOd -sRYzkxyf/f8DE+6P01F1EPTql8pZLLirOfZjUtboUY3gZr2JQ03RzTk3dcjEr4pI -wvQV8rAkj3GE638iBEByzQb/HHN+c9fLAM7f1IDcHS49jZj1gCiuCAVlf52zUmwd -NnBgKyVrEVhf02sDgXRpoTmoRfwmcMd2cWGvDmRiijHo +B2V4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCHyxiIjR9Z +m3tznMc8OqAvm5h14DAUin+2eq1HzjQZ1fxkTtP4i05ieppHLTxfJrM9mH5H6sb3 +NSNtX/L7p229tM3on8UPUZRp7qDmFNTpgdRbf03ZJFDp3MTprA85wq++gc7GMI6q +QHhLuc3gshuy4iFzVfrWE0MRF/aVkEiH91iNUCZ3vZTahDG/jTafyMYnADE+26mj +fK8yCoTA6qYnYQrMPy3jcr0g3aak5+z5Gn55qIJklaAXV7vAyoNgYIq6MjXs9J0f +kedZWwJTEfAarZDo2s9wEQi7McPzv4HmNB3H6JfJsAVgaD0WtQcAVr7Ngr24lIx4 +AMY7koGayD+VAgMBAAGjXDBaMBgGA1UdEQQRMA+BDWNoaWxkQGV4YW1wbGUwHQYD +VR0OBBYEFEVZPH+Sg200JF29GN4RJ13XfpIWMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgIEMA0GCSqGSIb3DQEBCwUAA4IBAQABo0B3iS7ykcIBRflUTQtd +ji60ZVsX+pseEvpFvlurdKR4vrhBu/5LImQxk3wMepEhyzXZbKBanWJjgZcfJBKA +XqWFAPu80WPunonxUpNdgKMouRBCmzmKwXojzafpZUKTZKEm7q8cbE7u1Eye8Ipv +uj41TMlIpGvJnjfGKugJh2Gu+5Sfl7P6h8nLvM5dkJW8WsRRMGc7vFEXKCvsZbth +wclhJXWciI4wsGUENTPpqxWhO2uj80/ob3rUNgIwROKeyBWXPUVKCme4AII5Cqk7 +qwQzNIRwWofBIb7TV2aICnFUHb3NHZEjMacviaMI+Nl5ND+gDAdc8YQmXrSHg1fW -----END CERTIFICATE----- diff --git a/test/rubygems/child_cert_32.pem b/test/rubygems/child_cert_32.pem index 3484803a2090ad..4e2fcf10df3f2c 100644 --- a/test/rubygems/child_cert_32.pem +++ b/test/rubygems/child_cert_32.pem @@ -1,20 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDSzCCAjOgAwIBAgIBAzANBgkqhkiG9w0BAQUFADAqMQ8wDQYDVQQDDAZub2Jv +MIIDKjCCAhKgAwIBAgIBAzANBgkqhkiG9w0BAQsFADAqMQ8wDQYDVQQDDAZub2Jv ZHkxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMB4XDTEyMDEwMTAwMDAwMFoXDTM4 MDExOTAzMTQwN1owKTEOMAwGA1UEAwwFY2hpbGQxFzAVBgoJkiaJk/IsZAEZFgdl -eGFtcGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyn+/tatHETIQ -v0TOloaaJ/+SMbkr3twgscXTdC3Em1IrBTJX9vGY/kueOUihXOoBxXJ2C2WbMhpu -BVhHeA4TaYP5IKAz7jxsEKdgxDryp553gf0oY/FfuqC6412mRQLvEPdenOfwS8/j -5RyCLDv0POuVzivuc9bGYtMb2pfEE+7uFLK3MvOoHr35Qm6QQFpDT2vw2Q6gPZ5N -Lwdlw0h74Wr3K2C3w62AJxc98Ime9C2EK5nXjqpD6WosP/0Kc6qfr7bhdm6+lImF -qTfnYXRbCMQMCBOZFmdZJOjgSeJB76/kofDqm3+lhQYVv5UGvcJXQNMYTcIRq9RQ -xHwvtIPwbwIDAQABo30wezAYBgNVHREEETAPgQ1jaGlsZEBleGFtcGxlMB0GA1Ud -DgQWBBR81VPTe7JJSgT6xxJcaGd9hYOuCDAfBgNVHSMEGDAWgBRfQ272mo5FJeki -4303XqTVNgKFGzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDANBgkq -hkiG9w0BAQUFAAOCAQEAhHnhcklUtCnLXVr4aCgdNgeuBMqT/v7cJFWGjy0s0isu -zsAHZ59caMGonykuZWwxQE2ytzMhz1fC1mRH5kfYy2h2uFHGzaexrK4n2BX0HIE+ -XFyZxDW5kwKrpmXrEeo6JVWftCoINrw3eY3iuQc3pKpLtGdir4MKByM90CcjHxzQ -RFvI9JzRY5TmY3nXdP3JNi4rNGZULEl+Hdm79LS6yrXthZQ4dqeMqJqXLggdVPf5 -5302z//0QKi+nK3UnTi5hbEOC9xUW2n5Yj2dJnSkD/aQFapobMaww8SbbOJ3IMK0 -hsI7EPoqOCw4egbv9SlvlVOQTPDqpZfSfT4Id0AnpA== +eGFtcGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAh8sYiI0fWZt7 +c5zHPDqgL5uYdeAwFIp/tnqtR840GdX8ZE7T+ItOYnqaRy08XyazPZh+R+rG9zUj +bV/y+6dtvbTN6J/FD1GUae6g5hTU6YHUW39N2SRQ6dzE6awPOcKvvoHOxjCOqkB4 +S7nN4LIbsuIhc1X61hNDERf2lZBIh/dYjVAmd72U2oQxv402n8jGJwAxPtupo3yv +MgqEwOqmJ2EKzD8t43K9IN2mpOfs+Rp+eaiCZJWgF1e7wMqDYGCKujI17PSdH5Hn +WVsCUxHwGq2Q6NrPcBEIuzHD87+B5jQdx+iXybAFYGg9FrUHAFa+zYK9uJSMeADG +O5KBmsg/lQIDAQABo1wwWjAYBgNVHREEETAPgQ1jaGlsZEBleGFtcGxlMB0GA1Ud +DgQWBBRFWTx/koNtNCRdvRjeESdd136SFjAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwICBDANBgkqhkiG9w0BAQsFAAOCAQEAR53288aEhg6x3zMHv0Y8ZSqB ++xPTrKzouqmHdaFBvEowIkfK6V29A2LAoIBi5DfsnkbKMGCD4mOlX3ipGoi7x2CZ +UspOfXQ93CdiG9laS4sr4f5ZUJR1sc083UT1PBwqtnajjVUPxYz9I8g2ZxxawmA/ +bybbft/l4xHDv7RUP56uzm/BoCyiUdEC9gvq+5NYS95+M7v2J/CsvV34d5xnb8cl +49zOoboN1JoZErPZ2dGnxpHvExOcQhz6CVUIEPri5eqRae+zln3RRd8RJ4gPe1FG +H2aDHUwX7NKxY5Xq2NT2vUmnhTmNzFT5HC9gjG8Zu+2dPw0tTZNxyuctSAhAgw== -----END CERTIFICATE----- diff --git a/test/rubygems/child_key.pem b/test/rubygems/child_key.pem index c56d0699c81f8b..61fdfb628e3ce0 100644 --- a/test/rubygems/child_key.pem +++ b/test/rubygems/child_key.pem @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/test/rubygems/encrypted_private_key.pem b/test/rubygems/encrypted_private_key.pem index d9667689a62992..2d0022a6c005f4 100644 --- a/test/rubygems/encrypted_private_key.pem +++ b/test/rubygems/encrypted_private_key.pem @@ -1,30 +1,30 @@ -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED -DEK-Info: AES-256-CBC,CB6FD0B173EF450C6EE21A01DD785C1D +DEK-Info: AES-256-CBC,4851D8D265711252BA5EAD983C957412 -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 -----END RSA PRIVATE KEY----- diff --git a/test/rubygems/expired_cert.pem b/test/rubygems/expired_cert.pem index c76fe4c58f9543..12b8836607861a 100644 --- a/test/rubygems/expired_cert.pem +++ b/test/rubygems/expired_cert.pem @@ -1,19 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDCzCCAfOgAwIBAgIBBjANBgkqhkiG9w0BAQUFADAqMQ8wDQYDVQQDDAZub2Jv +MIIDCzCCAfOgAwIBAgIBBjANBgkqhkiG9w0BAQsFADAqMQ8wDQYDVQQDDAZub2Jv ZHkxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMB4XDTcwMDEwMTAwMDAwMFoXDTcw MDEwMTAwMDAwMFowKjEPMA0GA1UEAwwGbm9ib2R5MRcwFQYKCZImiZPyLGQBGRYH -ZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKdlNYcvFB6x -gpT8QcnMybVelGLUKyQL/hQPTK9J5FyqB8hEDLt2ruMwKsHU6fu/mgG+sLvHF1nq -WhZADhn6rwCfNP03025vktOZ6iJfU60vytY/f3gkiGNkP21l0hz0+Ms15f+52gk+ -sFXqwGBbDteI0x57UsHi+KAN67QuPDnthYDtwhXIA5pcdx2wH+NW8F82HEZvm1hc -pA75BDVk4vPxnpDfvPOKSYn9dWghmUtaPmqyVvs8XkDxHDfY54/D3ziPehP+zQzE -g8C07Sq/z6vLSOQ3uaYn0nBDuNE6XP3ijJ4Zvs2eJEdOMyS1H3CsnkWiePCrLtKd -w8d/F+D5bocCAwEAAaM8MDowGQYDVR0RBBIwEIEObm9ib2R5QGV4YW1wbGUwHQYD -VR0OBBYEFF9DbvaajkUl6SLjfTdepNU2AoUbMA0GCSqGSIb3DQEBBQUAA4IBAQAP -Z8vKQ1OjQCHx8MJ0gy6WN2CIjh0Uqf3fSfza3nd+K8jlJPkF7znEBZ345iCSmNwn -EPrz/OrqiId2OHW2OCJv3c9NEb7hgaTswGfdq9LmqMRVeQy57FWh2lRdjVZbquWy -IvM72hjVLqnMVisWbDxf32YghnmT37SzZKsHSXU0xUx7rVSIShnoMjLWQtIQDoqI -3isMAeKals2NNJOy0TGKJ9SspIDl/IYm9sEO1HKiuxubrdN9q+wEQdizt59sXkol -4AYga+5TN+KtsSRclAGjfKYfuRrQ85IbVsRhQIYX1ZOJtMseEhBRnIeySKV4xWsi -kXAaxX5wIyoM+S1vaKcu +ZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANFC3H6Q26GO +bllXTiJBeALUbouzzxaGinwZeYYhhXKWEcfA0D8k+22w/JyndeEYc29JxwjFNwxM +/DyyQplptzbM1Q5BCcLNQaQhmpOryosjWuYWW1JUDGTG3nEg0qRCrtjwVoAU++Ko +NkQboM0wFQJxkBns0J1sr+O5Ml73YzKKtdVWWvg89osxyb4wRxkEoa9a/b9/aiK7 +WoeQhF00cRKoa/eoIN8usTjzKsYudHUtEQWibD7IxWdY3nMntGf1jyLYi40lVUbL +FFytWtlZGMVKpMVIOMMCQ+ex+ExGQaJrQF5QEqPq1L/BvXgTZkv5P6CS3YjBdVC2 +/ntfos3gMhsCAwEAAaM8MDowGQYDVR0RBBIwEIEObm9ib2R5QGV4YW1wbGUwHQYD +VR0OBBYEFLEaVAlnRWACAtfO9B1gSonf51jZMA0GCSqGSIb3DQEBCwUAA4IBAQDI +x70p19RI73Y9AEfBd0Wmk7KsZQyP55kjTAdaM37crhmClkUQRrk/Y2a0pXOhsrNI +0YO7t44fJKwMu++1dxh/bllKbuOkca6ApxTb2IfhOejx3IXXWzp+C1F9pmG9q5QW +0FDt//0SFZJIqDq9N+zFiA2z0MM1L7X/r29uUgAqkU7rsytKavHXru9EGQrrkxwh +5dM5VI+pnJgk9HYpBDPwiFVd0yFelebqdlv/nnW11tVBMTkMloVYyhei5yZbWKFk +f0Aj5g94+S107oRMyzq5e6lxQcJBhmKfOXqGaz2wue3/IHnwio9dMArayug9GLEr +ycy6PubJImhM/dboDIdO -----END CERTIFICATE----- diff --git a/test/rubygems/future_cert.pem b/test/rubygems/future_cert.pem index 05d3f9ebe3778a..06e08bb4c6288f 100644 --- a/test/rubygems/future_cert.pem +++ b/test/rubygems/future_cert.pem @@ -1,19 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDDzCCAfegAwIBAgIBCDANBgkqhkiG9w0BAQUFADAqMQ8wDQYDVQQDDAZub2Jv +MIIDDzCCAfegAwIBAgIBCDANBgkqhkiG9w0BAQsFADAqMQ8wDQYDVQQDDAZub2Jv ZHkxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMCIYDzk5OTkxMjMxMjM1OTU5WhgP OTk5OTEyMzEyMzU5NTlaMCoxDzANBgNVBAMMBm5vYm9keTEXMBUGCgmSJomT8ixk -ARkWB2V4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCnZTWH -LxQesYKU/EHJzMm1XpRi1CskC/4UD0yvSeRcqgfIRAy7dq7jMCrB1On7v5oBvrC7 -xxdZ6loWQA4Z+q8AnzT9N9Nub5LTmeoiX1OtL8rWP394JIhjZD9tZdIc9PjLNeX/ -udoJPrBV6sBgWw7XiNMee1LB4vigDeu0Ljw57YWA7cIVyAOaXHcdsB/jVvBfNhxG -b5tYXKQO+QQ1ZOLz8Z6Q37zzikmJ/XVoIZlLWj5qslb7PF5A8Rw32OePw984j3oT -/s0MxIPAtO0qv8+ry0jkN7mmJ9JwQ7jROlz94oyeGb7NniRHTjMktR9wrJ5Fonjw -qy7SncPHfxfg+W6HAgMBAAGjPDA6MBkGA1UdEQQSMBCBDm5vYm9keUBleGFtcGxl -MB0GA1UdDgQWBBRfQ272mo5FJeki4303XqTVNgKFGzANBgkqhkiG9w0BAQUFAAOC -AQEAM/0YoOjHEs1zdE6oG10XKdDcYn192AYhkMaITrfJUJiVUYehmcC+fa7aV5Hp -CYasFm5SawiyHwcI92GROaM97gJy7Tjpg8zcpkXg/vUA/8ItzD0UYphs5efZ9B3R -zOfxQDasTZJgg0uCxw23Bil7Anf5/KipuiU92Cc3fjpI6jWOuezGWqSqC2KGJLM+ -S59/oLqQNR67j7WBH3lHe3qbUehpNPkSrTdcLEbvspZM2udrRN9QYUUwBxD9dMlB -eC4hADgWEh5uPZO5sM2+qUdyIRa+fDUpcbTEhLQy6NceHuCNLK230DdC2xszrtNY -yNFy3B5BHgxfZeycaC4pMED0gA== +ARkWB2V4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRQtx+ +kNuhjm5ZV04iQXgC1G6Ls88Whop8GXmGIYVylhHHwNA/JPttsPycp3XhGHNvSccI +xTcMTPw8skKZabc2zNUOQQnCzUGkIZqTq8qLI1rmFltSVAxkxt5xINKkQq7Y8FaA +FPviqDZEG6DNMBUCcZAZ7NCdbK/juTJe92MyirXVVlr4PPaLMcm+MEcZBKGvWv2/ +f2oiu1qHkIRdNHESqGv3qCDfLrE48yrGLnR1LREFomw+yMVnWN5zJ7Rn9Y8i2IuN +JVVGyxRcrVrZWRjFSqTFSDjDAkPnsfhMRkGia0BeUBKj6tS/wb14E2ZL+T+gkt2I +wXVQtv57X6LN4DIbAgMBAAGjPDA6MBkGA1UdEQQSMBCBDm5vYm9keUBleGFtcGxl +MB0GA1UdDgQWBBSxGlQJZ0VgAgLXzvQdYEqJ3+dY2TANBgkqhkiG9w0BAQsFAAOC +AQEAATJNbSaVk8fM1uhqQnlBiQ/0TzchHADy+WmsbIbOiUAc8c29sjpCC4x0o5Gk +Zn18+BsXUjfyF6zyY4wPABZp9SCDIxvLxP2QVmbCtY2TJeKV95c4mWEnrFcCqYZ/ +je13m5iLnAu1WqVjSbFn1KamTf25pfBd9mqgQVwrdJMGoviJC18LyKJTZs7aV+Bu +tsF9fVMIP8p1Xu0Es/hBXFRwths41seqT0dYFszhwTCBC9tt85TTixWmEXpdyrov +vLFULJg4ijn9YZeKMViC6V3zgHUl9ZnMlWdFpVZ6cf7kA/1acW1ESEZnARLQhvMF +a1gof1D2Mj5k3AtQJ2TtPXytxw== -----END CERTIFICATE----- diff --git a/test/rubygems/future_cert_32.pem b/test/rubygems/future_cert_32.pem index aa74bdffbca223..c0231101414f93 100644 --- a/test/rubygems/future_cert_32.pem +++ b/test/rubygems/future_cert_32.pem @@ -1,19 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDCzCCAfOgAwIBAgIBCTANBgkqhkiG9w0BAQUFADAqMQ8wDQYDVQQDDAZub2Jv +MIIDCzCCAfOgAwIBAgIBCTANBgkqhkiG9w0BAQsFADAqMQ8wDQYDVQQDDAZub2Jv ZHkxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMB4XDTM4MDExOTAzMTQwN1oXDTM4 MDExOTAzMTQwN1owKjEPMA0GA1UEAwwGbm9ib2R5MRcwFQYKCZImiZPyLGQBGRYH -ZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKdlNYcvFB6x -gpT8QcnMybVelGLUKyQL/hQPTK9J5FyqB8hEDLt2ruMwKsHU6fu/mgG+sLvHF1nq -WhZADhn6rwCfNP03025vktOZ6iJfU60vytY/f3gkiGNkP21l0hz0+Ms15f+52gk+ -sFXqwGBbDteI0x57UsHi+KAN67QuPDnthYDtwhXIA5pcdx2wH+NW8F82HEZvm1hc -pA75BDVk4vPxnpDfvPOKSYn9dWghmUtaPmqyVvs8XkDxHDfY54/D3ziPehP+zQzE -g8C07Sq/z6vLSOQ3uaYn0nBDuNE6XP3ijJ4Zvs2eJEdOMyS1H3CsnkWiePCrLtKd -w8d/F+D5bocCAwEAAaM8MDowGQYDVR0RBBIwEIEObm9ib2R5QGV4YW1wbGUwHQYD -VR0OBBYEFF9DbvaajkUl6SLjfTdepNU2AoUbMA0GCSqGSIb3DQEBBQUAA4IBAQA6 -lip2nqmXyhz1uBDAxlNAv9nN2JPicWpRIvQ4KLNwmZKnagPWfleZ4TbLqsn723w8 -lD2VqFNX/Vj1XNuEJg8pXME+qxbMgtWxGsXC0z6k2Q3rT81QTdhXJ7nqdoe2i8y1 -423Fft2L6Dcgmx2USJwZsNy53pK9smxI9NipuRtL4W34PHHpaFsC2646daxZ2F8M -No3R9C4CtSFJDrM0XZoFiAnarbqoGCJs2q0NtcdV8D5m6xGeNShWJMLNbVx4DgsT -E90gVxVqPaqm5ytAIfdPWVUsyJBoD15jDVH5AZtkBmFRNoz60KPt3HpiRPspKWCd -tVabH2JRC0wDYRwEEMKB +ZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANFC3H6Q26GO +bllXTiJBeALUbouzzxaGinwZeYYhhXKWEcfA0D8k+22w/JyndeEYc29JxwjFNwxM +/DyyQplptzbM1Q5BCcLNQaQhmpOryosjWuYWW1JUDGTG3nEg0qRCrtjwVoAU++Ko +NkQboM0wFQJxkBns0J1sr+O5Ml73YzKKtdVWWvg89osxyb4wRxkEoa9a/b9/aiK7 +WoeQhF00cRKoa/eoIN8usTjzKsYudHUtEQWibD7IxWdY3nMntGf1jyLYi40lVUbL +FFytWtlZGMVKpMVIOMMCQ+ex+ExGQaJrQF5QEqPq1L/BvXgTZkv5P6CS3YjBdVC2 +/ntfos3gMhsCAwEAAaM8MDowGQYDVR0RBBIwEIEObm9ib2R5QGV4YW1wbGUwHQYD +VR0OBBYEFLEaVAlnRWACAtfO9B1gSonf51jZMA0GCSqGSIb3DQEBCwUAA4IBAQB2 +EjAxPVbDwoYehhEJEiMnMWk8GL6oo1uVwGJgCM76Yml69FVyWrre2GcSYiv+9f7K +AzE9S2uREeJuGcSV0VR0MeXoHXwQpQyBV12gCL1eQH15oxFfTi9XbVLhh5CyTKc1 +J6lYtQVpZPlLRoJN3oBq3J8PN8hWBWuhb2VIrpHXNBXAMOZ+hJM2B+EYifH6tcI5 +YK/Bw5Tes81QU4stQTLKybJzQkct02Rm7bYIM3GX/FGMMEPZE4jhnQ5btSNYVBlY +HXh6qfZVhZ8qpAy50yrlxROLa5zJSuTQ28QWh95XLzzHiHJ4Q4qZQzhcRGUQLfM3 +X6P8rtGWzXtB++CKKQIG -----END CERTIFICATE----- diff --git a/test/rubygems/grandchild_cert.pem b/test/rubygems/grandchild_cert.pem index dbd14bce802fc8..c1d9887b60ab69 100644 --- a/test/rubygems/grandchild_cert.pem +++ b/test/rubygems/grandchild_cert.pem @@ -1,20 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDNTCCAh2gAwIBAgIBDDANBgkqhkiG9w0BAQUFADApMQ4wDAYDVQQDDAVjaGls +MIIDFDCCAfygAwIBAgIBDDANBgkqhkiG9w0BAQsFADApMQ4wDAYDVQQDDAVjaGls ZDEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUwIBcNMTIwMTAxMDAwMDAwWhgPOTk5 OTEyMzEyMzU5NTlaMC4xEzARBgNVBAMMCmdyYW5kY2hpbGQxFzAVBgoJkiaJk/Is -ZAEZFgdleGFtcGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkfgy -EbzcRpXvpNA0s75R8gOVk7ENEPX5uXUElbzHbVEmHkC/NFsWZXV0vxGFfZrrnEkT -Y2kDaMMkfZX9rriRIvsZpxyqrdX87QfQTZ1ktDoytVnd+gw9A6AXB6PR7uoPymso -f/lZYJ8BWP9fIU39nogiptFqsgkpOtKSFjJfMILkcMAeBPs2B5HV5l4oLrpJ7Ns/ -0vazCXGakTByAXNKBagJWR43gh+RUQWF6Uh04VQTQ7ENGWI83088SKAPtCCcgKxr -ROHI025S7o7vEfDEqEn+gtu+4ndaLuRp+2AmF3YK8dEDiLXrrvEvG1r4+gIB/6tS -MUfkkJtBleZrDoIAgQIDAQABo2EwXzAdBgNVHREEFjAUgRJncmFuZGNoaWxkQGV4 -YW1wbGUwHQYDVR0OBBYEFAnex9R5fpiHNpHxq91rMog/PZA6MB8GA1UdIwQYMBaA -FHzVU9N7sklKBPrHElxoZ32Fg64IMA0GCSqGSIb3DQEBBQUAA4IBAQCYT10tUm9O -2xSGVmsbYv5YVrMr1Ucuq6Y+mXuTqqXuidILXZZl3LDwaYj64AhmMUqfITybGbR3 -sbWZrz2TWI2qWo+wcYDq+k0K+ys2PBavXdbjw4nVMf/9xYb2bCHK4bxxIG6rkmCw -zxYRTx+UivRf7Hw+6ZRtkHDxX/qPfMQK1PbmvK9c2VYXGN3+fRRIJqPnknN26Hv1 -gangMI7oqcaNwCvL16E/CpN8uwdJNB1LcCgjFJP7Ora+LIEJVe4eZvmuOYkYaYH2 -7u6CglItKwNjVZ5jULUfBuJqFkRiOxkVMVjChe9QvNXz/fkhW2sH05CR+TDyh4rD -ZeON5sdo9TV8 +ZAEZFgdleGFtcGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyh7u +lK+O7leQKBQzSSvhEur49Xu4sQJllkVbrVvkv2jSo68woESgljSS8jCSX0I9IJ5T +0kHzNRpiuOpfWKZx7E4cKeqW6nmV7D/B+Iy1QnJbMzUdnxp1Y+CMCK0JrLIsFBnx +ndVmiS/S817W3coqkmZqce4e33/O0qmCChGxGJZuAVQFGYI25SiYWPbysVEjwXoW +6zO0D1m8QZLYYCeDSRpxKgItBoJK+Up+bm/nsrkFvUf4kAZNLgik5zvflM3/Mjyx +zxgY2MO07YaULOlr0vZN6Wxnq2F3jkuZY8JbEOpQSDGSgU2wJ1iFH+GLvj7LsBuR +ScjL0FJ4s1EjqjjP8QIDAQABo0AwPjAdBgNVHREEFjAUgRJncmFuZGNoaWxkQGV4 +YW1wbGUwHQYDVR0OBBYEFEuKocg9sisZIWu12gxzse+7/sHfMA0GCSqGSIb3DQEB +CwUAA4IBAQAFaz3FUNzDYt/Cb++6U1PXsucAy3pKDj8bUW7slJFleNsSooIA9A5b +axpnHst1Lt6i/bmvbi8F8q/0iq4PtsZvusmwVhJkCinEUZ9inddSJdxpWSyzOww5 +at8ragidzREd9Fx62flRr3GflzqIufkKN8TDjYrB+n45ijnSxDcwZhu7m/tmP/e2 +FxqODaIO9sVrPAU7YbXb0m3p3Em7RK22d0tqy1dHhcRIR5/yMQB4MSEvQ7ytRD2x +aHAP7A4rDbkRwG+LQ/4L57RJ1kU3InqpOEQnCgpwu3xw/6Alti9TXS7sGhXL4Aav +OLsFS/1BLSJx/DSSK58Vg6JFxFh6X2NK -----END CERTIFICATE----- diff --git a/test/rubygems/grandchild_cert_32.pem b/test/rubygems/grandchild_cert_32.pem index 5077a43452e0f8..5d1ad45cb7b1c1 100644 --- a/test/rubygems/grandchild_cert_32.pem +++ b/test/rubygems/grandchild_cert_32.pem @@ -1,20 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDMzCCAhugAwIBAgIBDTANBgkqhkiG9w0BAQUFADApMQ4wDAYDVQQDDAVjaGls +MIIDEjCCAfqgAwIBAgIBDTANBgkqhkiG9w0BAQsFADApMQ4wDAYDVQQDDAVjaGls ZDEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUwHhcNMTIwMTAxMDAwMDAwWhcNMzgw MTE5MDMxNDA3WjAuMRMwEQYDVQQDDApncmFuZGNoaWxkMRcwFQYKCZImiZPyLGQB -GRYHZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJH4MhG8 -3EaV76TQNLO+UfIDlZOxDRD1+bl1BJW8x21RJh5AvzRbFmV1dL8RhX2a65xJE2Np -A2jDJH2V/a64kSL7Gaccqq3V/O0H0E2dZLQ6MrVZ3foMPQOgFwej0e7qD8prKH/5 -WWCfAVj/XyFN/Z6IIqbRarIJKTrSkhYyXzCC5HDAHgT7NgeR1eZeKC66SezbP9L2 -swlxmpEwcgFzSgWoCVkeN4IfkVEFhelIdOFUE0OxDRliPN9PPEigD7QgnICsa0Th -yNNuUu6O7xHwxKhJ/oLbvuJ3Wi7kaftgJhd2CvHRA4i1667xLxta+PoCAf+rUjFH -5JCbQZXmaw6CAIECAwEAAaNhMF8wHQYDVR0RBBYwFIESZ3JhbmRjaGlsZEBleGFt -cGxlMB0GA1UdDgQWBBQJ3sfUeX6YhzaR8avdazKIPz2QOjAfBgNVHSMEGDAWgBR8 -1VPTe7JJSgT6xxJcaGd9hYOuCDANBgkqhkiG9w0BAQUFAAOCAQEAnIlgmwVS3BGk -cT9LxE3bbQt1WGeLLxAF5ScqkNgFm3OvIxrKPX94WRa6tjWPEeJ9rl64QMKwJ8h1 -GzNbf0DUH8nMcSJLL1J5HUqdzwysQ96HNz54RuZ3ZF8w7QD4Kv3Vvh4IIsANchSj -unVYjcDVH9lSsbqTwC+bnUxYZ1Xu530fKZ440BG1ju9vLLZu5JaSOoJWRuHNOlQF -FbYj5AIjPwMNUidzoE9sUWdRzvARwecismWkPjfM0x1AmxVMs8hA5tS2QoCEvOxt -Hl3q6k7BaC8BRENkA/XRRIqgTMoTv86OOZIMFVaTiuHyU1XUxNHKv+ybAeAlP+H7 -hM/Hqka4bQ== +GRYHZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMoe7pSv +ju5XkCgUM0kr4RLq+PV7uLECZZZFW61b5L9o0qOvMKBEoJY0kvIwkl9CPSCeU9JB +8zUaYrjqX1imcexOHCnqlup5lew/wfiMtUJyWzM1HZ8adWPgjAitCayyLBQZ8Z3V +Zokv0vNe1t3KKpJmanHuHt9/ztKpggoRsRiWbgFUBRmCNuUomFj28rFRI8F6Fusz +tA9ZvEGS2GAng0kacSoCLQaCSvlKfm5v57K5Bb1H+JAGTS4IpOc735TN/zI8sc8Y +GNjDtO2GlCzpa9L2TelsZ6thd45LmWPCWxDqUEgxkoFNsCdYhR/hi74+y7AbkUnI +y9BSeLNRI6o4z/ECAwEAAaNAMD4wHQYDVR0RBBYwFIESZ3JhbmRjaGlsZEBleGFt +cGxlMB0GA1UdDgQWBBRLiqHIPbIrGSFrtdoMc7Hvu/7B3zANBgkqhkiG9w0BAQsF +AAOCAQEAFW6StPxdeONHUmWXUAKXNncP66aaHPAk+rQ84IvuyJKqR3UrrKdCbQLQ +LpL/lQZDkjGJSXdNHUhoB4MQsDJ8TQs2BdwDqOIvQLsZxTKZaXPfc1diFP+z/5f0 +9wbWezUateJwShDpp1RltCBmFCdibPZQUCpsgAsfqsgIWNpzhqy9dI/Upg3vECVc +c4g+EsEtiNXSbjd0kWUXCGBAeTMu4paBLVtt81fuffKJfnAKRhzrfFy0PoL3Kt2T +DkMr4MWfkMOyVlrSkvjPtW1oHVnxfZgqaE91J0Ht9qiHvekti3JDqxqcKaYuIgAL +w9HK9z5uQA2KrMvqn/jiuD8lBFsnuA== -----END CERTIFICATE----- diff --git a/test/rubygems/grandchild_key.pem b/test/rubygems/grandchild_key.pem index a9b9aef6248bbc..63635844b0d3d9 100644 --- a/test/rubygems/grandchild_key.pem +++ b/test/rubygems/grandchild_key.pem @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/test/rubygems/invalid_issuer_cert.pem b/test/rubygems/invalid_issuer_cert.pem index ea11756bb03fdb..5cb9d22a87b947 100644 --- a/test/rubygems/invalid_issuer_cert.pem +++ b/test/rubygems/invalid_issuer_cert.pem @@ -1,20 +1,20 @@ -----BEGIN CERTIFICATE----- -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 +vpqxaQ== -----END CERTIFICATE----- diff --git a/test/rubygems/invalid_issuer_cert_32.pem b/test/rubygems/invalid_issuer_cert_32.pem index bb73772735ea8c..2b71179270653b 100644 --- a/test/rubygems/invalid_issuer_cert_32.pem +++ b/test/rubygems/invalid_issuer_cert_32.pem @@ -1,20 +1,20 @@ -----BEGIN CERTIFICATE----- -MIIDTzCCAjegAwIBAgIBCzANBgkqhkiG9w0BAQUFADAqMQ8wDQYDVQQDDAZub2Jv +MIIDLjCCAhagAwIBAgIBCzANBgkqhkiG9w0BAQsFADAqMQ8wDQYDVQQDDAZub2Jv ZHkxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMB4XDTEyMDEwMTAwMDAwMFoXDTM4 MDExOTAzMTQwN1owKzEQMA4GA1UEAwwHaW52YWxpZDEXMBUGCgmSJomT8ixkARkW -B2V4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNMnDkoUji -gxoQ5T2d/iQFsKeygdqbP1ZS4SLGZdLgB8wgBjzSNSOOoJpWtYOxoeNvX2HidFYH -kU8SP60VjSdB19iPY4WiagJIjqleUZOkZCb/9JVNVUrtSAYykZleql4jXgVgPHbh -DzXXesyl+1KCnGIJhtwTA7hMuuwKllIGTo3PVlJ3eovpsFnIjLjarpevbzLweYKO -HP64LadWNz4SwyK4XmD/bPgc2tTDadBVBZaz5y+YM2U7D/yF9ru5BdwhISgmV2T1 -9KGXP6W6iEtjrkPU+n7ekrUsAPvSIQMgnifWxsgWCu/EsoknxCyshim5O+EpkQKo -6TdjyV96P4JPAgMBAAGjfzB9MBoGA1UdEQQTMBGBD2ludmFsaWRAZXhhbXBsZTAd -BgNVHQ4EFgQUk9+Lsaj37L/MP/nHPYBAoVp52U4wHwYDVR0jBBgwFoAUX0Nu9pqO -RSXpIuN9N16k1TYChRswDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAgQw -DQYJKoZIhvcNAQEFBQADggEBAMXxi62wMgtxERL3Snu9wB+qPBY0oaZn0gxcqH8x -IKbBa+ib63l3UX0vVqzHZlDYxBLTJicU3Cwr7Tm+GHPg/oMkqufxeFZPl/n4uvwY -iogyY5RMsx6C3WqdhA3x+tg04xMxDnAptRWMT4n19myPEadasLBwOqHeXtpc/v2N -XnNFlX3q8NB3AQya+Sp4fxL1fp9sCYlyJolS4dNZGOW4qC5I2GQGlduFom5oOyTB -QyWPs+McRfanWrZgmoViu5x+N7l/xRTJ7WEa9DDqZbPxjCaXrKIyteSIJgqsdqwy -0N+4pygu9VOdQNfQvI2jkxyDZI6rZ/YEr8sxhOKmzvaW0kc= +B2V4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDxGWcyHctJ +tY0m3BwcFHNDC6av/iSXcC6Rq4w9+QriOwzT9DIh/pjR25ck6jGnQd36J7dupEBS +Iw2bXNXrNWb7eJjaNZUnELL21RkRQ0Ctv8XWdDtBmyt9QuyCdgaGvdxfu+H+zXg+ +iyp/vklgsRzQilfN0bpkOnYhv1nVGULvJPcY6UcsCNrthMDQxE5G4Rmpo+czY+2v +KXD8onwcc04mfRWb1lWghDg73SKxeDXSLXl8mBEMA0S1g/50PWfcG8OCkArQP1FH +fqzm6HI73mrtcC4ma8rpoWUcMCCmVOPmmgDWExW97W5lCp6EfWi2ryr8RJ5RdOZB +6PcXB6EuX7cPAgMBAAGjXjBcMBoGA1UdEQQTMBGBD2ludmFsaWRAZXhhbXBsZTAd +BgNVHQ4EFgQUde3TNs2UED6K/5OjePyV3q1l4UgwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADggEBAGolEDY9meTGpP7j3Meb +pxtLX/JYPiTMqQR+FOOdGJlXg4V9syMBYUMmUj3yEPnpBFmDgDtBaH+OQcFuvf43 +mQYOQoTJD6OpC08fkPdVw56Em+cuUCXtDDYY4gc+nVRKk4+tJqkizHNAazqKkZoQ +PaHaCfXsrMGPLXxh/kbk14ESU9pL0LShh/bNn68hlAKwN2ctTSlfm81QgbNX83d1 +6kLSckj/9B1ksi6ks/eHkHWeMaiJe8H3vAU6PE6NeU3WRZY1ulSGOPleYfJA99fq +z9yks8IxwMzubJStq2sQ0n6gu3XS4Qu0sn3ih0TwRyUOSQkWa2Bf5SwUZ3/YJ25S +Wkw= -----END CERTIFICATE----- diff --git a/test/rubygems/invalid_key.pem b/test/rubygems/invalid_key.pem index 74bedabcda1d80..bc02147403cddc 100644 --- a/test/rubygems/invalid_key.pem +++ b/test/rubygems/invalid_key.pem @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/test/rubygems/invalid_signer_cert.pem b/test/rubygems/invalid_signer_cert.pem index 7f8b5cc727e2ff..59364ee51b5930 100644 --- a/test/rubygems/invalid_signer_cert.pem +++ b/test/rubygems/invalid_signer_cert.pem @@ -1,19 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDEDCCAfigAwIBAgIBDjANBgkqhkiG9w0BAQUFADArMRAwDgYDVQQDDAdpbnZh +MIIDEDCCAfigAwIBAgIBDjANBgkqhkiG9w0BAQsFADArMRAwDgYDVQQDDAdpbnZh bGlkMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTAgFw0xMjAxMDEwMDAwMDBaGA85 OTk5MTIzMTIzNTk1OVowKzEQMA4GA1UEAwwHaW52YWxpZDEXMBUGCgmSJomT8ixk -ARkWB2V4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNMnDk -oUjigxoQ5T2d/iQFsKeygdqbP1ZS4SLGZdLgB8wgBjzSNSOOoJpWtYOxoeNvX2Hi -dFYHkU8SP60VjSdB19iPY4WiagJIjqleUZOkZCb/9JVNVUrtSAYykZleql4jXgVg -PHbhDzXXesyl+1KCnGIJhtwTA7hMuuwKllIGTo3PVlJ3eovpsFnIjLjarpevbzLw -eYKOHP64LadWNz4SwyK4XmD/bPgc2tTDadBVBZaz5y+YM2U7D/yF9ru5BdwhISgm -V2T19KGXP6W6iEtjrkPU+n7ekrUsAPvSIQMgnifWxsgWCu/EsoknxCyshim5O+Ep -kQKo6TdjyV96P4JPAgMBAAGjPTA7MBoGA1UdEQQTMBGBD2ludmFsaWRAZXhhbXBs -ZTAdBgNVHQ4EFgQUk9+Lsaj37L/MP/nHPYBAoVp52U4wDQYJKoZIhvcNAQEFBQAD -ggEBAGJurQiRw3Vb2LPUhoL9BHyPy8TY+ZXz7eZyzf72saiATkHTuainb9jvLTzf -9ZNYNnjxGNwR4QnDhlh8Vb8vHaYfQGGwiLhd5ZbKjkid/41Y9XmNh+oHCrmwGcS6 -vX4QmTTmPQRBZ2Ilckr+wb1fdpLYk0wW/JFMFdAzp1OO3kP23hYElqia6qeJGw4k -4fe9d56huHHptSJrlMTjHwaqXq6QRjfjF5Za1unCjxQMO2vNQC/dUYRaq/M0kwFN -6A2xHKukkgA9cyjVpFVpxhE3/iFz8OE1GZg7VVcT+Jzhhxaajubpe+ZtDN5rbln/ -NI4WP/ZM3cnxVrHG84G3AYRpkhc= +ARkWB2V4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDxGWcy +HctJtY0m3BwcFHNDC6av/iSXcC6Rq4w9+QriOwzT9DIh/pjR25ck6jGnQd36J7du +pEBSIw2bXNXrNWb7eJjaNZUnELL21RkRQ0Ctv8XWdDtBmyt9QuyCdgaGvdxfu+H+ +zXg+iyp/vklgsRzQilfN0bpkOnYhv1nVGULvJPcY6UcsCNrthMDQxE5G4Rmpo+cz +Y+2vKXD8onwcc04mfRWb1lWghDg73SKxeDXSLXl8mBEMA0S1g/50PWfcG8OCkArQ +P1FHfqzm6HI73mrtcC4ma8rpoWUcMCCmVOPmmgDWExW97W5lCp6EfWi2ryr8RJ5R +dOZB6PcXB6EuX7cPAgMBAAGjPTA7MBoGA1UdEQQTMBGBD2ludmFsaWRAZXhhbXBs +ZTAdBgNVHQ4EFgQUde3TNs2UED6K/5OjePyV3q1l4UgwDQYJKoZIhvcNAQELBQAD +ggEBACbQA7m+zqdAE1/GrJKcXnC/Ujr1tu6rGpe0uExTwySptgVieUGAOvzlLLrY +r2b/nGmK4bgHkeDPSVuC3F8NhgESvPTuXFSw+DU+1m+mhHxdpW30uSbbebgqV5Ea +GpckCZj1SEdsn/1SDauXCmkrs/MBuK49mYXv3jejX0Rp0STu1NxnU13yrKF0MtrL +fzZ/QF8bOZdg5DwtqMwhDPp72x58KpqAPN9GgdlsTiwOMGy4avds1g5KMGmkK8pK +6I58NEMCOuN4CxFK4oWD9xuD4j+wtHy/UYxqor4rn+UKYHfr5fWtAyRJ3gD8vMUu +C+Nl2vB8t4OVwS5FCcn0ZK18bPU= -----END CERTIFICATE----- diff --git a/test/rubygems/invalid_signer_cert_32.pem b/test/rubygems/invalid_signer_cert_32.pem index 657608e5031ac9..97feb8fd0a9cf9 100644 --- a/test/rubygems/invalid_signer_cert_32.pem +++ b/test/rubygems/invalid_signer_cert_32.pem @@ -1,19 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDDjCCAfagAwIBAgIBDzANBgkqhkiG9w0BAQUFADArMRAwDgYDVQQDDAdpbnZh +MIIDDjCCAfagAwIBAgIBDzANBgkqhkiG9w0BAQsFADArMRAwDgYDVQQDDAdpbnZh bGlkMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTAeFw0xMjAxMDEwMDAwMDBaFw0z ODAxMTkwMzE0MDdaMCsxEDAOBgNVBAMMB2ludmFsaWQxFzAVBgoJkiaJk/IsZAEZ -FgdleGFtcGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzTJw5KFI -4oMaEOU9nf4kBbCnsoHamz9WUuEixmXS4AfMIAY80jUjjqCaVrWDsaHjb19h4nRW -B5FPEj+tFY0nQdfYj2OFomoCSI6pXlGTpGQm//SVTVVK7UgGMpGZXqpeI14FYDx2 -4Q8113rMpftSgpxiCYbcEwO4TLrsCpZSBk6Nz1ZSd3qL6bBZyIy42q6Xr28y8HmC -jhz+uC2nVjc+EsMiuF5g/2z4HNrUw2nQVQWWs+cvmDNlOw/8hfa7uQXcISEoJldk -9fShlz+luohLY65D1Pp+3pK1LAD70iEDIJ4n1sbIFgrvxLKJJ8QsrIYpuTvhKZEC -qOk3Y8lfej+CTwIDAQABoz0wOzAaBgNVHREEEzARgQ9pbnZhbGlkQGV4YW1wbGUw -HQYDVR0OBBYEFJPfi7Go9+y/zD/5xz2AQKFaedlOMA0GCSqGSIb3DQEBBQUAA4IB -AQA6WW6YyykIJmVFW8Og1R3d8fbFtQarDMGN+oZrCN3Eb9Twoy36Yr/h0bZgkCEe -arB+VCD1DfEii5luZowUDr/BlIjIR2cNIMFpmQ8ZLIpVWQz/BYHrbw7CHO5df3mg -HYTKlEoUMimOEWvCYnSgzKWCgSWU/jBQQ0bcUBk2HHpdT4BnLPe/7rs+TZmwd/Dz -r80sNXQ6vqTkQS+te2hqyh62r+WeaFx7aqnFjGtwiOqMmYPr80uYOy/rX26mmfwm -vyf8JlA4uTt795Krsc4Brc+BO0bOPfDDGhRs/2tvyHhOOqBbUxQeeV5ogiAZmA31 -ZrzbFysajMrWZ+1GV8QXOcBi +FgdleGFtcGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8RlnMh3L +SbWNJtwcHBRzQwumr/4kl3AukauMPfkK4jsM0/QyIf6Y0duXJOoxp0Hd+ie3bqRA +UiMNm1zV6zVm+3iY2jWVJxCy9tUZEUNArb/F1nQ7QZsrfULsgnYGhr3cX7vh/s14 +Posqf75JYLEc0IpXzdG6ZDp2Ib9Z1RlC7yT3GOlHLAja7YTA0MRORuEZqaPnM2Pt +rylw/KJ8HHNOJn0Vm9ZVoIQ4O90isXg10i15fJgRDANEtYP+dD1n3BvDgpAK0D9R +R36s5uhyO95q7XAuJmvK6aFlHDAgplTj5poA1hMVve1uZQqehH1otq8q/ESeUXTm +Qej3FwehLl+3DwIDAQABoz0wOzAaBgNVHREEEzARgQ9pbnZhbGlkQGV4YW1wbGUw +HQYDVR0OBBYEFHXt0zbNlBA+iv+To3j8ld6tZeFIMA0GCSqGSIb3DQEBCwUAA4IB +AQBM/EjV791vKu2KQQAhd03eUXfMlvObwEj9nGtEEnSFH5i16V1m8Y5ZY7Aw+VR5 +/xJ9J2AvFG6EXclDVmkDQpo1fUVhWM/SPKD6HJWuB/eyjA30xSj+UeLmBYjdKzHt +kK+HeEaGVQaT5j8OPOW6meGriucdBWtwbhTdyZgqvwpuZwbtPpElYXwGgSijKqHI +GG6RWzeANdG/4AIChrp8CIgFfW4sbmlIZK3BAXuSvZ9A/deYqC2DAadJIoTJ9H6w +0TgYlyTidaWtCkqRBXc3qrwpc/r3wJwpgan0kJAQ2kGc5W7gYUylpoS56sFq23YX +Fmm0pRq5UZj9jKZUIwcqAoGo -----END CERTIFICATE----- diff --git a/test/rubygems/invalidchild_cert.pem b/test/rubygems/invalidchild_cert.pem index 936dc650c9b32c..281dcce655cf41 100644 --- a/test/rubygems/invalidchild_cert.pem +++ b/test/rubygems/invalidchild_cert.pem @@ -1,20 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDOTCCAiGgAwIBAgIBEDANBgkqhkiG9w0BAQUFADApMQ4wDAYDVQQDDAVjaGls +MIIDGDCCAgCgAwIBAgIBEDANBgkqhkiG9w0BAQsFADApMQ4wDAYDVQQDDAVjaGls ZDEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUwIBcNMTIwMTAxMDAwMDAwWhgPOTk5 OTEyMzEyMzU5NTlaMDAxFTATBgNVBAMMDGludmFsaWRjaGlsZDEXMBUGCgmSJomT -8ixkARkWB2V4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDl -rDAlDZwmP6Zxc4sSaOdSRRXJBmbQubxmWpqU8bXrTKCkvg1l/2U6weJIS52zW6Te -Zok7Uus5jywyeNSJ/MBHb7X5ytAPQsvLu/3WFwaVfHJzimQI4vtmx9+CDgZzipYp -ett7IF18He8DPiFur1xCn8pp0qOOV8mXL/8TpUgJfmaOJosqgFqorj5niqF52IwJ -vtur/gwpq2xpCtYaCUB/dFzzefLV37kt58S6jTmZnYf4kIdFKhhyTeGmDRf/wOz+ -kK/H/aKtpsYgzI//bo+bsuWNFceIdWrdCBr63cVs4ql7VN7p2xfn9ckEfwH6wFut -QLquA/6fRkgUFF8fxUiHAgMBAAGjYzBhMB8GA1UdEQQYMBaBFGludmFsaWRjaGls -ZEBleGFtcGxlMB0GA1UdDgQWBBSwAwFqdxjicsovAzZ1ZeSAWlnKcDAfBgNVHSME -GDAWgBR81VPTe7JJSgT6xxJcaGd9hYOuCDANBgkqhkiG9w0BAQUFAAOCAQEAYxom -7nHgbfqLiMtVwx8D6LM6P3sk3p5HwoHJU0zzFVfPA0iuhhC2vWyPoHJroq6d31DG -DpPpOeVQxTYyQ6CtD6jGUpE+0MjmRoavFnvqFH5lf4OKO0dQ8xUa9fALo7fmK0v0 -ueDlgsHw3mwoVNX2Xu/+jCTuiK2KGG3J+pxr6JNA1++gQEghFFJjM8rw1/mYrDW0 -CSCyx/LeNyYbt9xzeVgo83XNO5TCfwwh8+df52I6Hj5BDFhhkP8KOai4ejq2CmZ8 -by9ylCUXc/aiz9mzX/NzIAYLuRzkmrI+lxDbUJpG/hV7MCS/TZegjD+SUSu9EI1O -RVerg89R7kQUWZyJqg== +8ixkARkWB2V4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDs +dqLesclj2/6HnJLw4al4swiDFBA4W0KeOS3DXOa2k5+rNfGacKOQ/AkciUnzqLiC +9D49x/YLlnlJYeSMG57C7gixhLHHDviCneQwy8TlCpuhUXnfcpmHQO+X/c+lrVB7 +wHTPjl5yZYzLFtPa8QAEtJa83E2GrUd+JEOwTRErOcBucIRP5HbeR2aD7BVP1V+F +gaUhOZb/n2e53diQF7BZurB45DTWQ2L1R/m8VldQiWoTZluWqnCGeEwtpZJXt9kU +8y5rQcxI3p8Qx4q0ilLKsE7c/sw2wzEFWoZ4BeURnjxdvPgYeOPk4K3a34pFg7lZ +u1s9XvjChJVsD8HRnbQtAgMBAAGjQjBAMB8GA1UdEQQYMBaBFGludmFsaWRjaGls +ZEBleGFtcGxlMB0GA1UdDgQWBBS3tDKiI1oVuEkKtGux8TsEy/8iuDANBgkqhkiG +9w0BAQsFAAOCAQEAQsgdq4NZBnQRk+eNbwS4go3S+m5cPPWY7kG94kpQ3aC3nwR4 +wnICb/hd+kRCB2azTTBY8PA0SkHxIXWgRFjdEpIAekm3Xtag+lCC1q7jtDTNoHw4 +KOdfeBEF621FHL5vBvJmnRMH8f4sCjVZZE8RJcaWAK7uJJXi6gzUm3xz0UnylZNr +vA+Z+cM5pFnCfxxqXUyT0MRb47O/wqH4f5SybKpOxO3+vnzpSeN++zgdMVjA/Pl0 +0SB8VKNKXGLQrvY2S3GuRoh7OD1DhRPzUTQ8gwwBAlhw2i3i5t9ib0ujw9MUO3GR +dqn4Yco98R0+wFpY8feGhr5uJNDuIC10l5LHLQ== -----END CERTIFICATE----- diff --git a/test/rubygems/invalidchild_cert_32.pem b/test/rubygems/invalidchild_cert_32.pem index 07687eb156c4ae..87885157f8dacb 100644 --- a/test/rubygems/invalidchild_cert_32.pem +++ b/test/rubygems/invalidchild_cert_32.pem @@ -1,20 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDNzCCAh+gAwIBAgIBETANBgkqhkiG9w0BAQUFADApMQ4wDAYDVQQDDAVjaGls +MIIDFjCCAf6gAwIBAgIBETANBgkqhkiG9w0BAQsFADApMQ4wDAYDVQQDDAVjaGls ZDEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUwHhcNMTIwMTAxMDAwMDAwWhcNMzgw MTE5MDMxNDA3WjAwMRUwEwYDVQQDDAxpbnZhbGlkY2hpbGQxFzAVBgoJkiaJk/Is -ZAEZFgdleGFtcGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5aww -JQ2cJj+mcXOLEmjnUkUVyQZm0Lm8ZlqalPG160ygpL4NZf9lOsHiSEuds1uk3maJ -O1LrOY8sMnjUifzAR2+1+crQD0LLy7v91hcGlXxyc4pkCOL7Zsffgg4Gc4qWKXrb -eyBdfB3vAz4hbq9cQp/KadKjjlfJly//E6VICX5mjiaLKoBaqK4+Z4qhediMCb7b -q/4MKatsaQrWGglAf3Rc83ny1d+5LefEuo05mZ2H+JCHRSoYck3hpg0X/8Ds/pCv -x/2irabGIMyP/26Pm7LljRXHiHVq3Qga+t3FbOKpe1Te6dsX5/XJBH8B+sBbrUC6 -rgP+n0ZIFBRfH8VIhwIDAQABo2MwYTAfBgNVHREEGDAWgRRpbnZhbGlkY2hpbGRA -ZXhhbXBsZTAdBgNVHQ4EFgQUsAMBancY4nLKLwM2dWXkgFpZynAwHwYDVR0jBBgw -FoAUfNVT03uySUoE+scSXGhnfYWDrggwDQYJKoZIhvcNAQEFBQADggEBAGK07MzH -/TJftVEgrghvEHIna0gadQUbWfrpMWxt/Vj7jsd4LvRaZEOWObMRxhtjMvMA2q3A -qKXoP1KddPkFGfAVdUsNKTKLsaMvDceZ7aN3SGEWv5IYGXtfjUEVhWj7CmpS05li -Phw9uPQVUwkkY20G2UGInRzxCYqyeW5KZIaep49KebaXCrjrV5Xy13UxgtpbmNMj -yKPvyA5u0J8TK4gQmx1Az0gujpT1KSwfMyEDrsbIqYDVMp4kF2yLlsrdmNT9Jhwj -R+M6AMhNqpLrjsklqE6TX2pCQGo+JFxCDOKQmvv5B7AhH0od46Jlwk//aIAheQQK -4rhDHEHYLCxGhrw= +ZAEZFgdleGFtcGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7Hai +3rHJY9v+h5yS8OGpeLMIgxQQOFtCnjktw1zmtpOfqzXxmnCjkPwJHIlJ86i4gvQ+ +Pcf2C5Z5SWHkjBuewu4IsYSxxw74gp3kMMvE5QqboVF533KZh0Dvl/3Ppa1Qe8B0 +z45ecmWMyxbT2vEABLSWvNxNhq1HfiRDsE0RKznAbnCET+R23kdmg+wVT9VfhYGl +ITmW/59nud3YkBewWbqweOQ01kNi9Uf5vFZXUIlqE2ZblqpwhnhMLaWSV7fZFPMu +a0HMSN6fEMeKtIpSyrBO3P7MNsMxBVqGeAXlEZ48Xbz4GHjj5OCt2t+KRYO5Wbtb +PV74woSVbA/B0Z20LQIDAQABo0IwQDAfBgNVHREEGDAWgRRpbnZhbGlkY2hpbGRA +ZXhhbXBsZTAdBgNVHQ4EFgQUt7QyoiNaFbhJCrRrsfE7BMv/IrgwDQYJKoZIhvcN +AQELBQADggEBAFPyjOoghY6Iba9+psCWC//rwLtDfZPQ3kO9hFtd4CGvalPtR103 +Oc1Dk5pxHSWDTdeQfOb75mqWuqs4ET7IUyw8yY+bKkOOhY1ldwaJhTyP/fkElnrL +prsLSpB3AdQceS1Ob2wpMaaGIPDzJlW0LG8cQNeU3SRTTdBjX5zjG6imHKG2yuJd +76PM0tl8ooslPABlYSPSLpd1PAARqxG2ekfrxZioCLknyhBtcRsl1aMWWBiG4BH9 +xZoJvEHwpOMTxMaAFXSkyMjZAoOzAn9qP6eLbwwzeuckIrZXxYBfGcC29VOPPAN4 +IPX0IUZ7/LlzzOE5iuVS/RIBRcD+qpEzSXs= -----END CERTIFICATE----- diff --git a/test/rubygems/invalidchild_key.pem b/test/rubygems/invalidchild_key.pem index 9706c9566ebcd5..1c9997150d8b30 100644 --- a/test/rubygems/invalidchild_key.pem +++ b/test/rubygems/invalidchild_key.pem @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/test/rubygems/private_key.pem b/test/rubygems/private_key.pem index c6ed3fc24e6aaf..4e6ce13e65baf1 100644 --- a/test/rubygems/private_key.pem +++ b/test/rubygems/private_key.pem @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/test/rubygems/public_cert.pem b/test/rubygems/public_cert.pem index 4517de53c6b490..7481c26b794697 100644 --- a/test/rubygems/public_cert.pem +++ b/test/rubygems/public_cert.pem @@ -1,20 +1,20 @@ -----BEGIN CERTIFICATE----- -MIIDLjCCAhagAwIBAgIBADANBgkqhkiG9w0BAQUFADAqMQ8wDQYDVQQDDAZub2Jv +MIIDLjCCAhagAwIBAgIBADANBgkqhkiG9w0BAQsFADAqMQ8wDQYDVQQDDAZub2Jv ZHkxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMCAXDTEyMDEwMTAwMDAwMFoYDzk5 OTkxMjMxMjM1OTU5WjAqMQ8wDQYDVQQDDAZub2JvZHkxFzAVBgoJkiaJk/IsZAEZ -FgdleGFtcGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp2U1hy8U -HrGClPxByczJtV6UYtQrJAv+FA9Mr0nkXKoHyEQMu3au4zAqwdTp+7+aAb6wu8cX -WepaFkAOGfqvAJ80/TfTbm+S05nqIl9TrS/K1j9/eCSIY2Q/bWXSHPT4yzXl/7na -CT6wVerAYFsO14jTHntSweL4oA3rtC48Oe2FgO3CFcgDmlx3HbAf41bwXzYcRm+b -WFykDvkENWTi8/GekN+884pJif11aCGZS1o+arJW+zxeQPEcN9jnj8PfOI96E/7N -DMSDwLTtKr/Pq8tI5De5pifScEO40Tpc/eKMnhm+zZ4kR04zJLUfcKyeRaJ48Ksu -0p3Dx38X4PluhwIDAQABo10wWzAZBgNVHREEEjAQgQ5ub2JvZHlAZXhhbXBsZTAd -BgNVHQ4EFgQUX0Nu9pqORSXpIuN9N16k1TYChRswDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQEFBQADggEBAJasznHQK7el5CY19uRM -QZSP2moi65jbESKA5CaSOK0erWfLL7k0W69Rr4RG8CQDXmtlVLzdQlEGkvJEfMLs -GumlIGDEsLZU/3tQ8lML2fMUKipv/fsyWoe6wUHyfsywYYT4WAxyKUtY6AepwN6Y -sJ6+qDWUFziSVgDnU2bBdqzIOw+ww1NtRGE3PEam+a/VL7l/a2DYcot5cvcc8RYR -6gyBXp4fvSGasM3iQp7sWdNV04H8m8+lYBLtsfuucgLDu45uEuvKL1tRcRXvtomp -rKB5y3B5qT/bcc+3b0tbOU6s7CBIdyzIflJI7GuIbZk6lZ+V8Yem+tWt1ArL3Hqf -Myk= +FgdleGFtcGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ULcfpDb +oY5uWVdOIkF4AtRui7PPFoaKfBl5hiGFcpYRx8DQPyT7bbD8nKd14Rhzb0nHCMU3 +DEz8PLJCmWm3NszVDkEJws1BpCGak6vKiyNa5hZbUlQMZMbecSDSpEKu2PBWgBT7 +4qg2RBugzTAVAnGQGezQnWyv47kyXvdjMoq11VZa+Dz2izHJvjBHGQShr1r9v39q +Irtah5CEXTRxEqhr96gg3y6xOPMqxi50dS0RBaJsPsjFZ1jecye0Z/WPItiLjSVV +RssUXK1a2VkYxUqkxUg4wwJD57H4TEZBomtAXlASo+rUv8G9eBNmS/k/oJLdiMF1 +ULb+e1+izeAyGwIDAQABo10wWzAZBgNVHREEEjAQgQ5ub2JvZHlAZXhhbXBsZTAd +BgNVHQ4EFgQUsRpUCWdFYAIC1870HWBKid/nWNkwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADggEBAAYrbeZLQujvqrzAa6NN +QsiGLSVoF+ZcySQH+rpoqcvbd8zLKz/vH+SoMM6db4OUgD8BKaeBb8dGhzz/lE8m +YUqW/La4xvf/ffW5yze51Rtr1bPw1Tjrk92nE630Unjf0ZZO0h8shTmq/WlXiEqg +cXxfbZiPP0KZkhn4ulf+RBbKKQGrLYvaVrCZcowSjLWzcfredYxElOpcgHCrL2pl +2ZAjCySqAUpYo8HTZwgY/DeeGS3V4fZ06ZDoG20cxi7t8R+AcNbEfaTMzG3oe5qN +A8+a3Qcf5M4yiJtXRNusMKeoRwLDkYRX9u76iOI5LfKTSqnUyhrUQcSYCTFO4y/V +P48= -----END CERTIFICATE----- diff --git a/test/rubygems/public_cert_32.pem b/test/rubygems/public_cert_32.pem index 0431b8ba1abecf..efcf7c0ed7437c 100644 --- a/test/rubygems/public_cert_32.pem +++ b/test/rubygems/public_cert_32.pem @@ -1,19 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDLDCCAhSgAwIBAgIBATANBgkqhkiG9w0BAQUFADAqMQ8wDQYDVQQDDAZub2Jv +MIIDLDCCAhSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAqMQ8wDQYDVQQDDAZub2Jv ZHkxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMB4XDTEyMDEwMTAwMDAwMFoXDTM4 MDExOTAzMTQwN1owKjEPMA0GA1UEAwwGbm9ib2R5MRcwFQYKCZImiZPyLGQBGRYH -ZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKdlNYcvFB6x -gpT8QcnMybVelGLUKyQL/hQPTK9J5FyqB8hEDLt2ruMwKsHU6fu/mgG+sLvHF1nq -WhZADhn6rwCfNP03025vktOZ6iJfU60vytY/f3gkiGNkP21l0hz0+Ms15f+52gk+ -sFXqwGBbDteI0x57UsHi+KAN67QuPDnthYDtwhXIA5pcdx2wH+NW8F82HEZvm1hc -pA75BDVk4vPxnpDfvPOKSYn9dWghmUtaPmqyVvs8XkDxHDfY54/D3ziPehP+zQzE -g8C07Sq/z6vLSOQ3uaYn0nBDuNE6XP3ijJ4Zvs2eJEdOMyS1H3CsnkWiePCrLtKd -w8d/F+D5bocCAwEAAaNdMFswGQYDVR0RBBIwEIEObm9ib2R5QGV4YW1wbGUwHQYD -VR0OBBYEFF9DbvaajkUl6SLjfTdepNU2AoUbMA8GA1UdEwEB/wQFMAMBAf8wDgYD -VR0PAQH/BAQDAgIEMA0GCSqGSIb3DQEBBQUAA4IBAQA2+XpC520DwKfqlv5Fn2N5 -sGOgr2Kop7Id2wVWiGDnjDEoTf2Fj+nmmLPltemoCumgY/AacUBAdK1kg47x+7NR -QMq1pOXR5dZbopw1vs9isQQx2P7jKEH7AgIkqo/6XMQGE3tQtJyNIi1LTGCOKNok -Fpv8ZVS8aBmXgC0zwtlrtTxCXpkFaNB99nEqo46Fy+D7dkEXE4Oc3JjTON83sHYD -VsV3DFYzZtR9qe/gCOdgnDHYnf5vU+LGA1gX+8d4Iu/B5ZZtaAowgrsA14oJDuO3 -4g491pjaEYDFZG6mUpvf79uZaBjJdDZeyfwtJ6cN3gTv98DO4DKh/qxnbM/46LM1 +ZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANFC3H6Q26GO +bllXTiJBeALUbouzzxaGinwZeYYhhXKWEcfA0D8k+22w/JyndeEYc29JxwjFNwxM +/DyyQplptzbM1Q5BCcLNQaQhmpOryosjWuYWW1JUDGTG3nEg0qRCrtjwVoAU++Ko +NkQboM0wFQJxkBns0J1sr+O5Ml73YzKKtdVWWvg89osxyb4wRxkEoa9a/b9/aiK7 +WoeQhF00cRKoa/eoIN8usTjzKsYudHUtEQWibD7IxWdY3nMntGf1jyLYi40lVUbL +FFytWtlZGMVKpMVIOMMCQ+ex+ExGQaJrQF5QEqPq1L/BvXgTZkv5P6CS3YjBdVC2 +/ntfos3gMhsCAwEAAaNdMFswGQYDVR0RBBIwEIEObm9ib2R5QGV4YW1wbGUwHQYD +VR0OBBYEFLEaVAlnRWACAtfO9B1gSonf51jZMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgIEMA0GCSqGSIb3DQEBCwUAA4IBAQBqjR8ioUTAmRjZNvRPMGXc +mx0nklEODMfG5k+X4QI2Hux/4CWuSZKh+LoIxOsqQJdm2rG1FkPr6JYQOj5HCFA7 +3gO/MoSOtqBBOY9uMnGJQUq0NrWvleO3giUhfHRzUh7utXy2u3umuwJLqF54vbuT +a1yufGSzwBO2BP7iURt9SyVrDWFmHSX976ZFWIandPXgMCJTgO6tONOC6/sABctb +YQKo2scrAiSsk+kgIMnebavL6gKgQud6xdjJzvUq3DV4s93ent9rpRzYRgnTM8Eo +UcgFbpFsWR21+gEt6UKv1rO9ZaWBf6RUVdh/sJKa/7vK/shQmnWw0A/LewxKQWV3 -----END CERTIFICATE----- diff --git a/test/rubygems/public_key.pem b/test/rubygems/public_key.pem index 7c29dcd6145d99..c233b35e7c8242 100644 --- a/test/rubygems/public_key.pem +++ b/test/rubygems/public_key.pem @@ -1,9 +1,9 @@ -----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp2U1hy8UHrGClPxByczJ -tV6UYtQrJAv+FA9Mr0nkXKoHyEQMu3au4zAqwdTp+7+aAb6wu8cXWepaFkAOGfqv -AJ80/TfTbm+S05nqIl9TrS/K1j9/eCSIY2Q/bWXSHPT4yzXl/7naCT6wVerAYFsO -14jTHntSweL4oA3rtC48Oe2FgO3CFcgDmlx3HbAf41bwXzYcRm+bWFykDvkENWTi -8/GekN+884pJif11aCGZS1o+arJW+zxeQPEcN9jnj8PfOI96E/7NDMSDwLTtKr/P -q8tI5De5pifScEO40Tpc/eKMnhm+zZ4kR04zJLUfcKyeRaJ48Ksu0p3Dx38X4Plu -hwIDAQAB +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ULcfpDboY5uWVdOIkF4 +AtRui7PPFoaKfBl5hiGFcpYRx8DQPyT7bbD8nKd14Rhzb0nHCMU3DEz8PLJCmWm3 +NszVDkEJws1BpCGak6vKiyNa5hZbUlQMZMbecSDSpEKu2PBWgBT74qg2RBugzTAV +AnGQGezQnWyv47kyXvdjMoq11VZa+Dz2izHJvjBHGQShr1r9v39qIrtah5CEXTRx +Eqhr96gg3y6xOPMqxi50dS0RBaJsPsjFZ1jecye0Z/WPItiLjSVVRssUXK1a2VkY +xUqkxUg4wwJD57H4TEZBomtAXlASo+rUv8G9eBNmS/k/oJLdiMF1ULb+e1+izeAy +GwIDAQAB -----END PUBLIC KEY----- diff --git a/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.lock b/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.lock index 0f1fa7c430e5a8..cf11ab247b86d0 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.lock +++ b/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.lock @@ -160,9 +160,9 @@ dependencies = [ [[package]] name = "rb-sys" -version = "0.9.30" +version = "0.9.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b22a374fc2e92eb6f49d7efe4eb7663655c6e9455d9259ed3342cc1599da85" +checksum = "bfc41b26ea88da6100f538d31467941e41ab0c002999d687315e67d3b371b796" dependencies = [ "bindgen", "linkify", @@ -171,9 +171,9 @@ dependencies = [ [[package]] name = "rb-sys-build" -version = "0.9.30" +version = "0.9.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd23b6dd929b7d50ccb35a6d3aa77dec364328ab9cb304dd32c629332491671" +checksum = "79be4233eabd2bf9e19eb8116391aeaf4b89b87a7ab38e0ded44de9158006e46" dependencies = [ "regex", "shell-words", diff --git a/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.toml b/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.toml index c9ba5c27bd696e..8dfbaf5799f097 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.toml +++ b/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -rb-sys = { version = "0.9.30", features = ["gem"] } +rb-sys = { version = "0.9.31", features = ["gem"] } diff --git a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock index 5e602fcf92db1f..23f571b1e77430 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock +++ b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock @@ -153,9 +153,9 @@ dependencies = [ [[package]] name = "rb-sys" -version = "0.9.30" +version = "0.9.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b22a374fc2e92eb6f49d7efe4eb7663655c6e9455d9259ed3342cc1599da85" +checksum = "bfc41b26ea88da6100f538d31467941e41ab0c002999d687315e67d3b371b796" dependencies = [ "bindgen", "linkify", @@ -164,9 +164,9 @@ dependencies = [ [[package]] name = "rb-sys-build" -version = "0.9.30" +version = "0.9.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd23b6dd929b7d50ccb35a6d3aa77dec364328ab9cb304dd32c629332491671" +checksum = "79be4233eabd2bf9e19eb8116391aeaf4b89b87a7ab38e0ded44de9158006e46" dependencies = [ "regex", "shell-words", diff --git a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml index 8e3f623728b3ce..3a37a73f730b1a 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml +++ b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -rb-sys = { version = "0.9.30", features = ["gem"] } +rb-sys = { version = "0.9.31", features = ["gem"] } diff --git a/test/rubygems/test_gem_security.rb b/test/rubygems/test_gem_security.rb index f0b9824aabb6af..0aecccdb273f33 100644 --- a/test/rubygems/test_gem_security.rb +++ b/test/rubygems/test_gem_security.rb @@ -51,7 +51,7 @@ def test_class_create_cert key_ident = cert.extensions.find {|ext| ext.oid == "subjectKeyIdentifier" } assert_equal 59, key_ident.value.length - assert_equal "5F:43:6E:F6:9A:8E:45:25:E9:22:E3:7D:37:5E:A4:D5:36:02:85:1B", + assert_equal "B1:1A:54:09:67:45:60:02:02:D7:CE:F4:1D:60:4A:89:DF:E7:58:D9", key_ident.value assert_equal "", cert.issuer.to_s @@ -99,7 +99,7 @@ def test_class_create_cert_email key_ident = cert.extensions.find {|ext| ext.oid == "subjectKeyIdentifier" } assert_equal 59, key_ident.value.length - assert_equal "5F:43:6E:F6:9A:8E:45:25:E9:22:E3:7D:37:5E:A4:D5:36:02:85:1B", + assert_equal "B1:1A:54:09:67:45:60:02:02:D7:CE:F4:1D:60:4A:89:DF:E7:58:D9", key_ident.value end @@ -151,7 +151,7 @@ def test_class_email_to_name end def test_class_re_sign - assert_equal "sha1WithRSAEncryption", EXPIRED_CERT.signature_algorithm + assert_equal "sha256WithRSAEncryption", EXPIRED_CERT.signature_algorithm re_signed = Gem::Security.re_sign EXPIRED_CERT, PRIVATE_KEY, 60 assert_in_delta Time.now, re_signed.not_before, 10 @@ -230,7 +230,7 @@ def test_class_sign key_ident = signed.extensions.find {|ext| ext.oid == "subjectKeyIdentifier" } assert_equal 59, key_ident.value.length - assert_equal "5F:43:6E:F6:9A:8E:45:25:E9:22:E3:7D:37:5E:A4:D5:36:02:85:1B", + assert_equal "B1:1A:54:09:67:45:60:02:02:D7:CE:F4:1D:60:4A:89:DF:E7:58:D9", key_ident.value assert signed.verify key @@ -272,7 +272,7 @@ def test_class_sign_AltName key_ident = signed.extensions.find {|ext| ext.oid == "subjectKeyIdentifier" } assert_equal 59, key_ident.value.length - assert_equal "5F:43:6E:F6:9A:8E:45:25:E9:22:E3:7D:37:5E:A4:D5:36:02:85:1B", + assert_equal "B1:1A:54:09:67:45:60:02:02:D7:CE:F4:1D:60:4A:89:DF:E7:58:D9", key_ident.value assert signed.verify PUBLIC_KEY diff --git a/test/rubygems/test_gem_security_signer.rb b/test/rubygems/test_gem_security_signer.rb index d9f320eeb01d3c..6b2a4a201a77c1 100644 --- a/test/rubygems/test_gem_security_signer.rb +++ b/test/rubygems/test_gem_security_signer.rb @@ -120,12 +120,12 @@ def test_sign signature = signer.sign "hello" expected = <<-EXPECTED -cHze2sEfRysoUMCfGVAx/7o8jxj5liJJ2ptNxe2jf3l+EZvyjdqpXo9Ndzxx -6xLp2rxLG4K2//ip4aCH5Sh7hnia+F5u6iuLBETPlklPrmw5dnuKZxolz+vM -0O1aOZsQHcVzQoESTGjkms3KZk+gn3lg0sSBbAV5/LyDYoHCEjxlcA5D+Olb -rDmRyBMOnMS+q489OZ5Hr6B2YJJ3QbUwIZNhUeNmOxIBEYTrrKkZ92qkxbRN -qhlqFP4jR6zXFeyBCOr0KpTiWBNuxBFXDsxmhGyt2BOIjD6qmKn7RSIfYg/U -toqvglr0kdbknSRRjBVLK6tsgr07aLT9gNP7mTW2PA== +FmrCYxEXW3dgYYNMxPdS16VrdXT+d5nyXTVlRm64ZHSgMxMAaPtQJsVYv73m +DWHTzNnLhhINSpgBMLh5a4atM52yxVdkPUTgqIH+LeIPBXn8xaP5JLmfDcmI +tBpc/9DhS3v9iKCX40igAArFu7Gg3swbgQ61SP+U22LvG5nDQZQz3sudtsw3 +qKPykFVaYjrRwzvBdSdJ1PwlAsanSwcwS/GKPtmE/ykZ6X5XOx7wvCDL/zGy +B8khkB8hDKC6moCzebmUxCBmTmXD0Wjzon+bf4MOriVE3a0ySGRvpr1mKR2+ +9EaVo7pDJLEM487+xg1CAZHRhwshd6II00XEzG/jBQ== EXPECTED assert_equal expected, [signature].pack("m") diff --git a/test/rubygems/wrong_key_cert.pem b/test/rubygems/wrong_key_cert.pem index 23396d7c81d703..2f2cffbc61c864 100644 --- a/test/rubygems/wrong_key_cert.pem +++ b/test/rubygems/wrong_key_cert.pem @@ -1,19 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDDTCCAfWgAwIBAgIBEjANBgkqhkiG9w0BAQUFADAqMQ8wDQYDVQQDDAZub2Jv +MIIDDTCCAfWgAwIBAgIBEjANBgkqhkiG9w0BAQsFADAqMQ8wDQYDVQQDDAZub2Jv ZHkxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMCAXDTEyMDEwMTAwMDAwMFoYDzk5 OTkxMjMxMjM1OTU5WjAqMQ8wDQYDVQQDDAZub2JvZHkxFzAVBgoJkiaJk/IsZAEZ -FgdleGFtcGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvZQipBa1 -xH3M9OonkrUYhGZeX9UHAcJhe6jJbUr/uHXkh1Tu2ERWNnblm85upqBfjyZEnKer -7uBcwwkkvmisVgC8uBECymsBxuEIw0rfiKYEnLu0B6SiWFYz3dYPS92bBK7Vks2/ -kNyXUmLLGoZ3id2K0eK5C/AJ0j+p84OqPnVhylsjrZmXfIZrh7lkHhgCIrzPefjE -3pOloi/tz6fh2ktb0FYKQMfweT3Ba2TMeflG13PEOW80AD5w0THxDutGG0zPNCDy -DEoT7UU1a3B3RMHYuUxEk1GUEYWq9L6a6SMpZISWTSpCp0Ww1QB55PONiCCn+o6v -cIy46jI71dATAQIDAQABozwwOjAZBgNVHREEEjAQgQ5ub2JvZHlAZXhhbXBsZTAd -BgNVHQ4EFgQUyvn/FwcZnA7AkzPjmoooB4/tKgcwDQYJKoZIhvcNAQEFBQADggEB -ABswixv3veo8S0Omyhbch3t19xAd/I4ZAx/lq6a/Ubl+X33hRbZQ7ulXja6Y5ZCs -iIkezGcpc182e7hZdHuEGGnJ1fJwxz3rbFWvs+MrtRSaCC73HbbxF1x0mQY6Kc7W -PahB2v+Dx5n3dIN6ah5p+STUHmzhKGr3bsQswtSHrFn74wt6mBu/hyCz+t6UaQ7b -rpRpzDFO1q3tZB8MeIHg57Lk2bu0LtfaHdkGDghNa3t7oZfV5A6pruiTy/EdQvFL -ZJpvDgHCyUsDmukMMjz6U4ts+nx7kZ9JoIH9K2lMJo3SGw4iZ8rB+HTfsbUdRfBj -UlyNcLqCW+FPlUHgHgNugFA= +FgdleGFtcGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApebGm7NO +nx+DtWG1xQsJBfTfwNlZvfzY61nlZccrhU6vx0AnYNiDZAG3J/gFQmYZ9gJ98rzE +wfLMCGq9R/TZM+lAEaLhzYZCu3X4QdhKxr1xZ/SFC+1f8KVuH4tLXORW30DwayPh +NxnrOvup4pWLiYuXUSZpV9CGMvPSUCW2odhMkBMKqaTTPjxoXJIcgacyprkNgIq4 +8cSvqWG/e/HrMRtkqvFbD5ta00uO1mlpajYYw1RRftEwktFo8vQgDBo9NT/EqoE7 +2tffaDnLq6rQrVtw4Kr9fy775DjNAWXyiCBjnJgOQSXCGPsM/AEdFrh/LKQQv2M/ +M7WNevnEUgsEIwIDAQABozwwOjAZBgNVHREEEjAQgQ5ub2JvZHlAZXhhbXBsZTAd +BgNVHQ4EFgQUYPwS8g98+4Tq/8gcEK1iilkGXH4wDQYJKoZIhvcNAQELBQADggEB +AJacpAT2GQQn5Rmb/LYaPhguWFHEdjHBO6rU0p7tE8QJW5pwMgim0mFtQlbuXE2L +mbHrYCyRgVyaPV9gNiFg1sLzQMmmG4Afg1N4cpdg8zLZFZho+eyYGRkH+EtrAN0Q +l8l603zovMXj8q8Q1eeurxkDHA6mDgwwMGiBQgAiPixQVOjvL+5M5PkwNw/kVzjA +0EXumGQkeZ1jUAkVjp7uWbyoVatamUcpYvo51NQQQeuqwzdo2oDYLa27axWxaqj2 +m4TKsz2WnnrSnrpq3NnflXfWcOrnXI3odNlhQoPmtZQVt6P8pNbGrx4XD/WTGkGw +i/6jlkwwjK7A7dSepfnTI4Y= -----END CERTIFICATE----- diff --git a/test/rubygems/wrong_key_cert_32.pem b/test/rubygems/wrong_key_cert_32.pem index 7a3bb9f7148418..aca829ab4487b0 100644 --- a/test/rubygems/wrong_key_cert_32.pem +++ b/test/rubygems/wrong_key_cert_32.pem @@ -1,19 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDCzCCAfOgAwIBAgIBEzANBgkqhkiG9w0BAQUFADAqMQ8wDQYDVQQDDAZub2Jv +MIIDCzCCAfOgAwIBAgIBEzANBgkqhkiG9w0BAQsFADAqMQ8wDQYDVQQDDAZub2Jv ZHkxFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMB4XDTEyMDEwMTAwMDAwMFoXDTM4 MDExOTAzMTQwN1owKjEPMA0GA1UEAwwGbm9ib2R5MRcwFQYKCZImiZPyLGQBGRYH -ZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL2UIqQWtcR9 -zPTqJ5K1GIRmXl/VBwHCYXuoyW1K/7h15IdU7thEVjZ25ZvObqagX48mRJynq+7g -XMMJJL5orFYAvLgRAsprAcbhCMNK34imBJy7tAekolhWM93WD0vdmwSu1ZLNv5Dc -l1JiyxqGd4nditHiuQvwCdI/qfODqj51YcpbI62Zl3yGa4e5ZB4YAiK8z3n4xN6T -paIv7c+n4dpLW9BWCkDH8Hk9wWtkzHn5RtdzxDlvNAA+cNEx8Q7rRhtMzzQg8gxK -E+1FNWtwd0TB2LlMRJNRlBGFqvS+mukjKWSElk0qQqdFsNUAeeTzjYggp/qOr3CM -uOoyO9XQEwECAwEAAaM8MDowGQYDVR0RBBIwEIEObm9ib2R5QGV4YW1wbGUwHQYD -VR0OBBYEFMr5/xcHGZwOwJMz45qKKAeP7SoHMA0GCSqGSIb3DQEBBQUAA4IBAQCU -VkESWkNeiJ1L3MfkMl2ybP2QPWP5nlhz+NOqwOCJSmEXF86Dq2XTY/GgSu1iPp4s -pPm1RSpnjujtiV7gjCziNif/XqAxeSjU2deApvq4mknyk958N0IS8c86dUXms1DQ -Rncmb3pxxvzP1d6Is35Uwoc5KqheJWR3aDwE8ejaFfO8pq/ncUDB25bc7OyslHMJ -7Ah+2YlFjvHYuPvN8bP44UMYyAPZCCJnjIPn7m7giyQiIo6SA9aiLQ8F7+NN3SU4 -7I9ED0F7RTDxNYISr1sLZ7aNtnXkTAnZclwKohuGfZD3OGAOshLZZXIB2pIRr/Kj -6zxTef39tli6orheYQXp +ZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKXmxpuzTp8f +g7VhtcULCQX038DZWb382OtZ5WXHK4VOr8dAJ2DYg2QBtyf4BUJmGfYCffK8xMHy +zAhqvUf02TPpQBGi4c2GQrt1+EHYSsa9cWf0hQvtX/Clbh+LS1zkVt9A8Gsj4TcZ +6zr7qeKVi4mLl1EmaVfQhjLz0lAltqHYTJATCqmk0z48aFySHIGnMqa5DYCKuPHE +r6lhv3vx6zEbZKrxWw+bWtNLjtZpaWo2GMNUUX7RMJLRaPL0IAwaPTU/xKqBO9rX +32g5y6uq0K1bcOCq/X8u++Q4zQFl8oggY5yYDkElwhj7DPwBHRa4fyykEL9jPzO1 +jXr5xFILBCMCAwEAAaM8MDowGQYDVR0RBBIwEIEObm9ib2R5QGV4YW1wbGUwHQYD +VR0OBBYEFGD8EvIPfPuE6v/IHBCtYopZBlx+MA0GCSqGSIb3DQEBCwUAA4IBAQBE +lq/rPaPT+5uui42u4BTFayrQU9EFik9xPG6WJw+IJ/5CprECj6h90FC+GaMNeu2Z +R0l+iEfgx4xBM4DERiRVLZIlHbZzuPp0YRYH9gyJot/+0piaAcnUEvjz2Z8axoFq +lE3/q4s6Yw8xdqwxvc5kiwymv2nEm4+v5w6Pb3K/fP/QQLvDUBWrBUMHPgdYXYk2 +zvc58BBwgGDSpFRO0tw+lnqMTM1y+fbpfuvP9TY1m4y13nuw/g7KxVxYolAWVQs3 +TptnJqqzEwdFa2S9BidUIlDRRY8cuhY6R3DM6THNLjR3c1oyf04nhT3sd/ilAJdD +YjnEtcLlkjxZyLLoWjn2 -----END CERTIFICATE----- diff --git a/test/test_delegate.rb b/test/test_delegate.rb index 57480b18ea674c..431d134f0f258a 100644 --- a/test/test_delegate.rb +++ b/test/test_delegate.rb @@ -29,6 +29,18 @@ def test_delegate_class_block assert_equal(1, klass.new([1]).foo) end + def test_delegate_class_block_with_override + warning = EnvUtil.verbose_warning do + klass = DelegateClass(Array) do + def first + super.inspect + end + end + assert_equal("1", klass.new([1]).first) + end + assert_empty(warning) + end + def test_systemcallerror_eq e = SystemCallError.new(0) assert((SimpleDelegator.new(e) == e) == (e == SimpleDelegator.new(e)), "[ruby-dev:34808]") diff --git a/test/test_pp.rb b/test/test_pp.rb index 9cef555d79f0d8..4fcb8df4b0241e 100644 --- a/test/test_pp.rb +++ b/test/test_pp.rb @@ -152,6 +152,15 @@ def test_struct assert_equal("#{a.inspect}\n", PP.pp(a, ''.dup)) end + if "3.2" <= RUBY_VERSION + D = Data.define(:aaa, :bbb) + def test_data + a = D.new("aaa", "bbb") + assert_equal("#\n", PP.pp(a, ''.dup, 20)) + assert_equal("#{a.inspect}\n", PP.pp(a, ''.dup)) + end + end + def test_object a = Object.new a.instance_eval {@a = a} diff --git a/test/uri/test_generic.rb b/test/uri/test_generic.rb index fdb405e396991e..3897c3d6eed38a 100644 --- a/test/uri/test_generic.rb +++ b/test/uri/test_generic.rb @@ -24,7 +24,8 @@ def test_to_s assert_equal "file:///foo", URI("file:///foo").to_s assert_equal "postgres:///foo", URI("postgres:///foo").to_s - assert_equal "http:/foo", URI("http:///foo").to_s + assert_equal "http:///foo", URI("http:///foo").to_s + assert_equal "http:/foo", URI("http:/foo").to_s end def test_parse @@ -157,6 +158,12 @@ def test_parse assert_equal(nil, url.user) assert_equal(nil, url.password) assert_equal(nil, url.userinfo) + + # sec-156615 + url = URI.parse('http:////example.com') + # must be empty string to identify as path-abempty, not path-absolute + assert_equal('', url.host) + assert_equal('http:////example.com', url.to_s) end def test_parse_scheme_with_symbols diff --git a/test/uri/test_ldap.rb b/test/uri/test_ldap.rb index 64845e487ac3e3..2625b241030965 100644 --- a/test/uri/test_ldap.rb +++ b/test/uri/test_ldap.rb @@ -39,7 +39,7 @@ def test_parse # from RFC2255, section 6. { 'ldap:///o=University%20of%20Michigan,c=US' => - ['ldap', nil, URI::LDAP::DEFAULT_PORT, + ['ldap', '', URI::LDAP::DEFAULT_PORT, 'o=University%20of%20Michigan,c=US', nil, nil, nil, nil], @@ -74,12 +74,12 @@ def test_parse nil, '(int=%5c00%5c00%5c00%5c04)', nil, nil], 'ldap:///??sub??bindname=cn=Manager%2co=Foo' => - ['ldap', nil, URI::LDAP::DEFAULT_PORT, + ['ldap', '', URI::LDAP::DEFAULT_PORT, '', nil, 'sub', nil, 'bindname=cn=Manager%2co=Foo'], 'ldap:///??sub??!bindname=cn=Manager%2co=Foo' => - ['ldap', nil, URI::LDAP::DEFAULT_PORT, + ['ldap', '', URI::LDAP::DEFAULT_PORT, '', nil, 'sub', nil, '!bindname=cn=Manager%2co=Foo'], }.each do |url2, ary| diff --git a/test/uri/test_parser.rb b/test/uri/test_parser.rb index f8e9299d098b5a..72fb5901d963f6 100644 --- a/test/uri/test_parser.rb +++ b/test/uri/test_parser.rb @@ -72,4 +72,11 @@ def test_unescape assert_equal("\u3042", p1.unescape('%e3%81%82'.force_encoding(Encoding::US_ASCII))) assert_equal("\xe3\x83\x90\xe3\x83\x90", p1.unescape("\xe3\x83\x90%e3%83%90")) end + + def test_split + assert_equal(["http", nil, "example.com", nil, nil, "", nil, nil, nil], URI.split("http://example.com")) + assert_equal(["http", nil, "[0::0]", nil, nil, "", nil, nil, nil], URI.split("http://[0::0]")) + assert_equal([nil, nil, "example.com", nil, nil, "", nil, nil, nil], URI.split("//example.com")) + assert_equal([nil, nil, "[0::0]", nil, nil, "", nil, nil, nil], URI.split("//[0::0]")) + end end diff --git a/thread_pthread.c b/thread_pthread.c index c29c7e195806e7..aa5435aa99a5fa 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -1861,7 +1861,8 @@ native_thread_native_thread_id(rb_thread_t *target_th) return INT2FIX(tid); #elif defined(__APPLE__) uint64_t tid; -# if ((MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6) || \ +# if (!defined(MAC_OS_X_VERSION_10_6) || \ + (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6) || \ defined(__POWERPC__) /* never defined for PowerPC platforms */) const bool no_pthread_threadid_np = true; # define NO_PTHREAD_MACH_THREAD_NP 1 diff --git a/thread_sync.c b/thread_sync.c index 4ae404ec055bb7..388853446861ad 100644 --- a/thread_sync.c +++ b/thread_sync.c @@ -1029,13 +1029,19 @@ static VALUE queue_do_pop(VALUE self, struct rb_queue *q, int should_block, VALUE timeout) { check_array(self, q->que); - rb_hrtime_t end = queue_timeout2hrtime(timeout); - - while (RARRAY_LEN(q->que) == 0) { + if (RARRAY_LEN(q->que) == 0) { if (!should_block) { rb_raise(rb_eThreadError, "queue empty"); } - else if (queue_closed_p(self)) { + + if (RTEST(rb_equal(INT2FIX(0), timeout))) { + return Qnil; + } + } + + rb_hrtime_t end = queue_timeout2hrtime(timeout); + while (RARRAY_LEN(q->que) == 0) { + if (queue_closed_p(self)) { return queue_closed_result(self, q); } else { @@ -1232,16 +1238,22 @@ rb_szqueue_max_set(VALUE self, VALUE vmax) static VALUE rb_szqueue_push(rb_execution_context_t *ec, VALUE self, VALUE object, VALUE non_block, VALUE timeout) { - rb_hrtime_t end = queue_timeout2hrtime(timeout); - bool timed_out = false; struct rb_szqueue *sq = szqueue_ptr(self); - while (queue_length(self, &sq->q) >= sq->max) { + if (queue_length(self, &sq->q) >= sq->max) { if (RTEST(non_block)) { rb_raise(rb_eThreadError, "queue full"); } - else if (queue_closed_p(self)) { - break; + + if (RTEST(rb_equal(INT2FIX(0), timeout))) { + return Qnil; + } + } + + rb_hrtime_t end = queue_timeout2hrtime(timeout); + while (queue_length(self, &sq->q) >= sq->max) { + if (queue_closed_p(self)) { + raise_closed_queue_error(self); } else { rb_execution_context_t *ec = GET_EC(); @@ -1262,18 +1274,11 @@ rb_szqueue_push(rb_execution_context_t *ec, VALUE self, VALUE object, VALUE non_ }; rb_ensure(queue_sleep, (VALUE)&queue_sleep_arg, szqueue_sleep_done, (VALUE)&queue_waiter); if (!NIL_P(timeout) && rb_hrtime_now() >= end) { - timed_out = true; - break; + return Qnil; } } } - if (queue_closed_p(self)) { - raise_closed_queue_error(self); - } - - if (timed_out) return Qnil; - return queue_do_push(self, &sq->q, object); } diff --git a/thread_sync.rb b/thread_sync.rb index 7e4c341ad0c65e..f8fa69900b39d0 100644 --- a/thread_sync.rb +++ b/thread_sync.rb @@ -10,7 +10,7 @@ class Queue # +ThreadError+ is raised. # # If +timeout+ seconds have passed and no data is available +nil+ is - # returned. + # returned. If +timeout+ is +0+ it returns immediately. def pop(non_block = false, timeout: nil) if non_block && timeout raise ArgumentError, "can't set a timeout if non_block is enabled" @@ -32,7 +32,7 @@ class SizedQueue # suspended, and +ThreadError+ is raised. # # If +timeout+ seconds have passed and no data is available +nil+ is - # returned. + # returned. If +timeout+ is +0+ it returns immediately. def pop(non_block = false, timeout: nil) if non_block && timeout raise ArgumentError, "can't set a timeout if non_block is enabled" @@ -54,7 +54,7 @@ def pop(non_block = false, timeout: nil) # thread isn't suspended, and +ThreadError+ is raised. # # If +timeout+ seconds have passed and no space is available +nil+ is - # returned. + # returned. If +timeout+ is +0+ it returns immediately. # Otherwise it returns +self+. def push(object, non_block = false, timeout: nil) if non_block && timeout diff --git a/time.c b/time.c index b3ad4159352e66..b16a0865378ce7 100644 --- a/time.c +++ b/time.c @@ -4030,7 +4030,7 @@ static VALUE strftime_cstr(const char *fmt, size_t len, VALUE time, rb_encoding * Returns a string representation of +self+, * formatted by strftime('%a %b %e %T %Y') * or its shorthand version strftime('%c'); - * see {Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html]: + * see {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]: * * t = Time.new(2000, 12, 31, 23, 59, 59, 0.5) * t.ctime # => "Sun Dec 31 23:59:59 2000" diff --git a/tool/file2lastrev.rb b/tool/file2lastrev.rb index 09cb9599327029..94c2b2a9d6c480 100755 --- a/tool/file2lastrev.rb +++ b/tool/file2lastrev.rb @@ -26,19 +26,11 @@ def self.output=(output) OptionParser.new {|opts| opts.banner << " paths..." vcs_options = VCS.define_options(opts) - new_vcs = proc do |path| - begin - vcs = VCS.detect(path, vcs_options, opts.new) - rescue VCS::NotFoundError => e - abort "#{File.basename(Program)}: #{e.message}" unless @suppress_not_found - opts.remove - nil - end - end + srcdir = nil opts.new opts.on("--srcdir=PATH", "use PATH as source directory") do |path| - abort "#{File.basename(Program)}: srcdir is already set" if vcs - new_vcs[path] + abort "#{File.basename(Program)}: srcdir is already set" if srcdir + srcdir = path end opts.on("--changed", "changed rev") do self.output = :changed @@ -60,10 +52,11 @@ def self.output=(output) @suppress_not_found = true end opts.order! rescue abort "#{File.basename(Program)}: #{$!}\n#{opts}" - if vcs - vcs.set_options(vcs_options) # options after --srcdir - elsif new_vcs["."] - else @suppress_not_found + begin + vcs = VCS.detect(srcdir || ".", vcs_options, opts.new) + rescue VCS::NotFoundError => e + abort "#{File.basename(Program)}: #{e.message}" unless @suppress_not_found + opts.remove (vcs = VCS::Null.new(nil)).set_options(vcs_options) end } diff --git a/tool/gen-mailmap.rb b/tool/gen-mailmap.rb index 27b7abf8de0929..df1884520c0c60 100755 --- a/tool/gen-mailmap.rb +++ b/tool/gen-mailmap.rb @@ -3,7 +3,7 @@ require "open-uri" require "yaml" -EMAIL_YML_URL = "https://cdn.jsdelivr.net/gh/ruby/ruby-commit-hook/config/email.yml" +EMAIL_YML_URL = "https://cdn.jsdelivr.net/gh/ruby/git.ruby-lang.org/config/email.yml" email_yml = URI(EMAIL_YML_URL).read.sub(/\A(?:#.*\n)+/, "").gsub(/^# +(.+)$/) { $1 + ": []" } diff --git a/tool/mjit/bindgen.rb b/tool/mjit/bindgen.rb index d0f9bf527bf4c3..77b81814e3e68d 100755 --- a/tool/mjit/bindgen.rb +++ b/tool/mjit/bindgen.rb @@ -341,12 +341,17 @@ def push_target(target) VM_METHOD_TYPE_CFUNC VM_METHOD_TYPE_ISEQ ], + ULONG: %w[ + INVALID_SHAPE_ID + SHAPE_MASK + ], }, types: %w[ CALL_DATA IC IVC RB_BUILTIN + attr_index_t compile_branch compile_status inlined_call_context @@ -360,10 +365,10 @@ def push_target(target) rb_callable_method_entry_struct rb_callcache rb_callinfo - rb_cref_t rb_control_frame_t - rb_execution_context_t + rb_cref_t rb_execution_context_struct + rb_execution_context_t rb_iseq_constant_body rb_iseq_location_t rb_iseq_struct @@ -375,9 +380,12 @@ def push_target(target) rb_mjit_compile_info rb_mjit_unit rb_serial_t + rb_shape + rb_shape_t ], dynamic_types: %w[ VALUE + shape_id_t ], skip_fields: { 'rb_execution_context_struct.machine': %w[regs], # differs between macOS and Linux diff --git a/tool/sync_default_gems.rb b/tool/sync_default_gems.rb index 1e8c086dcf1409..d7151af7012872 100755 --- a/tool/sync_default_gems.rb +++ b/tool/sync_default_gems.rb @@ -84,6 +84,30 @@ def pipe_readlines(args, rs: "\0", chomp: true) end end +def replace_rdoc_ref(file) + src = File.binread(file) + src.gsub!(%r[\[\Khttps://docs\.ruby-lang\.org/en/master(?:/doc)?/(([A-Z]\w+(?:/[A-Z]\w+)*)|\w+_rdoc)\.html(\#\S+)?(?=\])]) do + name, mod, label = $1, $2, $3 + mod &&= mod.gsub('/', '::') + if label && (m = label.match(/\A\#(?:method-([ci])|(?:(?:class|module)-#{mod}-)?label)-([-+\w]+)\z/)) + scope, label = m[1], m[2] + scope = scope ? scope.tr('ci', '.#') : '@' + end + "rdoc-ref:#{mod || name.chomp("_rdoc") + ".rdoc"}#{scope}#{label}" + end or return false + File.rename(file, file + "~") + File.binwrite(file, src) + return true +end + +def replace_rdoc_ref_all + result = pipe_readlines(%W"git status porcelain -z -- *.c *.rb *.rdoc") + result.map! {|line| line[/\A.M (.*)/, 1]} + result.compact! + result = pipe_readlines(%W"git grep -z -l -F [https://docs.ruby-lang.org/en/master/ --" + result) + result.inject(false) {|changed, file| changed | replace_rdoc_ref(file)} +end + # We usually don't use this. Please consider using #sync_default_gems_with_commits instead. def sync_default_gems(gem) repo = REPOSITORIES[gem.to_sym] @@ -382,6 +406,7 @@ def sync_default_gems(gem) else sync_lib gem, upstream end + replace_rdoc_ref_all end IGNORE_FILE_PATTERN = @@ -397,16 +422,33 @@ def message_filter(repo, sha) log = STDIN.read log.delete!("\r") url = "https://github.com/#{repo}" - print "[#{repo}] ", log.gsub(/\b(?:(?i:fix(?:e[sd])?) +|GH-)\K#(?=\d+\b)|\(\K#(?=\d+\))/) { - "#{url}/pull/" - }.gsub(%r{(? 68 + subject.gsub!(/\G.{,67}[^\s.,][.,]*\K\s+/, "\n") + end + end + if log + conv[log] + log.sub!(/\s*(?=(?i:\nCo-authored-by:.*)*\Z)/) { + "\n\n" "#{url}/commit/#{sha[0,10]}\n" + } + end + print subject, "\n\n", log end -# NOTE: This method is also used by ruby-commit-hook/bin/update-default-gem.sh +# NOTE: This method is also used by GitHub ruby/git.ruby-lang.org's bin/update-default-gem.sh # @param gem [String] A gem name, also used as a git remote name. REPOSITORIES converts it to the appropriate GitHub repository. # @param ranges [Array] "before..after". Note that it will NOT sync "before" (but commits after that). # @param edit [TrueClass] Set true if you want to resolve conflicts. Obviously, update-default-gem.sh doesn't use this. @@ -478,13 +520,13 @@ def sync_default_gems_with_commits(gem, ranges, edit: nil) skipped = true elsif /^CONFLICT/ =~ result result = pipe_readlines(%W"git status --porcelain -z") - result.map! {|line| line[/^.U (.*)/, 1]} + result.map! {|line| line[/\A.U (.*)/, 1]} result.compact! ignore, conflict = result.partition {|name| IGNORE_FILE_PATTERN =~ name} unless ignore.empty? system(*%W"git reset HEAD --", *ignore) File.unlink(*ignore) - ignore = pipe_readlines(%W"git status --porcelain -z" + ignore).map! {|line| line[/^.. (.*)/, 1]} + ignore = pipe_readlines(%W"git status --porcelain -z" + ignore).map! {|line| line[/\A.. (.*)/, 1]} system(*%W"git checkout HEAD --", *ignore) unless ignore.empty? end unless conflict.empty? @@ -508,6 +550,10 @@ def sync_default_gems_with_commits(gem, ranges, edit: nil) next end + if replace_rdoc_ref_all + `git commit --amend --no-edit` + end + puts "Update commit message: #{sha}" IO.popen(%W[git filter-branch -f --msg-filter #{[filter, repo, sha].join(' ')} -- HEAD~1..HEAD], &:read) @@ -613,6 +659,17 @@ def update_default_gems(gem, release: false) abort unless ARGV.size == 2 message_filter(*ARGV) exit +when "rdoc-ref" + ARGV.shift + pattern = ARGV.empty? ? %w[*.c *.rb *.rdoc] : ARGV + result = pipe_readlines(%W"git grep -z -l -F [https://docs.ruby-lang.org/en/master/ --" + pattern) + result.inject(false) do |changed, file| + if replace_rdoc_ref(file) + puts "replaced rdoc-ref in #{file}" + changed = true + end + changed + end when nil, "-h", "--help" puts <<-HELP \e[1mSync with upstream code of default libraries\e[0m diff --git a/variable.c b/variable.c index 056a1000b8edee..8d329d7900e23d 100644 --- a/variable.c +++ b/variable.c @@ -34,6 +34,7 @@ #include "ruby/st.h" #include "ruby/util.h" #include "transient_heap.h" +#include "shape.h" #include "variable.h" #include "vm_core.h" #include "ractor_core.h" @@ -63,12 +64,9 @@ static VALUE rb_const_search(VALUE klass, ID id, int exclude, int recurse, int v static st_table *generic_iv_tbl_; struct ivar_update { - union { - st_table *iv_index_tbl; - struct gen_ivtbl *ivtbl; - } u; - st_data_t index; - int iv_extended; + struct gen_ivtbl *ivtbl; + uint32_t iv_index; + rb_shape_t* shape; }; void @@ -896,30 +894,6 @@ rb_alias_variable(ID name1, ID name2) entry1->var = entry2->var; } -static bool -iv_index_tbl_lookup(struct st_table *tbl, ID id, uint32_t *indexp) -{ - st_data_t ent_data; - int r; - - if (tbl == NULL) return false; - - RB_VM_LOCK_ENTER(); - { - r = st_lookup(tbl, (st_data_t)id, &ent_data); - } - RB_VM_LOCK_LEAVE(); - - if (r) { - struct rb_iv_index_tbl_entry *ent = (void *)ent_data; - *indexp = ent->index; - return true; - } - else { - return false; - } -} - static void IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(ID id) { @@ -957,7 +931,20 @@ generic_ivtbl_no_ractor_check(VALUE obj) } static int -gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl) +gen_ivtbl_get_unlocked(VALUE obj, ID id, struct gen_ivtbl **ivtbl) +{ + st_data_t data; + + if (st_lookup(generic_ivtbl(obj, id, false), (st_data_t)obj, &data)) { + *ivtbl = (struct gen_ivtbl *)data; + return 1; + } + + return 0; +} + +MJIT_FUNC_EXPORTED int +rb_gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl) { st_data_t data; int r = 0; @@ -977,63 +964,7 @@ gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl) MJIT_FUNC_EXPORTED int rb_ivar_generic_ivtbl_lookup(VALUE obj, struct gen_ivtbl **ivtbl) { - return gen_ivtbl_get(obj, 0, ivtbl); -} - -MJIT_FUNC_EXPORTED VALUE -rb_ivar_generic_lookup_with_index(VALUE obj, ID id, uint32_t index) -{ - struct gen_ivtbl *ivtbl; - - if (gen_ivtbl_get(obj, id, &ivtbl)) { - if (LIKELY(index < ivtbl->numiv)) { - VALUE val = ivtbl->ivptr[index]; - return val; - } - } - - return Qundef; -} - -static VALUE -generic_ivar_delete(VALUE obj, ID id, VALUE undef) -{ - struct gen_ivtbl *ivtbl; - - if (gen_ivtbl_get(obj, id, &ivtbl)) { - st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj)); - uint32_t index; - - if (iv_index_tbl && iv_index_tbl_lookup(iv_index_tbl, id, &index)) { - if (index < ivtbl->numiv) { - VALUE ret = ivtbl->ivptr[index]; - - ivtbl->ivptr[index] = Qundef; - return ret == Qundef ? undef : ret; - } - } - } - return undef; -} - -static VALUE -generic_ivar_get(VALUE obj, ID id, VALUE undef) -{ - struct gen_ivtbl *ivtbl; - - if (gen_ivtbl_get(obj, id, &ivtbl)) { - st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj)); - uint32_t index; - - if (iv_index_tbl && iv_index_tbl_lookup(iv_index_tbl, id, &index)) { - if (index < ivtbl->numiv) { - VALUE ret = ivtbl->ivptr[index]; - - return ret == Qundef ? undef : ret; - } - } - } - return undef; + return rb_gen_ivtbl_get(obj, 0, ivtbl); } static size_t @@ -1045,6 +976,8 @@ gen_ivtbl_bytes(size_t n) static struct gen_ivtbl * gen_ivtbl_resize(struct gen_ivtbl *old, uint32_t n) { + RUBY_ASSERT(n > 0); + uint32_t len = old ? old->numiv : 0; struct gen_ivtbl *ivtbl = xrealloc(old, gen_ivtbl_bytes(n)); @@ -1069,18 +1002,6 @@ gen_ivtbl_dup(const struct gen_ivtbl *orig) } #endif -static uint32_t -iv_index_tbl_newsize(struct ivar_update *ivup) -{ - if (!ivup->iv_extended) { - return (uint32_t)ivup->u.iv_index_tbl->num_entries; - } - else { - uint32_t index = (uint32_t)ivup->index; /* should not overflow */ - return (index+1) + (index+1)/4; /* (index+1)*1.25 */ - } -} - static int generic_ivar_update(st_data_t *k, st_data_t *v, st_data_t u, int existing) { @@ -1091,53 +1012,22 @@ generic_ivar_update(st_data_t *k, st_data_t *v, st_data_t u, int existing) if (existing) { ivtbl = (struct gen_ivtbl *)*v; - if (ivup->index < ivtbl->numiv) { - ivup->u.ivtbl = ivtbl; + if (ivup->iv_index < ivtbl->numiv) { + ivup->ivtbl = ivtbl; return ST_STOP; } } FL_SET((VALUE)*k, FL_EXIVAR); - uint32_t newsize = iv_index_tbl_newsize(ivup); - ivtbl = gen_ivtbl_resize(ivtbl, newsize); + ivtbl = gen_ivtbl_resize(ivtbl, ivup->shape->iv_count); + // Reinsert in to the hash table because ivtbl might be a newly resized chunk of memory *v = (st_data_t)ivtbl; - ivup->u.ivtbl = ivtbl; + ivup->ivtbl = ivtbl; +#if !SHAPE_IN_BASIC_FLAGS + ivtbl->shape_id = rb_shape_id(ivup->shape); +#endif return ST_CONTINUE; } -static VALUE -generic_ivar_defined(VALUE obj, ID id) -{ - struct gen_ivtbl *ivtbl; - st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj)); - uint32_t index; - - if (!iv_index_tbl_lookup(iv_index_tbl, id, &index)) return Qfalse; - if (!gen_ivtbl_get(obj, id, &ivtbl)) return Qfalse; - - return RBOOL((index < ivtbl->numiv) && (ivtbl->ivptr[index] != Qundef)); -} - -static int -generic_ivar_remove(VALUE obj, ID id, VALUE *valp) -{ - struct gen_ivtbl *ivtbl; - uint32_t index; - st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj)); - - if (!iv_index_tbl) return 0; - if (!iv_index_tbl_lookup(iv_index_tbl, id, &index)) return 0; - if (!gen_ivtbl_get(obj, id, &ivtbl)) return 0; - - if (index < ivtbl->numiv) { - if (ivtbl->ivptr[index] != Qundef) { - *valp = ivtbl->ivptr[index]; - ivtbl->ivptr[index] = Qundef; - return 1; - } - } - return 0; -} - static void gen_ivtbl_mark(const struct gen_ivtbl *ivtbl) { @@ -1153,7 +1043,7 @@ rb_mark_generic_ivar(VALUE obj) { struct gen_ivtbl *ivtbl; - if (gen_ivtbl_get(obj, 0, &ivtbl)) { + if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) { gen_ivtbl_mark(ivtbl); } } @@ -1182,11 +1072,35 @@ rb_generic_ivar_memsize(VALUE obj) { struct gen_ivtbl *ivtbl; - if (gen_ivtbl_get(obj, 0, &ivtbl)) + if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) return gen_ivtbl_bytes(ivtbl->numiv); return 0; } +#if !SHAPE_IN_BASIC_FLAGS +MJIT_FUNC_EXPORTED shape_id_t +rb_generic_shape_id(VALUE obj) +{ + struct gen_ivtbl *ivtbl = 0; + shape_id_t shape_id = 0; + + RB_VM_LOCK_ENTER(); + { + st_table* global_iv_table = generic_ivtbl(obj, 0, false); + + if (global_iv_table && st_lookup(global_iv_table, obj, (st_data_t *)&ivtbl)) { + shape_id = ivtbl->shape_id; + } + else if (OBJ_FROZEN(obj)) { + shape_id = FROZEN_ROOT_SHAPE_ID; + } + } + RB_VM_LOCK_LEAVE(); + + return shape_id; +} +#endif + static size_t gen_ivtbl_count(const struct gen_ivtbl *ivtbl) { @@ -1254,23 +1168,16 @@ VALUE rb_ivar_lookup(VALUE obj, ID id, VALUE undef) { if (SPECIAL_CONST_P(obj)) return undef; + + shape_id_t shape_id; + VALUE * ivar_list; + rb_shape_t * shape; + +#if SHAPE_IN_BASIC_FLAGS + shape_id = RBASIC_SHAPE_ID(obj); +#endif + switch (BUILTIN_TYPE(obj)) { - case T_OBJECT: - { - uint32_t index; - uint32_t len = ROBJECT_NUMIV(obj); - VALUE *ptr = ROBJECT_IVPTR(obj); - VALUE val; - - if (iv_index_tbl_lookup(ROBJECT_IV_INDEX_TBL(obj), id, &index) && - index < len && - (val = ptr[index]) != Qundef) { - return val; - } - else { - break; - } - } case T_CLASS: case T_MODULE: { @@ -1287,14 +1194,37 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef) return val; } else { - break; + return undef; } } + case T_OBJECT: + { +#if !SHAPE_IN_BASIC_FLAGS + shape_id = ROBJECT_SHAPE_ID(obj); +#endif + ivar_list = ROBJECT_IVPTR(obj); + break; + } default: - if (FL_TEST(obj, FL_EXIVAR)) - return generic_ivar_get(obj, id, undef); + if (FL_TEST_RAW(obj, FL_EXIVAR)) { + struct gen_ivtbl *ivtbl; + rb_gen_ivtbl_get(obj, id, &ivtbl); +#if !SHAPE_IN_BASIC_FLAGS + shape_id = ivtbl->shape_id; +#endif + ivar_list = ivtbl->ivptr; + } else { + return undef; + } break; } + + attr_index_t index = 0; + shape = rb_shape_get_shape_by_id(shape_id); + if (rb_shape_get_iv_index(shape, id, &index)) { + return ivar_list[index]; + } + return undef; } @@ -1315,26 +1245,12 @@ rb_attr_get(VALUE obj, ID id) static VALUE rb_ivar_delete(VALUE obj, ID id, VALUE undef) { - VALUE *ptr; - struct st_table *iv_index_tbl; - uint32_t len, index; - rb_check_frozen(obj); - switch (BUILTIN_TYPE(obj)) { - case T_OBJECT: - len = ROBJECT_NUMIV(obj); - ptr = ROBJECT_IVPTR(obj); - iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); - if (iv_index_tbl_lookup(iv_index_tbl, id, &index) && - index < len) { - VALUE val = ptr[index]; - ptr[index] = Qundef; - if (val != Qundef) { - return val; - } - } - break; + VALUE val = Qnil; + attr_index_t index; + + switch (BUILTIN_TYPE(obj)) { case T_CLASS: case T_MODULE: IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id); @@ -1345,11 +1261,33 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef) } } break; - default: - if (FL_TEST(obj, FL_EXIVAR)) - return generic_ivar_delete(obj, id, undef); + case T_OBJECT: { + rb_shape_t * shape = rb_shape_get_shape(obj); + if (rb_shape_get_iv_index(shape, id, &index)) { + rb_shape_transition_shape_remove_ivar(obj, id, shape); + val = ROBJECT_IVPTR(obj)[index]; + ROBJECT_IVPTR(obj)[index] = Qundef; + return val; + } + break; + } + default: { + rb_shape_t * shape = rb_shape_get_shape(obj); + + if (rb_shape_get_iv_index(shape, id, &index)) { + rb_shape_transition_shape_remove_ivar(obj, id, shape); + struct gen_ivtbl *ivtbl; + rb_gen_ivtbl_get(obj, id, &ivtbl); + val = ivtbl->ivptr[index]; + ivtbl->ivptr[index] = Qundef; + return val; + } + + break; + } } + return undef; } @@ -1359,67 +1297,31 @@ rb_attr_delete(VALUE obj, ID id) return rb_ivar_delete(obj, id, Qnil); } -static st_table * -iv_index_tbl_make(VALUE obj, VALUE klass) -{ - st_table *iv_index_tbl; - - if (UNLIKELY(!klass)) { - rb_raise(rb_eTypeError, "hidden object cannot have instance variables"); - } - - if ((iv_index_tbl = RCLASS_IV_INDEX_TBL(klass)) == NULL) { - RB_VM_LOCK_ENTER(); - if ((iv_index_tbl = RCLASS_IV_INDEX_TBL(klass)) == NULL) { - iv_index_tbl = RCLASS_IV_INDEX_TBL(klass) = st_init_numtable(); - } - RB_VM_LOCK_LEAVE(); - } - - return iv_index_tbl; -} - -static void -iv_index_tbl_extend(struct ivar_update *ivup, ID id, VALUE klass) -{ - ASSERT_vm_locking(); - st_data_t ent_data; - struct rb_iv_index_tbl_entry *ent; - - if (st_lookup(ivup->u.iv_index_tbl, (st_data_t)id, &ent_data)) { - ent = (void *)ent_data; - ivup->index = ent->index; - return; - } - if (ivup->u.iv_index_tbl->num_entries >= INT_MAX) { - rb_raise(rb_eArgError, "too many instance variables"); - } - ent = ALLOC(struct rb_iv_index_tbl_entry); - ent->index = ivup->index = (uint32_t)ivup->u.iv_index_tbl->num_entries; - ent->class_value = klass; - ent->class_serial = RCLASS_SERIAL(klass); - st_add_direct(ivup->u.iv_index_tbl, (st_data_t)id, (st_data_t)ent); - ivup->iv_extended = 1; -} - static void generic_ivar_set(VALUE obj, ID id, VALUE val) { - VALUE klass = rb_obj_class(obj); struct ivar_update ivup; - ivup.iv_extended = 0; - ivup.u.iv_index_tbl = iv_index_tbl_make(obj, klass); + // The returned shape will have `id` in its iv_table + rb_shape_t * shape = rb_shape_get_next(rb_shape_get_shape(obj), obj, id); + ivup.shape = shape; RB_VM_LOCK_ENTER(); { - iv_index_tbl_extend(&ivup, id, klass); - st_update(generic_ivtbl(obj, id, false), (st_data_t)obj, generic_ivar_update, - (st_data_t)&ivup); + attr_index_t ent_data; + if (rb_shape_get_iv_index(shape, id, &ent_data)) { + ivup.iv_index = (uint32_t) ent_data; + } + else { + rb_bug("unreachable. Shape was not found for id: %s", rb_id2name(id)); + } + + st_update(generic_ivtbl(obj, id, false), (st_data_t)obj, generic_ivar_update, (st_data_t)&ivup); } RB_VM_LOCK_LEAVE(); - ivup.u.ivtbl->ivptr[ivup.index] = val; + ivup.ivtbl->ivptr[ivup.iv_index] = val; + rb_shape_set_shape(obj, shape); RB_OBJ_WRITTEN(obj, Qundef, val); } @@ -1486,8 +1388,8 @@ rb_obj_transient_heap_evacuate(VALUE obj, int promote) } #endif -static void -init_iv_list(VALUE obj, uint32_t len, uint32_t newsize, st_table *index_tbl) +void +rb_ensure_iv_list_size(VALUE obj, uint32_t len, uint32_t newsize) { VALUE *ptr = ROBJECT_IVPTR(obj); VALUE *newptr; @@ -1510,70 +1412,141 @@ init_iv_list(VALUE obj, uint32_t len, uint32_t newsize, st_table *index_tbl) #else ROBJECT(obj)->as.heap.numiv = newsize; #endif - ROBJECT(obj)->as.heap.iv_index_tbl = index_tbl; -} - -void -rb_init_iv_list(VALUE obj) -{ - st_table *index_tbl = ROBJECT_IV_INDEX_TBL(obj); - uint32_t newsize = (uint32_t)index_tbl->num_entries; - uint32_t len = ROBJECT_NUMIV(obj); - init_iv_list(obj, len, newsize, index_tbl); } -// Retrieve or create the id-to-index mapping for a given object and an -// instance variable name. -static struct ivar_update -obj_ensure_iv_index_mapping(VALUE obj, ID id) +struct gen_ivtbl * +rb_ensure_generic_iv_list_size(VALUE obj, uint32_t newsize) { - VALUE klass = rb_obj_class(obj); - struct ivar_update ivup; - ivup.iv_extended = 0; - ivup.u.iv_index_tbl = iv_index_tbl_make(obj, klass); + struct gen_ivtbl * ivtbl = 0; RB_VM_LOCK_ENTER(); { - iv_index_tbl_extend(&ivup, id, klass); + if (UNLIKELY(!gen_ivtbl_get_unlocked(obj, 0, &ivtbl) || newsize > ivtbl->numiv)) { + ivtbl = gen_ivtbl_resize(ivtbl, newsize); + st_insert(generic_ivtbl_no_ractor_check(obj), (st_data_t)obj, (st_data_t)ivtbl); + FL_SET_RAW(obj, FL_EXIVAR); + } } RB_VM_LOCK_LEAVE(); - return ivup; + RUBY_ASSERT(ivtbl); + + return ivtbl; } -// Return the instance variable index for a given name and T_OBJECT object. The -// mapping between name and index lives on `rb_obj_class(obj)` and is created -// if not already present. -// // @note May raise when there are too many instance variables. -// @note YJIT uses this function at compile time to simplify the work needed to -// access the variable at runtime. -uint32_t -rb_obj_ensure_iv_index_mapping(VALUE obj, ID id) +void +rb_init_iv_list(VALUE obj) { - RUBY_ASSERT(RB_TYPE_P(obj, T_OBJECT)); - // This uint32_t cast shouldn't lose information as it's checked in - // iv_index_tbl_extend(). The index is stored as an uint32_t in - // struct rb_iv_index_tbl_entry. - return (uint32_t)obj_ensure_iv_index_mapping(obj, id).index; + uint32_t newsize = (uint32_t)(rb_shape_get_shape(obj)->iv_count * 2.0); + uint32_t len = ROBJECT_NUMIV(obj); + rb_ensure_iv_list_size(obj, len, newsize < len ? len : newsize); } static VALUE obj_ivar_set(VALUE obj, ID id, VALUE val) { - uint32_t len; - struct ivar_update ivup = obj_ensure_iv_index_mapping(obj, id); + attr_index_t index; + + // Get the current shape + rb_shape_t * shape = rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj)); + + if (!rb_shape_get_iv_index(shape, id, &index)) { + shape = rb_shape_get_next(shape, obj, id); + index = shape->iv_count - 1; + } + + uint32_t len = ROBJECT_NUMIV(obj); - len = ROBJECT_NUMIV(obj); - if (len <= ivup.index) { - uint32_t newsize = iv_index_tbl_newsize(&ivup); - init_iv_list(obj, len, newsize, ivup.u.iv_index_tbl); + // Reallocating can kick off GC. We can't set the new shape + // on this object until the buffer has been allocated, otherwise + // GC could read off the end of the buffer. + if (len <= index) { + uint32_t newsize = (uint32_t)((len + 1) * 1.25); + rb_ensure_iv_list_size(obj, len, newsize); } - RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[ivup.index], val); + RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[index], val); + rb_shape_set_shape(obj, shape); + + return val; +} + +/* Set the instance variable +val+ on object +obj+ at ivar name +id+. + * This function only works with T_OBJECT objects, so make sure + * +obj+ is of type T_OBJECT before using this function. + */ +VALUE +rb_vm_set_ivar_id(VALUE obj, ID id, VALUE val) +{ + rb_check_frozen_internal(obj); + obj_ivar_set(obj, id, val); return val; } +bool +rb_shape_set_shape_id(VALUE obj, shape_id_t shape_id) +{ + if (rb_shape_get_shape_id(obj) == shape_id) { + return false; + } + +#if SHAPE_IN_BASIC_FLAGS + RBASIC_SET_SHAPE_ID(obj, shape_id); +#else + switch (BUILTIN_TYPE(obj)) { + case T_OBJECT: + ROBJECT_SET_SHAPE_ID(obj, shape_id); + break; + case T_CLASS: + case T_MODULE: + { + RCLASS_EXT(obj)->shape_id = shape_id; + break; + } + default: + { + if (shape_id != FROZEN_ROOT_SHAPE_ID) { + struct gen_ivtbl *ivtbl = 0; + RB_VM_LOCK_ENTER(); + { + st_table* global_iv_table = generic_ivtbl(obj, 0, false); + + if (st_lookup(global_iv_table, obj, (st_data_t *)&ivtbl)) { + ivtbl->shape_id = shape_id; + } + else { + rb_bug("Expected shape_id entry in global iv table"); + } + } + RB_VM_LOCK_LEAVE(); + } + } + } +#endif + + return true; +} + +/** + * Prevents further modifications to the given object. ::rb_eFrozenError shall + * be raised if modification is attempted. + * + * @param[out] x Object in question. + */ +void rb_obj_freeze_inline(VALUE x) +{ + if (RB_FL_ABLE(x)) { + RB_OBJ_FREEZE_RAW(x); + + rb_shape_transition_shape_frozen(x); + + if (RBASIC_CLASS(x) && !(RBASIC(x)->flags & RUBY_FL_SINGLETON)) { + rb_freeze_singleton_class(x); + } + } +} + static void ivar_set(VALUE obj, ID id, VALUE val) { @@ -1581,10 +1554,14 @@ ivar_set(VALUE obj, ID id, VALUE val) switch (BUILTIN_TYPE(obj)) { case T_OBJECT: - obj_ivar_set(obj, id, val); - break; + { + obj_ivar_set(obj, id, val); + break; + } case T_CLASS: case T_MODULE: + // TODO: Transition shapes on classes + //rb_shape_transition_shape(obj, id, rb_shape_get_shape_by_id(RCLASS_SHAPE_ID(obj))); IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id); rb_class_ivar_set(obj, id, val); break; @@ -1614,161 +1591,86 @@ rb_ivar_set_internal(VALUE obj, ID id, VALUE val) VALUE rb_ivar_defined(VALUE obj, ID id) { - VALUE val; - struct st_table *iv_index_tbl; - uint32_t index; + attr_index_t index; if (SPECIAL_CONST_P(obj)) return Qfalse; switch (BUILTIN_TYPE(obj)) { - case T_OBJECT: - iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); - if (iv_index_tbl_lookup(iv_index_tbl, id, &index) && - index < ROBJECT_NUMIV(obj) && - (val = ROBJECT_IVPTR(obj)[index]) != Qundef) { - return Qtrue; - } - break; case T_CLASS: case T_MODULE: - if (RCLASS_IV_TBL(obj) && lock_st_is_member(RCLASS_IV_TBL(obj), (st_data_t)id)) + if (RCLASS_IV_TBL(obj) && lock_st_is_member(RCLASS_IV_TBL(obj), (st_data_t)id)) { return Qtrue; - break; + } + else { + return Qfalse; + } default: - if (FL_TEST(obj, FL_EXIVAR)) - return generic_ivar_defined(obj, id); - break; + return RBOOL(rb_shape_get_iv_index(rb_shape_get_shape(obj), id, &index)); } - return Qfalse; } typedef int rb_ivar_foreach_callback_func(ID key, VALUE val, st_data_t arg); st_data_t rb_st_nth_key(st_table *tab, st_index_t index); -static ID -iv_index_tbl_nth_id(st_table *iv_index_tbl, uint32_t index) -{ - st_data_t key; - RB_VM_LOCK_ENTER(); - { - key = rb_st_nth_key(iv_index_tbl, index); - } - RB_VM_LOCK_LEAVE(); - return (ID)key; -} - -static inline bool -ivar_each_i(st_table *iv_index_tbl, VALUE val, uint32_t i, rb_ivar_foreach_callback_func *func, st_data_t arg) -{ - if (val != Qundef) { - ID id = iv_index_tbl_nth_id(iv_index_tbl, i); - switch (func(id, val, arg)) { - case ST_CHECK: - case ST_CONTINUE: - break; - case ST_STOP: - return true; - default: - rb_bug("unreachable"); - } +static void +iterate_over_shapes_with_callback(rb_shape_t *shape, VALUE* iv_list, rb_ivar_foreach_callback_func *callback, st_data_t arg) { + switch ((enum shape_type)shape->type) { + case SHAPE_ROOT: + return; + case SHAPE_IVAR: + iterate_over_shapes_with_callback(rb_shape_get_shape_by_id(shape->parent_id), iv_list, callback, arg); + VALUE val = iv_list[shape->iv_count - 1]; + if (val != Qundef) { + callback(shape->edge_name, val, arg); + } + return; + case SHAPE_IVAR_UNDEF: + case SHAPE_FROZEN: + iterate_over_shapes_with_callback(rb_shape_get_shape_by_id(shape->parent_id), iv_list, callback, arg); + return; } - return false; } static void obj_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg) { - st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); - if (!iv_index_tbl) return; - uint32_t i=0; - - for (i=0; i < ROBJECT_NUMIV(obj); i++) { - VALUE val = ROBJECT_IVPTR(obj)[i]; - if (ivar_each_i(iv_index_tbl, val, i, func, arg)) { - return; - } - } + rb_shape_t* shape = rb_shape_get_shape(obj); + iterate_over_shapes_with_callback(shape, ROBJECT_IVPTR(obj), func, arg); } static void gen_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg) { + rb_shape_t *shape = rb_shape_get_shape(obj); struct gen_ivtbl *ivtbl; - st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj)); - if (!iv_index_tbl) return; - if (!gen_ivtbl_get(obj, 0, &ivtbl)) return; - - for (uint32_t i=0; inumiv; i++) { - VALUE val = ivtbl->ivptr[i]; - if (ivar_each_i(iv_index_tbl, val, i, func, arg)) { - return; - } - } -} - -struct givar_copy { - VALUE obj; - VALUE klass; - st_table *iv_index_tbl; - struct gen_ivtbl *ivtbl; -}; - -static int -gen_ivar_copy(ID id, VALUE val, st_data_t arg) -{ - struct givar_copy *c = (struct givar_copy *)arg; - struct ivar_update ivup; - - ivup.iv_extended = 0; - ivup.u.iv_index_tbl = c->iv_index_tbl; - - RB_VM_LOCK_ENTER(); - { - iv_index_tbl_extend(&ivup, id, c->klass); - } - RB_VM_LOCK_LEAVE(); - - if (ivup.index >= c->ivtbl->numiv) { - uint32_t newsize = iv_index_tbl_newsize(&ivup); - c->ivtbl = gen_ivtbl_resize(c->ivtbl, newsize); - } - c->ivtbl->ivptr[ivup.index] = val; + if (!rb_gen_ivtbl_get(obj, 0, &ivtbl)) return; - RB_OBJ_WRITTEN(c->obj, Qundef, val); - - return ST_CONTINUE; + iterate_over_shapes_with_callback(shape, ivtbl->ivptr, func, arg); } void rb_copy_generic_ivar(VALUE clone, VALUE obj) { - struct gen_ivtbl *ivtbl; + struct gen_ivtbl *obj_ivtbl; + struct gen_ivtbl *new_ivtbl; rb_check_frozen(clone); if (!FL_TEST(obj, FL_EXIVAR)) { goto clear; } - if (gen_ivtbl_get(obj, 0, &ivtbl)) { - struct givar_copy c; - uint32_t i; - if (gen_ivtbl_count(ivtbl) == 0) + if (rb_gen_ivtbl_get(obj, 0, &obj_ivtbl)) { + if (gen_ivtbl_count(obj_ivtbl) == 0) goto clear; - if (gen_ivtbl_get(clone, 0, &c.ivtbl)) { - for (i = 0; i < c.ivtbl->numiv; i++) - c.ivtbl->ivptr[i] = Qundef; - } - else { - c.ivtbl = gen_ivtbl_resize(0, ivtbl->numiv); - FL_SET(clone, FL_EXIVAR); + new_ivtbl = gen_ivtbl_resize(0, obj_ivtbl->numiv); + FL_SET(clone, FL_EXIVAR); + + for (uint32_t i=0; inumiv; i++) { + new_ivtbl->ivptr[i] = obj_ivtbl->ivptr[i]; + RB_OBJ_WRITTEN(clone, Qundef, &new_ivtbl[i]); } - VALUE klass = rb_obj_class(clone); - c.iv_index_tbl = iv_index_tbl_make(clone, klass); - c.obj = clone; - c.klass = klass; - gen_ivar_each(obj, gen_ivar_copy, (st_data_t)&c); /* * c.ivtbl may change in gen_ivar_copy due to realloc, * no need to free @@ -1776,9 +1678,17 @@ rb_copy_generic_ivar(VALUE clone, VALUE obj) RB_VM_LOCK_ENTER(); { generic_ivtbl_no_ractor_check(clone); - st_insert(generic_ivtbl_no_ractor_check(obj), (st_data_t)clone, (st_data_t)c.ivtbl); + st_insert(generic_ivtbl_no_ractor_check(obj), (st_data_t)clone, (st_data_t)new_ivtbl); } RB_VM_LOCK_LEAVE(); + + rb_shape_t * obj_shape = rb_shape_get_shape(obj); + if (rb_shape_frozen_shape_p(obj_shape)) { + rb_shape_set_shape_id(clone, obj_shape->parent_id); + } + else { + rb_shape_set_shape(clone, obj_shape); + } } return; @@ -1846,8 +1756,8 @@ rb_ivar_count(VALUE obj) switch (BUILTIN_TYPE(obj)) { case T_OBJECT: - if (ROBJECT_IV_INDEX_TBL(obj) != 0) { - st_index_t i, count, num = ROBJECT_NUMIV(obj); + if (rb_shape_get_shape(obj)->iv_count > 0) { + st_index_t i, count, num = ROBJECT_IV_COUNT(obj); const VALUE *const ivptr = ROBJECT_IVPTR(obj); for (i = count = 0; i < num; ++i) { if (ivptr[i] != Qundef) { @@ -1867,7 +1777,7 @@ rb_ivar_count(VALUE obj) if (FL_TEST(obj, FL_EXIVAR)) { struct gen_ivtbl *ivtbl; - if (gen_ivtbl_get(obj, 0, &ivtbl)) { + if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) { return gen_ivtbl_count(ivtbl); } } @@ -1965,40 +1875,53 @@ rb_obj_remove_instance_variable(VALUE obj, VALUE name) { VALUE val = Qnil; const ID id = id_for_var(obj, name, an, instance); - st_data_t n, v; - struct st_table *iv_index_tbl; - uint32_t index; + // Frozen check comes here because it's expected that we raise a + // NameError (from the id_for_var check) before we raise a FrozenError rb_check_frozen(obj); + + attr_index_t index; + if (!id) { goto not_defined; } switch (BUILTIN_TYPE(obj)) { - case T_OBJECT: - iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); - if (iv_index_tbl_lookup(iv_index_tbl, id, &index) && - index < ROBJECT_NUMIV(obj) && - (val = ROBJECT_IVPTR(obj)[index]) != Qundef) { - ROBJECT_IVPTR(obj)[index] = Qundef; - return val; - } - break; case T_CLASS: case T_MODULE: IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id); - n = id; - if (RCLASS_IV_TBL(obj) && lock_st_delete(RCLASS_IV_TBL(obj), &n, &v)) { - return (VALUE)v; + if (RCLASS_IV_TBL(obj)) { + st_data_t id_data = (st_data_t)id, val; + if (lock_st_delete(RCLASS_IV_TBL(obj), &id_data, &val)) { + return (VALUE)val; + } } break; - default: - if (FL_TEST(obj, FL_EXIVAR)) { - if (generic_ivar_remove(obj, id, &val)) { - return val; - } + case T_OBJECT: { + rb_shape_t * shape = rb_shape_get_shape(obj); + if (rb_shape_get_iv_index(shape, id, &index)) { + rb_shape_transition_shape_remove_ivar(obj, id, shape); + val = ROBJECT_IVPTR(obj)[index]; + ROBJECT_IVPTR(obj)[index] = Qundef; + return val; } + + break; + } + default: { + rb_shape_t * shape = rb_shape_get_shape(obj); + + if (rb_shape_get_iv_index(shape, id, &index)) { + rb_shape_transition_shape_remove_ivar(obj, id, shape); + struct gen_ivtbl *ivtbl; + rb_gen_ivtbl_get(obj, id, &ivtbl); + val = ivtbl->ivptr[index]; + ivtbl->ivptr[index] = Qundef; + return val; + } + break; + } } not_defined: diff --git a/variable.h b/variable.h index 55596b00de6213..314ac82df0dbc9 100644 --- a/variable.h +++ b/variable.h @@ -11,11 +11,19 @@ /* per-object */ struct gen_ivtbl { +#if !SHAPE_IN_BASIC_FLAGS + uint16_t shape_id; +#endif uint32_t numiv; VALUE ivptr[FLEX_ARY_LEN]; }; int rb_ivar_generic_ivtbl_lookup(VALUE obj, struct gen_ivtbl **); -VALUE rb_ivar_generic_lookup_with_index(VALUE obj, ID id, uint32_t index); + +#include "shape.h" +#if !SHAPE_IN_BASIC_FLAGS +shape_id_t rb_generic_shape_id(VALUE obj); +#endif + #endif /* RUBY_TOPLEVEL_VARIABLE_H */ diff --git a/vm.c b/vm.c index 520acf87b34654..5cf8d7d27e32b3 100644 --- a/vm.c +++ b/vm.c @@ -26,6 +26,7 @@ #include "internal/thread.h" #include "internal/vm.h" #include "internal/sanitizers.h" +#include "internal/variable.h" #include "iseq.h" #include "mjit.h" #include "yjit.h" @@ -4030,6 +4031,11 @@ Init_BareVM(void) #endif } +#ifndef _WIN32 +#include +#include +#endif + void Init_vm_objects(void) { @@ -4041,6 +4047,31 @@ Init_vm_objects(void) vm->mark_object_ary = rb_ary_hidden_new(128); vm->loading_table = st_init_strtable(); vm->frozen_strings = st_init_table_with_size(&rb_fstring_hash_type, 10000); + +#if HAVE_MMAP + vm->shape_list = (rb_shape_t *)mmap(NULL, rb_size_mul_or_raise(SHAPE_BITMAP_SIZE * 32, sizeof(rb_shape_t), rb_eRuntimeError), + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (vm->shape_list == MAP_FAILED) { + vm->shape_list = 0; + } +#else + vm->shape_list = xcalloc(SHAPE_BITMAP_SIZE * 32, sizeof(rb_shape_t)); +#endif + + if (!vm->shape_list) { + rb_memerror(); + } + + // Root shape + vm->root_shape = rb_shape_alloc_with_parent_id(0, INVALID_SHAPE_ID); + RUBY_ASSERT(rb_shape_id(vm->root_shape) == ROOT_SHAPE_ID); + + // Frozen root shape + vm->frozen_root_shape = rb_shape_alloc_with_parent_id(rb_make_internal_id(), rb_shape_id(vm->root_shape)); + vm->frozen_root_shape->type = (uint8_t)SHAPE_FROZEN; + RUBY_ASSERT(rb_shape_id(vm->frozen_root_shape) == FROZEN_ROOT_SHAPE_ID); + + vm->next_shape_id = 2; } /* Stub for builtin function when not building YJIT units*/ diff --git a/vm_callinfo.h b/vm_callinfo.h index fd2215be7dd7af..20027188813f09 100644 --- a/vm_callinfo.h +++ b/vm_callinfo.h @@ -10,6 +10,7 @@ #include "debug_counter.h" #include "internal/class.h" +#include "shape.h" enum vm_call_flag_bits { VM_CALL_ARGS_SPLAT_bit, /* m(*args) */ @@ -284,14 +285,29 @@ struct rb_callcache { const vm_call_handler call_; union { - const unsigned int attr_index; + struct { + uintptr_t value; // Shape ID in upper bits, index in lower bits + } attr; const enum method_missing_reason method_missing_reason; /* used by method_missing */ VALUE v; } aux_; }; -#define VM_CALLCACHE_UNMARKABLE IMEMO_FL_USER0 -#define VM_CALLCACHE_ON_STACK IMEMO_FL_USER1 +#define VM_CALLCACHE_UNMARKABLE FL_FREEZE +#define VM_CALLCACHE_ON_STACK FL_EXIVAR + +extern const struct rb_callcache *rb_vm_empty_cc(void); +extern const struct rb_callcache *rb_vm_empty_cc_for_super(void); + +#define vm_cc_empty() rb_vm_empty_cc() + +static inline void vm_cc_attr_index_set(const struct rb_callcache *cc, attr_index_t index, shape_id_t dest_shape_id); + +static inline void +vm_cc_attr_index_initialize(const struct rb_callcache *cc, shape_id_t shape_id) +{ + vm_cc_attr_index_set(cc, (attr_index_t)-1, shape_id); +} static inline const struct rb_callcache * vm_cc_new(VALUE klass, @@ -299,6 +315,7 @@ vm_cc_new(VALUE klass, vm_call_handler call) { const struct rb_callcache *cc = (const struct rb_callcache *)rb_imemo_new(imemo_callcache, (VALUE)cme, (VALUE)call, 0, klass); + vm_cc_attr_index_initialize(cc, INVALID_SHAPE_ID); RB_DEBUG_COUNTER_INC(cc_new); return cc; } @@ -350,30 +367,43 @@ vm_cc_call(const struct rb_callcache *cc) return cc->call_; } -static inline unsigned int +static inline attr_index_t vm_cc_attr_index(const struct rb_callcache *cc) { VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache)); - return cc->aux_.attr_index - 1; + return (attr_index_t)((cc->aux_.attr.value & SHAPE_FLAG_MASK) - 1); } -static inline bool -vm_cc_attr_index_p(const struct rb_callcache *cc) +static inline shape_id_t +vm_cc_attr_index_dest_shape_id(const struct rb_callcache *cc) { VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache)); - return cc->aux_.attr_index > 0; + + return cc->aux_.attr.value >> SHAPE_FLAG_SHIFT; } -static inline uint32_t -vm_ic_entry_index(const struct iseq_inline_iv_cache_entry *ic) +static inline void +vm_cc_atomic_shape_and_index(const struct rb_callcache *cc, shape_id_t * shape_id, attr_index_t * index) { - return ic->entry->index; + uintptr_t cache_value = cc->aux_.attr.value; // Atomically read 64 bits + *shape_id = (shape_id_t)(cache_value >> SHAPE_FLAG_SHIFT); + *index = (attr_index_t)(cache_value & SHAPE_FLAG_MASK) - 1; + return; } -static inline bool -vm_ic_entry_p(const struct iseq_inline_iv_cache_entry *ic) +static inline void +vm_ic_atomic_shape_and_index(const struct iseq_inline_iv_cache_entry *ic, shape_id_t * shape_id, attr_index_t * index) { - return ic->entry; + uintptr_t cache_value = ic->value; // Atomically read 64 bits + *shape_id = (shape_id_t)(cache_value >> SHAPE_FLAG_SHIFT); + *index = (attr_index_t)(cache_value & SHAPE_FLAG_MASK) - 1; + return; +} + +static inline shape_id_t +vm_ic_attr_index_dest_shape_id(const struct iseq_inline_iv_cache_entry *ic) +{ + return (shape_id_t)(ic->value >> SHAPE_FLAG_SHIFT); } static inline unsigned int @@ -407,10 +437,6 @@ vm_cc_valid_p(const struct rb_callcache *cc, const rb_callable_method_entry_t *c } } -extern const struct rb_callcache *rb_vm_empty_cc(void); -extern const struct rb_callcache *rb_vm_empty_cc_for_super(void); -#define vm_cc_empty() rb_vm_empty_cc() - /* callcache: mutate */ static inline void @@ -422,26 +448,28 @@ vm_cc_call_set(const struct rb_callcache *cc, vm_call_handler call) } static inline void -vm_cc_attr_index_set(const struct rb_callcache *cc, int index) +vm_cc_attr_index_set(const struct rb_callcache *cc, attr_index_t index, shape_id_t dest_shape_id) { + uintptr_t *attr_value = (uintptr_t *)&cc->aux_.attr.value; + if (!vm_cc_markable(cc)) { + *attr_value = (uintptr_t)INVALID_SHAPE_ID << SHAPE_FLAG_SHIFT; + return; + } VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache)); VM_ASSERT(cc != vm_cc_empty()); - *(int *)&cc->aux_.attr_index = index + 1; + *attr_value = (attr_index_t)(index + 1) | ((uintptr_t)(dest_shape_id) << SHAPE_FLAG_SHIFT); } static inline void -vm_ic_entry_set(struct iseq_inline_iv_cache_entry *ic, struct rb_iv_index_tbl_entry *entry, const rb_iseq_t *iseq) +vm_ic_attr_index_set(const rb_iseq_t *iseq, const struct iseq_inline_iv_cache_entry *ic, attr_index_t index, shape_id_t dest_shape_id) { - ic->entry = entry; - RB_OBJ_WRITTEN(iseq, Qundef, entry->class_value); + *(uintptr_t *)&ic->value = ((uintptr_t)dest_shape_id << SHAPE_FLAG_SHIFT) | (attr_index_t)(index + 1); } static inline void -vm_cc_attr_index_initialize(const struct rb_callcache *cc) +vm_ic_attr_index_initialize(const struct iseq_inline_iv_cache_entry *ic, shape_id_t shape_id) { - VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache)); - VM_ASSERT(cc != vm_cc_empty()); - *(int *)&cc->aux_.attr_index = 0; + *(uintptr_t *)&ic->value = (uintptr_t)shape_id << SHAPE_FLAG_SHIFT; } static inline void diff --git a/vm_core.h b/vm_core.h index b923f5a49707fc..2bdf26b6a07ac7 100644 --- a/vm_core.h +++ b/vm_core.h @@ -99,6 +99,7 @@ extern int ruby_assert_critical_section_entered; #include "ruby/st.h" #include "ruby_atomic.h" #include "vm_opts.h" +#include "shape.h" #include "ruby/thread_native.h" @@ -276,7 +277,7 @@ struct iseq_inline_constant_cache { }; struct iseq_inline_iv_cache_entry { - struct rb_iv_index_tbl_entry *entry; + uintptr_t value; // attr_index in lower bits, dest_shape_id in upper bits }; struct iseq_inline_cvar_cache_entry { @@ -691,6 +692,12 @@ typedef struct rb_vm_struct { VALUE mark_object_ary; const VALUE special_exceptions[ruby_special_error_count]; + /* object shapes */ + rb_shape_t *shape_list; + rb_shape_t *root_shape; + rb_shape_t *frozen_root_shape; + shape_id_t next_shape_id; + /* load */ VALUE top_self; VALUE load_path; @@ -1096,7 +1103,7 @@ typedef struct rb_thread_struct { rb_fiber_t *root_fiber; VALUE scheduler; - unsigned blocking; + unsigned int blocking; /* misc */ VALUE name; diff --git a/vm_eval.c b/vm_eval.c index a71688c6bc07fb..eddc6f80da7cfc 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -48,7 +48,7 @@ rb_vm_call0(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE { struct rb_calling_info calling = { .ci = &VM_CI_ON_STACK(id, kw_splat ? VM_CALL_KW_SPLAT : 0, argc, NULL), - .cc = &VM_CC_ON_STACK(Qfalse, vm_call_general, { 0 }, cme), + .cc = &VM_CC_ON_STACK(Qfalse, vm_call_general, {{ 0 }}, cme), .block_handler = vm_passed_block_handler(ec), .recv = recv, .argc = argc, @@ -90,7 +90,7 @@ vm_call0_cc(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE static VALUE vm_call0_cme(rb_execution_context_t *ec, struct rb_calling_info *calling, const VALUE *argv, const rb_callable_method_entry_t *cme) { - calling->cc = &VM_CC_ON_STACK(Qfalse, vm_call_general, { 0 }, cme); + calling->cc = &VM_CC_ON_STACK(Qfalse, vm_call_general, {{ 0 }}, cme); return vm_call0_body(ec, calling, argv); } diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 03796d2ad197c9..8b19c6c10dfe2c 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -50,6 +50,11 @@ MJIT_STATIC VALUE ruby_vm_special_exception_copy(VALUE exc) { VALUE e = rb_obj_alloc(rb_class_real(RBASIC_CLASS(exc))); + rb_shape_t * shape = rb_shape_get_shape(exc); + if (rb_shape_frozen_shape_p(shape)) { + shape = rb_shape_get_shape_by_id(shape->parent_id); + } + rb_shape_set_shape(e, shape); rb_obj_copy_ivar(e, exc); return e; } @@ -1086,35 +1091,15 @@ vm_get_cvar_base(const rb_cref_t *cref, const rb_control_frame_t *cfp, int top_l return klass; } -static bool -iv_index_tbl_lookup(struct st_table *iv_index_tbl, ID id, struct rb_iv_index_tbl_entry **ent) -{ - int found; - st_data_t ent_data; - - if (iv_index_tbl == NULL) return false; - - RB_VM_LOCK_ENTER(); - { - found = st_lookup(iv_index_tbl, (st_data_t)id, &ent_data); - } - RB_VM_LOCK_LEAVE(); - if (found) *ent = (struct rb_iv_index_tbl_entry *)ent_data; - - return found ? true : false; -} - -ALWAYS_INLINE(static void fill_ivar_cache(const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr, struct rb_iv_index_tbl_entry *ent)); - +ALWAYS_INLINE(static void fill_ivar_cache(const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr, attr_index_t index, shape_id_t shape_id)); static inline void -fill_ivar_cache(const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr, struct rb_iv_index_tbl_entry *ent) +fill_ivar_cache(const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr, attr_index_t index, shape_id_t shape_id) { - // fill cache - if (!is_attr) { - vm_ic_entry_set(ic, ent, iseq); + if (is_attr) { + vm_cc_attr_index_set(cc, index, shape_id); } else { - vm_cc_attr_index_set(cc, ent->index); + vm_ic_attr_index_set(iseq, ic, index, shape_id); } } @@ -1123,74 +1108,120 @@ fill_ivar_cache(const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, in #define ractor_object_incidental_shareable_p(obj, val) \ ractor_incidental_shareable_p(rb_ractor_shareable_p(obj), val) +#define ATTR_INDEX_NOT_SET (attr_index_t)-1 + ALWAYS_INLINE(static VALUE vm_getivar(VALUE, ID, const rb_iseq_t *, IVC, const struct rb_callcache *, int)); static inline VALUE vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr) { #if OPT_IC_FOR_IVAR VALUE val = Qundef; + shape_id_t shape_id; + VALUE * ivar_list; if (SPECIAL_CONST_P(obj)) { - // frozen? + return Qnil; } - else if (LIKELY(is_attr ? - RB_DEBUG_COUNTER_INC_UNLESS(ivar_get_ic_miss_unset, vm_cc_attr_index_p(cc)) : - RB_DEBUG_COUNTER_INC_UNLESS(ivar_get_ic_miss_serial, vm_ic_entry_p(ic) && ic->entry->class_serial == RCLASS_SERIAL(RBASIC(obj)->klass)))) { - uint32_t index = !is_attr ? vm_ic_entry_index(ic): (vm_cc_attr_index(cc)); - RB_DEBUG_COUNTER_INC(ivar_get_ic_hit); +#if SHAPE_IN_BASIC_FLAGS + shape_id = RBASIC_SHAPE_ID(obj); +#endif - if (LIKELY(BUILTIN_TYPE(obj) == T_OBJECT) && - LIKELY(index < ROBJECT_NUMIV(obj))) { - val = ROBJECT_IVPTR(obj)[index]; + switch (BUILTIN_TYPE(obj)) { + case T_OBJECT: + ivar_list = ROBJECT_IVPTR(obj); + VM_ASSERT(rb_ractor_shareable_p(obj) ? rb_ractor_shareable_p(val) : true); - VM_ASSERT(ractor_object_incidental_shareable_p(obj, val)); +#if !SHAPE_IN_BASIC_FLAGS + shape_id = ROBJECT_SHAPE_ID(obj); +#endif + break; + case T_CLASS: + case T_MODULE: + { + goto general_path; + } + default: + if (FL_TEST_RAW(obj, FL_EXIVAR)) { + struct gen_ivtbl *ivtbl; + rb_gen_ivtbl_get(obj, id, &ivtbl); +#if !SHAPE_IN_BASIC_FLAGS + shape_id = ivtbl->shape_id; +#endif + ivar_list = ivtbl->ivptr; } - else if (FL_TEST_RAW(obj, FL_EXIVAR)) { - val = rb_ivar_generic_lookup_with_index(obj, id, index); + else { + return Qnil; } - - goto ret; } - else { - struct rb_iv_index_tbl_entry *ent; - if (BUILTIN_TYPE(obj) == T_OBJECT) { - struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); + shape_id_t cached_id; + attr_index_t index; - if (iv_index_tbl && iv_index_tbl_lookup(iv_index_tbl, id, &ent)) { - fill_ivar_cache(iseq, ic, cc, is_attr, ent); - - // get value - if (ent->index < ROBJECT_NUMIV(obj)) { - val = ROBJECT_IVPTR(obj)[ent->index]; + if (is_attr) { + vm_cc_atomic_shape_and_index(cc, &cached_id, &index); + } + else { + vm_ic_atomic_shape_and_index(ic, &cached_id, &index); + } - VM_ASSERT(ractor_object_incidental_shareable_p(obj, val)); - } - } + if (LIKELY(cached_id == shape_id)) { + if (index == ATTR_INDEX_NOT_SET) { + return Qnil; } - else if (FL_TEST_RAW(obj, FL_EXIVAR)) { - struct st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj)); - if (iv_index_tbl && iv_index_tbl_lookup(iv_index_tbl, id, &ent)) { - fill_ivar_cache(iseq, ic, cc, is_attr, ent); - val = rb_ivar_generic_lookup_with_index(obj, id, ent->index); + val = ivar_list[index]; + RUBY_ASSERT(val != Qundef); + } + else { // cache miss case +#if RUBY_DEBUG + if (is_attr) { + if (cached_id != INVALID_SHAPE_ID) { + RB_DEBUG_COUNTER_INC(ivar_get_cc_miss_set); + } + else { + RB_DEBUG_COUNTER_INC(ivar_get_cc_miss_unset); } } else { - // T_CLASS / T_MODULE - goto general_path; + if (cached_id != INVALID_SHAPE_ID) { + RB_DEBUG_COUNTER_INC(ivar_get_ic_miss_set); + } + else { + RB_DEBUG_COUNTER_INC(ivar_get_ic_miss_unset); + } } +#endif - ret: - if (LIKELY(val != Qundef)) { - return val; + rb_shape_t *shape = rb_shape_get_shape_by_id(shape_id); + + if (rb_shape_get_iv_index(shape, id, &index)) { + // This fills in the cache with the shared cache object. + // "ent" is the shared cache object + fill_ivar_cache(iseq, ic, cc, is_attr, index, shape_id); + + // We fetched the ivar list above + val = ivar_list[index]; + RUBY_ASSERT(val != Qundef); } else { - return Qnil; + if (is_attr) { + vm_cc_attr_index_initialize(cc, shape_id); + } + else { + vm_ic_attr_index_initialize(ic, shape_id); + } + + val = Qnil; } + } - general_path: + + RUBY_ASSERT(val != Qundef); + + return val; + +general_path: #endif /* OPT_IC_FOR_IVAR */ RB_DEBUG_COUNTER_INC(ivar_get_ic_miss); @@ -1202,6 +1233,18 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call } } +static void +populate_cache(attr_index_t index, shape_id_t next_shape_id, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, bool is_attr) +{ + // Cache population code + if (is_attr) { + vm_cc_attr_index_set(cc, index, next_shape_id); + } + else { + vm_ic_attr_index_set(iseq, ic, index, next_shape_id); + } +} + ALWAYS_INLINE(static VALUE vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr)); NOINLINE(static VALUE vm_setivar_slowpath_ivar(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic)); NOINLINE(static VALUE vm_setivar_slowpath_attr(VALUE obj, ID id, VALUE val, const struct rb_callcache *cc)); @@ -1209,33 +1252,72 @@ NOINLINE(static VALUE vm_setivar_slowpath_attr(VALUE obj, ID id, VALUE val, cons static VALUE vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr) { - rb_check_frozen_internal(obj); - #if OPT_IC_FOR_IVAR - if (RB_TYPE_P(obj, T_OBJECT)) { - struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); - struct rb_iv_index_tbl_entry *ent; + switch (BUILTIN_TYPE(obj)) { + case T_OBJECT: + { + rb_check_frozen_internal(obj); + + attr_index_t index; + + uint32_t num_iv = ROBJECT_NUMIV(obj); + rb_shape_t* shape = rb_shape_get_shape(obj); + shape_id_t next_shape_id = ROBJECT_SHAPE_ID(obj); - if (iv_index_tbl_lookup(iv_index_tbl, id, &ent)) { - if (!is_attr) { - vm_ic_entry_set(ic, ent, iseq); + rb_shape_t* next_shape = rb_shape_get_next(shape, obj, id); + + if (shape != next_shape) { + RUBY_ASSERT(next_shape->parent_id == rb_shape_id(shape)); + next_shape_id = rb_shape_id(next_shape); } - else if (ent->index >= INT_MAX) { - rb_raise(rb_eArgError, "too many instance variables"); + + if (rb_shape_get_iv_index(next_shape, id, &index)) { // based off the hash stored in the transition tree + if (index >= MAX_IVARS) { + rb_raise(rb_eArgError, "too many instance variables"); + } + + populate_cache(index, next_shape_id, id, iseq, ic, cc, is_attr); } else { - vm_cc_attr_index_set(cc, (int)(ent->index)); + rb_bug("Didn't find instance variable %s\n", rb_id2name(id)); } - uint32_t index = ent->index; - - if (UNLIKELY(index >= ROBJECT_NUMIV(obj))) { + // Ensure the IV buffer is wide enough to store the IV + if (UNLIKELY(index >= num_iv)) { + RUBY_ASSERT(index == num_iv); rb_init_iv_list(obj); } + + if (shape != next_shape) { + rb_shape_set_shape(obj, next_shape); + } VALUE *ptr = ROBJECT_IVPTR(obj); RB_OBJ_WRITE(obj, &ptr[index], val); RB_DEBUG_COUNTER_INC(ivar_set_ic_miss_iv_hit); + return val; + } + case T_CLASS: + case T_MODULE: + break; + default: + { + rb_ivar_set(obj, id, val); + shape_id_t next_shape_id = rb_shape_get_shape_id(obj); + rb_shape_t *next_shape = rb_shape_get_shape_by_id(next_shape_id); + attr_index_t index; + + if (rb_shape_get_iv_index(next_shape, id, &index)) { // based off the hash stored in the transition tree + if (index >= MAX_IVARS) { + rb_raise(rb_eArgError, "too many instance variables"); + } + + populate_cache(index, next_shape_id, id, iseq, ic, cc, is_attr); + } + else { + rb_bug("didn't find the id\n"); + } + return val; } } @@ -1256,39 +1338,109 @@ vm_setivar_slowpath_attr(VALUE obj, ID id, VALUE val, const struct rb_callcache return vm_setivar_slowpath(obj, id, val, NULL, NULL, cc, true); } +NOINLINE(static VALUE vm_setivar_default(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_index_t index)); +static VALUE +vm_setivar_default(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_index_t index) +{ +#if SHAPE_IN_BASIC_FLAGS + shape_id_t shape_id = RBASIC_SHAPE_ID(obj); +#else + shape_id_t shape_id = rb_generic_shape_id(obj); +#endif + + struct gen_ivtbl *ivtbl = 0; + + // Cache hit case + if (shape_id == dest_shape_id) { + RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID); + + // Just get the IV table + rb_gen_ivtbl_get(obj, 0, &ivtbl); + } + else if (dest_shape_id != INVALID_SHAPE_ID) { + rb_shape_t * dest_shape = rb_shape_get_shape_by_id(dest_shape_id); + shape_id_t source_shape_id = dest_shape->parent_id; + + if (shape_id == source_shape_id && dest_shape->edge_name == id && dest_shape->type == SHAPE_IVAR) { + ivtbl = rb_ensure_generic_iv_list_size(obj, index + 1); +#if SHAPE_IN_BASIC_FLAGS + RBASIC_SET_SHAPE_ID(obj, dest_shape_id); +#else + ivtbl->shape_id = dest_shape_id; +#endif + } + else { + return Qundef; + } + } + else { + return Qundef; + } + + VALUE *ptr = ivtbl->ivptr; + + RB_OBJ_WRITE(obj, &ptr[index], val); + + RB_DEBUG_COUNTER_INC(ivar_set_ic_hit); + + return val; +} + static inline VALUE -vm_setivar(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr) +vm_setivar(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_index_t index) { #if OPT_IC_FOR_IVAR - if (LIKELY(RB_TYPE_P(obj, T_OBJECT)) && - LIKELY(!RB_OBJ_FROZEN_RAW(obj))) { + switch (BUILTIN_TYPE(obj)) { + case T_OBJECT: + { + VM_ASSERT(!rb_ractor_shareable_p(obj) || rb_obj_frozen_p(obj)); - VM_ASSERT(!rb_ractor_shareable_p(obj)); + shape_id_t shape_id = ROBJECT_SHAPE_ID(obj); - if (LIKELY( - (!is_attr && RB_DEBUG_COUNTER_INC_UNLESS(ivar_set_ic_miss_serial, vm_ic_entry_p(ic) && ic->entry->class_serial == RCLASS_SERIAL(RBASIC(obj)->klass))) || - ( is_attr && RB_DEBUG_COUNTER_INC_UNLESS(ivar_set_ic_miss_unset, vm_cc_attr_index_p(cc))))) { - uint32_t index = !is_attr ? vm_ic_entry_index(ic) : vm_cc_attr_index(cc); + if (LIKELY(shape_id == dest_shape_id)) { + RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID); + VM_ASSERT(!rb_ractor_shareable_p(obj)); + } + else if (dest_shape_id != INVALID_SHAPE_ID) { + rb_shape_t *dest_shape = rb_shape_get_shape_by_id(dest_shape_id); + shape_id_t source_shape_id = dest_shape->parent_id; + if (shape_id == source_shape_id && dest_shape->edge_name == id && dest_shape->type == SHAPE_IVAR) { + RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID); + if (UNLIKELY(index >= ROBJECT_NUMIV(obj))) { + rb_init_iv_list(obj); + } - if (UNLIKELY(index >= ROBJECT_NUMIV(obj))) { - rb_init_iv_list(obj); + ROBJECT_SET_SHAPE_ID(obj, dest_shape_id); + + RUBY_ASSERT(rb_shape_get_next(rb_shape_get_shape_by_id(source_shape_id), obj, id) == dest_shape); + RUBY_ASSERT(index < ROBJECT_NUMIV(obj)); + + } + else { + break; + } + } + else { + break; } + VALUE *ptr = ROBJECT_IVPTR(obj); + RB_OBJ_WRITE(obj, &ptr[index], val); + RB_DEBUG_COUNTER_INC(ivar_set_ic_hit); - return val; /* inline cache hit */ + return val; } - } - else { + break; + case T_CLASS: + case T_MODULE: RB_DEBUG_COUNTER_INC(ivar_set_ic_miss_noobject); + default: + break; } + + return Qundef; #endif /* OPT_IC_FOR_IVAR */ - if (is_attr) { - return vm_setivar_slowpath_attr(obj, id, val, cc); - } - else { - return vm_setivar_slowpath_ivar(obj, id, val, iseq, ic); - } } static VALUE @@ -1383,7 +1535,23 @@ vm_getinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, IVC ic) static inline void vm_setinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, VALUE val, IVC ic) { - vm_setivar(obj, id, val, iseq, ic, 0, 0); + shape_id_t dest_shape_id; + attr_index_t index; + vm_ic_atomic_shape_and_index(ic, &dest_shape_id, &index); + + if (UNLIKELY(vm_setivar(obj, id, val, dest_shape_id, index) == Qundef)) { + switch (BUILTIN_TYPE(obj)) { + case T_OBJECT: + case T_CLASS: + case T_MODULE: + break; + default: + if (vm_setivar_default(obj, id, val, dest_shape_id, index) != Qundef) { + return; + } + } + vm_setivar_slowpath_ivar(obj, id, val, iseq, ic); + } } void @@ -1392,28 +1560,6 @@ rb_vm_setinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, VALUE val, IV vm_setinstancevariable(iseq, obj, id, val, ic); } -/* Set the instance variable +val+ on object +obj+ at the +index+. - * This function only works with T_OBJECT objects, so make sure - * +obj+ is of type T_OBJECT before using this function. - */ -VALUE -rb_vm_set_ivar_idx(VALUE obj, uint32_t index, VALUE val) -{ - RUBY_ASSERT(RB_TYPE_P(obj, T_OBJECT)); - - rb_check_frozen_internal(obj); - - VM_ASSERT(!rb_ractor_shareable_p(obj)); - - if (UNLIKELY(index >= ROBJECT_NUMIV(obj))) { - rb_init_iv_list(obj); - } - VALUE *ptr = ROBJECT_IVPTR(obj); - RB_OBJ_WRITE(obj, &ptr[index], val); - - return val; -} - static VALUE vm_throw_continue(const rb_execution_context_t *ec, VALUE err) { @@ -3106,17 +3252,44 @@ vm_call_ivar(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_call const struct rb_callcache *cc = calling->cc; RB_DEBUG_COUNTER_INC(ccf_ivar); cfp->sp -= 1; - return vm_getivar(calling->recv, vm_cc_cme(cc)->def->body.attr.id, NULL, NULL, cc, TRUE); + VALUE ivar = vm_getivar(calling->recv, vm_cc_cme(cc)->def->body.attr.id, NULL, NULL, cc, TRUE); + return ivar; } static VALUE -vm_call_attrset(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling) +vm_call_attrset_direct(rb_execution_context_t *ec, rb_control_frame_t *cfp, const struct rb_callcache *cc, VALUE obj) { - const struct rb_callcache *cc = calling->cc; RB_DEBUG_COUNTER_INC(ccf_attrset); VALUE val = *(cfp->sp - 1); cfp->sp -= 2; - return vm_setivar(calling->recv, vm_cc_cme(cc)->def->body.attr.id, val, NULL, NULL, cc, 1); + attr_index_t index = vm_cc_attr_index(cc); + shape_id_t dest_shape_id = vm_cc_attr_index_dest_shape_id(cc); + ID id = vm_cc_cme(cc)->def->body.attr.id; + rb_check_frozen_internal(obj); + VALUE res = vm_setivar(obj, id, val, dest_shape_id, index); + if (res == Qundef) { + switch (BUILTIN_TYPE(obj)) { + case T_OBJECT: + case T_CLASS: + case T_MODULE: + break; + default: + { + res = vm_setivar_default(obj, id, val, dest_shape_id, index); + if (res != Qundef) { + return res; + } + } + } + res = vm_setivar_slowpath_attr(obj, id, val, cc); + } + return res; +} + +static VALUE +vm_call_attrset(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling) +{ + return vm_call_attrset_direct(ec, cfp, calling->cc, calling->recv); } bool @@ -3225,7 +3398,7 @@ vm_call_alias(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_cal { calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, - { 0 }, + {{0}}, aliased_callable_method_entry(vm_cc_cme(calling->cc))); return vm_call_method_each_type(ec, cfp, calling); @@ -3395,7 +3568,7 @@ vm_call_method_missing_body(rb_execution_context_t *ec, rb_control_frame_t *reg_ ec->method_missing_reason = reason; calling->ci = &VM_CI_ON_STACK(idMethodMissing, flag, argc, vm_ci_kwarg(orig_ci)); - calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, { 0 }, + calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }}, rb_callable_method_entry_without_refinements(CLASS_OF(calling->recv), idMethodMissing, NULL)); return vm_call_method(ec, reg_cfp, calling); } @@ -3421,7 +3594,7 @@ vm_call_zsuper(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_ca cme = refined_method_callable_without_refinement(cme); } - calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, { 0 }, cme); + calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }}, cme); return vm_call_method_each_type(ec, cfp, calling); } @@ -3528,7 +3701,7 @@ search_refined_method(rb_execution_context_t *ec, rb_control_frame_t *cfp, struc static VALUE vm_call_refined(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling) { - struct rb_callcache *ref_cc = &VM_CC_ON_STACK(Qundef, vm_call_general, { 0 }, + struct rb_callcache *ref_cc = &VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }}, search_refined_method(ec, cfp, calling)); if (vm_cc_cme(ref_cc)) { @@ -3708,18 +3881,43 @@ vm_call_method_each_type(rb_execution_context_t *ec, rb_control_frame_t *cfp, st CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci); rb_check_arity(calling->argc, 1, 1); - vm_cc_attr_index_initialize(cc); + const unsigned int aset_mask = (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT | VM_CALL_KWARG); - VM_CALL_METHOD_ATTR(v, - vm_call_attrset(ec, cfp, calling), - CC_SET_FASTPATH(cc, vm_call_attrset, !(vm_ci_flag(ci) & aset_mask))); + + if (vm_cc_markable(cc)) { + vm_cc_attr_index_initialize(cc, INVALID_SHAPE_ID); + VM_CALL_METHOD_ATTR(v, + vm_call_attrset_direct(ec, cfp, cc, calling->recv), + CC_SET_FASTPATH(cc, vm_call_attrset, !(vm_ci_flag(ci) & aset_mask))); + } + else { + cc = &((struct rb_callcache) { + .flags = T_IMEMO | + (imemo_callcache << FL_USHIFT) | + VM_CALLCACHE_UNMARKABLE | + ((VALUE)INVALID_SHAPE_ID << SHAPE_FLAG_SHIFT) | + VM_CALLCACHE_ON_STACK, + .klass = cc->klass, + .cme_ = cc->cme_, + .call_ = cc->call_, + .aux_ = { + .attr = { + .value = INVALID_SHAPE_ID << SHAPE_FLAG_SHIFT, + } + }, + }); + + VM_CALL_METHOD_ATTR(v, + vm_call_attrset_direct(ec, cfp, cc, calling->recv), + CC_SET_FASTPATH(cc, vm_call_attrset, !(vm_ci_flag(ci) & aset_mask))); + } return v; case VM_METHOD_TYPE_IVAR: CALLER_SETUP_ARG(cfp, calling, ci); CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci); rb_check_arity(calling->argc, 0, 0); - vm_cc_attr_index_initialize(cc); + vm_cc_attr_index_initialize(cc, INVALID_SHAPE_ID); const unsigned int ivar_mask = (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT); VM_CALL_METHOD_ATTR(v, vm_call_ivar(ec, cfp, calling), diff --git a/yjit.c b/yjit.c index cc64cccac39913..2a523f9787bee1 100644 --- a/yjit.c +++ b/yjit.c @@ -74,6 +74,11 @@ rb_yjit_mark_writable(void *mem_block, uint32_t mem_size) void rb_yjit_mark_executable(void *mem_block, uint32_t mem_size) { + // Do not call mprotect when mem_size is zero. Some platforms may return + // an error for it. https://github.com/Shopify/ruby/issues/450 + if (mem_size == 0) { + return; + } if (mprotect(mem_block, mem_size, PROT_READ | PROT_EXEC)) { rb_bug("Couldn't make JIT page (%p, %lu bytes) executable, errno: %s\n", mem_block, (unsigned long)mem_size, strerror(errno)); @@ -509,6 +514,8 @@ rb_get_cme_def_body_attr_id(const rb_callable_method_entry_t *cme) return cme->def->body.attr.id; } +ID rb_get_symbol_id(VALUE namep); + enum method_optimized_type rb_get_cme_def_body_optimized_type(const rb_callable_method_entry_t *cme) { @@ -887,13 +894,11 @@ rb_assert_cme_handle(VALUE handle) RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle, imemo_ment)); } -typedef void (*iseq_callback)(const rb_iseq_t *); - // Heap-walking callback for rb_yjit_for_each_iseq(). static int for_each_iseq_i(void *vstart, void *vend, size_t stride, void *data) { - const iseq_callback callback = (iseq_callback)data; + const rb_iseq_callback callback = (rb_iseq_callback)data; VALUE v = (VALUE)vstart; for (; v != (VALUE)vend; v += stride) { void *ptr = asan_poisoned_object_p(v); @@ -912,7 +917,7 @@ for_each_iseq_i(void *vstart, void *vend, size_t stride, void *data) // Iterate through the whole GC heap and invoke a callback for each iseq. // Used for global code invalidation. void -rb_yjit_for_each_iseq(iseq_callback callback) +rb_yjit_for_each_iseq(rb_iseq_callback callback) { rb_objspace_each_objects(for_each_iseq_i, (void *)callback); } diff --git a/yjit.rb b/yjit.rb index 226f2a81345428..b80861dbfbb6fb 100644 --- a/yjit.rb +++ b/yjit.rb @@ -214,6 +214,7 @@ def _print_stats $stderr.puts "compilation_failure: " + ("%10d" % compilation_failure) if compilation_failure != 0 $stderr.puts "compiled_iseq_count: " + ("%10d" % stats[:compiled_iseq_count]) $stderr.puts "compiled_block_count: " + ("%10d" % stats[:compiled_block_count]) + $stderr.puts "freed_iseq_count: " + ("%10d" % stats[:freed_iseq_count]) $stderr.puts "invalidation_count: " + ("%10d" % stats[:invalidation_count]) $stderr.puts "constant_state_bumps: " + ("%10d" % stats[:constant_state_bumps]) $stderr.puts "inline_code_size: " + ("%10d" % stats[:inline_code_size]) diff --git a/yjit/bindgen/src/main.rs b/yjit/bindgen/src/main.rs index ebeeab14b12bd8..7bdfdade7709ad 100644 --- a/yjit/bindgen/src/main.rs +++ b/yjit/bindgen/src/main.rs @@ -40,6 +40,7 @@ fn main() { .header("internal.h") .header("internal/re.h") .header("include/ruby/ruby.h") + .header("shape.h") .header("vm_core.h") .header("vm_callinfo.h") @@ -81,6 +82,12 @@ fn main() { // This function prints info about a value and is useful for debugging .allowlist_function("rb_obj_info_dump") + // From shape.h + .allowlist_function("rb_shape_get_shape_id") + .allowlist_function("rb_shape_get_shape_by_id") + .allowlist_function("rb_shape_flags_mask") + .allowlist_function("rb_shape_get_iv_index") + // From ruby/internal/intern/object.h .allowlist_function("rb_obj_is_kind_of") @@ -297,7 +304,6 @@ fn main() { // From internal/variable.h .allowlist_function("rb_gvar_(get|set)") - .allowlist_function("rb_obj_ensure_iv_index_mapping") // From include/ruby/internal/intern/variable.h .allowlist_function("rb_attr_get") @@ -325,6 +331,7 @@ fn main() { .allowlist_function("rb_get_cfp_ep_level") .allowlist_function("rb_get_cme_def_type") .allowlist_function("rb_get_cme_def_body_attr_id") + .allowlist_function("rb_get_symbol_id") .allowlist_function("rb_get_cme_def_body_optimized_type") .allowlist_function("rb_get_cme_def_body_optimized_index") .allowlist_function("rb_get_cme_def_body_cfunc") diff --git a/yjit/src/asm/arm64/arg/shifted_imm.rs b/yjit/src/asm/arm64/arg/shifted_imm.rs index 0dd7af25b5994e..4602ac64ab9495 100644 --- a/yjit/src/asm/arm64/arg/shifted_imm.rs +++ b/yjit/src/asm/arm64/arg/shifted_imm.rs @@ -46,18 +46,24 @@ mod tests { #[test] fn test_no_shift() { - let value = 256; - let result = ShiftedImmediate::try_from(value); + let expected_value = 256; + let result = ShiftedImmediate::try_from(expected_value); - assert!(matches!(result, Ok(ShiftedImmediate { shift: Shift::LSL0, value }))); + match result { + Ok(ShiftedImmediate { shift: Shift::LSL0, value }) => assert_eq!(value as u64, expected_value), + _ => panic!("Unexpected shift value") + } } #[test] fn test_maximum_no_shift() { - let value = (1 << 12) - 1; - let result = ShiftedImmediate::try_from(value); + let expected_value = (1 << 12) - 1; + let result = ShiftedImmediate::try_from(expected_value); - assert!(matches!(result, Ok(ShiftedImmediate { shift: Shift::LSL0, value }))); + match result { + Ok(ShiftedImmediate { shift: Shift::LSL0, value }) => assert_eq!(value as u64, expected_value), + _ => panic!("Unexpected shift value") + } } #[test] diff --git a/yjit/src/asm/mod.rs b/yjit/src/asm/mod.rs index 2bc83ec0596ed4..1ab813964c8f5b 100644 --- a/yjit/src/asm/mod.rs +++ b/yjit/src/asm/mod.rs @@ -1,9 +1,20 @@ +use std::cell::RefCell; +use std::cmp; use std::fmt; use std::mem; +use std::rc::Rc; +#[cfg(target_arch = "x86_64")] +use crate::backend::x86_64::JMP_PTR_BYTES; +#[cfg(target_arch = "aarch64")] +use crate::backend::arm64::JMP_PTR_BYTES; +use crate::backend::ir::Assembler; +use crate::backend::ir::Target; +use crate::virtualmem::WriteError; #[cfg(feature = "asm_comments")] use std::collections::BTreeMap; +use crate::codegen::CodegenGlobals; use crate::virtualmem::{VirtualMem, CodePtr}; // Lots of manual vertical alignment in there that rustfmt doesn't handle well. @@ -17,7 +28,8 @@ pub mod arm64; // /// Reference to an ASM label -struct LabelRef { +#[derive(Clone)] +pub struct LabelRef { // Position in the code block where the label reference exists pos: usize, @@ -36,7 +48,7 @@ struct LabelRef { /// Block of memory into which instructions can be assembled pub struct CodeBlock { // Memory for storing the encoded instructions - mem_block: VirtualMem, + mem_block: Rc>, // Memory block size mem_size: usize, @@ -44,6 +56,12 @@ pub struct CodeBlock { // Current writing position write_pos: usize, + // Size of a code page (inlined + outlined) + page_size: usize, + + // Size reserved for writing a jump to the next page + page_end_reserve: usize, + // Table of registered label addresses label_addrs: Vec, @@ -58,7 +76,6 @@ pub struct CodeBlock { asm_comments: BTreeMap>, // True for OutlinedCb - #[cfg(feature = "disasm")] pub outlined: bool, // Set if the CodeBlock is unable to output some instructions, @@ -67,27 +84,158 @@ pub struct CodeBlock { dropped_bytes: bool, } +/// Set of CodeBlock label states. Used for recovering the previous state. +pub struct LabelState { + label_addrs: Vec, + label_names: Vec, + label_refs: Vec, +} + impl CodeBlock { /// Make a new CodeBlock - pub fn new(mem_block: VirtualMem, outlined: bool) -> Self { - Self { - mem_size: mem_block.virtual_region_size(), + pub fn new(mem_block: Rc>, page_size: usize, outlined: bool) -> Self { + let mem_size = mem_block.borrow().virtual_region_size(); + let mut cb = Self { mem_block, + mem_size, write_pos: 0, + page_size, + page_end_reserve: JMP_PTR_BYTES, label_addrs: Vec::new(), label_names: Vec::new(), label_refs: Vec::new(), #[cfg(feature = "asm_comments")] asm_comments: BTreeMap::new(), - #[cfg(feature = "disasm")] outlined, dropped_bytes: false, + }; + cb.write_pos = cb.page_start(); + cb + } + + /// Move the CodeBlock to the next page. If it's on the furthest page, + /// move the other CodeBlock to the next page as well. + pub fn next_page(&mut self, base_ptr: CodePtr, jmp_ptr: F) -> bool { + let old_write_ptr = self.get_write_ptr(); + self.set_write_ptr(base_ptr); + self.without_page_end_reserve(|cb| assert!(cb.has_capacity(JMP_PTR_BYTES))); + + // Move self to the next page + let next_page_idx = self.write_pos / self.page_size + 1; + if !self.set_page(next_page_idx, &jmp_ptr) { + self.set_write_ptr(old_write_ptr); // rollback if there are no more pages + return false; + } + + // Move the other CodeBlock to the same page if it'S on the furthest page + self.other_cb().unwrap().set_page(next_page_idx, &jmp_ptr); + + return !self.dropped_bytes; + } + + /// Move the CodeBlock to page_idx only if it's not going backwards. + fn set_page(&mut self, page_idx: usize, jmp_ptr: &F) -> bool { + // Do not move the CodeBlock if page_idx points to an old position so that this + // CodeBlock will not overwrite existing code. + // + // Let's say this is the current situation: + // cb: [page1, page2, page3 (write_pos)], ocb: [page1, page2, page3 (write_pos)] + // + // When cb needs to patch page1, this will be temporarily changed to: + // cb: [page1 (write_pos), page2, page3], ocb: [page1, page2, page3 (write_pos)] + // + // While patching page1, cb may need to jump to page2. What set_page currently does is: + // cb: [page1, page2 (write_pos), page3], ocb: [page1, page2, page3 (write_pos)] + // instead of: + // cb: [page1, page2 (write_pos), page3], ocb: [page1, page2 (write_pos), page3] + // because moving ocb's write_pos from page3 to the beginning of page2 will let ocb's + // write_pos point to existing code in page2, which might let ocb overwrite it later. + // + // We could remember the last write_pos in page2 and let set_page use that position, + // but you need to waste some space for keeping write_pos for every single page. + // It doesn't seem necessary for performance either. So we're currently not doing it. + let mut dst_pos = self.page_size * page_idx + self.page_start(); + if self.page_size * page_idx < self.mem_size && self.write_pos < dst_pos { + // Reset dropped_bytes + self.dropped_bytes = false; + + // Convert dst_pos to dst_ptr + let src_pos = self.write_pos; + self.write_pos = dst_pos; + let dst_ptr = self.get_write_ptr(); + self.write_pos = src_pos; + + // Generate jmp_ptr from src_pos to dst_pos + self.without_page_end_reserve(|cb| { + cb.add_comment("jump to next page"); + jmp_ptr(cb, dst_ptr); + assert!(!cb.has_dropped_bytes()); + }); + + // Start the next code from dst_pos + self.write_pos = dst_pos; } + !self.dropped_bytes + } + + /// write_pos of the current page start + pub fn page_start_pos(&self) -> usize { + self.get_write_pos() / self.page_size * self.page_size + self.page_start() + } + + /// Offset of each page where CodeBlock should start writing + pub fn page_start(&self) -> usize { + let mut start = if self.inline() { + 0 + } else { + self.page_size / 2 + }; + if cfg!(debug_assertions) && !cfg!(test) { + // Leave illegal instructions at the beginning of each page to assert + // we're not accidentally crossing page boundaries. + start += JMP_PTR_BYTES; + } + start + } + + /// Offset of each page where CodeBlock should stop writing (exclusive) + pub fn page_end(&self) -> usize { + let page_end = if self.inline() { + self.page_size / 2 + } else { + self.page_size + }; + page_end - self.page_end_reserve // reserve space to jump to the next page + } + + /// Call a given function with page_end_reserve = 0 + pub fn without_page_end_reserve(&mut self, block: F) { + let old_page_end_reserve = self.page_end_reserve; + self.page_end_reserve = 0; + block(self); + self.page_end_reserve = old_page_end_reserve; + } + + /// Return the address ranges of a given address range that this CodeBlock can write. + pub fn writable_addrs(&self, start_ptr: CodePtr, end_ptr: CodePtr) -> Vec<(usize, usize)> { + let mut addrs = vec![]; + let mut start = start_ptr.raw_ptr() as usize; + let codeblock_end = self.get_ptr(self.get_mem_size()).raw_ptr() as usize; + let end = std::cmp::min(end_ptr.raw_ptr() as usize, codeblock_end); + while start < end { + let current_page = start / self.page_size * self.page_size; + let page_end = std::cmp::min(end, current_page + self.page_end()) as usize; + addrs.push((start, page_end)); + start = current_page + self.page_size + self.page_start(); + } + addrs } /// Check if this code block has sufficient remaining capacity pub fn has_capacity(&self, num_bytes: usize) -> bool { - self.write_pos + num_bytes < self.mem_size + let page_offset = self.write_pos % self.page_size; + let capacity = self.page_end().saturating_sub(page_offset); + num_bytes <= capacity } /// Add an assembly comment if the feature is on. @@ -121,8 +269,8 @@ impl CodeBlock { self.write_pos } - pub fn get_mem(&mut self) -> &mut VirtualMem { - &mut self.mem_block + pub fn write_mem(&self, write_ptr: CodePtr, byte: u8) -> Result<(), WriteError> { + self.mem_block.borrow_mut().write_byte(write_ptr, byte) } // Set the current write position @@ -134,49 +282,31 @@ impl CodeBlock { self.write_pos = pos; } - // Align the current write pointer to a multiple of bytes - pub fn align_pos(&mut self, multiple: u32) { - // Compute the alignment boundary that is lower or equal - // Do everything with usize - let multiple: usize = multiple.try_into().unwrap(); - let pos = self.get_write_ptr().raw_ptr() as usize; - let remainder = pos % multiple; - let prev_aligned = pos - remainder; - - if prev_aligned == pos { - // Already aligned so do nothing - } else { - // Align by advancing - let pad = multiple - remainder; - self.set_pos(self.get_write_pos() + pad); - } - } - // Set the current write position from a pointer pub fn set_write_ptr(&mut self, code_ptr: CodePtr) { - let pos = code_ptr.into_usize() - self.mem_block.start_ptr().into_usize(); + let pos = code_ptr.into_usize() - self.mem_block.borrow().start_ptr().into_usize(); self.set_pos(pos); } /// Get a (possibly dangling) direct pointer into the executable memory block pub fn get_ptr(&self, offset: usize) -> CodePtr { - self.mem_block.start_ptr().add_bytes(offset) + self.mem_block.borrow().start_ptr().add_bytes(offset) } /// Get a (possibly dangling) direct pointer to the current write position - pub fn get_write_ptr(&mut self) -> CodePtr { + pub fn get_write_ptr(&self) -> CodePtr { self.get_ptr(self.write_pos) } /// Write a single byte at the current position. pub fn write_byte(&mut self, byte: u8) { let write_ptr = self.get_write_ptr(); - - if self.mem_block.write_byte(write_ptr, byte).is_ok() { - self.write_pos += 1; - } else { + if !self.has_capacity(1) || self.mem_block.borrow_mut().write_byte(write_ptr, byte).is_err() { self.dropped_bytes = true; } + + // Always advance write_pos since arm64 PadEntryExit needs this to stop the loop. + self.write_pos += 1; } /// Write multiple bytes starting from the current position. @@ -242,6 +372,9 @@ impl CodeBlock { self.label_refs.push(LabelRef { pos: self.write_pos, label_idx, num_bytes, encode }); // Move past however many bytes the instruction takes up + if !self.has_capacity(num_bytes) { + self.dropped_bytes = true; // retry emitting the Insn after next_page + } self.write_pos += num_bytes; } @@ -274,14 +407,43 @@ impl CodeBlock { assert!(self.label_refs.is_empty()); } + pub fn clear_labels(&mut self) { + self.label_addrs.clear(); + self.label_names.clear(); + self.label_refs.clear(); + } + + pub fn get_label_state(&self) -> LabelState { + LabelState { + label_addrs: self.label_addrs.clone(), + label_names: self.label_names.clone(), + label_refs: self.label_refs.clone(), + } + } + + pub fn set_label_state(&mut self, state: LabelState) { + self.label_addrs = state.label_addrs; + self.label_names = state.label_names; + self.label_refs = state.label_refs; + } + pub fn mark_all_executable(&mut self) { - self.mem_block.mark_all_executable(); + self.mem_block.borrow_mut().mark_all_executable(); } - #[cfg(feature = "disasm")] pub fn inline(&self) -> bool { !self.outlined } + + pub fn other_cb(&self) -> Option<&'static mut Self> { + if !CodegenGlobals::has_instance() { + None + } else if self.inline() { + Some(CodegenGlobals::get_outlined_cb().unwrap()) + } else { + Some(CodegenGlobals::get_inline_cb()) + } + } } #[cfg(test)] @@ -295,15 +457,15 @@ impl CodeBlock { let mem_start: *const u8 = alloc.mem_start(); let virt_mem = VirtualMem::new(alloc, 1, mem_start as *mut u8, mem_size); - Self::new(virt_mem, false) + Self::new(Rc::new(RefCell::new(virt_mem)), 16 * 1024, false) } } /// Produce hex string output from the bytes in a code block -impl<'a> fmt::LowerHex for CodeBlock { +impl fmt::LowerHex for CodeBlock { fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { for pos in 0..self.write_pos { - let byte = unsafe { self.mem_block.start_ptr().raw_ptr().add(pos).read() }; + let byte = unsafe { self.mem_block.borrow().start_ptr().raw_ptr().add(pos).read() }; fmtr.write_fmt(format_args!("{:02x}", byte))?; } Ok(()) @@ -393,7 +555,7 @@ mod tests assert_eq!(uimm_num_bits(((u16::MAX as u32) + 1).into()), 32); assert_eq!(uimm_num_bits(u32::MAX.into()), 32); - assert_eq!(uimm_num_bits(((u32::MAX as u64) + 1)), 64); + assert_eq!(uimm_num_bits((u32::MAX as u64) + 1), 64); assert_eq!(uimm_num_bits(u64::MAX), 64); } } diff --git a/yjit/src/asm/x86_64/mod.rs b/yjit/src/asm/x86_64/mod.rs index d310e3bf129137..9cc3bf3770ad93 100644 --- a/yjit/src/asm/x86_64/mod.rs +++ b/yjit/src/asm/x86_64/mod.rs @@ -161,6 +161,14 @@ impl X86Opnd { _ => unreachable!() } } + + pub fn is_some(&self) -> bool { + match self { + X86Opnd::None => false, + _ => true + } + } + } // Instruction pointer @@ -382,7 +390,7 @@ fn write_opcode(cb: &mut CodeBlock, opcode: u8, reg: X86Reg) { } /// Encode an RM instruction -fn write_rm(cb: &mut CodeBlock, sz_pref: bool, rex_w: bool, r_opnd: X86Opnd, rm_opnd: X86Opnd, op_ext: u8, bytes: &[u8]) { +fn write_rm(cb: &mut CodeBlock, sz_pref: bool, rex_w: bool, r_opnd: X86Opnd, rm_opnd: X86Opnd, op_ext: Option, bytes: &[u8]) { let op_len = bytes.len(); assert!(op_len > 0 && op_len <= 3); assert!(matches!(r_opnd, X86Opnd::Reg(_) | X86Opnd::None), "Can only encode an RM instruction with a register or a none"); @@ -439,7 +447,7 @@ fn write_rm(cb: &mut CodeBlock, sz_pref: bool, rex_w: bool, r_opnd: X86Opnd, rm_ // MODRM.rm (3 bits) assert!( - !(op_ext != 0xff && !matches!(r_opnd, X86Opnd::None)), + !(op_ext.is_some() && r_opnd.is_some()), "opcode extension and register operand present" ); @@ -460,8 +468,8 @@ fn write_rm(cb: &mut CodeBlock, sz_pref: bool, rex_w: bool, r_opnd: X86Opnd, rm_ // Encode the reg field let reg: u8; - if op_ext != 0xff { - reg = op_ext; + if let Some(val) = op_ext { + reg = val; } else { reg = match r_opnd { X86Opnd::Reg(reg) => reg.reg_no & 7, @@ -522,7 +530,7 @@ fn write_rm(cb: &mut CodeBlock, sz_pref: bool, rex_w: bool, r_opnd: X86Opnd, rm_ } // Encode a mul-like single-operand RM instruction -fn write_rm_unary(cb: &mut CodeBlock, op_mem_reg_8: u8, op_mem_reg_pref: u8, op_ext: u8, opnd: X86Opnd) { +fn write_rm_unary(cb: &mut CodeBlock, op_mem_reg_8: u8, op_mem_reg_pref: u8, op_ext: Option, opnd: X86Opnd) { assert!(matches!(opnd, X86Opnd::Reg(_) | X86Opnd::Mem(_))); let opnd_size = opnd.num_bits(); @@ -538,7 +546,7 @@ fn write_rm_unary(cb: &mut CodeBlock, op_mem_reg_8: u8, op_mem_reg_pref: u8, op_ } // Encode an add-like RM instruction with multiple possible encodings -fn write_rm_multi(cb: &mut CodeBlock, op_mem_reg8: u8, op_mem_reg_pref: u8, op_reg_mem8: u8, op_reg_mem_pref: u8, op_mem_imm8: u8, op_mem_imm_sml: u8, op_mem_imm_lrg: u8, op_ext_imm: u8, opnd0: X86Opnd, opnd1: X86Opnd) { +fn write_rm_multi(cb: &mut CodeBlock, op_mem_reg8: u8, op_mem_reg_pref: u8, op_reg_mem8: u8, op_reg_mem_pref: u8, op_mem_imm8: u8, op_mem_imm_sml: u8, op_mem_imm_lrg: u8, op_ext_imm: Option, opnd0: X86Opnd, opnd1: X86Opnd) { assert!(matches!(opnd0, X86Opnd::Reg(_) | X86Opnd::Mem(_))); // Check the size of opnd0 @@ -561,17 +569,17 @@ fn write_rm_multi(cb: &mut CodeBlock, op_mem_reg8: u8, op_mem_reg_pref: u8, op_r // R/M + Reg (X86Opnd::Mem(_), X86Opnd::Reg(_)) | (X86Opnd::Reg(_), X86Opnd::Reg(_)) => { if opnd_size == 8 { - write_rm(cb, false, false, opnd1, opnd0, 0xff, &[op_mem_reg8]); + write_rm(cb, false, false, opnd1, opnd0, None, &[op_mem_reg8]); } else { - write_rm(cb, sz_pref, rex_w, opnd1, opnd0, 0xff, &[op_mem_reg_pref]); + write_rm(cb, sz_pref, rex_w, opnd1, opnd0, None, &[op_mem_reg_pref]); } }, // Reg + R/M/IPRel (X86Opnd::Reg(_), X86Opnd::Mem(_) | X86Opnd::IPRel(_)) => { if opnd_size == 8 { - write_rm(cb, false, false, opnd0, opnd1, 0xff, &[op_reg_mem8]); + write_rm(cb, false, false, opnd0, opnd1, None, &[op_reg_mem8]); } else { - write_rm(cb, sz_pref, rex_w, opnd0, opnd1, 0xff, &[op_reg_mem_pref]); + write_rm(cb, sz_pref, rex_w, opnd0, opnd1, None, &[op_reg_mem_pref]); } }, // R/M + Imm @@ -617,7 +625,7 @@ fn write_rm_multi(cb: &mut CodeBlock, op_mem_reg8: u8, op_mem_reg_pref: u8, op_r write_rm(cb, sz_pref, rex_w, X86Opnd::None, opnd0, op_ext_imm, &[op_mem_imm_lrg]); cb.write_int(uimm.value, if opnd_size > 32 { 32 } else { opnd_size.into() }); } else { - panic!("immediate value too large"); + panic!("immediate value too large (num_bits={})", num_bits); } }, _ => unreachable!() @@ -640,7 +648,7 @@ pub fn add(cb: &mut CodeBlock, opnd0: X86Opnd, opnd1: X86Opnd) { 0x80, // opMemImm8 0x83, // opMemImmSml 0x81, // opMemImmLrg - 0x00, // opExtImm + Some(0x00), // opExtImm opnd0, opnd1 ); @@ -657,7 +665,7 @@ pub fn and(cb: &mut CodeBlock, opnd0: X86Opnd, opnd1: X86Opnd) { 0x80, // opMemImm8 0x83, // opMemImmSml 0x81, // opMemImmLrg - 0x04, // opExtImm + Some(0x04), // opExtImm opnd0, opnd1 ); @@ -705,7 +713,7 @@ pub fn call_label(cb: &mut CodeBlock, label_idx: usize) { /// call - Indirect call with an R/M operand pub fn call(cb: &mut CodeBlock, opnd: X86Opnd) { - write_rm(cb, false, false, X86Opnd::None, opnd, 2, &[0xff]); + write_rm(cb, false, false, X86Opnd::None, opnd, Some(2), &[0xff]); } /// Encode a conditional move instruction @@ -721,7 +729,7 @@ fn write_cmov(cb: &mut CodeBlock, opcode1: u8, dst: X86Opnd, src: X86Opnd) { let sz_pref = reg.num_bits == 16; let rex_w = reg.num_bits == 64; - write_rm(cb, sz_pref, rex_w, dst, src, 0xff, &[0x0f, opcode1]); + write_rm(cb, sz_pref, rex_w, dst, src, None, &[0x0f, opcode1]); } else { unreachable!() } @@ -770,7 +778,7 @@ pub fn cmp(cb: &mut CodeBlock, opnd0: X86Opnd, opnd1: X86Opnd) { 0x80, // opMemImm8 0x83, // opMemImmSml 0x81, // opMemImmLrg - 0x07, // opExtImm + Some(0x07), // opExtImm opnd0, opnd1 ); @@ -900,7 +908,7 @@ pub fn jmp_ptr (cb: &mut CodeBlock, ptr: CodePtr) { write_jcc_ptr(cb, 0xFF, 0xE9 /// jmp - Indirect jump near to an R/M operand. pub fn jmp_rm(cb: &mut CodeBlock, opnd: X86Opnd) { - write_rm(cb, false, false, X86Opnd::None, opnd, 4, &[0xff]); + write_rm(cb, false, false, X86Opnd::None, opnd, Some(4), &[0xff]); } // jmp - Jump with relative 32-bit offset @@ -913,7 +921,7 @@ pub fn jmp32(cb: &mut CodeBlock, offset: i32) { pub fn lea(cb: &mut CodeBlock, dst: X86Opnd, src: X86Opnd) { if let X86Opnd::Reg(reg) = dst { assert!(reg.num_bits == 64); - write_rm(cb, false, true, dst, src, 0xff, &[0x8d]); + write_rm(cb, false, true, dst, src, None, &[0x8d]); } else { unreachable!(); } @@ -981,9 +989,9 @@ pub fn mov(cb: &mut CodeBlock, dst: X86Opnd, src: X86Opnd) { assert!(imm.num_bits <= mem.num_bits); if mem.num_bits == 8 { - write_rm(cb, false, false, X86Opnd::None, dst, 0xff, &[0xc6]); + write_rm(cb, false, false, X86Opnd::None, dst, None, &[0xc6]); } else { - write_rm(cb, mem.num_bits == 16, mem.num_bits == 64, X86Opnd::None, dst, 0, &[0xc7]); + write_rm(cb, mem.num_bits == 16, mem.num_bits == 64, X86Opnd::None, dst, Some(0), &[0xc7]); } let output_num_bits:u32 = if mem.num_bits > 32 { 32 } else { mem.num_bits.into() }; @@ -995,10 +1003,10 @@ pub fn mov(cb: &mut CodeBlock, dst: X86Opnd, src: X86Opnd) { assert!(uimm.num_bits <= mem.num_bits); if mem.num_bits == 8 { - write_rm(cb, false, false, X86Opnd::None, dst, 0xff, &[0xc6]); + write_rm(cb, false, false, X86Opnd::None, dst, None, &[0xc6]); } else { - write_rm(cb, mem.num_bits == 16, mem.num_bits == 64, X86Opnd::None, dst, 0, &[0xc7]); + write_rm(cb, mem.num_bits == 16, mem.num_bits == 64, X86Opnd::None, dst, Some(0), &[0xc7]); } let output_num_bits = if mem.num_bits > 32 { 32 } else { mem.num_bits.into() }; @@ -1018,7 +1026,7 @@ pub fn mov(cb: &mut CodeBlock, dst: X86Opnd, src: X86Opnd) { 0xC6, // opMemImm8 0xFF, // opMemImmSml (not available) 0xFF, // opMemImmLrg - 0xFF, // opExtImm + None, // opExtImm dst, src ); @@ -1036,9 +1044,9 @@ pub fn movsx(cb: &mut CodeBlock, dst: X86Opnd, src: X86Opnd) { assert!(src_num_bits < dst_num_bits); match src_num_bits { - 8 => write_rm(cb, dst_num_bits == 16, dst_num_bits == 64, dst, src, 0xff, &[0x0f, 0xbe]), - 16 => write_rm(cb, dst_num_bits == 16, dst_num_bits == 64, dst, src, 0xff, &[0x0f, 0xbf]), - 32 => write_rm(cb, false, true, dst, src, 0xff, &[0x63]), + 8 => write_rm(cb, dst_num_bits == 16, dst_num_bits == 64, dst, src, None, &[0x0f, 0xbe]), + 16 => write_rm(cb, dst_num_bits == 16, dst_num_bits == 64, dst, src, None, &[0x0f, 0xbf]), + 32 => write_rm(cb, false, true, dst, src, None, &[0x63]), _ => unreachable!() }; } else { @@ -1116,7 +1124,7 @@ pub fn not(cb: &mut CodeBlock, opnd: X86Opnd) { cb, 0xf6, // opMemReg8 0xf7, // opMemRegPref - 0x02, // opExt + Some(0x02), // opExt opnd ); } @@ -1132,7 +1140,7 @@ pub fn or(cb: &mut CodeBlock, opnd0: X86Opnd, opnd1: X86Opnd) { 0x80, // opMemImm8 0x83, // opMemImmSml 0x81, // opMemImmLrg - 0x01, // opExtImm + Some(0x01), // opExtImm opnd0, opnd1 ); @@ -1152,7 +1160,7 @@ pub fn pop(cb: &mut CodeBlock, opnd: X86Opnd) { X86Opnd::Mem(mem) => { assert!(mem.num_bits == 64); - write_rm(cb, false, false, X86Opnd::None, opnd, 0, &[0x8f]); + write_rm(cb, false, false, X86Opnd::None, opnd, Some(0), &[0x8f]); }, _ => unreachable!() }; @@ -1174,7 +1182,7 @@ pub fn push(cb: &mut CodeBlock, opnd: X86Opnd) { write_opcode(cb, 0x50, reg); }, X86Opnd::Mem(_mem) => { - write_rm(cb, false, false, X86Opnd::None, opnd, 6, &[0xff]); + write_rm(cb, false, false, X86Opnd::None, opnd, Some(6), &[0xff]); }, _ => unreachable!() } @@ -1191,7 +1199,7 @@ pub fn ret(cb: &mut CodeBlock) { } // Encode a single-operand shift instruction -fn write_shift(cb: &mut CodeBlock, op_mem_one_pref: u8, _op_mem_cl_pref: u8, op_mem_imm_pref: u8, op_ext: u8, opnd0: X86Opnd, opnd1: X86Opnd) { +fn write_shift(cb: &mut CodeBlock, op_mem_one_pref: u8, _op_mem_cl_pref: u8, op_mem_imm_pref: u8, op_ext: Option, opnd0: X86Opnd, opnd1: X86Opnd) { assert!(matches!(opnd0, X86Opnd::Reg(_) | X86Opnd::Mem(_))); // Check the size of opnd0 @@ -1221,7 +1229,7 @@ pub fn sal(cb: &mut CodeBlock, opnd0: X86Opnd, opnd1: X86Opnd) { 0xD1, // opMemOnePref, 0xD3, // opMemClPref, 0xC1, // opMemImmPref, - 0x04, + Some(0x04), opnd0, opnd1 ); @@ -1234,7 +1242,7 @@ pub fn sar(cb: &mut CodeBlock, opnd0: X86Opnd, opnd1: X86Opnd) { 0xD1, // opMemOnePref, 0xD3, // opMemClPref, 0xC1, // opMemImmPref, - 0x07, + Some(0x07), opnd0, opnd1 ); @@ -1247,7 +1255,7 @@ pub fn shl(cb: &mut CodeBlock, opnd0: X86Opnd, opnd1: X86Opnd) { 0xD1, // opMemOnePref, 0xD3, // opMemClPref, 0xC1, // opMemImmPref, - 0x04, + Some(0x04), opnd0, opnd1 ); @@ -1260,7 +1268,7 @@ pub fn shr(cb: &mut CodeBlock, opnd0: X86Opnd, opnd1: X86Opnd) { 0xD1, // opMemOnePref, 0xD3, // opMemClPref, 0xC1, // opMemImmPref, - 0x05, + Some(0x05), opnd0, opnd1 ); @@ -1277,7 +1285,7 @@ pub fn sub(cb: &mut CodeBlock, opnd0: X86Opnd, opnd1: X86Opnd) { 0x80, // opMemImm8 0x83, // opMemImmSml 0x81, // opMemImmLrg - 0x05, // opExtImm + Some(0x05), // opExtImm opnd0, opnd1 ); @@ -1314,10 +1322,10 @@ pub fn test(cb: &mut CodeBlock, rm_opnd: X86Opnd, test_opnd: X86Opnd) { let rm_resized = resize_opnd(rm_opnd, uimm.num_bits); if uimm.num_bits == 8 { - write_rm(cb, false, false, X86Opnd::None, rm_resized, 0x00, &[0xf6]); + write_rm(cb, false, false, X86Opnd::None, rm_resized, Some(0x00), &[0xf6]); cb.write_int(uimm.value, uimm.num_bits.into()); } else { - write_rm(cb, uimm.num_bits == 16, false, X86Opnd::None, rm_resized, 0x00, &[0xf7]); + write_rm(cb, uimm.num_bits == 16, false, X86Opnd::None, rm_resized, Some(0x00), &[0xf7]); cb.write_int(uimm.value, uimm.num_bits.into()); } }, @@ -1326,16 +1334,16 @@ pub fn test(cb: &mut CodeBlock, rm_opnd: X86Opnd, test_opnd: X86Opnd) { assert!(imm.num_bits <= 32); assert!(rm_num_bits == 64); - write_rm(cb, false, true, X86Opnd::None, rm_opnd, 0x00, &[0xf7]); + write_rm(cb, false, true, X86Opnd::None, rm_opnd, Some(0x00), &[0xf7]); cb.write_int(imm.value as u64, 32); }, X86Opnd::Reg(reg) => { assert!(reg.num_bits == rm_num_bits); if rm_num_bits == 8 { - write_rm(cb, false, false, test_opnd, rm_opnd, 0xff, &[0x84]); + write_rm(cb, false, false, test_opnd, rm_opnd, None, &[0x84]); } else { - write_rm(cb, rm_num_bits == 16, rm_num_bits == 64, test_opnd, rm_opnd, 0xff, &[0x85]); + write_rm(cb, rm_num_bits == 16, rm_num_bits == 64, test_opnd, rm_opnd, None, &[0x85]); } }, _ => unreachable!() @@ -1361,7 +1369,7 @@ pub fn xchg(cb: &mut CodeBlock, rm_opnd: X86Opnd, r_opnd: X86Opnd) { // Write the opcode and register number cb.write_byte(0x90 + (r_reg.reg_no & 7)); } else { - write_rm(cb, false, true, r_opnd, rm_opnd, 0xff, &[0x87]); + write_rm(cb, false, true, r_opnd, rm_opnd, None, &[0x87]); } } else { unreachable!(); @@ -1379,7 +1387,7 @@ pub fn xor(cb: &mut CodeBlock, opnd0: X86Opnd, opnd1: X86Opnd) { 0x80, // opMemImm8 0x83, // opMemImmSml 0x81, // opMemImmLrg - 0x06, // opExtImm + Some(0x06), // opExtImm opnd0, opnd1 ); diff --git a/yjit/src/backend/arm64/mod.rs b/yjit/src/backend/arm64/mod.rs index ee4f96c0d8c4da..5df072ed387ad7 100644 --- a/yjit/src/backend/arm64/mod.rs +++ b/yjit/src/backend/arm64/mod.rs @@ -4,7 +4,7 @@ use crate::asm::{CodeBlock}; use crate::asm::arm64::*; -use crate::codegen::{JITState}; +use crate::codegen::{JITState, CodegenGlobals}; use crate::cruby::*; use crate::backend::ir::*; use crate::virtualmem::CodePtr; @@ -36,6 +36,9 @@ pub const _C_RET_OPND: Opnd = Opnd::Reg(X0_REG); pub const C_SP_REG: A64Opnd = X31; pub const C_SP_STEP: i32 = 16; +// The number of bytes that are generated by emit_jmp_ptr +pub const JMP_PTR_BYTES: usize = 20; + /// Map Opnd to A64Opnd impl From for A64Opnd { fn from(opnd: Opnd) -> Self { @@ -71,7 +74,7 @@ impl Assembler // A special scratch register for intermediate processing. // This register is caller-saved (so we don't have to save it before using it) const SCRATCH0: A64Opnd = A64Opnd::Reg(X16_REG); - const SCRATCH1: A64Opnd = A64Opnd::Reg(X17_REG); + const SCRATCH1: A64Opnd = A64Opnd::Reg(X17_REG); /// Get the list of registers from which we will allocate on this platform /// These are caller-saved registers @@ -281,6 +284,9 @@ impl Assembler }; } + // We are replacing instructions here so we know they are already + // being used. It is okay not to use their output here. + #[allow(unused_must_use)] match insn { Insn::Add { left, right, .. } => { match (left, right) { @@ -564,7 +570,7 @@ impl Assembler /// Emit the required instructions to load the given value into the /// given register. Our goal here is to use as few instructions as /// possible to get this value into the register. - fn emit_load_value(cb: &mut CodeBlock, rd: A64Opnd, value: u64) -> i32 { + fn emit_load_value(cb: &mut CodeBlock, rd: A64Opnd, value: u64) -> usize { let mut current = value; if current <= 0xffff { @@ -677,6 +683,31 @@ impl Assembler ldr_post(cb, opnd, A64Opnd::new_mem(64, C_SP_REG, C_SP_STEP)); } + fn emit_jmp_ptr(cb: &mut CodeBlock, dst_ptr: CodePtr) { + let src_addr = cb.get_write_ptr().into_i64(); + let dst_addr = dst_ptr.into_i64(); + + // If the offset is short enough, then we'll use the + // branch instruction. Otherwise, we'll move the + // destination into a register and use the branch + // register instruction. + let num_insns = if b_offset_fits_bits((dst_addr - src_addr) / 4) { + b(cb, InstructionOffset::from_bytes((dst_addr - src_addr) as i32)); + 1 + } else { + let num_insns = emit_load_value(cb, Assembler::SCRATCH0, dst_addr as u64); + br(cb, Assembler::SCRATCH0); + num_insns + 1 + }; + + // Make sure it's always a consistent number of + // instructions in case it gets patched and has to + // use the other branch. + for _ in num_insns..(JMP_PTR_BYTES / 4) { + nop(cb); + } + } + // dbg!(&self.insns); // List of GC offsets @@ -684,7 +715,13 @@ impl Assembler // For each instruction let start_write_pos = cb.get_write_pos(); - for insn in &self.insns { + let mut insn_idx: usize = 0; + while let Some(insn) = self.insns.get(insn_idx) { + let src_ptr = cb.get_write_ptr(); + let had_dropped_bytes = cb.has_dropped_bytes(); + let old_label_state = cb.get_label_state(); + let mut insn_gc_offsets: Vec = Vec::new(); + match insn { Insn::Comment(text) => { if cfg!(feature = "asm_comments") { @@ -793,7 +830,7 @@ impl Assembler cb.write_bytes(&value.as_u64().to_le_bytes()); let ptr_offset: u32 = (cb.get_write_pos() as u32) - (SIZEOF_VALUE as u32); - gc_offsets.push(ptr_offset); + insn_gc_offsets.push(ptr_offset); }, Opnd::None => { unreachable!("Attempted to load from None operand"); @@ -901,28 +938,7 @@ impl Assembler Insn::Jmp(target) => { match target { Target::CodePtr(dst_ptr) => { - let src_addr = cb.get_write_ptr().into_i64(); - let dst_addr = dst_ptr.into_i64(); - - // If the offset is short enough, then we'll use the - // branch instruction. Otherwise, we'll move the - // destination into a register and use the branch - // register instruction. - let num_insns = if b_offset_fits_bits((dst_addr - src_addr) / 4) { - b(cb, InstructionOffset::from_bytes((dst_addr - src_addr) as i32)); - 0 - } else { - let num_insns = emit_load_value(cb, Self::SCRATCH0, dst_addr as u64); - br(cb, Self::SCRATCH0); - num_insns - }; - - // Make sure it's always a consistent number of - // instructions in case it gets patched and has to - // use the other branch. - for _ in num_insns..4 { - nop(cb); - } + emit_jmp_ptr(cb, *dst_ptr); }, Target::Label(label_idx) => { // Here we're going to save enough space for @@ -994,13 +1010,21 @@ impl Assembler csel(cb, out.into(), truthy.into(), falsy.into(), Condition::GE); } Insn::LiveReg { .. } => (), // just a reg alloc signal, no code - Insn::PadEntryExit => { - let jmp_len = 5 * 4; // Op::Jmp may emit 5 instructions - while (cb.get_write_pos() - start_write_pos) < jmp_len { + Insn::PadInvalPatch => { + while (cb.get_write_pos().saturating_sub(std::cmp::max(start_write_pos, cb.page_start_pos()))) < JMP_PTR_BYTES { nop(cb); } } }; + + // On failure, jump to the next page and retry the current insn + if !had_dropped_bytes && cb.has_dropped_bytes() && cb.next_page(src_ptr, emit_jmp_ptr) { + // Reset cb states before retrying the current Insn + cb.set_label_state(old_label_state); + } else { + insn_idx += 1; + gc_offsets.append(&mut insn_gc_offsets); + } } gc_offsets @@ -1017,21 +1041,23 @@ impl Assembler assert!(label_idx == idx); } - let start_write_pos = cb.get_write_pos(); + let start_ptr = cb.get_write_ptr(); let gc_offsets = asm.arm64_emit(cb); - if !cb.has_dropped_bytes() { + if cb.has_dropped_bytes() { + cb.clear_labels(); + } else { cb.link_labels(); - } - // Invalidate icache for newly written out region so we don't run stale code. - #[cfg(not(test))] - { - let start = cb.get_ptr(start_write_pos).raw_ptr(); - let write_ptr = cb.get_write_ptr().raw_ptr(); - let codeblock_end = cb.get_ptr(cb.get_mem_size()).raw_ptr(); - let end = std::cmp::min(write_ptr, codeblock_end); - unsafe { rb_yjit_icache_invalidate(start as _, end as _) }; + // Invalidate icache for newly written out region so we don't run stale code. + // It should invalidate only the code ranges of the current cb because the code + // ranges of the other cb might have a memory region that is still PROT_NONE. + #[cfg(not(test))] + cb.without_page_end_reserve(|cb| { + for (start, end) in cb.writable_addrs(start_ptr, cb.get_write_ptr()) { + unsafe { rb_yjit_icache_invalidate(start as _, end as _) }; + } + }); } gc_offsets diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs index dfdc1deb0d8f85..df0600b2fff70c 100644 --- a/yjit/src/backend/ir.rs +++ b/yjit/src/backend/ir.rs @@ -5,6 +5,7 @@ use std::cell::Cell; use std::fmt; use std::convert::From; +use std::io::Write; use std::mem::take; use crate::cruby::{VALUE}; use crate::virtualmem::{CodePtr}; @@ -220,7 +221,7 @@ impl From for Opnd { impl From for Opnd { fn from(value: u64) -> Self { - Opnd::UImm(value.try_into().unwrap()) + Opnd::UImm(value) } } @@ -433,9 +434,9 @@ pub enum Insn { // binary OR operation. Or { left: Opnd, right: Opnd, out: Opnd }, - /// Pad nop instructions to accomodate Op::Jmp in case the block is - /// invalidated. - PadEntryExit, + /// Pad nop instructions to accomodate Op::Jmp in case the block or the insn + /// is invalidated. + PadInvalPatch, // Mark a position in the generated code PosMarker(PosMarkerFn), @@ -521,7 +522,7 @@ impl Insn { Insn::Mov { .. } => "Mov", Insn::Not { .. } => "Not", Insn::Or { .. } => "Or", - Insn::PadEntryExit => "PadEntryExit", + Insn::PadInvalPatch => "PadEntryExit", Insn::PosMarker(_) => "PosMarker", Insn::RShift { .. } => "RShift", Insn::Store { .. } => "Store", @@ -658,7 +659,7 @@ impl<'a> Iterator for InsnOpndIterator<'a> { Insn::Jz(_) | Insn::Label(_) | Insn::LeaLabel { .. } | - Insn::PadEntryExit | + Insn::PadInvalPatch | Insn::PosMarker(_) => None, Insn::CPopInto(opnd) | Insn::CPush(opnd) | @@ -755,7 +756,7 @@ impl<'a> InsnOpndMutIterator<'a> { Insn::Jz(_) | Insn::Label(_) | Insn::LeaLabel { .. } | - Insn::PadEntryExit | + Insn::PadInvalPatch | Insn::PosMarker(_) => None, Insn::CPopInto(opnd) | Insn::CPush(opnd) | @@ -1099,13 +1100,10 @@ impl Assembler let gc_offsets = self.compile_with_regs(cb, alloc_regs); #[cfg(feature = "disasm")] - if get_option!(dump_disasm) == DumpDisasm::All || (get_option!(dump_disasm) == DumpDisasm::Inline && cb.inline()) { - use crate::disasm::disasm_addr_range; - let last_ptr = cb.get_write_ptr(); - let disasm = disasm_addr_range(cb, start_addr, last_ptr.raw_ptr() as usize - start_addr as usize); - if disasm.len() > 0 { - println!("{disasm}"); - } + if let Some(dump_disasm) = get_option_ref!(dump_disasm) { + use crate::disasm::dump_disasm_addr_range; + let end_addr = cb.get_write_ptr().raw_ptr(); + dump_disasm_addr_range(cb, start_addr, end_addr, dump_disasm) } gc_offsets } @@ -1474,8 +1472,8 @@ impl Assembler { out } - pub fn pad_entry_exit(&mut self) { - self.push_insn(Insn::PadEntryExit); + pub fn pad_inval_patch(&mut self) { + self.push_insn(Insn::PadInvalPatch); } //pub fn pos_marker(&mut self, marker_fn: F) diff --git a/yjit/src/backend/tests.rs b/yjit/src/backend/tests.rs index 440b66d69acacd..3098c7e3b09ef5 100644 --- a/yjit/src/backend/tests.rs +++ b/yjit/src/backend/tests.rs @@ -1,47 +1,14 @@ #![cfg(test)] - use crate::asm::{CodeBlock}; -use crate::virtualmem::{CodePtr}; use crate::backend::ir::*; use crate::cruby::*; -use crate::core::*; use crate::utils::c_callable; -use InsnOpnd::*; - -// Test that this function type checks -fn gen_dup( - ctx: &mut Context, - asm: &mut Assembler, -) { - let dup_val = ctx.stack_pop(0); - let (mapping, tmp_type) = ctx.get_opnd_mapping(StackOpnd(0)); - - let loc0 = ctx.stack_push_mapping((mapping, tmp_type)); - asm.mov(loc0, dup_val); -} - -fn guard_object_is_heap( - asm: &mut Assembler, - object_opnd: Opnd, - ctx: &mut Context, - side_exit: CodePtr, -) { - asm.comment("guard object is heap"); - - // Test that the object is not an immediate - asm.test(object_opnd, Opnd::UImm(RUBY_IMMEDIATE_MASK as u64)); - asm.jnz(Target::CodePtr(side_exit)); - - // Test that the object is not false or nil - asm.cmp(object_opnd, Opnd::UImm(Qnil.into())); - asm.jbe(Target::CodePtr(side_exit)); -} #[test] fn test_add() { let mut asm = Assembler::new(); let out = asm.add(SP, Opnd::UImm(1)); - asm.add(out, Opnd::UImm(2)); + let _ = asm.add(out, Opnd::UImm(2)); } #[test] @@ -52,21 +19,21 @@ fn test_alloc_regs() { let out1 = asm.add(EC, Opnd::UImm(1)); // Pad some instructions in to make sure it can handle that. - asm.add(EC, Opnd::UImm(2)); + let _ = asm.add(EC, Opnd::UImm(2)); // Get the second output we're going to reuse. let out2 = asm.add(EC, Opnd::UImm(3)); // Pad another instruction. - asm.add(EC, Opnd::UImm(4)); + let _ = asm.add(EC, Opnd::UImm(4)); // Reuse both the previously captured outputs. - asm.add(out1, out2); + let _ = asm.add(out1, out2); // Now get a third output to make sure that the pool has registers to // allocate now that the previous ones have been returned. let out3 = asm.add(EC, Opnd::UImm(5)); - asm.add(out3, Opnd::UImm(6)); + let _ = asm.add(out3, Opnd::UImm(6)); // Here we're going to allocate the registers. let result = asm.alloc_regs(Assembler::get_alloc_regs()); @@ -77,9 +44,20 @@ fn test_alloc_regs() { let reg0 = regs[0]; let reg1 = regs[1]; - assert!(matches!(result.insns[0].out_opnd(), Some(Opnd::Reg(reg0)))); - assert!(matches!(result.insns[2].out_opnd(), Some(Opnd::Reg(reg1)))); - assert!(matches!(result.insns[5].out_opnd(), Some(Opnd::Reg(reg0)))); + match result.insns[0].out_opnd() { + Some(Opnd::Reg(value)) => assert_eq!(value, ®0), + val => panic!("Unexpected register value {:?}", val), + } + + match result.insns[2].out_opnd() { + Some(Opnd::Reg(value)) => assert_eq!(value, ®1), + val => panic!("Unexpected register value {:?}", val), + } + + match result.insns[5].out_opnd() { + Some(Opnd::Reg(value)) => assert_eq!(value, ®0), + val => panic!("Unexpected register value {:?}", val), + } } fn setup_asm() -> (Assembler, CodeBlock) { @@ -198,7 +176,7 @@ fn test_base_insn_out() fn test_c_call() { c_callable! { - fn dummy_c_fun(v0: usize, v1: usize) {} + fn dummy_c_fun(_v0: usize, _v1: usize) {} } let (mut asm, mut cb) = setup_asm(); @@ -253,7 +231,7 @@ fn test_jcc_ptr() { let (mut asm, mut cb) = setup_asm(); - let side_exit = Target::CodePtr((5 as *mut u8).into()); + let side_exit = Target::CodePtr(((cb.get_write_ptr().raw_ptr() as usize + 4) as *mut u8).into()); let not_mask = asm.not(Opnd::mem(32, EC, RUBY_OFFSET_EC_INTERRUPT_MASK)); asm.test( Opnd::mem(32, EC, RUBY_OFFSET_EC_INTERRUPT_FLAG), @@ -270,7 +248,7 @@ fn test_jmp_ptr() { let (mut asm, mut cb) = setup_asm(); - let stub = Target::CodePtr((5 as *mut u8).into()); + let stub = Target::CodePtr(((cb.get_write_ptr().raw_ptr() as usize + 4) as *mut u8).into()); asm.jmp(stub); asm.compile_with_num_regs(&mut cb, 0); @@ -281,7 +259,7 @@ fn test_jo() { let (mut asm, mut cb) = setup_asm(); - let side_exit = Target::CodePtr((5 as *mut u8).into()); + let side_exit = Target::CodePtr(((cb.get_write_ptr().raw_ptr() as usize + 4) as *mut u8).into()); let arg1 = Opnd::mem(64, SP, 0); let arg0 = Opnd::mem(64, SP, 8); @@ -305,11 +283,12 @@ fn test_bake_string() { #[test] fn test_draining_iterator() { + let mut asm = Assembler::new(); - asm.load(Opnd::None); + let _ = asm.load(Opnd::None); asm.store(Opnd::None, Opnd::None); - asm.add(Opnd::None, Opnd::None); + let _ = asm.add(Opnd::None, Opnd::None); let mut iter = asm.into_draining_iter(); @@ -327,11 +306,11 @@ fn test_draining_iterator() { fn test_lookback_iterator() { let mut asm = Assembler::new(); - asm.load(Opnd::None); + let _ = asm.load(Opnd::None); asm.store(Opnd::None, Opnd::None); asm.store(Opnd::None, Opnd::None); - let mut iter = asm.into_lookback_iter(); + let iter = asm.into_lookback_iter(); while let Some((index, insn)) = iter.next_unmapped() { if index > 0 { diff --git a/yjit/src/backend/x86_64/mod.rs b/yjit/src/backend/x86_64/mod.rs index 2f770c2eac7923..c8aa1a0ed507d3 100644 --- a/yjit/src/backend/x86_64/mod.rs +++ b/yjit/src/backend/x86_64/mod.rs @@ -9,6 +9,7 @@ use crate::asm::x86_64::*; use crate::codegen::{JITState}; use crate::cruby::*; use crate::backend::ir::*; +use crate::codegen::CodegenGlobals; // Use the x86 register type for this platform pub type Reg = X86Reg; @@ -32,6 +33,9 @@ pub const _C_ARG_OPNDS: [Opnd; 6] = [ pub const C_RET_REG: Reg = RAX_REG; pub const _C_RET_OPND: Opnd = Opnd::Reg(RAX_REG); +// The number of bytes that are generated by jmp_ptr +pub const JMP_PTR_BYTES: usize = 6; + /// Map Opnd to X86Opnd impl From for X86Opnd { fn from(opnd: Opnd) -> Self { @@ -152,6 +156,9 @@ impl Assembler } } + // We are replacing instructions here so we know they are already + // being used. It is okay not to use their output here. + #[allow(unused_must_use)] match &mut insn { Insn::Add { left, right, out } | Insn::Sub { left, right, out } | @@ -372,7 +379,13 @@ impl Assembler // For each instruction let start_write_pos = cb.get_write_pos(); - for insn in &self.insns { + let mut insns_idx: usize = 0; + while let Some(insn) = self.insns.get(insns_idx) { + let src_ptr = cb.get_write_ptr(); + let had_dropped_bytes = cb.has_dropped_bytes(); + let old_label_state = cb.get_label_state(); + let mut insn_gc_offsets: Vec = Vec::new(); + match insn { Insn::Comment(text) => { if cfg!(feature = "asm_comments") { @@ -458,7 +471,7 @@ impl Assembler if !val.special_const_p() { // The pointer immediate is encoded as the last part of the mov written out let ptr_offset: u32 = (cb.get_write_pos() as u32) - (SIZEOF_VALUE as u32); - gc_offsets.push(ptr_offset); + insn_gc_offsets.push(ptr_offset); } } }, @@ -648,11 +661,10 @@ impl Assembler emit_csel(cb, *truthy, *falsy, *out, cmovl); } Insn::LiveReg { .. } => (), // just a reg alloc signal, no code - Insn::PadEntryExit => { - // We assume that our Op::Jmp usage that gets invalidated is <= 5 - let code_size: u32 = (cb.get_write_pos() - start_write_pos).try_into().unwrap(); - if code_size < 5 { - nop(cb, 5 - code_size); + Insn::PadInvalPatch => { + let code_size = cb.get_write_pos().saturating_sub(std::cmp::max(start_write_pos, cb.page_start_pos())); + if code_size < JMP_PTR_BYTES { + nop(cb, (JMP_PTR_BYTES - code_size) as u32); } } @@ -660,8 +672,18 @@ impl Assembler // we feed to the backend could get lowered into other // instructions. So it's possible that some of our backend // instructions can never make it to the emit stage. + #[allow(unreachable_patterns)] _ => panic!("unsupported instruction passed to x86 backend: {:?}", insn) }; + + // On failure, jump to the next page and retry the current insn + if !had_dropped_bytes && cb.has_dropped_bytes() && cb.next_page(src_ptr, jmp_ptr) { + // Reset cb states before retrying the current Insn + cb.set_label_state(old_label_state); + } else { + insns_idx += 1; + gc_offsets.append(&mut insn_gc_offsets); + } } gc_offsets @@ -680,7 +702,9 @@ impl Assembler let gc_offsets = asm.x86_emit(cb); - if !cb.has_dropped_bytes() { + if cb.has_dropped_bytes() { + cb.clear_labels(); + } else { cb.link_labels(); } @@ -700,7 +724,7 @@ mod tests { fn test_emit_add_lt_32_bits() { let (mut asm, mut cb) = setup_asm(); - asm.add(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); + let _ = asm.add(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); assert_eq!(format!("{:x}", cb), "4889c04881c0ff000000"); @@ -710,7 +734,7 @@ mod tests { fn test_emit_add_gt_32_bits() { let (mut asm, mut cb) = setup_asm(); - asm.add(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); + let _ = asm.add(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); assert_eq!(format!("{:x}", cb), "4889c049bbffffffffffff00004c01d8"); @@ -720,7 +744,7 @@ mod tests { fn test_emit_and_lt_32_bits() { let (mut asm, mut cb) = setup_asm(); - asm.and(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); + let _ = asm.and(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); assert_eq!(format!("{:x}", cb), "4889c04881e0ff000000"); @@ -730,7 +754,7 @@ mod tests { fn test_emit_and_gt_32_bits() { let (mut asm, mut cb) = setup_asm(); - asm.and(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); + let _ = asm.and(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); assert_eq!(format!("{:x}", cb), "4889c049bbffffffffffff00004c21d8"); @@ -760,7 +784,7 @@ mod tests { fn test_emit_or_lt_32_bits() { let (mut asm, mut cb) = setup_asm(); - asm.or(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); + let _ = asm.or(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); assert_eq!(format!("{:x}", cb), "4889c04881c8ff000000"); @@ -770,7 +794,7 @@ mod tests { fn test_emit_or_gt_32_bits() { let (mut asm, mut cb) = setup_asm(); - asm.or(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); + let _ = asm.or(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); assert_eq!(format!("{:x}", cb), "4889c049bbffffffffffff00004c09d8"); @@ -780,7 +804,7 @@ mod tests { fn test_emit_sub_lt_32_bits() { let (mut asm, mut cb) = setup_asm(); - asm.sub(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); + let _ = asm.sub(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); assert_eq!(format!("{:x}", cb), "4889c04881e8ff000000"); @@ -790,7 +814,7 @@ mod tests { fn test_emit_sub_gt_32_bits() { let (mut asm, mut cb) = setup_asm(); - asm.sub(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); + let _ = asm.sub(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); assert_eq!(format!("{:x}", cb), "4889c049bbffffffffffff00004c29d8"); @@ -820,7 +844,7 @@ mod tests { fn test_emit_xor_lt_32_bits() { let (mut asm, mut cb) = setup_asm(); - asm.xor(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); + let _ = asm.xor(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); assert_eq!(format!("{:x}", cb), "4889c04881f0ff000000"); @@ -830,7 +854,7 @@ mod tests { fn test_emit_xor_gt_32_bits() { let (mut asm, mut cb) = setup_asm(); - asm.xor(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); + let _ = asm.xor(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); assert_eq!(format!("{:x}", cb), "4889c049bbffffffffffff00004c31d8"); diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 22634a7de00838..ae01149081789f 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -13,13 +13,15 @@ use crate::utils::*; use CodegenStatus::*; use InsnOpnd::*; - +use std::cell::RefCell; +use std::cell::RefMut; use std::cmp; use std::collections::HashMap; use std::ffi::CStr; use std::mem::{self, size_of}; use std::os::raw::c_uint; use std::ptr; +use std::rc::Rc; use std::slice; pub use crate::virtualmem::CodePtr; @@ -189,13 +191,6 @@ fn jit_peek_at_block_handler(jit: &JITState, level: u32) -> VALUE { } } -// Add a comment at the current position in the code block -fn add_comment(cb: &mut CodeBlock, comment_str: &str) { - if cfg!(feature = "asm_comments") { - cb.add_comment(comment_str); - } -} - /// Increment a profiling counter with counter_name #[cfg(not(feature = "stats"))] macro_rules! gen_counter_incr { @@ -303,6 +298,7 @@ fn jit_prepare_routine_call( /// Record the current codeblock write position for rewriting into a jump into /// the outlined block later. Used to implement global code invalidation. fn record_global_inval_patch(asm: &mut Assembler, outline_block_target_pos: CodePtr) { + asm.pad_inval_patch(); asm.pos_marker(move |code_ptr| { CodegenGlobals::push_global_inval_patch(code_ptr, outline_block_target_pos); }); @@ -613,23 +609,10 @@ fn gen_pc_guard(asm: &mut Assembler, iseq: IseqPtr, insn_idx: u32) { /// Compile an interpreter entry block to be inserted into an iseq /// Returns None if compilation fails. pub fn gen_entry_prologue(cb: &mut CodeBlock, iseq: IseqPtr, insn_idx: u32) -> Option { - const MAX_PROLOGUE_SIZE: usize = 1024; - - // Check if we have enough executable memory - if !cb.has_capacity(MAX_PROLOGUE_SIZE) { - return None; - } - - let old_write_pos = cb.get_write_pos(); - - // TODO: figure out if this is actually beneficial for performance - // Align the current write position to cache line boundaries - cb.align_pos(64); - let code_ptr = cb.get_write_ptr(); let mut asm = Assembler::new(); - if get_option!(dump_disasm).is_enabled() { + if get_option_ref!(dump_disasm).is_some() { asm.comment(&format!("YJIT entry: {}", iseq_get_location(iseq))); } else { asm.comment("YJIT entry"); @@ -667,10 +650,11 @@ pub fn gen_entry_prologue(cb: &mut CodeBlock, iseq: IseqPtr, insn_idx: u32) -> O asm.compile(cb); - // Verify MAX_PROLOGUE_SIZE - assert!(cb.get_write_pos() - old_write_pos <= MAX_PROLOGUE_SIZE); - - return Some(code_ptr); + if (cb.has_dropped_bytes()) { + None + } else { + Some(code_ptr) + } } // Generate code to check for interrupts and take a side-exit. @@ -758,7 +742,7 @@ pub fn gen_single_block( let mut asm = Assembler::new(); #[cfg(feature = "disasm")] - if get_option!(dump_disasm).is_enabled() { + if get_option_ref!(dump_disasm).is_some() { asm.comment(&format!("Block: {} (ISEQ offset: {})", iseq_get_location(blockid.iseq), blockid.idx)); } @@ -860,7 +844,7 @@ pub fn gen_single_block( { let mut block = jit.block.borrow_mut(); if block.entry_exit.is_some() { - asm.pad_entry_exit(); + asm.pad_inval_patch(); } // Compile code into the code block @@ -884,6 +868,7 @@ pub fn gen_single_block( // If code for the block doesn't fit, fail if cb.has_dropped_bytes() || ocb.unwrap().has_dropped_bytes() { + free_block(&blockref); return Err(()); } @@ -1918,6 +1903,9 @@ pub const OPT_AREF_MAX_CHAIN_DEPTH: i32 = 2; // up to 5 different classes pub const SEND_MAX_DEPTH: i32 = 5; +// up to 20 different methods for send +pub const SEND_MAX_CHAIN_DEPTH: i32 = 20; + // Codegen for setting an instance variable. // Preconditions: // - receiver is in REG0 @@ -1927,9 +1915,17 @@ fn gen_set_ivar( jit: &mut JITState, ctx: &mut Context, asm: &mut Assembler, - recv: VALUE, + _recv: VALUE, ivar_name: ID, + flags: u32, + argc: i32, ) -> CodegenStatus { + + // This is a .send call and we need to adjust the stack + if flags & VM_CALL_OPT_SEND != 0 { + handle_opt_send_shift_stack(asm, argc as i32, ctx); + } + // Save the PC and SP because the callee may allocate // Note that this modifies REG_SP, which is why we do it first jit_prepare_routine_call(jit, ctx, asm); @@ -1938,14 +1934,12 @@ fn gen_set_ivar( let val_opnd = ctx.stack_pop(1); let recv_opnd = ctx.stack_pop(1); - let ivar_index: u32 = unsafe { rb_obj_ensure_iv_index_mapping(recv, ivar_name) }; - - // Call rb_vm_set_ivar_idx with the receiver, the index of the ivar, and the value + // Call rb_vm_set_ivar_id with the receiver, the ivar name, and the value let val = asm.ccall( - rb_vm_set_ivar_idx as *const u8, + rb_vm_set_ivar_id as *const u8, vec![ recv_opnd, - ivar_index.into(), + Opnd::UImm(ivar_name), val_opnd, ], ); @@ -2023,97 +2017,98 @@ fn gen_get_ivar( return EndBlock; } - // FIXME: Mapping the index could fail when there is too many ivar names. If we're - // compiling for a branch stub that can cause the exception to be thrown from the - // wrong PC. - let ivar_index = - unsafe { rb_obj_ensure_iv_index_mapping(comptime_receiver, ivar_name) }.as_usize(); + let ivar_index = unsafe { + let shape_id = comptime_receiver.shape_of(); + let shape = rb_shape_get_shape_by_id(shape_id); + let mut ivar_index: u32 = 0; + if rb_shape_get_iv_index(shape, ivar_name, &mut ivar_index) { + Some(ivar_index as usize) + } else { + None + } + }; + + // must be before stack_pop + let recv_type = ctx.get_opnd_type(recv_opnd); + + // Upgrade type + if !recv_type.is_heap() { + ctx.upgrade_opnd_type(recv_opnd, Type::UnknownHeap); + } // Pop receiver if it's on the temp stack if recv_opnd != SelfOpnd { ctx.stack_pop(1); } - if USE_RVARGC != 0 { - // Check that the ivar table is big enough - // Check that the slot is inside the ivar table (num_slots > index) - let num_slots = Opnd::mem(32, recv, ROBJECT_OFFSET_NUMIV); - asm.cmp(num_slots, Opnd::UImm(ivar_index as u64)); - asm.jbe(counted_exit!(ocb, side_exit, getivar_idx_out_of_range).into()); + // Guard heap object + if !recv_type.is_heap() { + guard_object_is_heap(asm, recv, side_exit); } // Compile time self is embedded and the ivar index lands within the object - let test_result = unsafe { FL_TEST_RAW(comptime_receiver, VALUE(ROBJECT_EMBED.as_usize())) != VALUE(0) }; - if test_result { - // See ROBJECT_IVPTR() from include/ruby/internal/core/robject.h - - // Guard that self is embedded - // TODO: BT and JC is shorter - asm.comment("guard embedded getivar"); - let flags_opnd = Opnd::mem(64, recv, RUBY_OFFSET_RBASIC_FLAGS); - asm.test(flags_opnd, Opnd::UImm(ROBJECT_EMBED as u64)); - let side_exit = counted_exit!(ocb, side_exit, getivar_megamorphic); - jit_chain_guard( - JCC_JZ, - jit, - &starting_context, - asm, - ocb, - max_chain_depth, - side_exit, - ); + let embed_test_result = unsafe { FL_TEST_RAW(comptime_receiver, VALUE(ROBJECT_EMBED.as_usize())) != VALUE(0) }; - // Load the variable - let offs = ROBJECT_OFFSET_AS_ARY + (ivar_index * SIZEOF_VALUE) as i32; - let ivar_opnd = Opnd::mem(64, recv, offs); + let flags_mask: usize = unsafe { rb_shape_flags_mask() }.as_usize(); + let expected_flags_mask: usize = (RUBY_T_MASK as usize) | !flags_mask | (ROBJECT_EMBED as usize); + let expected_flags = comptime_receiver.builtin_flags() & expected_flags_mask; - // Guard that the variable is not Qundef - asm.cmp(ivar_opnd, Qundef.into()); - let out_val = asm.csel_e(Qnil.into(), ivar_opnd); + // Combined guard for all flags: shape, embeddedness, and T_OBJECT + let flags_opnd = Opnd::mem(64, recv, RUBY_OFFSET_RBASIC_FLAGS); - // Push the ivar on the stack - let out_opnd = ctx.stack_push(Type::Unknown); - asm.mov(out_opnd, out_val); - } else { - // Compile time value is *not* embedded. - - // Guard that value is *not* embedded - // See ROBJECT_IVPTR() from include/ruby/internal/core/robject.h - asm.comment("guard extended getivar"); - let flags_opnd = Opnd::mem(64, recv, RUBY_OFFSET_RBASIC_FLAGS); - asm.test(flags_opnd, Opnd::UImm(ROBJECT_EMBED as u64)); - let megamorphic_side_exit = counted_exit!(ocb, side_exit, getivar_megamorphic); - jit_chain_guard( - JCC_JNZ, - jit, - &starting_context, - asm, - ocb, - max_chain_depth, - megamorphic_side_exit, - ); + asm.comment("guard shape, embedded, and T_OBJECT"); + let flags_opnd = asm.and(flags_opnd, Opnd::UImm(expected_flags_mask as u64)); + asm.cmp(flags_opnd, Opnd::UImm(expected_flags as u64)); + jit_chain_guard( + JCC_JNE, + jit, + &starting_context, + asm, + ocb, + max_chain_depth, + side_exit, + ); - if USE_RVARGC == 0 { - // Check that the extended table is big enough - // Check that the slot is inside the extended table (num_slots > index) - let num_slots = Opnd::mem(32, recv, ROBJECT_OFFSET_NUMIV); - asm.cmp(num_slots, Opnd::UImm(ivar_index as u64)); - asm.jbe(counted_exit!(ocb, side_exit, getivar_idx_out_of_range).into()); + match ivar_index { + // If there is no IVAR index, then the ivar was undefined + // when we entered the compiler. That means we can just return + // nil for this shape + iv name + None => { + let out_opnd = ctx.stack_push(Type::Nil); + asm.mov(out_opnd, Qnil.into()); } + Some(ivar_index) => { + if embed_test_result { + // See ROBJECT_IVPTR() from include/ruby/internal/core/robject.h + + // Load the variable + let offs = ROBJECT_OFFSET_AS_ARY + (ivar_index * SIZEOF_VALUE) as i32; + let ivar_opnd = Opnd::mem(64, recv, offs); + + // Push the ivar on the stack + let out_opnd = ctx.stack_push(Type::Unknown); + asm.mov(out_opnd, ivar_opnd); + } else { + // Compile time value is *not* embedded. + + if USE_RVARGC == 0 { + // Check that the extended table is big enough + // Check that the slot is inside the extended table (num_slots > index) + let num_slots = Opnd::mem(32, recv, ROBJECT_OFFSET_NUMIV); + asm.cmp(num_slots, Opnd::UImm(ivar_index as u64)); + asm.jbe(counted_exit!(ocb, side_exit, getivar_idx_out_of_range).into()); + } - // Get a pointer to the extended table - let tbl_opnd = asm.load(Opnd::mem(64, recv, ROBJECT_OFFSET_AS_HEAP_IVPTR)); - - // Read the ivar from the extended table - let ivar_opnd = Opnd::mem(64, tbl_opnd, (SIZEOF_VALUE * ivar_index) as i32); + // Get a pointer to the extended table + let tbl_opnd = asm.load(Opnd::mem(64, recv, ROBJECT_OFFSET_AS_HEAP_IVPTR)); - // Check that the ivar is not Qundef - asm.cmp(ivar_opnd, Qundef.into()); - let out_val = asm.csel_ne(ivar_opnd, Qnil.into()); + // Read the ivar from the extended table + let ivar_opnd = Opnd::mem(64, tbl_opnd, (SIZEOF_VALUE * ivar_index) as i32); - // Push the ivar on the stack - let out_opnd = ctx.stack_push(Type::Unknown); - asm.mov(out_opnd, out_val); + let out_opnd = ctx.stack_push(Type::Unknown); + asm.mov(out_opnd, ivar_opnd); + } + } } // Jump to next instruction. This allows guard chains to share the same successor. @@ -2136,25 +2131,12 @@ fn gen_getinstancevariable( let ivar_name = jit_get_arg(jit, 0).as_u64(); let comptime_val = jit_peek_at_self(jit); - let comptime_val_klass = comptime_val.class_of(); // Generate a side exit let side_exit = get_side_exit(jit, ocb, ctx); // Guard that the receiver has the same class as the one from compile time. let self_asm_opnd = Opnd::mem(64, CFP, RUBY_OFFSET_CFP_SELF); - jit_guard_known_klass( - jit, - ctx, - asm, - ocb, - comptime_val_klass, - self_asm_opnd, - SelfOpnd, - comptime_val, - GET_IVAR_MAX_DEPTH, - side_exit, - ); gen_get_ivar( jit, @@ -4167,8 +4149,9 @@ fn gen_send_cfunc( ci: *const rb_callinfo, cme: *const rb_callable_method_entry_t, block: Option, - argc: i32, recv_known_klass: *const VALUE, + flags: u32, + argc: i32, ) -> CodegenStatus { let cfunc = unsafe { get_cme_def_body_cfunc(cme) }; let cfunc_argc = unsafe { get_mct_argc(cfunc) }; @@ -4177,8 +4160,6 @@ fn gen_send_cfunc( // Create a side-exit to fall back to the interpreter let side_exit = get_side_exit(jit, ocb, ctx); - let flags = unsafe { vm_ci_flag(ci) }; - // If the function expects a Ruby array of arguments if cfunc_argc < 0 && cfunc_argc != -1 { gen_counter_incr!(asm, send_cfunc_ruby_array_varg); @@ -4247,6 +4228,11 @@ fn gen_send_cfunc( return CantCompile; } + // This is a .send call and we need to adjust the stack + if flags & VM_CALL_OPT_SEND != 0 { + handle_opt_send_shift_stack(asm, argc as i32, ctx); + } + // Points to the receiver operand on the stack let recv = ctx.stack_opnd(argc); @@ -4459,6 +4445,7 @@ fn gen_send_bmethod( ci: *const rb_callinfo, cme: *const rb_callable_method_entry_t, block: Option, + flags: u32, argc: i32, ) -> CodegenStatus { let procv = unsafe { rb_get_def_bmethod_proc((*cme).def) }; @@ -4488,7 +4475,7 @@ fn gen_send_bmethod( } let frame_type = VM_FRAME_MAGIC_BLOCK | VM_FRAME_FLAG_BMETHOD | VM_FRAME_FLAG_LAMBDA; - gen_send_iseq(jit, ctx, asm, ocb, iseq, ci, frame_type, Some(capture.ep), cme, block, argc) + gen_send_iseq(jit, ctx, asm, ocb, iseq, ci, frame_type, Some(capture.ep), cme, block, flags, argc) } fn gen_send_iseq( @@ -4502,11 +4489,11 @@ fn gen_send_iseq( prev_ep: Option<*const VALUE>, cme: *const rb_callable_method_entry_t, block: Option, + flags: u32, argc: i32, ) -> CodegenStatus { let mut argc = argc; - let flags = unsafe { vm_ci_flag(ci) }; // Create a side-exit to fall back to the interpreter let side_exit = get_side_exit(jit, ocb, ctx); @@ -4730,6 +4717,13 @@ fn gen_send_iseq( Some(leaf_builtin_raw) }; if let (None, Some(builtin_info)) = (block, leaf_builtin) { + + // this is a .send call not currently supported for builtins + if flags & VM_CALL_OPT_SEND != 0 { + gen_counter_incr!(asm, send_send_builtin); + return CantCompile; + } + let builtin_argc = unsafe { (*builtin_info).argc }; if builtin_argc + 1 < (C_ARG_OPNDS.len() as i32) { asm.comment("inlined leaf builtin"); @@ -4777,6 +4771,11 @@ fn gen_send_iseq( push_splat_args(required_args, ctx, asm, ocb, side_exit) } + // This is a .send call and we need to adjust the stack + if flags & VM_CALL_OPT_SEND != 0 { + handle_opt_send_shift_stack(asm, argc as i32, ctx); + } + if doing_kw_call { // Here we're calling a method with keyword arguments and specifying // keyword arguments at this call site. @@ -5031,7 +5030,10 @@ fn gen_struct_aref( cme: *const rb_callable_method_entry_t, comptime_recv: VALUE, _comptime_recv_klass: VALUE, + flags: u32, + argc: i32, ) -> CodegenStatus { + if unsafe { vm_ci_argc(ci) } != 0 { return CantCompile; } @@ -5053,6 +5055,11 @@ fn gen_struct_aref( } } + // This is a .send call and we need to adjust the stack + if flags & VM_CALL_OPT_SEND != 0 { + handle_opt_send_shift_stack(asm, argc as i32, ctx); + } + // All structs from the same Struct class should have the same // length. So if our comptime_recv is embedded all runtime // structs of the same class should be as well, and the same is @@ -5086,11 +5093,18 @@ fn gen_struct_aset( cme: *const rb_callable_method_entry_t, comptime_recv: VALUE, _comptime_recv_klass: VALUE, + flags: u32, + argc: i32, ) -> CodegenStatus { if unsafe { vm_ci_argc(ci) } != 1 { return CantCompile; } + // This is a .send call and we need to adjust the stack + if flags & VM_CALL_OPT_SEND != 0 { + handle_opt_send_shift_stack(asm, argc, ctx); + } + let off: i32 = unsafe { get_cme_def_body_optimized_index(cme) } .try_into() .unwrap(); @@ -5132,9 +5146,9 @@ fn gen_send_general( // see vm_call_method(). let ci = unsafe { get_call_data_ci(cd) }; // info about the call site - let argc: i32 = unsafe { vm_ci_argc(ci) }.try_into().unwrap(); - let mid = unsafe { vm_ci_mid(ci) }; - let flags = unsafe { vm_ci_flag(ci) }; + let mut argc: i32 = unsafe { vm_ci_argc(ci) }.try_into().unwrap(); + let mut mid = unsafe { vm_ci_mid(ci) }; + let mut flags = unsafe { vm_ci_flag(ci) }; // Don't JIT calls with keyword splat if flags & VM_CALL_KW_SPLAT != 0 { @@ -5224,7 +5238,7 @@ fn gen_send_general( VM_METHOD_TYPE_ISEQ => { let iseq = unsafe { get_def_iseq_ptr((*cme).def) }; let frame_type = VM_FRAME_MAGIC_METHOD | VM_ENV_FLAG_LOCAL; - return gen_send_iseq(jit, ctx, asm, ocb, iseq, ci, frame_type, None, cme, block, argc); + return gen_send_iseq(jit, ctx, asm, ocb, iseq, ci, frame_type, None, cme, block, flags, argc); } VM_METHOD_TYPE_CFUNC => { return gen_send_cfunc( @@ -5235,8 +5249,9 @@ fn gen_send_general( ci, cme, block, - argc, &comptime_recv_klass, + flags, + argc, ); } VM_METHOD_TYPE_IVAR => { @@ -5246,6 +5261,12 @@ fn gen_send_general( return CantCompile; } + // This is a .send call not supported right now for getters + if flags & VM_CALL_OPT_SEND != 0 { + gen_counter_incr!(asm, send_send_getter); + return CantCompile; + } + if c_method_tracing_currently_enabled(jit) { // Can't generate code for firing c_call and c_return events // :attr-tracing: @@ -5289,12 +5310,12 @@ fn gen_send_general( return CantCompile; } else { let ivar_name = unsafe { get_cme_def_body_attr_id(cme) }; - return gen_set_ivar(jit, ctx, asm, comptime_recv, ivar_name); + return gen_set_ivar(jit, ctx, asm, comptime_recv, ivar_name, flags, argc); } } // Block method, e.g. define_method(:foo) { :my_block } VM_METHOD_TYPE_BMETHOD => { - return gen_send_bmethod(jit, ctx, asm, ocb, ci, cme, block, argc); + return gen_send_bmethod(jit, ctx, asm, ocb, ci, cme, block, flags, argc); } VM_METHOD_TYPE_ZSUPER => { gen_counter_incr!(asm, send_zsuper_method); @@ -5315,11 +5336,116 @@ fn gen_send_general( } // Send family of methods, e.g. call/apply VM_METHOD_TYPE_OPTIMIZED => { + let opt_type = unsafe { get_cme_def_body_optimized_type(cme) }; match opt_type { OPTIMIZED_METHOD_TYPE_SEND => { - gen_counter_incr!(asm, send_optimized_method_send); - return CantCompile; + + // This is for method calls like `foo.send(:bar)` + // The `send` method does not get its own stack frame. + // instead we look up the method and call it, + // doing some stack shifting based on the VM_CALL_OPT_SEND flag + + let starting_context = *ctx; + + if argc == 0 { + gen_counter_incr!(asm, send_send_wrong_args); + return CantCompile; + } + + argc -= 1; + + let compile_time_name = jit_peek_at_stack(jit, ctx, argc as isize); + + if !compile_time_name.string_p() && !compile_time_name.static_sym_p() { + gen_counter_incr!(asm, send_send_chain_not_string_or_sym); + return CantCompile; + } + + mid = unsafe { rb_get_symbol_id(compile_time_name) }; + if mid == 0 { + gen_counter_incr!(asm, send_send_null_mid); + return CantCompile; + } + + cme = unsafe { rb_callable_method_entry(comptime_recv_klass, mid) }; + if cme.is_null() { + gen_counter_incr!(asm, send_send_null_cme); + return CantCompile; + } + + // We aren't going to handle `send(send(:foo))`. We would need to + // do some stack manipulation here or keep track of how many levels + // deep we need to stack manipulate + // Because of how exits currently work, we can't do stack manipulation + // until we will no longer side exit. + let def_type = unsafe { get_cme_def_type(cme) }; + if let VM_METHOD_TYPE_OPTIMIZED = def_type { + let opt_type = unsafe { get_cme_def_body_optimized_type(cme) }; + if let OPTIMIZED_METHOD_TYPE_SEND = opt_type { + gen_counter_incr!(asm, send_send_nested); + return CantCompile; + } + } + + flags |= VM_CALL_FCALL | VM_CALL_OPT_SEND; + + assume_method_lookup_stable(jit, ocb, comptime_recv_klass, cme); + + let (known_class, type_mismatch_exit) = { + if compile_time_name.string_p() { + ( + unsafe { rb_cString }, + counted_exit!(ocb, side_exit, send_send_chain_not_string), + + ) + } else { + ( + unsafe { rb_cSymbol }, + counted_exit!(ocb, side_exit, send_send_chain_not_sym), + ) + } + }; + + jit_guard_known_klass( + jit, + ctx, + asm, + ocb, + known_class, + ctx.stack_opnd(argc), + StackOpnd(argc as u16), + compile_time_name, + 2, // We have string or symbol, so max depth is 2 + type_mismatch_exit + ); + + // Need to do this here so we don't have too many live + // values for the register allocator. + let name_opnd = asm.load(ctx.stack_opnd(argc)); + + let symbol_id_opnd = asm.ccall(rb_get_symbol_id as *const u8, vec![name_opnd]); + + asm.comment("chain_guard_send"); + let chain_exit = counted_exit!(ocb, side_exit, send_send_chain); + asm.cmp(symbol_id_opnd, 0.into()); + asm.jbe(chain_exit.into()); + + asm.cmp(symbol_id_opnd, mid.into()); + jit_chain_guard( + JCC_JNE, + jit, + &starting_context, + asm, + ocb, + SEND_MAX_CHAIN_DEPTH as i32, + chain_exit, + ); + + // We have changed the argc, flags, mid, and cme, so we need to re-enter the match + // and compile whatever method we found from send. + continue; + } OPTIMIZED_METHOD_TYPE_CALL => { gen_counter_incr!(asm, send_optimized_method_call); @@ -5339,6 +5465,8 @@ fn gen_send_general( cme, comptime_recv, comptime_recv_klass, + flags, + argc, ); } OPTIMIZED_METHOD_TYPE_STRUCT_ASET => { @@ -5351,6 +5479,8 @@ fn gen_send_general( cme, comptime_recv, comptime_recv_klass, + flags, + argc, ); } _ => { @@ -5373,6 +5503,32 @@ fn gen_send_general( } } + +/// Shifts the stack for send in order to remove the name of the method +/// Comment below borrow from vm_call_opt_send in vm_insnhelper.c +/// E.g. when argc == 2 +/// | | | | TOPN +/// +------+ | | +/// | arg1 | ---+ | | 0 +/// +------+ | +------+ +/// | arg0 | -+ +-> | arg1 | 1 +/// +------+ | +------+ +/// | sym | +---> | arg0 | 2 +/// +------+ +------+ +/// | recv | | recv | 3 +///--+------+--------+------+------ +/// +/// We do this for our compiletime context and the actual stack +fn handle_opt_send_shift_stack(asm: &mut Assembler, argc: i32, ctx: &mut Context) { + asm.comment("shift_stack"); + for j in (0..argc).rev() { + let opnd = ctx.stack_opnd(j); + let opnd2 = ctx.stack_opnd(j + 1); + asm.mov(opnd2, opnd); + } + ctx.shift_stack(argc as usize); +} + fn gen_opt_send_without_block( jit: &mut JITState, ctx: &mut Context, @@ -5534,10 +5690,10 @@ fn gen_invokesuper( VM_METHOD_TYPE_ISEQ => { let iseq = unsafe { get_def_iseq_ptr((*cme).def) }; let frame_type = VM_FRAME_MAGIC_METHOD | VM_ENV_FLAG_LOCAL; - gen_send_iseq(jit, ctx, asm, ocb, iseq, ci, frame_type, None, cme, block, argc) + gen_send_iseq(jit, ctx, asm, ocb, iseq, ci, frame_type, None, cme, block, ci_flags, argc) } VM_METHOD_TYPE_CFUNC => { - gen_send_cfunc(jit, ctx, asm, ocb, ci, cme, block, argc, ptr::null()) + gen_send_cfunc(jit, ctx, asm, ocb, ci, cme, block, ptr::null(), ci_flags, argc) } _ => unreachable!(), } @@ -6379,29 +6535,13 @@ static mut CODEGEN_GLOBALS: Option = None; impl CodegenGlobals { /// Initialize the codegen globals pub fn init() { - // Executable memory size in MiB - let mem_size = get_option!(exec_mem_size) * 1024 * 1024; + // Executable memory and code page size in bytes + let mem_size = get_option!(exec_mem_size); + let code_page_size = get_option!(code_page_size); #[cfg(not(test))] let (mut cb, mut ocb) = { - // TODO(alan): we can error more gracefully when the user gives - // --yjit-exec-mem=absurdly-large-number - // - // 2 GiB. It's likely a bug if we generate this much code. - const MAX_BUFFER_SIZE: usize = 2 * 1024 * 1024 * 1024; - assert!(mem_size <= MAX_BUFFER_SIZE); - let mem_size_u32 = mem_size as u32; - let half_size = mem_size / 2; - - let page_size = unsafe { rb_yjit_get_page_size() }; - let assert_page_aligned = |ptr| assert_eq!( - 0, - ptr as usize % page_size.as_usize(), - "Start of virtual address block should be page-aligned", - ); - - let virt_block: *mut u8 = unsafe { rb_yjit_reserve_addr_space(mem_size_u32) }; - let second_half = virt_block.wrapping_add(half_size); + let virt_block: *mut u8 = unsafe { rb_yjit_reserve_addr_space(mem_size as u32) }; // Memory protection syscalls need page-aligned addresses, so check it here. Assuming // `virt_block` is page-aligned, `second_half` should be page-aligned as long as the @@ -6410,26 +6550,25 @@ impl CodegenGlobals { // // Basically, we don't support x86-64 2MiB and 1GiB pages. ARMv8 can do up to 64KiB // (2¹⁶ bytes) pages, which should be fine. 4KiB pages seem to be the most popular though. - assert_page_aligned(virt_block); - assert_page_aligned(second_half); + let page_size = unsafe { rb_yjit_get_page_size() }; + assert_eq!( + virt_block as usize % page_size.as_usize(), 0, + "Start of virtual address block should be page-aligned", + ); + assert_eq!(code_page_size % page_size.as_usize(), 0, "code_page_size was not page-aligned"); use crate::virtualmem::*; - let first_half = VirtualMem::new( + let mem_block = VirtualMem::new( SystemAllocator {}, page_size, virt_block, - half_size - ); - let second_half = VirtualMem::new( - SystemAllocator {}, - page_size, - second_half, - half_size + mem_size, ); + let mem_block = Rc::new(RefCell::new(mem_block)); - let cb = CodeBlock::new(first_half, false); - let ocb = OutlinedCb::wrap(CodeBlock::new(second_half, true)); + let cb = CodeBlock::new(mem_block.clone(), code_page_size, false); + let ocb = OutlinedCb::wrap(CodeBlock::new(mem_block, code_page_size, true)); (cb, ocb) }; @@ -6537,6 +6676,10 @@ impl CodegenGlobals { unsafe { CODEGEN_GLOBALS.as_mut().unwrap() } } + pub fn has_instance() -> bool { + unsafe { CODEGEN_GLOBALS.as_mut().is_some() } + } + /// Get a mutable reference to the inline code block pub fn get_inline_cb() -> &'static mut CodeBlock { &mut CodegenGlobals::get_instance().inline_cb @@ -6638,7 +6781,7 @@ mod tests { #[test] fn test_gen_check_ints() { - let (_, _ctx, mut asm, mut cb, mut ocb) = setup_codegen(); + let (_, _ctx, mut asm, _cb, mut ocb) = setup_codegen(); let side_exit = ocb.unwrap().get_write_ptr(); gen_check_ints(&mut asm, side_exit); } @@ -6656,7 +6799,7 @@ mod tests { #[test] fn test_gen_pop() { - let (mut jit, _, mut asm, mut cb, mut ocb) = setup_codegen(); + let (mut jit, _, mut asm, _cb, mut ocb) = setup_codegen(); let mut context = Context::new_with_stack_size(1); let status = gen_pop(&mut jit, &mut context, &mut asm, &mut ocb); @@ -6706,7 +6849,7 @@ mod tests { #[test] fn test_gen_swap() { - let (mut jit, mut context, mut asm, mut cb, mut ocb) = setup_codegen(); + let (mut jit, mut context, mut asm, _cb, mut ocb) = setup_codegen(); context.stack_push(Type::Fixnum); context.stack_push(Type::Flonum); @@ -6774,7 +6917,7 @@ mod tests { #[test] fn test_int2fix() { - let (mut jit, mut context, mut asm, mut cb, mut ocb) = setup_codegen(); + let (mut jit, mut context, mut asm, _cb, mut ocb) = setup_codegen(); jit.opcode = YARVINSN_putobject_INT2FIX_0_.as_usize(); let status = gen_putobject_int2fix(&mut jit, &mut context, &mut asm, &mut ocb); @@ -6863,7 +7006,7 @@ mod tests { #[test] fn test_gen_leave() { - let (mut jit, mut context, mut asm, mut cb, mut ocb) = setup_codegen(); + let (mut jit, mut context, mut asm, _cb, mut ocb) = setup_codegen(); // Push return value context.stack_push(Type::Fixnum); gen_leave(&mut jit, &mut context, &mut asm, &mut ocb); diff --git a/yjit/src/core.rs b/yjit/src/core.rs index 66c1df083fb856..53cb31beb146dc 100644 --- a/yjit/src/core.rs +++ b/yjit/src/core.rs @@ -491,14 +491,14 @@ impl IseqPayload { /// Get the payload for an iseq. For safety it's up to the caller to ensure the returned `&mut` /// upholds aliasing rules and that the argument is a valid iseq. -pub unsafe fn load_iseq_payload(iseq: IseqPtr) -> Option<&'static mut IseqPayload> { - let payload = rb_iseq_get_yjit_payload(iseq); +pub fn get_iseq_payload(iseq: IseqPtr) -> Option<&'static mut IseqPayload> { + let payload = unsafe { rb_iseq_get_yjit_payload(iseq) }; let payload: *mut IseqPayload = payload.cast(); - payload.as_mut() + unsafe { payload.as_mut() } } /// Get the payload object associated with an iseq. Create one if none exists. -fn get_iseq_payload(iseq: IseqPtr) -> &'static mut IseqPayload { +fn get_or_create_iseq_payload(iseq: IseqPtr) -> &'static mut IseqPayload { type VoidPtr = *mut c_void; let payload_non_null = unsafe { @@ -546,6 +546,9 @@ pub extern "C" fn rb_yjit_iseq_free(payload: *mut c_void) { // SAFETY: We got the pointer from Box::into_raw(). let payload = unsafe { Box::from_raw(payload) }; + // Increment the freed iseq count + incr_counter!(freed_iseq_count); + // Remove all blocks in the payload from global invariants table. for versions in &payload.version_map { for block in versions { @@ -585,10 +588,8 @@ pub extern "C" fn rb_yjit_iseq_mark(payload: *mut c_void) { // Mark outgoing branch entries for branch in &block.outgoing { let branch = branch.borrow(); - for target in &branch.targets { - if let Some(target) = target { - unsafe { rb_gc_mark_movable(target.iseq.into()) }; - } + for target in branch.targets.iter().flatten() { + unsafe { rb_gc_mark_movable(target.iseq.into()) }; } } @@ -643,10 +644,8 @@ pub extern "C" fn rb_yjit_iseq_update_references(payload: *mut c_void) { // Update outgoing branch entries for branch in &block.outgoing { let mut branch = branch.borrow_mut(); - for target in &mut branch.targets { - if let Some(target) = target { - target.iseq = unsafe { rb_gc_location(target.iseq.into()) }.as_iseq(); - } + for target in branch.targets.iter_mut().flatten() { + target.iseq = unsafe { rb_gc_location(target.iseq.into()) }.as_iseq(); } } @@ -666,7 +665,7 @@ pub extern "C" fn rb_yjit_iseq_update_references(payload: *mut c_void) { if new_addr != object { for (byte_idx, &byte) in new_addr.as_u64().to_le_bytes().iter().enumerate() { let byte_code_ptr = value_code_ptr.add_bytes(byte_idx); - cb.get_mem().write_byte(byte_code_ptr, byte) + cb.write_mem(byte_code_ptr, byte) .expect("patching existing code should be within bounds"); } } @@ -683,8 +682,19 @@ pub extern "C" fn rb_yjit_iseq_update_references(payload: *mut c_void) { } /// Get all blocks for a particular place in an iseq. -fn get_version_list(blockid: BlockId) -> &'static mut VersionList { - let payload = get_iseq_payload(blockid.iseq); +fn get_version_list(blockid: BlockId) -> Option<&'static mut VersionList> { + let insn_idx = blockid.idx.as_usize(); + match get_iseq_payload(blockid.iseq) { + Some(payload) if insn_idx < payload.version_map.len() => { + Some(payload.version_map.get_mut(insn_idx).unwrap()) + }, + _ => None + } +} + +/// Get or create all blocks for a particular place in an iseq. +fn get_or_create_version_list(blockid: BlockId) -> &'static mut VersionList { + let payload = get_or_create_iseq_payload(blockid.iseq); let insn_idx = blockid.idx.as_usize(); // Expand the version map as necessary @@ -699,32 +709,34 @@ fn get_version_list(blockid: BlockId) -> &'static mut VersionList { /// Take all of the blocks for a particular place in an iseq pub fn take_version_list(blockid: BlockId) -> VersionList { - let payload = get_iseq_payload(blockid.iseq); let insn_idx = blockid.idx.as_usize(); - - if insn_idx >= payload.version_map.len() { - VersionList::default() - } else { - mem::take(&mut payload.version_map[insn_idx]) + match get_iseq_payload(blockid.iseq) { + Some(payload) if insn_idx < payload.version_map.len() => { + mem::take(&mut payload.version_map[insn_idx]) + }, + _ => VersionList::default(), } } /// Count the number of block versions matching a given blockid fn get_num_versions(blockid: BlockId) -> usize { let insn_idx = blockid.idx.as_usize(); - let payload = get_iseq_payload(blockid.iseq); - - payload - .version_map - .get(insn_idx) - .map(|versions| versions.len()) - .unwrap_or(0) + match get_iseq_payload(blockid.iseq) { + Some(payload) => { + payload + .version_map + .get(insn_idx) + .map(|versions| versions.len()) + .unwrap_or(0) + } + None => 0, + } } -/// Get a list of block versions generated for an iseq +/// Get or create a list of block versions generated for an iseq /// This is used for disassembly (see disasm.rs) -pub fn get_iseq_block_list(iseq: IseqPtr) -> Vec { - let payload = get_iseq_payload(iseq); +pub fn get_or_create_iseq_block_list(iseq: IseqPtr) -> Vec { + let payload = get_or_create_iseq_payload(iseq); let mut blocks = Vec::::new(); @@ -745,7 +757,10 @@ pub fn get_iseq_block_list(iseq: IseqPtr) -> Vec { /// Retrieve a basic block version for an (iseq, idx) tuple /// This will return None if no version is found fn find_block_version(blockid: BlockId, ctx: &Context) -> Option { - let versions = get_version_list(blockid); + let versions = match get_version_list(blockid) { + Some(versions) => versions, + None => return None, + }; // Best match found let mut best_version: Option = None; @@ -806,7 +821,7 @@ fn add_block_version(blockref: &BlockRef, cb: &CodeBlock) { // Function entry blocks must have stack size 0 assert!(!(block.blockid.idx == 0 && block.ctx.stack_size > 0)); - let version_list = get_version_list(block.blockid); + let version_list = get_or_create_version_list(block.blockid); version_list.push(blockref.clone()); @@ -834,7 +849,10 @@ fn add_block_version(blockref: &BlockRef, cb: &CodeBlock) { /// Remove a block version from the version map of its parent ISEQ fn remove_block_version(blockref: &BlockRef) { let block = blockref.borrow(); - let version_list = get_version_list(block.blockid); + let version_list = match get_version_list(block.blockid) { + Some(version_list) => version_list, + None => return, + }; // Retain the versions that are not this one version_list.retain(|other| blockref != other); @@ -1061,6 +1079,21 @@ impl Context { return top; } + pub fn shift_stack(&mut self, argc: usize) { + assert!(argc < self.stack_size.into()); + + let method_name_index = (self.stack_size - argc as u16 - 1) as usize; + + for i in method_name_index..(self.stack_size - 1) as usize { + + if i + 1 < MAX_TEMP_TYPES { + self.temp_types[i] = self.temp_types[i + 1]; + self.temp_mapping[i] = self.temp_mapping[i + 1]; + } + } + self.stack_pop(1); + } + /// Get an operand pointing to a slot on the temp stack pub fn stack_opnd(&self, idx: i32) -> Opnd { // SP points just above the topmost value @@ -1405,11 +1438,9 @@ fn gen_block_series_body( if result.is_err() { // Remove previously compiled block // versions from the version map + mem::drop(last_branch); // end borrow for blockref in &batch { - // FIXME: should be deallocating resources here too - // e.g. invariants, etc. - //free_block(blockref) - + free_block(blockref); remove_block_version(blockref); } @@ -1590,9 +1621,10 @@ fn make_branch_entry(block: &BlockRef, src_ctx: &Context, gen_fn: BranchGenFn) - return branchref; } -/// Generated code calls this function with the SysV calling convention. -/// See [get_branch_target]. + c_callable! { + /// Generated code calls this function with the SysV calling convention. + /// See [get_branch_target]. fn branch_stub_hit( branch_ptr: *const c_void, target_idx: u32, @@ -1884,7 +1916,9 @@ pub fn gen_branch( // Call the branch generation function asm.mark_branch_start(&branchref); - gen_fn(asm, branch.dst_addrs[0].unwrap(), branch.dst_addrs[1], BranchShape::Default); + if let Some(dst_addr) = branch.dst_addrs[0] { + gen_fn(asm, dst_addr, branch.dst_addrs[1], BranchShape::Default); + } asm.mark_branch_end(&branchref); } @@ -1923,6 +1957,7 @@ pub fn gen_direct_jump(jit: &JITState, ctx: &Context, target0: BlockId, asm: &mu branch.shape = BranchShape::Default; // Call the branch generation function + asm.comment("gen_direct_jmp: existing block"); asm.mark_branch_start(&branchref); gen_jump_branch(asm, branch.dst_addrs[0].unwrap(), None, BranchShape::Default); asm.mark_branch_end(&branchref); @@ -1933,6 +1968,7 @@ pub fn gen_direct_jump(jit: &JITState, ctx: &Context, target0: BlockId, asm: &mu branch.shape = BranchShape::Next0; // The branch is effectively empty (a noop) + asm.comment("gen_direct_jmp: fallthrough"); asm.mark_branch_start(&branchref); asm.mark_branch_end(&branchref); } @@ -1971,12 +2007,14 @@ pub fn defer_compilation( // Call the branch generation function asm.mark_branch_start(&branch_rc); - gen_jump_branch(asm, branch.dst_addrs[0].unwrap(), None, BranchShape::Default); + if let Some(dst_addr) = branch.dst_addrs[0] { + gen_jump_branch(asm, dst_addr, None, BranchShape::Default); + } asm.mark_branch_end(&branch_rc); } // Remove all references to a block then free it. -fn free_block(blockref: &BlockRef) { +pub fn free_block(blockref: &BlockRef) { use crate::invariants::*; block_assumptions_free(blockref); @@ -2003,14 +2041,12 @@ fn free_block(blockref: &BlockRef) { let out_branch = out_branchref.borrow(); // For each successor block - for succ in &out_branch.blocks { - if let Some(succ) = succ { - // Remove outgoing branch from the successor's incoming list - let mut succ_block = succ.borrow_mut(); - succ_block - .incoming - .retain(|succ_incoming| !Rc::ptr_eq(succ_incoming, out_branchref)); - } + for succ in out_branch.blocks.iter().flatten() { + // Remove outgoing branch from the successor's incoming list + let mut succ_block = succ.borrow_mut(); + succ_block + .incoming + .retain(|succ_incoming| !Rc::ptr_eq(succ_incoming, out_branchref)); } } diff --git a/yjit/src/cruby.rs b/yjit/src/cruby.rs index c379034a4c238e..f31390fc574a3b 100644 --- a/yjit/src/cruby.rs +++ b/yjit/src/cruby.rs @@ -96,6 +96,7 @@ pub type size_t = u64; pub type RedefinitionFlag = u32; #[allow(dead_code)] +#[allow(clippy::useless_transmute)] mod autogened { use super::*; // Textually include output from rust-bindgen as suggested by its user guide. @@ -120,7 +121,7 @@ extern "C" { obj: VALUE, v: VALUE, ) -> bool; - pub fn rb_vm_set_ivar_idx(obj: VALUE, idx: u32, val: VALUE) -> VALUE; + pub fn rb_vm_set_ivar_id(obj: VALUE, idx: u32, val: VALUE) -> VALUE; pub fn rb_vm_setinstancevariable(iseq: IseqPtr, obj: VALUE, id: ID, val: VALUE, ic: IVC); pub fn rb_aliased_callable_method_entry( me: *const rb_callable_method_entry_t, @@ -352,20 +353,32 @@ impl VALUE { self == Qnil } + pub fn string_p(self) -> bool { + self.class_of() == unsafe { rb_cString } + } + /// Read the flags bits from the RBasic object, then return a Ruby type enum (e.g. RUBY_T_ARRAY) pub fn builtin_type(self) -> ruby_value_type { + (self.builtin_flags() & (RUBY_T_MASK as usize)) as ruby_value_type + } + + pub fn builtin_flags(self) -> usize { assert!(!self.special_const_p()); let VALUE(cval) = self; let rbasic_ptr = cval as *const RBasic; let flags_bits: usize = unsafe { (*rbasic_ptr).flags }.as_usize(); - (flags_bits & (RUBY_T_MASK as usize)) as ruby_value_type + return flags_bits; } pub fn class_of(self) -> VALUE { unsafe { CLASS_OF(self) } } + pub fn shape_of(self) -> u32 { + unsafe { rb_shape_get_shape_id(self) } + } + pub fn as_isize(self) -> isize { let VALUE(is) = self; is as isize @@ -621,6 +634,7 @@ mod manual_defs { pub const VM_CALL_KW_SPLAT: u32 = 1 << VM_CALL_KW_SPLAT_bit; pub const VM_CALL_TAILCALL: u32 = 1 << VM_CALL_TAILCALL_bit; pub const VM_CALL_ZSUPER : u32 = 1 << VM_CALL_ZSUPER_bit; + pub const VM_CALL_OPT_SEND : u32 = 1 << VM_CALL_OPT_SEND_bit; // From internal/struct.h - in anonymous enum, so we can't easily import it pub const RSTRUCT_EMBED_LEN_MASK: usize = (RUBY_FL_USER2 | RUBY_FL_USER1) as usize; diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index 3bffc3073126c7..db124c930392f9 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -402,6 +402,29 @@ extern "C" { extern "C" { pub fn rb_reg_new_ary(ary: VALUE, options: ::std::os::raw::c_int) -> VALUE; } +pub type attr_index_t = u32; +pub type shape_id_t = u32; +#[repr(C)] +pub struct rb_shape { + pub edges: *mut rb_id_table, + pub edge_name: ID, + pub iv_count: attr_index_t, + pub type_: u8, + pub parent_id: shape_id_t, +} +pub type rb_shape_t = rb_shape; +extern "C" { + pub fn rb_shape_get_shape_by_id(shape_id: shape_id_t) -> *mut rb_shape_t; +} +extern "C" { + pub fn rb_shape_get_shape_id(obj: VALUE) -> shape_id_t; +} +extern "C" { + pub fn rb_shape_get_iv_index(shape: *mut rb_shape_t, id: ID, value: *mut attr_index_t) -> bool; +} +extern "C" { + pub fn rb_shape_flags_mask() -> VALUE; +} pub const idDot2: ruby_method_ids = 128; pub const idDot3: ruby_method_ids = 129; pub const idUPlus: ruby_method_ids = 132; @@ -719,6 +742,11 @@ pub const OPTIMIZED_METHOD_TYPE_STRUCT_AREF: method_optimized_type = 3; pub const OPTIMIZED_METHOD_TYPE_STRUCT_ASET: method_optimized_type = 4; pub const OPTIMIZED_METHOD_TYPE__MAX: method_optimized_type = 5; pub type method_optimized_type = u32; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct rb_id_table { + _unused: [u8; 0], +} extern "C" { pub fn rb_method_entry_at(obj: VALUE, id: ID) -> *const rb_method_entry_t; } @@ -749,7 +777,7 @@ pub struct iseq_inline_constant_cache { #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct iseq_inline_iv_cache_entry { - pub entry: *mut rb_iv_index_tbl_entry, + pub value: usize, } #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -938,12 +966,6 @@ extern "C" { ) -> *const rb_callable_method_entry_t; } #[repr(C)] -pub struct rb_iv_index_tbl_entry { - pub index: u32, - pub class_serial: rb_serial_t, - pub class_value: VALUE, -} -#[repr(C)] pub struct rb_cvar_class_tbl_entry { pub index: u32, pub global_cvar_state: rb_serial_t, @@ -993,9 +1015,6 @@ extern "C" { extern "C" { pub fn rb_hash_resurrect(hash: VALUE) -> VALUE; } -extern "C" { - pub fn rb_obj_ensure_iv_index_mapping(obj: VALUE, id: ID) -> u32; -} extern "C" { pub fn rb_gvar_get(arg1: ID) -> VALUE; } @@ -1225,6 +1244,7 @@ pub const YARVINSN_trace_putobject_INT2FIX_0_: ruby_vminsn_type = 200; pub const YARVINSN_trace_putobject_INT2FIX_1_: ruby_vminsn_type = 201; pub const VM_INSTRUCTION_SIZE: ruby_vminsn_type = 202; pub type ruby_vminsn_type = u32; +pub type rb_iseq_callback = ::std::option::Option; extern "C" { pub fn rb_vm_insn_addr2opcode(addr: *const ::std::os::raw::c_void) -> ::std::os::raw::c_int; } @@ -1340,6 +1360,9 @@ extern "C" { extern "C" { pub fn rb_get_cme_def_body_attr_id(cme: *const rb_callable_method_entry_t) -> ID; } +extern "C" { + pub fn rb_get_symbol_id(namep: VALUE) -> ID; +} extern "C" { pub fn rb_get_cme_def_body_optimized_type( cme: *const rb_callable_method_entry_t, @@ -1516,9 +1539,8 @@ extern "C" { extern "C" { pub fn rb_assert_cme_handle(handle: VALUE); } -pub type iseq_callback = ::std::option::Option; extern "C" { - pub fn rb_yjit_for_each_iseq(callback: iseq_callback); + pub fn rb_yjit_for_each_iseq(callback: rb_iseq_callback); } extern "C" { pub fn rb_yjit_obj_written( diff --git a/yjit/src/disasm.rs b/yjit/src/disasm.rs index c236d9055d98b5..21ab6b5507e9be 100644 --- a/yjit/src/disasm.rs +++ b/yjit/src/disasm.rs @@ -2,6 +2,7 @@ use crate::core::*; use crate::cruby::*; use crate::yjit::yjit_enabled_p; use crate::asm::CodeBlock; +use crate::options::DumpDisasm; use std::fmt::Write; @@ -42,7 +43,7 @@ pub fn disasm_iseq_insn_range(iseq: IseqPtr, start_idx: u32, end_idx: u32) -> St let mut out = String::from(""); // Get a list of block versions generated for this iseq - let mut block_list = get_iseq_block_list(iseq); + let mut block_list = get_or_create_iseq_block_list(iseq); // Get a list of codeblocks relevant to this iseq let global_cb = crate::codegen::CodegenGlobals::get_inline_cb(); @@ -70,11 +71,8 @@ pub fn disasm_iseq_insn_range(iseq: IseqPtr, start_idx: u32, end_idx: u32) -> St total_code_size += blockref.borrow().code_size(); } - out.push_str(&format!("NUM BLOCK VERSIONS: {}\n", block_list.len())); - out.push_str(&format!( - "TOTAL INLINE CODE SIZE: {} bytes\n", - total_code_size - )); + writeln!(out, "NUM BLOCK VERSIONS: {}", block_list.len()).unwrap(); + writeln!(out, "TOTAL INLINE CODE SIZE: {} bytes", total_code_size).unwrap(); // For each block, sorted by increasing start address for block_idx in 0..block_list.len() { @@ -95,10 +93,10 @@ pub fn disasm_iseq_insn_range(iseq: IseqPtr, start_idx: u32, end_idx: u32) -> St end_idx, code_size ); - out.push_str(&format!("== {:=<60}\n", block_ident)); + writeln!(out, "== {:=<60}", block_ident).unwrap(); // Disassemble the instructions - out.push_str(&disasm_addr_range(global_cb, start_addr, code_size)); + out.push_str(&disasm_addr_range(global_cb, start_addr, (start_addr as usize + code_size) as *const u8)); // If this is not the last block if block_idx < block_list.len() - 1 { @@ -109,7 +107,7 @@ pub fn disasm_iseq_insn_range(iseq: IseqPtr, start_idx: u32, end_idx: u32) -> St // Log the size of the gap between the blocks if nonzero if gap_size > 0 { - out.push_str(&format!("... {} byte gap ...\n", gap_size)); + writeln!(out, "... {} byte gap ...", gap_size).unwrap(); } } } @@ -118,9 +116,25 @@ pub fn disasm_iseq_insn_range(iseq: IseqPtr, start_idx: u32, end_idx: u32) -> St return out; } +#[cfg(feature = "disasm")] +pub fn dump_disasm_addr_range(cb: &CodeBlock, start_addr: *const u8, end_addr: *const u8, dump_disasm: &DumpDisasm) { + use std::fs::File; + use std::io::Write; + + let disasm = disasm_addr_range(cb, start_addr, end_addr); + if disasm.len() > 0 { + match dump_disasm { + DumpDisasm::Stdout => println!("{disasm}"), + DumpDisasm::File(path) => { + let mut f = File::options().append(true).create(true).open(path).unwrap(); + f.write_all(disasm.as_bytes()).unwrap(); + } + }; + } +} #[cfg(feature = "disasm")] -pub fn disasm_addr_range(cb: &CodeBlock, start_addr: *const u8, code_size: usize) -> String { +pub fn disasm_addr_range(cb: &CodeBlock, start_addr: *const u8, end_addr: *const u8) -> String { let mut out = String::from(""); // Initialize capstone @@ -141,9 +155,10 @@ pub fn disasm_addr_range(cb: &CodeBlock, start_addr: *const u8, code_size: usize .detail(true) .build() .unwrap(); - cs.set_skipdata(true); + cs.set_skipdata(true).unwrap(); // Disassemble the instructions + let code_size = end_addr as usize - start_addr as usize; let code_slice = unsafe { std::slice::from_raw_parts(start_addr, code_size) }; let insns = cs.disasm_all(code_slice, start_addr as u64).unwrap(); @@ -209,7 +224,7 @@ fn insns_compiled(iseq: IseqPtr) -> Vec<(String, u32)> { let mut insn_vec = Vec::new(); // Get a list of block versions generated for this iseq - let block_list = get_iseq_block_list(iseq); + let block_list = get_or_create_iseq_block_list(iseq); // For each block associated with this iseq for blockref in &block_list { diff --git a/yjit/src/invariants.rs b/yjit/src/invariants.rs index c7c0701e7447a5..07de3374c8ea7a 100644 --- a/yjit/src/invariants.rs +++ b/yjit/src/invariants.rs @@ -535,7 +535,7 @@ pub extern "C" fn rb_yjit_tracing_invalidate_all() { unsafe { rb_yjit_for_each_iseq(Some(invalidate_all_blocks_for_tracing)) }; extern "C" fn invalidate_all_blocks_for_tracing(iseq: IseqPtr) { - if let Some(payload) = unsafe { load_iseq_payload(iseq) } { + if let Some(payload) = unsafe { get_iseq_payload(iseq) } { // C comment: // Leaking the blocks for now since we might have situations where // a different ractor is waiting for the VM lock in branch_stub_hit(). diff --git a/yjit/src/options.rs b/yjit/src/options.rs index f73dca67de21bb..303ae4980f5fbb 100644 --- a/yjit/src/options.rs +++ b/yjit/src/options.rs @@ -4,9 +4,14 @@ use std::ffi::CStr; #[derive(Clone, PartialEq, Eq, Debug)] #[repr(C)] pub struct Options { - // Size of the executable memory block to allocate in MiB + // Size of the executable memory block to allocate in bytes + // Note that the command line argument is expressed in MiB and not bytes pub exec_mem_size: usize, + // Size of each executable memory code page in bytes + // Note that the command line argument is expressed in KiB and not bytes + pub code_page_size: usize, + // Number of method calls after which to start generating code // Threshold==1 means compile on first execution pub call_threshold: usize, @@ -31,7 +36,7 @@ pub struct Options { pub dump_insns: bool, /// Dump all compiled instructions of target cbs. - pub dump_disasm: DumpDisasm, + pub dump_disasm: Option, /// Print when specific ISEQ items are compiled or invalidated pub dump_iseq_disasm: Option, @@ -48,7 +53,8 @@ pub struct Options { // Initialize the options to default values pub static mut OPTIONS: Options = Options { - exec_mem_size: 256, + exec_mem_size: 256 * 1024 * 1024, + code_page_size: 16 * 1024, call_threshold: 10, greedy_versioning: false, no_type_prop: false, @@ -56,26 +62,18 @@ pub static mut OPTIONS: Options = Options { gen_stats: false, gen_trace_exits: false, dump_insns: false, - dump_disasm: DumpDisasm::None, + dump_disasm: None, verify_ctx: false, global_constant_state: false, dump_iseq_disasm: None, }; -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum DumpDisasm { - // Dump only inline cb - Inline, - // Dump both inline and outlined cbs - All, - // Dont dump anything - None, -} - -impl DumpDisasm { - pub fn is_enabled(&self) -> bool { - *self != DumpDisasm::None - } + // Dump to stdout + Stdout, + // Dump to "yjit_{pid}.log" file under the specified directory + File(String), } /// Macro to get an option value by name @@ -118,8 +116,30 @@ pub fn parse_option(str_ptr: *const std::os::raw::c_char) -> Option<()> { match (opt_name, opt_val) { ("", "") => (), // Simply --yjit - ("exec-mem-size", _) => match opt_val.parse() { - Ok(n) => unsafe { OPTIONS.exec_mem_size = n }, + ("exec-mem-size", _) => match opt_val.parse::() { + Ok(n) => { + if n == 0 || n > 2 * 1024 * 1024 { + return None + } + + // Convert from MiB to bytes internally for convenience + unsafe { OPTIONS.exec_mem_size = n * 1024 * 1024 } + } + Err(_) => { + return None; + } + }, + + ("code-page-size", _) => match opt_val.parse::() { + Ok(n) => { + // Enforce bounds checks and that n is divisible by 4KiB + if n < 4 || n > 256 || n % 4 != 0 { + return None + } + + // Convert from KiB to bytes internally for convenience + unsafe { OPTIONS.code_page_size = n * 1024 } + } Err(_) => { return None; } @@ -140,9 +160,13 @@ pub fn parse_option(str_ptr: *const std::os::raw::c_char) -> Option<()> { }, ("dump-disasm", _) => match opt_val.to_string().as_str() { - "all" => unsafe { OPTIONS.dump_disasm = DumpDisasm::All }, - "" => unsafe { OPTIONS.dump_disasm = DumpDisasm::Inline }, - _ => return None, + "" => unsafe { OPTIONS.dump_disasm = Some(DumpDisasm::Stdout) }, + directory => { + let pid = std::process::id(); + let path = format!("{directory}/yjit_{pid}.log"); + println!("YJIT disasm dump: {path}"); + unsafe { OPTIONS.dump_disasm = Some(DumpDisasm::File(path)) } + } }, ("dump-iseq-disasm", _) => unsafe { diff --git a/yjit/src/stats.rs b/yjit/src/stats.rs index 74319ec4edb088..0ad77fc5df1230 100644 --- a/yjit/src/stats.rs +++ b/yjit/src/stats.rs @@ -171,7 +171,6 @@ make_counters! { send_zsuper_method, send_undef_method, send_optimized_method, - send_optimized_method_send, send_optimized_method_call, send_optimized_method_block_call, send_missing_method, @@ -197,6 +196,19 @@ make_counters! { send_args_splat_non_iseq, send_args_splat_cfunc, send_iseq_ruby2_keywords, + send_send_not_imm, + send_send_wrong_args, + send_send_null_mid, + send_send_null_cme, + send_send_nested, + send_send_chain, + send_send_chain_string, + send_send_chain_not_string, + send_send_chain_not_sym, + send_send_chain_not_string_or_sym, + send_send_getter, + send_send_builtin, + send_bmethod_ractor, send_bmethod_block_arg, @@ -240,6 +252,7 @@ make_counters! { compiled_iseq_count, compiled_block_count, compilation_failure, + freed_iseq_count, exit_from_branch_stub, diff --git a/yjit/src/utils.rs b/yjit/src/utils.rs index bea57e4fc24a5d..b156c9d5eda721 100644 --- a/yjit/src/utils.rs +++ b/yjit/src/utils.rs @@ -74,14 +74,13 @@ pub(crate) use offset_of; // This should work fine on ASCII strings and anything else // that is considered legal UTF-8, including embedded nulls. fn ruby_str_to_rust(v: VALUE) -> String { - // Make sure the CRuby encoding is UTF-8 compatible - let encoding = unsafe { rb_ENCODING_GET(v) } as u32; - assert!(encoding == RUBY_ENCINDEX_ASCII_8BIT || encoding == RUBY_ENCINDEX_UTF_8 || encoding == RUBY_ENCINDEX_US_ASCII); - let str_ptr = unsafe { rb_RSTRING_PTR(v) } as *mut u8; let str_len: usize = unsafe { rb_RSTRING_LEN(v) }.try_into().unwrap(); let str_slice: &[u8] = unsafe { slice::from_raw_parts(str_ptr, str_len) }; - String::from_utf8(str_slice.to_vec()).unwrap() // does utf8 validation + match String::from_utf8(str_slice.to_vec()) { + Ok(utf8) => utf8, + Err(_) => String::new(), + } } // Location is the file defining the method, colon, method name. @@ -122,12 +121,20 @@ yjit_print_iseq(const rb_iseq_t *iseq) #[cfg(target_arch = "aarch64")] macro_rules! c_callable { - (fn $f:ident $args:tt $(-> $ret:ty)? $body:block) => { extern "C" fn $f $args $(-> $ret)? $body }; + ($(#[$outer:meta])* + fn $f:ident $args:tt $(-> $ret:ty)? $body:block) => { + $(#[$outer])* + extern "C" fn $f $args $(-> $ret)? $body + }; } #[cfg(target_arch = "x86_64")] macro_rules! c_callable { - (fn $f:ident $args:tt $(-> $ret:ty)? $body:block) => { extern "sysv64" fn $f $args $(-> $ret)? $body }; + ($(#[$outer:meta])* + fn $f:ident $args:tt $(-> $ret:ty)? $body:block) => { + $(#[$outer])* + extern "sysv64" fn $f $args $(-> $ret)? $body + }; } pub(crate) use c_callable; diff --git a/yjit/src/virtualmem.rs b/yjit/src/virtualmem.rs index 8d34e521b9c5d1..4d7c061ec7f406 100644 --- a/yjit/src/virtualmem.rs +++ b/yjit/src/virtualmem.rs @@ -141,10 +141,16 @@ impl VirtualMemory { if !alloc.mark_writable(mapped_region_end.cast(), alloc_size_u32) { return Err(FailedPageMapping); } - // Fill new memory with PUSH DS (0x1E) so that executing uninitialized memory - // will fault with #UD in 64-bit mode. On Linux it becomes SIGILL and use the - // usual Ruby crash reporter. - std::slice::from_raw_parts_mut(mapped_region_end, alloc_size).fill(0x1E); + if cfg!(target_arch = "x86_64") { + // Fill new memory with PUSH DS (0x1E) so that executing uninitialized memory + // will fault with #UD in 64-bit mode. On Linux it becomes SIGILL and use the + // usual Ruby crash reporter. + std::slice::from_raw_parts_mut(mapped_region_end, alloc_size).fill(0x1E); + } else if cfg!(target_arch = "aarch64") { + // In aarch64, all zeros encodes UDF, so it's already what we want. + } else { + unreachable!("unknown arch"); + } } self.mapped_region_bytes = self.mapped_region_bytes + alloc_size; @@ -309,6 +315,7 @@ pub mod tests { } #[test] + #[cfg(target_arch = "x86_64")] fn new_memory_is_initialized() { let mut virt = new_dummy_virt_mem();