diff options
author | Hiroshi SHIBATA <[email protected]> | 2022-12-22 08:20:23 +0900 |
---|---|---|
committer | Hiroshi SHIBATA <[email protected]> | 2022-12-24 16:57:07 +0900 |
commit | f6620037ba1477d2c337d7b511f094d6d0fbb69c (patch) | |
tree | 4d8d38eaf97e6ca88162dd574e7871e1739f22ae | |
parent | d5635dfe36588b04d3dd6065ab4e422f51629b11 (diff) |
Merge RubyGems-3.4.0 and Bundler-2.4.0
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/6987
57 files changed, 2895 insertions, 161 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb index 5ae8b6120a..c6a225977f 100644 --- a/lib/bundler.rb +++ b/lib/bundler.rb @@ -463,7 +463,7 @@ EOF end def local_platform - return Gem::Platform::RUBY if settings[:force_ruby_platform] || Gem.platforms == [Gem::Platform::RUBY] + return Gem::Platform::RUBY if settings[:force_ruby_platform] Gem::Platform.local end diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index a9331a0131..6745740f11 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -10,7 +10,7 @@ module Bundler AUTO_INSTALL_CMDS = %w[show binstubs outdated exec open console licenses clean].freeze PARSEABLE_COMMANDS = %w[check config help exec platform show version].freeze - EXTENSIONS = ["c"].freeze + EXTENSIONS = ["c", "rust"].freeze COMMAND_ALIASES = { "check" => "c", @@ -762,7 +762,7 @@ module Bundler # when deprecated version of `--ext` is called # print out deprecation warning and pretend `--ext=c` was provided if deprecated_ext_value?(arguments) - SharedHelpers.major_deprecation 2, "Option `--ext` without explicit value is deprecated. Please pass value like `--ext=c` for C extension. Pretending `--ext=c` was used for now." + SharedHelpers.major_deprecation 2, "Extensions can now be generated using C or Rust, so `--ext` with no arguments has been deprecated. Please select a language, e.g. `--ext=rust` to generate a Rust extension. This gem will now be generated as if `--ext=c` was used." arguments[arguments.index("--ext")] = "--ext=c" end end diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb index 40c464cc2c..7f1200f4a0 100644 --- a/lib/bundler/cli/gem.rb +++ b/lib/bundler/cli/gem.rb @@ -31,6 +31,7 @@ module Bundler @extension = options[:ext] validate_ext_name if @extension + validate_rust_builder_rubygems_version if @extension == "rust" travis_removal_info end @@ -73,6 +74,7 @@ module Bundler :git => use_git, :github_username => github_username.empty? ? "[USERNAME]" : github_username, :required_ruby_version => required_ruby_version, + :rust_builder_required_rubygems_version => rust_builder_required_rubygems_version, :minitest_constant_name => minitest_constant_name, } ensure_safe_gem_name(name, constant_array) @@ -189,14 +191,23 @@ module Bundler templates.merge!("exe/newgem.tt" => "exe/#{name}") if config[:exe] - if extension + if extension == "c" templates.merge!( - "ext/newgem/extconf.rb.tt" => "ext/#{name}/extconf.rb", + "ext/newgem/extconf-c.rb.tt" => "ext/#{name}/extconf.rb", "ext/newgem/newgem.h.tt" => "ext/#{name}/#{underscored_name}.h", "ext/newgem/newgem.c.tt" => "ext/#{name}/#{underscored_name}.c" ) end + if extension == "rust" + templates.merge!( + "Cargo.toml.tt" => "Cargo.toml", + "ext/newgem/Cargo.toml.tt" => "ext/#{name}/Cargo.toml", + "ext/newgem/extconf-rust.rb.tt" => "ext/#{name}/extconf.rb", + "ext/newgem/src/lib.rs.tt" => "ext/#{name}/src/lib.rs", + ) + end + if target.exist? && !target.directory? Bundler.ui.error "Couldn't create a new gem named `#{gem_name}` because there's an existing file named `#{gem_name}`." exit Bundler::BundlerError.all_errors[Bundler::GenericSystemCallError] @@ -415,6 +426,10 @@ module Bundler thor.run(%(#{editor} "#{file}")) end + def rust_builder_required_rubygems_version + "3.3.11" + end + def required_ruby_version "2.6.0" end @@ -427,7 +442,6 @@ module Bundler "1.3" end - # # TODO: remove at next minor release def travis_removal_info if options[:ci] == "travis" @@ -440,5 +454,12 @@ module Bundler exit 1 end end + + def validate_rust_builder_rubygems_version + if Gem::Version.new(rust_builder_required_rubygems_version) > Gem.rubygems_version + Bundler.ui.error "Your RubyGems version (#{Gem.rubygems_version}) is too old to build Rust extension. Please update your RubyGems using `gem update --system` or any other way and try again." + exit 1 + end + end end end diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 8659c64849..348f1b6a3d 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -263,10 +263,10 @@ module Bundler @locked_specs elsif !unlocking? && nothing_changed? if deleted_deps.any? - Bundler.ui.debug("Some dependencies were deleted, using a subset of the resolution from the lockfile") + Bundler.ui.debug "Some dependencies were deleted, using a subset of the resolution from the lockfile" SpecSet.new(filter_specs(@locked_specs, @dependencies - deleted_deps)) else - Bundler.ui.debug("Found no changes, using resolution from the lockfile") + Bundler.ui.debug "Found no changes, using resolution from the lockfile" if @locked_gems.may_include_redundant_platform_specific_gems? SpecSet.new(filter_specs(@locked_specs, @dependencies)) else @@ -274,7 +274,7 @@ module Bundler end end else - Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}") + Bundler.ui.debug "Found changes from the lockfile, re-resolving dependencies because #{change_reason}" start_resolution end end @@ -806,12 +806,13 @@ module Bundler end new_spec = new_specs[s].first - - # If the spec is no longer in the path source, unlock it. This - # commonly happens if the version changed in the gemspec - next unless new_spec - - s.dependencies.replace(new_spec.dependencies) + if new_spec + s.dependencies.replace(new_spec.dependencies) + else + # If the spec is no longer in the path source, unlock it. This + # commonly happens if the version changed in the gemspec + @unlock[:gems] << s.name + end end if dep.nil? && requested_dependencies.find {|d| s.name == d.name } diff --git a/lib/bundler/dependency.rb b/lib/bundler/dependency.rb index 695e5c12b2..1f8b9da2eb 100644 --- a/lib/bundler/dependency.rb +++ b/lib/bundler/dependency.rb @@ -7,7 +7,7 @@ require_relative "rubygems_ext" module Bundler class Dependency < Gem::Dependency attr_reader :autorequire - attr_reader :groups, :platforms, :gemfile, :path, :git, :github, :branch, :ref, :force_ruby_platform + attr_reader :groups, :platforms, :gemfile, :path, :git, :github, :branch, :ref ALL_RUBY_VERSIONS = ((18..27).to_a + (30..31).to_a).freeze PLATFORM_MAP = { @@ -42,7 +42,7 @@ module Bundler @env = options["env"] @should_include = options.fetch("should_include", true) @gemfile = options["gemfile"] - @force_ruby_platform = options["force_ruby_platform"] + @force_ruby_platform = options["force_ruby_platform"] if options.key?("force_ruby_platform") @autorequire = Array(options["require"] || []) if options.key?("require") end @@ -50,7 +50,7 @@ module Bundler # Returns the platforms this dependency is valid for, in the same order as # passed in the `valid_platforms` parameter def gem_platforms(valid_platforms) - return [Gem::Platform::RUBY] if @force_ruby_platform + return [Gem::Platform::RUBY] if force_ruby_platform return valid_platforms if @platforms.empty? valid_platforms.select {|p| expanded_platforms.include?(GemHelpers.generic(p)) } diff --git a/lib/bundler/force_platform.rb b/lib/bundler/force_platform.rb new file mode 100644 index 0000000000..249a24ecd1 --- /dev/null +++ b/lib/bundler/force_platform.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Bundler + module ForcePlatform + private + + # The `:force_ruby_platform` value used by dependencies for resolution, and + # by locked specifications for materialization is `false` by default, except + # for TruffleRuby. TruffleRuby generally needs to force the RUBY platform + # variant unless the name is explicitly allowlisted. + + def default_force_ruby_platform + return false unless RUBY_ENGINE == "truffleruby" + + !Gem::Platform::REUSE_AS_BINARY_ON_TRUFFLERUBY.include?(name) + end + end +end diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb index 21a6f96f69..ca51691b5c 100644 --- a/lib/bundler/lazy_specification.rb +++ b/lib/bundler/lazy_specification.rb @@ -1,8 +1,11 @@ # frozen_string_literal: true +require_relative "force_platform" + module Bundler class LazySpecification include MatchPlatform + include ForcePlatform attr_reader :name, :version, :dependencies, :platform attr_accessor :source, :remote, :force_ruby_platform @@ -14,6 +17,7 @@ module Bundler @platform = platform || Gem::Platform::RUBY @source = source @specification = nil + @force_ruby_platform = default_force_ruby_platform end def full_name diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1 index efd7c8edbc..11cc002194 100644 --- a/lib/bundler/man/bundle-gem.1 +++ b/lib/bundler/man/bundle-gem.1 @@ -31,41 +31,32 @@ The generated project skeleton can be customized with OPTIONS, as explained belo . .SH "OPTIONS" . -.TP -\fB\-\-exe\fR or \fB\-b\fR or \fB\-\-bin\fR -Specify that Bundler should create a binary executable (as \fBexe/GEM_NAME\fR) in the generated rubygem project\. This binary will also be added to the \fBGEM_NAME\.gemspec\fR manifest\. This behavior is disabled by default\. +.IP "\(bu" 4 +\fB\-\-exe\fR or \fB\-b\fR or \fB\-\-bin\fR: Specify that Bundler should create a binary executable (as \fBexe/GEM_NAME\fR) in the generated rubygem project\. This binary will also be added to the \fBGEM_NAME\.gemspec\fR manifest\. This behavior is disabled by default\. . -.TP -\fB\-\-no\-exe\fR -Do not create a binary (overrides \fB\-\-exe\fR specified in the global config)\. +.IP "\(bu" 4 +\fB\-\-no\-exe\fR: Do not create a binary (overrides \fB\-\-exe\fR specified in the global config)\. . -.TP -\fB\-\-coc\fR -Add a \fBCODE_OF_CONDUCT\.md\fR file to the root of the generated project\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. +.IP "\(bu" 4 +\fB\-\-coc\fR: Add a \fBCODE_OF_CONDUCT\.md\fR file to the root of the generated project\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . -.TP -\fB\-\-no\-coc\fR -Do not create a \fBCODE_OF_CONDUCT\.md\fR (overrides \fB\-\-coc\fR specified in the global config)\. +.IP "\(bu" 4 +\fB\-\-no\-coc\fR: Do not create a \fBCODE_OF_CONDUCT\.md\fR (overrides \fB\-\-coc\fR specified in the global config)\. . -.TP -\fB\-\-ext=c\fR -Add boilerplate for C extension code to the generated project\. This behavior is disabled by default\. +.IP "\(bu" 4 +\fB\-\-ext=c\fR, \fB\-\-ext=rust\fR Add boilerplate for C or Rust (currently magnus \fIhttps://docs\.rs/magnus\fR based) extension code to the generated project\. This behavior is disabled by default\. . -.TP -\fB\-\-no\-ext\fR -Do not add C extension code (overrides \fB\-\-ext\fR specified in the global config)\. +.IP "\(bu" 4 +\fB\-\-no\-ext\fR: Do not add extension code (overrides \fB\-\-ext\fR specified in the global config)\. . -.TP -\fB\-\-mit\fR -Add an MIT license to a \fBLICENSE\.txt\fR file in the root of the generated project\. Your name from the global git config is used for the copyright statement\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. +.IP "\(bu" 4 +\fB\-\-mit\fR: Add an MIT license to a \fBLICENSE\.txt\fR file in the root of the generated project\. Your name from the global git config is used for the copyright statement\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . -.TP -\fB\-\-no\-mit\fR -Do not create a \fBLICENSE\.txt\fR (overrides \fB\-\-mit\fR specified in the global config)\. +.IP "\(bu" 4 +\fB\-\-no\-mit\fR: Do not create a \fBLICENSE\.txt\fR (overrides \fB\-\-mit\fR specified in the global config)\. . -.TP -\fB\-t\fR, \fB\-\-test=minitest\fR, \fB\-\-test=rspec\fR, \fB\-\-test=test\-unit\fR -Specify the test framework that Bundler should use when generating the project\. Acceptable values are \fBminitest\fR, \fBrspec\fR and \fBtest\-unit\fR\. The \fBGEM_NAME\.gemspec\fR will be configured and a skeleton test/spec directory will be created based on this option\. Given no option is specified: +.IP "\(bu" 4 +\fB\-t\fR, \fB\-\-test=minitest\fR, \fB\-\-test=rspec\fR, \fB\-\-test=test\-unit\fR: Specify the test framework that Bundler should use when generating the project\. Acceptable values are \fBminitest\fR, \fBrspec\fR and \fBtest\-unit\fR\. The \fBGEM_NAME\.gemspec\fR will be configured and a skeleton test/spec directory will be created based on this option\. Given no option is specified: . .IP When Bundler is configured to generate tests, this defaults to Bundler\'s global config setting \fBgem\.test\fR\. @@ -76,9 +67,8 @@ When Bundler is configured to not generate tests, an interactive prompt will be .IP When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . -.TP -\fB\-\-ci\fR, \fB\-\-ci=github\fR, \fB\-\-ci=gitlab\fR, \fB\-\-ci=circle\fR -Specify the continuous integration service that Bundler should use when generating the project\. Acceptable values are \fBgithub\fR, \fBgitlab\fR and \fBcircle\fR\. A configuration file will be generated in the project directory\. Given no option is specified: +.IP "\(bu" 4 +\fB\-\-ci\fR, \fB\-\-ci=github\fR, \fB\-\-ci=gitlab\fR, \fB\-\-ci=circle\fR: Specify the continuous integration service that Bundler should use when generating the project\. Acceptable values are \fBgithub\fR, \fBgitlab\fR and \fBcircle\fR\. A configuration file will be generated in the project directory\. Given no option is specified: . .IP When Bundler is configured to generate CI files, this defaults to Bundler\'s global config setting \fBgem\.ci\fR\. @@ -89,9 +79,8 @@ When Bundler is configured to not generate CI files, an interactive prompt will .IP When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . -.TP -\fB\-\-linter\fR, \fB\-\-linter=rubocop\fR, \fB\-\-linter=standard\fR -Specify the linter and code formatter that Bundler should add to the project\'s development dependencies\. Acceptable values are \fBrubocop\fR and \fBstandard\fR\. A configuration file will be generated in the project directory\. Given no option is specified: +.IP "\(bu" 4 +\fB\-\-linter\fR, \fB\-\-linter=rubocop\fR, \fB\-\-linter=standard\fR: Specify the linter and code formatter that Bundler should add to the project\'s development dependencies\. Acceptable values are \fBrubocop\fR and \fBstandard\fR\. A configuration file will be generated in the project directory\. Given no option is specified: . .IP When Bundler is configured to add a linter, this defaults to Bundler\'s global config setting \fBgem\.linter\fR\. @@ -102,9 +91,10 @@ When Bundler is configured not to add a linter, an interactive prompt will be di .IP When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . -.TP -\fB\-e\fR, \fB\-\-edit[=EDITOR]\fR -Open the resulting GEM_NAME\.gemspec in EDITOR, or the default editor if not specified\. The default is \fB$BUNDLER_EDITOR\fR, \fB$VISUAL\fR, or \fB$EDITOR\fR\. +.IP "\(bu" 4 +\fB\-e\fR, \fB\-\-edit[=EDITOR]\fR: Open the resulting GEM_NAME\.gemspec in EDITOR, or the default editor if not specified\. The default is \fB$BUNDLER_EDITOR\fR, \fB$VISUAL\fR, or \fB$EDITOR\fR\. +. +.IP "" 0 . .SH "SEE ALSO" . diff --git a/lib/bundler/man/bundle-gem.1.ronn b/lib/bundler/man/bundle-gem.1.ronn index 96966107e3..46fa2f179f 100644 --- a/lib/bundler/man/bundle-gem.1.ronn +++ b/lib/bundler/man/bundle-gem.1.ronn @@ -41,12 +41,12 @@ configuration file using the following names: Do not create a `CODE_OF_CONDUCT.md` (overrides `--coc` specified in the global config). -* `--ext=c`: - Add boilerplate for C extension code to the generated project. This behavior +* `--ext=c`, `--ext=rust` + Add boilerplate for C or Rust (currently [magnus](https://docs.rs/magnus) based) extension code to the generated project. This behavior is disabled by default. * `--no-ext`: - Do not add C extension code (overrides `--ext` specified in the global + Do not add extension code (overrides `--ext` specified in the global config). * `--mit`: diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index b654cb819d..a2d4820d58 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -27,6 +27,17 @@ module Bundler remove_from_candidates(spec) end + @requirements = requirements + @packages = packages + + root, logger = setup_solver + + Bundler.ui.info "Resolving dependencies...", true + + solve_versions(:root => root, :logger => logger) + end + + def setup_solver root = Resolver::Root.new(name_for_explicit_dependency_source) root_version = Resolver::Candidate.new(0) @@ -42,24 +53,27 @@ module Bundler end end - root_dependencies = prepare_dependencies(requirements, packages) + root_dependencies = prepare_dependencies(@requirements, @packages) @cached_dependencies = Hash.new do |dependencies, package| dependencies[package] = if package.root? { root_version => root_dependencies } else Hash.new do |versions, version| - versions[version] = to_dependency_hash(version.dependencies, packages) + versions[version] = to_dependency_hash(version.dependencies, @packages) end end end logger = Bundler::UI::Shell.new logger.level = debug? ? "debug" : "warn" + + [root, logger] + end + + def solve_versions(root:, logger:) solver = PubGrub::VersionSolver.new(:source => self, :root => root, :logger => logger) - before_resolution result = solver.solve - after_resolution result.map {|package, version| version.to_specs(package) }.flatten.uniq rescue PubGrub::SolveFailure => e incompatibility = e.incompatibility @@ -82,8 +96,15 @@ module Bundler end end + names_to_unlock.uniq! + if names_to_unlock.any? + Bundler.ui.debug "Found conflicts with locked dependencies. Retrying with #{names_to_unlock.join(", ")} unlocked...", true + @base.unlock_names(names_to_unlock) + + root, logger = setup_solver + retry end @@ -144,14 +165,6 @@ module Bundler false end - def before_resolution - Bundler.ui.info "Resolving dependencies...", debug? - end - - def after_resolution - Bundler.ui.info "" - end - def incompatibilities_for(package, version) package_deps = @cached_dependencies[package] sorted_versions = @sorted_versions[package] @@ -202,7 +215,7 @@ module Bundler def all_versions_for(package) name = package.name - results = @base[name] + @all_specs[name] + results = (@base[name] + @all_specs[name]).uniq(&:full_name) locked_requirement = base_requirements[name] results = filter_matching_specs(results, locked_requirement) if locked_requirement diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb index 705c4c8458..0252e1a81a 100644 --- a/lib/bundler/rubygems_ext.rb +++ b/lib/bundler/rubygems_ext.rb @@ -16,6 +16,7 @@ require "rubygems/specification" require "rubygems/source" require_relative "match_metadata" +require_relative "force_platform" require_relative "match_platform" # Cherry-pick fixes to `Gem.ruby_version` to be useful for modern Bundler @@ -153,12 +154,16 @@ module Gem end class Dependency + include ::Bundler::ForcePlatform + attr_accessor :source, :groups alias_method :eql?, :== def force_ruby_platform - false + return @force_ruby_platform if defined?(@force_ruby_platform) && !@force_ruby_platform.nil? + + @force_ruby_platform = default_force_ruby_platform end def encode_with(coder) @@ -277,6 +282,10 @@ module Gem without_gnu_nor_abi_modifiers end end + + if RUBY_ENGINE == "truffleruby" && !defined?(REUSE_AS_BINARY_ON_TRUFFLERUBY) + REUSE_AS_BINARY_ON_TRUFFLERUBY = %w[libv8 libv8-node sorbet-static].freeze + end end Platform.singleton_class.module_eval do diff --git a/lib/bundler/source/git/git_proxy.rb b/lib/bundler/source/git/git_proxy.rb index 31b3107c9e..7133e260a0 100644 --- a/lib/bundler/source/git/git_proxy.rb +++ b/lib/bundler/source/git/git_proxy.rb @@ -176,37 +176,32 @@ module Bundler @depth = if !supports_fetching_unreachable_refs? nil - elsif not_pinned? + elsif not_pinned? || pinned_to_full_sha? 1 elsif ref.include?("~") parsed_depth = ref.split("~").last parsed_depth.to_i + 1 - elsif abbreviated_ref? - nil - else - 1 end end def refspec - if fully_qualified_ref - "#{fully_qualified_ref}:#{fully_qualified_ref}" - elsif ref.include?("~") - parsed_ref = ref.split("~").first - "#{parsed_ref}:#{parsed_ref}" + return ref if pinned_to_full_sha? + + ref_to_fetch = @revision || fully_qualified_ref + + ref_to_fetch ||= if ref.include?("~") + ref.split("~").first elsif ref.start_with?("refs/") - "#{ref}:#{ref}" - elsif abbreviated_ref? - nil - else ref + else + "refs/*" end + + "#{ref_to_fetch}:#{ref_to_fetch}" end def fully_qualified_ref - return @fully_qualified_ref if defined?(@fully_qualified_ref) - - @fully_qualified_ref = if branch + if branch "refs/heads/#{branch}" elsif tag "refs/tags/#{tag}" @@ -219,8 +214,8 @@ module Bundler branch || tag || ref.nil? end - def abbreviated_ref? - ref =~ /\A\h+\z/ && ref !~ /\A\h{40}\z/ + def pinned_to_full_sha? + ref =~ /\A\h{40}\z/ end def legacy_locked_revision? diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index a3d9218593..7478bd9ca2 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -190,12 +190,10 @@ module Bundler def specs_for_dependency(dep, platform) specs_for_name = lookup[dep.name] - if platform.nil? - matching_specs = specs_for_name.map {|s| s.materialize_for_installation if Gem::Platform.match_spec?(s) }.compact - GemHelpers.sort_best_platform_match(matching_specs, Bundler.local_platform) - else - GemHelpers.select_best_platform_match(specs_for_name, dep.force_ruby_platform ? Gem::Platform::RUBY : platform) - end + target_platform = dep.force_ruby_platform ? Gem::Platform::RUBY : (platform || Bundler.local_platform) + matching_specs = GemHelpers.select_best_platform_match(specs_for_name, target_platform) + matching_specs.map!(&:materialize_for_installation).compact! if platform.nil? + matching_specs end def tsort_each_child(s) diff --git a/lib/bundler/templates/newgem/Cargo.toml.tt b/lib/bundler/templates/newgem/Cargo.toml.tt new file mode 100644 index 0000000000..7be7550cce --- /dev/null +++ b/lib/bundler/templates/newgem/Cargo.toml.tt @@ -0,0 +1,7 @@ +# This Cargo.toml is here to let externals tools (IDEs, etc.) know that this is +# a Rust project. Your extensions depedencies should be added to the Cargo.toml +# in the ext/ directory. + +[workspace] +members = ["./ext/<%= config[:name] %>"] +resolver = "2" diff --git a/lib/bundler/templates/newgem/Gemfile.tt b/lib/bundler/templates/newgem/Gemfile.tt index de82a63c5f..41c95677a3 100644 --- a/lib/bundler/templates/newgem/Gemfile.tt +++ b/lib/bundler/templates/newgem/Gemfile.tt @@ -9,6 +9,9 @@ gem "rake", "~> 13.0" <%- if config[:ext] -%> gem "rake-compiler" +<%- if config[:ext] == 'rust' -%> +gem "rb_sys" +<%- end -%> <%- end -%> <%- if config[:test] -%> diff --git a/lib/bundler/templates/newgem/README.md.tt b/lib/bundler/templates/newgem/README.md.tt index a60c7967ec..20eaac8a62 100644 --- a/lib/bundler/templates/newgem/README.md.tt +++ b/lib/bundler/templates/newgem/README.md.tt @@ -1,18 +1,20 @@ # <%= config[:constant_name] %> -Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/<%= config[:namespaced_path] %>`. To experiment with that code, run `bin/console` for an interactive prompt. +TODO: Delete this and the text below, and describe your gem -TODO: Delete this and the text above, and describe your gem +Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/<%= config[:namespaced_path] %>`. To experiment with that code, run `bin/console` for an interactive prompt. ## Installation +TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org. + Install the gem and add to the application's Gemfile by executing: - $ bundle add <%= config[:name] %> + $ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG If bundler is not being used to manage dependencies, install the gem by executing: - $ gem install <%= config[:name] %> + $ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG ## Usage diff --git a/lib/bundler/templates/newgem/Rakefile.tt b/lib/bundler/templates/newgem/Rakefile.tt index b02ada9b6c..ac14545126 100644 --- a/lib/bundler/templates/newgem/Rakefile.tt +++ b/lib/bundler/templates/newgem/Rakefile.tt @@ -39,7 +39,8 @@ require "standard/rake" <% end -%> <% if config[:ext] -%> -<% default_task_names.unshift(:clobber, :compile) -%> +<% default_task_names.unshift(:compile) -%> +<% default_task_names.unshift(:clobber) unless config[:ext] == 'rust' -%> require "rake/extensiontask" task build: :compile diff --git a/lib/bundler/templates/newgem/circleci/config.yml.tt b/lib/bundler/templates/newgem/circleci/config.yml.tt index 79fd0dcc0f..f40f029bf1 100644 --- a/lib/bundler/templates/newgem/circleci/config.yml.tt +++ b/lib/bundler/templates/newgem/circleci/config.yml.tt @@ -3,8 +3,20 @@ jobs: build: docker: - image: ruby:<%= RUBY_VERSION %> +<%- if config[:ext] == 'rust' -%> + environment: + RB_SYS_FORCE_INSTALL_RUST_TOOLCHAIN: 'true' +<%- end -%> steps: - checkout +<%- if config[:ext] == 'rust' -%> + - run: + name: Install Rust/Cargo dependencies + command: apt-get update && apt-get install -y clang + - run: + name: Install a RubyGems version that can compile rust extensions + command: gem update --system '<%= ::Gem.rubygems_version %>' +<%- end -%> - run: name: Run the default task command: | diff --git a/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt b/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt new file mode 100644 index 0000000000..4b6e9587f7 --- /dev/null +++ b/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt @@ -0,0 +1,15 @@ +[package] +name = <%= config[:name].inspect %> +version = "0.1.0" +edition = "2021" +authors = ["<%= config[:author] %> <<%= config[:email] %>>"] +<%- if config[:mit] -%> +license = "MIT" +<%- end -%> +publish = false + +[lib] +crate-type = ["cdylib"] + +[dependencies] +magnus = { version = "0.4" } diff --git a/lib/bundler/templates/newgem/ext/newgem/extconf.rb.tt b/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt index e918063ddf..e918063ddf 100644 --- a/lib/bundler/templates/newgem/ext/newgem/extconf.rb.tt +++ b/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt diff --git a/lib/bundler/templates/newgem/ext/newgem/extconf-rust.rb.tt b/lib/bundler/templates/newgem/ext/newgem/extconf-rust.rb.tt new file mode 100644 index 0000000000..e24566a17a --- /dev/null +++ b/lib/bundler/templates/newgem/ext/newgem/extconf-rust.rb.tt @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +require "mkmf" +require "rb_sys/mkmf" + +create_rust_makefile(<%= config[:makefile_path].inspect %>) diff --git a/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt b/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt new file mode 100644 index 0000000000..b311283997 --- /dev/null +++ b/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt @@ -0,0 +1,12 @@ +use magnus::{define_module, function, prelude::*, Error}; + +fn hello(subject: String) -> String { + format!("Hello from Rust, {}!", subject) +} + +#[magnus::init] +fn init() -> Result<(), Error> { + let module = <%= config[:constant_array].map {|c| "define_module(#{c.dump})?"}.join(".") %>; + module.define_singleton_method("hello", function!(hello, 1))?; + Ok(()) +} diff --git a/lib/bundler/templates/newgem/github/workflows/main.yml.tt b/lib/bundler/templates/newgem/github/workflows/main.yml.tt index 1ff4b58b7b..d4021980b4 100644 --- a/lib/bundler/templates/newgem/github/workflows/main.yml.tt +++ b/lib/bundler/templates/newgem/github/workflows/main.yml.tt @@ -18,10 +18,20 @@ jobs: steps: - uses: actions/checkout@v3 +<%- if config[:ext] == 'rust' -%> + - name: Set up Ruby & Rust + uses: oxidize-rb/actions/setup-ruby-and-rust@main + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + cargo-cache: true + rubygems: '<%= ::Gem.rubygems_version %>' +<%- else -%> - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true +<%- end -%> - name: Run the default task run: bundle exec rake diff --git a/lib/bundler/templates/newgem/gitignore.tt b/lib/bundler/templates/newgem/gitignore.tt index b1c9f9986c..9b40ba5a58 100644 --- a/lib/bundler/templates/newgem/gitignore.tt +++ b/lib/bundler/templates/newgem/gitignore.tt @@ -12,6 +12,9 @@ *.o *.a mkmf.log +<%- if config[:ext] == 'rust' -%> +target/ +<%- end -%> <%- end -%> <%- if config[:test] == "rspec" -%> diff --git a/lib/bundler/templates/newgem/gitlab-ci.yml.tt b/lib/bundler/templates/newgem/gitlab-ci.yml.tt index 42e00392de..d2e1f33736 100644 --- a/lib/bundler/templates/newgem/gitlab-ci.yml.tt +++ b/lib/bundler/templates/newgem/gitlab-ci.yml.tt @@ -2,9 +2,17 @@ default: image: ruby:<%= RUBY_VERSION %> before_script: +<%- if config[:ext] == 'rust' -%> + - apt-get update && apt-get install -y clang + - gem update --system '<%= ::Gem.rubygems_version %>' +<%- end -%> - gem install bundler -v <%= Bundler::VERSION %> - bundle install example_job: +<%- if config[:ext] == 'rust' -%> + variables: + RB_SYS_FORCE_INSTALL_RUST_TOOLCHAIN: 'true' +<%- end -%> script: - bundle exec rake diff --git a/lib/bundler/templates/newgem/newgem.gemspec.tt b/lib/bundler/templates/newgem/newgem.gemspec.tt index a03dcc8bc2..e35a121245 100644 --- a/lib/bundler/templates/newgem/newgem.gemspec.tt +++ b/lib/bundler/templates/newgem/newgem.gemspec.tt @@ -15,6 +15,9 @@ Gem::Specification.new do |spec| spec.license = "MIT" <%- end -%> spec.required_ruby_version = ">= <%= config[:required_ruby_version] %>" +<%- if config[:ext] == 'rust' -%> + spec.required_rubygems_version = ">= <%= config[:rust_builder_required_rubygems_version] %>" +<%- end -%> spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'" @@ -32,9 +35,12 @@ Gem::Specification.new do |spec| spec.bindir = "exe" spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] -<%- if config[:ext] -%> +<%- if config[:ext] == 'c' -%> spec.extensions = ["ext/<%= config[:underscored_name] %>/extconf.rb"] <%- end -%> +<%- if config[:ext] == 'rust' -%> + spec.extensions = ["ext/<%= config[:underscored_name] %>/Cargo.toml"] +<%- end -%> # Uncomment to register a new dependency of your gem # spec.add_dependency "example-gem", "~> 1.0" diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb index a2a244c220..29f78a03c4 100644 --- a/lib/bundler/version.rb +++ b/lib/bundler/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false module Bundler - VERSION = "2.4.0.dev".freeze + VERSION = "2.4.0".freeze def self.bundler_major_version @bundler_major_version ||= VERSION.split(".").first.to_i diff --git a/lib/mjit/instruction.rb b/lib/mjit/instruction.rb new file mode 100644 index 0000000000..d7b16892d5 --- /dev/null +++ b/lib/mjit/instruction.rb @@ -0,0 +1,2162 @@ +module RubyVM::MJIT + Instruction = Struct.new( + :name, + :bin, + :len, + :expr, + :declarations, + :preamble, + :opes, + :pops, + :rets, + :always_leaf?, + :leaf_without_check_ints?, + :handles_sp?, + ) + + INSNS = { + 0 => Instruction.new( + name: :nop, + bin: 0, # BIN(nop) + len: 1, # insn_len + expr: <<-EXPR, +{ + /* none */ +} + EXPR + declarations: [], + preamble: [], + opes: [], + pops: [], + rets: [], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 1 => Instruction.new( + name: :getlocal, + bin: 1, # BIN(getlocal) + len: 3, # insn_len + expr: <<-EXPR, +{ + val = *(vm_get_ep(GET_EP(), level) - idx); + RB_DEBUG_COUNTER_INC(lvar_get); + (void)RB_DEBUG_COUNTER_INC_IF(lvar_get_dynamic, level > 0); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(lindex_t) idx", "MAYBE_UNUSED(rb_num_t) level"], + preamble: [], + opes: [{:decl=>"lindex_t idx", :type=>"lindex_t", :name=>"idx"}, {:decl=>"rb_num_t level", :type=>"rb_num_t", :name=>"level"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 2 => Instruction.new( + name: :setlocal, + bin: 2, # BIN(setlocal) + len: 3, # insn_len + expr: <<-EXPR, +{ + vm_env_write(vm_get_ep(GET_EP(), level), -(int)idx, val); + RB_DEBUG_COUNTER_INC(lvar_set); + (void)RB_DEBUG_COUNTER_INC_IF(lvar_set_dynamic, level > 0); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(lindex_t) idx", "MAYBE_UNUSED(rb_num_t) level"], + preamble: [], + opes: [{:decl=>"lindex_t idx", :type=>"lindex_t", :name=>"idx"}, {:decl=>"rb_num_t level", :type=>"rb_num_t", :name=>"level"}], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + rets: [], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 3 => Instruction.new( + name: :getblockparam, + bin: 3, # BIN(getblockparam) + len: 3, # insn_len + expr: <<-EXPR, +{ + const VALUE *ep = vm_get_ep(GET_EP(), level); + VM_ASSERT(VM_ENV_LOCAL_P(ep)); + + if (!VM_ENV_FLAGS(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM)) { + val = rb_vm_bh_to_procval(ec, VM_ENV_BLOCK_HANDLER(ep)); + vm_env_write(ep, -(int)idx, val); + VM_ENV_FLAGS_SET(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM); + } + else { + val = *(ep - idx); + RB_DEBUG_COUNTER_INC(lvar_get); + (void)RB_DEBUG_COUNTER_INC_IF(lvar_get_dynamic, level > 0); + } +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(lindex_t) idx", "MAYBE_UNUSED(rb_num_t) level"], + preamble: [], + opes: [{:decl=>"lindex_t idx", :type=>"lindex_t", :name=>"idx"}, {:decl=>"rb_num_t level", :type=>"rb_num_t", :name=>"level"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 4 => Instruction.new( + name: :setblockparam, + bin: 4, # BIN(setblockparam) + len: 3, # insn_len + expr: <<-EXPR, +{ + const VALUE *ep = vm_get_ep(GET_EP(), level); + VM_ASSERT(VM_ENV_LOCAL_P(ep)); + + vm_env_write(ep, -(int)idx, val); + RB_DEBUG_COUNTER_INC(lvar_set); + (void)RB_DEBUG_COUNTER_INC_IF(lvar_set_dynamic, level > 0); + + VM_ENV_FLAGS_SET(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(lindex_t) idx", "MAYBE_UNUSED(rb_num_t) level"], + preamble: [], + opes: [{:decl=>"lindex_t idx", :type=>"lindex_t", :name=>"idx"}, {:decl=>"rb_num_t level", :type=>"rb_num_t", :name=>"level"}], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + rets: [], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 5 => Instruction.new( + name: :getblockparamproxy, + bin: 5, # BIN(getblockparamproxy) + len: 3, # insn_len + expr: <<-EXPR, +{ + const VALUE *ep = vm_get_ep(GET_EP(), level); + VM_ASSERT(VM_ENV_LOCAL_P(ep)); + + if (!VM_ENV_FLAGS(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM)) { + VALUE block_handler = VM_ENV_BLOCK_HANDLER(ep); + + if (block_handler) { + switch (vm_block_handler_type(block_handler)) { + case block_handler_type_iseq: + case block_handler_type_ifunc: + val = rb_block_param_proxy; + break; + case block_handler_type_symbol: + val = rb_sym_to_proc(VM_BH_TO_SYMBOL(block_handler)); + goto INSN_LABEL(set); + case block_handler_type_proc: + val = VM_BH_TO_PROC(block_handler); + goto INSN_LABEL(set); + default: + VM_UNREACHABLE(getblockparamproxy); + } + } + else { + val = Qnil; + INSN_LABEL(set): + vm_env_write(ep, -(int)idx, val); + VM_ENV_FLAGS_SET(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM); + } + } + else { + val = *(ep - idx); + RB_DEBUG_COUNTER_INC(lvar_get); + (void)RB_DEBUG_COUNTER_INC_IF(lvar_get_dynamic, level > 0); + } +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(lindex_t) idx", "MAYBE_UNUSED(rb_num_t) level"], + preamble: [], + opes: [{:decl=>"lindex_t idx", :type=>"lindex_t", :name=>"idx"}, {:decl=>"rb_num_t level", :type=>"rb_num_t", :name=>"level"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 6 => Instruction.new( + name: :getspecial, + bin: 6, # BIN(getspecial) + len: 3, # insn_len + expr: <<-EXPR, +{ + val = vm_getspecial(ec, GET_LEP(), key, type); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(rb_num_t) key, type"], + preamble: [], + opes: [{:decl=>"rb_num_t key", :type=>"rb_num_t", :name=>"key"}, {:decl=>"rb_num_t type", :type=>"rb_num_t", :name=>"type"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 7 => Instruction.new( + name: :setspecial, + bin: 7, # BIN(setspecial) + len: 2, # insn_len + expr: <<-EXPR, +{ + lep_svar_set(ec, GET_LEP(), key, obj); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) obj", "MAYBE_UNUSED(rb_num_t) key"], + preamble: [], + opes: [{:decl=>"rb_num_t key", :type=>"rb_num_t", :name=>"key"}], + pops: [{:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 8 => Instruction.new( + name: :getinstancevariable, + bin: 8, # BIN(getinstancevariable) + len: 3, # insn_len + expr: <<-EXPR, +{ + val = vm_getinstancevariable(GET_ISEQ(), GET_SELF(), id, ic); +} + EXPR + declarations: ["MAYBE_UNUSED(ID) id", "MAYBE_UNUSED(IVC) ic", "MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"ID id", :type=>"ID", :name=>"id"}, {:decl=>"IVC ic", :type=>"IVC", :name=>"ic"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 9 => Instruction.new( + name: :setinstancevariable, + bin: 9, # BIN(setinstancevariable) + len: 3, # insn_len + expr: <<-EXPR, +{ + vm_setinstancevariable(GET_ISEQ(), GET_SELF(), id, val, ic); +} + EXPR + declarations: ["MAYBE_UNUSED(ID) id", "MAYBE_UNUSED(IVC) ic", "MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"ID id", :type=>"ID", :name=>"id"}, {:decl=>"IVC ic", :type=>"IVC", :name=>"ic"}], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + rets: [], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 10 => Instruction.new( + name: :getclassvariable, + bin: 10, # BIN(getclassvariable) + len: 3, # insn_len + expr: <<-EXPR, +{ + rb_control_frame_t *cfp = GET_CFP(); + val = vm_getclassvariable(GET_ISEQ(), cfp, id, ic); +} + EXPR + declarations: ["MAYBE_UNUSED(ICVARC) ic", "MAYBE_UNUSED(ID) id", "MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"ID id", :type=>"ID", :name=>"id"}, {:decl=>"ICVARC ic", :type=>"ICVARC", :name=>"ic"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 11 => Instruction.new( + name: :setclassvariable, + bin: 11, # BIN(setclassvariable) + len: 3, # insn_len + expr: <<-EXPR, +{ + vm_ensure_not_refinement_module(GET_SELF()); + vm_setclassvariable(GET_ISEQ(), GET_CFP(), id, val, ic); +} + EXPR + declarations: ["MAYBE_UNUSED(ICVARC) ic", "MAYBE_UNUSED(ID) id", "MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"ID id", :type=>"ID", :name=>"id"}, {:decl=>"ICVARC ic", :type=>"ICVARC", :name=>"ic"}], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + rets: [], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 12 => Instruction.new( + name: :opt_getconstant_path, + bin: 12, # BIN(opt_getconstant_path) + len: 2, # insn_len + expr: <<-EXPR, +{ + const ID *segments = ic->segments; + struct iseq_inline_constant_cache_entry *ice = ic->entry; + if (ice && vm_ic_hit_p(ice, GET_EP())) { + val = ice->value; + + VM_ASSERT(val == vm_get_ev_const_chain(ec, segments)); + } else { + ruby_vm_constant_cache_misses++; + val = vm_get_ev_const_chain(ec, segments); + vm_ic_track_const_chain(GET_CFP(), ic, segments); + // Because leaf=false, we need to undo the PC increment to get the address to this instruction + // INSN_ATTR(width) == 2 + vm_ic_update(GET_ISEQ(), ic, val, GET_EP(), GET_PC() - 2); + } +} + EXPR + declarations: ["MAYBE_UNUSED(IC) ic", "MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"IC ic", :type=>"IC", :name=>"ic"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 13 => Instruction.new( + name: :getconstant, + bin: 13, # BIN(getconstant) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_get_ev_const(ec, klass, id, allow_nil == Qtrue, 0); +} + EXPR + declarations: ["MAYBE_UNUSED(ID) id", "MAYBE_UNUSED(VALUE) allow_nil, klass, val"], + preamble: [], + opes: [{:decl=>"ID id", :type=>"ID", :name=>"id"}], + pops: [{:decl=>"VALUE klass", :type=>"VALUE", :name=>"klass"}, {:decl=>"VALUE allow_nil", :type=>"VALUE", :name=>"allow_nil"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 14 => Instruction.new( + name: :setconstant, + bin: 14, # BIN(setconstant) + len: 2, # insn_len + expr: <<-EXPR, +{ + vm_check_if_namespace(cbase); + vm_ensure_not_refinement_module(GET_SELF()); + rb_const_set(cbase, id, val); +} + EXPR + declarations: ["MAYBE_UNUSED(ID) id", "MAYBE_UNUSED(VALUE) cbase, val"], + preamble: [], + opes: [{:decl=>"ID id", :type=>"ID", :name=>"id"}], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}, {:decl=>"VALUE cbase", :type=>"VALUE", :name=>"cbase"}], + rets: [], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 15 => Instruction.new( + name: :getglobal, + bin: 15, # BIN(getglobal) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = rb_gvar_get(gid); +} + EXPR + declarations: ["MAYBE_UNUSED(ID) gid", "MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"ID gid", :type=>"ID", :name=>"gid"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 16 => Instruction.new( + name: :setglobal, + bin: 16, # BIN(setglobal) + len: 2, # insn_len + expr: <<-EXPR, +{ + rb_gvar_set(gid, val); +} + EXPR + declarations: ["MAYBE_UNUSED(ID) gid", "MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"ID gid", :type=>"ID", :name=>"gid"}], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + rets: [], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 17 => Instruction.new( + name: :putnil, + bin: 17, # BIN(putnil) + len: 1, # insn_len + expr: <<-EXPR, +{ + val = Qnil; +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 18 => Instruction.new( + name: :putself, + bin: 18, # BIN(putself) + len: 1, # insn_len + expr: <<-EXPR, +{ + val = GET_SELF(); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 19 => Instruction.new( + name: :putobject, + bin: 19, # BIN(putobject) + len: 2, # insn_len + expr: <<-EXPR, +{ + /* */ +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 20 => Instruction.new( + name: :putspecialobject, + bin: 20, # BIN(putspecialobject) + len: 2, # insn_len + expr: <<-EXPR, +{ + enum vm_special_object_type type; + + type = (enum vm_special_object_type)value_type; + val = vm_get_special_object(GET_EP(), type); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(rb_num_t) value_type"], + preamble: [], + opes: [{:decl=>"rb_num_t value_type", :type=>"rb_num_t", :name=>"value_type"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 21 => Instruction.new( + name: :putstring, + bin: 21, # BIN(putstring) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = rb_ec_str_resurrect(ec, str); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) str, val"], + preamble: [], + opes: [{:decl=>"VALUE str", :type=>"VALUE", :name=>"str"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 22 => Instruction.new( + name: :concatstrings, + bin: 22, # BIN(concatstrings) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = rb_str_concat_literals(num, STACK_ADDR_FROM_TOP(num)); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(rb_num_t) num"], + preamble: [], + opes: [{:decl=>"rb_num_t num", :type=>"rb_num_t", :name=>"num"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 23 => Instruction.new( + name: :anytostring, + bin: 23, # BIN(anytostring) + len: 1, # insn_len + expr: <<-EXPR, +{ + val = rb_obj_as_string_result(str, val); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) str, val"], + preamble: [], + opes: [], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}, {:decl=>"VALUE str", :type=>"VALUE", :name=>"str"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 24 => Instruction.new( + name: :toregexp, + bin: 24, # BIN(toregexp) + len: 3, # insn_len + expr: <<-EXPR, +{ + const VALUE ary = rb_ary_tmp_new_from_values(0, cnt, STACK_ADDR_FROM_TOP(cnt)); + val = rb_reg_new_ary(ary, (int)opt); + rb_ary_clear(ary); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(rb_num_t) cnt, opt"], + preamble: [], + opes: [{:decl=>"rb_num_t opt", :type=>"rb_num_t", :name=>"opt"}, {:decl=>"rb_num_t cnt", :type=>"rb_num_t", :name=>"cnt"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 25 => Instruction.new( + name: :intern, + bin: 25, # BIN(intern) + len: 1, # insn_len + expr: <<-EXPR, +{ + sym = rb_str_intern(str); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) str, sym"], + preamble: [], + opes: [], + pops: [{:decl=>"VALUE str", :type=>"VALUE", :name=>"str"}], + rets: [{:decl=>"VALUE sym", :type=>"VALUE", :name=>"sym"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 26 => Instruction.new( + name: :newarray, + bin: 26, # BIN(newarray) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = rb_ec_ary_new_from_values(ec, num, STACK_ADDR_FROM_TOP(num)); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(rb_num_t) num"], + preamble: [], + opes: [{:decl=>"rb_num_t num", :type=>"rb_num_t", :name=>"num"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 27 => Instruction.new( + name: :newarraykwsplat, + bin: 27, # BIN(newarraykwsplat) + len: 2, # insn_len + expr: <<-EXPR, +{ + if (RHASH_EMPTY_P(*STACK_ADDR_FROM_TOP(1))) { + val = rb_ary_new4(num-1, STACK_ADDR_FROM_TOP(num)); + } + else { + val = rb_ary_new4(num, STACK_ADDR_FROM_TOP(num)); + } +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(rb_num_t) num"], + preamble: [], + opes: [{:decl=>"rb_num_t num", :type=>"rb_num_t", :name=>"num"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 28 => Instruction.new( + name: :duparray, + bin: 28, # BIN(duparray) + len: 2, # insn_len + expr: <<-EXPR, +{ + RUBY_DTRACE_CREATE_HOOK(ARRAY, RARRAY_LEN(ary)); + val = rb_ary_resurrect(ary); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) ary, val"], + preamble: [], + opes: [{:decl=>"VALUE ary", :type=>"VALUE", :name=>"ary"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 29 => Instruction.new( + name: :duphash, + bin: 29, # BIN(duphash) + len: 2, # insn_len + expr: <<-EXPR, +{ + RUBY_DTRACE_CREATE_HOOK(HASH, RHASH_SIZE(hash) << 1); + val = rb_hash_resurrect(hash); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) hash, val"], + preamble: [], + opes: [{:decl=>"VALUE hash", :type=>"VALUE", :name=>"hash"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 30 => Instruction.new( + name: :expandarray, + bin: 30, # BIN(expandarray) + len: 3, # insn_len + expr: <<-EXPR, +{ + vm_expandarray(GET_SP(), ary, num, (int)flag); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) ary", "MAYBE_UNUSED(rb_num_t) flag, num"], + preamble: [], + opes: [{:decl=>"rb_num_t num", :type=>"rb_num_t", :name=>"num"}, {:decl=>"rb_num_t flag", :type=>"rb_num_t", :name=>"flag"}], + pops: [{:decl=>"VALUE ary", :type=>"VALUE", :name=>"ary"}], + rets: [], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 31 => Instruction.new( + name: :concatarray, + bin: 31, # BIN(concatarray) + len: 1, # insn_len + expr: <<-EXPR, +{ + ary = vm_concat_array(ary1, ary2); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) ary, ary1, ary2"], + preamble: [], + opes: [], + pops: [{:decl=>"VALUE ary1", :type=>"VALUE", :name=>"ary1"}, {:decl=>"VALUE ary2", :type=>"VALUE", :name=>"ary2"}], + rets: [{:decl=>"VALUE ary", :type=>"VALUE", :name=>"ary"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 32 => Instruction.new( + name: :splatarray, + bin: 32, # BIN(splatarray) + len: 2, # insn_len + expr: <<-EXPR, +{ + obj = vm_splat_array(flag, ary); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) ary, flag, obj"], + preamble: [], + opes: [{:decl=>"VALUE flag", :type=>"VALUE", :name=>"flag"}], + pops: [{:decl=>"VALUE ary", :type=>"VALUE", :name=>"ary"}], + rets: [{:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 33 => Instruction.new( + name: :newhash, + bin: 33, # BIN(newhash) + len: 2, # insn_len + expr: <<-EXPR, +{ + RUBY_DTRACE_CREATE_HOOK(HASH, num); + + if (num) { + val = rb_hash_new_with_size(num / 2); + rb_hash_bulk_insert(num, STACK_ADDR_FROM_TOP(num), val); + } + else { + val = rb_hash_new(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(rb_num_t) num"], + preamble: [], + opes: [{:decl=>"rb_num_t num", :type=>"rb_num_t", :name=>"num"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 34 => Instruction.new( + name: :newrange, + bin: 34, # BIN(newrange) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = rb_range_new(low, high, (int)flag); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) high, low, val", "MAYBE_UNUSED(rb_num_t) flag"], + preamble: [], + opes: [{:decl=>"rb_num_t flag", :type=>"rb_num_t", :name=>"flag"}], + pops: [{:decl=>"VALUE low", :type=>"VALUE", :name=>"low"}, {:decl=>"VALUE high", :type=>"VALUE", :name=>"high"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 35 => Instruction.new( + name: :pop, + bin: 35, # BIN(pop) + len: 1, # insn_len + expr: <<-EXPR, +{ + (void)val; + /* none */ +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + rets: [], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 36 => Instruction.new( + name: :dup, + bin: 36, # BIN(dup) + len: 1, # insn_len + expr: <<-EXPR, +{ + val1 = val2 = val; +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val, val1, val2"], + preamble: [], + opes: [], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + rets: [{:decl=>"VALUE val1", :type=>"VALUE", :name=>"val1"}, {:decl=>"VALUE val2", :type=>"VALUE", :name=>"val2"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 37 => Instruction.new( + name: :dupn, + bin: 37, # BIN(dupn) + len: 2, # insn_len + expr: <<-EXPR, +{ + void *dst = GET_SP(); + void *src = STACK_ADDR_FROM_TOP(n); + + MEMCPY(dst, src, VALUE, n); +} + EXPR + declarations: ["MAYBE_UNUSED(rb_num_t) n"], + preamble: [], + opes: [{:decl=>"rb_num_t n", :type=>"rb_num_t", :name=>"n"}], + pops: [], + rets: [], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 38 => Instruction.new( + name: :swap, + bin: 38, # BIN(swap) + len: 1, # insn_len + expr: <<-EXPR, +{ + /* none */ +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) obj, val"], + preamble: [], + opes: [], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [{:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}, {:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 39 => Instruction.new( + name: :opt_reverse, + bin: 39, # BIN(opt_reverse) + len: 2, # insn_len + expr: <<-EXPR, +{ + rb_num_t i; + VALUE *sp = STACK_ADDR_FROM_TOP(n); + + for (i=0; i<n/2; i++) { + VALUE v0 = sp[i]; + VALUE v1 = TOPN(i); + sp[i] = v1; + TOPN(i) = v0; + } +} + EXPR + declarations: ["MAYBE_UNUSED(rb_num_t) n"], + preamble: [], + opes: [{:decl=>"rb_num_t n", :type=>"rb_num_t", :name=>"n"}], + pops: [], + rets: [], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 40 => Instruction.new( + name: :topn, + bin: 40, # BIN(topn) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = TOPN(n); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(rb_num_t) n"], + preamble: [], + opes: [{:decl=>"rb_num_t n", :type=>"rb_num_t", :name=>"n"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 41 => Instruction.new( + name: :setn, + bin: 41, # BIN(setn) + len: 2, # insn_len + expr: <<-EXPR, +{ + TOPN(n) = val; +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(rb_num_t) n"], + preamble: [], + opes: [{:decl=>"rb_num_t n", :type=>"rb_num_t", :name=>"n"}], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 42 => Instruction.new( + name: :adjuststack, + bin: 42, # BIN(adjuststack) + len: 2, # insn_len + expr: <<-EXPR, +{ + /* none */ +} + EXPR + declarations: ["MAYBE_UNUSED(rb_num_t) n"], + preamble: [], + opes: [{:decl=>"rb_num_t n", :type=>"rb_num_t", :name=>"n"}], + pops: [], + rets: [], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 43 => Instruction.new( + name: :defined, + bin: 43, # BIN(defined) + len: 4, # insn_len + expr: <<-EXPR, +{ + val = Qnil; + if (vm_defined(ec, GET_CFP(), op_type, obj, v)) { + val = pushval; + } +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) obj, pushval, v, val", "MAYBE_UNUSED(rb_num_t) op_type"], + preamble: [], + opes: [{:decl=>"rb_num_t op_type", :type=>"rb_num_t", :name=>"op_type"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}, {:decl=>"VALUE pushval", :type=>"VALUE", :name=>"pushval"}], + pops: [{:decl=>"VALUE v", :type=>"VALUE", :name=>"v"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 44 => Instruction.new( + name: :checkmatch, + bin: 44, # BIN(checkmatch) + len: 2, # insn_len + expr: <<-EXPR, +{ + result = vm_check_match(ec, target, pattern, flag); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) pattern, result, target", "MAYBE_UNUSED(rb_num_t) flag"], + preamble: [], + opes: [{:decl=>"rb_num_t flag", :type=>"rb_num_t", :name=>"flag"}], + pops: [{:decl=>"VALUE target", :type=>"VALUE", :name=>"target"}, {:decl=>"VALUE pattern", :type=>"VALUE", :name=>"pattern"}], + rets: [{:decl=>"VALUE result", :type=>"VALUE", :name=>"result"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 45 => Instruction.new( + name: :checkkeyword, + bin: 45, # BIN(checkkeyword) + len: 3, # insn_len + expr: <<-EXPR, +{ + ret = vm_check_keyword(kw_bits_index, keyword_index, GET_EP()); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) ret", "MAYBE_UNUSED(lindex_t) keyword_index, kw_bits_index"], + preamble: [], + opes: [{:decl=>"lindex_t kw_bits_index", :type=>"lindex_t", :name=>"kw_bits_index"}, {:decl=>"lindex_t keyword_index", :type=>"lindex_t", :name=>"keyword_index"}], + pops: [], + rets: [{:decl=>"VALUE ret", :type=>"VALUE", :name=>"ret"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 46 => Instruction.new( + name: :checktype, + bin: 46, # BIN(checktype) + len: 2, # insn_len + expr: <<-EXPR, +{ + ret = RBOOL(TYPE(val) == (int)type); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) ret, val", "MAYBE_UNUSED(rb_num_t) type"], + preamble: [], + opes: [{:decl=>"rb_num_t type", :type=>"rb_num_t", :name=>"type"}], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + rets: [{:decl=>"VALUE ret", :type=>"VALUE", :name=>"ret"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 47 => Instruction.new( + name: :defineclass, + bin: 47, # BIN(defineclass) + len: 4, # insn_len + expr: <<-EXPR, +{ + VALUE klass = vm_find_or_create_class_by_id(id, flags, cbase, super); + + rb_iseq_check(class_iseq); + + /* enter scope */ + vm_push_frame(ec, class_iseq, VM_FRAME_MAGIC_CLASS | VM_ENV_FLAG_LOCAL, klass, + GET_BLOCK_HANDLER(), + (VALUE)vm_cref_push(ec, klass, NULL, FALSE, FALSE), + ISEQ_BODY(class_iseq)->iseq_encoded, GET_SP(), + ISEQ_BODY(class_iseq)->local_table_size, + ISEQ_BODY(class_iseq)->stack_max); + RESTORE_REGS(); + NEXT_INSN(); +} + EXPR + declarations: ["MAYBE_UNUSED(ID) id", "MAYBE_UNUSED(ISEQ) class_iseq", "MAYBE_UNUSED(VALUE) cbase, super, val", "MAYBE_UNUSED(rb_num_t) flags"], + preamble: [], + opes: [{:decl=>"ID id", :type=>"ID", :name=>"id"}, {:decl=>"ISEQ class_iseq", :type=>"ISEQ", :name=>"class_iseq"}, {:decl=>"rb_num_t flags", :type=>"rb_num_t", :name=>"flags"}], + pops: [{:decl=>"VALUE cbase", :type=>"VALUE", :name=>"cbase"}, {:decl=>"VALUE super", :type=>"VALUE", :name=>"super"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: true, + ), + 48 => Instruction.new( + name: :definemethod, + bin: 48, # BIN(definemethod) + len: 3, # insn_len + expr: <<-EXPR, +{ + vm_define_method(ec, Qnil, id, (VALUE)iseq, FALSE); +} + EXPR + declarations: ["MAYBE_UNUSED(ID) id", "MAYBE_UNUSED(ISEQ) iseq"], + preamble: [], + opes: [{:decl=>"ID id", :type=>"ID", :name=>"id"}, {:decl=>"ISEQ iseq", :type=>"ISEQ", :name=>"iseq"}], + pops: [], + rets: [], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: true, + ), + 49 => Instruction.new( + name: :definesmethod, + bin: 49, # BIN(definesmethod) + len: 3, # insn_len + expr: <<-EXPR, +{ + vm_define_method(ec, obj, id, (VALUE)iseq, TRUE); +} + EXPR + declarations: ["MAYBE_UNUSED(ID) id", "MAYBE_UNUSED(ISEQ) iseq", "MAYBE_UNUSED(VALUE) obj"], + preamble: [], + opes: [{:decl=>"ID id", :type=>"ID", :name=>"id"}, {:decl=>"ISEQ iseq", :type=>"ISEQ", :name=>"iseq"}], + pops: [{:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: true, + ), + 50 => Instruction.new( + name: :send, + bin: 50, # BIN(send) + len: 3, # insn_len + expr: <<-EXPR, +{ + VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, false); + val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method); + + if (val == Qundef) { + RESTORE_REGS(); + NEXT_INSN(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(ISEQ) blockiseq", "MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}, {:decl=>"ISEQ blockiseq", :type=>"ISEQ", :name=>"blockiseq"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: true, + ), + 51 => Instruction.new( + name: :opt_send_without_block, + bin: 51, # BIN(opt_send_without_block) + len: 2, # insn_len + expr: <<-EXPR, +{ + VALUE bh = VM_BLOCK_HANDLER_NONE; + val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method); + + if (val == Qundef) { + RESTORE_REGS(); + NEXT_INSN(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: true, + ), + 52 => Instruction.new( + name: :objtostring, + bin: 52, # BIN(objtostring) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_objtostring(GET_ISEQ(), recv, cd); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 53 => Instruction.new( + name: :opt_str_freeze, + bin: 53, # BIN(opt_str_freeze) + len: 3, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_str_freeze(str, BOP_FREEZE, idFreeze); + + if (val == Qundef) { + PUSH(rb_str_resurrect(str)); + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) str, val"], + preamble: [], + opes: [{:decl=>"VALUE str", :type=>"VALUE", :name=>"str"}, {:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 54 => Instruction.new( + name: :opt_nil_p, + bin: 54, # BIN(opt_nil_p) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_nil_p(GET_ISEQ(), cd, recv); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 55 => Instruction.new( + name: :opt_str_uminus, + bin: 55, # BIN(opt_str_uminus) + len: 3, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_str_freeze(str, BOP_UMINUS, idUMinus); + + if (val == Qundef) { + PUSH(rb_str_resurrect(str)); + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) str, val"], + preamble: [], + opes: [{:decl=>"VALUE str", :type=>"VALUE", :name=>"str"}, {:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 56 => Instruction.new( + name: :opt_newarray_max, + bin: 56, # BIN(opt_newarray_max) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_newarray_max(ec, num, STACK_ADDR_FROM_TOP(num)); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(rb_num_t) num"], + preamble: [], + opes: [{:decl=>"rb_num_t num", :type=>"rb_num_t", :name=>"num"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 57 => Instruction.new( + name: :opt_newarray_min, + bin: 57, # BIN(opt_newarray_min) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_newarray_min(ec, num, STACK_ADDR_FROM_TOP(num)); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(rb_num_t) num"], + preamble: [], + opes: [{:decl=>"rb_num_t num", :type=>"rb_num_t", :name=>"num"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 58 => Instruction.new( + name: :invokesuper, + bin: 58, # BIN(invokesuper) + len: 3, # insn_len + expr: <<-EXPR, +{ + VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, true); + val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_super); + + if (val == Qundef) { + RESTORE_REGS(); + NEXT_INSN(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(ISEQ) blockiseq", "MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}, {:decl=>"ISEQ blockiseq", :type=>"ISEQ", :name=>"blockiseq"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: true, + ), + 59 => Instruction.new( + name: :invokeblock, + bin: 59, # BIN(invokeblock) + len: 2, # insn_len + expr: <<-EXPR, +{ + VALUE bh = VM_BLOCK_HANDLER_NONE; + val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_invokeblock); + + if (val == Qundef) { + RESTORE_REGS(); + NEXT_INSN(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: true, + ), + 60 => Instruction.new( + name: :leave, + bin: 60, # BIN(leave) + len: 1, # insn_len + expr: <<-EXPR, +{ + if (OPT_CHECKED_RUN) { + const VALUE *const bp = vm_base_ptr(GET_CFP()); + if (GET_SP() != bp) { + vm_stack_consistency_error(ec, GET_CFP(), bp); + } + } + + if (vm_pop_frame(ec, GET_CFP(), GET_EP())) { +#if OPT_CALL_THREADED_CODE + rb_ec_thread_ptr(ec)->retval = val; + return 0; +#else + return val; +#endif + } + else { + RESTORE_REGS(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: true, + ), + 61 => Instruction.new( + name: :throw, + bin: 61, # BIN(throw) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_throw(ec, GET_CFP(), throw_state, throwobj); + THROW_EXCEPTION(val); + /* unreachable */ +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) throwobj, val", "MAYBE_UNUSED(rb_num_t) throw_state"], + preamble: [], + opes: [{:decl=>"rb_num_t throw_state", :type=>"rb_num_t", :name=>"throw_state"}], + pops: [{:decl=>"VALUE throwobj", :type=>"VALUE", :name=>"throwobj"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 62 => Instruction.new( + name: :jump, + bin: 62, # BIN(jump) + len: 2, # insn_len + expr: <<-EXPR, +{ + RUBY_VM_CHECK_INTS(ec); + JUMP(dst); +} + EXPR + declarations: ["MAYBE_UNUSED(OFFSET) dst"], + preamble: [], + opes: [{:decl=>"OFFSET dst", :type=>"OFFSET", :name=>"dst"}], + pops: [], + rets: [], + always_leaf?: false, + leaf_without_check_ints?: true, + handles_sp?: false, + ), + 63 => Instruction.new( + name: :branchif, + bin: 63, # BIN(branchif) + len: 2, # insn_len + expr: <<-EXPR, +{ + if (RTEST(val)) { + RUBY_VM_CHECK_INTS(ec); + JUMP(dst); + } +} + EXPR + declarations: ["MAYBE_UNUSED(OFFSET) dst", "MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"OFFSET dst", :type=>"OFFSET", :name=>"dst"}], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + rets: [], + always_leaf?: false, + leaf_without_check_ints?: true, + handles_sp?: false, + ), + 64 => Instruction.new( + name: :branchunless, + bin: 64, # BIN(branchunless) + len: 2, # insn_len + expr: <<-EXPR, +{ + if (!RTEST(val)) { + RUBY_VM_CHECK_INTS(ec); + JUMP(dst); + } +} + EXPR + declarations: ["MAYBE_UNUSED(OFFSET) dst", "MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"OFFSET dst", :type=>"OFFSET", :name=>"dst"}], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + rets: [], + always_leaf?: false, + leaf_without_check_ints?: true, + handles_sp?: false, + ), + 65 => Instruction.new( + name: :branchnil, + bin: 65, # BIN(branchnil) + len: 2, # insn_len + expr: <<-EXPR, +{ + if (NIL_P(val)) { + RUBY_VM_CHECK_INTS(ec); + JUMP(dst); + } +} + EXPR + declarations: ["MAYBE_UNUSED(OFFSET) dst", "MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"OFFSET dst", :type=>"OFFSET", :name=>"dst"}], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + rets: [], + always_leaf?: false, + leaf_without_check_ints?: true, + handles_sp?: false, + ), + 66 => Instruction.new( + name: :once, + bin: 66, # BIN(once) + len: 3, # insn_len + expr: <<-EXPR, +{ + val = vm_once_dispatch(ec, iseq, ise); +} + EXPR + declarations: ["MAYBE_UNUSED(ISE) ise", "MAYBE_UNUSED(ISEQ) iseq", "MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"ISEQ iseq", :type=>"ISEQ", :name=>"iseq"}, {:decl=>"ISE ise", :type=>"ISE", :name=>"ise"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: true, + ), + 67 => Instruction.new( + name: :opt_case_dispatch, + bin: 67, # BIN(opt_case_dispatch) + len: 3, # insn_len + expr: <<-EXPR, +{ + OFFSET dst = vm_case_dispatch(hash, else_offset, key); + + if (dst) { + JUMP(dst); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CDHASH) hash", "MAYBE_UNUSED(OFFSET) else_offset", "MAYBE_UNUSED(VALUE) key"], + preamble: [], + opes: [{:decl=>"CDHASH hash", :type=>"CDHASH", :name=>"hash"}, {:decl=>"OFFSET else_offset", :type=>"OFFSET", :name=>"else_offset"}], + pops: [{:decl=>"VALUE key", :type=>"VALUE", :name=>"key"}], + rets: [], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 68 => Instruction.new( + name: :opt_plus, + bin: 68, # BIN(opt_plus) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_plus(recv, obj); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) obj, recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 69 => Instruction.new( + name: :opt_minus, + bin: 69, # BIN(opt_minus) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_minus(recv, obj); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) obj, recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 70 => Instruction.new( + name: :opt_mult, + bin: 70, # BIN(opt_mult) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_mult(recv, obj); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) obj, recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 71 => Instruction.new( + name: :opt_div, + bin: 71, # BIN(opt_div) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_div(recv, obj); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) obj, recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 72 => Instruction.new( + name: :opt_mod, + bin: 72, # BIN(opt_mod) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_mod(recv, obj); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) obj, recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 73 => Instruction.new( + name: :opt_eq, + bin: 73, # BIN(opt_eq) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = opt_equality(GET_ISEQ(), recv, obj, cd); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) obj, recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 74 => Instruction.new( + name: :opt_neq, + bin: 74, # BIN(opt_neq) + len: 3, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_neq(GET_ISEQ(), cd, cd_eq, recv, obj); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd, cd_eq", "MAYBE_UNUSED(VALUE) obj, recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd_eq", :type=>"CALL_DATA", :name=>"cd_eq"}, {:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 75 => Instruction.new( + name: :opt_lt, + bin: 75, # BIN(opt_lt) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_lt(recv, obj); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) obj, recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 76 => Instruction.new( + name: :opt_le, + bin: 76, # BIN(opt_le) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_le(recv, obj); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) obj, recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 77 => Instruction.new( + name: :opt_gt, + bin: 77, # BIN(opt_gt) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_gt(recv, obj); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) obj, recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 78 => Instruction.new( + name: :opt_ge, + bin: 78, # BIN(opt_ge) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_ge(recv, obj); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) obj, recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 79 => Instruction.new( + name: :opt_ltlt, + bin: 79, # BIN(opt_ltlt) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_ltlt(recv, obj); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) obj, recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 80 => Instruction.new( + name: :opt_and, + bin: 80, # BIN(opt_and) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_and(recv, obj); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) obj, recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 81 => Instruction.new( + name: :opt_or, + bin: 81, # BIN(opt_or) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_or(recv, obj); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) obj, recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 82 => Instruction.new( + name: :opt_aref, + bin: 82, # BIN(opt_aref) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_aref(recv, obj); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) obj, recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 83 => Instruction.new( + name: :opt_aset, + bin: 83, # BIN(opt_aset) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_aset(recv, obj, set); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) obj, recv, set, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE obj", :type=>"VALUE", :name=>"obj"}, {:decl=>"VALUE set", :type=>"VALUE", :name=>"set"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 84 => Instruction.new( + name: :opt_aset_with, + bin: 84, # BIN(opt_aset_with) + len: 3, # insn_len + expr: <<-EXPR, +{ + VALUE tmp = vm_opt_aset_with(recv, key, val); + + if (tmp != Qundef) { + val = tmp; + } + else { +#ifndef MJIT_HEADER + TOPN(0) = rb_str_resurrect(key); + PUSH(val); +#endif + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) key, recv, val"], + preamble: [], + opes: [{:decl=>"VALUE key", :type=>"VALUE", :name=>"key"}, {:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}, {:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 85 => Instruction.new( + name: :opt_aref_with, + bin: 85, # BIN(opt_aref_with) + len: 3, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_aref_with(recv, key); + + if (val == Qundef) { +#ifndef MJIT_HEADER + PUSH(rb_str_resurrect(key)); +#endif + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) key, recv, val"], + preamble: [], + opes: [{:decl=>"VALUE key", :type=>"VALUE", :name=>"key"}, {:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 86 => Instruction.new( + name: :opt_length, + bin: 86, # BIN(opt_length) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_length(recv, BOP_LENGTH); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 87 => Instruction.new( + name: :opt_size, + bin: 87, # BIN(opt_size) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_length(recv, BOP_SIZE); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 88 => Instruction.new( + name: :opt_empty_p, + bin: 88, # BIN(opt_empty_p) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_empty_p(recv); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 89 => Instruction.new( + name: :opt_succ, + bin: 89, # BIN(opt_succ) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_succ(recv); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 90 => Instruction.new( + name: :opt_not, + bin: 90, # BIN(opt_not) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_not(GET_ISEQ(), cd, recv); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) recv, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE recv", :type=>"VALUE", :name=>"recv"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 91 => Instruction.new( + name: :opt_regexpmatch2, + bin: 91, # BIN(opt_regexpmatch2) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_opt_regexpmatch2(obj2, obj1); + + if (val == Qundef) { + CALL_SIMPLE_METHOD(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(CALL_DATA) cd", "MAYBE_UNUSED(VALUE) obj1, obj2, val"], + preamble: [], + opes: [{:decl=>"CALL_DATA cd", :type=>"CALL_DATA", :name=>"cd"}], + pops: [{:decl=>"VALUE obj2", :type=>"VALUE", :name=>"obj2"}, {:decl=>"VALUE obj1", :type=>"VALUE", :name=>"obj1"}], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 92 => Instruction.new( + name: :invokebuiltin, + bin: 92, # BIN(invokebuiltin) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = vm_invoke_builtin(ec, reg_cfp, bf, STACK_ADDR_FROM_TOP(bf->argc)); +} + EXPR + declarations: ["MAYBE_UNUSED(RB_BUILTIN) bf", "MAYBE_UNUSED(VALUE) val"], + preamble: [], + opes: [{:decl=>"RB_BUILTIN bf", :type=>"RB_BUILTIN", :name=>"bf"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 93 => Instruction.new( + name: :opt_invokebuiltin_delegate, + bin: 93, # BIN(opt_invokebuiltin_delegate) + len: 3, # insn_len + expr: <<-EXPR, +{ + val = vm_invoke_builtin_delegate(ec, reg_cfp, bf, (unsigned int)index); +} + EXPR + declarations: ["MAYBE_UNUSED(RB_BUILTIN) bf", "MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(rb_num_t) index"], + preamble: [], + opes: [{:decl=>"RB_BUILTIN bf", :type=>"RB_BUILTIN", :name=>"bf"}, {:decl=>"rb_num_t index", :type=>"rb_num_t", :name=>"index"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 94 => Instruction.new( + name: :opt_invokebuiltin_delegate_leave, + bin: 94, # BIN(opt_invokebuiltin_delegate_leave) + len: 3, # insn_len + expr: <<-EXPR, +{ + val = vm_invoke_builtin_delegate(ec, reg_cfp, bf, (unsigned int)index); + + /* leave fastpath */ + /* TracePoint/return fallbacks this insn to opt_invokebuiltin_delegate */ + if (vm_pop_frame(ec, GET_CFP(), GET_EP())) { +#if OPT_CALL_THREADED_CODE + rb_ec_thread_ptr(ec)->retval = val; + return 0; +#else + return val; +#endif + } + else { + RESTORE_REGS(); + } +} + EXPR + declarations: ["MAYBE_UNUSED(RB_BUILTIN) bf", "MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(rb_num_t) index"], + preamble: [], + opes: [{:decl=>"RB_BUILTIN bf", :type=>"RB_BUILTIN", :name=>"bf"}, {:decl=>"rb_num_t index", :type=>"rb_num_t", :name=>"index"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: false, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 95 => Instruction.new( + name: :getlocal_WC_0, + bin: 95, # BIN(getlocal_WC_0) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = *(vm_get_ep(GET_EP(), level) - idx); + RB_DEBUG_COUNTER_INC(lvar_get); + (void)RB_DEBUG_COUNTER_INC_IF(lvar_get_dynamic, level > 0); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(lindex_t) idx", "MAYBE_UNUSED(rb_num_t) level"], + preamble: [" const rb_num_t level = 0;"], + opes: [{:decl=>"lindex_t idx", :type=>"lindex_t", :name=>"idx"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 96 => Instruction.new( + name: :getlocal_WC_1, + bin: 96, # BIN(getlocal_WC_1) + len: 2, # insn_len + expr: <<-EXPR, +{ + val = *(vm_get_ep(GET_EP(), level) - idx); + RB_DEBUG_COUNTER_INC(lvar_get); + (void)RB_DEBUG_COUNTER_INC_IF(lvar_get_dynamic, level > 0); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(lindex_t) idx", "MAYBE_UNUSED(rb_num_t) level"], + preamble: [" const rb_num_t level = 1;"], + opes: [{:decl=>"lindex_t idx", :type=>"lindex_t", :name=>"idx"}], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 97 => Instruction.new( + name: :setlocal_WC_0, + bin: 97, # BIN(setlocal_WC_0) + len: 2, # insn_len + expr: <<-EXPR, +{ + vm_env_write(vm_get_ep(GET_EP(), level), -(int)idx, val); + RB_DEBUG_COUNTER_INC(lvar_set); + (void)RB_DEBUG_COUNTER_INC_IF(lvar_set_dynamic, level > 0); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(lindex_t) idx", "MAYBE_UNUSED(rb_num_t) level"], + preamble: [" const rb_num_t level = 0;"], + opes: [{:decl=>"lindex_t idx", :type=>"lindex_t", :name=>"idx"}], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + rets: [], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 98 => Instruction.new( + name: :setlocal_WC_1, + bin: 98, # BIN(setlocal_WC_1) + len: 2, # insn_len + expr: <<-EXPR, +{ + vm_env_write(vm_get_ep(GET_EP(), level), -(int)idx, val); + RB_DEBUG_COUNTER_INC(lvar_set); + (void)RB_DEBUG_COUNTER_INC_IF(lvar_set_dynamic, level > 0); +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val", "MAYBE_UNUSED(lindex_t) idx", "MAYBE_UNUSED(rb_num_t) level"], + preamble: [" const rb_num_t level = 1;"], + opes: [{:decl=>"lindex_t idx", :type=>"lindex_t", :name=>"idx"}], + pops: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + rets: [], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 99 => Instruction.new( + name: :putobject_INT2FIX_0_, + bin: 99, # BIN(putobject_INT2FIX_0_) + len: 1, # insn_len + expr: <<-EXPR, +{ + /* */ +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val"], + preamble: [" const VALUE val = INT2FIX(0);"], + opes: [], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + 100 => Instruction.new( + name: :putobject_INT2FIX_1_, + bin: 100, # BIN(putobject_INT2FIX_1_) + len: 1, # insn_len + expr: <<-EXPR, +{ + /* */ +} + EXPR + declarations: ["MAYBE_UNUSED(VALUE) val"], + preamble: [" const VALUE val = INT2FIX(1);"], + opes: [], + pops: [], + rets: [{:decl=>"VALUE val", :type=>"VALUE", :name=>"val"}], + always_leaf?: true, + leaf_without_check_ints?: false, + handles_sp?: false, + ), + } + + private_constant(*constants) +end diff --git a/lib/rubygems.rb b/lib/rubygems.rb index 0c0ca9c1ba..56e47ca351 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -8,7 +8,7 @@ require "rbconfig" module Gem - VERSION = "3.4.0.dev".freeze + VERSION = "3.4.0".freeze end # Must be first since it unloads the prelude from 1.9.2 @@ -1297,7 +1297,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/".freeze - autoload :BundlerVersionFinder, File.expand_path("rubygems/bundler_version_finder", __dir__) autoload :ConfigFile, File.expand_path("rubygems/config_file", __dir__) autoload :Dependency, File.expand_path("rubygems/dependency", __dir__) autoload :DependencyList, File.expand_path("rubygems/dependency_list", __dir__) diff --git a/lib/rubygems/dependency.rb b/lib/rubygems/dependency.rb index 85f8609677..7fa0f91bd4 100644 --- a/lib/rubygems/dependency.rb +++ b/lib/rubygems/dependency.rb @@ -277,7 +277,10 @@ class Gem::Dependency requirement.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version) end.map(&:to_spec) - Gem::BundlerVersionFinder.prioritize!(matches) if prioritizes_bundler? + if prioritizes_bundler? + require_relative "bundler_version_finder" + Gem::BundlerVersionFinder.prioritize!(matches) + end if platform_only matches.reject! do |spec| diff --git a/lib/rubygems/ext/cargo_builder.rb b/lib/rubygems/ext/cargo_builder.rb index 3377c9a8ad..3851e8d523 100644 --- a/lib/rubygems/ext/cargo_builder.rb +++ b/lib/rubygems/ext/cargo_builder.rb @@ -37,7 +37,8 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder def build_env build_env = rb_config_env build_env["RUBY_STATIC"] = "true" if ruby_static? && ENV.key?("RUBY_STATIC") - build_env["RUSTFLAGS"] = "#{ENV["RUSTFLAGS"]} --cfg=rb_sys_gem".strip + cfg = "--cfg=rb_sys_gem --cfg=rubygems --cfg=rubygems_#{Gem::VERSION.tr(".", "_")}" + build_env["RUSTFLAGS"] = [ENV["RUSTFLAGS"], cfg].compact.join(" ") build_env end @@ -47,6 +48,7 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder cmd = [] cmd += [cargo, "rustc"] + cmd += ["--crate-type", "cdylib"] cmd += ["--target", ENV["CARGO_BUILD_TARGET"]] if ENV["CARGO_BUILD_TARGET"] cmd += ["--target-dir", dest_path] cmd += ["--manifest-path", manifest] @@ -103,14 +105,23 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder # We want to use the same linker that Ruby uses, so that the linker flags from # mkmf work properly. def linker_args - # Have to handle CC="cl /nologo" on mswin cc_flag = Shellwords.split(makefile_config("CC")) linker = cc_flag.shift link_args = cc_flag.flat_map {|a| ["-C", "link-arg=#{a}"] } + return mswin_link_args if linker == "cl" + ["-C", "linker=#{linker}", *link_args] end + def mswin_link_args + args = [] + args += ["-l", makefile_config("LIBRUBYARG_SHARED").chomp(".lib")] + args += split_flags("LIBS").flat_map {|lib| ["-l", lib.chomp(".lib")] } + args += split_flags("LOCAL_LIBS").flat_map {|lib| ["-l", lib.chomp(".lib")] } + args + end + def libruby_args(dest_dir) libs = makefile_config(ruby_static? ? "LIBRUBYARG_STATIC" : "LIBRUBYARG_SHARED") raw_libs = Shellwords.split(libs) diff --git a/lib/rubygems/ext/cargo_builder/link_flag_converter.rb b/lib/rubygems/ext/cargo_builder/link_flag_converter.rb index 111bb05492..e4d196cb10 100644 --- a/lib/rubygems/ext/cargo_builder/link_flag_converter.rb +++ b/lib/rubygems/ext/cargo_builder/link_flag_converter.rb @@ -3,20 +3,24 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder # Converts Ruby link flags into something cargo understands class LinkFlagConverter + FILTERED_PATTERNS = [ + /compress-debug-sections/, # Not supported by all linkers, and not required for Rust + ].freeze + def self.convert(arg) + return [] if FILTERED_PATTERNS.any? {|p| p.match?(arg) } + case arg.chomp when /^-L\s*(.+)$/ ["-L", "native=#{$1}"] when /^--library=(\w+\S+)$/, /^-l\s*(\w+\S+)$/ ["-l", $1] - when /^-l\s*:lib(\S+).a$/ - ["-l", "static=#{$1}"] - when /^-l\s*:lib(\S+).(so|dylib|dll)$/ - ["-l", "dylib=#{$1}"] + when /^-l\s*([^:\s])+/ # -lfoo, but not -l:libfoo.a + ["-l", $1] when /^-F\s*(.*)$/ ["-l", "framework=#{$1}"] else - ["-C", "link_arg=#{arg}"] + ["-C", "link-args=#{arg}"] end end end diff --git a/lib/rubygems/specification_policy.rb b/lib/rubygems/specification_policy.rb index 44b31211e5..f01a6cd743 100644 --- a/lib/rubygems/specification_policy.rb +++ b/lib/rubygems/specification_policy.rb @@ -460,6 +460,20 @@ http://spdx.org/licenses or '#{Gem::Licenses::NONSTANDARD}' for a nonstandard li require_relative "ext" builder = Gem::Ext::Builder.new(@specification) + validate_rake_extensions(builder) + validate_rust_extensions(builder) + end + + def validate_rust_extensions(builder) # :nodoc: + rust_extension = @specification.extensions.any? {|s| builder.builder_for(s).is_a? Gem::Ext::CargoBuilder } + missing_cargo_lock = [email protected]?("Cargo.lock") + + error <<-ERROR if rust_extension && missing_cargo_lock +You have specified rust based extension, but Cargo.lock is not part of the gem files. Please run `cargo generate-lockfile` or any other command to generate Cargo.lock and ensure it is added to your gem files section in gemspec. + ERROR + end + + def validate_rake_extensions(builder) # :nodoc: rake_extension = @specification.extensions.any? {|s| builder.builder_for(s) == Gem::Ext::RakeBuilder } rake_dependency = @specification.dependencies.any? {|d| d.name == "rake" } diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb index ed0c3dfadf..c80b9dc646 100644 --- a/spec/bundler/commands/lock_spec.rb +++ b/spec/bundler/commands/lock_spec.rb @@ -752,5 +752,94 @@ RSpec.describe "bundle lock" do version solving has failed. ERR end + + it "is able to display some explanation on crazy irresolvable cases" do + build_repo4 do + build_gem "activeadmin", "2.13.1" do |s| + s.add_dependency "ransack", "= 3.1.0" + end + + # Activemodel is missing as a dependency in lockfile + build_gem "ransack", "3.1.0" do |s| + s.add_dependency "activemodel", ">= 6.0.4" + s.add_dependency "activesupport", ">= 6.0.4" + end + + %w[6.0.4 7.0.2.3 7.0.3.1 7.0.4].each do |version| + build_gem "activesupport", version + + # Activemodel is only available on 6.0.4 + if version == "6.0.4" + build_gem "activemodel", version do |s| + s.add_dependency "activesupport", version + end + end + + build_gem "rails", version do |s| + # Depednencies of Rails 7.0.2.3 are in reverse order + if version == "7.0.2.3" + s.add_dependency "activesupport", version + s.add_dependency "activemodel", version + else + s.add_dependency "activemodel", version + s.add_dependency "activesupport", version + end + end + end + end + + gemfile <<~G + source "#{file_uri_for(gem_repo4)}" + + gem "rails", ">= 7.0.2.3" + gem "activeadmin", "= 2.13.1" + G + + lockfile <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + activeadmin (2.13.1) + ransack (= 3.1.0) + ransack (3.1.0) + activemodel (>= 6.0.4) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + activeadmin (= 2.13.1) + ransack (= 3.1.0) + + BUNDLED WITH + #{Bundler::VERSION} + L + + bundle "lock", :raise_on_error => false + + expect(err).to eq <<~ERR.strip + Could not find compatible versions + + Because every version of activemodel depends on activesupport = 6.0.4 + and rails >= 7.0.2.3, < 7.0.3.1 depends on activesupport = 7.0.2.3, + every version of activemodel is incompatible with rails >= 7.0.2.3, < 7.0.3.1. + And because rails >= 7.0.2.3, < 7.0.3.1 depends on activemodel = 7.0.2.3, + rails >= 7.0.2.3, < 7.0.3.1 is forbidden. + (1) So, because rails >= 7.0.3.1, < 7.0.4 depends on activemodel = 7.0.3.1 + and rails >= 7.0.4 depends on activemodel = 7.0.4, + rails >= 7.0.2.3 requires activemodel = 7.0.3.1 OR = 7.0.4. + + Because rails >= 7.0.2.3, < 7.0.3.1 depends on activemodel = 7.0.2.3 + and rails >= 7.0.3.1, < 7.0.4 depends on activesupport = 7.0.3.1, + rails >= 7.0.2.3, < 7.0.4 requires activemodel = 7.0.2.3 or activesupport = 7.0.3.1. + And because rails >= 7.0.4 depends on activesupport = 7.0.4 + and every version of activemodel depends on activesupport = 6.0.4, + activemodel != 7.0.2.3 is incompatible with rails >= 7.0.2.3. + And because rails >= 7.0.2.3 requires activemodel = 7.0.3.1 OR = 7.0.4 (1), + rails >= 7.0.2.3 is forbidden. + So, because Gemfile depends on rails >= 7.0.2.3, + version solving has failed. + ERR + end end end diff --git a/spec/bundler/commands/newgem_spec.rb b/spec/bundler/commands/newgem_spec.rb index 15a75577a1..5827f7380c 100644 --- a/spec/bundler/commands/newgem_spec.rb +++ b/spec/bundler/commands/newgem_spec.rb @@ -310,28 +310,28 @@ RSpec.describe "bundle gem" do expect(last_command).to be_success end - it "has no rubocop offenses when using --ext and --linter=rubocop flag", :readline do + it "has no rubocop offenses when using --ext=c and --linter=rubocop flag", :readline do skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core? bundle "gem #{gem_name} --ext=c --linter=rubocop" bundle_exec_rubocop expect(last_command).to be_success end - it "has no rubocop offenses when using --ext, --test=minitest, and --linter=rubocop flag", :readline do + it "has no rubocop offenses when using --ext=c, --test=minitest, and --linter=rubocop flag", :readline do skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core? bundle "gem #{gem_name} --ext=c --test=minitest --linter=rubocop" bundle_exec_rubocop expect(last_command).to be_success end - it "has no rubocop offenses when using --ext, --test=rspec, and --linter=rubocop flag", :readline do + it "has no rubocop offenses when using --ext=c, --test=rspec, and --linter=rubocop flag", :readline do skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core? bundle "gem #{gem_name} --ext=c --test=rspec --linter=rubocop" bundle_exec_rubocop expect(last_command).to be_success end - it "has no rubocop offenses when using --ext, --ext=test-unit, and --linter=rubocop flag", :readline do + it "has no rubocop offenses when using --ext=c, --test=test-unit, and --linter=rubocop flag", :readline do skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core? bundle "gem #{gem_name} --ext=c --test=test-unit --linter=rubocop" bundle_exec_rubocop @@ -345,6 +345,42 @@ RSpec.describe "bundle gem" do expect(last_command).to be_success end + it "has no rubocop offenses when using --ext=rust and --linter=rubocop flag", :readline do + skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core? + skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version + + bundle "gem #{gem_name} --ext=rust --linter=rubocop" + bundle_exec_rubocop + expect(last_command).to be_success + end + + it "has no rubocop offenses when using --ext=rust, --test=minitest, and --linter=rubocop flag", :readline do + skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core? + skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version + + bundle "gem #{gem_name} --ext=rust --test=minitest --linter=rubocop" + bundle_exec_rubocop + expect(last_command).to be_success + end + + it "has no rubocop offenses when using --ext=rust, --test=rspec, and --linter=rubocop flag", :readline do + skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core? + skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version + + bundle "gem #{gem_name} --ext=rust --test=rspec --linter=rubocop" + bundle_exec_rubocop + expect(last_command).to be_success + end + + it "has no rubocop offenses when using --ext=rust, --test=test-unit, and --linter=rubocop flag", :readline do + skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core? + skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version + + bundle "gem #{gem_name} --ext=rust --test=test-unit --linter=rubocop" + bundle_exec_rubocop + expect(last_command).to be_success + end + shared_examples_for "CI config is absent" do it "does not create any CI files" do expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to_not exist @@ -1336,12 +1372,15 @@ RSpec.describe "bundle gem" do context "is deprecated", :bundler => "< 3" do it "prints deprecation when used after gem name" do bundle ["gem", "--ext", gem_name].compact.join(" ") - expect(err).to include "[DEPRECATED] Option `--ext` without explicit value is deprecated." + expect(err).to include "[DEPRECATED]" + expect(err).to include "`--ext` with no arguments has been deprecated" expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist end it "prints deprecation when used before gem name" do bundle ["gem", gem_name, "--ext"].compact.join(" ") + expect(err).to include "[DEPRECATED]" + expect(err).to include "`--ext` with no arguments has been deprecated" expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist end end @@ -1364,8 +1403,11 @@ RSpec.describe "bundle gem" do expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist end - it "includes rake-compiler" do + it "includes rake-compiler, but no Rust related changes" do expect(bundled_app("#{gem_name}/Gemfile").read).to include('gem "rake-compiler"') + + expect(bundled_app("#{gem_name}/Gemfile").read).to_not include('gem "rb_sys"') + expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to_not include('spec.required_rubygems_version = ">= ') end it "depends on compile task for build" do @@ -1387,6 +1429,64 @@ RSpec.describe "bundle gem" do expect(bundled_app("#{gem_name}/Rakefile").read).to eq(rakefile) end end + + context "--ext parameter set with rust and old RubyGems" do + it "fails in friendly way" do + if ::Gem::Version.new("3.3.11") <= ::Gem.rubygems_version + skip "RubyGems compatible with Rust builder" + end + + expect do + bundle ["gem", gem_name, "--ext=rust"].compact.join(" ") + end.to raise_error(RuntimeError, /too old to build Rust extension/) + end + end + + context "--ext parameter set with rust" do + let(:flags) { "--ext=rust" } + + before do + skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version + + bundle ["gem", gem_name, flags].compact.join(" ") + end + + it "is not deprecated" do + expect(err).not_to include "[DEPRECATED] Option `--ext` without explicit value is deprecated." + end + + it "builds ext skeleton" do + expect(bundled_app("#{gem_name}/Cargo.toml")).to exist + expect(bundled_app("#{gem_name}/ext/#{gem_name}/Cargo.toml")).to exist + expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb")).to exist + expect(bundled_app("#{gem_name}/ext/#{gem_name}/src/lib.rs")).to exist + end + + it "includes rake-compiler, rb_sys gems and required_rubygems_version constraint" do + expect(bundled_app("#{gem_name}/Gemfile").read).to include('gem "rake-compiler"') + expect(bundled_app("#{gem_name}/Gemfile").read).to include('gem "rb_sys"') + expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include('spec.required_rubygems_version = ">= ') + end + + it "depends on compile task for build" do + rakefile = strip_whitespace <<-RAKEFILE + # frozen_string_literal: true + + require "bundler/gem_tasks" + require "rake/extensiontask" + + task build: :compile + + Rake::ExtensionTask.new("#{gem_name}") do |ext| + ext.lib_dir = "lib/#{gem_name}" + end + + task default: :compile + RAKEFILE + + expect(bundled_app("#{gem_name}/Rakefile").read).to eq(rakefile) + end + end end context "gem naming with dashed", :readline do diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb index 583e2aa41b..8c7b9c13c8 100644 --- a/spec/bundler/commands/update_spec.rb +++ b/spec/bundler/commands/update_spec.rb @@ -1310,21 +1310,19 @@ RSpec.describe "bundle update --bundler" do end it "updates the bundler version in the lockfile even if the latest version is not installed", :ruby_repo, :realworld do - skip "ruby-head has a default Bundler version too high for this spec to work" if RUBY_PATCHLEVEL == -1 - pristine_system_gems "bundler-2.3.9" build_repo4 do build_gem "rack", "1.0" end - install_gemfile <<-G + install_gemfile <<-G, :env => { "BUNDLER_IGNORE_DEFAULT_GEM" => "true" } source "#{file_uri_for(gem_repo4)}" gem "rack" G lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, "2.3.9") - bundle :update, :bundler => true, :artifice => "vcr", :verbose => true + bundle :update, :bundler => true, :artifice => "vcr", :verbose => true, :env => { "BUNDLER_IGNORE_DEFAULT_GEM" => "true" } # Only updates properly on modern RubyGems. @@ -1356,15 +1354,13 @@ RSpec.describe "bundle update --bundler" do end it "errors if the explicit target version does not exist", :realworld do - skip "ruby-head has a default Bundler version too high for this spec to work" if RUBY_PATCHLEVEL == -1 - pristine_system_gems "bundler-2.3.9" build_repo4 do build_gem "rack", "1.0" end - install_gemfile <<-G + install_gemfile <<-G, :env => { "BUNDLER_IGNORE_DEFAULT_GEM" => "true" } source "#{file_uri_for(gem_repo4)}" gem "rack" G diff --git a/spec/bundler/install/gemfile/git_spec.rb b/spec/bundler/install/gemfile/git_spec.rb index 7d263a2fe5..6a9532332c 100644 --- a/spec/bundler/install/gemfile/git_spec.rb +++ b/spec/bundler/install/gemfile/git_spec.rb @@ -235,6 +235,29 @@ RSpec.describe "bundle install with git sources" do G end + it "works when a tag that does not look like a commit hash is used as the value of :ref" do + build_git "foo" + @remote = build_git("bar", :bare => true) + update_git "foo", :remote => file_uri_for(@remote.path) + update_git "foo", :push => "main" + + install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem 'foo', :git => "#{@remote.path}" + G + + # Create a new tag on the remote that needs fetching + update_git "foo", :tag => "v1.0.0" + update_git "foo", :push => "v1.0.0" + + install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem 'foo', :git => "#{@remote.path}", :ref => "v1.0.0" + G + + expect(err).to be_empty + end + it "works when the revision is a non-head ref" do # want to ensure we don't fallback to main update_git "foo", :path => lib_path("foo-1.0") do |s| diff --git a/spec/bundler/install/gemfile/path_spec.rb b/spec/bundler/install/gemfile/path_spec.rb index 515901064f..9ef1c879f8 100644 --- a/spec/bundler/install/gemfile/path_spec.rb +++ b/spec/bundler/install/gemfile/path_spec.rb @@ -92,14 +92,12 @@ RSpec.describe "bundle install with explicit source paths" do build_lib "demo", :path => lib_path("demo") build_lib "aaa", :path => lib_path("demo/aaa") - gemfile = <<-G + gemfile lib_path("demo/Gemfile"), <<-G source "#{file_uri_for(gem_repo1)}" gemspec gem "aaa", :path => "./aaa" G - File.open(lib_path("demo/Gemfile"), "w") {|f| f.puts gemfile } - lockfile = <<~L PATH remote: . @@ -314,18 +312,67 @@ RSpec.describe "bundle install with explicit source paths" do s.add_dependency "rack", "1.0" end - gemfile = <<-G + gemfile lib_path("foo/Gemfile"), <<-G source "#{file_uri_for(gem_repo1)}" gemspec G - File.open(lib_path("foo/Gemfile"), "w") {|f| f.puts gemfile } - bundle "install", :dir => lib_path("foo") expect(the_bundle).to include_gems "foo 1.0", :dir => lib_path("foo") expect(the_bundle).to include_gems "rack 1.0", :dir => lib_path("foo") end + it "does not unlock dependencies of path sources" do + build_repo4 do + build_gem "graphql", "2.0.15" + build_gem "graphql", "2.0.16" + end + + build_lib "foo", "0.1.0", :path => lib_path("foo") do |s| + s.add_dependency "graphql", "~> 2.0" + end + + gemfile_path = lib_path("foo/Gemfile") + + gemfile gemfile_path, <<-G + source "#{file_uri_for(gem_repo4)}" + gemspec + G + + lockfile_path = lib_path("foo/Gemfile.lock") + + original_lockfile = <<~L + PATH + remote: . + specs: + foo (0.1.0) + graphql (~> 2.0) + + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + graphql (2.0.15) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + L + + lockfile lockfile_path, original_lockfile + + build_lib "foo", "0.1.1", :path => lib_path("foo") do |s| + s.add_dependency "graphql", "~> 2.0" + end + + bundle "install", :dir => lib_path("foo") + expect(lockfile_path).to read_as(original_lockfile.gsub("foo (0.1.0)", "foo (0.1.1)")) + end + it "supports gemspec syntax with an alternative path" do build_lib "foo", "1.0", :path => lib_path("foo") do |s| s.add_dependency "rack", "1.0" @@ -791,13 +838,11 @@ RSpec.describe "bundle install with explicit source paths" do describe "when there are both a gemspec and remote gems" do it "doesn't query rubygems for local gemspec name" do build_lib "private_lib", "2.2", :path => lib_path("private_lib") - gemfile = <<-G + gemfile lib_path("private_lib/Gemfile"), <<-G source "http://localgemserver.test" gemspec gem 'rack' G - File.open(lib_path("private_lib/Gemfile"), "w") {|f| f.puts gemfile } - bundle :install, :env => { "DEBUG" => "1" }, :artifice => "endpoint", :dir => lib_path("private_lib") expect(out).to match(%r{^HTTP GET http://localgemserver\.test/api/v1/dependencies\?gems=rack$}) expect(out).not_to match(/^HTTP GET.*private_lib/) diff --git a/spec/bundler/lock/git_spec.rb b/spec/bundler/lock/git_spec.rb index df9d71fdd6..dfcbb645b1 100644 --- a/spec/bundler/lock/git_spec.rb +++ b/spec/bundler/lock/git_spec.rb @@ -52,6 +52,44 @@ RSpec.describe "bundle lock with git gems" do expect(err).to be_empty end + it "properly fetches a git source locked to an unreachable ref" do + # Create a commit and make it unreachable + git "checkout -b foo ", lib_path("foo-1.0") + unreachable_sha = update_git("foo").ref_for("HEAD") + git "checkout main ", lib_path("foo-1.0") + git "branch -D foo ", lib_path("foo-1.0") + + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem 'foo', :git => "#{lib_path("foo-1.0")}" + G + + lockfile <<-L + GIT + remote: #{lib_path("foo-1.0")} + revision: #{unreachable_sha} + specs: + foo (1.0) + + GEM + remote: #{file_uri_for(gem_repo1)}/ + specs: + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + L + + bundle "install" + + expect(err).to be_empty + end + it "provides correct #full_gem_path" do run <<-RUBY puts Bundler.rubygems.find_name('foo').first.full_gem_path diff --git a/spec/bundler/support/hax.rb b/spec/bundler/support/hax.rb index ad7a6e0de9..c7fe3637cc 100644 --- a/spec/bundler/support/hax.rb +++ b/spec/bundler/support/hax.rb @@ -24,13 +24,30 @@ module Gem end if ENV["BUNDLER_SPEC_PLATFORM"] + previous_platforms = @platforms + previous_local = Platform.local + class Platform @local = new(ENV["BUNDLER_SPEC_PLATFORM"]) end - @platforms = [Gem::Platform::RUBY, Gem::Platform.local] + @platforms = previous_platforms.map {|platform| platform == previous_local ? Platform.local : platform } end if ENV["BUNDLER_SPEC_GEM_SOURCES"] self.sources = [ENV["BUNDLER_SPEC_GEM_SOURCES"]] end + + if ENV["BUNDLER_IGNORE_DEFAULT_GEM"] + module RemoveDefaultBundlerStub + def default_stubs(pattern = "*") + super.delete_if {|stub| stub.name == "bundler" } + end + end + + class Specification + class << self + prepend RemoveDefaultBundlerStub + end + end + end end diff --git a/spec/bundler/support/matchers.rb b/spec/bundler/support/matchers.rb index 8b22e7dbc3..ea7c784683 100644 --- a/spec/bundler/support/matchers.rb +++ b/spec/bundler/support/matchers.rb @@ -162,7 +162,7 @@ module Spec end if exitstatus == 65 actual_platform = out.split("\n").last - next "#{name} was expected to be of platform #{platform} but was #{actual_platform}" + next "#{name} was expected to be of platform #{platform || "ruby"} but was #{actual_platform || "ruby"}" end if exitstatus == 66 actual_source = out.split("\n").last diff --git a/test/rubygems/test_gem_bundler_version_finder.rb b/test/rubygems/test_gem_bundler_version_finder.rb index 60e2b65047..fd61000b8a 100644 --- a/test/rubygems/test_gem_bundler_version_finder.rb +++ b/test/rubygems/test_gem_bundler_version_finder.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true require_relative "helper" +require "rubygems/bundler_version_finder" class TestGemBundlerVersionFinder < Gem::TestCase def setup diff --git a/test/rubygems/test_gem_dependency.rb b/test/rubygems/test_gem_dependency.rb index c585e87087..bf0745ddc1 100644 --- a/test/rubygems/test_gem_dependency.rb +++ b/test/rubygems/test_gem_dependency.rb @@ -358,6 +358,8 @@ class TestGemDependency < Gem::TestCase assert_equal [b, b_1], dep.to_specs + require "rubygems/bundler_version_finder" + Gem::BundlerVersionFinder.stub(:bundler_version, Gem::Version.new("1")) do assert_equal [b_1, b], dep.to_specs end diff --git a/test/rubygems/test_gem_ext_cargo_builder.rb b/test/rubygems/test_gem_ext_cargo_builder.rb index e5bad0bcbc..9c1ee2ae31 100644 --- a/test/rubygems/test_gem_ext_cargo_builder.rb +++ b/test/rubygems/test_gem_ext_cargo_builder.rb @@ -2,6 +2,7 @@ require_relative "helper" require "rubygems/ext" +require "open3" class TestGemExtCargoBuilder < Gem::TestCase def setup @@ -22,31 +23,39 @@ class TestGemExtCargoBuilder < Gem::TestCase FileUtils.cp_r(@fixture_dir.to_s, @ext) end - def test_build_staticlib + def test_build_cdylib skip_unsupported_platforms! setup_rust_gem "rust_ruby_example" - content = @fixture_dir.join("Cargo.toml").read.gsub("cdylib", "staticlib") - File.write(File.join(@ext, "Cargo.toml"), content) - output = [] Dir.chdir @ext do ENV.update(@rust_envs) spec = Gem::Specification.new "rust_ruby_example", "0.1.0" builder = Gem::Ext::CargoBuilder.new(spec) - assert_raise(Gem::Ext::CargoBuilder::DylibNotFoundError) do - builder.build nil, @dest_path, output - end + builder.build nil, @dest_path, output end + + output = output.join "\n" + bundle = File.join(@dest_path, "release/rust_ruby_example.#{RbConfig::CONFIG['DLEXT']}") + + assert_match(/Finished/, output) + assert_match(/release/, output) + assert_ffi_handle bundle, "Init_rust_ruby_example" + rescue Exception => e + pp output if output + + raise(e) end - def test_build_cdylib + def test_rubygems_cfg_passed_to_rustc skip_unsupported_platforms! setup_rust_gem "rust_ruby_example" - + version_slug = Gem::VERSION.tr(".", "_") output = [] + replace_in_rust_file("src/lib.rs", "rubygems_x_x_x", "rubygems_#{version_slug}") + Dir.chdir @ext do ENV.update(@rust_envs) spec = Gem::Specification.new "rust_ruby_example", "0.1.0" @@ -57,9 +66,9 @@ class TestGemExtCargoBuilder < Gem::TestCase output = output.join "\n" bundle = File.join(@dest_path, "release/rust_ruby_example.#{RbConfig::CONFIG['DLEXT']}") - assert_match(/Finished/, output) - assert_match(/release/, output) - assert_ffi_handle bundle, "Init_rust_ruby_example" + assert_ffi_handle bundle, "hello_from_rubygems" + assert_ffi_handle bundle, "hello_from_rubygems_version" + refute_ffi_handle bundle, "should_never_exist" rescue Exception => e pp output if output @@ -140,7 +149,6 @@ class TestGemExtCargoBuilder < Gem::TestCase def skip_unsupported_platforms! pend "jruby not supported" if java_platform? pend "truffleruby not supported (yet)" if RUBY_ENGINE == "truffleruby" - pend "mswin not supported (yet)" if RUBY_PLATFORM.include?("mswin") && ENV.key?("GITHUB_ACTIONS") system(@rust_envs, "cargo", "-V", out: IO::NULL, err: [:child, :out]) pend "cargo not present" unless $?.success? pend "ruby.h is not provided by ruby repo" if ruby_repo? @@ -151,4 +159,15 @@ class TestGemExtCargoBuilder < Gem::TestCase dylib_handle = Fiddle.dlopen bundle assert_nothing_raised { dylib_handle[name] } end + + def refute_ffi_handle(bundle, name) + require "fiddle" + dylib_handle = Fiddle.dlopen bundle + assert_raise { dylib_handle[name] } + end + + def replace_in_rust_file(name, from, to) + content = @fixture_dir.join(name).read.gsub(from, to) + File.write(File.join(@ext, name), content) + end end diff --git a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/src/lib.rs b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/src/lib.rs index b2a907c736..0626f04e0f 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/src/lib.rs +++ b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/src/lib.rs @@ -21,6 +21,18 @@ unsafe extern "C" fn pub_reverse(_klass: VALUE, mut input: VALUE) -> VALUE { rb_utf8_str_new(reversed_cstring.as_ptr(), size) } +#[cfg(rubygems)] +#[no_mangle] +pub extern "C" fn hello_from_rubygems() {} + +#[cfg(rubygems_0_0_0)] +#[no_mangle] +pub extern "C" fn should_never_exist() {} + +#[cfg(rubygems_x_x_x)] +#[no_mangle] +pub extern "C" fn hello_from_rubygems_version() {} + #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn Init_rust_ruby_example() { diff --git a/test/rubygems/test_gem_ext_cargo_builder_link_flag_converter.rb b/test/rubygems/test_gem_ext_cargo_builder_link_flag_converter.rb index 92bd893a18..01648605d7 100644 --- a/test/rubygems/test_gem_ext_cargo_builder_link_flag_converter.rb +++ b/test/rubygems/test_gem_ext_cargo_builder_link_flag_converter.rb @@ -12,15 +12,15 @@ class TestGemExtCargoBuilderLinkFlagConverter < Gem::TestCase test_lib_with_nonascii: ["-lws2_32", ["-l", "ws2_32"]], test_simple_lib_space: ["-l foo", ["-l", "foo"]], test_verbose_lib_space: ["--library=foo", ["-l", "foo"]], - test_libstatic_with_colon: ["-l:libssp.a", ["-l", "static=ssp"]], - test_libstatic_with_colon_space: ["-l :libssp.a", ["-l", "static=ssp"]], - test_unconventional_lib_with_colon: ["-l:ssp.a", ["-C", "link_arg=-l:ssp.a"]], - test_dylib_with_colon_space: ["-l :libssp.dylib", ["-l", "dylib=ssp"]], - test_so_with_colon_space: ["-l :libssp.so", ["-l", "dylib=ssp"]], - test_dll_with_colon_space: ["-l :libssp.dll", ["-l", "dylib=ssp"]], + test_libstatic_with_colon: ["-l:libssp.a", ["-C", "link-args=-l:libssp.a"]], + test_libstatic_with_colon_space: ["-l :libssp.a", ["-C", "link-args=-l :libssp.a"]], + test_unconventional_lib_with_colon: ["-l:ssp.a", ["-C", "link-args=-l:ssp.a"]], + test_dylib_with_colon_space: ["-l :libssp.dylib", ["-C", "link-args=-l :libssp.dylib"]], + test_so_with_colon_space: ["-l :libssp.so", ["-C", "link-args=-l :libssp.so"]], + test_dll_with_colon_space: ["-l :libssp.dll", ["-C", "link-args=-l :libssp.dll"]], test_framework: ["-F/some/path", ["-l", "framework=/some/path"]], test_framework_space: ["-F /some/path", ["-l", "framework=/some/path"]], - test_non_lib_dash_l: ["test_rubygems_20220413-976-lemgf9/prefix", ["-C", "link_arg=test_rubygems_20220413-976-lemgf9/prefix"]], + test_non_lib_dash_l: ["test_rubygems_20220413-976-lemgf9/prefix", ["-C", "link-args=test_rubygems_20220413-976-lemgf9/prefix"]], }.freeze CASES.each do |test_name, (arg, expected)| diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb index 24a7261466..dda47e6bdf 100644 --- a/test/rubygems/test_gem_specification.rb +++ b/test/rubygems/test_gem_specification.rb @@ -2708,6 +2708,39 @@ duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use: end end + def test_validate_rust_extension_have_missing_cargo_toml_error + util_setup_validate + + Dir.chdir @tempdir do + @a1.extensions = ["Cargo.toml"] + File.write File.join(@tempdir, "Cargo.toml"), "" + + e = assert_raise Gem::InvalidSpecificationException do + use_ui @ui do + @a1.validate + end + end + + assert_match(/but Cargo.lock is not part of the gem files/, e.message) + end + end + + def test_validate_rust_extension_have_no_missing_cargo_toml_error + util_setup_validate + + Dir.chdir @tempdir do + @a1.extensions = ["Cargo.toml"] + @a1.files << "Cargo.toml" + @a1.files << "Cargo.lock" + File.write File.join(@tempdir, "Cargo.toml"), "" + File.write File.join(@tempdir, "Cargo.lock"), "" + + use_ui @ui do + @a1.validate + end + end + end + def test_validate_description util_setup_validate diff --git a/test/rubygems/test_kernel.rb b/test/rubygems/test_kernel.rb index 091a5419fb..ce38d92d8d 100644 --- a/test/rubygems/test_kernel.rb +++ b/test/rubygems/test_kernel.rb @@ -118,6 +118,8 @@ class TestKernel < Gem::TestCase end def test_gem_bundler_inferred_bundler_version + require "rubygems/bundler_version_finder" + Gem::BundlerVersionFinder.stub(:bundler_version, Gem::Version.new("1")) do quick_gem "bundler", "1" quick_gem "bundler", "2.a" diff --git a/test/rubygems/test_require.rb b/test/rubygems/test_require.rb index fba7f0c8be..43774d638e 100644 --- a/test/rubygems/test_require.rb +++ b/test/rubygems/test_require.rb @@ -666,6 +666,24 @@ class TestGemRequire < Gem::TestCase end end + def test_require_does_not_crash_when_utilizing_bundler_version_finder + a1 = util_spec "a", "1.1", { "bundler" => ">= 0" } + a2 = util_spec "a", "1.2", { "bundler" => ">= 0" } + b1 = util_spec "bundler", "2.3.7" + b2 = util_spec "bundler", "2.3.24" + c = util_spec "c", "1", { "a" => [">= 1.1", "< 99.0"] }, "lib/test_gem_require_c.rb" + + install_specs a1, a2, b1, b2, c + + cmd = <<-RUBY + require "test_gem_require_c" + require "json" + RUBY + out = Gem::Util.popen({ "GEM_HOME" => @gemhome }, *ruby_with_rubygems_in_load_path, "-e", cmd) + puts out + assert $?.success? + end + private def util_install_extension_file(name) diff --git a/tool/bundler/dev_gems.rb b/tool/bundler/dev_gems.rb index 1603d5f8bc..ef63263414 100644 --- a/tool/bundler/dev_gems.rb +++ b/tool/bundler/dev_gems.rb @@ -4,6 +4,7 @@ source "https://rubygems.org" gem "test-unit", "~> 3.0" gem "rake", "~> 13.0" +gem "rb_sys" gem "webrick", "~> 1.6" gem "parallel_tests", "~> 2.29" diff --git a/tool/bundler/dev_gems.rb.lock b/tool/bundler/dev_gems.rb.lock index 41e2128bb8..07b6d302ca 100644 --- a/tool/bundler/dev_gems.rb.lock +++ b/tool/bundler/dev_gems.rb.lock @@ -10,6 +10,7 @@ GEM parallel power_assert (2.0.2) rake (13.0.6) + rb_sys (0.9.52) rdiscount (2.2.7) ronn (0.7.3) hpricot (>= 0.8.2) @@ -43,6 +44,7 @@ DEPENDENCIES parallel (~> 1.19) parallel_tests (~> 2.29) rake (~> 13.0) + rb_sys ronn (~> 0.7.3) rspec-core (~> 3.12) rspec-expectations (~> 3.12) @@ -52,4 +54,4 @@ DEPENDENCIES webrick (~> 1.6) BUNDLED WITH - 2.4.0.dev + 2.4.0 diff --git a/tool/bundler/rubocop_gems.rb b/tool/bundler/rubocop_gems.rb index 84cb226330..9cb740cd15 100644 --- a/tool/bundler/rubocop_gems.rb +++ b/tool/bundler/rubocop_gems.rb @@ -9,3 +9,4 @@ gem "rake" gem "rake-compiler" gem "rspec" gem "test-unit" +gem "rb_sys" diff --git a/tool/bundler/rubocop_gems.rb.lock b/tool/bundler/rubocop_gems.rb.lock index dbb7601a11..e2831aebb3 100644 --- a/tool/bundler/rubocop_gems.rb.lock +++ b/tool/bundler/rubocop_gems.rb.lock @@ -14,6 +14,7 @@ GEM rake (13.0.6) rake-compiler (1.2.0) rake + rb_sys (0.9.52) regexp_parser (2.6.1) rexml (3.2.5) rspec (3.12.0) @@ -63,9 +64,10 @@ DEPENDENCIES minitest rake rake-compiler + rb_sys rspec rubocop (~> 1.7) test-unit BUNDLED WITH - 2.4.0.dev + 2.4.0 diff --git a/tool/bundler/standard_gems.rb b/tool/bundler/standard_gems.rb index 1cd189742d..20c1ecd827 100644 --- a/tool/bundler/standard_gems.rb +++ b/tool/bundler/standard_gems.rb @@ -9,3 +9,4 @@ gem "rake" gem "rake-compiler" gem "rspec" gem "test-unit" +gem "rb_sys" diff --git a/tool/bundler/standard_gems.rb.lock b/tool/bundler/standard_gems.rb.lock index 198aada23b..a84bdd7619 100644 --- a/tool/bundler/standard_gems.rb.lock +++ b/tool/bundler/standard_gems.rb.lock @@ -15,6 +15,7 @@ GEM rake (13.0.6) rake-compiler (1.2.0) rake + rb_sys (0.9.52) regexp_parser (2.6.1) rexml (3.2.5) rspec (3.12.0) @@ -71,9 +72,10 @@ DEPENDENCIES minitest rake rake-compiler + rb_sys rspec standard (~> 1.0) test-unit BUNDLED WITH - 2.4.0.dev + 2.4.0 diff --git a/tool/bundler/test_gems.rb b/tool/bundler/test_gems.rb index 3fb58b9388..9ba5763a3b 100644 --- a/tool/bundler/test_gems.rb +++ b/tool/bundler/test_gems.rb @@ -9,3 +9,4 @@ gem "compact_index", "~> 0.13.0" gem "sinatra", "~> 2.0" gem "rake", "13.0.1" gem "builder", "~> 3.2" +gem "rb_sys" diff --git a/tool/bundler/test_gems.rb.lock b/tool/bundler/test_gems.rb.lock index 554fd3ed9e..d961ab9f76 100644 --- a/tool/bundler/test_gems.rb.lock +++ b/tool/bundler/test_gems.rb.lock @@ -11,6 +11,7 @@ GEM rack-test (1.1.0) rack (>= 1.0, < 3) rake (13.0.1) + rb_sys (0.9.52) ruby2_keywords (0.0.5) sinatra (2.0.8.1) mustermann (~> 1.0) @@ -36,8 +37,9 @@ DEPENDENCIES rack (= 2.0.8) rack-test (~> 1.1) rake (= 13.0.1) + rb_sys sinatra (~> 2.0) webrick (= 1.7.0) BUNDLED WITH - 2.4.0.dev + 2.4.0 |