diff options
Diffstat (limited to 'lib')
33 files changed, 2440 insertions, 113 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" } |