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