diff options
147 files changed, 2076 insertions, 1027 deletions
@@ -51,7 +51,7 @@ define rp printf "%sT_OBJECT%s: ", $color_type, $color_end print ((struct RObject *)($arg0))->basic if ($flags & ROBJECT_EMBED) - print/x *((VALUE*)((struct RObject*)($arg0))->as.ary) @ (rb_shape_get_shape($arg0)->capacity) + print/x *((VALUE*)((struct RObject*)($arg0))->as.ary) @ (RSHAPE_CAPACITY(rb_obj_shape_id($arg0))) else print (((struct RObject *)($arg0))->as.heap) if (((struct RObject*)($arg0))->as.heap.numiv) > 0 diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 426893be2a..2c2982d1d4 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -16,3 +16,7 @@ updates: directory: '/yjit' schedule: interval: 'daily' + - package-ecosystem: 'vcpkg' + directory: '/' + schedule: + interval: 'daily' diff --git a/.github/workflows/check_dependencies.yml b/.github/workflows/check_dependencies.yml index 6d85cf8e9c..db93e90efb 100644 --- a/.github/workflows/check_dependencies.yml +++ b/.github/workflows/check_dependencies.yml @@ -48,11 +48,7 @@ jobs: - name: Run configure run: ./configure -C --disable-install-doc --disable-rubygems --with-gcc 'optflags=-O0' 'debugflags=-save-temps=obj -g' - - run: make all golf - - - run: ./goruby -veh - - - run: ruby tool/update-deps --fix + - run: make fix-depends - run: git diff --no-ext-diff --ignore-submodules --exit-code diff --git a/.github/workflows/dependabot_automerge.yml b/.github/workflows/dependabot_automerge.yml index 2d2427a907..3a2ba704ae 100644 --- a/.github/workflows/dependabot_automerge.yml +++ b/.github/workflows/dependabot_automerge.yml @@ -17,7 +17,7 @@ jobs: id: metadata - name: Wait for status checks - uses: lewagon/wait-on-check-action@31f07a800aa1ba8518509dc8561cdf5a891deb4b # v1.4.0 + uses: lewagon/wait-on-check-action@0dceb95e7c4cad8cc7422aee3885998f5cab9c79 # v1.4.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} ref: ${{ github.event.pull_request.head.sha || github.sha }} diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 27cd43bf9c..8955ea91d4 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -191,6 +191,11 @@ jobs: if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }} continue-on-error: ${{ matrix.continue-on-skipped_tests || false }} + - name: test-pc + run: | + DESTDIR=${RUNNER_TEMP-${TMPDIR-/tmp}}/installed + $SETARCH make test-pc "DESTDIR=$DESTDIR" + - uses: ./.github/actions/slack with: label: ${{ matrix.test_task }} ${{ matrix.configure }}${{ matrix.arch }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 0b7bf25d95..3e85f7a1c5 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -86,7 +86,7 @@ jobs: - name: Restore vcpkg artifact id: restore-vcpkg - uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 with: path: src\vcpkg_installed key: windows-${{ matrix.os }}-vcpkg-${{ hashFiles('src/vcpkg.json') }} @@ -98,7 +98,7 @@ jobs: if: ${{ ! steps.restore-vcpkg.outputs.cache-hit }} - name: Save vcpkg artifact - uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + uses: actions/cache/save@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 with: path: src\vcpkg_installed key: windows-${{ matrix.os }}-vcpkg-${{ hashFiles('src/vcpkg.json') }} diff --git a/.gitignore b/.gitignore index ddf8e9a99a..6cf5fb5f32 100644 --- a/.gitignore +++ b/.gitignore @@ -272,6 +272,7 @@ lcov*.info /prism/prettyprint.c /prism/serialize.c /prism/token_type.c +/prism/srcs.mk # tool/update-NEWS-gemlist.rb /bundled_gems.json diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb index b1e9e3a79d..4a58ece8ac 100644 --- a/bootstraptest/test_ractor.rb +++ b/bootstraptest/test_ractor.rb @@ -1573,6 +1573,33 @@ assert_equal 'true', %q{ rs.map{|r| r.value} == Array.new(RN){n} } +# check method cache invalidation +assert_equal 'true', %q{ + class Foo + def hello = nil + end + + r1 = Ractor.new do + 1000.times do + class Foo + def hello = nil + end + end + end + + r2 = Ractor.new do + 1000.times do + o = Foo.new + o.hello + end + end + + r1.value + r2.value + + true +} + # check experimental warning assert_match /\Atest_ractor\.rb:1:\s+warning:\s+Ractor is experimental/, %q{ Warning[:experimental] = $VERBOSE = true @@ -205,83 +205,6 @@ $(PRISM_BUILD_DIR)/.time $(PRISM_BUILD_DIR)/util/.time: $(Q) $(MAKEDIRS) $(@D) @$(NULLCMD) > $@ -main: $(srcdir)/lib/prism/compiler.rb -srcs: $(srcdir)/lib/prism/compiler.rb -$(srcdir)/lib/prism/compiler.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/compiler.rb.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/compiler.rb $(srcdir)/lib/prism/compiler.rb - -main: $(srcdir)/lib/prism/dispatcher.rb -srcs: $(srcdir)/lib/prism/dispatcher.rb -$(srcdir)/lib/prism/dispatcher.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/dispatcher.rb.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/dispatcher.rb $(srcdir)/lib/prism/dispatcher.rb - -main: $(srcdir)/lib/prism/dsl.rb -srcs: $(srcdir)/lib/prism/dsl.rb -$(srcdir)/lib/prism/dsl.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/dsl.rb.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/dsl.rb $(srcdir)/lib/prism/dsl.rb - -main: $(srcdir)/lib/prism/inspect_visitor.rb -srcs: $(srcdir)/lib/prism/inspect_visitor.rb -$(srcdir)/lib/prism/inspect_visitor.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/inspect_visitor.rb.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/inspect_visitor.rb $(srcdir)/lib/prism/inspect_visitor.rb - -main: $(srcdir)/lib/prism/mutation_compiler.rb -srcs: $(srcdir)/lib/prism/mutation_compiler.rb -$(srcdir)/lib/prism/mutation_compiler.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/mutation_compiler.rb.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/mutation_compiler.rb $(srcdir)/lib/prism/mutation_compiler.rb - -main: $(srcdir)/lib/prism/node.rb -srcs: $(srcdir)/lib/prism/node.rb -$(srcdir)/lib/prism/node.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/node.rb.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/node.rb $(srcdir)/lib/prism/node.rb - -main: $(srcdir)/lib/prism/reflection.rb -srcs: $(srcdir)/lib/prism/reflection.rb -$(srcdir)/lib/prism/reflection.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/reflection.rb.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/reflection.rb $(srcdir)/lib/prism/reflection.rb - -main: $(srcdir)/lib/prism/serialize.rb -srcs: $(srcdir)/lib/prism/serialize.rb -$(srcdir)/lib/prism/serialize.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/serialize.rb.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/serialize.rb $(srcdir)/lib/prism/serialize.rb - -main: $(srcdir)/lib/prism/visitor.rb -srcs: $(srcdir)/lib/prism/visitor.rb -$(srcdir)/lib/prism/visitor.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/visitor.rb.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/visitor.rb $(srcdir)/lib/prism/visitor.rb - -srcs: prism/api_node.c -prism/api_node.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/ext/prism/api_node.c.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb ext/prism/api_node.c $@ - -srcs: prism/ast.h -prism/ast.h: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/include/prism/ast.h.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb include/prism/ast.h $@ - -srcs: prism/diagnostic.c -prism/diagnostic.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/src/diagnostic.c.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb src/diagnostic.c $@ - -srcs: prism/diagnostic.h -prism/diagnostic.h: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/include/prism/diagnostic.h.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb include/prism/diagnostic.h $@ - -srcs: prism/node.c -prism/node.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/src/node.c.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb src/node.c $@ - -srcs: prism/prettyprint.c -prism/prettyprint.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/src/prettyprint.c.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb src/prettyprint.c $@ - -srcs: prism/serialize.c -prism/serialize.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/src/serialize.c.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb src/serialize.c $@ - -srcs: prism/token_type.c -prism/token_type.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/src/token_type.c.erb - $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb src/token_type.c $@ - EXPORTOBJS = $(DLNOBJ) \ localeinit.$(OBJEXT) \ loadpath.$(OBJEXT) \ @@ -797,7 +720,8 @@ clean-srcs-local:: realclean-srcs-local:: clean-srcs-local $(Q)$(CHDIR) $(srcdir) && $(RM) \ parse.c parse.h lex.c enc/trans/newline.c $(PRELUDES) revision.h \ - id.c id.h probes.dmyh configure aclocal.m4 tool/config.guess tool/config.sub gems/*.gem \ + id.c id.h probes.dmyh configure aclocal.m4 tool/config.guess tool/config.sub \ + $(PRISM_SRCDIR)/srcs.mk gems/*.gem \ || $(NULLCMD) clean-srcs-ext:: @@ -1290,7 +1214,6 @@ incs: $(INSNS) {$(VPATH)}node_name.inc {$(VPATH)}known_errors.inc \ {$(VPATH)}vm_call_iseq_optimized.inc $(srcdir)/revision.h \ $(REVISION_H) \ $(UNICODE_DATA_HEADERS) $(ENC_HEADERS) \ - $(srcs_vpath)prism/ast.h $(srcs_vpath)prism/diagnostic.h \ {$(VPATH)}id.h {$(VPATH)}probes.dmyh insns: $(INSNS) @@ -1379,6 +1302,11 @@ $(REVISION_H)$(yes_baseruby:yes=~disabled~): # uncommon.mk: $(REVISION_H) # $(MKFILES): $(REVISION_H) +# $(common_mk_includes) is set by config.status or GNUmakefile +common_mk__$(gnumake:yes=artifact)_ = uncommon.mk +common_mk_$(gnumake)_artifact_ = $(MKFILES) +$(common_mk__artifact_): $(srcdir)/common.mk $(common_mk_includes) + ripper_srcs: $(RIPPER_SRCS) $(RIPPER_SRCS): $(srcdir)/parse.y $(srcdir)/defs/id.def @@ -1915,6 +1843,9 @@ clean-gems: CLEAN_CACHE = clean-extlibs +prepare-package: prereq after-update +clean-cache: $(CLEAN_CACHE) + info: info-program info-libruby_a info-libruby_so info-arch info-program: PHONY @echo PROGRAM=$(PROGRAM) @@ -2046,3 +1977,6 @@ help: PHONY $(CROSS_COMPILING:yes=)builtin.$(OBJEXT): {$(VPATH)}mini_builtin.c $(CROSS_COMPILING:yes=)builtin.$(OBJEXT): {$(VPATH)}miniprelude.c + +!include $(srcdir)/prism/srcs.mk +!include $(srcdir)/depend diff --git a/configure.ac b/configure.ac index c8018cdabb..fdff2469cb 100644 --- a/configure.ac +++ b/configure.ac @@ -4698,8 +4698,12 @@ AC_CONFIG_FILES(Makefile:template/Makefile.in, [ sed '/^MISSING/s/\$U\././g;/^VCS *=/s#@VCS@#'"$VCS"'#;/^VCSUP *=/s#@VCSUP@#'"$VCSUP"'#' Makefile echo; test x"$EXEEXT" = x || echo 'miniruby: miniruby$(EXEEXT)' AS_IF([test "$gnumake" != yes], [ - echo ['$(MKFILES): $(srcdir)/common.mk $(srcdir)/depend'] - sed ['s/{\$([^(){}]*)[^{}]*}//g'] ${srcdir}/common.mk ${srcdir}/depend + # extract NMake-style include list + set = `sed -n 's/^!include *//p' ${srcdir}/common.mk` + echo common_mk_includes "@S|@*" # generate the macro assignment + shift + common_mk_includes="`echo \"@S|@*\" | sed 's|\$(srcdir)|.|g'`" + (PWD= cd ${srcdir} && sed -f tool/prereq.status common.mk ${common_mk_includes}) AS_IF([test "$YJIT_SUPPORT" = yes], [ cat ${srcdir}/yjit/not_gmake.mk echo ['$(MKFILES): ${srcdir}/yjit/not_gmake.mk'] @@ -4722,6 +4726,7 @@ AC_CONFIG_FILES(Makefile:template/Makefile.in, [ ]) && test -z "`${MAKE-make} -f $tmpgmk info-program | grep '^PROGRAM=ruby$'`" && echo 'ruby: $(PROGRAM);' >> $tmpmk + rm -f uncommon.mk # remove stale uncommon.mk, it should be updated by GNUmakefile test "$tmpmk" = "$tmpgmk" || rm -f "$tmpgmk" ]) && mv -f $tmpmk Makefile], [EXEEXT='$EXEEXT' MAKE='${MAKE-make}' gnumake='$gnumake' GIT='$GIT' YJIT_SUPPORT='$YJIT_SUPPORT']) diff --git a/defs/gmake.mk b/defs/gmake.mk index 6382e3d003..bd4b8b8e39 100644 --- a/defs/gmake.mk +++ b/defs/gmake.mk @@ -505,6 +505,9 @@ update-deps: $(GIT) --git-dir=$(GIT_DIR) merge --no-edit --ff-only $(update_deps) $(GIT) --git-dir=$(GIT_DIR) branch --delete $(update_deps) +fix-depends check-depends: all hello + $(BASERUBY) -C $(srcdir) tool/update-deps $(if $(filter fix-%,$@),--fix) + # order-only-prerequisites doesn't work for $(RUBYSPEC_CAPIEXT) # because the same named directory exists in the source tree. $(RUBYSPEC_CAPIEXT)/%.$(DLEXT): $(srcdir)/$(RUBYSPEC_CAPIEXT)/%.c $(RUBYSPEC_CAPIEXT_DEPS) \ @@ -303,7 +303,9 @@ 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): $(top_srcdir)/prism/ast.h ast.$(OBJEXT): $(top_srcdir)/prism/defines.h +ast.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h ast.$(OBJEXT): $(top_srcdir)/prism/encoding.h ast.$(OBJEXT): $(top_srcdir)/prism/node.h ast.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -323,6 +325,7 @@ ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +ast.$(OBJEXT): $(top_srcdir)/prism/version.h ast.$(OBJEXT): {$(VPATH)}assert.h ast.$(OBJEXT): {$(VPATH)}ast.c ast.$(OBJEXT): {$(VPATH)}ast.rbinc @@ -501,9 +504,6 @@ ast.$(OBJEXT): {$(VPATH)}missing.h ast.$(OBJEXT): {$(VPATH)}node.h ast.$(OBJEXT): {$(VPATH)}onigmo.h ast.$(OBJEXT): {$(VPATH)}oniguruma.h -ast.$(OBJEXT): {$(VPATH)}prism/ast.h -ast.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -ast.$(OBJEXT): {$(VPATH)}prism/version.h ast.$(OBJEXT): {$(VPATH)}prism_compile.h ast.$(OBJEXT): {$(VPATH)}ruby_assert.h ast.$(OBJEXT): {$(VPATH)}ruby_atomic.h @@ -746,7 +746,9 @@ 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): $(top_srcdir)/prism/ast.h builtin.$(OBJEXT): $(top_srcdir)/prism/defines.h +builtin.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h builtin.$(OBJEXT): $(top_srcdir)/prism/encoding.h builtin.$(OBJEXT): $(top_srcdir)/prism/node.h builtin.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -766,6 +768,7 @@ builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +builtin.$(OBJEXT): $(top_srcdir)/prism/version.h builtin.$(OBJEXT): {$(VPATH)}assert.h builtin.$(OBJEXT): {$(VPATH)}atomic.h builtin.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -944,9 +947,6 @@ builtin.$(OBJEXT): {$(VPATH)}missing.h builtin.$(OBJEXT): {$(VPATH)}node.h builtin.$(OBJEXT): {$(VPATH)}onigmo.h builtin.$(OBJEXT): {$(VPATH)}oniguruma.h -builtin.$(OBJEXT): {$(VPATH)}prism/ast.h -builtin.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -builtin.$(OBJEXT): {$(VPATH)}prism/version.h builtin.$(OBJEXT): {$(VPATH)}prism_compile.h builtin.$(OBJEXT): {$(VPATH)}ruby_assert.h builtin.$(OBJEXT): {$(VPATH)}ruby_atomic.h @@ -1391,7 +1391,9 @@ compile.$(OBJEXT): $(top_srcdir)/internal/thread.h compile.$(OBJEXT): $(top_srcdir)/internal/variable.h compile.$(OBJEXT): $(top_srcdir)/internal/vm.h compile.$(OBJEXT): $(top_srcdir)/internal/warnings.h +compile.$(OBJEXT): $(top_srcdir)/prism/ast.h compile.$(OBJEXT): $(top_srcdir)/prism/defines.h +compile.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h compile.$(OBJEXT): $(top_srcdir)/prism/encoding.h compile.$(OBJEXT): $(top_srcdir)/prism/node.h compile.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -1399,6 +1401,7 @@ compile.$(OBJEXT): $(top_srcdir)/prism/pack.h compile.$(OBJEXT): $(top_srcdir)/prism/parser.h compile.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h compile.$(OBJEXT): $(top_srcdir)/prism/prism.h +compile.$(OBJEXT): $(top_srcdir)/prism/prism.h compile.$(OBJEXT): $(top_srcdir)/prism/regexp.h compile.$(OBJEXT): $(top_srcdir)/prism/static_literals.h compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h @@ -1411,6 +1414,7 @@ compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +compile.$(OBJEXT): $(top_srcdir)/prism/version.h compile.$(OBJEXT): $(top_srcdir)/prism_compile.c compile.$(OBJEXT): {$(VPATH)}assert.h compile.$(OBJEXT): {$(VPATH)}atomic.h @@ -1597,10 +1601,6 @@ compile.$(OBJEXT): {$(VPATH)}node.h compile.$(OBJEXT): {$(VPATH)}onigmo.h compile.$(OBJEXT): {$(VPATH)}oniguruma.h compile.$(OBJEXT): {$(VPATH)}optinsn.inc -compile.$(OBJEXT): {$(VPATH)}prism/ast.h -compile.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -compile.$(OBJEXT): {$(VPATH)}prism/prism.h -compile.$(OBJEXT): {$(VPATH)}prism/version.h compile.$(OBJEXT): {$(VPATH)}prism_compile.c compile.$(OBJEXT): {$(VPATH)}prism_compile.h compile.$(OBJEXT): {$(VPATH)}ractor.h @@ -2067,7 +2067,9 @@ cont.$(OBJEXT): $(top_srcdir)/internal/thread.h cont.$(OBJEXT): $(top_srcdir)/internal/variable.h cont.$(OBJEXT): $(top_srcdir)/internal/vm.h cont.$(OBJEXT): $(top_srcdir)/internal/warnings.h +cont.$(OBJEXT): $(top_srcdir)/prism/ast.h cont.$(OBJEXT): $(top_srcdir)/prism/defines.h +cont.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h cont.$(OBJEXT): $(top_srcdir)/prism/encoding.h cont.$(OBJEXT): $(top_srcdir)/prism/node.h cont.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -2087,6 +2089,7 @@ cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +cont.$(OBJEXT): $(top_srcdir)/prism/version.h cont.$(OBJEXT): {$(VPATH)}$(COROUTINE_H) cont.$(OBJEXT): {$(VPATH)}assert.h cont.$(OBJEXT): {$(VPATH)}atomic.h @@ -2267,9 +2270,6 @@ cont.$(OBJEXT): {$(VPATH)}missing.h cont.$(OBJEXT): {$(VPATH)}node.h cont.$(OBJEXT): {$(VPATH)}onigmo.h cont.$(OBJEXT): {$(VPATH)}oniguruma.h -cont.$(OBJEXT): {$(VPATH)}prism/ast.h -cont.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -cont.$(OBJEXT): {$(VPATH)}prism/version.h cont.$(OBJEXT): {$(VPATH)}prism_compile.h cont.$(OBJEXT): {$(VPATH)}ractor.h cont.$(OBJEXT): {$(VPATH)}ractor_core.h @@ -5074,7 +5074,9 @@ eval.$(OBJEXT): $(top_srcdir)/internal/thread.h eval.$(OBJEXT): $(top_srcdir)/internal/variable.h eval.$(OBJEXT): $(top_srcdir)/internal/vm.h eval.$(OBJEXT): $(top_srcdir)/internal/warnings.h +eval.$(OBJEXT): $(top_srcdir)/prism/ast.h eval.$(OBJEXT): $(top_srcdir)/prism/defines.h +eval.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h eval.$(OBJEXT): $(top_srcdir)/prism/encoding.h eval.$(OBJEXT): $(top_srcdir)/prism/node.h eval.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -5094,6 +5096,7 @@ eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +eval.$(OBJEXT): $(top_srcdir)/prism/version.h eval.$(OBJEXT): {$(VPATH)}assert.h eval.$(OBJEXT): {$(VPATH)}atomic.h eval.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -5276,9 +5279,6 @@ eval.$(OBJEXT): {$(VPATH)}missing.h eval.$(OBJEXT): {$(VPATH)}node.h eval.$(OBJEXT): {$(VPATH)}onigmo.h eval.$(OBJEXT): {$(VPATH)}oniguruma.h -eval.$(OBJEXT): {$(VPATH)}prism/ast.h -eval.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -eval.$(OBJEXT): {$(VPATH)}prism/version.h eval.$(OBJEXT): {$(VPATH)}prism_compile.h eval.$(OBJEXT): {$(VPATH)}probes.dmyh eval.$(OBJEXT): {$(VPATH)}probes.h @@ -5563,7 +5563,9 @@ gc.$(OBJEXT): $(top_srcdir)/internal/thread.h gc.$(OBJEXT): $(top_srcdir)/internal/variable.h gc.$(OBJEXT): $(top_srcdir)/internal/vm.h gc.$(OBJEXT): $(top_srcdir)/internal/warnings.h +gc.$(OBJEXT): $(top_srcdir)/prism/ast.h gc.$(OBJEXT): $(top_srcdir)/prism/defines.h +gc.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h gc.$(OBJEXT): $(top_srcdir)/prism/encoding.h gc.$(OBJEXT): $(top_srcdir)/prism/node.h gc.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -5583,6 +5585,7 @@ gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +gc.$(OBJEXT): $(top_srcdir)/prism/version.h gc.$(OBJEXT): {$(VPATH)}assert.h gc.$(OBJEXT): {$(VPATH)}atomic.h gc.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -5767,9 +5770,6 @@ gc.$(OBJEXT): {$(VPATH)}missing.h gc.$(OBJEXT): {$(VPATH)}node.h gc.$(OBJEXT): {$(VPATH)}onigmo.h gc.$(OBJEXT): {$(VPATH)}oniguruma.h -gc.$(OBJEXT): {$(VPATH)}prism/ast.h -gc.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -gc.$(OBJEXT): {$(VPATH)}prism/version.h gc.$(OBJEXT): {$(VPATH)}prism_compile.h gc.$(OBJEXT): {$(VPATH)}probes.dmyh gc.$(OBJEXT): {$(VPATH)}probes.h @@ -5825,7 +5825,9 @@ 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): $(top_srcdir)/prism/ast.h goruby.$(OBJEXT): $(top_srcdir)/prism/defines.h +goruby.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h goruby.$(OBJEXT): $(top_srcdir)/prism/encoding.h goruby.$(OBJEXT): $(top_srcdir)/prism/node.h goruby.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -5845,6 +5847,7 @@ goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +goruby.$(OBJEXT): $(top_srcdir)/prism/version.h goruby.$(OBJEXT): {$(VPATH)}assert.h goruby.$(OBJEXT): {$(VPATH)}atomic.h goruby.$(OBJEXT): {$(VPATH)}backward.h @@ -6024,9 +6027,6 @@ goruby.$(OBJEXT): {$(VPATH)}missing.h goruby.$(OBJEXT): {$(VPATH)}node.h goruby.$(OBJEXT): {$(VPATH)}onigmo.h goruby.$(OBJEXT): {$(VPATH)}oniguruma.h -goruby.$(OBJEXT): {$(VPATH)}prism/ast.h -goruby.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -goruby.$(OBJEXT): {$(VPATH)}prism/version.h goruby.$(OBJEXT): {$(VPATH)}prism_compile.h goruby.$(OBJEXT): {$(VPATH)}ruby_assert.h goruby.$(OBJEXT): {$(VPATH)}ruby_atomic.h @@ -6072,7 +6072,9 @@ 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): $(top_srcdir)/prism/ast.h hash.$(OBJEXT): $(top_srcdir)/prism/defines.h +hash.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h hash.$(OBJEXT): $(top_srcdir)/prism/encoding.h hash.$(OBJEXT): $(top_srcdir)/prism/node.h hash.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -6092,6 +6094,7 @@ hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +hash.$(OBJEXT): $(top_srcdir)/prism/version.h hash.$(OBJEXT): {$(VPATH)}assert.h hash.$(OBJEXT): {$(VPATH)}atomic.h hash.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -6272,9 +6275,6 @@ hash.$(OBJEXT): {$(VPATH)}missing.h hash.$(OBJEXT): {$(VPATH)}node.h hash.$(OBJEXT): {$(VPATH)}onigmo.h hash.$(OBJEXT): {$(VPATH)}oniguruma.h -hash.$(OBJEXT): {$(VPATH)}prism/ast.h -hash.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -hash.$(OBJEXT): {$(VPATH)}prism/version.h hash.$(OBJEXT): {$(VPATH)}prism_compile.h hash.$(OBJEXT): {$(VPATH)}probes.dmyh hash.$(OBJEXT): {$(VPATH)}probes.h @@ -7149,7 +7149,9 @@ iseq.$(OBJEXT): $(top_srcdir)/internal/thread.h iseq.$(OBJEXT): $(top_srcdir)/internal/variable.h iseq.$(OBJEXT): $(top_srcdir)/internal/vm.h iseq.$(OBJEXT): $(top_srcdir)/internal/warnings.h +iseq.$(OBJEXT): $(top_srcdir)/prism/ast.h iseq.$(OBJEXT): $(top_srcdir)/prism/defines.h +iseq.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h iseq.$(OBJEXT): $(top_srcdir)/prism/encoding.h iseq.$(OBJEXT): $(top_srcdir)/prism/node.h iseq.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -7157,6 +7159,7 @@ iseq.$(OBJEXT): $(top_srcdir)/prism/pack.h iseq.$(OBJEXT): $(top_srcdir)/prism/parser.h iseq.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h iseq.$(OBJEXT): $(top_srcdir)/prism/prism.h +iseq.$(OBJEXT): $(top_srcdir)/prism/prism.h iseq.$(OBJEXT): $(top_srcdir)/prism/regexp.h iseq.$(OBJEXT): $(top_srcdir)/prism/static_literals.h iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h @@ -7169,6 +7172,7 @@ iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +iseq.$(OBJEXT): $(top_srcdir)/prism/version.h iseq.$(OBJEXT): {$(VPATH)}assert.h iseq.$(OBJEXT): {$(VPATH)}atomic.h iseq.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -7352,10 +7356,6 @@ iseq.$(OBJEXT): {$(VPATH)}missing.h iseq.$(OBJEXT): {$(VPATH)}node.h iseq.$(OBJEXT): {$(VPATH)}onigmo.h iseq.$(OBJEXT): {$(VPATH)}oniguruma.h -iseq.$(OBJEXT): {$(VPATH)}prism/ast.h -iseq.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -iseq.$(OBJEXT): {$(VPATH)}prism/prism.h -iseq.$(OBJEXT): {$(VPATH)}prism/version.h iseq.$(OBJEXT): {$(VPATH)}prism_compile.h iseq.$(OBJEXT): {$(VPATH)}ractor.h iseq.$(OBJEXT): {$(VPATH)}ruby_assert.h @@ -7393,7 +7393,9 @@ jit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h jit.$(OBJEXT): $(top_srcdir)/internal/variable.h jit.$(OBJEXT): $(top_srcdir)/internal/vm.h jit.$(OBJEXT): $(top_srcdir)/internal/warnings.h +jit.$(OBJEXT): $(top_srcdir)/prism/ast.h jit.$(OBJEXT): $(top_srcdir)/prism/defines.h +jit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h jit.$(OBJEXT): $(top_srcdir)/prism/encoding.h jit.$(OBJEXT): $(top_srcdir)/prism/node.h jit.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -7413,6 +7415,7 @@ jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +jit.$(OBJEXT): $(top_srcdir)/prism/version.h jit.$(OBJEXT): {$(VPATH)}assert.h jit.$(OBJEXT): {$(VPATH)}atomic.h jit.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -7594,9 +7597,6 @@ jit.$(OBJEXT): {$(VPATH)}missing.h jit.$(OBJEXT): {$(VPATH)}node.h jit.$(OBJEXT): {$(VPATH)}onigmo.h jit.$(OBJEXT): {$(VPATH)}oniguruma.h -jit.$(OBJEXT): {$(VPATH)}prism/ast.h -jit.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -jit.$(OBJEXT): {$(VPATH)}prism/version.h jit.$(OBJEXT): {$(VPATH)}prism_compile.h jit.$(OBJEXT): {$(VPATH)}ruby_assert.h jit.$(OBJEXT): {$(VPATH)}ruby_atomic.h @@ -7646,7 +7646,9 @@ load.$(OBJEXT): $(top_srcdir)/internal/thread.h load.$(OBJEXT): $(top_srcdir)/internal/variable.h load.$(OBJEXT): $(top_srcdir)/internal/vm.h load.$(OBJEXT): $(top_srcdir)/internal/warnings.h +load.$(OBJEXT): $(top_srcdir)/prism/ast.h load.$(OBJEXT): $(top_srcdir)/prism/defines.h +load.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h load.$(OBJEXT): $(top_srcdir)/prism/encoding.h load.$(OBJEXT): $(top_srcdir)/prism/node.h load.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -7666,6 +7668,7 @@ load.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h load.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h load.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h load.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +load.$(OBJEXT): $(top_srcdir)/prism/version.h load.$(OBJEXT): {$(VPATH)}assert.h load.$(OBJEXT): {$(VPATH)}atomic.h load.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -7845,9 +7848,6 @@ load.$(OBJEXT): {$(VPATH)}missing.h load.$(OBJEXT): {$(VPATH)}node.h load.$(OBJEXT): {$(VPATH)}onigmo.h load.$(OBJEXT): {$(VPATH)}oniguruma.h -load.$(OBJEXT): {$(VPATH)}prism/ast.h -load.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -load.$(OBJEXT): {$(VPATH)}prism/version.h load.$(OBJEXT): {$(VPATH)}prism_compile.h load.$(OBJEXT): {$(VPATH)}probes.dmyh load.$(OBJEXT): {$(VPATH)}probes.h @@ -9000,7 +9000,9 @@ 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): $(top_srcdir)/prism/ast.h miniinit.$(OBJEXT): $(top_srcdir)/prism/defines.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h miniinit.$(OBJEXT): $(top_srcdir)/prism/encoding.h miniinit.$(OBJEXT): $(top_srcdir)/prism/node.h miniinit.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -9020,6 +9022,7 @@ miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +miniinit.$(OBJEXT): $(top_srcdir)/prism/version.h miniinit.$(OBJEXT): {$(VPATH)}array.rb miniinit.$(OBJEXT): {$(VPATH)}assert.h miniinit.$(OBJEXT): {$(VPATH)}ast.rb @@ -9215,9 +9218,6 @@ miniinit.$(OBJEXT): {$(VPATH)}oniguruma.h miniinit.$(OBJEXT): {$(VPATH)}pack.rb miniinit.$(OBJEXT): {$(VPATH)}pathname_builtin.rb miniinit.$(OBJEXT): {$(VPATH)}prelude.rb -miniinit.$(OBJEXT): {$(VPATH)}prism/ast.h -miniinit.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -miniinit.$(OBJEXT): {$(VPATH)}prism/version.h miniinit.$(OBJEXT): {$(VPATH)}prism_compile.h miniinit.$(OBJEXT): {$(VPATH)}ractor.rb miniinit.$(OBJEXT): {$(VPATH)}ruby_assert.h @@ -11008,7 +11008,10 @@ pathname.$(OBJEXT): {$(VPATH)}st.h pathname.$(OBJEXT): {$(VPATH)}subst.h prism/api_node.$(OBJEXT): $(hdrdir)/ruby.h prism/api_node.$(OBJEXT): $(hdrdir)/ruby/ruby.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/api_node.c +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/encoding.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/extension.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/node.h @@ -11029,6 +11032,7 @@ prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +prism/api_node.$(OBJEXT): $(top_srcdir)/prism/version.h prism/api_node.$(OBJEXT): {$(VPATH)}assert.h prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/assume.h prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/attributes.h @@ -11195,16 +11199,14 @@ prism/api_node.$(OBJEXT): {$(VPATH)}internal/xmalloc.h prism/api_node.$(OBJEXT): {$(VPATH)}missing.h prism/api_node.$(OBJEXT): {$(VPATH)}onigmo.h prism/api_node.$(OBJEXT): {$(VPATH)}oniguruma.h -prism/api_node.$(OBJEXT): {$(VPATH)}prism/api_node.c -prism/api_node.$(OBJEXT): {$(VPATH)}prism/ast.h -prism/api_node.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -prism/api_node.$(OBJEXT): {$(VPATH)}prism/version.h prism/api_node.$(OBJEXT): {$(VPATH)}st.h prism/api_node.$(OBJEXT): {$(VPATH)}subst.h prism/api_pack.$(OBJEXT): $(hdrdir)/ruby.h prism/api_pack.$(OBJEXT): $(hdrdir)/ruby/ruby.h prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/api_pack.c +prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/encoding.h prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/extension.h prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/node.h @@ -11225,6 +11227,7 @@ prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/version.h prism/api_pack.$(OBJEXT): {$(VPATH)}assert.h prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/assume.h prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/attributes.h @@ -11391,12 +11394,12 @@ prism/api_pack.$(OBJEXT): {$(VPATH)}internal/xmalloc.h prism/api_pack.$(OBJEXT): {$(VPATH)}missing.h prism/api_pack.$(OBJEXT): {$(VPATH)}onigmo.h prism/api_pack.$(OBJEXT): {$(VPATH)}oniguruma.h -prism/api_pack.$(OBJEXT): {$(VPATH)}prism/ast.h -prism/api_pack.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -prism/api_pack.$(OBJEXT): {$(VPATH)}prism/version.h prism/api_pack.$(OBJEXT): {$(VPATH)}st.h prism/api_pack.$(OBJEXT): {$(VPATH)}subst.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/diagnostic.c +prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h @@ -11404,16 +11407,15 @@ prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -prism/diagnostic.$(OBJEXT): {$(VPATH)}prism/ast.h -prism/diagnostic.$(OBJEXT): {$(VPATH)}prism/diagnostic.c -prism/diagnostic.$(OBJEXT): {$(VPATH)}prism/diagnostic.h prism/encoding.$(OBJEXT): $(top_srcdir)/prism/defines.h prism/encoding.$(OBJEXT): $(top_srcdir)/prism/encoding.c prism/encoding.$(OBJEXT): $(top_srcdir)/prism/encoding.h prism/encoding.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h prism/extension.$(OBJEXT): $(hdrdir)/ruby.h prism/extension.$(OBJEXT): $(hdrdir)/ruby/ruby.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/encoding.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/extension.c prism/extension.$(OBJEXT): $(top_srcdir)/prism/extension.h @@ -11435,6 +11437,7 @@ prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +prism/extension.$(OBJEXT): $(top_srcdir)/prism/version.h prism/extension.$(OBJEXT): {$(VPATH)}assert.h prism/extension.$(OBJEXT): {$(VPATH)}backward/2/assume.h prism/extension.$(OBJEXT): {$(VPATH)}backward/2/attributes.h @@ -11601,13 +11604,13 @@ prism/extension.$(OBJEXT): {$(VPATH)}internal/xmalloc.h prism/extension.$(OBJEXT): {$(VPATH)}missing.h prism/extension.$(OBJEXT): {$(VPATH)}onigmo.h prism/extension.$(OBJEXT): {$(VPATH)}oniguruma.h -prism/extension.$(OBJEXT): {$(VPATH)}prism/ast.h -prism/extension.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -prism/extension.$(OBJEXT): {$(VPATH)}prism/version.h prism/extension.$(OBJEXT): {$(VPATH)}st.h prism/extension.$(OBJEXT): {$(VPATH)}subst.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/node.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h prism/node.$(OBJEXT): $(top_srcdir)/prism/encoding.h +prism/node.$(OBJEXT): $(top_srcdir)/prism/node.c prism/node.$(OBJEXT): $(top_srcdir)/prism/node.h prism/node.$(OBJEXT): $(top_srcdir)/prism/options.h prism/node.$(OBJEXT): $(top_srcdir)/prism/pack.h @@ -11624,9 +11627,6 @@ prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h -prism/node.$(OBJEXT): {$(VPATH)}prism/ast.h -prism/node.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -prism/node.$(OBJEXT): {$(VPATH)}prism/node.c prism/options.$(OBJEXT): $(top_srcdir)/prism/defines.h prism/options.$(OBJEXT): $(top_srcdir)/prism/options.c prism/options.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -11636,10 +11636,12 @@ prism/options.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h prism/pack.$(OBJEXT): $(top_srcdir)/prism/defines.h prism/pack.$(OBJEXT): $(top_srcdir)/prism/pack.c prism/pack.$(OBJEXT): $(top_srcdir)/prism/pack.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/defines.h prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/encoding.h prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/options.h prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/parser.h +prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/prettyprint.c prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/static_literals.h prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h @@ -11650,9 +11652,9 @@ prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -prism/prettyprint.$(OBJEXT): {$(VPATH)}prism/ast.h -prism/prettyprint.$(OBJEXT): {$(VPATH)}prism/prettyprint.c +prism/prism.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/prism.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h prism/prism.$(OBJEXT): $(top_srcdir)/prism/encoding.h prism/prism.$(OBJEXT): $(top_srcdir)/prism/node.h prism/prism.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -11674,9 +11676,8 @@ prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h prism/prism.$(OBJEXT): $(top_srcdir)/prism/version.h -prism/prism.$(OBJEXT): {$(VPATH)}prism/ast.h -prism/prism.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -prism/prism.$(OBJEXT): {$(VPATH)}prism/version.h +prism/prism.$(OBJEXT): $(top_srcdir)/prism/version.h +prism/regexp.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/regexp.$(OBJEXT): $(top_srcdir)/prism/defines.h prism/regexp.$(OBJEXT): $(top_srcdir)/prism/encoding.h prism/regexp.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -11693,8 +11694,9 @@ prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -prism/regexp.$(OBJEXT): {$(VPATH)}prism/ast.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/encoding.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/node.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -11703,6 +11705,7 @@ prism/serialize.$(OBJEXT): $(top_srcdir)/prism/parser.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/prism.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/regexp.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/serialize.c prism/serialize.$(OBJEXT): $(top_srcdir)/prism/static_literals.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h @@ -11714,10 +11717,8 @@ prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h -prism/serialize.$(OBJEXT): {$(VPATH)}prism/ast.h -prism/serialize.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -prism/serialize.$(OBJEXT): {$(VPATH)}prism/serialize.c -prism/serialize.$(OBJEXT): {$(VPATH)}prism/version.h +prism/serialize.$(OBJEXT): $(top_srcdir)/prism/version.h +prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/defines.h prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/encoding.h prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/node.h @@ -11733,16 +11734,15 @@ prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -prism/static_literals.$(OBJEXT): {$(VPATH)}prism/ast.h +prism/token_type.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/token_type.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/token_type.$(OBJEXT): $(top_srcdir)/prism/token_type.c prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h -prism/token_type.$(OBJEXT): {$(VPATH)}prism/ast.h -prism/token_type.$(OBJEXT): {$(VPATH)}prism/token_type.c prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/defines.h prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.c prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h @@ -11764,6 +11764,7 @@ prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h prism/util/pm_list.$(OBJEXT): $(top_srcdir)/prism/defines.h prism/util/pm_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.c prism/util/pm_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h +prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/defines.h prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/encoding.h prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/parser.h @@ -11774,7 +11775,6 @@ prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h -prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}prism/ast.h prism/util/pm_newline_list.$(OBJEXT): $(top_srcdir)/prism/defines.h prism/util/pm_newline_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.c prism/util/pm_newline_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h @@ -11784,7 +11784,9 @@ prism/util/pm_string.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h prism/util/pm_strncasecmp.$(OBJEXT): $(top_srcdir)/prism/defines.h prism/util/pm_strncasecmp.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.c prism/util/pm_strncasecmp.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h +prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/encoding.h prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/options.h prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/parser.h @@ -11799,11 +11801,11 @@ prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.c prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}prism/ast.h -prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}prism/diagnostic.h prism_init.$(OBJEXT): $(hdrdir)/ruby.h prism_init.$(OBJEXT): $(hdrdir)/ruby/ruby.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/ast.h prism_init.$(OBJEXT): $(top_srcdir)/prism/defines.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h prism_init.$(OBJEXT): $(top_srcdir)/prism/encoding.h prism_init.$(OBJEXT): $(top_srcdir)/prism/extension.h prism_init.$(OBJEXT): $(top_srcdir)/prism/node.h @@ -11824,6 +11826,7 @@ prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +prism_init.$(OBJEXT): $(top_srcdir)/prism/version.h prism_init.$(OBJEXT): $(top_srcdir)/prism_init.c prism_init.$(OBJEXT): {$(VPATH)}assert.h prism_init.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -11991,9 +11994,6 @@ prism_init.$(OBJEXT): {$(VPATH)}internal/xmalloc.h prism_init.$(OBJEXT): {$(VPATH)}missing.h prism_init.$(OBJEXT): {$(VPATH)}onigmo.h prism_init.$(OBJEXT): {$(VPATH)}oniguruma.h -prism_init.$(OBJEXT): {$(VPATH)}prism/ast.h -prism_init.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -prism_init.$(OBJEXT): {$(VPATH)}prism/version.h prism_init.$(OBJEXT): {$(VPATH)}prism_init.c prism_init.$(OBJEXT): {$(VPATH)}st.h prism_init.$(OBJEXT): {$(VPATH)}subst.h @@ -12024,7 +12024,9 @@ 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): $(top_srcdir)/prism/ast.h proc.$(OBJEXT): $(top_srcdir)/prism/defines.h +proc.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h proc.$(OBJEXT): $(top_srcdir)/prism/encoding.h proc.$(OBJEXT): $(top_srcdir)/prism/node.h proc.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -12044,6 +12046,7 @@ proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +proc.$(OBJEXT): $(top_srcdir)/prism/version.h proc.$(OBJEXT): {$(VPATH)}assert.h proc.$(OBJEXT): {$(VPATH)}atomic.h proc.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -12221,9 +12224,6 @@ proc.$(OBJEXT): {$(VPATH)}missing.h proc.$(OBJEXT): {$(VPATH)}node.h proc.$(OBJEXT): {$(VPATH)}onigmo.h proc.$(OBJEXT): {$(VPATH)}oniguruma.h -proc.$(OBJEXT): {$(VPATH)}prism/ast.h -proc.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -proc.$(OBJEXT): {$(VPATH)}prism/version.h proc.$(OBJEXT): {$(VPATH)}prism_compile.h proc.$(OBJEXT): {$(VPATH)}proc.c proc.$(OBJEXT): {$(VPATH)}ractor.h @@ -14578,7 +14578,9 @@ ruby.$(OBJEXT): $(top_srcdir)/internal/thread.h ruby.$(OBJEXT): $(top_srcdir)/internal/variable.h ruby.$(OBJEXT): $(top_srcdir)/internal/vm.h ruby.$(OBJEXT): $(top_srcdir)/internal/warnings.h +ruby.$(OBJEXT): $(top_srcdir)/prism/ast.h ruby.$(OBJEXT): $(top_srcdir)/prism/defines.h +ruby.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h ruby.$(OBJEXT): $(top_srcdir)/prism/encoding.h ruby.$(OBJEXT): $(top_srcdir)/prism/node.h ruby.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -14598,6 +14600,7 @@ ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +ruby.$(OBJEXT): $(top_srcdir)/prism/version.h ruby.$(OBJEXT): {$(VPATH)}assert.h ruby.$(OBJEXT): {$(VPATH)}atomic.h ruby.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -14777,9 +14780,6 @@ ruby.$(OBJEXT): {$(VPATH)}missing.h ruby.$(OBJEXT): {$(VPATH)}node.h ruby.$(OBJEXT): {$(VPATH)}onigmo.h ruby.$(OBJEXT): {$(VPATH)}oniguruma.h -ruby.$(OBJEXT): {$(VPATH)}prism/ast.h -ruby.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -ruby.$(OBJEXT): {$(VPATH)}prism/version.h ruby.$(OBJEXT): {$(VPATH)}prism_compile.h ruby.$(OBJEXT): {$(VPATH)}ruby.c ruby.$(OBJEXT): {$(VPATH)}ruby_assert.h @@ -17280,7 +17280,9 @@ 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): $(top_srcdir)/prism/ast.h thread.$(OBJEXT): $(top_srcdir)/prism/defines.h +thread.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h thread.$(OBJEXT): $(top_srcdir)/prism/encoding.h thread.$(OBJEXT): $(top_srcdir)/prism/node.h thread.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -17300,6 +17302,7 @@ thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +thread.$(OBJEXT): $(top_srcdir)/prism/version.h thread.$(OBJEXT): {$(VPATH)}$(COROUTINE_H) thread.$(OBJEXT): {$(VPATH)}assert.h thread.$(OBJEXT): {$(VPATH)}atomic.h @@ -17483,9 +17486,6 @@ thread.$(OBJEXT): {$(VPATH)}missing.h thread.$(OBJEXT): {$(VPATH)}node.h thread.$(OBJEXT): {$(VPATH)}onigmo.h thread.$(OBJEXT): {$(VPATH)}oniguruma.h -thread.$(OBJEXT): {$(VPATH)}prism/ast.h -thread.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -thread.$(OBJEXT): {$(VPATH)}prism/version.h thread.$(OBJEXT): {$(VPATH)}prism_compile.h thread.$(OBJEXT): {$(VPATH)}ractor.h thread.$(OBJEXT): {$(VPATH)}ractor_core.h @@ -18568,7 +18568,9 @@ vm.$(OBJEXT): $(top_srcdir)/internal/transcode.h vm.$(OBJEXT): $(top_srcdir)/internal/variable.h vm.$(OBJEXT): $(top_srcdir)/internal/vm.h vm.$(OBJEXT): $(top_srcdir)/internal/warnings.h +vm.$(OBJEXT): $(top_srcdir)/prism/ast.h vm.$(OBJEXT): $(top_srcdir)/prism/defines.h +vm.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h vm.$(OBJEXT): $(top_srcdir)/prism/encoding.h vm.$(OBJEXT): $(top_srcdir)/prism/node.h vm.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -18588,6 +18590,7 @@ vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +vm.$(OBJEXT): $(top_srcdir)/prism/version.h vm.$(OBJEXT): {$(VPATH)}assert.h vm.$(OBJEXT): {$(VPATH)}atomic.h vm.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -18772,9 +18775,6 @@ vm.$(OBJEXT): {$(VPATH)}missing.h vm.$(OBJEXT): {$(VPATH)}node.h vm.$(OBJEXT): {$(VPATH)}onigmo.h vm.$(OBJEXT): {$(VPATH)}oniguruma.h -vm.$(OBJEXT): {$(VPATH)}prism/ast.h -vm.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -vm.$(OBJEXT): {$(VPATH)}prism/version.h vm.$(OBJEXT): {$(VPATH)}prism_compile.h vm.$(OBJEXT): {$(VPATH)}probes.dmyh vm.$(OBJEXT): {$(VPATH)}probes.h @@ -18832,7 +18832,9 @@ 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): $(top_srcdir)/prism/ast.h vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/defines.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/encoding.h vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/node.h vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -18852,6 +18854,7 @@ vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/version.h vm_backtrace.$(OBJEXT): {$(VPATH)}assert.h vm_backtrace.$(OBJEXT): {$(VPATH)}atomic.h vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -19030,9 +19033,6 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}missing.h vm_backtrace.$(OBJEXT): {$(VPATH)}node.h vm_backtrace.$(OBJEXT): {$(VPATH)}onigmo.h vm_backtrace.$(OBJEXT): {$(VPATH)}oniguruma.h -vm_backtrace.$(OBJEXT): {$(VPATH)}prism/ast.h -vm_backtrace.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -vm_backtrace.$(OBJEXT): {$(VPATH)}prism/version.h vm_backtrace.$(OBJEXT): {$(VPATH)}prism_compile.h vm_backtrace.$(OBJEXT): {$(VPATH)}ruby_assert.h vm_backtrace.$(OBJEXT): {$(VPATH)}ruby_atomic.h @@ -19065,7 +19065,9 @@ vm_dump.$(OBJEXT): $(top_srcdir)/internal/static_assert.h vm_dump.$(OBJEXT): $(top_srcdir)/internal/variable.h vm_dump.$(OBJEXT): $(top_srcdir)/internal/vm.h vm_dump.$(OBJEXT): $(top_srcdir)/internal/warnings.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/ast.h vm_dump.$(OBJEXT): $(top_srcdir)/prism/defines.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h vm_dump.$(OBJEXT): $(top_srcdir)/prism/encoding.h vm_dump.$(OBJEXT): $(top_srcdir)/prism/node.h vm_dump.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -19085,6 +19087,7 @@ vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +vm_dump.$(OBJEXT): $(top_srcdir)/prism/version.h vm_dump.$(OBJEXT): {$(VPATH)}addr2line.h vm_dump.$(OBJEXT): {$(VPATH)}assert.h vm_dump.$(OBJEXT): {$(VPATH)}atomic.h @@ -19262,9 +19265,6 @@ vm_dump.$(OBJEXT): {$(VPATH)}missing.h vm_dump.$(OBJEXT): {$(VPATH)}node.h vm_dump.$(OBJEXT): {$(VPATH)}onigmo.h vm_dump.$(OBJEXT): {$(VPATH)}oniguruma.h -vm_dump.$(OBJEXT): {$(VPATH)}prism/ast.h -vm_dump.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -vm_dump.$(OBJEXT): {$(VPATH)}prism/version.h vm_dump.$(OBJEXT): {$(VPATH)}prism_compile.h vm_dump.$(OBJEXT): {$(VPATH)}procstat_vm.c vm_dump.$(OBJEXT): {$(VPATH)}ractor.h @@ -19514,7 +19514,9 @@ vm_trace.$(OBJEXT): $(top_srcdir)/internal/thread.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): $(top_srcdir)/prism/ast.h vm_trace.$(OBJEXT): $(top_srcdir)/prism/defines.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h vm_trace.$(OBJEXT): $(top_srcdir)/prism/encoding.h vm_trace.$(OBJEXT): $(top_srcdir)/prism/node.h vm_trace.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -19534,6 +19536,7 @@ vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +vm_trace.$(OBJEXT): $(top_srcdir)/prism/version.h vm_trace.$(OBJEXT): {$(VPATH)}assert.h vm_trace.$(OBJEXT): {$(VPATH)}atomic.h vm_trace.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -19713,9 +19716,6 @@ vm_trace.$(OBJEXT): {$(VPATH)}missing.h vm_trace.$(OBJEXT): {$(VPATH)}node.h vm_trace.$(OBJEXT): {$(VPATH)}onigmo.h vm_trace.$(OBJEXT): {$(VPATH)}oniguruma.h -vm_trace.$(OBJEXT): {$(VPATH)}prism/ast.h -vm_trace.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -vm_trace.$(OBJEXT): {$(VPATH)}prism/version.h vm_trace.$(OBJEXT): {$(VPATH)}prism_compile.h vm_trace.$(OBJEXT): {$(VPATH)}ractor.h vm_trace.$(OBJEXT): {$(VPATH)}ruby_assert.h @@ -19962,7 +19962,9 @@ yjit.$(OBJEXT): $(top_srcdir)/internal/string.h yjit.$(OBJEXT): $(top_srcdir)/internal/variable.h yjit.$(OBJEXT): $(top_srcdir)/internal/vm.h yjit.$(OBJEXT): $(top_srcdir)/internal/warnings.h +yjit.$(OBJEXT): $(top_srcdir)/prism/ast.h yjit.$(OBJEXT): $(top_srcdir)/prism/defines.h +yjit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h yjit.$(OBJEXT): $(top_srcdir)/prism/encoding.h yjit.$(OBJEXT): $(top_srcdir)/prism/node.h yjit.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -19982,6 +19984,7 @@ yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +yjit.$(OBJEXT): $(top_srcdir)/prism/version.h yjit.$(OBJEXT): {$(VPATH)}assert.h yjit.$(OBJEXT): {$(VPATH)}atomic.h yjit.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -20164,9 +20167,6 @@ yjit.$(OBJEXT): {$(VPATH)}missing.h yjit.$(OBJEXT): {$(VPATH)}node.h yjit.$(OBJEXT): {$(VPATH)}onigmo.h yjit.$(OBJEXT): {$(VPATH)}oniguruma.h -yjit.$(OBJEXT): {$(VPATH)}prism/ast.h -yjit.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -yjit.$(OBJEXT): {$(VPATH)}prism/version.h yjit.$(OBJEXT): {$(VPATH)}prism_compile.h yjit.$(OBJEXT): {$(VPATH)}probes.dmyh yjit.$(OBJEXT): {$(VPATH)}probes.h @@ -20214,7 +20214,9 @@ zjit.$(OBJEXT): $(top_srcdir)/internal/string.h zjit.$(OBJEXT): $(top_srcdir)/internal/variable.h zjit.$(OBJEXT): $(top_srcdir)/internal/vm.h zjit.$(OBJEXT): $(top_srcdir)/internal/warnings.h +zjit.$(OBJEXT): $(top_srcdir)/prism/ast.h zjit.$(OBJEXT): $(top_srcdir)/prism/defines.h +zjit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h zjit.$(OBJEXT): $(top_srcdir)/prism/encoding.h zjit.$(OBJEXT): $(top_srcdir)/prism/node.h zjit.$(OBJEXT): $(top_srcdir)/prism/options.h @@ -20234,6 +20236,7 @@ zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h zjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h +zjit.$(OBJEXT): $(top_srcdir)/prism/version.h zjit.$(OBJEXT): {$(VPATH)}assert.h zjit.$(OBJEXT): {$(VPATH)}atomic.h zjit.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -20415,9 +20418,6 @@ zjit.$(OBJEXT): {$(VPATH)}missing.h zjit.$(OBJEXT): {$(VPATH)}node.h zjit.$(OBJEXT): {$(VPATH)}onigmo.h zjit.$(OBJEXT): {$(VPATH)}oniguruma.h -zjit.$(OBJEXT): {$(VPATH)}prism/ast.h -zjit.$(OBJEXT): {$(VPATH)}prism/diagnostic.h -zjit.$(OBJEXT): {$(VPATH)}prism/version.h zjit.$(OBJEXT): {$(VPATH)}prism_compile.h zjit.$(OBJEXT): {$(VPATH)}probes.dmyh zjit.$(OBJEXT): {$(VPATH)}probes.h diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c index 5248a9e26a..9c6ed93049 100644 --- a/ext/json/generator/generator.c +++ b/ext/json/generator/generator.c @@ -137,8 +137,8 @@ static inline FORCE_INLINE void search_flush(search_state *search) { // Do not remove this conditional without profiling, specifically escape-heavy text. // escape_UTF8_char_basic will advance search->ptr and search->cursor (effectively a search_flush). - // For back-to-back characters that need to be escaped, specifcally for the SIMD code paths, this method - // will be called just before calling escape_UTF8_char_basic. There will be no characers to append for the + // For back-to-back characters that need to be escaped, specifically for the SIMD code paths, this method + // will be called just before calling escape_UTF8_char_basic. There will be no characters to append for the // consecutive characters that need to be escaped. While the fbuffer_append is a no-op if // nothing needs to be flushed, we can save a few memory references with this conditional. if (search->ptr > search->cursor) { diff --git a/ext/json/lib/json.rb b/ext/json/lib/json.rb index 735f238066..0ebff2f948 100644 --- a/ext/json/lib/json.rb +++ b/ext/json/lib/json.rb @@ -133,7 +133,7 @@ require 'json/common' # When not specified: # # The last value is used and a deprecation warning emitted. # JSON.parse('{"a": 1, "a":2}') => {"a" => 2} -# # waring: detected duplicate keys in JSON object. +# # warning: detected duplicate keys in JSON object. # # This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true` # # When set to `+true+` diff --git a/ext/json/lib/json/add/string.rb b/ext/json/lib/json/add/string.rb index 46f07967cd..9c3bde27fb 100644 --- a/ext/json/lib/json/add/string.rb +++ b/ext/json/lib/json/add/string.rb @@ -5,7 +5,7 @@ end class String # call-seq: json_create(o) - # + # # Raw Strings are JSON Objects (the raw bytes are stored in an array for the # key "raw"). The Ruby String can be created by this class method. def self.json_create(object) @@ -13,7 +13,7 @@ class String end # call-seq: to_json_raw_object() - # + # # This method creates a raw object hash, that can be nested into # other data structures and will be generated as a raw string. This # method should be used, if you want to convert raw strings to JSON @@ -26,10 +26,10 @@ class String end # call-seq: to_json_raw(*args) - # + # # This method creates a JSON text from the result of a call to # to_json_raw_object of this String. def to_json_raw(...) to_json_raw_object.to_json(...) end -end
\ No newline at end of file +end diff --git a/ext/json/lib/json/common.rb b/ext/json/lib/json/common.rb index 9a878cead9..e99d152a88 100644 --- a/ext/json/lib/json/common.rb +++ b/ext/json/lib/json/common.rb @@ -1002,7 +1002,7 @@ module JSON # See {Parsing Options}[#module-JSON-label-Parsing+Options], and {Generating Options}[#module-JSON-label-Generating+Options]. # # For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is - # encoutered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native + # encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native # \JSON counterpart: # # module MyApp diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c index ab9d6c205e..1e6ee753f0 100644 --- a/ext/json/parser/parser.c +++ b/ext/json/parser/parser.c @@ -1265,7 +1265,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config) break; } - raise_parse_error("unreacheable: %s", state); + raise_parse_error("unreachable: %s", state); } static void json_ensure_eof(JSON_ParserState *state) diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c index 8291578f27..c18596cbf5 100644 --- a/ext/openssl/ossl_x509store.c +++ b/ext/openssl/ossl_x509store.c @@ -191,8 +191,8 @@ ossl_x509store_set_vfy_cb(VALUE self, VALUE cb) GetX509Store(self, store); rb_iv_set(self, "@verify_callback", cb); - // We don't need to trigger a write barrier because `rb_iv_set` did it. X509_STORE_set_ex_data(store, store_ex_verify_cb_idx, (void *)cb); + RB_OBJ_WRITTEN(self, Qundef, cb); return cb; } @@ -611,6 +611,7 @@ ossl_x509stctx_verify(VALUE self) GetX509StCtx(self, ctx); VALUE cb = rb_iv_get(self, "@verify_callback"); X509_STORE_CTX_set_ex_data(ctx, stctx_ex_verify_cb_idx, (void *)cb); + RB_OBJ_WRITTEN(self, Qundef, cb); switch (X509_verify_cert(ctx)) { case 1: diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c index bc6c303c36..ca00e51ee7 100644 --- a/ext/socket/raddrinfo.c +++ b/ext/socket/raddrinfo.c @@ -578,6 +578,10 @@ start: #endif +#define GETNAMEINFO_WONT_BLOCK(host, serv, flags) \ + ((!(host) || ((flags) & NI_NUMERICHOST)) && \ + (!(serv) || ((flags) & NI_NUMERICSERV))) + #if GETADDRINFO_IMPL == 0 int @@ -615,6 +619,10 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) { + if (GETNAMEINFO_WONT_BLOCK(host, serv, flags)) { + return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); + } + struct getnameinfo_arg arg; int ret; arg.sa = sa; @@ -743,6 +751,10 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen, struct getnameinfo_arg *arg; int err = 0, gni_errno = 0; + if (GETNAMEINFO_WONT_BLOCK(host, serv, flags)) { + return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); + } + start: retry = 0; @@ -4698,19 +4698,22 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU APPEND_S("shared -> "); rb_raw_obj_info(BUFF_ARGS, ARY_SHARED_ROOT(obj)); } - else if (ARY_EMBED_P(obj)) { - APPEND_F("[%s%s] len: %ld (embed)", - C(ARY_EMBED_P(obj), "E"), - C(ARY_SHARED_P(obj), "S"), - RARRAY_LEN(obj)); - } else { - APPEND_F("[%s%s] len: %ld, capa:%ld ptr:%p", - C(ARY_EMBED_P(obj), "E"), + APPEND_F("[%s%s%s] ", + C(ARY_EMBED_P(obj), "E"), C(ARY_SHARED_P(obj), "S"), - RARRAY_LEN(obj), - ARY_EMBED_P(obj) ? -1L : RARRAY(obj)->as.heap.aux.capa, - (void *)RARRAY_CONST_PTR(obj)); + C(ARY_SHARED_ROOT_P(obj), "R")); + + if (ARY_EMBED_P(obj)) { + APPEND_F("len: %ld (embed)", + RARRAY_LEN(obj)); + } + else { + APPEND_F("len: %ld, capa:%ld ptr:%p", + RARRAY_LEN(obj), + RARRAY(obj)->as.heap.aux.capa, + (void *)RARRAY_CONST_PTR(obj)); + } } break; case T_STRING: { @@ -321,40 +321,35 @@ objid_hash(VALUE obj) #endif } -/** +/* * call-seq: - * obj.hash -> integer - * - * Generates an Integer hash value for this object. This function must have the - * property that <code>a.eql?(b)</code> implies <code>a.hash == b.hash</code>. - * - * The hash value is used along with #eql? by the Hash class to determine if - * two objects reference the same hash key. Any hash value that exceeds the - * capacity of an Integer will be truncated before being used. + * hash -> integer * - * The hash value for an object may not be identical across invocations or - * implementations of Ruby. If you need a stable identifier across Ruby - * invocations and implementations you will need to generate one with a custom - * method. + * Returns the integer hash value for +self+; + * has the property that if <tt>foo.eql?(bar)</tt> + * then <tt>foo.hash == bar.hash</tt>. * - * Certain core classes such as Integer use built-in hash calculations and - * do not call the #hash method when used as a hash key. + * \Class Hash uses both #hash and #eql? to determine whether two objects + * used as hash keys are to be treated as the same key. + * A hash value that exceeds the capacity of an Integer is truncated before being used. * - * When implementing your own #hash based on multiple values, the best - * practice is to combine the class and any values using the hash code of an - * array: + * Many core classes override method Object#hash; + * other core classes (e.g., Integer) calculate the hash internally, + * and do not call the #hash method when used as a hash key. * - * For example: + * When implementing #hash for a user-defined class, + * best practice is to use Array#hash with the class name and the values + * that are important in the instance; + * this takes advantage of that method's logic for safely and efficiently + * generating a hash value: * * def hash * [self.class, a, b, c].hash * end * - * The reason for this is that the Array#hash method already has logic for - * safely and efficiently combining multiple hash values. - *-- - * \private - *++ + * The hash value may differ among invocations or implementations of Ruby. + * If you need stable hash-like identifiers across Ruby invocations and implementations, + * use a custom method to generate them. */ VALUE rb_obj_hash(VALUE obj) diff --git a/internal/re.h b/internal/re.h index 2788f8b42a..593e5c464f 100644 --- a/internal/re.h +++ b/internal/re.h @@ -25,4 +25,9 @@ int rb_match_count(VALUE match); VALUE rb_reg_new_ary(VALUE ary, int options); VALUE rb_reg_last_defined(VALUE match); +#define ARG_REG_OPTION_MASK \ + (ONIG_OPTION_IGNORECASE|ONIG_OPTION_MULTILINE|ONIG_OPTION_EXTEND) +#define ARG_ENCODING_FIXED 16 +#define ARG_ENCODING_NONE 32 + #endif /* INTERNAL_RE_H */ @@ -1497,9 +1497,9 @@ rb_iseq_remove_coverage_all(void) /* define wrapper class methods (RubyVM::InstructionSequence) */ static void -iseqw_mark(void *ptr) +iseqw_mark_and_move(void *ptr) { - rb_gc_mark_movable(*(VALUE *)ptr); + rb_gc_mark_and_move((VALUE *)ptr); } static size_t @@ -1508,20 +1508,13 @@ iseqw_memsize(const void *ptr) return rb_iseq_memsize(*(const rb_iseq_t **)ptr); } -static void -iseqw_ref_update(void *ptr) -{ - VALUE *vptr = ptr; - *vptr = rb_gc_location(*vptr); -} - static const rb_data_type_t iseqw_data_type = { "T_IMEMO/iseq", { - iseqw_mark, + iseqw_mark_and_move, RUBY_TYPED_DEFAULT_FREE, iseqw_memsize, - iseqw_ref_update, + iseqw_mark_and_move, }, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED }; diff --git a/lib/bundler/checksum.rb b/lib/bundler/checksum.rb index 356f4a48bc..ce05818bb0 100644 --- a/lib/bundler/checksum.rb +++ b/lib/bundler/checksum.rb @@ -205,6 +205,12 @@ module Bundler @store[spec.lock_name].nil? end + def empty?(spec) + return false unless spec.source.is_a?(Bundler::Source::Rubygems) + + @store[spec.lock_name].empty? + end + def register(spec, checksum) register_checksum(spec.lock_name, checksum) end diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index ea85f9af22..47a39069cc 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -287,8 +287,8 @@ module Bundler method_option "outdated", type: :boolean, banner: "Show verbose output including whether gems are outdated." def show(gem_name = nil) if ARGV.include?("--outdated") - message = "the `--outdated` flag to `bundle show` was undocumented and will be removed without replacement" - removed_message = "the `--outdated` flag to `bundle show` was undocumented and has been removed without replacement" + message = "the `--outdated` flag to `bundle show` will be removed in favor of `bundle show --verbose`" + removed_message = "the `--outdated` flag to `bundle show` has been removed in favor of `bundle show --verbose`" SharedHelpers.major_deprecation(2, message, removed_message: removed_message) end require_relative "cli/show" @@ -299,6 +299,7 @@ module Bundler method_option "name-only", type: :boolean, banner: "print only the gem names" method_option "only-group", type: :array, default: [], banner: "print gems from a given set of groups" method_option "without-group", type: :array, default: [], banner: "print all gems except from a given set of groups" + method_option "format", type: :string, banner: "format output ('json' is the only supported format)" method_option "paths", type: :boolean, banner: "print the path to each gem in the bundle" def list require_relative "cli/list" @@ -412,6 +413,7 @@ module Bundler D def cache print_remembered_flag_deprecation("--all", "cache_all", "true") if ARGV.include?("--all") + print_remembered_flag_deprecation("--no-all", "cache_all", "false") if ARGV.include?("--no-all") if flag_passed?("--path") message = @@ -518,11 +520,11 @@ module Bundler Viz requires the ruby-graphviz gem (and its dependencies). The associated gems must also be installed via 'bundle install'. D - method_option :file, type: :string, default: "gem_graph", aliases: "-f", desc: "The name to use for the generated file. see format option" - method_option :format, type: :string, default: "png", aliases: "-F", desc: "This is output format option. Supported format is png, jpg, svg, dot ..." - method_option :requirements, type: :boolean, default: false, aliases: "-R", desc: "Set to show the version of each required dependency." - method_option :version, type: :boolean, default: false, aliases: "-v", desc: "Set to show each gem version." - method_option :without, type: :array, default: [], aliases: "-W", banner: "GROUP[ GROUP...]", desc: "Exclude gems that are part of the specified named group." + method_option :file, type: :string, default: "gem_graph", aliases: "-f", banner: "The name to use for the generated file. see format option" + method_option :format, type: :string, default: "png", aliases: "-F", banner: "This is output format option. Supported format is png, jpg, svg, dot ..." + method_option :requirements, type: :boolean, default: false, aliases: "-R", banner: "Set to show the version of each required dependency." + method_option :version, type: :boolean, default: false, aliases: "-v", banner: "Set to show each gem version." + method_option :without, type: :array, default: [], aliases: "-W", banner: "Exclude gems that are part of the specified named group." def viz SharedHelpers.major_deprecation 2, "The `viz` command has been renamed to `graph` and moved to a plugin. See https://github.com/rubygems/bundler-graph" require_relative "cli/viz" @@ -531,19 +533,19 @@ module Bundler end desc "gem NAME [OPTIONS]", "Creates a skeleton for creating a rubygem" - method_option :exe, type: :boolean, default: false, aliases: ["--bin", "-b"], desc: "Generate a binary executable for your library." - method_option :coc, type: :boolean, desc: "Generate a code of conduct file. Set a default with `bundle config set --global gem.coc true`." - method_option :edit, type: :string, aliases: "-e", required: false, banner: "EDITOR", lazy_default: [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? }, desc: "Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)" - method_option :ext, type: :string, desc: "Generate the boilerplate for C extension code.", enum: EXTENSIONS - method_option :git, type: :boolean, default: true, desc: "Initialize a git repo inside your library." - method_option :mit, type: :boolean, desc: "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`." - method_option :rubocop, type: :boolean, desc: "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`." - method_option :changelog, type: :boolean, desc: "Generate changelog file. Set a default with `bundle config set --global gem.changelog true`." + method_option :exe, type: :boolean, default: false, aliases: ["--bin", "-b"], banner: "Generate a binary executable for your library." + method_option :coc, type: :boolean, banner: "Generate a code of conduct file. Set a default with `bundle config set --global gem.coc true`." + method_option :edit, type: :string, aliases: "-e", required: false, lazy_default: [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? }, banner: "Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)" + method_option :ext, type: :string, banner: "Generate the boilerplate for C extension code.", enum: EXTENSIONS + method_option :git, type: :boolean, default: true, banner: "Initialize a git repo inside your library." + method_option :mit, type: :boolean, banner: "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`." + method_option :rubocop, type: :boolean, banner: "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`." + method_option :changelog, type: :boolean, banner: "Generate changelog file. Set a default with `bundle config set --global gem.changelog true`." method_option :test, type: :string, lazy_default: Bundler.settings["gem.test"] || "", aliases: "-t", banner: "Use the specified test framework for your library", enum: %w[rspec minitest test-unit], desc: "Generate a test directory for your library, either rspec, minitest or test-unit. Set a default with `bundle config set --global gem.test (rspec|minitest|test-unit)`." - method_option :ci, type: :string, lazy_default: Bundler.settings["gem.ci"] || "", enum: %w[github gitlab circle], desc: "Generate CI configuration, either GitHub Actions, GitLab CI or CircleCI. Set a default with `bundle config set --global gem.ci (github|gitlab|circle)`" - method_option :linter, type: :string, lazy_default: Bundler.settings["gem.linter"] || "", enum: %w[rubocop standard], desc: "Add a linter and code formatter, either RuboCop or Standard. Set a default with `bundle config set --global gem.linter (rubocop|standard)`" + method_option :ci, type: :string, lazy_default: Bundler.settings["gem.ci"] || "", enum: %w[github gitlab circle], banner: "Generate CI configuration, either GitHub Actions, GitLab CI or CircleCI. Set a default with `bundle config set --global gem.ci (github|gitlab|circle)`" + method_option :linter, type: :string, lazy_default: Bundler.settings["gem.linter"] || "", enum: %w[rubocop standard], banner: "Add a linter and code formatter, either RuboCop or Standard. Set a default with `bundle config set --global gem.linter (rubocop|standard)`" method_option :github_username, type: :string, default: Bundler.settings["gem.github_username"], banner: "Set your username on GitHub", desc: "Fill in GitHub username on README so that you don't have to do it manually. Set a default with `bundle config set --global gem.github_username <your_username>`." - method_option :bundle, type: :boolean, default: Bundler.settings["gem.bundle"], desc: "Automatically run `bundle install` after creation. Set a default with `bundle config set --global gem.bundle true`" + method_option :bundle, type: :boolean, default: Bundler.settings["gem.bundle"], banner: "Automatically run `bundle install` after creation. Set a default with `bundle config set --global gem.bundle true`" def gem(name) require_relative "cli/gem" @@ -713,7 +715,12 @@ module Bundler command_name = cmd.name return if PARSEABLE_COMMANDS.include?(command_name) command = ["bundle", command_name] + args - command << Thor::Options.to_switches(options.sort_by(&:first)).strip + options_to_print = options.dup + options_to_print.delete_if do |k, v| + next unless o = cmd.options[k] + o.default == v + end + command << Thor::Options.to_switches(options_to_print.sort_by(&:first)).strip command.reject!(&:empty?) Bundler.ui.info "Running `#{command * " "}` with bundler #{Bundler.verbose_version}" end diff --git a/lib/bundler/cli/list.rb b/lib/bundler/cli/list.rb index f56bf5b86a..6a467f45a9 100644 --- a/lib/bundler/cli/list.rb +++ b/lib/bundler/cli/list.rb @@ -1,11 +1,14 @@ # frozen_string_literal: true +require "json" + module Bundler class CLI::List def initialize(options) @options = options @without_group = options["without-group"].map(&:to_sym) @only_group = options["only-group"].map(&:to_sym) + @format = options["format"] end def run @@ -25,6 +28,36 @@ module Bundler end end.reject {|s| s.name == "bundler" }.sort_by(&:name) + case @format + when "json" + print_json(specs: specs) + when nil + print_human(specs: specs) + else + raise InvalidOption, "Unknown option`--format=#{@format}`. Supported formats: `json`" + end + end + + private + + def print_json(specs:) + gems = if @options["name-only"] + specs.map {|s| { name: s.name } } + else + specs.map do |s| + { + name: s.name, + version: s.version.to_s, + git_version: s.git_version&.strip, + }.tap do |h| + h[:path] = s.full_gem_path if @options["paths"] + end + end + end + Bundler.ui.info({ gems: gems }.to_json) + end + + def print_human(specs:) return Bundler.ui.info "No gems in the Gemfile" if specs.empty? return specs.each {|s| Bundler.ui.info s.name } if @options["name-only"] @@ -37,8 +70,6 @@ module Bundler Bundler.ui.info "Use `bundle info` to print more detailed information about a gem" end - private - def verify_group_exists(groups) (@without_group + @only_group).each do |group| raise InvalidOption, "`#{group}` group could not be found." unless groups.include?(group) diff --git a/lib/bundler/cli/show.rb b/lib/bundler/cli/show.rb index 13bb8b774b..b55eb7bad5 100644 --- a/lib/bundler/cli/show.rb +++ b/lib/bundler/cli/show.rb @@ -57,12 +57,8 @@ module Bundler def fetch_latest_specs definition = Bundler.definition(true) - if options[:outdated] - Bundler.ui.info "Fetching remote specs for outdated check...\n\n" - Bundler.ui.silence { definition.remotely! } - else - definition.with_cache! - end + Bundler.ui.info "Fetching remote specs for outdated check...\n\n" + Bundler.ui.silence { definition.remotely! } Bundler.reset! definition.specs end diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 6c7a3e9c38..52f9c6e125 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -492,8 +492,6 @@ module Bundler @unlocking end - attr_writer :source_requirements - def add_checksums @locked_checksums = true @@ -533,7 +531,7 @@ module Bundler return unless added.any? || deleted.any? || changed.any? || resolve_needed? - msg = String.new("#{change_reason.capitalize.strip}, but ") + msg = String.new("#{change_reason[0].upcase}#{change_reason[1..-1].strip}, but ") msg << "the lockfile " unless msg.start_with?("Your lockfile") msg << "can't be updated because #{update_refused_reason}" msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any? @@ -559,6 +557,7 @@ module Bundler @missing_lockfile_dep || @unlocking_bundler || @locked_spec_with_missing_checksums || + @locked_spec_with_empty_checksums || @locked_spec_with_missing_deps || @locked_spec_with_invalid_deps end @@ -614,7 +613,7 @@ module Bundler end def resolver - @resolver ||= Resolver.new(resolution_base, gem_version_promoter, @most_specific_locked_platform) + @resolver ||= new_resolver(resolution_base) end def expanded_dependencies @@ -632,8 +631,7 @@ module Bundler @resolution_base ||= begin last_resolve = converge_locked_specs remove_invalid_platforms! - new_resolution_platforms = @current_platform_missing ? @new_platforms + [Bundler.local_platform] : @new_platforms - base = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: @unlocking_all || @gems_to_unlock, prerelease: gem_version_promoter.pre?, prefer_local: @prefer_local, new_platforms: new_resolution_platforms) + base = new_resolution_base(last_resolve: last_resolve, unlock: @unlocking_all || @gems_to_unlock) base = additional_base_requirements_to_prevent_downgrades(base) base = additional_base_requirements_to_force_updates(base) base @@ -839,6 +837,7 @@ module Bundler [@missing_lockfile_dep, "your lockfile is missing \"#{@missing_lockfile_dep}\""], [@unlocking_bundler, "an update to the version of Bundler itself was requested"], [@locked_spec_with_missing_checksums, "your lockfile is missing a CHECKSUMS entry for \"#{@locked_spec_with_missing_checksums}\""], + [@locked_spec_with_empty_checksums, "your lockfile has an empty CHECKSUMS entry for \"#{@locked_spec_with_empty_checksums}\""], [@locked_spec_with_missing_deps, "your lockfile includes \"#{@locked_spec_with_missing_deps}\" but not some of its dependencies"], [@locked_spec_with_invalid_deps, "your lockfile does not satisfy dependencies of \"#{@locked_spec_with_invalid_deps}\""], ].select(&:first).map(&:last).join(", ") @@ -898,13 +897,23 @@ module Bundler @locked_spec_with_invalid_deps = nil @locked_spec_with_missing_deps = nil @locked_spec_with_missing_checksums = nil + @locked_spec_with_empty_checksums = nil missing_deps = [] missing_checksums = [] + empty_checksums = [] invalid = [] @locked_specs.each do |s| - missing_checksums << s if @locked_checksums && s.source.checksum_store.missing?(s) + if @locked_checksums + checksum_store = s.source.checksum_store + + if checksum_store.missing?(s) + missing_checksums << s + elsif checksum_store.empty?(s) + empty_checksums << s + end + end validation = @locked_specs.validate_deps(s) @@ -913,6 +922,7 @@ module Bundler end @locked_spec_with_missing_checksums = missing_checksums.first.name if missing_checksums.any? + @locked_spec_with_empty_checksums = empty_checksums.first.name if empty_checksums.any? if missing_deps.any? @locked_specs.delete(missing_deps) @@ -1136,7 +1146,7 @@ module Bundler def additional_base_requirements_to_force_updates(resolution_base) return resolution_base if @explicit_unlocks.empty? - full_update = dup_for_full_unlock.resolve + full_update = SpecSet.new(new_resolver_for_full_update.start) @explicit_unlocks.each do |name| version = full_update.version_for(name) resolution_base.base_requirements[name] = Gem::Requirement.new("= #{version}") if version @@ -1144,17 +1154,6 @@ module Bundler resolution_base end - def dup_for_full_unlock - unlocked_definition = self.class.new(@lockfile, @dependencies, @sources, true, @ruby_version, @optional_groups, @gemfiles) - unlocked_definition.source_requirements = source_requirements - unlocked_definition.gem_version_promoter.tap do |gvp| - gvp.level = gem_version_promoter.level - gvp.strict = gem_version_promoter.strict - gvp.pre = gem_version_promoter.pre - end - unlocked_definition - end - def remove_invalid_platforms! return if Bundler.frozen_bundle? @@ -1173,5 +1172,22 @@ module Bundler def source_map @source_map ||= SourceMap.new(sources, dependencies, @locked_specs) end + + def new_resolver_for_full_update + new_resolver(unlocked_resolution_base) + end + + def unlocked_resolution_base + new_resolution_base(last_resolve: SpecSet.new([]), unlock: true) + end + + def new_resolution_base(last_resolve:, unlock:) + new_resolution_platforms = @current_platform_missing ? @new_platforms + [Bundler.local_platform] : @new_platforms + Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: unlock, prerelease: gem_version_promoter.pre?, prefer_local: @prefer_local, new_platforms: new_resolution_platforms) + end + + def new_resolver(base) + Resolver.new(base, gem_version_promoter, @most_specific_locked_platform) + end end end diff --git a/lib/bundler/man/bundle-add.1 b/lib/bundler/man/bundle-add.1 index baa4a376c8..74422cbd31 100644 --- a/lib/bundler/man/bundle-add.1 +++ b/lib/bundler/man/bundle-add.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-ADD" "1" "July 2025" "" +.TH "BUNDLE\-ADD" "1" "August 2025" "" .SH "NAME" \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-binstubs.1 b/lib/bundler/man/bundle-binstubs.1 index 0131dd663e..be9c6d0d09 100644 --- a/lib/bundler/man/bundle-binstubs.1 +++ b/lib/bundler/man/bundle-binstubs.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-BINSTUBS" "1" "July 2025" "" +.TH "BUNDLE\-BINSTUBS" "1" "August 2025" "" .SH "NAME" \fBbundle\-binstubs\fR \- Install the binstubs of the listed gems .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-cache.1 b/lib/bundler/man/bundle-cache.1 index 4c5dcff052..1d16b164fa 100644 --- a/lib/bundler/man/bundle-cache.1 +++ b/lib/bundler/man/bundle-cache.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-CACHE" "1" "July 2025" "" +.TH "BUNDLE\-CACHE" "1" "August 2025" "" .SH "NAME" \fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-check.1 b/lib/bundler/man/bundle-check.1 index 376becdbe4..4f0d51bb71 100644 --- a/lib/bundler/man/bundle-check.1 +++ b/lib/bundler/man/bundle-check.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-CHECK" "1" "July 2025" "" +.TH "BUNDLE\-CHECK" "1" "August 2025" "" .SH "NAME" \fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-clean.1 b/lib/bundler/man/bundle-clean.1 index 85e6186f49..df66523829 100644 --- a/lib/bundler/man/bundle-clean.1 +++ b/lib/bundler/man/bundle-clean.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-CLEAN" "1" "July 2025" "" +.TH "BUNDLE\-CLEAN" "1" "August 2025" "" .SH "NAME" \fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index 6f12696ab6..5157e51453 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -1,16 +1,16 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-CONFIG" "1" "July 2025" "" +.TH "BUNDLE\-CONFIG" "1" "August 2025" "" .SH "NAME" \fBbundle\-config\fR \- Set bundler configuration options .SH "SYNOPSIS" -\fBbundle config\fR list +\fBbundle config\fR [list] .br -\fBbundle config\fR [get] NAME +\fBbundle config\fR [get [\-\-local|\-\-global]] NAME .br -\fBbundle config\fR [set] NAME VALUE +\fBbundle config\fR [set [\-\-local|\-\-global]] NAME VALUE .br -\fBbundle config\fR unset NAME +\fBbundle config\fR unset [\-\-local|\-\-global] NAME .SH "DESCRIPTION" This command allows you to interact with Bundler's configuration system\. .P @@ -25,23 +25,40 @@ Global config (\fB~/\.bundle/config\fR) Bundler default config .IP "" 0 .P +Executing \fBbundle\fR with the \fBBUNDLE_IGNORE_CONFIG\fR environment variable set will cause it to ignore all configuration\. +.SH "SUB\-COMMANDS" +.SS "list (default command)" Executing \fBbundle config list\fR will print a list of all bundler configuration for the current bundle, and where that configuration was set\. +.SS "get" +Executing \fBbundle config get <name>\fR will print the value of that configuration setting, and all locations where it was set\. .P -Executing \fBbundle config get <name>\fR will print the value of that configuration setting, and where it was set\. -.P -Executing \fBbundle config set <name> <value>\fR defaults to setting \fBlocal\fR configuration if executing from within a local application, otherwise it will set \fBglobal\fR configuration\. See \fB\-\-local\fR and \fB\-\-global\fR options below\. +\fBOPTIONS\fR +.TP +\fB\-\-local\fR +Get configuration from configuration file for the local application, namely, \fB<project_root>/\.bundle/config\fR, or \fB$BUNDLE_APP_CONFIG/config\fR if \fBBUNDLE_APP_CONFIG\fR is set\. +.TP +\fB\-\-global\fR +Get configuration from configuration file global to all bundles executed as the current user, namely, from \fB~/\.bundle/config\fR\. +.SS "set" +Executing \fBbundle config set <name> <value>\fR defaults to setting \fBlocal\fR configuration if executing from within a local application, otherwise it will set \fBglobal\fR configuration\. .P +\fBOPTIONS\fR +.TP +\fB\-\-local\fR Executing \fBbundle config set \-\-local <name> <value>\fR will set that configuration in the directory for the local application\. The configuration will be stored in \fB<project_root>/\.bundle/config\fR\. If \fBBUNDLE_APP_CONFIG\fR is set, the configuration will be stored in \fB$BUNDLE_APP_CONFIG/config\fR\. -.P +.TP +\fB\-\-global\fR Executing \fBbundle config set \-\-global <name> <value>\fR will set that configuration to the value specified for all bundles executed as the current user\. The configuration will be stored in \fB~/\.bundle/config\fR\. If \fIname\fR already is set, \fIname\fR will be overridden and user will be warned\. -.P +.SS "unset" Executing \fBbundle config unset <name>\fR will delete the configuration in both local and global sources\. .P -Executing \fBbundle config unset \-\-global <name>\fR will delete the configuration only from the user configuration\. -.P +\fBOPTIONS\fR +.TP +\fB\-\-local\fR Executing \fBbundle config unset \-\-local <name>\fR will delete the configuration only from the local application\. -.P -Executing bundle with the \fBBUNDLE_IGNORE_CONFIG\fR environment variable set will cause it to ignore all configuration\. +.TP +\fB\-\-global\fR +Executing \fBbundle config unset \-\-global <name>\fR will delete the configuration only from the user configuration\. .SH "CONFIGURATION KEYS" Configuration keys in bundler have two forms: the canonical form and the environment variable form\. .P diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn index 7f31eb4c39..2b2e39f03e 100644 --- a/lib/bundler/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -3,10 +3,10 @@ bundle-config(1) -- Set bundler configuration options ## SYNOPSIS -`bundle config` list<br> -`bundle config` [get] NAME<br> -`bundle config` [set] NAME VALUE<br> -`bundle config` unset NAME +`bundle config` [list]<br> +`bundle config` [get [--local|--global]] NAME<br> +`bundle config` [set [--local|--global]] NAME VALUE<br> +`bundle config` unset [--local|--global] NAME ## DESCRIPTION @@ -19,38 +19,67 @@ Bundler loads configuration settings in this order: 3. Global config (`~/.bundle/config`) 4. Bundler default config +Executing `bundle` with the `BUNDLE_IGNORE_CONFIG` environment variable set will +cause it to ignore all configuration. + +## SUB-COMMANDS + +### list (default command) + Executing `bundle config list` will print a list of all bundler configuration for the current bundle, and where that configuration was set. +### get + Executing `bundle config get <name>` will print the value of that configuration -setting, and where it was set. +setting, and all locations where it was set. + +**OPTIONS** + +* `--local`: + Get configuration from configuration file for the local application, namely, + `<project_root>/.bundle/config`, or `$BUNDLE_APP_CONFIG/config` if + `BUNDLE_APP_CONFIG` is set. + +* `--global`: + Get configuration from configuration file global to all bundles executed as + the current user, namely, from `~/.bundle/config`. + +### set Executing `bundle config set <name> <value>` defaults to setting `local` configuration if executing from within a local application, otherwise it will -set `global` configuration. See `--local` and `--global` options below. +set `global` configuration. -Executing `bundle config set --local <name> <value>` will set that configuration -in the directory for the local application. The configuration will be stored in -`<project_root>/.bundle/config`. If `BUNDLE_APP_CONFIG` is set, the configuration -will be stored in `$BUNDLE_APP_CONFIG/config`. +**OPTIONS** -Executing `bundle config set --global <name> <value>` will set that -configuration to the value specified for all bundles executed as the current -user. The configuration will be stored in `~/.bundle/config`. If <name> already -is set, <name> will be overridden and user will be warned. +* `--local`: + Executing `bundle config set --local <name> <value>` will set that configuration + in the directory for the local application. The configuration will be stored in + `<project_root>/.bundle/config`. If `BUNDLE_APP_CONFIG` is set, the configuration + will be stored in `$BUNDLE_APP_CONFIG/config`. + +* `--global`: + Executing `bundle config set --global <name> <value>` will set that + configuration to the value specified for all bundles executed as the current + user. The configuration will be stored in `~/.bundle/config`. If <name> already + is set, <name> will be overridden and user will be warned. + +### unset Executing `bundle config unset <name>` will delete the configuration in both local and global sources. -Executing `bundle config unset --global <name>` will delete the configuration -only from the user configuration. +**OPTIONS** -Executing `bundle config unset --local <name>` will delete the configuration -only from the local application. +* `--local`: + Executing `bundle config unset --local <name>` will delete the configuration + only from the local application. -Executing bundle with the `BUNDLE_IGNORE_CONFIG` environment variable set will -cause it to ignore all configuration. +* `--global`: + Executing `bundle config unset --global <name>` will delete the configuration + only from the user configuration. ## CONFIGURATION KEYS diff --git a/lib/bundler/man/bundle-console.1 b/lib/bundler/man/bundle-console.1 index a263fef376..18c765372b 100644 --- a/lib/bundler/man/bundle-console.1 +++ b/lib/bundler/man/bundle-console.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-CONSOLE" "1" "July 2025" "" +.TH "BUNDLE\-CONSOLE" "1" "August 2025" "" .SH "NAME" \fBbundle\-console\fR \- Open an IRB session with the bundle pre\-loaded .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-doctor.1 b/lib/bundler/man/bundle-doctor.1 index 2b695dc2ee..6d4b0376a6 100644 --- a/lib/bundler/man/bundle-doctor.1 +++ b/lib/bundler/man/bundle-doctor.1 @@ -1,12 +1,12 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-DOCTOR" "1" "July 2025" "" +.TH "BUNDLE\-DOCTOR" "1" "August 2025" "" .SH "NAME" \fBbundle\-doctor\fR \- Checks the bundle for common problems .SH "SYNOPSIS" \fBbundle doctor [diagnose]\fR [\-\-quiet] [\-\-gemfile=GEMFILE] [\-\-ssl] .br -\fBbundle doctor ssl\fR [\-\-host=HOST] [\-\-tls\-version=VERSION] [\-\-verify\-mode=MODE] +\fBbundle doctor ssl\fR [\-\-host=HOST] [\-\-tls\-version=TLS\-VERSION] [\-\-verify\-mode=VERIFY\-MODE] .br \fBbundle doctor\fR help [COMMAND] .SH "DESCRIPTION" @@ -57,12 +57,12 @@ Open a TLS connection and verify the outcome\. \fB\-\-host=HOST\fR Perform the diagnostic on HOST\. Defaults to \fBrubygems\.org\fR\. .TP -\fB\-\-tls\-version=VERSION\fR +\fB\-\-tls\-version=TLS\-VERSION\fR Specify the TLS version when opening the connection to HOST\. .IP Accepted values are: \fB1\.1\fR or \fB1\.2\fR\. .TP -\fB\-\-verify\-mode=MODE\fR +\fB\-\-verify\-mode=VERIFY\-MODE\fR Specify the TLS verify mode when opening the connection to HOST\. Defaults to \fBSSL_VERIFY_PEER\fR\. .IP Accepted values are: \fBCLIENT_ONCE\fR, \fBFAIL_IF_NO_PEER_CERT\fR, \fBNONE\fR, \fBPEER\fR\. diff --git a/lib/bundler/man/bundle-doctor.1.ronn b/lib/bundler/man/bundle-doctor.1.ronn index 7e8a21b1c5..7495099ff5 100644 --- a/lib/bundler/man/bundle-doctor.1.ronn +++ b/lib/bundler/man/bundle-doctor.1.ronn @@ -7,8 +7,8 @@ bundle-doctor(1) -- Checks the bundle for common problems [--gemfile=GEMFILE] [--ssl]<br> `bundle doctor ssl` [--host=HOST] - [--tls-version=VERSION] - [--verify-mode=MODE]<br> + [--tls-version=TLS-VERSION] + [--verify-mode=VERIFY-MODE]<br> `bundle doctor` help [COMMAND] ## DESCRIPTION @@ -65,12 +65,12 @@ The diagnostic will perform a few checks such as: * `--host=HOST`: Perform the diagnostic on HOST. Defaults to `rubygems.org`. -* `--tls-version=VERSION`: +* `--tls-version=TLS-VERSION`: Specify the TLS version when opening the connection to HOST. Accepted values are: `1.1` or `1.2`. -* `--verify-mode=MODE`: +* `--verify-mode=VERIFY-MODE`: Specify the TLS verify mode when opening the connection to HOST. Defaults to `SSL_VERIFY_PEER`. diff --git a/lib/bundler/man/bundle-env.1 b/lib/bundler/man/bundle-env.1 index 3e6c9f6e17..28ccc17f03 100644 --- a/lib/bundler/man/bundle-env.1 +++ b/lib/bundler/man/bundle-env.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-ENV" "1" "July 2025" "" +.TH "BUNDLE\-ENV" "1" "August 2025" "" .SH "NAME" \fBbundle\-env\fR \- Print information about the environment Bundler is running under .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-exec.1 b/lib/bundler/man/bundle-exec.1 index 79cdad0288..cd53916cff 100644 --- a/lib/bundler/man/bundle-exec.1 +++ b/lib/bundler/man/bundle-exec.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-EXEC" "1" "July 2025" "" +.TH "BUNDLE\-EXEC" "1" "August 2025" "" .SH "NAME" \fBbundle\-exec\fR \- Execute a command in the context of the bundle .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-fund.1 b/lib/bundler/man/bundle-fund.1 index 3f6e3a46df..a91c180951 100644 --- a/lib/bundler/man/bundle-fund.1 +++ b/lib/bundler/man/bundle-fund.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-FUND" "1" "July 2025" "" +.TH "BUNDLE\-FUND" "1" "August 2025" "" .SH "NAME" \fBbundle\-fund\fR \- Lists information about gems seeking funding assistance .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1 index 44a02c033c..5fe2777230 100644 --- a/lib/bundler/man/bundle-gem.1 +++ b/lib/bundler/man/bundle-gem.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-GEM" "1" "July 2025" "" +.TH "BUNDLE\-GEM" "1" "August 2025" "" .SH "NAME" \fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-help.1 b/lib/bundler/man/bundle-help.1 index e6bbea6dad..9ea28bef14 100644 --- a/lib/bundler/man/bundle-help.1 +++ b/lib/bundler/man/bundle-help.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-HELP" "1" "July 2025" "" +.TH "BUNDLE\-HELP" "1" "August 2025" "" .SH "NAME" \fBbundle\-help\fR \- Displays detailed help for each subcommand .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-info.1 b/lib/bundler/man/bundle-info.1 index 435518e120..29d649d342 100644 --- a/lib/bundler/man/bundle-info.1 +++ b/lib/bundler/man/bundle-info.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-INFO" "1" "July 2025" "" +.TH "BUNDLE\-INFO" "1" "August 2025" "" .SH "NAME" \fBbundle\-info\fR \- Show information for the given gem in your bundle .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-init.1 b/lib/bundler/man/bundle-init.1 index 48b3232b8c..be9399c20f 100644 --- a/lib/bundler/man/bundle-init.1 +++ b/lib/bundler/man/bundle-init.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-INIT" "1" "July 2025" "" +.TH "BUNDLE\-INIT" "1" "August 2025" "" .SH "NAME" \fBbundle\-init\fR \- Generates a Gemfile into the current working directory .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-inject.1 b/lib/bundler/man/bundle-inject.1 index abc63c392e..7e30e26a4e 100644 --- a/lib/bundler/man/bundle-inject.1 +++ b/lib/bundler/man/bundle-inject.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-INJECT" "1" "July 2025" "" +.TH "BUNDLE\-INJECT" "1" "August 2025" "" .SH "NAME" \fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-install.1 b/lib/bundler/man/bundle-install.1 index bf06747558..f9bbade2fd 100644 --- a/lib/bundler/man/bundle-install.1 +++ b/lib/bundler/man/bundle-install.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-INSTALL" "1" "July 2025" "" +.TH "BUNDLE\-INSTALL" "1" "August 2025" "" .SH "NAME" \fBbundle\-install\fR \- Install the dependencies specified in your Gemfile .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-issue.1 b/lib/bundler/man/bundle-issue.1 index 668da5712f..3c7e5305f3 100644 --- a/lib/bundler/man/bundle-issue.1 +++ b/lib/bundler/man/bundle-issue.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-ISSUE" "1" "July 2025" "" +.TH "BUNDLE\-ISSUE" "1" "August 2025" "" .SH "NAME" \fBbundle\-issue\fR \- Get help reporting Bundler issues .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-licenses.1 b/lib/bundler/man/bundle-licenses.1 index cccb860854..eb0ad5ae40 100644 --- a/lib/bundler/man/bundle-licenses.1 +++ b/lib/bundler/man/bundle-licenses.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-LICENSES" "1" "July 2025" "" +.TH "BUNDLE\-LICENSES" "1" "August 2025" "" .SH "NAME" \fBbundle\-licenses\fR \- Print the license of all gems in the bundle .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-list.1 b/lib/bundler/man/bundle-list.1 index 26c2833218..a345787a5e 100644 --- a/lib/bundler/man/bundle-list.1 +++ b/lib/bundler/man/bundle-list.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-LIST" "1" "July 2025" "" +.TH "BUNDLE\-LIST" "1" "August 2025" "" .SH "NAME" \fBbundle\-list\fR \- List all the gems in the bundle .SH "SYNOPSIS" @@ -19,6 +19,8 @@ bundle list \-\-without\-group test bundle list \-\-only\-group dev .P bundle list \-\-only\-group dev test \-\-paths +.P +bundle list \-\-format json .SH "OPTIONS" .TP \fB\-\-name\-only\fR @@ -32,4 +34,7 @@ A space\-separated list of groups of gems to skip during printing\. .TP \fB\-\-only\-group=<list>\fR A space\-separated list of groups of gems to print\. +.TP +\fB\-\-format=FORMAT\fR +Format output ('json' is the only supported format) diff --git a/lib/bundler/man/bundle-list.1.ronn b/lib/bundler/man/bundle-list.1.ronn index 81bee0ac33..9ec2b13282 100644 --- a/lib/bundler/man/bundle-list.1.ronn +++ b/lib/bundler/man/bundle-list.1.ronn @@ -21,6 +21,8 @@ bundle list --only-group dev bundle list --only-group dev test --paths +bundle list --format json + ## OPTIONS * `--name-only`: @@ -34,3 +36,6 @@ bundle list --only-group dev test --paths * `--only-group=<list>`: A space-separated list of groups of gems to print. + +* `--format=FORMAT`: + Format output ('json' is the only supported format) diff --git a/lib/bundler/man/bundle-lock.1 b/lib/bundler/man/bundle-lock.1 index 5faa46da18..79aa1e2452 100644 --- a/lib/bundler/man/bundle-lock.1 +++ b/lib/bundler/man/bundle-lock.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-LOCK" "1" "July 2025" "" +.TH "BUNDLE\-LOCK" "1" "August 2025" "" .SH "NAME" \fBbundle\-lock\fR \- Creates / Updates a lockfile without installing .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-open.1 b/lib/bundler/man/bundle-open.1 index e8a24f3541..b1c2022f40 100644 --- a/lib/bundler/man/bundle-open.1 +++ b/lib/bundler/man/bundle-open.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-OPEN" "1" "July 2025" "" +.TH "BUNDLE\-OPEN" "1" "August 2025" "" .SH "NAME" \fBbundle\-open\fR \- Opens the source directory for a gem in your bundle .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-outdated.1 b/lib/bundler/man/bundle-outdated.1 index 3259b0f023..d4790f8876 100644 --- a/lib/bundler/man/bundle-outdated.1 +++ b/lib/bundler/man/bundle-outdated.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-OUTDATED" "1" "July 2025" "" +.TH "BUNDLE\-OUTDATED" "1" "August 2025" "" .SH "NAME" \fBbundle\-outdated\fR \- List installed gems with newer versions available .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-platform.1 b/lib/bundler/man/bundle-platform.1 index 1032acc4e6..78de506b57 100644 --- a/lib/bundler/man/bundle-platform.1 +++ b/lib/bundler/man/bundle-platform.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-PLATFORM" "1" "July 2025" "" +.TH "BUNDLE\-PLATFORM" "1" "August 2025" "" .SH "NAME" \fBbundle\-platform\fR \- Displays platform compatibility information .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-plugin.1 b/lib/bundler/man/bundle-plugin.1 index 5803b7a554..5fcc88b50d 100644 --- a/lib/bundler/man/bundle-plugin.1 +++ b/lib/bundler/man/bundle-plugin.1 @@ -1,10 +1,10 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-PLUGIN" "1" "July 2025" "" +.TH "BUNDLE\-PLUGIN" "1" "August 2025" "" .SH "NAME" \fBbundle\-plugin\fR \- Manage Bundler plugins .SH "SYNOPSIS" -\fBbundle plugin\fR install PLUGINS [\-\-source=\fISOURCE\fR] [\-\-version=\fIversion\fR] [\-\-git=\fIgit\-url\fR] [\-\-branch=\fIbranch\fR|\-\-ref=\fIrev\fR] [\-\-path=\fIpath\fR] +\fBbundle plugin\fR install PLUGINS [\-\-source=SOURCE] [\-\-version=VERSION] [\-\-git=GIT] [\-\-branch=BRANCH|\-\-ref=REF] [\-\-local\-git=LOCAL_GIT] [\-\-path=PATH] .br \fBbundle plugin\fR uninstall PLUGINS [\-\-all] .br @@ -16,18 +16,23 @@ You can install, uninstall, and list plugin(s) with this command to extend funct .SH "SUB\-COMMANDS" .SS "install" Install the given plugin(s)\. +.P +For example, \fBbundle plugin install bundler\-graph\fR will install bundler\-graph gem from globally configured sources (defaults to RubyGems\.org)\. Note that the global source specified in Gemfile is ignored\. +.P +\fBOPTIONS\fR .TP -\fBbundle plugin install bundler\-graph\fR -Install bundler\-graph gem from globally configured sources (defaults to RubyGems\.org)\. The global source, specified in source in Gemfile is ignored\. -.TP -\fBbundle plugin install bundler\-graph \-\-source https://example\.com\fR -Install bundler\-graph gem from example\.com\. The global source, specified in source in Gemfile is not considered\. +\fB\-\-source=SOURCE\fR +Install the plugin gem from a specific source, rather than from globally configured sources\. +.IP +Example: \fBbundle plugin install bundler\-graph \-\-source https://example\.com\fR .TP -\fBbundle plugin install bundler\-graph \-\-version 0\.2\.1\fR -You can specify the version of the gem via \fB\-\-version\fR\. +\fB\-\-version=VERSION\fR +Specify a version of the plugin gem to install via \fB\-\-version\fR\. +.IP +Example: \fBbundle plugin install bundler\-graph \-\-version 0\.2\.1\fR .TP -\fBbundle plugin install bundler\-graph \-\-git https://github\.com/rubygems/bundler\-graph\fR -Install bundler\-graph gem from Git repository\. You can use standard Git URLs like: +\fB\-\-git=GIT\fR +Install the plugin gem from a Git repository\. You can use standard Git URLs like: .IP \fBssh://[user@]host\.xz[:port]/path/to/repo\.git\fR .br @@ -37,12 +42,24 @@ Install bundler\-graph gem from Git repository\. You can use standard Git URLs l .br \fBfile:///path/to/repo\fR .IP -When you specify \fB\-\-git\fR, you can use \fB\-\-branch\fR or \fB\-\-ref\fR to specify any branch, tag, or commit hash (revision) to use\. +Example: \fBbundle plugin install bundler\-graph \-\-git https://github\.com/rubygems/bundler\-graph\fR .TP -\fBbundle plugin install bundler\-graph \-\-path \.\./bundler\-graph\fR -Install bundler\-graph gem from a local path\. +\fB\-\-branch=BRANCH\fR +When you specify \fB\-\-git\fR, you can use \fB\-\-branch\fR to use\. .TP -\fBbundle plugin install bundler\-graph \-\-local\-git \.\./bundler\-graph\fR +\fB\-\-ref=REF\fR +When you specify \fB\-\-git\fR, you can use \fB\-\-ref\fR to specify any tag, or commit hash (revision) to use\. +.TP +\fB\-\-path=PATH\fR +Install the plugin gem from a local path\. +.IP +Example: \fBbundle plugin install bundler\-graph \-\-path \.\./bundler\-graph\fR +.TP +\fB\-\-local\-git=LOCAL_GIT\fR +Install the plugin gem from a local Git repository\. +.IP +Example: \fBbundle plugin install bundler\-graph \-\-local\-git \.\./bundler\-graph\fR\. +.IP This option is deprecated in favor of \fB\-\-git\fR\. .SS "uninstall" Uninstall the plugin(s) specified in PLUGINS\. diff --git a/lib/bundler/man/bundle-plugin.1.ronn b/lib/bundler/man/bundle-plugin.1.ronn index 74879aa681..efb4240761 100644 --- a/lib/bundler/man/bundle-plugin.1.ronn +++ b/lib/bundler/man/bundle-plugin.1.ronn @@ -3,9 +3,10 @@ bundle-plugin(1) -- Manage Bundler plugins ## SYNOPSIS -`bundle plugin` install PLUGINS [--source=<SOURCE>] [--version=<version>] - [--git=<git-url>] [--branch=<branch>|--ref=<rev>] - [--path=<path>]<br> +`bundle plugin` install PLUGINS [--source=SOURCE] [--version=VERSION] + [--git=GIT] [--branch=BRANCH|--ref=REF] + [--local-git=LOCAL_GIT] + [--path=PATH]<br> `bundle plugin` uninstall PLUGINS [--all]<br> `bundle plugin` list<br> `bundle plugin` help [COMMAND] @@ -20,29 +21,49 @@ You can install, uninstall, and list plugin(s) with this command to extend funct Install the given plugin(s). -* `bundle plugin install bundler-graph`: - Install bundler-graph gem from globally configured sources (defaults to RubyGems.org). The global source, specified in source in Gemfile is ignored. +For example, `bundle plugin install bundler-graph` will install bundler-graph +gem from globally configured sources (defaults to RubyGems.org). Note that the +global source specified in Gemfile is ignored. -* `bundle plugin install bundler-graph --source https://example.com`: - Install bundler-graph gem from example.com. The global source, specified in source in Gemfile is not considered. +**OPTIONS** + +* `--source=SOURCE`: + Install the plugin gem from a specific source, rather than from globally configured sources. + + Example: `bundle plugin install bundler-graph --source https://example.com` -* `bundle plugin install bundler-graph --version 0.2.1`: - You can specify the version of the gem via `--version`. +* `--version=VERSION`: + Specify a version of the plugin gem to install via `--version`. -* `bundle plugin install bundler-graph --git https://github.com/rubygems/bundler-graph`: - Install bundler-graph gem from Git repository. You can use standard Git URLs like: + Example: `bundle plugin install bundler-graph --version 0.2.1` + +* `--git=GIT`: + Install the plugin gem from a Git repository. You can use standard Git URLs like: `ssh://[user@]host.xz[:port]/path/to/repo.git`<br> `http[s]://host.xz[:port]/path/to/repo.git`<br> `/path/to/repo`<br> `file:///path/to/repo` - When you specify `--git`, you can use `--branch` or `--ref` to specify any branch, tag, or commit hash (revision) to use. + Example: `bundle plugin install bundler-graph --git https://github.com/rubygems/bundler-graph` + +* `--branch=BRANCH`: + When you specify `--git`, you can use `--branch` to use. + +* `--ref=REF`: + When you specify `--git`, you can use `--ref` to specify any tag, or commit + hash (revision) to use. + +* `--path=PATH`: + Install the plugin gem from a local path. + + Example: `bundle plugin install bundler-graph --path ../bundler-graph` + +* `--local-git=LOCAL_GIT`: + Install the plugin gem from a local Git repository. -* `bundle plugin install bundler-graph --path ../bundler-graph`: - Install bundler-graph gem from a local path. + Example: `bundle plugin install bundler-graph --local-git ../bundler-graph`. -* `bundle plugin install bundler-graph --local-git ../bundler-graph`: This option is deprecated in favor of `--git`. ### uninstall diff --git a/lib/bundler/man/bundle-pristine.1 b/lib/bundler/man/bundle-pristine.1 index 5c7871069c..e39f264cef 100644 --- a/lib/bundler/man/bundle-pristine.1 +++ b/lib/bundler/man/bundle-pristine.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-PRISTINE" "1" "July 2025" "" +.TH "BUNDLE\-PRISTINE" "1" "August 2025" "" .SH "NAME" \fBbundle\-pristine\fR \- Restores installed gems to their pristine condition .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-remove.1 b/lib/bundler/man/bundle-remove.1 index df8ce3232a..6750817680 100644 --- a/lib/bundler/man/bundle-remove.1 +++ b/lib/bundler/man/bundle-remove.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-REMOVE" "1" "July 2025" "" +.TH "BUNDLE\-REMOVE" "1" "August 2025" "" .SH "NAME" \fBbundle\-remove\fR \- Removes gems from the Gemfile .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-show.1 b/lib/bundler/man/bundle-show.1 index ca10c00701..67b387559d 100644 --- a/lib/bundler/man/bundle-show.1 +++ b/lib/bundler/man/bundle-show.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-SHOW" "1" "July 2025" "" +.TH "BUNDLE\-SHOW" "1" "August 2025" "" .SH "NAME" \fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-update.1 b/lib/bundler/man/bundle-update.1 index 8655aa5cd3..fbcabb69a8 100644 --- a/lib/bundler/man/bundle-update.1 +++ b/lib/bundler/man/bundle-update.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-UPDATE" "1" "July 2025" "" +.TH "BUNDLE\-UPDATE" "1" "August 2025" "" .SH "NAME" \fBbundle\-update\fR \- Update your gems to the latest available versions .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-version.1 b/lib/bundler/man/bundle-version.1 index e591f59766..261140ff38 100644 --- a/lib/bundler/man/bundle-version.1 +++ b/lib/bundler/man/bundle-version.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-VERSION" "1" "July 2025" "" +.TH "BUNDLE\-VERSION" "1" "August 2025" "" .SH "NAME" \fBbundle\-version\fR \- Prints Bundler version information .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-viz.1 b/lib/bundler/man/bundle-viz.1 index b5dd1db7b7..f2570103dc 100644 --- a/lib/bundler/man/bundle-viz.1 +++ b/lib/bundler/man/bundle-viz.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-VIZ" "1" "July 2025" "" +.TH "BUNDLE\-VIZ" "1" "August 2025" "" .SH "NAME" \fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle.1 b/lib/bundler/man/bundle.1 index 269e28141d..f87a98150d 100644 --- a/lib/bundler/man/bundle.1 +++ b/lib/bundler/man/bundle.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE" "1" "July 2025" "" +.TH "BUNDLE" "1" "August 2025" "" .SH "NAME" \fBbundle\fR \- Ruby Dependency Management .SH "SYNOPSIS" diff --git a/lib/bundler/man/gemfile.5 b/lib/bundler/man/gemfile.5 index c926e1ff2d..cd04d3d198 100644 --- a/lib/bundler/man/gemfile.5 +++ b/lib/bundler/man/gemfile.5 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "GEMFILE" "5" "July 2025" "" +.TH "GEMFILE" "5" "August 2025" "" .SH "NAME" \fBGemfile\fR \- A format for describing gem dependencies for Ruby programs .SH "SYNOPSIS" diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index fba9badec7..1dbf565d46 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -165,7 +165,7 @@ module Bundler PubGrub::VersionConstraint.new(package, range: range) end - def versions_for(package, range=VersionRange.any) + def versions_for(package, range = VersionRange.any) range.select_versions(@sorted_versions[package]) end diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb index 8cf3b56b83..fedf44b0e6 100644 --- a/lib/bundler/rubygems_ext.rb +++ b/lib/bundler/rubygems_ext.rb @@ -417,7 +417,7 @@ module Gem unless Gem::NameTuple.new("a", Gem::Version.new("1"), Gem::Platform.new("x86_64-linux")).platform.is_a?(String) alias_method :initialize_with_platform, :initialize - def initialize(name, version, platform=Gem::Platform::RUBY) + def initialize(name, version, platform = Gem::Platform::RUBY) if Gem::Platform === platform initialize_with_platform(name, version, platform.to_s) else diff --git a/lib/rubygems.rb b/lib/rubygems.rb index d4e88579e8..f8f1451ee6 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -224,7 +224,7 @@ module Gem finish_resolve rs end - def self.finish_resolve(request_set=Gem::RequestSet.new) + def self.finish_resolve(request_set = Gem::RequestSet.new) request_set.import Gem::Specification.unresolved_deps.values request_set.import Gem.loaded_specs.values.map {|s| Gem::Dependency.new(s.name, s.version) } @@ -341,7 +341,7 @@ module Gem ## # The path where gem executables are to be installed. - def self.bindir(install_dir=Gem.dir) + def self.bindir(install_dir = Gem.dir) return File.join install_dir, "bin" unless install_dir.to_s == Gem.default_dir.to_s Gem.default_bindir @@ -350,7 +350,7 @@ module Gem ## # The path were rubygems plugins are to be installed. - def self.plugindir(install_dir=Gem.dir) + def self.plugindir(install_dir = Gem.dir) File.join install_dir, "plugins" end @@ -534,7 +534,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} # Note that find_files will return all files even if they are from different # versions of the same gem. See also find_latest_files - def self.find_files(glob, check_load_path=true) + def self.find_files(glob, check_load_path = true) files = [] files = find_files_from_load_path glob if check_load_path @@ -571,7 +571,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} # Unlike find_files, find_latest_files will return only files from the # latest version of a gem. - def self.find_latest_files(glob, check_load_path=true) + def self.find_latest_files(glob, check_load_path = true) files = [] files = find_files_from_load_path glob if check_load_path diff --git a/lib/rubygems/command.rb b/lib/rubygems/command.rb index 3a149ea38e..d38363f293 100644 --- a/lib/rubygems/command.rb +++ b/lib/rubygems/command.rb @@ -117,7 +117,7 @@ class Gem::Command # Unhandled arguments (gem names, files, etc.) are left in # <tt>options[:args]</tt>. - def initialize(command, summary=nil, defaults={}) + def initialize(command, summary = nil, defaults = {}) @command = command @summary = summary @program_name = "gem #{command}" diff --git a/lib/rubygems/command_manager.rb b/lib/rubygems/command_manager.rb index 15834ce4dd..8521517a24 100644 --- a/lib/rubygems/command_manager.rb +++ b/lib/rubygems/command_manager.rb @@ -118,7 +118,7 @@ class Gem::CommandManager ## # Register the Symbol +command+ as a gem command. - def register_command(command, obj=false) + def register_command(command, obj = false) @commands[command] = obj end @@ -148,7 +148,7 @@ class Gem::CommandManager ## # Run the command specified by +args+. - def run(args, build_args=nil) + def run(args, build_args = nil) process_args(args, build_args) rescue StandardError, Gem::Timeout::Error => ex if ex.respond_to?(:detailed_message) @@ -165,7 +165,7 @@ class Gem::CommandManager terminate_interaction(1) end - def process_args(args, build_args=nil) + def process_args(args, build_args = nil) if args.empty? say Gem::Command::HELP terminate_interaction 1 diff --git a/lib/rubygems/dependency.rb b/lib/rubygems/dependency.rb index d1ec9222af..1e91f493a6 100644 --- a/lib/rubygems/dependency.rb +++ b/lib/rubygems/dependency.rb @@ -217,7 +217,7 @@ class Gem::Dependency # NOTE: Unlike #matches_spec? this method does not return true when the # version is a prerelease version unless this is a prerelease dependency. - def match?(obj, version=nil, allow_prerelease=false) + def match?(obj, version = nil, allow_prerelease = false) if !version name = obj.name version = obj.version diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb index b119dca1cf..b4152e83e9 100644 --- a/lib/rubygems/dependency_installer.rb +++ b/lib/rubygems/dependency_installer.rb @@ -127,7 +127,7 @@ class Gem::DependencyInstaller # sources. Gems are sorted with newer gems preferred over older gems, and # local gems preferred over remote gems. - def find_gems_with_sources(dep, best_only=false) # :nodoc: + def find_gems_with_sources(dep, best_only = false) # :nodoc: set = Gem::AvailableSet.new if consider_local? diff --git a/lib/rubygems/dependency_list.rb b/lib/rubygems/dependency_list.rb index ad5e59e8c1..99643a426d 100644 --- a/lib/rubygems/dependency_list.rb +++ b/lib/rubygems/dependency_list.rb @@ -140,7 +140,7 @@ class Gem::DependencyList # If removing the gemspec creates breaks a currently ok dependency, then it # is NOT ok to remove the gemspec. - def ok_to_remove?(full_name, check_dev=true) + def ok_to_remove?(full_name, check_dev = true) gem_to_remove = find_name full_name # If the state is inconsistent, at least don't crash diff --git a/lib/rubygems/deprecate.rb b/lib/rubygems/deprecate.rb index a20649cbda..303b344d42 100644 --- a/lib/rubygems/deprecate.rb +++ b/lib/rubygems/deprecate.rb @@ -126,7 +126,7 @@ module Gem # telling the user of +repl+ (unless +repl+ is :none) and the # Rubygems version that it is planned to go away. - def rubygems_deprecate(name, replacement=:none, version=nil) + def rubygems_deprecate(name, replacement = :none, version = nil) class_eval do old = "_deprecated_#{name}" alias_method old, name diff --git a/lib/rubygems/errors.rb b/lib/rubygems/errors.rb index 57fb3eb120..4bbc5217e0 100644 --- a/lib/rubygems/errors.rb +++ b/lib/rubygems/errors.rb @@ -26,7 +26,7 @@ module Gem # system. Instead of rescuing from this class, make sure to rescue from the # superclass Gem::LoadError to catch all types of load errors. class MissingSpecError < Gem::LoadError - def initialize(name, requirement, extra_message=nil) + def initialize(name, requirement, extra_message = nil) @name = name @requirement = requirement @extra_message = extra_message diff --git a/lib/rubygems/exceptions.rb b/lib/rubygems/exceptions.rb index 793324b875..adf7ad6d7d 100644 --- a/lib/rubygems/exceptions.rb +++ b/lib/rubygems/exceptions.rb @@ -110,7 +110,7 @@ class Gem::SpecificGemNotFoundException < Gem::GemNotFoundException # and +version+. Any +errors+ encountered when attempting to find the gem # are also stored. - def initialize(name, version, errors=nil) + def initialize(name, version, errors = nil) super "Could not find a valid gem '#{name}' (#{version}) locally or in a repository" @name = name @@ -261,7 +261,7 @@ class Gem::UnsatisfiableDependencyError < Gem::DependencyError # Creates a new UnsatisfiableDependencyError for the unsatisfiable # Gem::Resolver::DependencyRequest +dep+ - def initialize(dep, platform_mismatch=nil) + def initialize(dep, platform_mismatch = nil) if platform_mismatch && !platform_mismatch.empty? plats = platform_mismatch.map {|x| x.platform.to_s }.sort.uniq super "Unable to resolve dependency: No match for '#{dep}' on this platform. Found: #{plats.join(", ")}" diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb index 05cd735bd9..b47996d092 100644 --- a/lib/rubygems/ext/builder.rb +++ b/lib/rubygems/ext/builder.rb @@ -11,6 +11,9 @@ require_relative "../user_interaction" class Gem::Ext::Builder include Gem::UserInteraction + class NoMakefileError < Gem::InstallError + end + attr_accessor :build_args # :nodoc: def self.class_name @@ -21,7 +24,8 @@ class Gem::Ext::Builder def self.make(dest_path, results, make_dir = Dir.pwd, sitedir = nil, targets = ["clean", "", "install"], target_rbconfig: Gem.target_rbconfig) unless File.exist? File.join(make_dir, "Makefile") - raise Gem::InstallError, "Makefile not found" + # No makefile exists, nothing to do. + raise NoMakefileError, "No Makefile found in #{make_dir}" end # try to find make program from Ruby configure arguments first diff --git a/lib/rubygems/ext/cargo_builder.rb b/lib/rubygems/ext/cargo_builder.rb index 21b50f394d..e58d0bb75c 100644 --- a/lib/rubygems/ext/cargo_builder.rb +++ b/lib/rubygems/ext/cargo_builder.rb @@ -15,7 +15,7 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder end def build(extension, dest_path, results, args = [], lib_dir = nil, cargo_dir = Dir.pwd, - target_rbconfig=Gem.target_rbconfig) + target_rbconfig = Gem.target_rbconfig) require "tempfile" require "fileutils" diff --git a/lib/rubygems/ext/cmake_builder.rb b/lib/rubygems/ext/cmake_builder.rb index 34564f668d..c7bfbb8a57 100644 --- a/lib/rubygems/ext/cmake_builder.rb +++ b/lib/rubygems/ext/cmake_builder.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true class Gem::Ext::CmakeBuilder < Gem::Ext::Builder - def self.build(extension, dest_path, results, args=[], lib_dir=nil, cmake_dir=Dir.pwd, - target_rbconfig=Gem.target_rbconfig) + def self.build(extension, dest_path, results, args = [], lib_dir = nil, cmake_dir = Dir.pwd, + target_rbconfig = Gem.target_rbconfig) if target_rbconfig.path warn "--target-rbconfig is not yet supported for CMake extensions. Ignoring" end diff --git a/lib/rubygems/ext/configure_builder.rb b/lib/rubygems/ext/configure_builder.rb index d91b1ec5e8..76c1cd8b19 100644 --- a/lib/rubygems/ext/configure_builder.rb +++ b/lib/rubygems/ext/configure_builder.rb @@ -7,8 +7,8 @@ #++ class Gem::Ext::ConfigureBuilder < Gem::Ext::Builder - def self.build(extension, dest_path, results, args=[], lib_dir=nil, configure_dir=Dir.pwd, - target_rbconfig=Gem.target_rbconfig) + def self.build(extension, dest_path, results, args = [], lib_dir = nil, configure_dir = Dir.pwd, + target_rbconfig = Gem.target_rbconfig) if target_rbconfig.path warn "--target-rbconfig is not yet supported for configure-based extensions. Ignoring" end diff --git a/lib/rubygems/ext/ext_conf_builder.rb b/lib/rubygems/ext/ext_conf_builder.rb index e652a221f8..ec2fa59412 100644 --- a/lib/rubygems/ext/ext_conf_builder.rb +++ b/lib/rubygems/ext/ext_conf_builder.rb @@ -7,8 +7,8 @@ #++ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder - def self.build(extension, dest_path, results, args=[], lib_dir=nil, extension_dir=Dir.pwd, - target_rbconfig=Gem.target_rbconfig) + def self.build(extension, dest_path, results, args = [], lib_dir = nil, extension_dir = Dir.pwd, + target_rbconfig = Gem.target_rbconfig) require "fileutils" require "tempfile" @@ -66,6 +66,10 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder end results + rescue Gem::Ext::Builder::NoMakefileError => error + results << error.message + results << "Skipping make for #{extension} as no Makefile was found." + # We are good, do not re-raise the error. ensure FileUtils.rm_rf tmp_dest if tmp_dest end diff --git a/lib/rubygems/ext/rake_builder.rb b/lib/rubygems/ext/rake_builder.rb index 8edd8d1373..0eac5a180c 100644 --- a/lib/rubygems/ext/rake_builder.rb +++ b/lib/rubygems/ext/rake_builder.rb @@ -7,8 +7,8 @@ #++ class Gem::Ext::RakeBuilder < Gem::Ext::Builder - def self.build(extension, dest_path, results, args=[], lib_dir=nil, extension_dir=Dir.pwd, - target_rbconfig=Gem.target_rbconfig) + def self.build(extension, dest_path, results, args = [], lib_dir = nil, extension_dir = Dir.pwd, + target_rbconfig = Gem.target_rbconfig) if target_rbconfig.path warn "--target-rbconfig is not yet supported for Rake extensions. Ignoring" end diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 2b3200223a..0cfe59b5bb 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -67,23 +67,6 @@ class Gem::Installer attr_reader :package class << self - # - # Changes in rubygems to lazily loading `rubygems/command` (in order to - # lazily load `optparse` as a side effect) affect bundler's custom installer - # which uses `Gem::Command` without requiring it (up until bundler 2.2.29). - # This hook is to compensate for that missing require. - # - # TODO: Remove when rubygems no longer supports running on bundler older - # than 2.2.29. - - def inherited(klass) - if klass.name == "Bundler::RubyGemsGemInstaller" - require "rubygems/command" - end - - super(klass) - end - ## # Overrides the executable format. # @@ -170,7 +153,7 @@ class Gem::Installer # process. If not set, then Gem::Command.build_args is used # :post_install_message:: Print gem post install message if true - def initialize(package, options={}) + def initialize(package, options = {}) require "fileutils" @options = options diff --git a/lib/rubygems/name_tuple.rb b/lib/rubygems/name_tuple.rb index 3f4a6fcf3d..67c6f30a3d 100644 --- a/lib/rubygems/name_tuple.rb +++ b/lib/rubygems/name_tuple.rb @@ -6,7 +6,7 @@ # wrap the data returned from the indexes. class Gem::NameTuple - def initialize(name, version, platform=Gem::Platform::RUBY) + def initialize(name, version, platform = Gem::Platform::RUBY) @name = name @version = version diff --git a/lib/rubygems/package/tar_writer.rb b/lib/rubygems/package/tar_writer.rb index 7dcb9737c0..39fed9e2af 100644 --- a/lib/rubygems/package/tar_writer.rb +++ b/lib/rubygems/package/tar_writer.rb @@ -99,7 +99,7 @@ class Gem::Package::TarWriter # Gem.source_date_epoch if not specified), and yields an IO for # writing the file to - def add_file(name, mode, mtime=nil) # :yields: io + def add_file(name, mode, mtime = nil) # :yields: io check_closed name, prefix = split_name name diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb index 355a668b39..6ed0842963 100644 --- a/lib/rubygems/remote_fetcher.rb +++ b/lib/rubygems/remote_fetcher.rb @@ -72,7 +72,7 @@ class Gem::RemoteFetcher # +headers+: A set of additional HTTP headers to be sent to the server when # fetching the gem. - def initialize(proxy=nil, dns=nil, headers={}) + def initialize(proxy = nil, dns = nil, headers = {}) require_relative "core_ext/tcpsocket_init" if Gem.configuration.ipv4_fallback_enabled require_relative "vendored_net_http" require_relative "vendor/uri/lib/uri" diff --git a/lib/rubygems/resolver.rb b/lib/rubygems/resolver.rb index 9bf5f80930..ed4cbde3ba 100644 --- a/lib/rubygems/resolver.rb +++ b/lib/rubygems/resolver.rb @@ -144,7 +144,7 @@ class Gem::Resolver [spec, activation_request] end - def requests(s, act, reqs=[]) # :nodoc: + def requests(s, act, reqs = []) # :nodoc: return reqs if @ignore_dependencies s.fetch_development_dependencies if @development diff --git a/lib/rubygems/resolver/conflict.rb b/lib/rubygems/resolver/conflict.rb index 367a36b43d..77c3add4b3 100644 --- a/lib/rubygems/resolver/conflict.rb +++ b/lib/rubygems/resolver/conflict.rb @@ -21,7 +21,7 @@ class Gem::Resolver::Conflict # Creates a new resolver conflict when +dependency+ is in conflict with an # already +activated+ specification. - def initialize(dependency, activated, failed_dep=dependency) + def initialize(dependency, activated, failed_dep = dependency) @dependency = dependency @activated = activated @failed_dep = failed_dep diff --git a/lib/rubygems/source.rb b/lib/rubygems/source.rb index 772ad04bc9..8b031e27a8 100644 --- a/lib/rubygems/source.rb +++ b/lib/rubygems/source.rb @@ -190,7 +190,7 @@ class Gem::Source # Downloads +spec+ and writes it to +dir+. See also # Gem::RemoteFetcher#download. - def download(spec, dir=Dir.pwd) + def download(spec, dir = Dir.pwd) fetcher = Gem::RemoteFetcher.fetcher fetcher.download spec, uri.to_s, dir end @@ -210,7 +210,7 @@ class Gem::Source end end - def typo_squatting?(host, distance_threshold=4) + def typo_squatting?(host, distance_threshold = 4) return if @uri.host.nil? levenshtein_distance(@uri.host, host).between? 1, distance_threshold end diff --git a/lib/rubygems/spec_fetcher.rb b/lib/rubygems/spec_fetcher.rb index 285f117b39..835dedf948 100644 --- a/lib/rubygems/spec_fetcher.rb +++ b/lib/rubygems/spec_fetcher.rb @@ -83,7 +83,7 @@ class Gem::SpecFetcher # # If +matching_platform+ is false, gems for all platforms are returned. - def search_for_dependency(dependency, matching_platform=true) + def search_for_dependency(dependency, matching_platform = true) found = {} rejected_specs = {} @@ -130,7 +130,7 @@ class Gem::SpecFetcher ## # Return all gem name tuples who's names match +obj+ - def detect(type=:complete) + def detect(type = :complete) tuples = [] list, _ = available_specs(type) @@ -150,7 +150,7 @@ class Gem::SpecFetcher # # If +matching_platform+ is false, gems for all platforms are returned. - def spec_for_dependency(dependency, matching_platform=true) + def spec_for_dependency(dependency, matching_platform = true) tuples, errors = search_for_dependency(dependency, matching_platform) specs = [] @@ -280,7 +280,7 @@ class Gem::SpecFetcher # Retrieves NameTuples from +source+ of the given +type+ (:prerelease, # etc.). If +gracefully_ignore+ is true, errors are ignored. - def tuples_for(source, type, gracefully_ignore=false) # :nodoc: + def tuples_for(source, type, gracefully_ignore = false) # :nodoc: @caches[type][source.uri] ||= source.load_specs(type).sort_by(&:name) rescue Gem::RemoteFetcher::FetchError diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 68ebbf8bc3..1d351f8aff 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -1757,7 +1757,7 @@ class Gem::Specification < Gem::BasicSpecification # # [depending_gem, dependency, [list_of_gems_that_satisfy_dependency]] - def dependent_gems(check_dev=true) + def dependent_gems(check_dev = true) out = [] Gem::Specification.each do |spec| deps = check_dev ? spec.dependencies : spec.runtime_dependencies diff --git a/lib/rubygems/text.rb b/lib/rubygems/text.rb index da0795b771..88d4ce59b4 100644 --- a/lib/rubygems/text.rb +++ b/lib/rubygems/text.rb @@ -21,7 +21,7 @@ module Gem::Text # Wraps +text+ to +wrap+ characters and optionally indents by +indent+ # characters - def format_text(text, wrap, indent=0) + def format_text(text, wrap, indent = 0) result = [] work = clean_text(text) diff --git a/lib/rubygems/user_interaction.rb b/lib/rubygems/user_interaction.rb index 0172c4ee89..5711376294 100644 --- a/lib/rubygems/user_interaction.rb +++ b/lib/rubygems/user_interaction.rb @@ -193,7 +193,7 @@ class Gem::StreamUI # then special operations (like asking for passwords) will use the TTY # commands to disable character echo. - def initialize(in_stream, out_stream, err_stream=$stderr, usetty=true) + def initialize(in_stream, out_stream, err_stream = $stderr, usetty = true) @ins = in_stream @outs = out_stream @errs = err_stream @@ -246,7 +246,7 @@ class Gem::StreamUI # to a tty, raises an exception if default is nil, otherwise returns # default. - def ask_yes_no(question, default=nil) + def ask_yes_no(question, default = nil) unless tty? if default.nil? raise Gem::OperationNotSupportedError, @@ -325,14 +325,14 @@ class Gem::StreamUI ## # Display a statement. - def say(statement="") + def say(statement = "") @outs.puts statement end ## # Display an informational alert. Will ask +question+ if it is not nil. - def alert(statement, question=nil) + def alert(statement, question = nil) @outs.puts "INFO: #{statement}" ask(question) if question end @@ -340,7 +340,7 @@ class Gem::StreamUI ## # Display a warning on stderr. Will ask +question+ if it is not nil. - def alert_warning(statement, question=nil) + def alert_warning(statement, question = nil) @errs.puts "WARNING: #{statement}" ask(question) if question end @@ -349,7 +349,7 @@ class Gem::StreamUI # Display an error message in a location expected to get error messages. # Will ask +question+ if it is not nil. - def alert_error(statement, question=nil) + def alert_error(statement, question = nil) @errs.puts "ERROR: #{statement}" ask(question) if question end diff --git a/lib/rubygems/validator.rb b/lib/rubygems/validator.rb index 57e0747eb4..eb5b513570 100644 --- a/lib/rubygems/validator.rb +++ b/lib/rubygems/validator.rb @@ -59,7 +59,7 @@ class Gem::Validator #-- # TODO needs further cleanup - def alien(gems=[]) + def alien(gems = []) errors = Hash.new {|h,k| h[k] = {} } Gem::Specification.each do |spec| diff --git a/lib/syntax_suggest/api.rb b/lib/syntax_suggest/api.rb index 46c9c8adac..0f82d8362a 100644 --- a/lib/syntax_suggest/api.rb +++ b/lib/syntax_suggest/api.rb @@ -146,11 +146,7 @@ module SyntaxSuggest def self.valid_without?(without_lines:, code_lines:) lines = code_lines - Array(without_lines).flatten - if lines.empty? - true - else - valid?(lines) - end + lines.empty? || valid?(lines) end # SyntaxSuggest.invalid? [Private] diff --git a/prism/generate-srcs.mk.rb b/prism/generate-srcs.mk.rb new file mode 100644 index 0000000000..af031ef2e4 --- /dev/null +++ b/prism/generate-srcs.mk.rb @@ -0,0 +1,17 @@ +require_relative 'templates/template' + +puts %[ +PRISM_TEMPLATES_DIR = $(PRISM_SRCDIR)/templates +PRISM_TEMPLATE = $(PRISM_TEMPLATES_DIR)/template.rb +PRISM_CONFIG = $(PRISM_SRCDIR)/config.yml +] + +Prism::Template::TEMPLATES.map do |t| + /\.(?:[ch]|rb)\z/ =~ t or next + s = t.sub(%r[\A(?:(src)|ext|include)/]) {$1 && 'prism/'} + puts %[ +main srcs: $(srcdir)/#{s} +$(srcdir)/#{s}: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/#{t}.erb +\t$(Q) $(BASERUBY) $(PRISM_TEMPLATE) #{t} $@ +] +end diff --git a/prism/srcs.mk b/prism/srcs.mk new file mode 100644 index 0000000000..aa5c0fa2b5 --- /dev/null +++ b/prism/srcs.mk @@ -0,0 +1,142 @@ +PRISM_TEMPLATES_DIR = $(PRISM_SRCDIR)/templates +PRISM_TEMPLATE = $(PRISM_TEMPLATES_DIR)/template.rb +PRISM_CONFIG = $(PRISM_SRCDIR)/config.yml + +srcs uncommon.mk: prism/.srcs.mk.time + +prism/.srcs.mk.time: +prism/$(HAVE_BASERUBY:yes=.srcs.mk.time): \ + $(PRISM_SRCDIR)/templates/template.rb \ + $(PRISM_SRCDIR)/srcs.mk.in + $(BASERUBY) $(tooldir)/generic_erb.rb -c -t$@ -o $(PRISM_SRCDIR)/srcs.mk $(PRISM_SRCDIR)/srcs.mk.in + +realclean-prism-srcs:: + $(RM) $(PRISM_SRCDIR)/srcs.mk + +realclean-srcs-local:: realclean-prism-srcs + +main srcs: $(srcdir)/prism/api_node.c +$(srcdir)/prism/api_node.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/ext/prism/api_node.c.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) ext/prism/api_node.c $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/prism/api_node.c + +main incs: $(srcdir)/prism/ast.h +$(srcdir)/prism/ast.h: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/include/prism/ast.h.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) include/prism/ast.h $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/prism/ast.h + +main incs: $(srcdir)/prism/diagnostic.h +$(srcdir)/prism/diagnostic.h: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/include/prism/diagnostic.h.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) include/prism/diagnostic.h $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/prism/diagnostic.h + +main srcs: $(srcdir)/lib/prism/compiler.rb +$(srcdir)/lib/prism/compiler.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/compiler.rb.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/compiler.rb $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/lib/prism/compiler.rb + +main srcs: $(srcdir)/lib/prism/dispatcher.rb +$(srcdir)/lib/prism/dispatcher.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/dispatcher.rb.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/dispatcher.rb $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/lib/prism/dispatcher.rb + +main srcs: $(srcdir)/lib/prism/dot_visitor.rb +$(srcdir)/lib/prism/dot_visitor.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/dot_visitor.rb.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/dot_visitor.rb $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/lib/prism/dot_visitor.rb + +main srcs: $(srcdir)/lib/prism/dsl.rb +$(srcdir)/lib/prism/dsl.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/dsl.rb.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/dsl.rb $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/lib/prism/dsl.rb + +main srcs: $(srcdir)/lib/prism/inspect_visitor.rb +$(srcdir)/lib/prism/inspect_visitor.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/inspect_visitor.rb.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/inspect_visitor.rb $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/lib/prism/inspect_visitor.rb + +main srcs: $(srcdir)/lib/prism/mutation_compiler.rb +$(srcdir)/lib/prism/mutation_compiler.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/mutation_compiler.rb.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/mutation_compiler.rb $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/lib/prism/mutation_compiler.rb + +main srcs: $(srcdir)/lib/prism/node.rb +$(srcdir)/lib/prism/node.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/node.rb.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/node.rb $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/lib/prism/node.rb + +main srcs: $(srcdir)/lib/prism/reflection.rb +$(srcdir)/lib/prism/reflection.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/reflection.rb.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/reflection.rb $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/lib/prism/reflection.rb + +main srcs: $(srcdir)/lib/prism/serialize.rb +$(srcdir)/lib/prism/serialize.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/serialize.rb.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/serialize.rb $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/lib/prism/serialize.rb + +main srcs: $(srcdir)/lib/prism/visitor.rb +$(srcdir)/lib/prism/visitor.rb: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/lib/prism/visitor.rb.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) lib/prism/visitor.rb $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/lib/prism/visitor.rb + +main srcs: $(srcdir)/prism/diagnostic.c +$(srcdir)/prism/diagnostic.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/diagnostic.c.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/diagnostic.c $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/prism/diagnostic.c + +main srcs: $(srcdir)/prism/node.c +$(srcdir)/prism/node.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/node.c.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/node.c $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/prism/node.c + +main srcs: $(srcdir)/prism/prettyprint.c +$(srcdir)/prism/prettyprint.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/prettyprint.c.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/prettyprint.c $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/prism/prettyprint.c + +main srcs: $(srcdir)/prism/serialize.c +$(srcdir)/prism/serialize.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/serialize.c.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/serialize.c $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/prism/serialize.c + +main srcs: $(srcdir)/prism/token_type.c +$(srcdir)/prism/token_type.c: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/src/token_type.c.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) src/token_type.c $@ + +realclean-prism-srcs:: + $(RM) $(srcdir)/prism/token_type.c diff --git a/prism/srcs.mk.in b/prism/srcs.mk.in new file mode 100644 index 0000000000..655de155d5 --- /dev/null +++ b/prism/srcs.mk.in @@ -0,0 +1,40 @@ +<% # -*- ruby -*- +require_relative 'templates/template' + +script = File.basename(__FILE__) +srcs = output ? File.basename(output) : script.chomp('.in') +mk = 'uncommon.mk' + +# %> +PRISM_TEMPLATES_DIR = $(PRISM_SRCDIR)/templates +PRISM_TEMPLATE = $(PRISM_TEMPLATES_DIR)/template.rb +PRISM_CONFIG = $(PRISM_SRCDIR)/config.yml + +srcs <%=%><%=mk%>: prism/.srcs.mk.time + +prism/.srcs.mk.time: +prism/$(HAVE_BASERUBY:yes=.srcs.mk.time): \ + $(PRISM_SRCDIR)/templates/template.rb \ + $(PRISM_SRCDIR)/<%=%><%=script%> + $(BASERUBY) $(tooldir)/generic_erb.rb -c -t$@ -o $(PRISM_SRCDIR)/<%=%><%=srcs%> $(PRISM_SRCDIR)/<%=%><%=script%> + +realclean-prism-srcs:: + $(RM) $(PRISM_SRCDIR)/<%=%><%=srcs%> + +realclean-srcs-local:: realclean-prism-srcs +<% Prism::Template::TEMPLATES.map do |t| + /\.(?:[ch]|rb)\z/ =~ t or next + s = '$(srcdir)/' + t.sub(%r[\A(?:(src)|ext|include)/]) {$1 && 'prism/'} + s.sub!(%r[\A\$(srcdir)/prism/], '$(PRISM_SRCDIR)/') + target = s.end_with?('.h') ? 'incs' : 'srcs' +# %> + +main <%=%><%=target%>: <%=%><%=s%> +<%=%><%=s%>: $(PRISM_CONFIG) $(PRISM_TEMPLATE) $(PRISM_TEMPLATES_DIR)/<%=%><%=t%>.erb + $(Q) $(BASERUBY) $(PRISM_TEMPLATE) <%=%><%=t%> $@ + +realclean-prism-srcs:: + $(RM) <%=%><%=s%> +<% +end +# %> @@ -716,12 +716,15 @@ rb_func_proc_dup(VALUE src_obj) VALUE proc_obj = TypedData_Make_Struct(rb_obj_class(src_obj), cfunc_proc_t, &proc_data_type, proc); memcpy(&proc->basic, src_proc, sizeof(rb_proc_t)); + RB_OBJ_WRITTEN(proc_obj, Qundef, proc->basic.block.as.captured.self); + RB_OBJ_WRITTEN(proc_obj, Qundef, proc->basic.block.as.captured.code.val); + const VALUE *src_ep = src_proc->block.as.captured.ep; VALUE *ep = *(VALUE **)&proc->basic.block.as.captured.ep = proc->env + VM_ENV_DATA_SIZE - 1; - ep[VM_ENV_DATA_INDEX_FLAGS] = src_proc->block.as.captured.ep[VM_ENV_DATA_INDEX_FLAGS]; - ep[VM_ENV_DATA_INDEX_ME_CREF] = src_proc->block.as.captured.ep[VM_ENV_DATA_INDEX_ME_CREF]; - ep[VM_ENV_DATA_INDEX_SPECVAL] = src_proc->block.as.captured.ep[VM_ENV_DATA_INDEX_SPECVAL]; - ep[VM_ENV_DATA_INDEX_ENV] = src_proc->block.as.captured.ep[VM_ENV_DATA_INDEX_ENV]; + ep[VM_ENV_DATA_INDEX_FLAGS] = src_ep[VM_ENV_DATA_INDEX_FLAGS]; + ep[VM_ENV_DATA_INDEX_ME_CREF] = src_ep[VM_ENV_DATA_INDEX_ME_CREF]; + ep[VM_ENV_DATA_INDEX_SPECVAL] = src_ep[VM_ENV_DATA_INDEX_SPECVAL]; + RB_OBJ_WRITE(proc_obj, &ep[VM_ENV_DATA_INDEX_ENV], src_ep[VM_ENV_DATA_INDEX_ENV]); return proc_obj; } @@ -142,18 +142,21 @@ static const rb_random_interface_t random_mt_if = { }; static rb_random_mt_t * -rand_mt_start(rb_random_mt_t *r) +rand_mt_start(rb_random_mt_t *r, VALUE obj) { if (!genrand_initialized(&r->mt)) { r->base.seed = rand_init(&random_mt_if, &r->base, random_seed(Qundef)); + if (obj) { + RB_OBJ_WRITTEN(obj, Qundef, r->base.seed); + } } return r; } static rb_random_t * -rand_start(rb_random_mt_t *r) +rand_start(rb_random_mt_t *r, VALUE obj) { - return &rand_mt_start(r)->base; + return &rand_mt_start(r, obj)->base; } static rb_ractor_local_key_t default_rand_key; @@ -192,7 +195,13 @@ default_rand(void) static rb_random_mt_t * default_mt(void) { - return rand_mt_start(default_rand()); + return rand_mt_start(default_rand(), Qfalse); +} + +static rb_random_t * +default_rand_start(void) +{ + return &default_mt()->base; } unsigned int @@ -293,7 +302,7 @@ get_rnd(VALUE obj) rb_random_t *ptr; TypedData_Get_Struct(obj, rb_random_t, &rb_random_data_type, ptr); if (RTYPEDDATA_TYPE(obj) == &random_mt_type) - return rand_start((rb_random_mt_t *)ptr); + return rand_start((rb_random_mt_t *)ptr, obj); return ptr; } @@ -309,11 +318,11 @@ static rb_random_t * try_get_rnd(VALUE obj) { if (obj == rb_cRandom) { - return rand_start(default_rand()); + return default_rand_start(); } if (!rb_typeddata_is_kind_of(obj, &rb_random_data_type)) return NULL; if (RTYPEDDATA_TYPE(obj) == &random_mt_type) - return rand_start(DATA_PTR(obj)); + return rand_start(DATA_PTR(obj), obj); rb_random_t *rnd = DATA_PTR(obj); if (!rnd) { rb_raise(rb_eArgError, "uninitialized random: %s", @@ -829,6 +838,7 @@ rand_mt_copy(VALUE obj, VALUE orig) mt = &rnd1->mt; *rnd1 = *rnd2; + RB_OBJ_WRITTEN(obj, Qundef, rnd1->base.seed); mt->next = mt->state + numberof(mt->state) - mt->left + 1; return obj; } @@ -916,7 +926,7 @@ rand_mt_load(VALUE obj, VALUE dump) } mt->left = (unsigned int)x; mt->next = mt->state + numberof(mt->state) - x + 1; - rnd->base.seed = rb_to_int(seed); + RB_OBJ_WRITE(obj, &rnd->base.seed, rb_to_int(seed)); return obj; } @@ -975,7 +985,7 @@ static VALUE rb_f_srand(int argc, VALUE *argv, VALUE obj) { VALUE seed, old; - rb_random_mt_t *r = rand_mt_start(default_rand()); + rb_random_mt_t *r = default_mt(); if (rb_check_arity(argc, 0, 1) == 0) { seed = random_seed(obj); @@ -1337,7 +1347,7 @@ rb_random_bytes(VALUE obj, long n) static VALUE random_s_bytes(VALUE obj, VALUE len) { - rb_random_t *rnd = rand_start(default_rand()); + rb_random_t *rnd = default_rand_start(); return rand_bytes(&random_mt_if, rnd, NUM2LONG(rb_to_int(len))); } @@ -1359,7 +1369,7 @@ random_s_bytes(VALUE obj, VALUE len) static VALUE random_s_seed(VALUE obj) { - rb_random_mt_t *rnd = rand_mt_start(default_rand()); + rb_random_mt_t *rnd = default_mt(); return rnd->base.seed; } @@ -1689,7 +1699,7 @@ static VALUE rb_f_rand(int argc, VALUE *argv, VALUE obj) { VALUE vmax; - rb_random_t *rnd = rand_start(default_rand()); + rb_random_t *rnd = default_rand_start(); if (rb_check_arity(argc, 0, 1) && !NIL_P(vmax = argv[0])) { VALUE v = rand_range(obj, rnd, vmax); @@ -1716,7 +1726,7 @@ rb_f_rand(int argc, VALUE *argv, VALUE obj) static VALUE random_s_rand(int argc, VALUE *argv, VALUE obj) { - VALUE v = rand_random(argc, argv, Qnil, rand_start(default_rand())); + VALUE v = rand_random(argc, argv, Qnil, default_rand_start()); check_random_number(v, argv); return v; } @@ -47,6 +47,7 @@ static VALUE r_cover_p(VALUE, VALUE, VALUE, VALUE); static void range_init(VALUE range, VALUE beg, VALUE end, VALUE exclude_end) { + // Changing this condition has implications for JITs. If you do, please let maintainers know. if ((!FIXNUM_P(beg) || !FIXNUM_P(end)) && !NIL_P(beg) && !NIL_P(end)) { VALUE v; @@ -290,11 +290,6 @@ rb_memsearch(const void *x0, long m, const void *y0, long n, rb_encoding *enc) #define KCODE_FIXED FL_USER4 -#define ARG_REG_OPTION_MASK \ - (ONIG_OPTION_IGNORECASE|ONIG_OPTION_MULTILINE|ONIG_OPTION_EXTEND) -#define ARG_ENCODING_FIXED 16 -#define ARG_ENCODING_NONE 32 - static int char_to_option(int c) { @@ -369,7 +369,7 @@ RUBY_FUNC_EXPORTED shape_id_t rb_obj_shape_id(VALUE obj) { if (RB_SPECIAL_CONST_P(obj)) { - return SPECIAL_CONST_SHAPE_ID; + rb_bug("rb_obj_shape_id: called on a special constant"); } if (BUILTIN_TYPE(obj) == T_CLASS || BUILTIN_TYPE(obj) == T_MODULE) { @@ -1180,6 +1180,7 @@ rb_shape_copy_complex_ivars(VALUE dest, VALUE obj, shape_id_t src_shape_id, st_t st_delete(table, &id, NULL); } rb_obj_init_too_complex(dest, table); + rb_gc_writebarrier_remember(dest); } size_t @@ -1424,6 +1425,9 @@ rb_shape_parent(VALUE self) static VALUE rb_shape_debug_shape(VALUE self, VALUE obj) { + if (RB_SPECIAL_CONST_P(obj)) { + rb_raise(rb_eArgError, "Can't get shape of special constant"); + } return shape_id_t_to_rb_cShape(rb_obj_shape_id(obj)); } diff --git a/spec/bundler/commands/list_spec.rb b/spec/bundler/commands/list_spec.rb index cc0db9169d..c890646a81 100644 --- a/spec/bundler/commands/list_spec.rb +++ b/spec/bundler/commands/list_spec.rb @@ -1,6 +1,28 @@ # frozen_string_literal: true +require "json" + RSpec.describe "bundle list" do + def find_gem_name(json:, name:) + parse_json(json)["gems"].detect {|h| h["name"] == name } + end + + def parse_json(json) + JSON.parse(json) + end + + context "in verbose mode" do + it "logs the actual flags passed to the command" do + install_gemfile <<-G + source "https://gem.repo1" + G + + bundle "list --verbose" + + expect(out).to include("Running `bundle list --verbose`") + end + end + context "with name-only and paths option" do it "raises an error" do bundle "list --name-only --paths", raise_on_error: false @@ -17,6 +39,20 @@ RSpec.describe "bundle list" do end end + context "with invalid format option" do + before do + install_gemfile <<-G + source "https://gem.repo1" + G + end + + it "raises an error" do + bundle "list --format=nope", raise_on_error: false + + expect(err).to eq "Unknown option`--format=nope`. Supported formats: `json`" + end + end + describe "with without-group option" do before do install_gemfile <<-G @@ -36,6 +72,17 @@ RSpec.describe "bundle list" do expect(out).to include(" * rails (2.3.2)") expect(out).not_to include(" * rspec (1.2.7)") end + + it "prints the gems not in the specified group with json" do + bundle "list --without-group test --format=json" + + gem = find_gem_name(json: out, name: "myrack") + expect(gem["version"]).to eq("1.0.0") + gem = find_gem_name(json: out, name: "rails") + expect(gem["version"]).to eq("2.3.2") + gem = find_gem_name(json: out, name: "rspec") + expect(gem).to be_nil + end end context "when group is not found" do @@ -54,6 +101,17 @@ RSpec.describe "bundle list" do expect(out).not_to include(" * rails (2.3.2)") expect(out).not_to include(" * rspec (1.2.7)") end + + it "prints the gems not in the specified groups with json" do + bundle "list --without-group test production --format=json" + + gem = find_gem_name(json: out, name: "myrack") + expect(gem["version"]).to eq("1.0.0") + gem = find_gem_name(json: out, name: "rails") + expect(gem).to be_nil + gem = find_gem_name(json: out, name: "rspec") + expect(gem).to be_nil + end end end @@ -75,6 +133,15 @@ RSpec.describe "bundle list" do expect(out).to include(" * myrack (1.0.0)") expect(out).not_to include(" * rspec (1.2.7)") end + + it "prints the gems in the specified group with json" do + bundle "list --only-group default --format=json" + + gem = find_gem_name(json: out, name: "myrack") + expect(gem["version"]).to eq("1.0.0") + gem = find_gem_name(json: out, name: "rspec") + expect(gem).to be_nil + end end context "when group is not found" do @@ -93,6 +160,17 @@ RSpec.describe "bundle list" do expect(out).to include(" * rails (2.3.2)") expect(out).not_to include(" * rspec (1.2.7)") end + + it "prints the gems in the specified groups with json" do + bundle "list --only-group default production --format=json" + + gem = find_gem_name(json: out, name: "myrack") + expect(gem["version"]).to eq("1.0.0") + gem = find_gem_name(json: out, name: "rails") + expect(gem["version"]).to eq("2.3.2") + gem = find_gem_name(json: out, name: "rspec") + expect(gem).to be_nil + end end end @@ -112,6 +190,15 @@ RSpec.describe "bundle list" do expect(out).to include("myrack") expect(out).to include("rspec") end + + it "prints only the name of the gems in the bundle with json" do + bundle "list --name-only --format=json" + + gem = find_gem_name(json: out, name: "myrack") + expect(gem.keys).to eq(["name"]) + gem = find_gem_name(json: out, name: "rspec") + expect(gem.keys).to eq(["name"]) + end end context "with paths option" do @@ -146,6 +233,27 @@ RSpec.describe "bundle list" do expect(out).to match(%r{.*\/git_test\-\w}) expect(out).to match(%r{.*\/gemspec_test}) end + + it "prints the path of each gem in the bundle with json" do + bundle "list --paths --format=json" + + gem = find_gem_name(json: out, name: "rails") + expect(gem["path"]).to match(%r{.*\/rails\-2\.3\.2}) + expect(gem["git_version"]).to be_nil + + gem = find_gem_name(json: out, name: "myrack") + expect(gem["path"]).to match(%r{.*\/myrack\-1\.2}) + expect(gem["git_version"]).to be_nil + + gem = find_gem_name(json: out, name: "git_test") + expect(gem["path"]).to match(%r{.*\/git_test\-\w}) + expect(gem["git_version"]).to be_truthy + expect(gem["git_version"].strip).to eq(gem["git_version"]) + + gem = find_gem_name(json: out, name: "gemspec_test") + expect(gem["path"]).to match(%r{.*\/gemspec_test}) + expect(gem["git_version"]).to be_nil + end end context "when no gems are in the gemfile" do @@ -159,6 +267,11 @@ RSpec.describe "bundle list" do bundle "list" expect(out).to include("No gems in the Gemfile") end + + it "prints empty json" do + bundle "list --format=json" + expect(parse_json(out)["gems"]).to eq([]) + end end context "without options" do @@ -175,6 +288,13 @@ RSpec.describe "bundle list" do bundle "list" expect(out).to include(" * myrack (1.0.0)") end + + it "lists gems installed in the bundle with json" do + bundle "list --format=json" + + gem = find_gem_name(json: out, name: "myrack") + expect(gem["version"]).to eq("1.0.0") + end end context "when using the ls alias" do diff --git a/spec/bundler/commands/show_spec.rb b/spec/bundler/commands/show_spec.rb index 82ec6e51f2..ba903ac495 100644 --- a/spec/bundler/commands/show_spec.rb +++ b/spec/bundler/commands/show_spec.rb @@ -3,8 +3,10 @@ RSpec.describe "bundle show" do context "with a standard Gemfile" do before :each do + build_repo2 + install_gemfile <<-G - source "https://gem.repo1" + source "https://gem.repo2" gem "rails" G end @@ -86,6 +88,24 @@ RSpec.describe "bundle show" do \tStatus: Up to date MSG end + + it "includes up to date status in summary of gems" do + update_repo2 do + build_gem "rails", "3.0.0" + end + + bundle "show --verbose" + + expect(out).to include <<~MSG + * rails (2.3.2) + \tSummary: This is just a fake gem for testing + \tHomepage: http://example.com + \tStatus: Outdated - 2.3.2 < 3.0.0 + MSG + + # check lockfile is not accidentally updated + expect(lockfile).to include("actionmailer (2.3.2)") + end end context "with a git repo in the Gemfile" do @@ -219,6 +239,6 @@ RSpec.describe "bundle show" do end end -RSpec.describe "bundle show", bundler: "4" do +RSpec.describe "bundle show", bundler: "5" do pending "shows a friendly error about the command removal" end diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb index 22bb1662e6..7702c72397 100644 --- a/spec/bundler/commands/update_spec.rb +++ b/spec/bundler/commands/update_spec.rb @@ -445,6 +445,49 @@ RSpec.describe "bundle update" do expect(out).to include("Installing sneakers 2.11.0").and include("Installing rake 13.0.6") end + it "downgrades indirect dependencies if required to fulfill an explicit upgrade request" do + build_repo4 do + build_gem "rbs", "3.6.1" + build_gem "rbs", "3.9.4" + + build_gem "solargraph", "0.56.0" do |s| + s.add_dependency "rbs", "~> 3.3" + end + + build_gem "solargraph", "0.56.2" do |s| + s.add_dependency "rbs", "~> 3.6.1" + end + end + + gemfile <<~G + source "https://gem.repo4" + + gem 'solargraph', '~> 0.56.0' + G + + lockfile <<~L + GEM + remote: https://gem.repo4/ + specs: + rbs (3.9.4) + solargraph (0.56.0) + rbs (~> 3.3) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + solargraph (~> 0.56.0) + + BUNDLED WITH + #{Bundler::VERSION} + L + + bundle "lock --update solargraph" + + expect(lockfile).to include("solargraph (0.56.2)") + end + it "does not downgrade direct dependencies unnecessarily" do build_repo4 do build_gem "redis", "4.8.1" @@ -1809,7 +1852,7 @@ RSpec.describe "bundle update --bundler" do system_gems "bundler-9.9.9", path: local_gem_path bundle "update --bundler=9.9.9", env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false - expect(err).to include("An update to the version of bundler itself was requested, but the lockfile can't be updated because frozen mode is set") + expect(err).to include("An update to the version of Bundler itself was requested, but the lockfile can't be updated because frozen mode is set") end end diff --git a/spec/bundler/install/gemfile/git_spec.rb b/spec/bundler/install/gemfile/git_spec.rb index cd83ad71c0..216548cf27 100644 --- a/spec/bundler/install/gemfile/git_spec.rb +++ b/spec/bundler/install/gemfile/git_spec.rb @@ -2,12 +2,8 @@ RSpec.describe "bundle install with git sources" do describe "when floating on main" do - before :each do - build_git "foo" do |s| - s.executables = "foobar" - end - - install_gemfile <<-G + let(:base_gemfile) do + <<-G source "https://gem.repo1" git "#{lib_path("foo-1.0")}" do gem 'foo' @@ -15,7 +11,16 @@ RSpec.describe "bundle install with git sources" do G end + let(:install_base_gemfile) do + build_git "foo" do |s| + s.executables = "foobar" + end + + install_gemfile base_gemfile + end + it "fetches gems" do + install_base_gemfile expect(the_bundle).to include_gems("foo 1.0") run <<-RUBY @@ -26,17 +31,57 @@ RSpec.describe "bundle install with git sources" do expect(out).to eq("WIN") end + it "does not (yet?) enforce CHECKSUMS" do + build_git "foo" + revision = revision_for(lib_path("foo-1.0")) + + bundle "config set lockfile_checksums true" + gemfile base_gemfile + + lockfile <<~L + GIT + remote: #{lib_path("foo-1.0")} + revision: #{revision} + specs: + foo (1.0) + + GEM + remote: https://gem.repo1/ + specs: + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + foo! + + CHECKSUMS + foo (1.0) + + BUNDLED WITH + #{Bundler::VERSION} + L + + bundle "config set frozen true" + + bundle "install" + expect(the_bundle).to include_gems("foo 1.0") + end + it "caches the git repo" do + install_base_gemfile expect(Dir["#{default_bundle_path}/cache/bundler/git/foo-1.0-*"]).to have_attributes size: 1 end it "does not write to cache on bundler/setup" do + install_base_gemfile FileUtils.rm_r(default_cache_path) ruby "require 'bundler/setup'" expect(default_cache_path).not_to exist end it "caches the git repo globally and properly uses the cached repo on the next invocation" do + install_base_gemfile pristine_system_gems bundle "config set global_gem_cache true" bundle :install @@ -48,6 +93,7 @@ RSpec.describe "bundle install with git sources" do end it "caches the evaluated gemspec" do + install_base_gemfile git = update_git "foo" do |s| s.executables = ["foobar"] # we added this the first time, so keep it now s.files = ["bin/foobar"] # updating git nukes the files list @@ -66,6 +112,7 @@ RSpec.describe "bundle install with git sources" do end it "does not update the git source implicitly" do + install_base_gemfile update_git "foo" install_gemfile bundled_app2("Gemfile"), <<-G, dir: bundled_app2 @@ -84,6 +131,7 @@ RSpec.describe "bundle install with git sources" do end it "sets up git gem executables on the path" do + install_base_gemfile bundle "exec foobar" expect(out).to eq("1.0") end @@ -136,7 +184,7 @@ RSpec.describe "bundle install with git sources" do it "still works after moving the application directory" do bundle "config set --local path vendor/bundle" - bundle "install" + install_base_gemfile FileUtils.mv bundled_app, tmp("bundled_app.bck") @@ -145,7 +193,7 @@ RSpec.describe "bundle install with git sources" do it "can still install after moving the application directory" do bundle "config set --local path vendor/bundle" - bundle "install" + install_base_gemfile FileUtils.mv bundled_app, tmp("bundled_app.bck") diff --git a/spec/bundler/install/gemfile/specific_platform_spec.rb b/spec/bundler/install/gemfile/specific_platform_spec.rb index 71065c36f3..62540f0488 100644 --- a/spec/bundler/install/gemfile/specific_platform_spec.rb +++ b/spec/bundler/install/gemfile/specific_platform_spec.rb @@ -1432,7 +1432,7 @@ RSpec.describe "bundle install with specific platforms" do end end - it "does not fail when a platform variant is incompatible with the current ruby and another equivalent platform specific variant is part of the resolution", rubygems: ">= 3.3.21" do + it "does not fail when a platform variant is incompatible with the current ruby and another equivalent platform specific variant is part of the resolution" do build_repo4 do build_gem "nokogiri", "1.15.5" @@ -1578,7 +1578,7 @@ RSpec.describe "bundle install with specific platforms" do end end - it "adds current musl platform, when there are also gnu variants", rubygems: ">= 3.3.21" do + it "adds current musl platform, when there are also gnu variants" do build_repo4 do build_gem "rcee_precompiled", "0.5.0" do |s| s.platform = "x86_64-linux-gnu" diff --git a/spec/bundler/lock/lockfile_spec.rb b/spec/bundler/lock/lockfile_spec.rb index e1fbe6934a..6b98e0924e 100644 --- a/spec/bundler/lock/lockfile_spec.rb +++ b/spec/bundler/lock/lockfile_spec.rb @@ -1638,7 +1638,7 @@ RSpec.describe "the lockfile format" do G expect(err).to eq <<~L.strip - Your lockfile is missing a checksums entry for \"myrack_middleware\", but can't be updated because frozen mode is set + Your lockfile is missing a CHECKSUMS entry for \"myrack_middleware\", but can't be updated because frozen mode is set Run `bundle install` elsewhere and add the updated Gemfile.lock to version control. L @@ -1646,6 +1646,40 @@ RSpec.describe "the lockfile format" do expect(the_bundle).not_to include_gems "myrack_middleware 1.0" end + it "raises a clear error when frozen mode is set and lockfile has empty checksums in CHECKSUMS section, and does not install any gems" do + lockfile <<-L + GEM + remote: https://gem.repo2/ + specs: + myrack (0.9.1) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + myrack + + CHECKSUMS + myrack (0.9.1) + + BUNDLED WITH + #{Bundler::VERSION} + L + + install_gemfile <<-G, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false + source "https://gem.repo2" + gem "myrack" + G + + expect(err).to eq <<~L.strip + Your lockfile has an empty CHECKSUMS entry for \"myrack\", but can't be updated because frozen mode is set + + Run `bundle install` elsewhere and add the updated Gemfile.lock to version control. + L + + expect(the_bundle).not_to include_gems "myrack 0.9.1" + end + it "automatically fixes the lockfile when it's missing deps, they conflict with other locked deps, but conflicts are fixable" do build_repo4 do build_gem "other_dep", "0.9" diff --git a/spec/bundler/other/cli_man_pages_spec.rb b/spec/bundler/other/cli_man_pages_spec.rb index 84ffca14e6..6efd2904d6 100644 --- a/spec/bundler/other/cli_man_pages_spec.rb +++ b/spec/bundler/other/cli_man_pages_spec.rb @@ -1,49 +1,72 @@ # frozen_string_literal: true RSpec.describe "bundle commands" do - it "expects all commands to have a man page" do - Bundler::CLI.all_commands.each_key do |command_name| - next if command_name == "cli_help" + it "expects all commands to have all options and subcommands documented" do + check_commands!(Bundler::CLI) - expect(man_page(command_name)).to exist + Bundler::CLI.subcommand_classes.each_value do |klass| + check_commands!(klass) end end - it "expects all commands to have all options documented" do - Bundler::CLI.all_commands.each do |command_name, command| - next if command_name == "cli_help" + private + + def check_commands!(command_class) + command_class.commands.each do |command_name, command| + next if command.is_a?(Bundler::Thor::HiddenCommand) + + if command_class == Bundler::CLI + man_page = man_page(command_name) + expect(man_page).to exist + + check_options!(command, man_page) + else + man_page = man_page(command.ancestor_name) + expect(man_page).to exist - man_page_content = man_page(command_name).read + check_options!(command, man_page) + check_subcommand!(command_name, man_page) + end + end + end - command.options.each do |_, option| - aliases = option.aliases - formatted_aliases = aliases.sort.map {|name| "`#{name}`" }.join(", ") if aliases + def check_options!(command, man_page) + command.options.each do |_, option| + check_option!(option, man_page) + end + end - help = if option.type == :boolean - "* #{append_aliases("`#{option.switch_name}`", formatted_aliases)}:" - elsif option.enum - formatted_aliases = "`#{option.switch_name}`" if aliases.empty? && option.lazy_default - "* #{prepend_aliases(option.enum.sort.map {|enum| "`#{option.switch_name}=#{enum}`" }.join(", "), formatted_aliases)}:" - else - names = [option.switch_name, *aliases] - value = - case option.type - when :array then "<list>" - when :numeric then "<number>" - else option.name.upcase - end + def check_option!(option, man_page) + man_page_content = man_page.read - value = option.type != :numeric && option.lazy_default ? "[=#{value}]" : "=#{value}" + aliases = option.aliases + formatted_aliases = aliases.sort.map {|name| "`#{name}`" }.join(", ") if aliases - "* #{names.map {|name| "`#{name}#{value}`" }.join(", ")}:" + help = if option.type == :boolean + "* #{append_aliases("`#{option.switch_name}`", formatted_aliases)}:" + elsif option.enum + formatted_aliases = "`#{option.switch_name}`" if aliases.empty? && option.lazy_default + "* #{prepend_aliases(option.enum.sort.map {|enum| "`#{option.switch_name}=#{enum}`" }.join(", "), formatted_aliases)}:" + else + names = [option.switch_name, *aliases] + value = + case option.type + when :array then "<list>" + when :numeric then "<number>" + else option.name.upcase end - expect(man_page_content).to include(help) - end + value = option.type != :numeric && option.lazy_default ? "[=#{value}]" : "=#{value}" + + "* #{names.map {|name| "`#{name}#{value}`" }.join(", ")}:" end + + expect(man_page_content).to include(help) end - private + def check_subcommand!(name, man_page) + expect(man_page.read).to match(name) + end def append_aliases(text, aliases) return text if aliases.empty? @@ -57,6 +80,10 @@ RSpec.describe "bundle commands" do "#{aliases}, #{text}" end + def man_page_content(command_name) + man_page(command_name).read + end + def man_page(command_name) source_root.join("lib/bundler/man/bundle-#{command_name}.1.ronn") end diff --git a/spec/bundler/other/major_deprecation_spec.rb b/spec/bundler/other/major_deprecation_spec.rb index 51d490ea72..d57abe45f3 100644 --- a/spec/bundler/other/major_deprecation_spec.rb +++ b/spec/bundler/other/major_deprecation_spec.rb @@ -199,6 +199,28 @@ RSpec.describe "major deprecations" do pending "fails with a helpful error", bundler: "4" end + context "bundle cache --no-all" do + before do + install_gemfile <<-G + source "https://gem.repo1" + gem "myrack" + G + + bundle "cache --no-all", raise_on_error: false + end + + it "should print a deprecation warning" do + expect(deprecations).to include( + "The `--no-all` flag is deprecated because it relies on being " \ + "remembered across bundler invocations, which bundler will no " \ + "longer do in future versions. Instead please use `bundle config set " \ + "cache_all false`, and stop using this flag" + ) + end + + pending "fails with a helpful error", bundler: "4" + end + context "bundle cache --path" do before do install_gemfile <<-G @@ -592,7 +614,7 @@ RSpec.describe "major deprecations" do end it "prints a deprecation warning informing about its removal" do - expect(deprecations).to include("the `--outdated` flag to `bundle show` was undocumented and will be removed without replacement") + expect(deprecations).to include("the `--outdated` flag to `bundle show` will be removed in favor of `bundle show --verbose`") end pending "fails with a helpful message", bundler: "4" diff --git a/spec/bundler/quality_spec.rb b/spec/bundler/quality_spec.rb index 18d8e20030..3e5a960a96 100644 --- a/spec/bundler/quality_spec.rb +++ b/spec/bundler/quality_spec.rb @@ -251,58 +251,9 @@ RSpec.describe "The library itself" do expect(lib_code).to eq(spec_code) end - it "documents all cli command options in their associated man pages" do - commands = normalize_commands_and_options(Bundler::CLI) - cli_and_man_pages_in_sync!(commands) - - Bundler::CLI.subcommand_classes.each do |_, klass| - subcommands = normalize_commands_and_options(klass) - - cli_and_man_pages_in_sync!(subcommands) - end - end - private def each_line(filename, &block) File.readlines(filename, encoding: "UTF-8").each_with_index(&block) end - - def normalize_commands_and_options(command_class) - commands = {} - - command_class.commands.each do |command_name, command| - next if command.is_a?(Bundler::Thor::HiddenCommand) - - key = command.ancestor_name || command_name - commands[key] ||= [] - # Verify that all subcommands are documented in the main command's man page. - commands[key] << command_name unless command_class == Bundler::CLI - - command.options.each do |_, option| - commands[key] << option.switch_name - end - end - - commands - end - - def cli_and_man_pages_in_sync!(commands) - commands.each do |command_name, opts| - man_page_path = man_tracked_files.find {|f| File.basename(f) == "bundle-#{command_name}.1.ronn" } - expect(man_page_path).to_not be_nil, "The command #{command_name} has no associated man page." - - next if opts.empty? - - man_page_content = File.read(man_page_path) - opts.each do |option_name| - error_msg = <<~EOM - The command #{command_name} has no mention of the option or subcommand `#{option_name}` in its man page. - Document the `#{option_name}` in the man page to discard this error. - EOM - - expect(man_page_content).to match(option_name), error_msg - end - end - end end diff --git a/spec/bundler/resolver/platform_spec.rb b/spec/bundler/resolver/platform_spec.rb index 13f3e15282..a1d095d024 100644 --- a/spec/bundler/resolver/platform_spec.rb +++ b/spec/bundler/resolver/platform_spec.rb @@ -387,7 +387,7 @@ RSpec.describe "Resolving platform craziness" do should_resolve_as %w[thin-1.2.7-x64-mingw-ucrt] end - it "finds universal-mingw gems on x64-mingw-ucrt", rubygems: ">= 3.3.18" do + it "finds universal-mingw gems on x64-mingw-ucrt" do platform "x64-mingw-ucrt" dep "win32-api" should_resolve_as %w[win32-api-1.5.1-universal-mingw32] diff --git a/spec/bundler/runtime/inline_spec.rb b/spec/bundler/runtime/inline_spec.rb index 0467d8b14a..cffaab3579 100644 --- a/spec/bundler/runtime/inline_spec.rb +++ b/spec/bundler/runtime/inline_spec.rb @@ -590,14 +590,10 @@ RSpec.describe "bundler/inline#gemfile" do expect(err).to be_empty end - it "does not load default timeout" do + it "does not load default timeout", rubygems: ">= 3.5.0" do default_timeout_version = ruby "gem 'timeout', '< 999999'; require 'timeout'; puts Timeout::VERSION", raise_on_error: false skip "timeout isn't a default gem" if default_timeout_version.empty? - # This only works on RubyGems 3.5.0 or higher - ruby "require 'rubygems/timeout'", raise_on_error: false - skip "rubygems under test does not yet vendor timeout" unless last_command.success? - build_repo4 do build_gem "timeout", "999" end diff --git a/template/GNUmakefile.in b/template/GNUmakefile.in index 22ff1078dc..452e7cdeef 100644 --- a/template/GNUmakefile.in +++ b/template/GNUmakefile.in @@ -27,5 +27,8 @@ override UNICODE_TABLES_DEPENDENTS = \ $(UNICODE_TABLES_DATA_FILES)))),\ force,none) +# extract NMake-style include list +$(eval common_mk_includes := $(shell sed -n 's/^!include *//p' $(srcdir)/common.mk)) + -include uncommon.mk include $(srcdir)/defs/gmake.mk diff --git a/template/Makefile.in b/template/Makefile.in index 66ac10de1b..39f702b66d 100644 --- a/template/Makefile.in +++ b/template/Makefile.in @@ -350,13 +350,40 @@ $(LIBRUBY_$(LIBRUBY_WITH_EXT)): $(LIBRUBY_SO_UPDATE) PKG_CONFIG = @PKG_CONFIG@ ruby_pc = @ruby_pc@ $(ruby_pc): config.status Makefile - $(Q)./config.status --file=-:$(srcdir)/template/ruby.pc.in | \ + $(Q) \ + pkg="$(@libdirname@)/pkgconfig" prefix="$(prefix)"; \ + if [ "$(LIBRUBY_RELATIVE)" = yes ]; then \ + case "$$pkg" in "$$prefix"/?*) \ + pkg="$${pkg#$$prefix/}"; \ + prefix='$${pcfiledir}'`echo "/$${pkg}" | sed -e 's|/[^/][^/]*|/..|g'`; \ + esac; \ + fi; \ + ./config.status --file=-:$(srcdir)/template/ruby.pc.in | \ sed -e 's/\$$(\([A-Za-z_][A-Za-z0-9_]*\))/$${\1}/g' \ - -e 's|^prefix=.*|prefix=$(prefix)|' \ + -e "s|^prefix=.*|prefix=$$prefix|" \ > ruby.tmp.pc $(Q)pkg_config=${PKG_CONFIG} && PKG_CONFIG_PATH=. $${pkg_config:-:} --print-errors ruby.tmp $(Q)$(MV) -f ruby.tmp.pc $(ruby_pc) +test-pc: install-data + set -ex; \ + [ -z "$${pkg_config=$(PKG_CONFIG)}" ] && exit; \ + export PKG_CONFIG_PATH=$(DESTDIR)/$(libdir)/pkgconfig$${PKG_CONFIG_PATH:+:$$PKG_CONFIG_PATH}; \ + $${pkg_config} --exists $(ruby_pc:.pc=); \ + path=`$${pkg_config} --variable=prefix $(ruby_pc:.pc=)`; \ + if [ "$(LIBRUBY_RELATIVE)" = yes ]; then \ + test "$$path" -ef "$(DESTDIR)$(prefix)"; \ + else \ + test "$$path" = "$(prefix)"; \ + fi + +install-data: pkgconfig-data pre-install-data do-install-data post-install-data +pre-install-data:: install-prereq +do-install-data: $(PREP) pre-install-data + $(INSTRUBY) --make="$(MAKE)" $(INSTRUBY_ARGS) --install=data +post-install-data:: + @$(NULLCMD) + modular-gc-precheck: $(Q) if test -z $(modular_gc_dir); then \ echo "You must configure with --with-modular-gc to use modular GC"; \ @@ -399,8 +426,8 @@ $(MKFILES): config.status $(srcdir)/version.h $(ABI_VERSION_HDR) $(MAKE) -f conftest.mk | grep '^AUTO_REMAKE$$' >/dev/null 2>&1 || \ { echo "$@ updated, restart."; exit 1; } -uncommon.mk: $(srcdir)/common.mk $(srcdir)/depend - sed 's/{\$$([^(){}]*)[^{}]*}//g' $(srcdir)/common.mk $(srcdir)/depend > $@ +uncommon.mk: $(srcdir)/tool/prereq.status + sed -f $(srcdir)/tool/prereq.status $(srcdir)/common.mk $(common_mk_includes) > $@ .PHONY: reconfig reconfig-args = $(srcdir)/$(CONFIGURE) $(yes_silence:yes=--silent) $(configure_args) diff --git a/test/.excludes-zjit/TestRubyOptimization.rb b/test/.excludes-zjit/TestRubyOptimization.rb new file mode 100644 index 0000000000..5361ab02c7 --- /dev/null +++ b/test/.excludes-zjit/TestRubyOptimization.rb @@ -0,0 +1 @@ +exclude(:test_side_effect_in_popped_splat, 'Test fails with ZJIT due to locals invalidation') diff --git a/test/json/ractor_test.rb b/test/json/ractor_test.rb index dda34c64c0..0ebdb0e91a 100644 --- a/test/json/ractor_test.rb +++ b/test/json/ractor_test.rb @@ -42,7 +42,7 @@ class JSONInRactorTest < Test::Unit::TestCase else puts "Expected:" puts expected_json - puts "Acutual:" + puts "Actual:" puts actual_json puts exit 1 diff --git a/test/ruby/test_gc.rb b/test/ruby/test_gc.rb index 5fc9ea508c..7aba333e92 100644 --- a/test/ruby/test_gc.rb +++ b/test/ruby/test_gc.rb @@ -447,7 +447,7 @@ class TestGc < Test::Unit::TestCase end def test_singleton_method_added - assert_in_out_err([], <<-EOS, [], [], "[ruby-dev:44436]") + assert_in_out_err([], <<-EOS, [], [], "[ruby-dev:44436]", timeout: 30) class BasicObject undef singleton_method_added def singleton_method_added(mid) diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index dbf041a732..576a5f6064 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -880,21 +880,20 @@ class TestHash < Test::Unit::TestCase assert_equal(quote1, eval(quote1).inspect) assert_equal(quote2, eval(quote2).inspect) assert_equal(quote3, eval(quote3).inspect) - begin - verbose_bak, $VERBOSE = $VERBOSE, nil - enc = Encoding.default_external - Encoding.default_external = Encoding::ASCII + + EnvUtil.with_default_external(Encoding::ASCII) do utf8_ascii_hash = '{"\\u3042": 1}' assert_equal(eval(utf8_ascii_hash).inspect, utf8_ascii_hash) - Encoding.default_external = Encoding::UTF_8 + end + + EnvUtil.with_default_external(Encoding::UTF_8) do utf8_hash = "{\u3042: 1}" assert_equal(eval(utf8_hash).inspect, utf8_hash) - Encoding.default_external = Encoding::Windows_31J + end + + EnvUtil.with_default_external(Encoding::Windows_31J) do sjis_hash = "{\x87]: 1}".force_encoding('sjis') assert_equal(eval(sjis_hash).inspect, sjis_hash) - ensure - Encoding.default_external = enc - $VERBOSE = verbose_bak end end diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb index 4563308fa2..1e3e0e53b1 100644 --- a/test/ruby/test_keyword.rb +++ b/test/ruby/test_keyword.rb @@ -4033,7 +4033,7 @@ class TestKeywordArguments < Test::Unit::TestCase tap { m } GC.start tap { m } - }, bug8964 + }, bug8964, timeout: 30 assert_normal_exit %q{ prc = Proc.new {|a: []|} GC.stress = true diff --git a/test/ruby/test_m17n.rb b/test/ruby/test_m17n.rb index b0e2e9f849..9f7a3c7f4b 100644 --- a/test/ruby/test_m17n.rb +++ b/test/ruby/test_m17n.rb @@ -186,33 +186,35 @@ class TestM17N < Test::Unit::TestCase end def test_string_inspect_encoding - EnvUtil.suppress_warning do - begin - orig_int = Encoding.default_internal - orig_ext = Encoding.default_external - Encoding.default_internal = nil - [Encoding::UTF_8, Encoding::EUC_JP, Encoding::Windows_31J, Encoding::GB18030]. - each do |e| - Encoding.default_external = e - str = "\x81\x30\x81\x30".force_encoding('GB18030') - assert_equal(Encoding::GB18030 == e ? %{"#{str}"} : '"\x{81308130}"', str.inspect) - str = e("\xa1\x8f\xa1\xa1") - expected = "\"\\xA1\x8F\xA1\xA1\"".force_encoding("EUC-JP") - assert_equal(Encoding::EUC_JP == e ? expected : "\"\\xA1\\x{8FA1A1}\"", str.inspect) - str = s("\x81@") - assert_equal(Encoding::Windows_31J == e ? %{"#{str}"} : '"\x{8140}"', str.inspect) - str = "\u3042\u{10FFFD}" - assert_equal(Encoding::UTF_8 == e ? %{"#{str}"} : '"\u3042\u{10FFFD}"', str.inspect) - end - Encoding.default_external = Encoding::UTF_8 - [Encoding::UTF_16BE, Encoding::UTF_16LE, Encoding::UTF_32BE, Encoding::UTF_32LE, - Encoding::UTF8_SOFTBANK].each do |e| - str = "abc".encode(e) - assert_equal('"abc"', str.inspect) - end - ensure - Encoding.default_internal = orig_int - Encoding.default_external = orig_ext + [ + Encoding::UTF_8, + Encoding::EUC_JP, + Encoding::Windows_31J, + Encoding::GB18030, + ].each do |e| + EnvUtil.with_default_external(e) do + str = "\x81\x30\x81\x30".force_encoding('GB18030') + assert_equal(Encoding::GB18030 == e ? %{"#{str}"} : '"\x{81308130}"', str.inspect) + str = e("\xa1\x8f\xa1\xa1") + expected = "\"\\xA1\x8F\xA1\xA1\"".force_encoding("EUC-JP") + assert_equal(Encoding::EUC_JP == e ? expected : "\"\\xA1\\x{8FA1A1}\"", str.inspect) + str = s("\x81@") + assert_equal(Encoding::Windows_31J == e ? %{"#{str}"} : '"\x{8140}"', str.inspect) + str = "\u3042\u{10FFFD}" + assert_equal(Encoding::UTF_8 == e ? %{"#{str}"} : '"\u3042\u{10FFFD}"', str.inspect) + end + end + + EnvUtil.with_default_external(Encoding::UTF_8) do + [ + Encoding::UTF_16BE, + Encoding::UTF_16LE, + Encoding::UTF_32BE, + Encoding::UTF_32LE, + Encoding::UTF8_SOFTBANK + ].each do |e| + str = "abc".encode(e) + assert_equal('"abc"', str.inspect) end end end @@ -246,59 +248,43 @@ class TestM17N < Test::Unit::TestCase end def test_object_utf16_32_inspect - EnvUtil.suppress_warning do - begin - orig_int = Encoding.default_internal - orig_ext = Encoding.default_external - Encoding.default_internal = nil - Encoding.default_external = Encoding::UTF_8 - o = Object.new - [Encoding::UTF_16BE, Encoding::UTF_16LE, Encoding::UTF_32BE, Encoding::UTF_32LE].each do |e| - o.instance_eval "undef inspect;def inspect;'abc'.encode('#{e}');end" - assert_equal '[abc]', [o].inspect - end - ensure - Encoding.default_internal = orig_int - Encoding.default_external = orig_ext + EnvUtil.with_default_external(Encoding::UTF_8) do + o = Object.new + [Encoding::UTF_16BE, Encoding::UTF_16LE, Encoding::UTF_32BE, Encoding::UTF_32LE].each do |e| + o.instance_eval "undef inspect;def inspect;'abc'.encode('#{e}');end" + assert_equal '[abc]', [o].inspect end end end def test_object_inspect_external - orig_v, $VERBOSE = $VERBOSE, false - orig_int, Encoding.default_internal = Encoding.default_internal, nil - orig_ext = Encoding.default_external - omit "https://bugs.ruby-lang.org/issues/18338" o = Object.new - Encoding.default_external = Encoding::UTF_16BE - def o.inspect - "abc" - end - assert_nothing_raised(Encoding::CompatibilityError) { [o].inspect } + EnvUtil.with_default_external(Encoding::UTF_16BE) do + def o.inspect + "abc" + end + assert_nothing_raised(Encoding::CompatibilityError) { [o].inspect } - def o.inspect - "abc".encode(Encoding.default_external) + def o.inspect + "abc".encode(Encoding.default_external) + end + assert_equal '[abc]', [o].inspect end - assert_equal '[abc]', [o].inspect - - Encoding.default_external = Encoding::US_ASCII - def o.inspect - "\u3042" - end - assert_equal '[\u3042]', [o].inspect + EnvUtil.with_default_external(Encoding::US_ASCII) do + def o.inspect + "\u3042" + end + assert_equal '[\u3042]', [o].inspect - def o.inspect - "\x82\xa0".force_encoding(Encoding::Windows_31J) + def o.inspect + "\x82\xa0".force_encoding(Encoding::Windows_31J) + end + assert_equal '[\x{82A0}]', [o].inspect end - assert_equal '[\x{82A0}]', [o].inspect - ensure - Encoding.default_internal = orig_int - Encoding.default_external = orig_ext - $VERBOSE = orig_v end def test_str_dump diff --git a/test/ruby/test_shapes.rb b/test/ruby/test_shapes.rb index 77bba6421b..aa488e0421 100644 --- a/test/ruby/test_shapes.rb +++ b/test/ruby/test_shapes.rb @@ -1032,12 +1032,23 @@ class TestShapes < Test::Unit::TestCase assert_shape_equal(RubyVM::Shape.root_shape, RubyVM::Shape.of([])) end - def test_true_has_special_const_shape_id - assert_equal(RubyVM::Shape::SPECIAL_CONST_SHAPE_ID, RubyVM::Shape.of(true).id) - end - - def test_nil_has_special_const_shape_id - assert_equal(RubyVM::Shape::SPECIAL_CONST_SHAPE_ID, RubyVM::Shape.of(nil).id) + def test_raise_on_special_consts + assert_raise ArgumentError do + RubyVM::Shape.of(true) + end + assert_raise ArgumentError do + RubyVM::Shape.of(false) + end + assert_raise ArgumentError do + RubyVM::Shape.of(nil) + end + assert_raise ArgumentError do + RubyVM::Shape.of(0) + end + # 32-bit platforms don't have flonums or static symbols as special + # constants + # TODO(max): Add ArgumentError tests for symbol and flonum, skipping if + # RUBY_PLATFORM =~ /i686/ end def test_root_shape_transition_to_special_const_on_frozen diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb index c7e4b0c1ec..1e0f31ba7c 100644 --- a/test/ruby/test_string.rb +++ b/test/ruby/test_string.rb @@ -3251,18 +3251,12 @@ CODE assert_equal('"\\u3042\\u3044\\u3046"', S("\u3042\u3044\u3046".encode(e)).inspect) assert_equal('"ab\\"c"', S("ab\"c".encode(e)).inspect, bug4081) end - begin - verbose, $VERBOSE = $VERBOSE, nil - ext = Encoding.default_external - Encoding.default_external = "us-ascii" - $VERBOSE = verbose + + EnvUtil.with_default_external(Encoding::US_ASCII) do i = S("abc\"\\".force_encoding("utf-8")).inspect - ensure - $VERBOSE = nil - Encoding.default_external = ext - $VERBOSE = verbose + + assert_equal('"abc\\"\\\\"', i, bug4081) end - assert_equal('"abc\\"\\\\"', i, bug4081) end def test_dummy_inspect diff --git a/test/ruby/test_zjit.rb b/test/ruby/test_zjit.rb index d30af737c3..b5b5a69847 100644 --- a/test/ruby/test_zjit.rb +++ b/test/ruby/test_zjit.rb @@ -509,6 +509,116 @@ class TestZJIT < Test::Unit::TestCase }, insns: [:opt_ge], call_threshold: 2 end + def test_new_hash_empty + assert_compiles '{}', %q{ + def test = {} + test + }, insns: [:newhash] + end + + def test_new_hash_nonempty + assert_compiles '{"key" => "value", 42 => 100}', %q{ + def test + key = "key" + value = "value" + num = 42 + result = 100 + {key => value, num => result} + end + test + }, insns: [:newhash] + end + + def test_new_hash_single_key_value + assert_compiles '{"key" => "value"}', %q{ + def test = {"key" => "value"} + test + }, insns: [:newhash] + end + + def test_new_hash_with_computation + assert_compiles '{"sum" => 5, "product" => 6}', %q{ + def test(a, b) + {"sum" => a + b, "product" => a * b} + end + test(2, 3) + }, insns: [:newhash] + end + + def test_new_hash_with_user_defined_hash_method + assert_runs 'true', %q{ + class CustomKey + attr_reader :val + + def initialize(val) + @val = val + end + + def hash + @val.hash + end + + def eql?(other) + other.is_a?(CustomKey) && @val == other.val + end + end + + def test + key = CustomKey.new("key") + hash = {key => "value"} + hash[key] == "value" + end + test + } + end + + def test_new_hash_with_user_hash_method_exception + assert_runs 'RuntimeError', %q{ + class BadKey + def hash + raise "Hash method failed!" + end + end + + def test + key = BadKey.new + {key => "value"} + end + + begin + test + rescue => e + e.class + end + } + end + + def test_new_hash_with_user_eql_method_exception + assert_runs 'RuntimeError', %q{ + class BadKey + def hash + 42 + end + + def eql?(other) + raise "Eql method failed!" + end + end + + def test + key1 = BadKey.new + key2 = BadKey.new + {key1 => "value1", key2 => "value2"} + end + + begin + test + rescue => e + e.class + end + } + end + def test_opt_hash_freeze assert_compiles '{}', <<~RUBY, insns: [:opt_hash_freeze] def test = {}.freeze @@ -1135,6 +1245,14 @@ class TestZJIT < Test::Unit::TestCase }, insns: [:defined] end + def test_defined_with_method_call + assert_compiles '["method", nil]', %q{ + def test = return defined?("x".reverse(1)), defined?("x".reverse(1).reverse) + + test + }, insns: [:defined] + end + def test_defined_yield assert_compiles "nil", "defined?(yield)" assert_compiles '[nil, nil, "yield"]', %q{ @@ -1729,6 +1847,29 @@ class TestZJIT < Test::Unit::TestCase }, insns: [:concatstrings] end + def test_regexp_interpolation + assert_compiles '/123/', %q{ + def test = /#{1}#{2}#{3}/ + + test + }, insns: [:toregexp] + end + + def test_new_range_non_leaf + assert_compiles '(0/1)..1', %q{ + def jit_entry(v) = make_range_then_exit(v) + + def make_range_then_exit(v) + range = (v..1) + super rescue range # TODO(alan): replace super with side-exit intrinsic + end + + jit_entry(0) # profile + jit_entry(0) # compile + jit_entry(0/1r) # run without stub + }, call_threshold: 2 + end + private # Assert that every method call in `test_script` can be compiled by ZJIT diff --git a/test/rubygems/helper.rb b/test/rubygems/helper.rb index 2f4abff1e8..51c99a1bc5 100644 --- a/test/rubygems/helper.rb +++ b/test/rubygems/helper.rb @@ -724,7 +724,7 @@ class Gem::TestCase < Test::Unit::TestCase # # Use this with #write_file to build an installed gem. - def quick_gem(name, version="2") + def quick_gem(name, version = "2") require "rubygems/specification" spec = Gem::Specification.new do |s| @@ -1033,7 +1033,7 @@ Also, a list: # Add +spec+ to +@fetcher+ serving the data in the file +path+. # +repo+ indicates which repo to make +spec+ appear to be in. - def add_to_fetcher(spec, path=nil, repo=@gem_repo) + def add_to_fetcher(spec, path = nil, repo = @gem_repo) path ||= spec.cache_file @fetcher.data["#{@gem_repo}gems/#{spec.file_name}"] = read_binary(path) end @@ -1206,7 +1206,7 @@ Also, a list: ## # Allows the proper version of +rake+ to be used for the test. - def build_rake_in(good=true) + def build_rake_in(good = true) gem_ruby = Gem.ruby Gem.ruby = self.class.rubybin env_rake = ENV["rake"] diff --git a/test/rubygems/installer_test_case.rb b/test/rubygems/installer_test_case.rb index 7a71984320..ded205c5f5 100644 --- a/test/rubygems/installer_test_case.rb +++ b/test/rubygems/installer_test_case.rb @@ -215,7 +215,7 @@ class Gem::InstallerTestCase < Gem::TestCase ## # Creates an installer for +spec+ that will install into +gem_home+. - def util_installer(spec, gem_home, force=true) + def util_installer(spec, gem_home, force = true) Gem::Installer.at(spec.cache_file, install_dir: gem_home, force: force) diff --git a/test/rubygems/mock_gem_ui.rb b/test/rubygems/mock_gem_ui.rb index 218d4b6965..fb804c5555 100644 --- a/test/rubygems/mock_gem_ui.rb +++ b/test/rubygems/mock_gem_ui.rb @@ -77,7 +77,7 @@ class Gem::MockGemUi < Gem::StreamUI @terminated end - def terminate_interaction(status=0) + def terminate_interaction(status = 0) @terminated = true raise TermError, status if status != 0 diff --git a/test/rubygems/test_gem_ext_ext_conf_builder.rb b/test/rubygems/test_gem_ext_ext_conf_builder.rb index 218c6f3d5e..bc383e5540 100644 --- a/test/rubygems/test_gem_ext_ext_conf_builder.rb +++ b/test/rubygems/test_gem_ext_ext_conf_builder.rb @@ -15,15 +15,12 @@ class TestGemExtExtConfBuilder < Gem::TestCase end def test_class_build - if Gem.java_platform? - pend("failing on jruby") - end - if vc_windows? && !nmake_found? pend("test_class_build skipped - nmake not found") end File.open File.join(@ext, "extconf.rb"), "w" do |extconf| + extconf.puts "return if Gem.java_platform?" extconf.puts "require 'mkmf'\ncreate_makefile 'foo'" end @@ -35,20 +32,22 @@ class TestGemExtExtConfBuilder < Gem::TestCase assert_match(/^current directory:/, output[0]) assert_match(/^#{Regexp.quote(Gem.ruby)}.* extconf.rb/, output[1]) - assert_equal "creating Makefile\n", output[2] - assert_match(/^current directory:/, output[3]) - assert_contains_make_command "clean", output[4] - assert_contains_make_command "", output[7] - assert_contains_make_command "install", output[10] + + if Gem.java_platform? + assert_includes(output, "Skipping make for extconf.rb as no Makefile was found.") + else + assert_equal "creating Makefile\n", output[2] + assert_match(/^current directory:/, output[3]) + assert_contains_make_command "clean", output[4] + assert_contains_make_command "", output[7] + assert_contains_make_command "install", output[10] + end + assert_empty Dir.glob(File.join(@ext, "siteconf*.rb")) assert_empty Dir.glob(File.join(@ext, ".gem.*")) end def test_class_build_rbconfig_make_prog - if Gem.java_platform? - pend("failing on jruby") - end - configure_args do File.open File.join(@ext, "extconf.rb"), "w" do |extconf| extconf.puts "require 'mkmf'\ncreate_makefile 'foo'" @@ -72,10 +71,6 @@ class TestGemExtExtConfBuilder < Gem::TestCase env_large_make = ENV.delete "MAKE" ENV["MAKE"] = "anothermake" - if Gem.java_platform? - pend("failing on jruby") - end - configure_args "" do File.open File.join(@ext, "extconf.rb"), "w" do |extconf| extconf.puts "require 'mkmf'\ncreate_makefile 'foo'" @@ -206,11 +201,11 @@ end end def test_class_make_no_Makefile - error = assert_raise Gem::InstallError do + error = assert_raise Gem::Ext::Builder::NoMakefileError do Gem::Ext::ExtConfBuilder.make @ext, ["output"], @ext end - assert_equal "Makefile not found", error.message + assert_match(/No Makefile found/, error.message) end def configure_args(args = nil) diff --git a/test/rubygems/test_gem_remote_fetcher.rb b/test/rubygems/test_gem_remote_fetcher.rb index ca858cfda5..5c1d89fad6 100644 --- a/test/rubygems/test_gem_remote_fetcher.rb +++ b/test/rubygems/test_gem_remote_fetcher.rb @@ -592,7 +592,7 @@ class TestGemRemoteFetcher < Gem::TestCase end end - def assert_error(exception_class=Exception) + def assert_error(exception_class = Exception) got_exception = false begin diff --git a/tool/make-snapshot b/tool/make-snapshot index c7ccc468d4..2b9a5006e0 100755 --- a/tool/make-snapshot +++ b/tool/make-snapshot @@ -334,7 +334,7 @@ def package(vcs, rev, destdir, tmp = nil) FileUtils.rm(file, verbose: $VERBOSE) end - status = IO.read(File.dirname(__FILE__) + "/prereq.status") + status = File.read(File.dirname(__FILE__) + "/prereq.status") Dir.chdir(tmp) if tmp if !File.directory?(v) @@ -346,10 +346,10 @@ def package(vcs, rev, destdir, tmp = nil) File.open("#{v}/revision.h", "wb") {|f| f.puts vcs.revision_header(revision, modified) } - version ||= (versionhdr = IO.read("#{v}/version.h"))[RUBY_VERSION_PATTERN, 1] + version ||= (versionhdr = File.read("#{v}/version.h"))[RUBY_VERSION_PATTERN, 1] version ||= begin - include_ruby_versionhdr = IO.read("#{v}/include/ruby/version.h") + include_ruby_versionhdr = File.read("#{v}/include/ruby/version.h") api_major_version = include_ruby_versionhdr[/^\#define\s+RUBY_API_VERSION_MAJOR\s+([\d.]+)/, 1] api_minor_version = include_ruby_versionhdr[/^\#define\s+RUBY_API_VERSION_MINOR\s+([\d.]+)/, 1] version_teeny = versionhdr[/^\#define\s+RUBY_VERSION_TEENY\s+(\d+)/, 1] @@ -358,14 +358,14 @@ def package(vcs, rev, destdir, tmp = nil) version or return if patchlevel unless tag.empty? - versionhdr ||= IO.read("#{v}/version.h") + versionhdr ||= File.read("#{v}/version.h") patchlevel = versionhdr[/^\#define\s+RUBY_PATCHLEVEL\s+(\d+)/, 1] tag = (patchlevel ? "p#{patchlevel}" : vcs.revision_name(revision)) end elsif prerelease - versionhdr ||= IO.read("#{v}/version.h") + versionhdr ||= File.read("#{v}/version.h") versionhdr.sub!(/^\#\s*define\s+RUBY_PATCHLEVEL_STR\s+"\K.+?(?=")/, tag) or raise "no match of RUBY_PATCHLEVEL_STR to replace" - IO.write("#{v}/version.h", versionhdr) + File.write("#{v}/version.h", versionhdr) else tag ||= vcs.revision_name(revision) end @@ -430,7 +430,7 @@ def package(vcs, rev, destdir, tmp = nil) puts "cross.rb:", File.read("cross.rb").gsub(/^/, "> "), "" if $VERBOSE unless File.exist?("configure") print "creating configure..." - unless system([ENV["AUTOCONF"]]*2) + unless system(File.exist?(gen = "./autogen.sh") ? gen : [ENV["AUTOCONF"]]*2) puts $colorize.fail(" failed") return end @@ -439,11 +439,11 @@ def package(vcs, rev, destdir, tmp = nil) clean.add("autom4te.cache") clean.add("enc/unicode/data") print "creating prerequisites..." - if File.file?("common.mk") && /^prereq/ =~ commonmk = IO.read("common.mk") + if File.file?("common.mk") && /^prereq/ =~ commonmk = File.read("common.mk") puts extout = clean.add('tmp') begin - status = IO.read("tool/prereq.status") + status = File.read("tool/prereq.status") rescue Errno::ENOENT # use fallback file end @@ -456,7 +456,7 @@ def package(vcs, rev, destdir, tmp = nil) File.binwrite("#{defaults}/ruby.rb", "") miniruby = ENV['MINIRUBY'] + " -I. -I#{extout} -rcross" baseruby = ENV["BASERUBY"] - mk = (IO.read("template/Makefile.in") rescue IO.read("Makefile.in")). + mk = (File.read("template/Makefile.in") rescue File.read("Makefile.in")). gsub(/^@.*\n/, '') vars = { "EXTOUT"=>extout, @@ -480,6 +480,13 @@ def package(vcs, rev, destdir, tmp = nil) vars["UNICODE_VERSION"] = $unicode_version if $unicode_version args = vars.dup mk.gsub!(/@([A-Za-z_]\w*)@/) {args.delete($1); vars[$1] || ENV[$1]} + commonmk.gsub!(/^!(?:include \$\(srcdir\)\/(.*))?/) do + if inc = $1 and File.exist?(inc) + File.binread(inc).gsub(/^!/, '# !') + else + "#" + end + end mk << commonmk.gsub(/\{\$([^(){}]*)[^{}]*\}/, "").sub(/^revision\.tmp::$/, '\& Makefile') mk << <<-'APPEND' diff --git a/tool/prereq.status b/tool/prereq.status index 6de00c8a92..6aca615e90 100644 --- a/tool/prereq.status +++ b/tool/prereq.status @@ -41,4 +41,5 @@ s,@rubylibprefix@,,g s,@srcdir@,.,g s/@[A-Za-z][A-Za-z0-9_]*@//g -s/{\$([A-Za-z]*)}//g +s/{\$([^(){}]*)}//g +s/^!/#!/ diff --git a/tool/sync_default_gems.rb b/tool/sync_default_gems.rb index 5794edaa83..cb4e0af50b 100755 --- a/tool/sync_default_gems.rb +++ b/tool/sync_default_gems.rb @@ -330,6 +330,7 @@ module SyncDefaultGems rm_rf("test/prism/snapshots") rm("prism/extconf.rb") + `git checkout prism/srcs.mk*` when "resolv" rm_rf(%w[lib/resolv.* ext/win32/resolv test/resolv ext/win32/lib/win32/resolv.rb]) cp_r("#{upstream}/lib/resolv.rb", "lib") diff --git a/tool/update-deps b/tool/update-deps index 375986a915..c927d2483e 100755 --- a/tool/update-deps +++ b/tool/update-deps @@ -96,6 +96,15 @@ result.each {|k,v| # They can be referenced as $(top_srcdir)/filename. # % ruby -e 'def g(d) Dir.chdir(d) { Dir["**/*.{c,h,inc,dmyh}"] } end; puts((g("repo_source_dir_after_build") - g("repo_source_dir_original")).sort)' FILES_IN_SOURCE_DIRECTORY = %w[ + prism/api_node.c + prism/ast.h + prism/diagnostic.c + prism/diagnostic.h + prism/node.c + prism/prettyprint.c + prism/serialize.c + prism/token_type.c + prism/version.h ] # Files built in the build directory (except extconf.h). @@ -157,16 +166,6 @@ FILES_NEED_VPATH = %w[ enc/trans/single_byte.c enc/trans/utf8_mac.c enc/trans/utf_16_32.c - - prism/api_node.c - prism/ast.h - prism/diagnostic.c - prism/diagnostic.h - prism/node.c - prism/prettyprint.c - prism/serialize.c - prism/token_type.c - prism/version.h ] # Multiple files with same filename. diff --git a/vcpkg.json b/vcpkg.json index 16415dece1..efd356e814 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -7,5 +7,5 @@ "openssl", "zlib" ], - "builtin-baseline": "65be7019941e1401e02daaba0738cab2c8a4a355" -} + "builtin-baseline": "dd3097e305afa53f7b4312371f62058d2e665320" +}
\ No newline at end of file diff --git a/vm_callinfo.h b/vm_callinfo.h index 79ccbfa7ab..e52b2f9b1a 100644 --- a/vm_callinfo.h +++ b/vm_callinfo.h @@ -613,7 +613,7 @@ static inline bool vm_cc_check_cme(const struct rb_callcache *cc, const rb_callable_method_entry_t *cme) { bool valid; - RB_VM_LOCKING() { + RB_VM_LOCKING_NO_BARRIER() { valid = vm_cc_cme(cc) == cme || (cme->def->iseq_overload && vm_cc_cme(cc) == rb_vm_lookup_overloaded_cme(cme)); } diff --git a/vm_method.c b/vm_method.c index c1793c102c..73a431ce93 100644 --- a/vm_method.c +++ b/vm_method.c @@ -428,6 +428,8 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid) if (rb_objspace_garbage_object_p(klass)) return; RB_VM_LOCKING() { + rb_vm_barrier(); + if (LIKELY(RCLASS_SUBCLASSES_FIRST(klass) == NULL)) { // no subclasses // check only current class @@ -510,7 +512,7 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid) } rb_gccct_clear_table(Qnil); -} + } } static void @@ -1752,6 +1754,8 @@ cached_callable_method_entry(VALUE klass, ID mid) return ccs->cme; } else { + rb_vm_barrier(); + rb_managed_id_table_delete(cc_tbl, mid); rb_vm_ccs_invalidate_and_free(ccs); } diff --git a/win32/Makefile.sub b/win32/Makefile.sub index 664d54e5ff..1bdef106b3 100644 --- a/win32/Makefile.sub +++ b/win32/Makefile.sub @@ -570,7 +570,6 @@ ACTIONS_ENDGROUP = @:: ABI_VERSION_HDR = $(hdrdir)/ruby/internal/abi.h !include $(srcdir)/common.mk -!include $(srcdir)/depend !ifdef SCRIPTPROGRAMS !else if [echo>scriptbin.mk SCRIPTPROGRAMS = \] diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 9644b948d7..9c06010527 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -3104,7 +3104,7 @@ fn gen_set_ivar( // Get the iv index let shape_too_complex = comptime_receiver.shape_too_complex(); - let ivar_index = if !shape_too_complex { + let ivar_index = if !comptime_receiver.special_const_p() && !shape_too_complex { let shape_id = comptime_receiver.shape_id_of(); let mut ivar_index: u16 = 0; if unsafe { rb_shape_get_iv_index(shape_id, ivar_name, &mut ivar_index) } { @@ -3369,7 +3369,7 @@ fn gen_definedivar( // Specialize base on compile time values let comptime_receiver = jit.peek_at_self(); - if comptime_receiver.shape_too_complex() || asm.ctx.get_chain_depth() >= GET_IVAR_MAX_DEPTH { + if comptime_receiver.special_const_p() || comptime_receiver.shape_too_complex() || asm.ctx.get_chain_depth() >= GET_IVAR_MAX_DEPTH { // Fall back to calling rb_ivar_defined // Save the PC and SP because the callee may allocate @@ -4315,11 +4315,11 @@ fn gen_opt_ary_freeze( return None; } - let str = jit.get_arg(0); + let ary = jit.get_arg(0); // Push the return value onto the stack let stack_ret = asm.stack_push(Type::CArray); - asm.mov(stack_ret, str.into()); + asm.mov(stack_ret, ary.into()); Some(KeepCompiling) } @@ -4332,11 +4332,11 @@ fn gen_opt_hash_freeze( return None; } - let str = jit.get_arg(0); + let hash = jit.get_arg(0); // Push the return value onto the stack let stack_ret = asm.stack_push(Type::CHash); - asm.mov(stack_ret, str.into()); + asm.mov(stack_ret, hash.into()); Some(KeepCompiling) } diff --git a/zjit/bindgen/src/main.rs b/zjit/bindgen/src/main.rs index 77299c2657..59b7f9737e 100644 --- a/zjit/bindgen/src/main.rs +++ b/zjit/bindgen/src/main.rs @@ -259,6 +259,13 @@ fn main() { // From internal/re.h .allowlist_function("rb_reg_new_ary") + .allowlist_var("ARG_ENCODING_FIXED") + .allowlist_var("ARG_ENCODING_NONE") + + // From include/ruby/onigmo.h + .allowlist_var("ONIG_OPTION_IGNORECASE") + .allowlist_var("ONIG_OPTION_EXTEND") + .allowlist_var("ONIG_OPTION_MULTILINE") // `ruby_value_type` is a C enum and this stops it from // prefixing all the members with the name of the type diff --git a/zjit/src/backend/lir.rs b/zjit/src/backend/lir.rs index 54bef9d925..be5bda052d 100644 --- a/zjit/src/backend/lir.rs +++ b/zjit/src/backend/lir.rs @@ -147,26 +147,15 @@ impl Opnd } } - /// Return Some(Opnd) with a given num_bits if self has num_bits. - /// None if self doesn't have a num_bits field. - pub fn try_num_bits(&self, num_bits: u8) -> Option<Opnd> { - assert!(num_bits == 8 || num_bits == 16 || num_bits == 32 || num_bits == 64); - match *self { - Opnd::Reg(reg) => Some(Opnd::Reg(reg.with_num_bits(num_bits))), - Opnd::Mem(Mem { base, disp, .. }) => Some(Opnd::Mem(Mem { base, disp, num_bits })), - Opnd::VReg { idx, .. } => Some(Opnd::VReg { idx, num_bits }), - _ => None, - } - } - - /// Return Opnd with a given num_bits if self has num_bits. - /// Panic otherwise. This should be used only when you know which Opnd self is. + /// Return Opnd with a given num_bits if self has num_bits. Panic otherwise. #[track_caller] pub fn with_num_bits(&self, num_bits: u8) -> Opnd { - if let Some(opnd) = self.try_num_bits(num_bits) { - opnd - } else { - unreachable!("with_num_bits should not be used on: {self:?}"); + assert!(num_bits == 8 || num_bits == 16 || num_bits == 32 || num_bits == 64); + match *self { + Opnd::Reg(reg) => Opnd::Reg(reg.with_num_bits(num_bits)), + Opnd::Mem(Mem { base, disp, .. }) => Opnd::Mem(Mem { base, disp, num_bits }), + Opnd::VReg { idx, .. } => Opnd::VReg { idx, num_bits }, + _ => unreachable!("with_num_bits should not be used for: {self:?}"), } } @@ -1684,6 +1673,7 @@ impl Assembler { } pub fn cpop_into(&mut self, opnd: Opnd) { + assert!(matches!(opnd, Opnd::Reg(_)), "Destination of cpop_into must be a register, got: {opnd:?}"); self.push_insn(Insn::CPopInto(opnd)); } @@ -1831,6 +1821,7 @@ impl Assembler { } pub fn lea_into(&mut self, out: Opnd, opnd: Opnd) { + assert!(matches!(out, Opnd::Reg(_)), "Destination of lea_into must be a register, got: {out:?}"); self.push_insn(Insn::Lea { opnd, out }); } @@ -1856,7 +1847,7 @@ impl Assembler { } pub fn load_into(&mut self, dest: Opnd, opnd: Opnd) { - assert!(matches!(dest, Opnd::Reg(_) | Opnd::VReg{..}), "Destination of load_into must be a register"); + assert!(matches!(dest, Opnd::Reg(_)), "Destination of load_into must be a register, got: {dest:?}"); match (dest, opnd) { (Opnd::Reg(dest), Opnd::Reg(opnd)) if dest == opnd => {}, // skip if noop _ => self.push_insn(Insn::LoadInto { dest, opnd }), @@ -1882,6 +1873,7 @@ impl Assembler { } pub fn mov(&mut self, dest: Opnd, src: Opnd) { + assert!(!matches!(dest, Opnd::VReg { .. }), "Destination of mov must not be Opnd::VReg, got: {dest:?}"); self.push_insn(Insn::Mov { dest, src }); } @@ -1919,6 +1911,7 @@ impl Assembler { } pub fn store(&mut self, dest: Opnd, src: Opnd) { + assert!(!matches!(dest, Opnd::VReg { .. }), "Destination of store must not be Opnd::VReg, got: {dest:?}"); self.push_insn(Insn::Store { dest, src }); } diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index a58950ab9a..db56db0927 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -1,6 +1,6 @@ -use std::cell::Cell; +use std::cell::{Cell, RefCell}; use std::rc::Rc; -use std::ffi::{c_int, c_void}; +use std::ffi::{c_int, c_long, c_void}; use crate::asm::Label; use crate::backend::current::{Reg, ALLOC_REGS}; @@ -27,7 +27,7 @@ struct JITState { labels: Vec<Option<Target>>, /// ISEQ calls that need to be compiled later - iseq_calls: Vec<Rc<IseqCall>>, + iseq_calls: Vec<Rc<RefCell<IseqCall>>>, /// The number of bytes allocated for basic block arguments spilled onto the C stack c_stack_slots: usize, @@ -46,12 +46,8 @@ impl JITState { } /// Retrieve the output of a given instruction that has been compiled - fn get_opnd(&self, insn_id: InsnId) -> Option<lir::Opnd> { - let opnd = self.opnds[insn_id.0]; - if opnd.is_none() { - debug!("Failed to get_opnd({insn_id})"); - } - opnd + fn get_opnd(&self, insn_id: InsnId) -> lir::Opnd { + self.opnds[insn_id.0].expect(&format!("Failed to get_opnd({insn_id})")) } /// Find or create a label for a given BlockId @@ -130,13 +126,14 @@ fn gen_iseq_entry_point_body(cb: &mut CodeBlock, iseq: IseqPtr) -> Option<CodePt }; // Stub callee ISEQs for JIT-to-JIT calls - for iseq_call in jit.iseq_calls.into_iter() { + for iseq_call in jit.iseq_calls.iter() { gen_iseq_call(cb, iseq, iseq_call)?; } // Remember the block address to reuse it later let payload = get_or_create_iseq_payload(iseq); payload.status = IseqStatus::Compiled(start_ptr); + payload.iseq_calls.extend(jit.iseq_calls); append_gc_offsets(iseq, &gc_offsets); // Return a JIT code address @@ -144,19 +141,20 @@ fn gen_iseq_entry_point_body(cb: &mut CodeBlock, iseq: IseqPtr) -> Option<CodePt } /// Stub a branch for a JIT-to-JIT call -fn gen_iseq_call(cb: &mut CodeBlock, caller_iseq: IseqPtr, iseq_call: Rc<IseqCall>) -> Option<()> { +fn gen_iseq_call(cb: &mut CodeBlock, caller_iseq: IseqPtr, iseq_call: &Rc<RefCell<IseqCall>>) -> Option<()> { // Compile a function stub let Some(stub_ptr) = gen_function_stub(cb, iseq_call.clone()) else { // Failed to compile the stub. Bail out of compiling the caller ISEQ. debug!("Failed to compile iseq: could not compile stub: {} -> {}", - iseq_get_location(caller_iseq, 0), iseq_get_location(iseq_call.iseq, 0)); + iseq_get_location(caller_iseq, 0), iseq_get_location(iseq_call.borrow().iseq, 0)); return None; }; // Update the JIT-to-JIT call to call the stub let stub_addr = stub_ptr.raw_ptr(cb); - iseq_call.regenerate(cb, |asm| { - asm_comment!(asm, "call function stub: {}", iseq_get_location(iseq_call.iseq, 0)); + let iseq = iseq_call.borrow().iseq; + iseq_call.borrow_mut().regenerate(cb, |asm| { + asm_comment!(asm, "call function stub: {}", iseq_get_location(iseq, 0)); asm.ccall(stub_addr, vec![]); }); Some(()) @@ -209,7 +207,7 @@ fn gen_entry(cb: &mut CodeBlock, iseq: IseqPtr, function: &Function, function_pt } /// Compile an ISEQ into machine code -fn gen_iseq(cb: &mut CodeBlock, iseq: IseqPtr) -> Option<(CodePtr, Vec<Rc<IseqCall>>)> { +fn gen_iseq(cb: &mut CodeBlock, iseq: IseqPtr) -> Option<(CodePtr, Vec<Rc<RefCell<IseqCall>>>)> { // Return an existing pointer if it's already compiled let payload = get_or_create_iseq_payload(iseq); match payload.status { @@ -231,6 +229,7 @@ fn gen_iseq(cb: &mut CodeBlock, iseq: IseqPtr) -> Option<(CodePtr, Vec<Rc<IseqCa let result = gen_function(cb, iseq, &function); if let Some((start_ptr, gc_offsets, jit)) = result { payload.status = IseqStatus::Compiled(start_ptr); + payload.iseq_calls.extend(jit.iseq_calls.clone()); append_gc_offsets(iseq, &gc_offsets); Some((start_ptr, jit.iseq_calls)) } else { @@ -313,18 +312,24 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio // Convert InsnId to lir::Opnd macro_rules! opnd { ($insn_id:ident) => { - jit.get_opnd($insn_id.clone())? + jit.get_opnd($insn_id.clone()) }; } macro_rules! opnds { ($insn_ids:ident) => { { - Option::from_iter($insn_ids.iter().map(|insn_id| jit.get_opnd(*insn_id)))? + $insn_ids.iter().map(|insn_id| jit.get_opnd(*insn_id)).collect::<Vec<_>>() } }; } + macro_rules! no_output { + ($call:expr) => { + { let () = $call; return Some(()); } + }; + } + if !matches!(*insn, Insn::Snapshot { .. }) { asm_comment!(asm, "Insn: {insn_id} {insn}"); } @@ -332,55 +337,63 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio let out_opnd = match insn { Insn::Const { val: Const::Value(val) } => gen_const(*val), Insn::NewArray { elements, state } => gen_new_array(asm, opnds!(elements), &function.frame_state(*state)), - Insn::NewRange { low, high, flag, state } => gen_new_range(asm, opnd!(low), opnd!(high), *flag, &function.frame_state(*state)), + Insn::NewHash { elements, state } => gen_new_hash(jit, asm, elements, &function.frame_state(*state)), + Insn::NewRange { low, high, flag, state } => gen_new_range(jit, asm, opnd!(low), opnd!(high), *flag, &function.frame_state(*state)), Insn::ArrayDup { val, state } => gen_array_dup(asm, opnd!(val), &function.frame_state(*state)), Insn::StringCopy { val, chilled, state } => gen_string_copy(asm, opnd!(val), *chilled, &function.frame_state(*state)), - Insn::StringConcat { strings, state } => gen_string_concat(jit, asm, opnds!(strings), &function.frame_state(*state))?, - Insn::StringIntern { val, state } => gen_intern(asm, opnd!(val), &function.frame_state(*state))?, + // concatstrings shouldn't have 0 strings + // If it happens we abort the compilation for now + Insn::StringConcat { strings, .. } if strings.is_empty() => return None, + Insn::StringConcat { strings, state } => gen_string_concat(jit, asm, opnds!(strings), &function.frame_state(*state)), + Insn::StringIntern { val, state } => gen_intern(asm, opnd!(val), &function.frame_state(*state)), + Insn::ToRegexp { opt, values, state } => gen_toregexp(jit, asm, *opt, opnds!(values), &function.frame_state(*state)), Insn::Param { idx } => unreachable!("block.insns should not have Insn::Param({idx})"), Insn::Snapshot { .. } => return Some(()), // we don't need to do anything for this instruction at the moment - Insn::Jump(branch) => return gen_jump(jit, asm, branch), - Insn::IfTrue { val, target } => return gen_if_true(jit, asm, opnd!(val), target), - Insn::IfFalse { val, target } => return gen_if_false(jit, asm, opnd!(val), target), - Insn::SendWithoutBlock { cd, state, self_val, args, .. } => gen_send_without_block(jit, asm, *cd, &function.frame_state(*state), opnd!(self_val), opnds!(args))?, + Insn::Jump(branch) => no_output!(gen_jump(jit, asm, branch)), + Insn::IfTrue { val, target } => no_output!(gen_if_true(jit, asm, opnd!(val), target)), + Insn::IfFalse { val, target } => no_output!(gen_if_false(jit, asm, opnd!(val), target)), + Insn::SendWithoutBlock { cd, state, self_val, args, .. } => gen_send_without_block(jit, asm, *cd, &function.frame_state(*state), opnd!(self_val), opnds!(args)), // Give up SendWithoutBlockDirect for 6+ args since asm.ccall() doesn't support it. Insn::SendWithoutBlockDirect { cd, state, self_val, args, .. } if args.len() + 1 > C_ARG_OPNDS.len() => // +1 for self - gen_send_without_block(jit, asm, *cd, &function.frame_state(*state), opnd!(self_val), opnds!(args))?, - Insn::SendWithoutBlockDirect { cme, iseq, self_val, args, state, .. } => gen_send_without_block_direct(cb, jit, asm, *cme, *iseq, opnd!(self_val), opnds!(args), &function.frame_state(*state))?, - Insn::InvokeBuiltin { bf, args, state, .. } => gen_invokebuiltin(jit, asm, &function.frame_state(*state), bf, opnds!(args))?, - Insn::Return { val } => return Some(gen_return(asm, opnd!(val))?), - Insn::FixnumAdd { left, right, state } => gen_fixnum_add(jit, asm, opnd!(left), opnd!(right), &function.frame_state(*state))?, - Insn::FixnumSub { left, right, state } => gen_fixnum_sub(jit, asm, opnd!(left), opnd!(right), &function.frame_state(*state))?, - Insn::FixnumMult { left, right, state } => gen_fixnum_mult(jit, asm, opnd!(left), opnd!(right), &function.frame_state(*state))?, - Insn::FixnumEq { left, right } => gen_fixnum_eq(asm, opnd!(left), opnd!(right))?, - Insn::FixnumNeq { left, right } => gen_fixnum_neq(asm, opnd!(left), opnd!(right))?, - Insn::FixnumLt { left, right } => gen_fixnum_lt(asm, opnd!(left), opnd!(right))?, - Insn::FixnumLe { left, right } => gen_fixnum_le(asm, opnd!(left), opnd!(right))?, - Insn::FixnumGt { left, right } => gen_fixnum_gt(asm, opnd!(left), opnd!(right))?, - Insn::FixnumGe { left, right } => gen_fixnum_ge(asm, opnd!(left), opnd!(right))?, - Insn::FixnumAnd { left, right } => gen_fixnum_and(asm, opnd!(left), opnd!(right))?, - Insn::FixnumOr { left, right } => gen_fixnum_or(asm, opnd!(left), opnd!(right))?, - Insn::IsNil { val } => gen_isnil(asm, opnd!(val))?, - Insn::Test { val } => gen_test(asm, opnd!(val))?, - Insn::GuardType { val, guard_type, state } => gen_guard_type(jit, asm, opnd!(val), *guard_type, &function.frame_state(*state))?, - Insn::GuardBitEquals { val, expected, state } => gen_guard_bit_equals(jit, asm, opnd!(val), *expected, &function.frame_state(*state))?, - Insn::PatchPoint { invariant, state } => return gen_patch_point(jit, asm, invariant, &function.frame_state(*state)), - Insn::CCall { cfun, args, name: _, return_type: _, elidable: _ } => gen_ccall(asm, *cfun, opnds!(args))?, + gen_send_without_block(jit, asm, *cd, &function.frame_state(*state), opnd!(self_val), opnds!(args)), + Insn::SendWithoutBlockDirect { cme, iseq, self_val, args, state, .. } => gen_send_without_block_direct(cb, jit, asm, *cme, *iseq, opnd!(self_val), opnds!(args), &function.frame_state(*state)), + // Ensure we have enough room fit ec, self, and arguments + // TODO remove this check when we have stack args (we can use Time.new to test it) + Insn::InvokeBuiltin { bf, .. } if bf.argc + 2 > (C_ARG_OPNDS.len() as i32) => return None, + Insn::InvokeBuiltin { bf, args, state, .. } => gen_invokebuiltin(jit, asm, &function.frame_state(*state), bf, opnds!(args)), + Insn::Return { val } => no_output!(gen_return(asm, opnd!(val))), + Insn::FixnumAdd { left, right, state } => gen_fixnum_add(jit, asm, opnd!(left), opnd!(right), &function.frame_state(*state)), + Insn::FixnumSub { left, right, state } => gen_fixnum_sub(jit, asm, opnd!(left), opnd!(right), &function.frame_state(*state)), + Insn::FixnumMult { left, right, state } => gen_fixnum_mult(jit, asm, opnd!(left), opnd!(right), &function.frame_state(*state)), + Insn::FixnumEq { left, right } => gen_fixnum_eq(asm, opnd!(left), opnd!(right)), + Insn::FixnumNeq { left, right } => gen_fixnum_neq(asm, opnd!(left), opnd!(right)), + Insn::FixnumLt { left, right } => gen_fixnum_lt(asm, opnd!(left), opnd!(right)), + Insn::FixnumLe { left, right } => gen_fixnum_le(asm, opnd!(left), opnd!(right)), + Insn::FixnumGt { left, right } => gen_fixnum_gt(asm, opnd!(left), opnd!(right)), + Insn::FixnumGe { left, right } => gen_fixnum_ge(asm, opnd!(left), opnd!(right)), + Insn::FixnumAnd { left, right } => gen_fixnum_and(asm, opnd!(left), opnd!(right)), + Insn::FixnumOr { left, right } => gen_fixnum_or(asm, opnd!(left), opnd!(right)), + Insn::IsNil { val } => gen_isnil(asm, opnd!(val)), + Insn::Test { val } => gen_test(asm, opnd!(val)), + Insn::GuardType { val, guard_type, state } => gen_guard_type(jit, asm, opnd!(val), *guard_type, &function.frame_state(*state)), + Insn::GuardBitEquals { val, expected, state } => gen_guard_bit_equals(jit, asm, opnd!(val), *expected, &function.frame_state(*state)), + Insn::PatchPoint { invariant, state } => no_output!(gen_patch_point(jit, asm, invariant, &function.frame_state(*state))), + Insn::CCall { cfun, args, name: _, return_type: _, elidable: _ } => gen_ccall(asm, *cfun, opnds!(args)), Insn::GetIvar { self_val, id, state: _ } => gen_getivar(asm, opnd!(self_val), *id), - Insn::SetGlobal { id, val, state } => return gen_setglobal(jit, asm, *id, opnd!(val), &function.frame_state(*state)), + Insn::SetGlobal { id, val, state } => no_output!(gen_setglobal(jit, asm, *id, opnd!(val), &function.frame_state(*state))), Insn::GetGlobal { id, state: _ } => gen_getglobal(asm, *id), - &Insn::GetLocal { ep_offset, level } => gen_getlocal_with_ep(asm, ep_offset, level)?, - &Insn::SetLocal { val, ep_offset, level } => return gen_setlocal_with_ep(asm, jit, function, val, ep_offset, level), - Insn::GetConstantPath { ic, state } => gen_get_constant_path(jit, asm, *ic, &function.frame_state(*state))?, - Insn::SetIvar { self_val, id, val, state: _ } => return gen_setivar(asm, opnd!(self_val), *id, opnd!(val)), - Insn::SideExit { state, reason } => return gen_side_exit(jit, asm, reason, &function.frame_state(*state)), + &Insn::GetLocal { ep_offset, level } => gen_getlocal_with_ep(asm, ep_offset, level), + &Insn::SetLocal { val, ep_offset, level } => no_output!(gen_setlocal_with_ep(asm, opnd!(val), function.type_of(val), ep_offset, level)), + Insn::GetConstantPath { ic, state } => gen_get_constant_path(jit, asm, *ic, &function.frame_state(*state)), + Insn::SetIvar { self_val, id, val, state: _ } => no_output!(gen_setivar(asm, opnd!(self_val), *id, opnd!(val))), + Insn::SideExit { state, reason } => no_output!(gen_side_exit(jit, asm, reason, &function.frame_state(*state))), Insn::PutSpecialObject { value_type } => gen_putspecialobject(asm, *value_type), - Insn::AnyToString { val, str, state } => gen_anytostring(asm, opnd!(val), opnd!(str), &function.frame_state(*state))?, - Insn::Defined { op_type, obj, pushval, v, state } => gen_defined(jit, asm, *op_type, *obj, *pushval, opnd!(v), &function.frame_state(*state))?, + Insn::AnyToString { val, str, state } => gen_anytostring(asm, opnd!(val), opnd!(str), &function.frame_state(*state)), + Insn::Defined { op_type, obj, pushval, v, state } => gen_defined(jit, asm, *op_type, *obj, *pushval, opnd!(v), &function.frame_state(*state)), Insn::GetSpecialSymbol { symbol_type, state: _ } => gen_getspecial_symbol(asm, *symbol_type), Insn::GetSpecialNumber { nth, state } => gen_getspecial_number(asm, *nth, &function.frame_state(*state)), - &Insn::IncrCounter(counter) => return Some(gen_incr_counter(asm, counter)), - Insn::ObjToString { val, cd, state, .. } => gen_objtostring(jit, asm, opnd!(val), *cd, &function.frame_state(*state))?, + &Insn::IncrCounter(counter) => no_output!(gen_incr_counter(asm, counter)), + Insn::ObjToString { val, cd, state, .. } => gen_objtostring(jit, asm, opnd!(val), *cd, &function.frame_state(*state)), Insn::ArrayExtend { .. } | Insn::ArrayMax { .. } | Insn::ArrayPush { .. } @@ -388,7 +401,6 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio | Insn::FixnumDiv { .. } | Insn::FixnumMod { .. } | Insn::HashDup { .. } - | Insn::NewHash { .. } | Insn::Send { .. } | Insn::Throw { .. } | Insn::ToArray { .. } @@ -446,8 +458,8 @@ fn gen_get_ep(asm: &mut Assembler, level: u32) -> Opnd { ep_opnd } -fn gen_objtostring(jit: &mut JITState, asm: &mut Assembler, val: Opnd, cd: *const rb_call_data, state: &FrameState) -> Option<Opnd> { - gen_prepare_non_leaf_call(jit, asm, state)?; +fn gen_objtostring(jit: &mut JITState, asm: &mut Assembler, val: Opnd, cd: *const rb_call_data, state: &FrameState) -> Opnd { + gen_prepare_non_leaf_call(jit, asm, state); let iseq_opnd = Opnd::Value(jit.iseq.into()); @@ -459,12 +471,12 @@ fn gen_objtostring(jit: &mut JITState, asm: &mut Assembler, val: Opnd, cd: *cons // Need to replicate what CALL_SIMPLE_METHOD does asm_comment!(asm, "side-exit if rb_vm_objtostring returns Qundef"); asm.cmp(ret, Qundef.into()); - asm.je(side_exit(jit, state, ObjToStringFallback)?); + asm.je(side_exit(jit, state, ObjToStringFallback)); - Some(ret) + ret } -fn gen_defined(jit: &JITState, asm: &mut Assembler, op_type: usize, obj: VALUE, pushval: VALUE, tested_value: Opnd, state: &FrameState) -> Option<Opnd> { +fn gen_defined(jit: &JITState, asm: &mut Assembler, op_type: usize, obj: VALUE, pushval: VALUE, tested_value: Opnd, state: &FrameState) -> Opnd { match op_type as defined_type { DEFINED_YIELD => { // `yield` goes to the block handler stowed in the "local" iseq which is @@ -476,21 +488,21 @@ fn gen_defined(jit: &JITState, asm: &mut Assembler, op_type: usize, obj: VALUE, let block_handler = asm.load(Opnd::mem(64, lep, SIZEOF_VALUE_I32 * VM_ENV_DATA_INDEX_SPECVAL)); let pushval = asm.load(pushval.into()); asm.cmp(block_handler, VM_BLOCK_HANDLER_NONE.into()); - Some(asm.csel_e(Qnil.into(), pushval.into())) + asm.csel_e(Qnil.into(), pushval.into()) } else { - Some(Qnil.into()) + Qnil.into() } } _ => { // Save the PC and SP because the callee may allocate or call #respond_to? - gen_prepare_non_leaf_call(jit, asm, state)?; + gen_prepare_non_leaf_call(jit, asm, state); // TODO: Inline the cases for each op_type // Call vm_defined(ec, reg_cfp, op_type, obj, v) let def_result = asm_ccall!(asm, rb_vm_defined, EC, CFP, op_type.into(), obj.into(), tested_value); asm.cmp(def_result.with_num_bits(8), 0.into()); - Some(asm.csel_ne(pushval.into(), Qnil.into())) + asm.csel_ne(pushval.into(), Qnil.into()) } } } @@ -498,69 +510,64 @@ fn gen_defined(jit: &JITState, asm: &mut Assembler, op_type: usize, obj: VALUE, /// Get a local variable from a higher scope or the heap. `local_ep_offset` is in number of VALUEs. /// We generate this instruction with level=0 only when the local variable is on the heap, so we /// can't optimize the level=0 case using the SP register. -fn gen_getlocal_with_ep(asm: &mut Assembler, local_ep_offset: u32, level: u32) -> Option<lir::Opnd> { +fn gen_getlocal_with_ep(asm: &mut Assembler, local_ep_offset: u32, level: u32) -> lir::Opnd { let ep = gen_get_ep(asm, level); - let offset = -(SIZEOF_VALUE_I32 * i32::try_from(local_ep_offset).ok()?); - Some(asm.load(Opnd::mem(64, ep, offset))) + let offset = -(SIZEOF_VALUE_I32 * i32::try_from(local_ep_offset).expect(&format!("Could not convert local_ep_offset {local_ep_offset} to i32"))); + asm.load(Opnd::mem(64, ep, offset)) } /// Set a local variable from a higher scope or the heap. `local_ep_offset` is in number of VALUEs. /// We generate this instruction with level=0 only when the local variable is on the heap, so we /// can't optimize the level=0 case using the SP register. -fn gen_setlocal_with_ep(asm: &mut Assembler, jit: &JITState, function: &Function, val: InsnId, local_ep_offset: u32, level: u32) -> Option<()> { +fn gen_setlocal_with_ep(asm: &mut Assembler, val: Opnd, val_type: Type, local_ep_offset: u32, level: u32) { let ep = gen_get_ep(asm, level); // When we've proved that we're writing an immediate, // we can skip the write barrier. - if function.type_of(val).is_immediate() { - let offset = -(SIZEOF_VALUE_I32 * i32::try_from(local_ep_offset).ok()?); - asm.mov(Opnd::mem(64, ep, offset), jit.get_opnd(val)?); + if val_type.is_immediate() { + let offset = -(SIZEOF_VALUE_I32 * i32::try_from(local_ep_offset).expect(&format!("Could not convert local_ep_offset {local_ep_offset} to i32"))); + asm.mov(Opnd::mem(64, ep, offset), val); } else { // We're potentially writing a reference to an IMEMO/env object, // so take care of the write barrier with a function. - let local_index = c_int::try_from(local_ep_offset).ok().and_then(|idx| idx.checked_mul(-1))?; - asm_ccall!(asm, rb_vm_env_write, ep, local_index.into(), jit.get_opnd(val)?); + let local_index = c_int::try_from(local_ep_offset).ok().and_then(|idx| idx.checked_mul(-1)).expect(&format!("Could not turn {local_ep_offset} into a negative c_int")); + asm_ccall!(asm, rb_vm_env_write, ep, local_index.into(), val); } - Some(()) } -fn gen_get_constant_path(jit: &JITState, asm: &mut Assembler, ic: *const iseq_inline_constant_cache, state: &FrameState) -> Option<Opnd> { +fn gen_get_constant_path(jit: &JITState, asm: &mut Assembler, ic: *const iseq_inline_constant_cache, state: &FrameState) -> Opnd { unsafe extern "C" { fn rb_vm_opt_getconstant_path(ec: EcPtr, cfp: CfpPtr, ic: *const iseq_inline_constant_cache) -> VALUE; } // Anything could be called on const_missing - gen_prepare_non_leaf_call(jit, asm, state)?; + gen_prepare_non_leaf_call(jit, asm, state); - Some(asm_ccall!(asm, rb_vm_opt_getconstant_path, EC, CFP, Opnd::const_ptr(ic))) + asm_ccall!(asm, rb_vm_opt_getconstant_path, EC, CFP, Opnd::const_ptr(ic)) } -fn gen_invokebuiltin(jit: &JITState, asm: &mut Assembler, state: &FrameState, bf: &rb_builtin_function, args: Vec<Opnd>) -> Option<lir::Opnd> { - // Ensure we have enough room fit ec, self, and arguments - // TODO remove this check when we have stack args (we can use Time.new to test it) - if bf.argc + 2 > (C_ARG_OPNDS.len() as i32) { - return None; - } - +fn gen_invokebuiltin(jit: &JITState, asm: &mut Assembler, state: &FrameState, bf: &rb_builtin_function, args: Vec<Opnd>) -> lir::Opnd { + assert!(bf.argc + 2 <= C_ARG_OPNDS.len() as i32, + "gen_invokebuiltin should not be called for builtin function {} with too many arguments: {}", + unsafe { std::ffi::CStr::from_ptr(bf.name).to_str().unwrap() }, + bf.argc); // Anything can happen inside builtin functions - gen_prepare_non_leaf_call(jit, asm, state)?; + gen_prepare_non_leaf_call(jit, asm, state); let mut cargs = vec![EC]; cargs.extend(args); - let val = asm.ccall(bf.func_ptr as *const u8, cargs); - - Some(val) + asm.ccall(bf.func_ptr as *const u8, cargs) } /// Record a patch point that should be invalidated on a given invariant -fn gen_patch_point(jit: &mut JITState, asm: &mut Assembler, invariant: &Invariant, state: &FrameState) -> Option<()> { +fn gen_patch_point(jit: &mut JITState, asm: &mut Assembler, invariant: &Invariant, state: &FrameState) { let payload_ptr = get_or_create_iseq_payload_ptr(jit.iseq); let label = asm.new_label("patch_point").unwrap_label(); let invariant = invariant.clone(); // Compile a side exit. Fill nop instructions if the last patch point is too close. - asm.patch_point(build_side_exit(jit, state, PatchPoint(invariant), Some(label))?); + asm.patch_point(build_side_exit(jit, state, PatchPoint(invariant), Some(label))); // Remember the current address as a patch point asm.pos_marker(move |code_ptr, cb| { @@ -583,13 +590,12 @@ fn gen_patch_point(jit: &mut JITState, asm: &mut Assembler, invariant: &Invarian } } }); - Some(()) } /// Lowering for [`Insn::CCall`]. This is a low-level raw call that doesn't know /// anything about the callee, so handling for e.g. GC safety is dealt with elsewhere. -fn gen_ccall(asm: &mut Assembler, cfun: *const u8, args: Vec<Opnd>) -> Option<lir::Opnd> { - Some(asm.ccall(cfun, args)) +fn gen_ccall(asm: &mut Assembler, cfun: *const u8, args: Vec<Opnd>) -> lir::Opnd { + asm.ccall(cfun, args) } /// Emit an uncached instance variable lookup @@ -598,9 +604,8 @@ fn gen_getivar(asm: &mut Assembler, recv: Opnd, id: ID) -> Opnd { } /// Emit an uncached instance variable store -fn gen_setivar(asm: &mut Assembler, recv: Opnd, id: ID, val: Opnd) -> Option<()> { +fn gen_setivar(asm: &mut Assembler, recv: Opnd, id: ID, val: Opnd) { asm_ccall!(asm, rb_ivar_set, recv, id.0.into(), val); - Some(()) } /// Look up global variables @@ -609,25 +614,23 @@ fn gen_getglobal(asm: &mut Assembler, id: ID) -> Opnd { } /// Intern a string -fn gen_intern(asm: &mut Assembler, val: Opnd, state: &FrameState) -> Option<Opnd> { +fn gen_intern(asm: &mut Assembler, val: Opnd, state: &FrameState) -> Opnd { gen_prepare_call_with_gc(asm, state); - Some(asm_ccall!(asm, rb_str_intern, val)) + asm_ccall!(asm, rb_str_intern, val) } /// Set global variables -fn gen_setglobal(jit: &mut JITState, asm: &mut Assembler, id: ID, val: Opnd, state: &FrameState) -> Option<()> { +fn gen_setglobal(jit: &mut JITState, asm: &mut Assembler, id: ID, val: Opnd, state: &FrameState) { // When trace_var is used, setting a global variable can cause exceptions - gen_prepare_non_leaf_call(jit, asm, state)?; + gen_prepare_non_leaf_call(jit, asm, state); asm_ccall!(asm, rb_gvar_set, id.0.into(), val); - Some(()) } /// Side-exit into the interpreter -fn gen_side_exit(jit: &mut JITState, asm: &mut Assembler, reason: &SideExitReason, state: &FrameState) -> Option<()> { - asm.jmp(side_exit(jit, state, *reason)?); - Some(()) +fn gen_side_exit(jit: &mut JITState, asm: &mut Assembler, reason: &SideExitReason, state: &FrameState) { + asm.jmp(side_exit(jit, state, *reason)); } /// Emit a special object lookup @@ -734,25 +737,26 @@ fn gen_entry_params(asm: &mut Assembler, iseq: IseqPtr, entry_block: &Block) { } /// Set branch params to basic block arguments -fn gen_branch_params(jit: &mut JITState, asm: &mut Assembler, branch: &BranchEdge) -> Option<()> { - if !branch.args.is_empty() { - asm_comment!(asm, "set branch params: {}", branch.args.len()); - let mut moves: Vec<(Reg, Opnd)> = vec![]; - for (idx, &arg) in branch.args.iter().enumerate() { - match param_opnd(idx) { - Opnd::Reg(reg) => { - // If a parameter is a register, we need to parallel-move it - moves.push((reg, jit.get_opnd(arg)?)); - }, - param => { - // If a parameter is memory, we set it beforehand - asm.mov(param, jit.get_opnd(arg)?); - } +fn gen_branch_params(jit: &mut JITState, asm: &mut Assembler, branch: &BranchEdge) { + if branch.args.is_empty() { + return; + } + + asm_comment!(asm, "set branch params: {}", branch.args.len()); + let mut moves: Vec<(Reg, Opnd)> = vec![]; + for (idx, &arg) in branch.args.iter().enumerate() { + match param_opnd(idx) { + Opnd::Reg(reg) => { + // If a parameter is a register, we need to parallel-move it + moves.push((reg, jit.get_opnd(arg))); + }, + param => { + // If a parameter is memory, we set it beforehand + asm.mov(param, jit.get_opnd(arg)); } } - asm.parallel_mov(moves); } - Some(()) + asm.parallel_mov(moves); } /// Get a method parameter on JIT entry. As of entry, whether EP is escaped or not solely @@ -795,18 +799,17 @@ fn gen_param(asm: &mut Assembler, idx: usize) -> lir::Opnd { } /// Compile a jump to a basic block -fn gen_jump(jit: &mut JITState, asm: &mut Assembler, branch: &BranchEdge) -> Option<()> { +fn gen_jump(jit: &mut JITState, asm: &mut Assembler, branch: &BranchEdge) { // Set basic block arguments gen_branch_params(jit, asm, branch); // Jump to the basic block let target = jit.get_label(asm, branch.target); asm.jmp(target); - Some(()) } /// Compile a conditional branch to a basic block -fn gen_if_true(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, branch: &BranchEdge) -> Option<()> { +fn gen_if_true(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, branch: &BranchEdge) { // If val is zero, move on to the next instruction. let if_false = asm.new_label("if_false"); asm.test(val, val); @@ -819,12 +822,10 @@ fn gen_if_true(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, branch: asm.jmp(if_true); asm.write_label(if_false); - - Some(()) } /// Compile a conditional branch to a basic block -fn gen_if_false(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, branch: &BranchEdge) -> Option<()> { +fn gen_if_false(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, branch: &BranchEdge) { // If val is not zero, move on to the next instruction. let if_true = asm.new_label("if_true"); asm.test(val, val); @@ -837,8 +838,6 @@ fn gen_if_false(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, branch: asm.jmp(if_false); asm.write_label(if_true); - - Some(()) } /// Compile a dynamic dispatch without block @@ -849,8 +848,8 @@ fn gen_send_without_block( state: &FrameState, self_val: Opnd, args: Vec<Opnd>, -) -> Option<lir::Opnd> { - gen_spill_locals(jit, asm, state)?; +) -> lir::Opnd { + gen_spill_locals(jit, asm, state); // Spill the receiver and the arguments onto the stack. // They need to be on the interpreter stack to let the interpreter access them. // TODO: Avoid spilling operands that have been spilled before. @@ -879,7 +878,7 @@ fn gen_send_without_block( // TODO(max): Add a PatchPoint here that can side-exit the function if the callee messed with // the frame's locals - Some(ret) + ret } /// Compile a direct jump to an ISEQ call without block @@ -892,13 +891,13 @@ fn gen_send_without_block_direct( recv: Opnd, args: Vec<Opnd>, state: &FrameState, -) -> Option<lir::Opnd> { +) -> lir::Opnd { // Save cfp->pc and cfp->sp for the caller frame gen_save_pc(asm, state); gen_save_sp(asm, state.stack().len() - args.len() - 1); // -1 for receiver - gen_spill_locals(jit, asm, state)?; - gen_spill_stack(jit, asm, state)?; + gen_spill_locals(jit, asm, state); + gen_spill_stack(jit, asm, state); // Set up the new frame // TODO: Lazily materialize caller frames on side exits or when needed @@ -944,7 +943,7 @@ fn gen_send_without_block_direct( let new_sp = asm.sub(SP, sp_offset.into()); asm.mov(SP, new_sp); - Some(ret) + ret } /// Compile a string resurrection @@ -974,7 +973,7 @@ fn gen_new_array( ) -> lir::Opnd { gen_prepare_call_with_gc(asm, state); - let length: ::std::os::raw::c_long = elements.len().try_into().expect("Unable to fit length of elements into c_long"); + let length: c_long = elements.len().try_into().expect("Unable to fit length of elements into c_long"); let new_array = asm_ccall!(asm, rb_ary_new_capa, length.into()); @@ -985,22 +984,79 @@ fn gen_new_array( new_array } +/// Compile a new hash instruction +fn gen_new_hash( + jit: &mut JITState, + asm: &mut Assembler, + elements: &Vec<(InsnId, InsnId)>, + state: &FrameState, +) -> lir::Opnd { + gen_prepare_non_leaf_call(jit, asm, state); + + let cap: c_long = elements.len().try_into().expect("Unable to fit length of elements into c_long"); + let new_hash = asm_ccall!(asm, rb_hash_new_with_size, lir::Opnd::Imm(cap)); + + if !elements.is_empty() { + let mut pairs = Vec::new(); + for (key_id, val_id) in elements.iter() { + let key = jit.get_opnd(*key_id); + let val = jit.get_opnd(*val_id); + pairs.push(key); + pairs.push(val); + } + + let n = pairs.len(); + + // Calculate the compile-time NATIVE_STACK_PTR offset from NATIVE_BASE_PTR + // At this point, frame_setup(&[], jit.c_stack_slots) has been called, + // which allocated aligned_stack_bytes(jit.c_stack_slots) on the stack + let frame_size = aligned_stack_bytes(jit.c_stack_slots); + let allocation_size = aligned_stack_bytes(n); + + asm_comment!(asm, "allocate {} bytes on C stack for {} hash elements", allocation_size, n); + asm.sub_into(NATIVE_STACK_PTR, allocation_size.into()); + + // Calculate the total offset from NATIVE_BASE_PTR to our buffer + let total_offset_from_base = (frame_size + allocation_size) as i32; + + for (idx, &pair_opnd) in pairs.iter().enumerate() { + let slot_offset = -total_offset_from_base + (idx as i32 * SIZEOF_VALUE_I32); + asm.mov( + Opnd::mem(VALUE_BITS, NATIVE_BASE_PTR, slot_offset), + pair_opnd + ); + } + + let argv = asm.lea(Opnd::mem(64, NATIVE_BASE_PTR, -total_offset_from_base)); + + let argc = (elements.len() * 2) as ::std::os::raw::c_long; + asm_ccall!(asm, rb_hash_bulk_insert, lir::Opnd::Imm(argc), argv, new_hash); + + asm_comment!(asm, "restore C stack pointer"); + asm.add_into(NATIVE_STACK_PTR, allocation_size.into()); + } + + new_hash +} + /// Compile a new range instruction fn gen_new_range( + jit: &JITState, asm: &mut Assembler, low: lir::Opnd, high: lir::Opnd, flag: RangeType, state: &FrameState, ) -> lir::Opnd { - gen_prepare_call_with_gc(asm, state); + // Sometimes calls `low.<=>(high)` + gen_prepare_non_leaf_call(jit, asm, state); // Call rb_range_new(low, high, flag) asm_ccall!(asm, rb_range_new, low, high, (flag as i64).into()) } /// Compile code that exits from JIT code with a return value -fn gen_return(asm: &mut Assembler, val: lir::Opnd) -> Option<()> { +fn gen_return(asm: &mut Assembler, val: lir::Opnd) { // Pop the current frame (ec->cfp++) // Note: the return PC is already in the previous CFP asm_comment!(asm, "pop stack frame"); @@ -1015,31 +1071,28 @@ fn gen_return(asm: &mut Assembler, val: lir::Opnd) -> Option<()> { // Return from the function asm.frame_teardown(&[]); // matching the setup in :bb0-prologue: asm.cret(C_RET_OPND); - Some(()) } /// Compile Fixnum + Fixnum -fn gen_fixnum_add(jit: &mut JITState, asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd, state: &FrameState) -> Option<lir::Opnd> { +fn gen_fixnum_add(jit: &mut JITState, asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd, state: &FrameState) -> lir::Opnd { // Add left + right and test for overflow let left_untag = asm.sub(left, Opnd::Imm(1)); let out_val = asm.add(left_untag, right); - asm.jo(side_exit(jit, state, FixnumAddOverflow)?); + asm.jo(side_exit(jit, state, FixnumAddOverflow)); - Some(out_val) + out_val } /// Compile Fixnum - Fixnum -fn gen_fixnum_sub(jit: &mut JITState, asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd, state: &FrameState) -> Option<lir::Opnd> { +fn gen_fixnum_sub(jit: &mut JITState, asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd, state: &FrameState) -> lir::Opnd { // Subtract left - right and test for overflow let val_untag = asm.sub(left, right); - asm.jo(side_exit(jit, state, FixnumSubOverflow)?); - let out_val = asm.add(val_untag, Opnd::Imm(1)); - - Some(out_val) + asm.jo(side_exit(jit, state, FixnumSubOverflow)); + asm.add(val_untag, Opnd::Imm(1)) } /// Compile Fixnum * Fixnum -fn gen_fixnum_mult(jit: &mut JITState, asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd, state: &FrameState) -> Option<lir::Opnd> { +fn gen_fixnum_mult(jit: &mut JITState, asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd, state: &FrameState) -> lir::Opnd { // Do some bitwise gymnastics to handle tag bits // x * y is translated to (x >> 1) * (y - 1) + 1 let left_untag = asm.rshift(left, Opnd::UImm(1)); @@ -1047,107 +1100,105 @@ fn gen_fixnum_mult(jit: &mut JITState, asm: &mut Assembler, left: lir::Opnd, rig let out_val = asm.mul(left_untag, right_untag); // Test for overflow - asm.jo_mul(side_exit(jit, state, FixnumMultOverflow)?); - let out_val = asm.add(out_val, Opnd::UImm(1)); - - Some(out_val) + asm.jo_mul(side_exit(jit, state, FixnumMultOverflow)); + asm.add(out_val, Opnd::UImm(1)) } /// Compile Fixnum == Fixnum -fn gen_fixnum_eq(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> Option<lir::Opnd> { +fn gen_fixnum_eq(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> lir::Opnd { asm.cmp(left, right); - Some(asm.csel_e(Qtrue.into(), Qfalse.into())) + asm.csel_e(Qtrue.into(), Qfalse.into()) } /// Compile Fixnum != Fixnum -fn gen_fixnum_neq(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> Option<lir::Opnd> { +fn gen_fixnum_neq(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> lir::Opnd { asm.cmp(left, right); - Some(asm.csel_ne(Qtrue.into(), Qfalse.into())) + asm.csel_ne(Qtrue.into(), Qfalse.into()) } /// Compile Fixnum < Fixnum -fn gen_fixnum_lt(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> Option<lir::Opnd> { +fn gen_fixnum_lt(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> lir::Opnd { asm.cmp(left, right); - Some(asm.csel_l(Qtrue.into(), Qfalse.into())) + asm.csel_l(Qtrue.into(), Qfalse.into()) } /// Compile Fixnum <= Fixnum -fn gen_fixnum_le(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> Option<lir::Opnd> { +fn gen_fixnum_le(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> lir::Opnd { asm.cmp(left, right); - Some(asm.csel_le(Qtrue.into(), Qfalse.into())) + asm.csel_le(Qtrue.into(), Qfalse.into()) } /// Compile Fixnum > Fixnum -fn gen_fixnum_gt(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> Option<lir::Opnd> { +fn gen_fixnum_gt(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> lir::Opnd { asm.cmp(left, right); - Some(asm.csel_g(Qtrue.into(), Qfalse.into())) + asm.csel_g(Qtrue.into(), Qfalse.into()) } /// Compile Fixnum >= Fixnum -fn gen_fixnum_ge(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> Option<lir::Opnd> { +fn gen_fixnum_ge(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> lir::Opnd { asm.cmp(left, right); - Some(asm.csel_ge(Qtrue.into(), Qfalse.into())) + asm.csel_ge(Qtrue.into(), Qfalse.into()) } /// Compile Fixnum & Fixnum -fn gen_fixnum_and(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> Option<lir::Opnd> { - Some(asm.and(left, right)) +fn gen_fixnum_and(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> lir::Opnd { + asm.and(left, right) } /// Compile Fixnum | Fixnum -fn gen_fixnum_or(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> Option<lir::Opnd> { - Some(asm.or(left, right)) +fn gen_fixnum_or(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd) -> lir::Opnd { + asm.or(left, right) } // Compile val == nil -fn gen_isnil(asm: &mut Assembler, val: lir::Opnd) -> Option<lir::Opnd> { +fn gen_isnil(asm: &mut Assembler, val: lir::Opnd) -> lir::Opnd { asm.cmp(val, Qnil.into()); // TODO: Implement and use setcc - Some(asm.csel_e(Opnd::Imm(1), Opnd::Imm(0))) + asm.csel_e(Opnd::Imm(1), Opnd::Imm(0)) } -fn gen_anytostring(asm: &mut Assembler, val: lir::Opnd, str: lir::Opnd, state: &FrameState) -> Option<lir::Opnd> { +fn gen_anytostring(asm: &mut Assembler, val: lir::Opnd, str: lir::Opnd, state: &FrameState) -> lir::Opnd { gen_prepare_call_with_gc(asm, state); - Some(asm_ccall!(asm, rb_obj_as_string_result, str, val)) + asm_ccall!(asm, rb_obj_as_string_result, str, val) } /// Evaluate if a value is truthy /// Produces a CBool type (0 or 1) /// In Ruby, only nil and false are falsy /// Everything else evaluates to true -fn gen_test(asm: &mut Assembler, val: lir::Opnd) -> Option<lir::Opnd> { +fn gen_test(asm: &mut Assembler, val: lir::Opnd) -> lir::Opnd { // Test if any bit (outside of the Qnil bit) is on // See RB_TEST(), include/ruby/internal/special_consts.h asm.test(val, Opnd::Imm(!Qnil.as_i64())); - Some(asm.csel_e(0.into(), 1.into())) + asm.csel_e(0.into(), 1.into()) } /// Compile a type check with a side exit -fn gen_guard_type(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, guard_type: Type, state: &FrameState) -> Option<lir::Opnd> { +fn gen_guard_type(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, guard_type: Type, state: &FrameState) -> lir::Opnd { if guard_type.is_subtype(types::Fixnum) { asm.test(val, Opnd::UImm(RUBY_FIXNUM_FLAG as u64)); - asm.jz(side_exit(jit, state, GuardType(guard_type))?); + asm.jz(side_exit(jit, state, GuardType(guard_type))); } else if guard_type.is_subtype(types::Flonum) { // Flonum: (val & RUBY_FLONUM_MASK) == RUBY_FLONUM_FLAG let masked = asm.and(val, Opnd::UImm(RUBY_FLONUM_MASK as u64)); asm.cmp(masked, Opnd::UImm(RUBY_FLONUM_FLAG as u64)); - asm.jne(side_exit(jit, state, GuardType(guard_type))?); + asm.jne(side_exit(jit, state, GuardType(guard_type))); } else if guard_type.is_subtype(types::StaticSymbol) { // Static symbols have (val & 0xff) == RUBY_SYMBOL_FLAG - // Use 8-bit comparison like YJIT does - debug_assert!(val.try_num_bits(8).is_some(), "GuardType should not be used for a known constant, but val was: {val:?}"); - asm.cmp(val.try_num_bits(8)?, Opnd::UImm(RUBY_SYMBOL_FLAG as u64)); - asm.jne(side_exit(jit, state, GuardType(guard_type))?); + // Use 8-bit comparison like YJIT does. GuardType should not be used + // for a known VALUE, which with_num_bits() does not support. + asm.cmp(val.with_num_bits(8), Opnd::UImm(RUBY_SYMBOL_FLAG as u64)); + asm.jne(side_exit(jit, state, GuardType(guard_type))); } else if guard_type.is_subtype(types::NilClass) { asm.cmp(val, Qnil.into()); - asm.jne(side_exit(jit, state, GuardType(guard_type))?); + asm.jne(side_exit(jit, state, GuardType(guard_type))); } else if guard_type.is_subtype(types::TrueClass) { asm.cmp(val, Qtrue.into()); - asm.jne(side_exit(jit, state, GuardType(guard_type))?); + asm.jne(side_exit(jit, state, GuardType(guard_type))); } else if guard_type.is_subtype(types::FalseClass) { asm.cmp(val, Qfalse.into()); - asm.jne(side_exit(jit, state, GuardType(guard_type))?); + asm.jne(side_exit(jit, state, GuardType(guard_type))); } else if guard_type.is_immediate() { // All immediate types' guard should have been handled above panic!("unexpected immediate guard type: {guard_type}"); @@ -1162,7 +1213,7 @@ fn gen_guard_type(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, guard }; // Check if it's a special constant - let side_exit = side_exit(jit, state, GuardType(guard_type))?; + let side_exit = side_exit(jit, state, GuardType(guard_type)); asm.test(val, (RUBY_IMMEDIATE_MASK as u64).into()); asm.jnz(side_exit.clone()); @@ -1178,18 +1229,18 @@ fn gen_guard_type(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, guard } else { unimplemented!("unsupported type: {guard_type}"); } - Some(val) + val } /// Compile an identity check with a side exit -fn gen_guard_bit_equals(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, expected: VALUE, state: &FrameState) -> Option<lir::Opnd> { +fn gen_guard_bit_equals(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, expected: VALUE, state: &FrameState) -> lir::Opnd { asm.cmp(val, Opnd::Value(expected)); - asm.jnz(side_exit(jit, state, GuardBitEquals(expected))?); - Some(val) + asm.jnz(side_exit(jit, state, GuardBitEquals(expected))); + val } /// Generate code that increments a counter in ZJIT stats -fn gen_incr_counter(asm: &mut Assembler, counter: Counter) -> () { +fn gen_incr_counter(asm: &mut Assembler, counter: Counter) { let ptr = counter_ptr(counter); let ptr_reg = asm.load(Opnd::const_ptr(ptr as *const u8)); let counter_opnd = Opnd::mem(64, ptr_reg, 0); @@ -1221,30 +1272,27 @@ fn gen_save_sp(asm: &mut Assembler, stack_size: usize) { } /// Spill locals onto the stack. -fn gen_spill_locals(jit: &JITState, asm: &mut Assembler, state: &FrameState) -> Option<()> { +fn gen_spill_locals(jit: &JITState, asm: &mut Assembler, state: &FrameState) { // TODO: Avoid spilling locals that have been spilled before and not changed. asm_comment!(asm, "spill locals"); for (idx, &insn_id) in state.locals().enumerate() { - asm.mov(Opnd::mem(64, SP, (-local_idx_to_ep_offset(jit.iseq, idx) - 1) * SIZEOF_VALUE_I32), jit.get_opnd(insn_id)?); + asm.mov(Opnd::mem(64, SP, (-local_idx_to_ep_offset(jit.iseq, idx) - 1) * SIZEOF_VALUE_I32), jit.get_opnd(insn_id)); } - Some(()) } /// Spill the virtual stack onto the stack. -fn gen_spill_stack(jit: &JITState, asm: &mut Assembler, state: &FrameState) -> Option<()> { +fn gen_spill_stack(jit: &JITState, asm: &mut Assembler, state: &FrameState) { // This function does not call gen_save_sp() at the moment because // gen_send_without_block_direct() spills stack slots above SP for arguments. asm_comment!(asm, "spill stack"); for (idx, &insn_id) in state.stack().enumerate() { - asm.mov(Opnd::mem(64, SP, idx as i32 * SIZEOF_VALUE_I32), jit.get_opnd(insn_id)?); + asm.mov(Opnd::mem(64, SP, idx as i32 * SIZEOF_VALUE_I32), jit.get_opnd(insn_id)); } - Some(()) } /// Prepare for calling a C function that may call an arbitrary method. /// Use gen_prepare_call_with_gc() if the method is leaf but allocates objects. -#[must_use] -fn gen_prepare_non_leaf_call(jit: &JITState, asm: &mut Assembler, state: &FrameState) -> Option<()> { +fn gen_prepare_non_leaf_call(jit: &JITState, asm: &mut Assembler, state: &FrameState) { // TODO: Lazily materialize caller frames when needed // Save PC for backtraces and allocation tracing gen_save_pc(asm, state); @@ -1252,11 +1300,10 @@ fn gen_prepare_non_leaf_call(jit: &JITState, asm: &mut Assembler, state: &FrameS // Save SP and spill the virtual stack in case it raises an exception // and the interpreter uses the stack for handling the exception gen_save_sp(asm, state.stack().len()); - gen_spill_stack(jit, asm, state)?; + gen_spill_stack(jit, asm, state); // Spill locals in case the method looks at caller Bindings - gen_spill_locals(jit, asm, state)?; - Some(()) + gen_spill_locals(jit, asm, state); } /// Prepare for calling a C function that may allocate objects and trigger GC. @@ -1353,20 +1400,20 @@ fn compile_iseq(iseq: IseqPtr) -> Option<Function> { } /// Build a Target::SideExit for non-PatchPoint instructions -fn side_exit(jit: &mut JITState, state: &FrameState, reason: SideExitReason) -> Option<Target> { +fn side_exit(jit: &mut JITState, state: &FrameState, reason: SideExitReason) -> Target { build_side_exit(jit, state, reason, None) } /// Build a Target::SideExit out of a FrameState -fn build_side_exit(jit: &mut JITState, state: &FrameState, reason: SideExitReason, label: Option<Label>) -> Option<Target> { +fn build_side_exit(jit: &mut JITState, state: &FrameState, reason: SideExitReason, label: Option<Label>) -> Target { let mut stack = Vec::new(); for &insn_id in state.stack() { - stack.push(jit.get_opnd(insn_id)?); + stack.push(jit.get_opnd(insn_id)); } let mut locals = Vec::new(); for &insn_id in state.locals() { - locals.push(jit.get_opnd(insn_id)?); + locals.push(jit.get_opnd(insn_id)); } let target = Target::SideExit { @@ -1376,7 +1423,7 @@ fn build_side_exit(jit: &mut JITState, state: &FrameState, reason: SideExitReaso reason, label, }; - Some(target) + target } /// Return true if a given ISEQ is known to escape EP to the heap on entry. @@ -1429,9 +1476,9 @@ c_callable! { with_vm_lock(src_loc!(), || { // gen_push_frame() doesn't set PC and SP, so we need to set them before exit. // function_stub_hit_body() may allocate and call gc_validate_pc(), so we always set PC. - let iseq_call = unsafe { Rc::from_raw(iseq_call_ptr as *const IseqCall) }; + let iseq_call = unsafe { Rc::from_raw(iseq_call_ptr as *const RefCell<IseqCall>) }; let cfp = unsafe { get_ec_cfp(ec) }; - let pc = unsafe { rb_iseq_pc_at_idx(iseq_call.iseq, 0) }; // TODO: handle opt_pc once supported + let pc = unsafe { rb_iseq_pc_at_idx(iseq_call.borrow().iseq, 0) }; // TODO: handle opt_pc once supported unsafe { rb_set_cfp_pc(cfp, pc) }; unsafe { rb_set_cfp_sp(cfp, sp) }; @@ -1439,10 +1486,10 @@ c_callable! { // TODO: Alan thinks the payload status part of this check can happen without the VM lock, since the whole // code path can be made read-only. But you still need the check as is while holding the VM lock in any case. let cb = ZJITState::get_code_block(); - let payload = get_or_create_iseq_payload(iseq_call.iseq); + let payload = get_or_create_iseq_payload(iseq_call.borrow().iseq); if cb.has_dropped_bytes() || payload.status == IseqStatus::CantCompile { // We'll use this Rc again, so increment the ref count decremented by from_raw. - unsafe { Rc::increment_strong_count(iseq_call_ptr as *const IseqCall); } + unsafe { Rc::increment_strong_count(iseq_call_ptr as *const RefCell<IseqCall>); } // Exit to the interpreter return ZJITState::get_exit_trampoline().raw_ptr(cb); @@ -1463,22 +1510,23 @@ c_callable! { } /// Compile an ISEQ for a function stub -fn function_stub_hit_body(cb: &mut CodeBlock, iseq_call: &Rc<IseqCall>) -> Option<CodePtr> { +fn function_stub_hit_body(cb: &mut CodeBlock, iseq_call: &Rc<RefCell<IseqCall>>) -> Option<CodePtr> { // Compile the stubbed ISEQ - let Some((code_ptr, iseq_calls)) = gen_iseq(cb, iseq_call.iseq) else { - debug!("Failed to compile iseq: gen_iseq failed: {}", iseq_get_location(iseq_call.iseq, 0)); + let Some((code_ptr, iseq_calls)) = gen_iseq(cb, iseq_call.borrow().iseq) else { + debug!("Failed to compile iseq: gen_iseq failed: {}", iseq_get_location(iseq_call.borrow().iseq, 0)); return None; }; // Stub callee ISEQs for JIT-to-JIT calls - for callee_iseq_call in iseq_calls.into_iter() { - gen_iseq_call(cb, iseq_call.iseq, callee_iseq_call)?; + for callee_iseq_call in iseq_calls.iter() { + gen_iseq_call(cb, iseq_call.borrow().iseq, callee_iseq_call)?; } // Update the stub to call the code pointer let code_addr = code_ptr.raw_ptr(cb); - iseq_call.regenerate(cb, |asm| { - asm_comment!(asm, "call compiled function: {}", iseq_get_location(iseq_call.iseq, 0)); + let iseq = iseq_call.borrow().iseq; + iseq_call.borrow_mut().regenerate(cb, |asm| { + asm_comment!(asm, "call compiled function: {}", iseq_get_location(iseq, 0)); asm.ccall(code_addr, vec![]); }); @@ -1486,9 +1534,9 @@ fn function_stub_hit_body(cb: &mut CodeBlock, iseq_call: &Rc<IseqCall>) -> Optio } /// Compile a stub for an ISEQ called by SendWithoutBlockDirect -fn gen_function_stub(cb: &mut CodeBlock, iseq_call: Rc<IseqCall>) -> Option<CodePtr> { +fn gen_function_stub(cb: &mut CodeBlock, iseq_call: Rc<RefCell<IseqCall>>) -> Option<CodePtr> { let mut asm = Assembler::new(); - asm_comment!(asm, "Stub: {}", iseq_get_location(iseq_call.iseq, 0)); + asm_comment!(asm, "Stub: {}", iseq_get_location(iseq_call.borrow().iseq, 0)); // Call function_stub_hit using the shared trampoline. See `gen_function_stub_hit_trampoline`. // Use load_into instead of mov, which is split on arm64, to avoid clobbering ALLOC_REGS. @@ -1550,16 +1598,8 @@ pub fn gen_exit_trampoline(cb: &mut CodeBlock) -> Option<CodePtr> { }) } -fn gen_string_concat(jit: &mut JITState, asm: &mut Assembler, strings: Vec<Opnd>, state: &FrameState) -> Option<Opnd> { - let n = strings.len(); - - // concatstrings shouldn't have 0 strings - // If it happens we abort the compilation for now - if n == 0 { - return None; - } - - gen_prepare_non_leaf_call(jit, asm, state)?; +fn gen_push_opnds(jit: &mut JITState, asm: &mut Assembler, opnds: &[Opnd]) -> lir::Opnd { + let n = opnds.len(); // Calculate the compile-time NATIVE_STACK_PTR offset from NATIVE_BASE_PTR // At this point, frame_setup(&[], jit.c_stack_slots) has been called, @@ -1567,28 +1607,51 @@ fn gen_string_concat(jit: &mut JITState, asm: &mut Assembler, strings: Vec<Opnd> let frame_size = aligned_stack_bytes(jit.c_stack_slots); let allocation_size = aligned_stack_bytes(n); - asm_comment!(asm, "allocate {} bytes on C stack for {} strings", allocation_size, n); + asm_comment!(asm, "allocate {} bytes on C stack for {} values", allocation_size, n); asm.sub_into(NATIVE_STACK_PTR, allocation_size.into()); // Calculate the total offset from NATIVE_BASE_PTR to our buffer let total_offset_from_base = (frame_size + allocation_size) as i32; - for (idx, &string_opnd) in strings.iter().enumerate() { + for (idx, &opnd) in opnds.iter().enumerate() { let slot_offset = -total_offset_from_base + (idx as i32 * SIZEOF_VALUE_I32); asm.mov( Opnd::mem(VALUE_BITS, NATIVE_BASE_PTR, slot_offset), - string_opnd + opnd ); } - let first_string_ptr = asm.lea(Opnd::mem(64, NATIVE_BASE_PTR, -total_offset_from_base)); - - let result = asm_ccall!(asm, rb_str_concat_literals, n.into(), first_string_ptr); + asm.lea(Opnd::mem(64, NATIVE_BASE_PTR, -total_offset_from_base)) +} +fn gen_pop_opnds(asm: &mut Assembler, opnds: &[Opnd]) { asm_comment!(asm, "restore C stack pointer"); + let allocation_size = aligned_stack_bytes(opnds.len()); asm.add_into(NATIVE_STACK_PTR, allocation_size.into()); +} + +fn gen_toregexp(jit: &mut JITState, asm: &mut Assembler, opt: usize, values: Vec<Opnd>, state: &FrameState) -> Opnd { + gen_prepare_non_leaf_call(jit, asm, state); + + let first_opnd_ptr = gen_push_opnds(jit, asm, &values); + + let tmp_ary = asm_ccall!(asm, rb_ary_tmp_new_from_values, Opnd::Imm(0), values.len().into(), first_opnd_ptr); + let result = asm_ccall!(asm, rb_reg_new_ary, tmp_ary, opt.into()); + asm_ccall!(asm, rb_ary_clear, tmp_ary); + + gen_pop_opnds(asm, &values); - Some(result) + result +} + +fn gen_string_concat(jit: &mut JITState, asm: &mut Assembler, strings: Vec<Opnd>, state: &FrameState) -> Opnd { + gen_prepare_non_leaf_call(jit, asm, state); + + let first_string_ptr = gen_push_opnds(jit, asm, &strings); + let result = asm_ccall!(asm, rb_str_concat_literals, strings.len().into(), first_string_ptr); + gen_pop_opnds(asm, &strings); + + result } /// Given the number of spill slots needed for a function, return the number of bytes @@ -1602,7 +1665,7 @@ fn aligned_stack_bytes(num_slots: usize) -> usize { impl Assembler { /// Make a C call while marking the start and end positions for IseqCall - fn ccall_with_iseq_call(&mut self, fptr: *const u8, opnds: Vec<Opnd>, iseq_call: &Rc<IseqCall>) -> Opnd { + fn ccall_with_iseq_call(&mut self, fptr: *const u8, opnds: Vec<Opnd>, iseq_call: &Rc<RefCell<IseqCall>>) -> Opnd { // We need to create our own branch rc objects so that we can move the closure below let start_iseq_call = iseq_call.clone(); let end_iseq_call = iseq_call.clone(); @@ -1611,10 +1674,10 @@ impl Assembler { fptr, opnds, move |code_ptr, _| { - start_iseq_call.start_addr.set(Some(code_ptr)); + start_iseq_call.borrow_mut().start_addr.set(Some(code_ptr)); }, move |code_ptr, _| { - end_iseq_call.end_addr.set(Some(code_ptr)); + end_iseq_call.borrow_mut().end_addr.set(Some(code_ptr)); }, ) } @@ -1622,9 +1685,9 @@ impl Assembler { /// Store info about a JIT-to-JIT call #[derive(Debug)] -struct IseqCall { +pub struct IseqCall { /// Callee ISEQ that start_addr jumps to - iseq: IseqPtr, + pub iseq: IseqPtr, /// Position where the call instruction starts start_addr: Cell<Option<CodePtr>>, @@ -1635,12 +1698,13 @@ struct IseqCall { impl IseqCall { /// Allocate a new IseqCall - fn new(iseq: IseqPtr) -> Rc<Self> { - Rc::new(IseqCall { + fn new(iseq: IseqPtr) -> Rc<RefCell<Self>> { + let iseq_call = IseqCall { iseq, start_addr: Cell::new(None), end_addr: Cell::new(None), - }) + }; + Rc::new(RefCell::new(iseq_call)) } /// Regenerate a IseqCall with a given callback diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs index 5c939fabe7..524b06b580 100644 --- a/zjit/src/cruby_bindings.inc.rs +++ b/zjit/src/cruby_bindings.inc.rs @@ -30,6 +30,11 @@ impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> { fmt.write_str("__IncompleteArrayField") } } +pub const ONIG_OPTION_IGNORECASE: u32 = 1; +pub const ONIG_OPTION_EXTEND: u32 = 2; +pub const ONIG_OPTION_MULTILINE: u32 = 4; +pub const ARG_ENCODING_FIXED: u32 = 16; +pub const ARG_ENCODING_NONE: u32 = 32; pub const INTEGER_REDEFINED_OP_FLAG: u32 = 1; pub const FLOAT_REDEFINED_OP_FLAG: u32 = 2; pub const STRING_REDEFINED_OP_FLAG: u32 = 4; diff --git a/zjit/src/gc.rs b/zjit/src/gc.rs index 52a036d49e..3462b80232 100644 --- a/zjit/src/gc.rs +++ b/zjit/src/gc.rs @@ -1,6 +1,9 @@ // This module is responsible for marking/moving objects on GC. +use std::cell::RefCell; +use std::rc::Rc; use std::{ffi::c_void, ops::Range}; +use crate::codegen::IseqCall; use crate::{cruby::*, profile::IseqProfile, state::ZJITState, stats::with_time_stat, virtualmem::CodePtr}; use crate::stats::Counter::gc_time_ns; @@ -15,6 +18,9 @@ pub struct IseqPayload { /// GC offsets of the JIT code. These are the addresses of objects that need to be marked. pub gc_offsets: Vec<CodePtr>, + + /// JIT-to-JIT calls in the ISEQ. The IseqPayload's ISEQ is the caller of it. + pub iseq_calls: Vec<Rc<RefCell<IseqCall>>>, } impl IseqPayload { @@ -23,6 +29,7 @@ impl IseqPayload { status: IseqStatus::NotCompiled, profile: IseqProfile::new(iseq_size), gc_offsets: vec![], + iseq_calls: vec![], } } } @@ -112,6 +119,16 @@ pub extern "C" fn rb_zjit_iseq_update_references(payload: *mut c_void) { with_time_stat(gc_time_ns, || iseq_update_references(payload)); } +/// GC callback for updating object references after all object moves +#[unsafe(no_mangle)] +pub extern "C" fn rb_zjit_root_update_references() { + if !ZJITState::has_instance() { + return; + } + let invariants = ZJITState::get_invariants(); + invariants.update_references(); +} + fn iseq_mark(payload: &IseqPayload) { // Mark objects retained by profiling instructions payload.profile.each_object(|object| { @@ -135,10 +152,22 @@ fn iseq_mark(payload: &IseqPayload) { /// This is a mirror of [iseq_mark]. fn iseq_update_references(payload: &mut IseqPayload) { // Move objects retained by profiling instructions - payload.profile.each_object_mut(|object| { - *object = unsafe { rb_gc_location(*object) }; + payload.profile.each_object_mut(|old_object| { + let new_object = unsafe { rb_gc_location(*old_object) }; + if *old_object != new_object { + *old_object = new_object; + } }); + // Move ISEQ references in IseqCall + for iseq_call in payload.iseq_calls.iter_mut() { + let old_iseq = iseq_call.borrow().iseq; + let new_iseq = unsafe { rb_gc_location(VALUE(old_iseq as usize)) }.0 as IseqPtr; + if old_iseq != new_iseq { + iseq_call.borrow_mut().iseq = new_iseq; + } + } + // Move objects baked in JIT code let cb = ZJITState::get_code_block(); for &offset in payload.gc_offsets.iter() { diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index c50c1ce985..e7aaf64f28 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -439,6 +439,7 @@ pub enum SideExitReason { CalleeSideExit, ObjToStringFallback, UnknownSpecialVariable(u64), + UnhandledDefinedType(usize), } impl std::fmt::Display for SideExitReason { @@ -472,6 +473,9 @@ pub enum Insn { StringIntern { val: InsnId, state: InsnId }, StringConcat { strings: Vec<InsnId>, state: InsnId }, + /// Combine count stack values into a regexp + ToRegexp { opt: usize, values: Vec<InsnId>, state: InsnId }, + /// Put special object (VMCORE, CBASE, etc.) based on value_type PutSpecialObject { value_type: SpecialObjectType }, @@ -634,7 +638,6 @@ impl Insn { // NewHash's operands may be hashed and compared for equality, which could have // side-effects. Insn::NewHash { elements, .. } => elements.len() > 0, - Insn::NewRange { .. } => false, Insn::ArrayDup { .. } => false, Insn::HashDup { .. } => false, Insn::Test { .. } => false, @@ -656,6 +659,9 @@ impl Insn { Insn::GetLocal { .. } => false, Insn::IsNil { .. } => false, Insn::CCall { elidable, .. } => !elidable, + // TODO: NewRange is effects free if we can prove the two ends to be Fixnum, + // but we don't have type information here in `impl Insn`. See rb_range_new(). + Insn::NewRange { .. } => true, _ => true, } } @@ -667,6 +673,14 @@ pub struct InsnPrinter<'a> { ptr_map: &'a PtrPrintMap, } +static REGEXP_FLAGS: &[(u32, &str)] = &[ + (ONIG_OPTION_MULTILINE, "MULTILINE"), + (ONIG_OPTION_IGNORECASE, "IGNORECASE"), + (ONIG_OPTION_EXTEND, "EXTENDED"), + (ARG_ENCODING_FIXED, "FIXEDENCODING"), + (ARG_ENCODING_NONE, "NOENCODING"), +]; + impl<'a> std::fmt::Display for InsnPrinter<'a> { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match &self.inner { @@ -715,6 +729,28 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> { Ok(()) } + Insn::ToRegexp { values, opt, .. } => { + write!(f, "ToRegexp")?; + let mut prefix = " "; + for value in values { + write!(f, "{prefix}{value}")?; + prefix = ", "; + } + + let opt = *opt as u32; + if opt != 0 { + write!(f, ", ")?; + let mut sep = ""; + for (flag, name) in REGEXP_FLAGS { + if opt & flag != 0 { + write!(f, "{sep}{name}")?; + sep = "|"; + } + } + } + + Ok(()) + } Insn::Test { val } => { write!(f, "Test {val}") } Insn::IsNil { val } => { write!(f, "IsNil {val}") } Insn::Jump(target) => { write!(f, "Jump {target}") } @@ -1178,6 +1214,7 @@ impl Function { &StringCopy { val, chilled, state } => StringCopy { val: find!(val), chilled, state }, &StringIntern { val, state } => StringIntern { val: find!(val), state: find!(state) }, &StringConcat { ref strings, state } => StringConcat { strings: find_vec!(strings), state: find!(state) }, + &ToRegexp { opt, ref values, state } => ToRegexp { opt, values: find_vec!(values), state }, &Test { val } => Test { val: find!(val) }, &IsNil { val } => IsNil { val: find!(val) }, &Jump(ref target) => Jump(find_branch_edge!(target)), @@ -1304,6 +1341,7 @@ impl Function { Insn::StringCopy { .. } => types::StringExact, Insn::StringIntern { .. } => types::Symbol, Insn::StringConcat { .. } => types::StringExact, + Insn::ToRegexp { .. } => types::RegexpExact, Insn::NewArray { .. } => types::ArrayExact, Insn::ArrayDup { .. } => types::ArrayExact, Insn::NewHash { .. } => types::HashExact, @@ -1330,7 +1368,7 @@ impl Function { Insn::SendWithoutBlockDirect { .. } => types::BasicObject, Insn::Send { .. } => types::BasicObject, Insn::InvokeBuiltin { return_type, .. } => return_type.unwrap_or(types::BasicObject), - Insn::Defined { .. } => types::BasicObject, + Insn::Defined { pushval, .. } => Type::from_value(*pushval).union(types::NilClass), Insn::DefinedIvar { .. } => types::BasicObject, Insn::GetConstantPath { .. } => types::BasicObject, Insn::ArrayMax { .. } => types::BasicObject, @@ -1938,14 +1976,18 @@ impl Function { worklist.extend(strings); worklist.push_back(state); } + &Insn::ToRegexp { ref values, state, .. } => { + worklist.extend(values); + worklist.push_back(state); + } | &Insn::Return { val } | &Insn::Throw { val, .. } - | &Insn::Defined { v: val, .. } | &Insn::Test { val } | &Insn::SetLocal { val, .. } | &Insn::IsNil { val } => worklist.push_back(val), &Insn::SetGlobal { val, state, .. } + | &Insn::Defined { v: val, state, .. } | &Insn::StringIntern { val, state } | &Insn::StringCopy { val, state, .. } | &Insn::GuardType { val, state, .. } @@ -2862,6 +2904,15 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { let insn_id = fun.push_insn(block, Insn::StringConcat { strings, state: exit_id }); state.stack_push(insn_id); } + YARVINSN_toregexp => { + // First arg contains the options (multiline, extended, ignorecase) used to create the regexp + let opt = get_arg(pc, 0).as_usize(); + let count = get_arg(pc, 1).as_usize(); + let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state }); + let values = state.stack_pop_n(count)?; + let insn_id = fun.push_insn(block, Insn::ToRegexp { opt, values, state: exit_id }); + state.stack_push(insn_id); + } YARVINSN_newarray => { let count = get_arg(pc, 0).as_usize(); let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state }); @@ -2957,6 +3008,11 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { let pushval = get_arg(pc, 2); let v = state.stack_pop()?; let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state }); + if op_type == DEFINED_METHOD.try_into().unwrap() { + // TODO(Shopify/ruby#703): Fix codegen for defined?(method call expr) + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledDefinedType(op_type)}); + break; // End the block + } state.stack_push(fun.push_insn(block, Insn::Defined { op_type, obj, pushval, v, state: exit_id })); } YARVINSN_definedivar => { @@ -4204,10 +4260,10 @@ mod tests { fn test@<compiled>:2: bb0(v0:BasicObject): v2:NilClass = Const Value(nil) - v4:BasicObject = Defined constant, v2 - v6:BasicObject = Defined func, v0 + v4:StringExact|NilClass = Defined constant, v2 + v6:StringExact|NilClass = Defined func, v0 v7:NilClass = Const Value(nil) - v9:BasicObject = Defined global-variable, v7 + v9:StringExact|NilClass = Defined global-variable, v7 v11:ArrayExact = NewArray v4, v6, v9 Return v11 "#]]); @@ -5325,6 +5381,47 @@ mod tests { } #[test] + fn test_toregexp() { + eval(r##" + def test = /#{1}#{2}#{3}/ + "##); + assert_method_hir_with_opcode("test", YARVINSN_toregexp, expect![[r#" + fn test@<compiled>:2: + bb0(v0:BasicObject): + v2:Fixnum[1] = Const Value(1) + v4:BasicObject = ObjToString v2 + v6:String = AnyToString v2, str: v4 + v7:Fixnum[2] = Const Value(2) + v9:BasicObject = ObjToString v7 + v11:String = AnyToString v7, str: v9 + v12:Fixnum[3] = Const Value(3) + v14:BasicObject = ObjToString v12 + v16:String = AnyToString v12, str: v14 + v18:RegexpExact = ToRegexp v6, v11, v16 + Return v18 + "#]]); + } + + #[test] + fn test_toregexp_with_options() { + eval(r##" + def test = /#{1}#{2}/mixn + "##); + assert_method_hir_with_opcode("test", YARVINSN_toregexp, expect![[r#" + fn test@<compiled>:2: + bb0(v0:BasicObject): + v2:Fixnum[1] = Const Value(1) + v4:BasicObject = ObjToString v2 + v6:String = AnyToString v2, str: v4 + v7:Fixnum[2] = Const Value(2) + v9:BasicObject = ObjToString v7 + v11:String = AnyToString v7, str: v9 + v13:RegexpExact = ToRegexp v6, v11, MULTILINE|IGNORECASE|EXTENDED|NOENCODING + Return v13 + "#]]); + } + + #[test] fn throw() { eval(" define_method(:throw_return) { return 1 } @@ -6104,6 +6201,29 @@ mod opt_tests { } #[test] + fn test_do_not_eliminate_new_range_non_fixnum() { + eval(" + def test() + _ = (-'a'..'b') + 0 + end + test; test + "); + assert_optimized_method_hir("test", expect![[r#" + fn test@<compiled>:3: + bb0(v0:BasicObject): + v1:NilClass = Const Value(nil) + v4:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) + PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_UMINUS) + v6:StringExact[VALUE(0x1008)] = Const Value(VALUE(0x1008)) + v8:StringExact = StringCopy v6 + v10:RangeExact = NewRange v4 NewRangeInclusive v8 + v11:Fixnum[0] = Const Value(0) + Return v11 + "#]]); + } + + #[test] fn test_eliminate_new_array_with_elements() { eval(" def test(a) diff --git a/zjit/src/invariants.rs b/zjit/src/invariants.rs index 3f291415be..14fea76d1b 100644 --- a/zjit/src/invariants.rs +++ b/zjit/src/invariants.rs @@ -1,6 +1,6 @@ use std::{collections::{HashMap, HashSet}, mem}; -use crate::{backend::lir::{asm_comment, Assembler}, cruby::{rb_callable_method_entry_t, ruby_basic_operators, src_loc, with_vm_lock, IseqPtr, RedefinitionFlag, ID}, gc::IseqPayload, hir::Invariant, options::debug, state::{zjit_enabled_p, ZJITState}, virtualmem::CodePtr}; +use crate::{backend::lir::{asm_comment, Assembler}, cruby::{rb_callable_method_entry_t, rb_gc_location, ruby_basic_operators, src_loc, with_vm_lock, IseqPtr, RedefinitionFlag, ID, VALUE}, gc::IseqPayload, hir::Invariant, options::debug, state::{zjit_enabled_p, ZJITState}, virtualmem::CodePtr}; use crate::stats::with_time_stat; use crate::stats::Counter::invalidation_time_ns; use crate::gc::remove_gc_offsets; @@ -56,6 +56,31 @@ pub struct Invariants { single_ractor_patch_points: HashSet<PatchPoint>, } +impl Invariants { + /// Update object references in Invariants + pub fn update_references(&mut self) { + Self::update_iseq_references(&mut self.ep_escape_iseqs); + Self::update_iseq_references(&mut self.no_ep_escape_iseqs); + } + + /// Update ISEQ references in a given HashSet<IseqPtr> + fn update_iseq_references(iseqs: &mut HashSet<IseqPtr>) { + let mut moved: Vec<IseqPtr> = Vec::with_capacity(iseqs.len()); + + iseqs.retain(|&old_iseq| { + let new_iseq = unsafe { rb_gc_location(VALUE(old_iseq as usize)) }.0 as IseqPtr; + if old_iseq != new_iseq { + moved.push(new_iseq); + } + old_iseq == new_iseq + }); + + for new_iseq in moved { + iseqs.insert(new_iseq); + } + } +} + /// Called when a basic operator is redefined. Note that all the blocks assuming /// the stability of different operators are invalidated together and we don't /// do fine-grained tracking. diff --git a/zjit/src/profile.rs b/zjit/src/profile.rs index 7ffaea29dc..771d90cb0e 100644 --- a/zjit/src/profile.rs +++ b/zjit/src/profile.rs @@ -98,19 +98,32 @@ fn profile_operands(profiler: &mut Profiler, profile: &mut IseqProfile, n: usize let obj = profiler.peek_at_stack((n - i - 1) as isize); // TODO(max): Handle GC-hidden classes like Array, Hash, etc and make them look normal or // drop them or something - let ty = ProfiledType::new(obj.class_of(), obj.shape_id_of()); + let ty = ProfiledType::new(obj); unsafe { rb_gc_writebarrier(profiler.iseq.into(), ty.class()) }; types[i].observe(ty); } } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct Flags(u32); + +impl Flags { + const NONE: u32 = 0; + const IS_IMMEDIATE: u32 = 1 << 0; + + pub fn none() -> Self { Self(Self::NONE) } + + pub fn immediate() -> Self { Self(Self::IS_IMMEDIATE) } + pub fn is_immediate(self) -> bool { (self.0 & Self::IS_IMMEDIATE) != 0 } +} + /// opt_send_without_block/opt_plus/... should store: /// * the class of the receiver, so we can do method lookup /// * the shape of the receiver, so we can optimize ivar lookup /// with those two, pieces of information, we can also determine when an object is an immediate: -/// * Integer + SPECIAL_CONST_SHAPE_ID == Fixnum -/// * Float + SPECIAL_CONST_SHAPE_ID == Flonum -/// * Symbol + SPECIAL_CONST_SHAPE_ID == StaticSymbol +/// * Integer + IS_IMMEDIATE == Fixnum +/// * Float + IS_IMMEDIATE == Flonum +/// * Symbol + IS_IMMEDIATE == StaticSymbol /// * NilClass == Nil /// * TrueClass == True /// * FalseClass == False @@ -118,6 +131,7 @@ fn profile_operands(profiler: &mut Profiler, profile: &mut IseqProfile, n: usize pub struct ProfiledType { class: VALUE, shape: ShapeId, + flags: Flags, } impl Default for ProfiledType { @@ -127,12 +141,42 @@ impl Default for ProfiledType { } impl ProfiledType { - fn new(class: VALUE, shape: ShapeId) -> Self { - Self { class, shape } + fn new(obj: VALUE) -> Self { + if obj == Qfalse { + return Self { class: unsafe { rb_cFalseClass }, + shape: INVALID_SHAPE_ID, + flags: Flags::immediate() }; + } + if obj == Qtrue { + return Self { class: unsafe { rb_cTrueClass }, + shape: INVALID_SHAPE_ID, + flags: Flags::immediate() }; + } + if obj == Qnil { + return Self { class: unsafe { rb_cNilClass }, + shape: INVALID_SHAPE_ID, + flags: Flags::immediate() }; + } + if obj.fixnum_p() { + return Self { class: unsafe { rb_cInteger }, + shape: INVALID_SHAPE_ID, + flags: Flags::immediate() }; + } + if obj.flonum_p() { + return Self { class: unsafe { rb_cFloat }, + shape: INVALID_SHAPE_ID, + flags: Flags::immediate() }; + } + if obj.static_sym_p() { + return Self { class: unsafe { rb_cSymbol }, + shape: INVALID_SHAPE_ID, + flags: Flags::immediate() }; + } + Self { class: obj.class_of(), shape: obj.shape_id_of(), flags: Flags::none() } } pub fn empty() -> Self { - Self { class: VALUE(0), shape: INVALID_SHAPE_ID } + Self { class: VALUE(0), shape: INVALID_SHAPE_ID, flags: Flags::none() } } pub fn is_empty(&self) -> bool { @@ -148,27 +192,27 @@ impl ProfiledType { } pub fn is_fixnum(&self) -> bool { - self.class == unsafe { rb_cInteger } && self.shape == SPECIAL_CONST_SHAPE_ID + self.class == unsafe { rb_cInteger } && self.flags.is_immediate() } pub fn is_flonum(&self) -> bool { - self.class == unsafe { rb_cFloat } && self.shape == SPECIAL_CONST_SHAPE_ID + self.class == unsafe { rb_cFloat } && self.flags.is_immediate() } pub fn is_static_symbol(&self) -> bool { - self.class == unsafe { rb_cSymbol } && self.shape == SPECIAL_CONST_SHAPE_ID + self.class == unsafe { rb_cSymbol } && self.flags.is_immediate() } pub fn is_nil(&self) -> bool { - self.class == unsafe { rb_cNilClass } && self.shape == SPECIAL_CONST_SHAPE_ID + self.class == unsafe { rb_cNilClass } && self.flags.is_immediate() } pub fn is_true(&self) -> bool { - self.class == unsafe { rb_cTrueClass } && self.shape == SPECIAL_CONST_SHAPE_ID + self.class == unsafe { rb_cTrueClass } && self.flags.is_immediate() } pub fn is_false(&self) -> bool { - self.class == unsafe { rb_cFalseClass } && self.shape == SPECIAL_CONST_SHAPE_ID + self.class == unsafe { rb_cFalseClass } && self.flags.is_immediate() } } |