diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c
index 71a87f04636c98..18fa8edeb5777e 100644
--- a/ext/openssl/ossl_asn1.c
+++ b/ext/openssl/ossl_asn1.c
@@ -130,15 +130,17 @@ asn1integer_to_num(const ASN1_INTEGER *ai)
if (!ai) {
ossl_raise(rb_eTypeError, "ASN1_INTEGER is NULL!");
}
+
+ num = ossl_bn_new(BN_value_one());
+ bn = GetBNPtr(num);
+
if (ASN1_STRING_type(ai) == V_ASN1_ENUMERATED)
- bn = ASN1_ENUMERATED_to_BN(ai, NULL);
+ bn = ASN1_ENUMERATED_to_BN(ai, bn);
else
- bn = ASN1_INTEGER_to_BN(ai, NULL);
+ bn = ASN1_INTEGER_to_BN(ai, bn);
if (!bn)
ossl_raise(eOSSLError, NULL);
- num = ossl_bn_new(bn);
- BN_free(bn);
return num;
}
diff --git a/hash.c b/hash.c
index c09c7b26b5414a..773df7e78d8c7f 100644
--- a/hash.c
+++ b/hash.c
@@ -5332,7 +5332,7 @@ static VALUE
env_fetch(int argc, VALUE *argv, VALUE _)
{
VALUE key;
- long block_given;
+ int block_given;
const char *nam;
VALUE env;
diff --git a/parse.y b/parse.y
index ab301d6034acf4..6813b396332b00 100644
--- a/parse.y
+++ b/parse.y
@@ -11708,16 +11708,10 @@ rb_node_match3_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, const
return n;
}
-/* TODO: Use union for NODE_LIST2 */
static rb_node_list_t *
rb_node_list_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc)
{
- rb_node_list_t *n = NODE_NEWNODE(NODE_LIST, rb_node_list_t, loc);
- n->nd_head = nd_head;
- n->as.nd_alen = 1;
- n->nd_next = 0;
-
- return n;
+ return rb_node_list_new2(p, nd_head, 1, 0, loc);
}
static rb_node_list_t *
diff --git a/prism/prism.c b/prism/prism.c
index c644c947538c4e..ebd86b01fe089b 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -21740,6 +21740,19 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
return node;
}
break;
+ case PM_RESCUE_MODIFIER_NODE:
+ // A rescue modifier whose handler is a one-liner pattern match
+ // (=> or in) produces a statement. That means it cannot be
+ // extended by operators above the modifier level.
+ if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
+ pm_rescue_modifier_node_t *cast = (pm_rescue_modifier_node_t *) node;
+ pm_node_t *rescue_expression = cast->rescue_expression;
+
+ if (PM_NODE_TYPE_P(rescue_expression, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(rescue_expression, PM_MATCH_PREDICATE_NODE)) {
+ return node;
+ }
+ }
+ break;
default:
break;
}
diff --git a/shape.h b/shape.h
index 96c78f2bc1a356..ad9b148247b32e 100644
--- a/shape.h
+++ b/shape.h
@@ -14,33 +14,33 @@ STATIC_ASSERT(shape_id_num_bits, SHAPE_ID_NUM_BITS == sizeof(shape_id_t) * CHAR_
#define SHAPE_BUFFER_SIZE (1 << SHAPE_ID_OFFSET_NUM_BITS)
#define SHAPE_ID_OFFSET_MASK (SHAPE_BUFFER_SIZE - 1)
-#define SHAPE_ID_HEAP_INDEX_BITS 3
+#define SHAPE_ID_HEAP_INDEX_BITS 5
#define SHAPE_ID_HEAP_INDEX_MAX ((1 << SHAPE_ID_HEAP_INDEX_BITS) - 1)
+#define SHAPE_ID_HEAP_INDEX_OFFSET SHAPE_ID_OFFSET_NUM_BITS
#define SHAPE_ID_FL_USHIFT (SHAPE_ID_OFFSET_NUM_BITS + SHAPE_ID_HEAP_INDEX_BITS)
-#define SHAPE_ID_HEAP_INDEX_OFFSET SHAPE_ID_FL_USHIFT
// shape_id_t bits:
// 0-18 SHAPE_ID_OFFSET_MASK
// index in rb_shape_tree.shape_list. Allow to access `rb_shape_t *`.
-// 19-21 SHAPE_ID_HEAP_INDEX_MASK
+// 19-23 SHAPE_ID_HEAP_INDEX_MASK
// index in rb_shape_tree.capacities. Allow to access slot size.
// Always 0 except for T_OBJECT.
-// 22 SHAPE_ID_FL_FROZEN
+// 24 SHAPE_ID_FL_FROZEN
// Whether the object is frozen or not.
-// 23 SHAPE_ID_FL_HAS_OBJECT_ID
+// 25 SHAPE_ID_FL_HAS_OBJECT_ID
// Whether the object has an `SHAPE_OBJ_ID` transition.
-// 24 SHAPE_ID_FL_TOO_COMPLEX
+// 26 SHAPE_ID_FL_TOO_COMPLEX
// The object is backed by a `st_table`.
enum shape_id_fl_type {
#define RBIMPL_SHAPE_ID_FL(n) (1<<(SHAPE_ID_FL_USHIFT+n))
- SHAPE_ID_HEAP_INDEX_MASK = RBIMPL_SHAPE_ID_FL(0) | RBIMPL_SHAPE_ID_FL(1) | RBIMPL_SHAPE_ID_FL(2),
+ SHAPE_ID_HEAP_INDEX_MASK = ((1 << SHAPE_ID_HEAP_INDEX_BITS) - 1) << SHAPE_ID_HEAP_INDEX_OFFSET,
- SHAPE_ID_FL_FROZEN = RBIMPL_SHAPE_ID_FL(3),
- SHAPE_ID_FL_HAS_OBJECT_ID = RBIMPL_SHAPE_ID_FL(4),
- SHAPE_ID_FL_TOO_COMPLEX = RBIMPL_SHAPE_ID_FL(5),
+ SHAPE_ID_FL_FROZEN = RBIMPL_SHAPE_ID_FL(0),
+ SHAPE_ID_FL_HAS_OBJECT_ID = RBIMPL_SHAPE_ID_FL(1),
+ SHAPE_ID_FL_TOO_COMPLEX = RBIMPL_SHAPE_ID_FL(2),
SHAPE_ID_FL_NON_CANONICAL_MASK = SHAPE_ID_FL_FROZEN | SHAPE_ID_FL_HAS_OBJECT_ID,
SHAPE_ID_FLAGS_MASK = SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_NON_CANONICAL_MASK | SHAPE_ID_FL_TOO_COMPLEX,
diff --git a/spec/mspec/lib/mspec/commands/mspec-tag.rb b/spec/mspec/lib/mspec/commands/mspec-tag.rb
index 8b1cb8380949cd..9ce9f048c63b6d 100644
--- a/spec/mspec/lib/mspec/commands/mspec-tag.rb
+++ b/spec/mspec/lib/mspec/commands/mspec-tag.rb
@@ -112,6 +112,7 @@ def register
MSpec.register_mode :pretend
MSpec.register_mode :unguarded
config[:formatter] = false
+ config[:xtags] = []
else
raise ArgumentError, "No recognized action given"
end
diff --git a/spec/mspec/lib/mspec/runner/formatters/base.rb b/spec/mspec/lib/mspec/runner/formatters/base.rb
index e3b5bb23e0bfd0..882e15c8c222bd 100644
--- a/spec/mspec/lib/mspec/runner/formatters/base.rb
+++ b/spec/mspec/lib/mspec/runner/formatters/base.rb
@@ -46,7 +46,7 @@ def register
LeakCheckerAction.new.register
end
- if ENV['CHECK_LEAKS'] || ENV['CHECK_CONSTANT_LEAKS']
+ if (ENV['CHECK_LEAKS'] || ENV['CHECK_CONSTANT_LEAKS']) && ENV['CHECK_CONSTANT_LEAKS'] != 'false'
save = ENV['CHECK_LEAKS'] == 'save' || ENV['CHECK_CONSTANT_LEAKS'] == 'save'
ConstantsLeakCheckerAction.new(save).register
end
diff --git a/spec/mspec/lib/mspec/runner/mspec.rb b/spec/mspec/lib/mspec/runner/mspec.rb
index 97c3f365bc73d7..0e016c67a7544b 100644
--- a/spec/mspec/lib/mspec/runner/mspec.rb
+++ b/spec/mspec/lib/mspec/runner/mspec.rb
@@ -365,6 +365,7 @@ def self.make_tag_dir(path)
# Writes each tag in +tags+ to the tag file. Overwrites the
# tag file if it exists.
def self.write_tags(tags)
+ return delete_tags if tags.empty?
file = tags_file
make_tag_dir(file)
File.open(file, "w:utf-8") do |f|
diff --git a/spec/mspec/tool/remove_old_guards.rb b/spec/mspec/tool/remove_old_guards.rb
index 75c48e058433e7..bc5612c78dde9c 100755
--- a/spec/mspec/tool/remove_old_guards.rb
+++ b/spec/mspec/tool/remove_old_guards.rb
@@ -31,6 +31,12 @@ def each_spec_file(&block)
Dir["*/**/*.rb"].each(&block)
end
+def each_file(&block)
+ Dir["**/*"].each { |path|
+ yield path if File.file?(path)
+ }
+end
+
def remove_guards(guard, keep)
each_spec_file do |file|
contents = File.binread(file)
@@ -109,7 +115,7 @@ def remove_unused_shared_specs
end
def search(regexp)
- each_spec_file do |file|
+ each_file do |file|
contents = File.binread(file)
if contents =~ regexp
puts file
@@ -136,3 +142,4 @@ def search(regexp)
puts "Search:"
search(/(["'])#{version}\1/)
search(/^\s*#.+#{version}/)
+search(/RUBY_VERSION_IS_#{version.tr('.', '_')}/)
diff --git a/spec/ruby/README.md b/spec/ruby/README.md
index 14a0068346fe3d..b259a97e21c95f 100644
--- a/spec/ruby/README.md
+++ b/spec/ruby/README.md
@@ -30,8 +30,8 @@ ruby/spec is known to be tested in these implementations for every commit:
* [Opal](https://github.com/opal/opal/tree/master/spec)
* [Artichoke](https://github.com/artichoke/spec/tree/artichoke-vendor)
-ruby/spec describes the behavior of Ruby 3.2 and more recent Ruby versions.
-More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (3.2.x, 3.3.x, etc), and those are tested in CI.
+ruby/spec describes the behavior of Ruby 3.3 and more recent Ruby versions.
+More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (3.3.x, 3.4.x, etc), and those are tested in CI.
### Synchronization with Ruby Implementations
diff --git a/spec/ruby/command_line/error_message_spec.rb b/spec/ruby/command_line/error_message_spec.rb
index 02150f30ce012d..5bed905cf634a6 100644
--- a/spec/ruby/command_line/error_message_spec.rb
+++ b/spec/ruby/command_line/error_message_spec.rb
@@ -8,4 +8,9 @@
out = ruby_exe("end #syntax error", args: "2> #{File::NULL}", exit_status: 1)
out.chomp.should.empty?
end
+
+ it "is not modified with extra escaping of control characters and backslashes" do
+ out = ruby_exe('raise "\e[31mRed\e[0m error\\\\message"', args: "2>&1", exit_status: 1)
+ out.chomp.should include("\e[31mRed\e[0m error\\message")
+ end
end
diff --git a/spec/ruby/core/data/fixtures/classes.rb b/spec/ruby/core/data/fixtures/classes.rb
index 650c0b2a623fdd..147293ee45ba6f 100644
--- a/spec/ruby/core/data/fixtures/classes.rb
+++ b/spec/ruby/core/data/fixtures/classes.rb
@@ -1,6 +1,7 @@
module DataSpecs
if Data.respond_to?(:define)
Measure = Data.define(:amount, :unit)
+ Single = Data.define(:value)
class MeasureWithOverriddenName < Measure
def self.name
@@ -8,6 +9,12 @@ def self.name
end
end
+ class SingleWithOverriddenName < Single
+ def self.name
+ "A"
+ end
+ end
+
class DataSubclass < Data; end
MeasureSubclass = Class.new(Measure) do
diff --git a/spec/ruby/core/data/initialize_spec.rb b/spec/ruby/core/data/initialize_spec.rb
index 010c73b91b8fea..9c3f97ec86720d 100644
--- a/spec/ruby/core/data/initialize_spec.rb
+++ b/spec/ruby/core/data/initialize_spec.rb
@@ -2,6 +2,16 @@
require_relative 'fixtures/classes'
describe "Data#initialize" do
+ context "with no members" do
+ ruby_bug "#21819", ""..."4.0.1" do
+ it "is frozen" do
+ data = Data.define
+
+ data.new.should.frozen?
+ end
+ end
+ end
+
it "accepts positional arguments" do
data = DataSpecs::Measure.new(42, "km")
@@ -37,6 +47,17 @@
data.unit.should == "km"
end
+ it "accepts positional arguments with empty keyword arguments" do
+ data = DataSpecs::Single.new(42, **{})
+
+ data.value.should == 42
+
+ data = DataSpecs::Measure.new(42, "km", **{})
+
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
+
it "raises ArgumentError if no arguments are given" do
-> {
DataSpecs::Measure.new
@@ -111,6 +132,17 @@ def initialize(*, **)
ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}]
end
+ it "accepts positional arguments with empty keyword arguments" do
+ data = DataSpecs::SingleWithOverriddenName.new(42, **{})
+
+ data.value.should == 42
+
+ data = DataSpecs::MeasureWithOverriddenName.new(42, "km", **{})
+
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
+
# See https://github.com/ruby/psych/pull/765
it "can be deserialized by calling Data.instance_method(:initialize)" do
d1 = DataSpecs::Area.new(width: 2, height: 3)
diff --git a/spec/ruby/core/encoding/locale_charmap_spec.rb b/spec/ruby/core/encoding/locale_charmap_spec.rb
index 8143b9083a8cc1..345a7b7093705e 100644
--- a/spec/ruby/core/encoding/locale_charmap_spec.rb
+++ b/spec/ruby/core/encoding/locale_charmap_spec.rb
@@ -5,52 +5,52 @@
Encoding.locale_charmap.should be_an_instance_of(String)
end
- # FIXME: Get this working on Windows
- platform_is :linux do
- platform_is_not :android do
- it "returns a value based on the LC_ALL environment variable" do
- old_lc_all = ENV['LC_ALL']
- ENV['LC_ALL'] = 'C'
- ruby_exe("print Encoding.locale_charmap").should == 'ANSI_X3.4-1968'
- ENV['LC_ALL'] = old_lc_all
+ describe "when setting LC_ALL=C" do
+ before :each do
+ @old_lc_all = ENV['LC_ALL']
+ end
+
+ after :each do
+ ENV['LC_ALL'] = @old_lc_all
+ end
+
+ # FIXME: Get this working on Windows
+ platform_is :linux do
+ platform_is_not :android do
+ it "returns a value based on the LC_ALL environment variable" do
+ ENV['LC_ALL'] = 'C'
+ ruby_exe("print Encoding.locale_charmap").should == 'ANSI_X3.4-1968'
+ end
end
end
- end
- platform_is :freebsd, :openbsd, :darwin do
- it "returns a value based on the LC_ALL environment variable" do
- old_lc_all = ENV['LC_ALL']
- ENV['LC_ALL'] = 'C'
- ruby_exe("print Encoding.locale_charmap").should == 'US-ASCII'
- ENV['LC_ALL'] = old_lc_all
+ platform_is :freebsd, :openbsd, :darwin do
+ it "returns a value based on the LC_ALL environment variable" do
+ ENV['LC_ALL'] = 'C'
+ ruby_exe("print Encoding.locale_charmap").should == 'US-ASCII'
+ end
end
- end
- platform_is :netbsd do
- it "returns a value based on the LC_ALL environment variable" do
- old_lc_all = ENV['LC_ALL']
- ENV['LC_ALL'] = 'C'
- ruby_exe("print Encoding.locale_charmap").should == '646'
- ENV['LC_ALL'] = old_lc_all
+ platform_is :netbsd do
+ it "returns a value based on the LC_ALL environment variable" do
+ ENV['LC_ALL'] = 'C'
+ ruby_exe("print Encoding.locale_charmap").should == '646'
+ end
end
- end
- platform_is :android do
- it "always returns UTF-8" do
- old_lc_all = ENV['LC_ALL']
- ENV['LC_ALL'] = 'C'
- ruby_exe("print Encoding.locale_charmap").should == 'UTF-8'
- ENV['LC_ALL'] = old_lc_all
+ platform_is :android do
+ it "always returns UTF-8" do
+ ENV['LC_ALL'] = 'C'
+ ruby_exe("print Encoding.locale_charmap").should == 'UTF-8'
+ end
end
- end
- platform_is :bsd, :darwin, :linux do
- it "is unaffected by assigning to ENV['LC_ALL'] in the same process" do
- old_charmap = Encoding.locale_charmap
- old_lc_all = ENV['LC_ALL']
- ENV['LC_ALL'] = 'C'
- Encoding.locale_charmap.should == old_charmap
- ENV['LC_ALL'] = old_lc_all
+ platform_is :bsd, :darwin, :linux do
+ it "is unaffected by assigning to ENV['LC_ALL'] in the same process" do
+ old_charmap = Encoding.locale_charmap
+ ENV['LC_ALL'] = 'C'
+ Encoding.locale_charmap.should == old_charmap
+ end
end
end
end
diff --git a/spec/ruby/core/fiber/raise_spec.rb b/spec/ruby/core/fiber/raise_spec.rb
index 896f760290a37b..51d64bba549900 100644
--- a/spec/ruby/core/fiber/raise_spec.rb
+++ b/spec/ruby/core/fiber/raise_spec.rb
@@ -3,11 +3,16 @@
require_relative '../../shared/kernel/raise'
describe "Fiber#raise" do
+ it "is a public method" do
+ Fiber.public_instance_methods.should include(:raise)
+ end
+
it_behaves_like :kernel_raise, :raise, FiberSpecs::NewFiberToRaise
it_behaves_like :kernel_raise_across_contexts, :raise, FiberSpecs::NewFiberToRaise
-end
+ ruby_version_is "4.0" do
+ it_behaves_like :kernel_raise_with_cause, :raise, FiberSpecs::NewFiberToRaise
+ end
-describe "Fiber#raise" do
it 'raises RuntimeError by default' do
-> { FiberSpecs::NewFiberToRaise.raise }.should raise_error(RuntimeError)
end
@@ -126,10 +131,7 @@
end.should raise_error(RuntimeError, "Expected error")
end
end
-end
-
-describe "Fiber#raise" do
it "transfers and raises on a transferring fiber" do
root = Fiber.current
fiber = Fiber.new { root.transfer }
diff --git a/spec/ruby/core/fiber/storage_spec.rb b/spec/ruby/core/fiber/storage_spec.rb
index 6ffc13ee283bec..def8af46cec414 100644
--- a/spec/ruby/core/fiber/storage_spec.rb
+++ b/spec/ruby/core/fiber/storage_spec.rb
@@ -84,17 +84,15 @@
Fiber.new { Fiber[:life] }.resume.should be_nil
end
- ruby_version_is "3.2.3" do
- it "can use dynamically defined keys" do
- key = :"#{self.class.name}#.#{self.object_id}"
- Fiber.new { Fiber[key] = 42; Fiber[key] }.resume.should == 42
- end
+ it "can use dynamically defined keys" do
+ key = :"#{self.class.name}#.#{self.object_id}"
+ Fiber.new { Fiber[key] = 42; Fiber[key] }.resume.should == 42
+ end
- it "can't use invalid keys" do
- invalid_keys = [Object.new, 12]
- invalid_keys.each do |key|
- -> { Fiber[key] }.should raise_error(TypeError)
- end
+ it "can't use invalid keys" do
+ invalid_keys = [Object.new, 12]
+ invalid_keys.each do |key|
+ -> { Fiber[key] }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/core/hash/new_spec.rb b/spec/ruby/core/hash/new_spec.rb
index 8de44ec9411deb..ca43646ef4b9f1 100644
--- a/spec/ruby/core/hash/new_spec.rb
+++ b/spec/ruby/core/hash/new_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+# Actually these are specs of Hash#initialize, there is no Hash.new it's just Class.new.
describe "Hash.new" do
it "creates an empty Hash if passed no arguments" do
Hash.new.should == {}
diff --git a/spec/ruby/core/integer/shared/exponent.rb b/spec/ruby/core/integer/shared/exponent.rb
index 5ef6d686d809d4..d30c54fd3195d5 100644
--- a/spec/ruby/core/integer/shared/exponent.rb
+++ b/spec/ruby/core/integer/shared/exponent.rb
@@ -57,7 +57,15 @@
end
ruby_version_is "3.4" do
- it "raises an ArgumentError when the number is too big" do
+ it "returns an Integer for results larger than the old 32MB limit" do
+ # 2 ** 40000000 requires 40000001 bits
+ # This exceeds the old 32MB limit but is within the new 16GB limit
+ result = 2.send(@method, 40000000)
+ result.should.is_a?(Integer)
+ result.bit_length.should == 40000001
+ end
+
+ it "raises an ArgumentError when the result size exceeds the limit" do
-> { 100000000.send(@method, 1000000000) }.should raise_error(ArgumentError)
end
end
@@ -128,7 +136,17 @@
end
ruby_version_is "3.4" do
- it "does not switch to a Float when the values is too big" do
+ it "returns an Integer for large Bignum results exceeding the old limit" do
+ # (2 ** 70) ** 500000 requires 35000001 bits
+ # This exceeds the old 32MB limit but is within the new 16GB limit
+ bignum_base = 2 ** 70
+ result = bignum_base.send(@method, 500000)
+ result.should.is_a?(Integer)
+ result.bit_length.should == 35000001
+ end
+
+ it "raises an ArgumentError when Bignum result exceeds the limit" do
+ # @bignum ** @bignum would require enormous memory
-> {
@bignum.send(@method, @bignum)
}.should raise_error(ArgumentError)
diff --git a/spec/ruby/core/io/buffer/and_spec.rb b/spec/ruby/core/io/buffer/and_spec.rb
new file mode 100644
index 00000000000000..1f3611cfa9d8da
--- /dev/null
+++ b/spec/ruby/core/io/buffer/and_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../../spec_helper'
+
+describe :io_buffer_and, shared: true do
+ it "applies the argument buffer as an AND bit mask across the whole buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\x30\x02\x30\x04\x30".b
+ result.free
+ end
+ end
+ end
+
+ it "ignores extra parts of mask if it is longer than source buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F\x00\x00\x00\xFF\xFF") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\x30\x02\x00\x00\x00".b
+ result.free
+ end
+ end
+ end
+
+ it "raises TypeError if mask is not an IO::Buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ -> { buffer.send(@method, "\xF8\x8F") }.should raise_error(TypeError, "wrong argument type String (expected IO::Buffer)")
+ -> { buffer.send(@method, 0xF8) }.should raise_error(TypeError, "wrong argument type Integer (expected IO::Buffer)")
+ -> { buffer.send(@method, nil) }.should raise_error(TypeError, "wrong argument type nil (expected IO::Buffer)")
+ end
+ end
+end
+
+describe "IO::Buffer#&" do
+ it_behaves_like :io_buffer_and, :&
+
+ it "creates a new internal buffer of the same size" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer & mask
+ result.should_not.equal? buffer
+ result.should.internal?
+ result.size.should == buffer.size
+ result.free
+ buffer.get_string.should == "12345".b
+ end
+ end
+ end
+end
+
+describe "IO::Buffer#and!" do
+ it_behaves_like :io_buffer_and, :and!
+
+ it "modifies the buffer in place" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.and!(mask)
+ result.should.equal? buffer
+ result.should.external?
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/not_spec.rb b/spec/ruby/core/io/buffer/not_spec.rb
new file mode 100644
index 00000000000000..4737a30bde66ff
--- /dev/null
+++ b/spec/ruby/core/io/buffer/not_spec.rb
@@ -0,0 +1,37 @@
+require_relative '../../../spec_helper'
+
+describe :io_buffer_not, shared: true do
+ it "inverts every bit of the buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ result = buffer.send(@method)
+ result.get_string.should == "\xCE\xCD\xCC\xCB\xCA".b
+ result.free
+ end
+ end
+end
+
+describe "IO::Buffer#~" do
+ it_behaves_like :io_buffer_not, :~
+
+ it "creates a new internal buffer of the same size" do
+ IO::Buffer.for(+"12345") do |buffer|
+ result = ~buffer
+ result.should_not.equal? buffer
+ result.should.internal?
+ result.size.should == buffer.size
+ result.free
+ end
+ end
+end
+
+describe "IO::Buffer#not!" do
+ it_behaves_like :io_buffer_not, :not!
+
+ it "modifies the buffer in place" do
+ IO::Buffer.for(+"12345") do |buffer|
+ result = buffer.not!
+ result.should.equal? buffer
+ result.should.external?
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/or_spec.rb b/spec/ruby/core/io/buffer/or_spec.rb
new file mode 100644
index 00000000000000..1c9e52a4cac2d4
--- /dev/null
+++ b/spec/ruby/core/io/buffer/or_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../../spec_helper'
+
+describe :io_buffer_or, shared: true do
+ it "applies the argument buffer as an OR bit mask across the whole buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\xF9\xBF\xFB\xBF\xFD".b
+ result.free
+ end
+ end
+ end
+
+ it "ignores extra parts of mask if it is longer than source buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F\x00\x00\x00\xFF\xFF") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\xF9\xBF345".b
+ result.free
+ end
+ end
+ end
+
+ it "raises TypeError if mask is not an IO::Buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ -> { buffer.send(@method, "\xF8\x8F") }.should raise_error(TypeError, "wrong argument type String (expected IO::Buffer)")
+ -> { buffer.send(@method, 0xF8) }.should raise_error(TypeError, "wrong argument type Integer (expected IO::Buffer)")
+ -> { buffer.send(@method, nil) }.should raise_error(TypeError, "wrong argument type nil (expected IO::Buffer)")
+ end
+ end
+end
+
+describe "IO::Buffer#|" do
+ it_behaves_like :io_buffer_or, :|
+
+ it "creates a new internal buffer of the same size" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer | mask
+ result.should_not.equal? buffer
+ result.should.internal?
+ result.size.should == buffer.size
+ result.free
+ buffer.get_string.should == "12345".b
+ end
+ end
+ end
+end
+
+describe "IO::Buffer#or!" do
+ it_behaves_like :io_buffer_or, :or!
+
+ it "modifies the buffer in place" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.or!(mask)
+ result.should.equal? buffer
+ result.should.external?
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/xor_spec.rb b/spec/ruby/core/io/buffer/xor_spec.rb
new file mode 100644
index 00000000000000..637f7519d54a00
--- /dev/null
+++ b/spec/ruby/core/io/buffer/xor_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../../spec_helper'
+
+describe :io_buffer_xor, shared: true do
+ it "applies the argument buffer as an XOR bit mask across the whole buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\xC9\xBD\xCB\xBB\xCD".b
+ result.free
+ end
+ end
+ end
+
+ it "ignores extra parts of mask if it is longer than source buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F\x00\x00\x00\xFF\xFF") do |mask|
+ result = buffer.send(@method, mask)
+ result.get_string.should == "\xC9\xBD345".b
+ result.free
+ end
+ end
+ end
+
+ it "raises TypeError if mask is not an IO::Buffer" do
+ IO::Buffer.for(+"12345") do |buffer|
+ -> { buffer.send(@method, "\xF8\x8F") }.should raise_error(TypeError, "wrong argument type String (expected IO::Buffer)")
+ -> { buffer.send(@method, 0xF8) }.should raise_error(TypeError, "wrong argument type Integer (expected IO::Buffer)")
+ -> { buffer.send(@method, nil) }.should raise_error(TypeError, "wrong argument type nil (expected IO::Buffer)")
+ end
+ end
+end
+
+describe "IO::Buffer#^" do
+ it_behaves_like :io_buffer_xor, :^
+
+ it "creates a new internal buffer of the same size" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer ^ mask
+ result.should_not.equal? buffer
+ result.should.internal?
+ result.size.should == buffer.size
+ result.free
+ buffer.get_string.should == "12345".b
+ end
+ end
+ end
+end
+
+describe "IO::Buffer#xor!" do
+ it_behaves_like :io_buffer_xor, :xor!
+
+ it "modifies the buffer in place" do
+ IO::Buffer.for(+"12345") do |buffer|
+ IO::Buffer.for(+"\xF8\x8F") do |mask|
+ result = buffer.xor!(mask)
+ result.should.equal? buffer
+ result.should.external?
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/select_spec.rb b/spec/ruby/core/io/select_spec.rb
index 9fdb7e12c932db..8e0b89c053548f 100644
--- a/spec/ruby/core/io/select_spec.rb
+++ b/spec/ruby/core/io/select_spec.rb
@@ -112,7 +112,17 @@
end
it "raises an ArgumentError when passed a negative timeout" do
- -> { IO.select(nil, nil, nil, -5)}.should raise_error(ArgumentError)
+ -> { IO.select(nil, nil, nil, -5)}.should raise_error(ArgumentError, "time interval must not be negative")
+ end
+
+ ruby_version_is "4.0" do
+ it "raises an ArgumentError when passed negative infinity as timeout" do
+ -> { IO.select(nil, nil, nil, -Float::INFINITY)}.should raise_error(ArgumentError, "time interval must not be negative")
+ end
+ end
+
+ it "raises an RangeError when passed NaN as timeout" do
+ -> { IO.select(nil, nil, nil, Float::NAN)}.should raise_error(RangeError, "NaN out of Time range")
end
describe "returns the available descriptors when the file descriptor" do
diff --git a/spec/ruby/core/kernel/raise_spec.rb b/spec/ruby/core/kernel/raise_spec.rb
index fcd011d4e62e88..d08303cd830b2f 100644
--- a/spec/ruby/core/kernel/raise_spec.rb
+++ b/spec/ruby/core/kernel/raise_spec.rb
@@ -4,9 +4,19 @@
describe "Kernel#raise" do
it "is a private method" do
- Kernel.should have_private_instance_method(:raise)
+ Kernel.private_instance_methods.should include(:raise)
end
+ # Shared specs expect a public #raise method.
+ public_raiser = Object.new
+ class << public_raiser
+ public :raise
+ end
+ it_behaves_like :kernel_raise, :raise, public_raiser
+ it_behaves_like :kernel_raise_with_cause, :raise, public_raiser
+end
+
+describe "Kernel#raise with previously rescued exception" do
it "re-raises the previously rescued exception if no exception is specified" do
ScratchPad.record nil
@@ -28,87 +38,6 @@
ScratchPad.recorded.should be_nil
end
- it "accepts a cause keyword argument that sets the cause" do
- cause = StandardError.new
- -> { raise("error", cause: cause) }.should raise_error(RuntimeError) { |e| e.cause.should == cause }
- end
-
- it "accepts a cause keyword argument that overrides the last exception" do
- begin
- raise "first raise"
- rescue => ignored
- cause = StandardError.new
- -> { raise("error", cause: cause) }.should raise_error(RuntimeError) { |e| e.cause.should == cause }
- end
- end
-
- it "raises an ArgumentError when only cause is given" do
- cause = StandardError.new
- -> { raise(cause: cause) }.should raise_error(ArgumentError, "only cause is given with no arguments")
- end
-
- it "raises an ArgumentError when only cause is given even if it has nil value" do
- -> { raise(cause: nil) }.should raise_error(ArgumentError, "only cause is given with no arguments")
- end
-
- it "raises a TypeError when given cause is not an instance of Exception" do
- -> { raise "message", cause: Object.new }.should raise_error(TypeError, "exception object expected")
- end
-
- it "doesn't raise a TypeError when given cause is nil" do
- -> { raise "message", cause: nil }.should raise_error(RuntimeError, "message")
- end
-
- it "allows cause equal an exception" do
- e = RuntimeError.new("message")
- -> { raise e, cause: e }.should raise_error(e)
- end
-
- it "doesn't set given cause when it equals an exception" do
- e = RuntimeError.new("message")
-
- begin
- raise e, cause: e
- rescue
- end
-
- e.cause.should == nil
- end
-
- it "raises ArgumentError when exception is part of the cause chain" do
- -> {
- begin
- raise "Error 1"
- rescue => e1
- begin
- raise "Error 2"
- rescue => e2
- begin
- raise "Error 3"
- rescue => e3
- raise e1, cause: e3
- end
- end
- end
- }.should raise_error(ArgumentError, "circular causes")
- end
-
- it "re-raises a rescued exception" do
- -> do
- begin
- raise StandardError, "aaa"
- rescue Exception
- begin
- raise ArgumentError
- rescue ArgumentError
- end
-
- # should raise StandardError "aaa"
- raise
- end
- end.should raise_error(StandardError, "aaa")
- end
-
it "re-raises a previously rescued exception without overwriting the cause" do
begin
begin
@@ -283,10 +212,11 @@
end
end
-describe "Kernel#raise" do
- it_behaves_like :kernel_raise, :raise, Kernel
-end
-
describe "Kernel.raise" do
- it "needs to be reviewed for spec completeness"
+ it "is a public method" do
+ Kernel.singleton_class.should.public_method_defined?(:raise)
+ end
+
+ it_behaves_like :kernel_raise, :raise, Kernel
+ it_behaves_like :kernel_raise_with_cause, :raise, Kernel
end
diff --git a/spec/ruby/core/kernel/require_spec.rb b/spec/ruby/core/kernel/require_spec.rb
index da2f48fb61500b..c609809df55e92 100644
--- a/spec/ruby/core/kernel/require_spec.rb
+++ b/spec/ruby/core/kernel/require_spec.rb
@@ -16,28 +16,34 @@
Kernel.should have_private_instance_method(:require)
end
- provided = %w[complex enumerator fiber rational thread ruby2_keywords]
- ruby_version_is "4.0" do
- provided << "set"
- provided << "pathname"
- end
- ruby_version_is "4.1" do
- provided << "monitor"
- end
+ it "provided features are already required" do
+ provided = %w[complex enumerator fiber rational thread ruby2_keywords]
+ ruby_version_is "4.0" do
+ provided += %w[set pathname]
+ end
+ ruby_version_is "4.1" do
+ provided += %w[monitor]
+ end
- it "#{provided.join(', ')} are already required" do
out = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems --disable-did-you-mean')
features = out.lines.map { |line| File.basename(line.chomp, '.*') }
- # Ignore CRuby internals
- features -= %w[encdb transdb windows_1252 windows_31]
+ # Ignore engine-specific internals
+ case RUBY_ENGINE
+ when "jruby"
+ features -= %w[java util]
+ else
+ features -= %w[encdb transdb windows_1252 windows_31]
+ end
features.reject! { |feature| feature.end_with?('-fake') }
features.sort.should == provided.sort
requires = provided
ruby_version_is "4.0" do
- requires = requires.map { |f| f == "pathname" ? "pathname.so" : f }
+ if RUBY_ENGINE != "jruby"
+ requires = requires.map { |f| f == "pathname" ? "pathname.so" : f }
+ end
end
ruby_version_is "4.1" do
diff --git a/spec/ruby/core/kernel/shared/sprintf.rb b/spec/ruby/core/kernel/shared/sprintf.rb
index 5ffe118035d683..e18747e6b851cc 100644
--- a/spec/ruby/core/kernel/shared/sprintf.rb
+++ b/spec/ruby/core/kernel/shared/sprintf.rb
@@ -934,10 +934,27 @@ def obj.to_str
}.should raise_error(ArgumentError)
end
- it "raises KeyError when there is no matching key" do
+ it "respects Hash#default when there is no set key" do
+ @method.call("%{foo}", Hash.new(123)).should == "123"
+ @method.call("%{foo}", Hash.new { 123 }).should == "123"
+ end
+
+ it "raises KeyError when Hash#default returns nil" do
-> {
@method.call("%{foo}", {})
- }.should raise_error(KeyError)
+ }.should raise_error(KeyError, 'key{foo} not found')
+
+ -> {
+ @method.call("%{foo}", Hash.new(nil))
+ }.should raise_error(KeyError, 'key{foo} not found')
+
+ -> {
+ @method.call("%{foo}", Hash.new { nil })
+ }.should raise_error(KeyError, 'key{foo} not found')
+ end
+
+ it "accepts a nil value for an existing key" do
+ @method.call("%{foo}", { foo: nil }).should == ""
end
it "converts value to String with to_s" do
diff --git a/spec/ruby/core/module/autoload_spec.rb b/spec/ruby/core/module/autoload_spec.rb
index 625d945686af4b..87b1d520555cd7 100644
--- a/spec/ruby/core/module/autoload_spec.rb
+++ b/spec/ruby/core/module/autoload_spec.rb
@@ -948,7 +948,7 @@ class ModuleSpecs::Autoload::Z < ModuleSpecs::Autoload::ZZ
begin
Object.const_get(mod_name).foo
- rescue NoMethodError
+ rescue NameError, NoMethodError # rubocop:disable Lint/ShadowedException
barrier.disable!
break false
end
@@ -956,7 +956,7 @@ class ModuleSpecs::Autoload::Z < ModuleSpecs::Autoload::ZZ
end
end
- # check that no thread got a NoMethodError because of partially loaded module
+ # check that no thread got a NameError or NoMethodError because of partially loaded module
threads.all? {|t| t.value}.should be_true
# check that the autoloaded file was evaled exactly once
@@ -965,6 +965,8 @@ class ModuleSpecs::Autoload::Z < ModuleSpecs::Autoload::ZZ
mod_names.each do |mod_name|
Object.send(:remove_const, mod_name)
end
+ ensure
+ threads.each(&:join) if threads
end
it "raises a NameError in each thread if the constant is not set" do
diff --git a/spec/ruby/core/mutex/lock_spec.rb b/spec/ruby/core/mutex/lock_spec.rb
index e9d33f5fd940d9..c1501e8ec26865 100644
--- a/spec/ruby/core/mutex/lock_spec.rb
+++ b/spec/ruby/core/mutex/lock_spec.rb
@@ -20,11 +20,73 @@
# Unable to find a specific ticket but behavior change may be
# related to this ML thread.
- it "raises a ThreadError when used recursively" do
+ it "raises a deadlock ThreadError when used recursively" do
m = Mutex.new
m.lock
-> {
m.lock
- }.should raise_error(ThreadError)
+ }.should raise_error(ThreadError, /deadlock/)
+ end
+
+ it "raises a deadlock ThreadError when multiple fibers from the same thread try to lock" do
+ m = Mutex.new
+
+ m.lock
+ f0 = Fiber.new do
+ m.lock
+ end
+ -> { f0.resume }.should raise_error(ThreadError, /deadlock/)
+
+ m.unlock
+ f1 = Fiber.new do
+ m.lock
+ Fiber.yield
+ end
+ f2 = Fiber.new do
+ m.lock
+ end
+ f1.resume
+ -> { f2.resume }.should raise_error(ThreadError, /deadlock/)
+ end
+
+ it "does not raise deadlock if a fiber's attempt to lock was interrupted" do
+ lock = Mutex.new
+ main = Thread.current
+
+ t2 = nil
+ t1 = Thread.new do
+ loop do
+ # interrupt fiber below looping on synchronize
+ sleep 0.01
+ t2.raise if t2
+ end
+ end
+
+ # loop ten times to try to handle the interrupt during synchronize
+ t2 = Thread.new do
+ 10.times do
+ Fiber.new do
+ begin
+ loop { lock.synchronize {} }
+ rescue RuntimeError
+ end
+ end.resume
+
+ Fiber.new do
+ -> do
+ lock.synchronize {}
+ end.should_not raise_error(ThreadError)
+ end.resume
+ rescue RuntimeError
+ retry
+ end
+ end
+ t2.join
+ ensure
+ t1.kill rescue nil
+ t2.kill rescue nil
+
+ t1.join
+ t2.join
end
end
diff --git a/spec/ruby/core/refinement/import_methods_spec.rb b/spec/ruby/core/refinement/import_methods_spec.rb
index 13c0b1004cdfea..dc3e0ea31d38d6 100644
--- a/spec/ruby/core/refinement/import_methods_spec.rb
+++ b/spec/ruby/core/refinement/import_methods_spec.rb
@@ -242,6 +242,26 @@ def foo(number)
end
end
+ it "correctly sets owner as the refinement module" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+ end
+
+ refinement = Module.new do
+ refine String do
+ import_methods str_utils
+ end
+ end
+
+ Module.new do
+ using refinement
+
+ String.instance_method(:indent).owner.should == refinement.refinements.first
+ end
+ end
+
context "when methods are not defined in Ruby code" do
it "raises ArgumentError" do
Module.new do
diff --git a/spec/ruby/core/regexp/linear_time_spec.rb b/spec/ruby/core/regexp/linear_time_spec.rb
index 2f3f81ed207236..f70021dfed647f 100644
--- a/spec/ruby/core/regexp/linear_time_spec.rb
+++ b/spec/ruby/core/regexp/linear_time_spec.rb
@@ -25,7 +25,56 @@
}.should complain(/warning: flags ignored/)
end
- it "returns true for positive lookarounds" do
- Regexp.linear_time?(/(?:(?=a*)a)*/).should == true
+ it "returns true for positive lookahead" do
+ Regexp.linear_time?(/a*(?:(?=a*)a)*b/).should == true
+ end
+
+ it "returns true for positive lookbehind" do
+ Regexp.linear_time?(/a*(?:(?<=a)a*)*b/).should == true
+ end
+
+ it "returns true for negative lookbehind" do
+ Regexp.linear_time?(/a*(?:(? { uses_regexp_caching } do
+ it "returns true for negative lookahead" do
+ Regexp.linear_time?(/a*(?:(?!a*)a*)*b/).should == true
+ end
+
+ it "returns true for atomic groups" do
+ Regexp.linear_time?(/a*(?:(?>a)a*)*b/).should == true
+ end
+
+ it "returns true for possessive quantifiers" do
+ Regexp.linear_time?(/a*(?:(?:a)?+a*)*b/).should == true
+ end
+
+ it "returns true for positive lookbehind with capture group" do
+ Regexp.linear_time?(/.(?<=(a))/).should == true
+ end
+ end
+
+ # The following specs should not be relied upon,
+ # they are here only to illustrate differences between Regexp engines.
+ guard -> { uses_dfa_regexp_engine } do
+ it "returns true for non-recursive subexpression call" do
+ Regexp.linear_time?(/(?a){0}\g/).should == true
+ end
+
+ it "returns true for positive lookahead with capture group" do
+ Regexp.linear_time?(/x+(?=(a))/).should == true
+ end
end
end
diff --git a/spec/ruby/core/string/shared/encode.rb b/spec/ruby/core/string/shared/encode.rb
index 9466308886ee9d..51a117c90ed564 100644
--- a/spec/ruby/core/string/shared/encode.rb
+++ b/spec/ruby/core/string/shared/encode.rb
@@ -72,6 +72,14 @@
"abc".send(@method, "xyz")
end.should raise_error(Encoding::ConverterNotFoundError)
end
+
+ it "raises an Encoding::UndefinedConversionError when a character cannot be represented in the destination encoding" do
+ # U+0100 (Ā) is valid UTF-8 but not representable in windows-1252
+ str = "test\u0100".force_encoding('utf-8')
+ -> {
+ str.send(@method, Encoding::Windows_1252)
+ }.should raise_error(Encoding::UndefinedConversionError)
+ end
end
describe "when passed options" do
@@ -142,6 +150,14 @@
"ab#{xFF}c".send(@method, Encoding::ISO_8859_1, invalid: :replace).should == "ab?c"
end
+ it "raises UndefinedConversionError for characters not representable in destination encoding with only invalid: :replace" do
+ # U+0100 (Ā) is valid UTF-8 but not representable in windows-1252
+ str = "test\u0100".force_encoding('utf-8')
+ -> {
+ str.send(@method, Encoding::Windows_1252, invalid: :replace, replace: "")
+ }.should raise_error(Encoding::UndefinedConversionError)
+ end
+
it "calls #to_hash to convert the options object" do
options = mock("string encode options")
options.should_receive(:to_hash).and_return({ undef: :replace })
diff --git a/spec/ruby/core/string/split_spec.rb b/spec/ruby/core/string/split_spec.rb
index 3c6d1864d1797e..cada1a6789353d 100644
--- a/spec/ruby/core/string/split_spec.rb
+++ b/spec/ruby/core/string/split_spec.rb
@@ -119,21 +119,21 @@
$; = old_fs
end
end
+ end
- context "when $; is not nil" do
- before do
- suppress_warning do
- @old_value, $; = $;, 'foobar'
- end
+ context "when $; is not nil" do
+ before do
+ suppress_warning do
+ @old_value, $; = $;, 'foobar'
end
+ end
- after do
- $; = @old_value
- end
+ after do
+ $; = @old_value
+ end
- it "warns" do
- -> { "".split }.should complain(/warning: \$; is set to non-nil value/)
- end
+ it "warns" do
+ -> { "".split }.should complain(/warning: \$; is set to non-nil value/)
end
end
diff --git a/spec/ruby/core/string/to_f_spec.rb b/spec/ruby/core/string/to_f_spec.rb
index abfd2517b69327..520a797af97764 100644
--- a/spec/ruby/core/string/to_f_spec.rb
+++ b/spec/ruby/core/string/to_f_spec.rb
@@ -120,12 +120,10 @@
"\3771.2".b.to_f.should == 0
end
- ruby_version_is "3.2.3" do
- it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
- -> {
- '1.2'.encode("UTF-16").to_f
- }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
- end
+ it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
+ -> {
+ '1.2'.encode("UTF-16").to_f
+ }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
end
it "allows String representation without a fractional part" do
diff --git a/spec/ruby/core/struct/fixtures/classes.rb b/spec/ruby/core/struct/fixtures/classes.rb
index 7b80b814efc909..675d403abde28f 100644
--- a/spec/ruby/core/struct/fixtures/classes.rb
+++ b/spec/ruby/core/struct/fixtures/classes.rb
@@ -3,6 +3,7 @@ module StructClasses
class Apple < Struct; end
Ruby = Struct.new(:version, :platform)
+ Single = Struct.new(:value)
Car = Struct.new(:make, :model, :year)
diff --git a/spec/ruby/core/struct/initialize_spec.rb b/spec/ruby/core/struct/initialize_spec.rb
index 06055594d5b18d..6a541d7c9edb3b 100644
--- a/spec/ruby/core/struct/initialize_spec.rb
+++ b/spec/ruby/core/struct/initialize_spec.rb
@@ -48,4 +48,27 @@
positional_args.version.should == keyword_args.version
positional_args.platform.should == keyword_args.platform
end
+
+ it "accepts positional arguments with empty keyword arguments" do
+ data = StructClasses::Single.new(42, **{})
+
+ data.value.should == 42
+
+ data = StructClasses::Ruby.new("3.2", "OS", **{})
+
+ data.version.should == "3.2"
+ data.platform.should == "OS"
+ end
+
+ it "can be called via delegated ... from a prepended module" do
+ wrapper = Module.new do
+ def initialize(...)
+ super(...)
+ end
+ end
+
+ klass = Class.new(Struct.new(:a)) { prepend wrapper }
+ s = klass.new("x")
+ s.a.should == "x"
+ end
end
diff --git a/spec/ruby/core/thread/raise_spec.rb b/spec/ruby/core/thread/raise_spec.rb
index b473eabd42c492..996b07b1b81de6 100644
--- a/spec/ruby/core/thread/raise_spec.rb
+++ b/spec/ruby/core/thread/raise_spec.rb
@@ -3,8 +3,15 @@
require_relative '../../shared/kernel/raise'
describe "Thread#raise" do
+ it "is a public method" do
+ Thread.public_instance_methods.should include(:raise)
+ end
+
it_behaves_like :kernel_raise, :raise, ThreadSpecs::NewThreadToRaise
it_behaves_like :kernel_raise_across_contexts, :raise, ThreadSpecs::NewThreadToRaise
+ ruby_version_is "4.0" do
+ it_behaves_like :kernel_raise_with_cause, :raise, ThreadSpecs::NewThreadToRaise
+ end
it "ignores dead threads and returns nil" do
t = Thread.new { :dead }
diff --git a/spec/ruby/core/time/new_spec.rb b/spec/ruby/core/time/new_spec.rb
index f3b5d0142044b4..e4e54e16a39fe7 100644
--- a/spec/ruby/core/time/new_spec.rb
+++ b/spec/ruby/core/time/new_spec.rb
@@ -570,18 +570,16 @@ def obj.to_int; 3; end
}.should raise_error(ArgumentError, /missing min part: 00 |can't parse:/)
end
- ruby_version_is "3.2.3" do
- it "raises ArgumentError if the time part is missing" do
- -> {
- Time.new("2020-12-25")
- }.should raise_error(ArgumentError, /no time information|can't parse:/)
- end
+ it "raises ArgumentError if the time part is missing" do
+ -> {
+ Time.new("2020-12-25")
+ }.should raise_error(ArgumentError, /no time information|can't parse:/)
+ end
- it "raises ArgumentError if day is missing" do
- -> {
- Time.new("2020-12")
- }.should raise_error(ArgumentError, /no time information|can't parse:/)
- end
+ it "raises ArgumentError if day is missing" do
+ -> {
+ Time.new("2020-12")
+ }.should raise_error(ArgumentError, /no time information|can't parse:/)
end
it "raises ArgumentError if subsecond is missing after dot" do
@@ -720,24 +718,22 @@ def obj.to_int; 3; end
}.should raise_error(ArgumentError, /can't parse.+ abc/)
end
- ruby_version_is "3.2.3" do
- it "raises ArgumentError when there are leading space characters" do
- -> { Time.new(" 2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\t2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\n2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\v2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\f2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\r2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- end
+ it "raises ArgumentError when there are leading space characters" do
+ -> { Time.new(" 2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("\t2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("\n2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("\v2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("\f2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("\r2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
+ end
- it "raises ArgumentError when there are trailing whitespaces" do
- -> { Time.new("2020-12-02 00:00:00 ") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\t") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\n") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\v") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\f") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\r") }.should raise_error(ArgumentError, /can't parse/)
- end
+ it "raises ArgumentError when there are trailing whitespaces" do
+ -> { Time.new("2020-12-02 00:00:00 ") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\t") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\n") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\v") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\f") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\r") }.should raise_error(ArgumentError, /can't parse/)
end
end
end
diff --git a/spec/ruby/language/ensure_spec.rb b/spec/ruby/language/ensure_spec.rb
index b76292c0075aeb..1b44457f6a051f 100644
--- a/spec/ruby/language/ensure_spec.rb
+++ b/spec/ruby/language/ensure_spec.rb
@@ -6,7 +6,7 @@
ScratchPad.record []
end
- it "is executed when an exception is raised in it's corresponding begin block" do
+ it "is executed when an exception is raised in its corresponding begin block" do
-> {
begin
ScratchPad << :begin
@@ -19,7 +19,7 @@
ScratchPad.recorded.should == [:begin, :ensure]
end
- it "is executed when an exception is raised and rescued in it's corresponding begin block" do
+ it "is executed when an exception is raised and rescued in its corresponding begin block" do
begin
ScratchPad << :begin
raise "An exception occurred!"
@@ -32,7 +32,7 @@
ScratchPad.recorded.should == [:begin, :rescue, :ensure]
end
- it "is executed even when a symbol is thrown in it's corresponding begin block" do
+ it "is executed even when a symbol is thrown in its corresponding begin block" do
catch(:symbol) do
begin
ScratchPad << :begin
@@ -47,7 +47,7 @@
ScratchPad.recorded.should == [:begin, :ensure]
end
- it "is executed when nothing is raised or thrown in it's corresponding begin block" do
+ it "is executed when nothing is raised or thrown in its corresponding begin block" do
begin
ScratchPad << :begin
rescue
@@ -256,7 +256,7 @@ class EnsureInClassExample
ScratchPad.record []
end
- it "is executed when an exception is raised in it's corresponding begin block" do
+ it "is executed when an exception is raised in its corresponding begin block" do
-> {
eval(<<-ruby).call
lambda do
@@ -271,7 +271,7 @@ class EnsureInClassExample
ScratchPad.recorded.should == [:begin, :ensure]
end
- it "is executed when an exception is raised and rescued in it's corresponding begin block" do
+ it "is executed when an exception is raised and rescued in its corresponding begin block" do
eval(<<-ruby).call
lambda do
ScratchPad << :begin
@@ -286,7 +286,7 @@ class EnsureInClassExample
ScratchPad.recorded.should == [:begin, :rescue, :ensure]
end
- it "is executed even when a symbol is thrown in it's corresponding begin block" do
+ it "is executed even when a symbol is thrown in its corresponding begin block" do
catch(:symbol) do
eval(<<-ruby).call
lambda do
@@ -303,7 +303,7 @@ class EnsureInClassExample
ScratchPad.recorded.should == [:begin, :ensure]
end
- it "is executed when nothing is raised or thrown in it's corresponding begin block" do
+ it "is executed when nothing is raised or thrown in its corresponding begin block" do
eval(<<-ruby).call
lambda do
ScratchPad << :begin
diff --git a/spec/ruby/language/fixtures/super.rb b/spec/ruby/language/fixtures/super.rb
index c5bdcf0e402780..b6d4218b03446e 100644
--- a/spec/ruby/language/fixtures/super.rb
+++ b/spec/ruby/language/fixtures/super.rb
@@ -266,7 +266,7 @@ def name
# Use this so that we can see collect all supers that we see.
# One bug that arises is that we call Alias2#name from Alias2#name
- # as it's superclass. In that case, either we get a runaway recursion
+ # as its superclass. In that case, either we get a runaway recursion
# super OR we get the return value being [:alias2, :alias2, :alias1]
# rather than [:alias2, :alias1].
#
diff --git a/spec/ruby/language/keyword_arguments_spec.rb b/spec/ruby/language/keyword_arguments_spec.rb
index c51c3bc656d4e9..d769839bdaa2a5 100644
--- a/spec/ruby/language/keyword_arguments_spec.rb
+++ b/spec/ruby/language/keyword_arguments_spec.rb
@@ -86,6 +86,20 @@ def m(*a)
m(*[], 42, **{}).should == [42]
end
+ context "marked as ruby2_keywords_hash" do
+ it "is not copied when passed as a positional argument" do
+ h = Hash.ruby2_keywords_hash(a:1)
+
+ def bar(a)
+ a
+ end
+
+ h2 = bar(h)
+ h2.should equal(h)
+ Hash.ruby2_keywords_hash?(h).should == true
+ end
+ end
+
context "**" do
it "copies a non-empty Hash for a method taking (*args)" do
def m(*args)
diff --git a/spec/ruby/language/lambda_spec.rb b/spec/ruby/language/lambda_spec.rb
index ed5a1c69e84b98..8a73b51d2cff2b 100644
--- a/spec/ruby/language/lambda_spec.rb
+++ b/spec/ruby/language/lambda_spec.rb
@@ -286,6 +286,24 @@ def a; 1; end
end
end
end
+
+ evaluate <<-ruby do
+ @a = -> (**nil) { :ok }
+ ruby
+
+ @a.call().should == :ok
+ -> { @a.call(a: 1) }.should raise_error(ArgumentError, 'no keywords accepted')
+ -> { @a.call(**{a: 1}) }.should raise_error(ArgumentError, 'no keywords accepted')
+ -> { @a.call("a" => 1) }.should raise_error(ArgumentError, 'no keywords accepted')
+ end
+
+ evaluate <<-ruby do
+ @a = -> (a, **nil) { a }
+ ruby
+
+ @a.call({a: 1}).should == {a: 1}
+ -> { @a.call(a: 1) }.should raise_error(ArgumentError, 'no keywords accepted')
+ end
end
describe "A lambda expression 'lambda { ... }'" do
@@ -583,5 +601,23 @@ def m2() yield end
result = @a.(1, 2, e: 3, g: 4, h: 5, i: 6, &(l = ->{}))
result.should == [1, 1, [], 2, 3, 2, 4, { h: 5, i: 6 }, l]
end
+
+ evaluate <<-ruby do
+ @a = lambda { |**nil| :ok }
+ ruby
+
+ @a.call().should == :ok
+ -> { @a.call(a: 1) }.should raise_error(ArgumentError, 'no keywords accepted')
+ -> { @a.call(**{a: 1}) }.should raise_error(ArgumentError, 'no keywords accepted')
+ -> { @a.call("a" => 1) }.should raise_error(ArgumentError, 'no keywords accepted')
+ end
+
+ evaluate <<-ruby do
+ @a = lambda { |a, **nil| a }
+ ruby
+
+ @a.call({a: 1}).should == {a: 1}
+ -> { @a.call(a: 1) }.should raise_error(ArgumentError, 'no keywords accepted')
+ end
end
end
diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb
index dd93703d9f4fe6..00a087b33730bf 100644
--- a/spec/ruby/language/method_spec.rb
+++ b/spec/ruby/language/method_spec.rb
@@ -1100,6 +1100,16 @@ def m(a, b=1, *c, d, e:, f: 2, g:, **k, &l)
result.should == [1, 1, [], 2, 3, 2, 4, { h: 5, i: 6 }, l]
end
+ evaluate <<-ruby do
+ def m(**nil); :ok; end;
+ ruby
+
+ m().should == :ok
+ -> { m(a: 1) }.should raise_error(ArgumentError, 'no keywords accepted')
+ -> { m(**{a: 1}) }.should raise_error(ArgumentError, 'no keywords accepted')
+ -> { m("a" => 1) }.should raise_error(ArgumentError, 'no keywords accepted')
+ end
+
evaluate <<-ruby do
def m(a, **nil); a end;
ruby
diff --git a/spec/ruby/language/predefined_spec.rb b/spec/ruby/language/predefined_spec.rb
index fc1667a38fe8d0..948ad2647528ac 100644
--- a/spec/ruby/language/predefined_spec.rb
+++ b/spec/ruby/language/predefined_spec.rb
@@ -720,6 +720,7 @@ def foo
$/.should equal(str)
end
end
+
it "can be assigned nil" do
$/ = nil
$/.should be_nil
diff --git a/spec/ruby/language/proc_spec.rb b/spec/ruby/language/proc_spec.rb
index ca9a13aa615e2e..f26f82b015588a 100644
--- a/spec/ruby/language/proc_spec.rb
+++ b/spec/ruby/language/proc_spec.rb
@@ -246,4 +246,22 @@
-> { p.call() }.should raise_error(ArgumentError)
end
end
+
+ evaluate <<-ruby do
+ @p = proc { |**nil| :ok }
+ ruby
+
+ @p.call().should == :ok
+ -> { @p.call(a: 1) }.should raise_error(ArgumentError, 'no keywords accepted')
+ -> { @p.call(**{a: 1}) }.should raise_error(ArgumentError, 'no keywords accepted')
+ -> { @p.call("a" => 1) }.should raise_error(ArgumentError, 'no keywords accepted')
+ end
+
+ evaluate <<-ruby do
+ @p = proc { |a, **nil| a }
+ ruby
+
+ @p.call({a: 1}).should == {a: 1}
+ -> { @p.call(a: 1) }.should raise_error(ArgumentError, 'no keywords accepted')
+ end
end
diff --git a/spec/ruby/language/singleton_class_spec.rb b/spec/ruby/language/singleton_class_spec.rb
index 45e1f7f3ad5936..958bf464a7c9c0 100644
--- a/spec/ruby/language/singleton_class_spec.rb
+++ b/spec/ruby/language/singleton_class_spec.rb
@@ -60,7 +60,7 @@
ClassSpecs::H.singleton_class.singleton_class
end
- it "for BasicObject has Class as it's superclass" do
+ it "for BasicObject has Class as its superclass" do
BasicObject.singleton_class.superclass.should == Class
end
diff --git a/spec/ruby/language/string_spec.rb b/spec/ruby/language/string_spec.rb
index f287731bed518e..050ffaa4e777a9 100644
--- a/spec/ruby/language/string_spec.rb
+++ b/spec/ruby/language/string_spec.rb
@@ -133,6 +133,12 @@ class << obj
"#{obj}".should == '42'
end
+ it "raise NoMethodError when #to_s is not defined for the object" do
+ obj = BasicObject.new
+
+ -> { "#{obj}" }.should raise_error(NoMethodError)
+ end
+
it "uses an internal representation when #to_s doesn't return a String" do
obj = mock('to_s')
obj.stub!(:to_s).and_return(42)
diff --git a/spec/ruby/language/super_spec.rb b/spec/ruby/language/super_spec.rb
index 7d9e896d8b1199..e205fae13cedda 100644
--- a/spec/ruby/language/super_spec.rb
+++ b/spec/ruby/language/super_spec.rb
@@ -461,4 +461,18 @@ def obj.foobar(array)
@all.foo('a', b: 'b').should == [['a'], {b: 'b'}]
end
end
+
+ it "works in method definitions using **nil" do
+ parent = Class.new do
+ def m(*args, **kwargs)
+ [args, kwargs]
+ end
+ end
+ child = Class.new(parent) do
+ def m(*args, **nil)
+ super
+ end
+ end
+ child.new.m(1, 2).should == [[1, 2], {}]
+ end
end
diff --git a/spec/ruby/language/yield_spec.rb b/spec/ruby/language/yield_spec.rb
index e125cf8e738bea..3b1313914f2ede 100644
--- a/spec/ruby/language/yield_spec.rb
+++ b/spec/ruby/language/yield_spec.rb
@@ -48,6 +48,12 @@
it "passes a single, multi-value Array" do
@y.s([1, 2, 3]) { |*a| a }.should == [[1, 2, 3]]
end
+
+ describe "with optional argument" do
+ it "does not destructure a single array argument" do
+ @y.s([1, 2, 3]) { |a = 99| a }.should == [1, 2, 3]
+ end
+ end
end
describe "yielding to a lambda" do
diff --git a/spec/ruby/library/cgi/htmlextension/multipart_form_spec.rb b/spec/ruby/library/cgi/htmlextension/multipart_form_spec.rb
index ee1c45b84e267e..4b56a7abfe34a2 100644
--- a/spec/ruby/library/cgi/htmlextension/multipart_form_spec.rb
+++ b/spec/ruby/library/cgi/htmlextension/multipart_form_spec.rb
@@ -11,7 +11,7 @@
end
describe "when passed no arguments" do
- it "returns a 'form'-element with it's enctype set to multipart" do
+ it "returns a 'form'-element with its enctype set to multipart" do
output = @html.multipart_form
output.should equal_element("FORM", { "ENCTYPE" => "multipart/form-data", "METHOD" => "post" }, "")
end
diff --git a/spec/ruby/library/pathname/glob_spec.rb b/spec/ruby/library/pathname/glob_spec.rb
index de322bab476341..6249d0ae021bd6 100644
--- a/spec/ruby/library/pathname/glob_spec.rb
+++ b/spec/ruby/library/pathname/glob_spec.rb
@@ -41,7 +41,7 @@
it "raises an ArgumentError when supplied a keyword argument other than :base" do
-> {
Pathname.glob('*i*.rb', foo: @dir + 'lib')
- }.should raise_error(ArgumentError, /unknown keyword: :?foo/)
+ }.should raise_error(ArgumentError, "unknown keyword: :foo")
end
it "does not raise an ArgumentError when supplied a flag and :base keyword argument" do
diff --git a/spec/ruby/library/socket/addrinfo/initialize_spec.rb b/spec/ruby/library/socket/addrinfo/initialize_spec.rb
index c556bd758b925a..931984b6515b43 100644
--- a/spec/ruby/library/socket/addrinfo/initialize_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/initialize_spec.rb
@@ -53,11 +53,11 @@
@addrinfo.ip_port.should == 25
end
- it "returns the specified family" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET6
end
- it "returns the specified family" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET6
end
@@ -83,11 +83,11 @@
@addrinfo.ip_port.should == 25
end
- it "returns the specified family" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET6
end
- it "returns the specified family" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET6
end
@@ -113,11 +113,11 @@
@addrinfo.ip_port.should == 25
end
- it "returns the specified family" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET6
end
- it "returns the specified family" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET6
end
@@ -147,11 +147,11 @@
@addrinfo.ip_port.should == 46102
end
- it "returns the specified family" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET
end
- it "returns the specified family" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET
end
@@ -217,11 +217,11 @@
@addrinfo.ip_port.should == 46102
end
- it "returns the specified family" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET
end
- it "returns the specified family" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET
end
@@ -247,11 +247,11 @@
@addrinfo.ip_port.should == 46102
end
- it "returns the specified family" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET
end
- it "returns the specified family" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET
end
@@ -311,11 +311,11 @@
@addrinfo.ip_port.should == 46102
end
- it "returns the specified family" do
+ it "returns the specified pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET
end
- it "returns the specified family" do
+ it "returns the specified afamily" do
@addrinfo.afamily.should == Socket::AF_INET
end
@@ -514,13 +514,13 @@
@sockaddr = Socket.sockaddr_in(80, '127.0.0.1')
end
- it 'returns an Addrinfo with the specified family' do
+ it 'returns an Addrinfo with the specified pfamily for :PF_INET' do
addr = Addrinfo.new(@sockaddr, :PF_INET)
addr.pfamily.should == Socket::PF_INET
end
- it 'returns an Addrinfo with the specified family' do
+ it 'returns an Addrinfo with the specified pfamily for :INET' do
addr = Addrinfo.new(@sockaddr, :INET)
addr.pfamily.should == Socket::PF_INET
@@ -544,13 +544,13 @@
@sockaddr = Socket.sockaddr_in(80, '127.0.0.1')
end
- it 'returns an Addrinfo with the specified family' do
+ it 'returns an Addrinfo with the specified pfamily for PF_INET' do
addr = Addrinfo.new(@sockaddr, 'PF_INET')
addr.pfamily.should == Socket::PF_INET
end
- it 'returns an Addrinfo with the specified family' do
+ it 'returns an Addrinfo with the specified pfamily for INET' do
addr = Addrinfo.new(@sockaddr, 'INET')
addr.pfamily.should == Socket::PF_INET
diff --git a/spec/ruby/optional/capi/encoding_spec.rb b/spec/ruby/optional/capi/encoding_spec.rb
index 734b5f125381db..260ebc88a437cc 100644
--- a/spec/ruby/optional/capi/encoding_spec.rb
+++ b/spec/ruby/optional/capi/encoding_spec.rb
@@ -452,7 +452,7 @@
describe "rb_enc_compatible" do
it "returns 0 if the encodings of the Strings are not compatible" do
a = [0xff].pack('C').force_encoding "binary"
- b = "\u3042".encode("utf-8")
+ b = "あ"
@s.rb_enc_compatible(a, b).should == 0
end
@@ -461,11 +461,25 @@
# Encoding.compatible?
it "returns the same value as Encoding.compatible? if the Strings have a compatible encoding" do
a = "abc".force_encoding("us-ascii")
- b = "\u3042".encode("utf-8")
+ b = "あ"
@s.rb_enc_compatible(a, b).should == Encoding.compatible?(a, b)
end
end
+ describe "rb_enc_check" do
+ it "returns the compatible encoding of the two Strings" do
+ a = "abc".force_encoding("us-ascii")
+ b = "あ"
+ @s.rb_enc_check(a, b).should == Encoding::UTF_8
+ end
+
+ it "raises Encoding::CompatibilityError if the encodings are not compatible" do
+ a = [0xff].pack('C').b
+ b = "あ"
+ -> { @s.rb_enc_check(a, b) }.should raise_error(Encoding::CompatibilityError)
+ end
+ end
+
describe "rb_enc_copy" do
before :each do
@obj = "rb_enc_copy".encode(Encoding::US_ASCII)
diff --git a/spec/ruby/optional/capi/ext/encoding_spec.c b/spec/ruby/optional/capi/ext/encoding_spec.c
index 98d4e2e3b772c8..2038a5d4a85e50 100644
--- a/spec/ruby/optional/capi/ext/encoding_spec.c
+++ b/spec/ruby/optional/capi/ext/encoding_spec.c
@@ -91,6 +91,11 @@ static VALUE encoding_spec_rb_enc_compatible(VALUE self, VALUE a, VALUE b) {
return rb_enc_from_encoding(enc);
}
+static VALUE encoding_spec_rb_enc_check(VALUE self, VALUE a, VALUE b) {
+ rb_encoding* enc = rb_enc_check(a, b);
+ return rb_enc_from_encoding(enc);
+}
+
static VALUE encoding_spec_rb_enc_copy(VALUE self, VALUE dest, VALUE src) {
rb_enc_copy(dest, src);
return dest;
@@ -353,6 +358,7 @@ void Init_encoding_spec(void) {
rb_define_method(cls, "rb_enc_associate", encoding_spec_rb_enc_associate, 2);
rb_define_method(cls, "rb_enc_associate_index", encoding_spec_rb_enc_associate_index, 2);
rb_define_method(cls, "rb_enc_compatible", encoding_spec_rb_enc_compatible, 2);
+ rb_define_method(cls, "rb_enc_check", encoding_spec_rb_enc_check, 2);
rb_define_method(cls, "rb_enc_copy", encoding_spec_rb_enc_copy, 2);
rb_define_method(cls, "rb_enc_codelen", encoding_spec_rb_enc_codelen, 2);
rb_define_method(cls, "rb_enc_strlen", encoding_spec_rb_enc_strlen, 3);
diff --git a/spec/ruby/optional/capi/ext/io_spec.c b/spec/ruby/optional/capi/ext/io_spec.c
index f3ede15729bde2..fe31cffb495241 100644
--- a/spec/ruby/optional/capi/ext/io_spec.c
+++ b/spec/ruby/optional/capi/ext/io_spec.c
@@ -287,6 +287,18 @@ VALUE io_spec_rb_cloexec_open(VALUE self, VALUE path, VALUE flags, VALUE mode) {
return rb_funcall(rb_cIO, rb_intern("for_fd"), 1, INT2FIX(fd));
}
+VALUE io_spec_rb_cloexec_dup(VALUE self, VALUE io) {
+ int fd = io_spec_get_fd(io);
+ int new_fd = rb_cloexec_dup(fd);
+ return rb_funcall(rb_cIO, rb_intern("for_fd"), 1, INT2FIX(new_fd));
+}
+
+VALUE io_spec_rb_cloexec_fcntl_dupfd(VALUE self, VALUE io, VALUE minfd) {
+ int fd = io_spec_get_fd(io);
+ int new_fd = rb_cloexec_fcntl_dupfd(fd, FIX2INT(minfd));
+ return rb_funcall(rb_cIO, rb_intern("for_fd"), 1, INT2FIX(new_fd));
+}
+
VALUE io_spec_rb_io_close(VALUE self, VALUE io) {
return rb_io_close(io);
}
@@ -319,13 +331,7 @@ static VALUE io_spec_errno_set(VALUE self, VALUE val) {
VALUE io_spec_mode_sync_flag(VALUE self, VALUE io) {
int mode;
-#ifdef RUBY_VERSION_IS_3_3
mode = rb_io_mode(io);
-#else
- rb_io_t *fp;
- GetOpenFile(io, fp);
- mode = fp->mode;
-#endif
if (mode & FMODE_SYNC) {
return Qtrue;
} else {
@@ -333,7 +339,6 @@ VALUE io_spec_mode_sync_flag(VALUE self, VALUE io) {
}
}
-#if defined(RUBY_VERSION_IS_3_3) || defined(TRUFFLERUBY)
static VALUE io_spec_rb_io_mode(VALUE self, VALUE io) {
return INT2FIX(rb_io_mode(io));
}
@@ -360,7 +365,6 @@ static VALUE io_spec_rb_io_open_descriptor(VALUE self, VALUE klass, VALUE descri
static VALUE io_spec_rb_io_open_descriptor_without_encoding(VALUE self, VALUE klass, VALUE descriptor, VALUE mode, VALUE path, VALUE timeout) {
return rb_io_open_descriptor(klass, FIX2INT(descriptor), FIX2INT(mode), path, timeout, NULL);
}
-#endif
void Init_io_spec(void) {
VALUE cls = rb_define_class("CApiIOSpecs", rb_cObject);
@@ -391,9 +395,10 @@ void Init_io_spec(void) {
rb_define_method(cls, "rb_io_binmode", io_spec_rb_io_binmode, 1);
rb_define_method(cls, "rb_fd_fix_cloexec", io_spec_rb_fd_fix_cloexec, 1);
rb_define_method(cls, "rb_cloexec_open", io_spec_rb_cloexec_open, 3);
+ rb_define_method(cls, "rb_cloexec_dup", io_spec_rb_cloexec_dup, 1);
+ rb_define_method(cls, "rb_cloexec_fcntl_dupfd", io_spec_rb_cloexec_fcntl_dupfd, 2);
rb_define_method(cls, "errno=", io_spec_errno_set, 1);
rb_define_method(cls, "rb_io_mode_sync_flag", io_spec_mode_sync_flag, 1);
-#if defined(RUBY_VERSION_IS_3_3) || defined(TRUFFLERUBY)
rb_define_method(cls, "rb_io_mode", io_spec_rb_io_mode, 1);
rb_define_method(cls, "rb_io_path", io_spec_rb_io_path, 1);
rb_define_method(cls, "rb_io_closed_p", io_spec_rb_io_closed_p, 1);
@@ -404,7 +409,6 @@ void Init_io_spec(void) {
rb_define_const(cls, "FMODE_BINMODE", INT2FIX(FMODE_BINMODE));
rb_define_const(cls, "FMODE_TEXTMODE", INT2FIX(FMODE_TEXTMODE));
rb_define_const(cls, "ECONV_UNIVERSAL_NEWLINE_DECORATOR", INT2FIX(ECONV_UNIVERSAL_NEWLINE_DECORATOR));
-#endif
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/rubyspec.h b/spec/ruby/optional/capi/ext/rubyspec.h
index 6c4bea5da0e124..7107bead90ebff 100644
--- a/spec/ruby/optional/capi/ext/rubyspec.h
+++ b/spec/ruby/optional/capi/ext/rubyspec.h
@@ -43,8 +43,4 @@
#define RUBY_VERSION_IS_3_4
#endif
-#if RUBY_VERSION_SINCE(3, 3)
-#define RUBY_VERSION_IS_3_3
-#endif
-
#endif
diff --git a/spec/ruby/optional/capi/ext/string_spec.c b/spec/ruby/optional/capi/ext/string_spec.c
index 74aa9e56e816fe..f41d6fa1737057 100644
--- a/spec/ruby/optional/capi/ext/string_spec.c
+++ b/spec/ruby/optional/capi/ext/string_spec.c
@@ -296,6 +296,26 @@ VALUE string_spec_rb_str_substr(VALUE self, VALUE str, VALUE beg, VALUE len) {
return rb_str_substr(str, FIX2INT(beg), FIX2INT(len));
}
+VALUE string_spec_rb_str_subpos(VALUE self, VALUE str, VALUE beg) {
+ char* original = RSTRING_PTR(str);
+ char* end = RSTRING_END(str);
+ long len = rb_str_strlen(str);
+ char *p = rb_str_subpos(str, FIX2LONG(beg), &len);
+ if (p == NULL) {
+ return Qnil;
+ }
+
+ if (p >= original && p <= end) {
+ return rb_ary_new_from_args(2, LONG2FIX(p - RSTRING_PTR(str)), LONG2FIX(len));
+ } else {
+ rb_raise(rb_eRuntimeError, "the returned pointer is not inside the original string buffer");
+ }
+}
+
+VALUE string_spec_rb_str_sublen(VALUE self, VALUE str, VALUE pos) {
+ return LONG2FIX(rb_str_sublen(str, FIX2LONG(pos)));
+}
+
VALUE string_spec_rb_str_to_str(VALUE self, VALUE arg) {
return rb_str_to_str(arg);
}
@@ -308,6 +328,11 @@ VALUE string_spec_RSTRING_LENINT(VALUE self, VALUE str) {
return INT2FIX(RSTRING_LENINT(str));
}
+VALUE string_spec_RSTRING_PTR(VALUE self, VALUE str) {
+ char* ptr = RSTRING_PTR(str);
+ return LONG2FIX((long)ptr);
+}
+
VALUE string_spec_RSTRING_PTR_iterate(VALUE self, VALUE str) {
int i;
char* ptr;
@@ -393,6 +418,7 @@ VALUE string_spec_RSTRING_PTR_read(VALUE self, VALUE str, VALUE path) {
if (read(fd, buffer, 30) < 0) {
rb_syserr_fail(errno, "read");
}
+ rb_str_set_len(str, 30);
rb_str_modify_expand(str, 53);
rb_ary_push(capacities, SIZET2NUM(rb_str_capacity(str)));
@@ -531,7 +557,10 @@ static VALUE string_spec_rb_str_modify(VALUE self, VALUE str) {
}
static VALUE string_spec_rb_utf8_str_new_static(VALUE self) {
- return rb_utf8_str_new_static("nokogiri", 8);
+ const char* literal = "nokogiri";
+ return rb_ary_new_from_args(2,
+ rb_utf8_str_new_static("nokogiri", 8),
+ LONG2FIX((long)literal));
}
static VALUE string_spec_rb_utf8_str_new(VALUE self) {
@@ -645,9 +674,12 @@ void Init_string_spec(void) {
rb_define_method(cls, "rb_str_split", string_spec_rb_str_split, 1);
rb_define_method(cls, "rb_str_subseq", string_spec_rb_str_subseq, 3);
rb_define_method(cls, "rb_str_substr", string_spec_rb_str_substr, 3);
+ rb_define_method(cls, "rb_str_subpos", string_spec_rb_str_subpos, 2);
+ rb_define_method(cls, "rb_str_sublen", string_spec_rb_str_sublen, 2);
rb_define_method(cls, "rb_str_to_str", string_spec_rb_str_to_str, 1);
rb_define_method(cls, "RSTRING_LEN", string_spec_RSTRING_LEN, 1);
rb_define_method(cls, "RSTRING_LENINT", string_spec_RSTRING_LENINT, 1);
+ rb_define_method(cls, "RSTRING_PTR", string_spec_RSTRING_PTR, 1);
rb_define_method(cls, "RSTRING_PTR_iterate", string_spec_RSTRING_PTR_iterate, 1);
rb_define_method(cls, "RSTRING_PTR_iterate_uint32", string_spec_RSTRING_PTR_iterate_uint32, 1);
rb_define_method(cls, "RSTRING_PTR_short_memcpy", string_spec_RSTRING_PTR_short_memcpy, 1);
diff --git a/spec/ruby/optional/capi/ext/struct_spec.c b/spec/ruby/optional/capi/ext/struct_spec.c
index 756cfca8dd37bf..1c669d153ec9b7 100644
--- a/spec/ruby/optional/capi/ext/struct_spec.c
+++ b/spec/ruby/optional/capi/ext/struct_spec.c
@@ -66,7 +66,6 @@ static VALUE struct_spec_rb_struct_initialize(VALUE self, VALUE st, VALUE values
return rb_struct_initialize(st, values);
}
-#if defined(RUBY_VERSION_IS_3_3)
/* Only allow setting three attributes, should be sufficient for testing. */
static VALUE struct_spec_rb_data_define(VALUE self, VALUE superclass,
VALUE attr1, VALUE attr2, VALUE attr3) {
@@ -81,7 +80,6 @@ static VALUE struct_spec_rb_data_define(VALUE self, VALUE superclass,
return rb_data_define(superclass, a1, a2, a3, NULL);
}
-#endif
void Init_struct_spec(void) {
VALUE cls = rb_define_class("CApiStructSpecs", rb_cObject);
@@ -95,9 +93,7 @@ void Init_struct_spec(void) {
rb_define_method(cls, "rb_struct_new", struct_spec_rb_struct_new, 4);
rb_define_method(cls, "rb_struct_size", struct_spec_rb_struct_size, 1);
rb_define_method(cls, "rb_struct_initialize", struct_spec_rb_struct_initialize, 2);
-#if defined(RUBY_VERSION_IS_3_3)
rb_define_method(cls, "rb_data_define", struct_spec_rb_data_define, 4);
-#endif
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/util_spec.c b/spec/ruby/optional/capi/ext/util_spec.c
index b5bde420d212dc..043da99ace5f91 100644
--- a/spec/ruby/optional/capi/ext/util_spec.c
+++ b/spec/ruby/optional/capi/ext/util_spec.c
@@ -20,15 +20,11 @@ VALUE util_spec_rb_scan_args(VALUE self, VALUE argv, VALUE fmt, VALUE expected,
a1 = a2 = a3 = a4 = a5 = a6 = INT2FIX(-1);
-#ifdef RB_SCAN_ARGS_KEYWORDS
if (*RSTRING_PTR(fmt) == 'k') {
result = rb_scan_args_kw(RB_SCAN_ARGS_KEYWORDS, argc, args, RSTRING_PTR(fmt)+1, &a1, &a2, &a3, &a4, &a5, &a6);
} else {
-#endif
result = rb_scan_args(argc, args, RSTRING_PTR(fmt), &a1, &a2, &a3, &a4, &a5, &a6);
-#ifdef RB_SCAN_ARGS_KEYWORDS
}
-#endif
switch(NUM2INT(expected)) {
case 6:
diff --git a/spec/ruby/optional/capi/io_spec.rb b/spec/ruby/optional/capi/io_spec.rb
index dc4ac3e3744ce8..94874c7ae2bd27 100644
--- a/spec/ruby/optional/capi/io_spec.rb
+++ b/spec/ruby/optional/capi/io_spec.rb
@@ -15,7 +15,7 @@
end
after :each do
- @io.close unless @io.closed?
+ @io.close
rm_r @name
end
@@ -118,7 +118,7 @@
end
after :each do
- @io.close unless @io.closed?
+ @io.close
rm_r @name
end
@@ -213,9 +213,9 @@
end
after :each do
- @r_io.close unless @r_io.closed?
- @w_io.close unless @w_io.closed?
- @rw_io.close unless @rw_io.closed?
+ @r_io.close
+ @w_io.close
+ @rw_io.close
rm_r @name
end
@@ -678,7 +678,7 @@ def path.to_str; "a.txt"; end
end
after :each do
- @io.close unless @io.closed?
+ @io.close
rm_r @name
end
@@ -699,7 +699,7 @@ def path.to_str; "a.txt"; end
end
after :each do
- @io.close unless @io.nil? || @io.closed?
+ @io.close if @io
rm_r @name
end
@@ -709,6 +709,58 @@ def path.to_str; "a.txt"; end
end
end
+describe "rb_cloexec_dup" do
+ before :each do
+ @o = CApiIOSpecs.new
+ @name = tmp("c_api_rb_io_specs")
+ touch @name
+
+ @io = new_io @name, "r"
+ @dup = nil
+ end
+
+ after :each do
+ @dup.close if @dup
+ @io.close
+ rm_r @name
+ end
+
+ it "duplicates a file descriptor and sets close_on_exec" do
+ @dup = @o.rb_cloexec_dup(@io)
+ @dup.should.close_on_exec?
+ @dup.fileno.should_not == @io.fileno
+ end
+end
+
+describe "rb_cloexec_fcntl_dupfd" do
+ before :each do
+ @o = CApiIOSpecs.new
+ @name = tmp("c_api_rb_io_specs")
+ touch @name
+
+ @io = new_io @name, "r"
+ @dup = nil
+ end
+
+ after :each do
+ @dup.close if @dup
+ @io.close
+ rm_r @name
+ end
+
+ it "duplicates a file descriptor and sets close_on_exec" do
+ @dup = @o.rb_cloexec_fcntl_dupfd(@io, 3)
+ @dup.close_on_exec?.should be_true
+ @dup.fileno.should_not == @io.fileno
+ end
+
+ it "returns a file descriptor greater than or equal to minfd" do
+ @dup = @o.rb_cloexec_fcntl_dupfd(@io, 100)
+ @dup.fileno.should >= 100
+ @dup.close_on_exec?.should be_true
+ end
+end
+
describe "rb_io_t modes flags" do
before :each do
@o = CApiIOSpecs.new
diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb
index 889f0a6cfe5d51..6861366dd3e033 100644
--- a/spec/ruby/optional/capi/string_spec.rb
+++ b/spec/ruby/optional/capi/string_spec.rb
@@ -536,6 +536,61 @@ def inspect
end
end
+ describe "rb_str_sublen" do
+ it "returns the character length for a given byte offset in an ASCII string" do
+ @s.rb_str_sublen("hello", 3).should == 3
+ end
+
+ it "returns the character length for a given byte offset in a multibyte string" do
+ # "hëllo" where 'ë' is 2 bytes in UTF-8, total 6 bytes
+ str = "hëllo"
+ @s.rb_str_sublen(str, 3).should == 2
+ end
+
+ it "returns 0 for byte offset 0" do
+ @s.rb_str_sublen("hello", 0).should == 0
+ end
+
+ it "returns the full character length for the total byte length" do
+ str = "hëllo"
+ @s.rb_str_sublen(str, str.bytesize).should == str.length
+ end
+ end
+
+ describe "rb_str_subpos" do
+ it "returns [byte_offset, byte_length] for a valid character offset in an ASCII string" do
+ @s.rb_str_subpos("hello", 1).should == [1, 4]
+ end
+
+ it "returns [byte_offset, byte_length] for a valid character offset in a multibyte string" do
+ # "hëllo" where 'ë' is 2 bytes in UTF-8
+ str = "hëllo"
+ @s.rb_str_subpos(str, 0).should == [0, 6]
+ @s.rb_str_subpos(str, 1).should == [1, 5]
+ @s.rb_str_subpos(str, 2).should == [3, 3]
+ end
+
+ it "returns [0, byte_length] for offset 0" do
+ @s.rb_str_subpos("hello", 0).should == [0, 5]
+ end
+
+ it "returns nil for a negative offset that is out of range" do
+ @s.rb_str_subpos("hello", -6).should be_nil
+ end
+
+ it "returns the correct position for a negative offset" do
+ @s.rb_str_subpos("hello", -2).should == [3, 2]
+ end
+
+ it "returns [byte_length, 0] when offset equals string length" do
+ @s.rb_str_subpos("hello", 5).should == [5, 0]
+ end
+
+ it "returns nil when offset is beyond string length" do
+ @s.rb_str_subpos("hello", 6).should be_nil
+ end
+ end
+
describe "rb_str_to_str" do
it "calls #to_str to coerce the value to a String" do
@s.rb_str_to_str("foo").should == "foo"
@@ -1175,9 +1230,11 @@ def inspect
describe "rb_utf8_str_new_static" do
it "returns a UTF-8 string of the correct characters and length" do
- str = @s.rb_utf8_str_new_static
+ str, ptr = @s.rb_utf8_str_new_static
str.should == "nokogiri"
str.encoding.should == Encoding::UTF_8
+
+ @s.RSTRING_PTR(str).should == ptr
end
end
diff --git a/spec/ruby/optional/capi/util_spec.rb b/spec/ruby/optional/capi/util_spec.rb
index 6cf064bf973b36..31754af0510b34 100644
--- a/spec/ruby/optional/capi/util_spec.rb
+++ b/spec/ruby/optional/capi/util_spec.rb
@@ -21,11 +21,11 @@
end
it "raises an ArgumentError if there are insufficient arguments" do
- -> { @o.rb_scan_args([1, 2], "3", 0, @acc) }.should raise_error(ArgumentError)
+ -> { @o.rb_scan_args([1, 2], "3", 0, @acc) }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 3)")
end
it "raises an ArgumentError if there are too many arguments" do
- -> { @o.rb_scan_args([1, 2, 3, 4], "3", 0, @acc) }.should raise_error(ArgumentError)
+ -> { @o.rb_scan_args([1, 2, 3, 4], "3", 0, @acc) }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 3)")
end
it "assigns the required and optional arguments scanned" do
@@ -117,8 +117,15 @@
it "rejects the use of nil as a hash" do
-> {
- @o.rb_scan_args([1, nil], "1:", 2, @acc).should == 1
- }.should raise_error(ArgumentError)
+ @o.rb_scan_args([1, nil], "1:", 2, @acc)
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 1)")
+ ScratchPad.recorded.should == []
+ end
+
+ it "rejects the use of of a non-Hash as keywords" do
+ -> {
+ @o.rb_scan_args([42], ":", 1, @acc)
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 1, expected 0)")
ScratchPad.recorded.should == []
end
@@ -186,7 +193,7 @@
it "raises an error if a required argument is not in the hash" do
h = { :a => 7, :c => 12, :b => 5 }
- -> { @o.rb_get_kwargs(h, [:b, :d], 2, 0) }.should raise_error(ArgumentError, /missing keyword: :?d/)
+ -> { @o.rb_get_kwargs(h, [:b, :d], 2, 0) }.should raise_error(ArgumentError, "missing keyword: :d")
h.should == {:a => 7, :c => 12}
end
@@ -198,7 +205,7 @@
it "raises an error if there are additional arguments and optional is positive" do
h = { :a => 7, :c => 12, :b => 5 }
- -> { @o.rb_get_kwargs(h, [:b, :a], 2, 0) }.should raise_error(ArgumentError, /unknown keyword: :?c/)
+ -> { @o.rb_get_kwargs(h, [:b, :a], 2, 0) }.should raise_error(ArgumentError, "unknown keyword: :c")
h.should == {:c => 12}
end
diff --git a/spec/ruby/shared/kernel/raise.rb b/spec/ruby/shared/kernel/raise.rb
index 2be06ea797aa6d..c15eb926bc7b95 100644
--- a/spec/ruby/shared/kernel/raise.rb
+++ b/spec/ruby/shared/kernel/raise.rb
@@ -140,11 +140,35 @@ def e.exception
}
end
end
+end
- ruby_version_is "4.0" do
- it "allows cause keyword argument" do
+describe :kernel_raise_with_cause, shared: true do
+ context "without cause keyword argument" do
+ it "sets cause to nil when there is no previous exception" do
+ -> do
+ @object.raise("error without a cause")
+ end.should raise_error(RuntimeError, "error without a cause") do |error|
+ error.cause.should == nil
+ end
+ end
+
+ it "supports automatic cause chaining from a previous exception" do
+ -> do
+ begin
+ raise StandardError,"first error"
+ rescue
+ @object.raise("second error")
+ end
+ end.should raise_error(RuntimeError, "second error") do |error|
+ error.cause.should be_kind_of(StandardError)
+ error.cause.message.should == "first error"
+ end
+ end
+ end
+
+ context "with cause keyword argument" do
+ it "allows setting exception's cause" do
cause = StandardError.new("original error")
- result = nil
-> do
@object.raise("new error", cause: cause)
@@ -153,6 +177,14 @@ def e.exception
end
end
+ it "allows setting cause to nil" do
+ -> do
+ @object.raise("error without a cause", cause: nil)
+ end.should raise_error(RuntimeError, "error without a cause") do |error|
+ error.cause.should == nil
+ end
+ end
+
it "raises an ArgumentError when only cause is given" do
cause = StandardError.new("cause")
-> do
@@ -166,7 +198,7 @@ def e.exception
end.should raise_error(ArgumentError, "only cause is given with no arguments")
end
- it "raises a TypeError when given cause is not an instance of Exception" do
+ it "raises a TypeError when given cause is not an instance of Exception or nil" do
cause = Object.new
-> do
@object.raise("message", cause: cause)
@@ -175,7 +207,6 @@ def e.exception
it "doesn't set given cause when it equals the raised exception" do
cause = StandardError.new("cause")
- result = nil
-> do
@object.raise(cause, cause: cause)
@@ -185,18 +216,7 @@ def e.exception
end
end
- it "accepts cause equal an exception" do
- error = RuntimeError.new("message")
- result = nil
-
- -> do
- @object.raise(error, cause: error)
- end.should raise_error(RuntimeError, "message") do |e|
- e.cause.should == nil
- end
- end
-
- it "rejects circular causes" do
+ it "raises ArgumentError when cause creates a circular reference" do
-> {
begin
raise "Error 1"
@@ -216,7 +236,6 @@ def e.exception
it "supports exception class with message and cause" do
cause = StandardError.new("cause message")
- result = nil
-> do
@object.raise(ArgumentError, "argument error message", cause: cause)
@@ -230,7 +249,6 @@ def e.exception
it "supports exception class with message, backtrace and cause" do
cause = StandardError.new("cause message")
backtrace = ["line1", "line2"]
- result = nil
-> do
@object.raise(ArgumentError, "argument error message", backtrace, cause: cause)
@@ -242,21 +260,21 @@ def e.exception
end
end
- it "supports automatic cause chaining" do
+ it "supports cause: exception, overriding previous exception" do
+ custom_error = StandardError.new("custom error")
-> do
begin
raise "first error"
rescue
- # No explicit cause - should chain automatically:
- @object.raise("second error")
+ @object.raise("second error", cause: custom_error)
end
end.should raise_error(RuntimeError, "second error") do |error|
- error.cause.should be_kind_of(RuntimeError)
- error.cause.message.should == "first error"
+ error.cause.should be_kind_of(StandardError)
+ error.cause.message.should == "custom error"
end
end
- it "supports cause: nil to prevent automatic cause chaining" do
+ it "supports cause: nil, discarding previous exception" do
-> do
begin
raise "first error"
diff --git a/spec/ruby/shared/process/fork.rb b/spec/ruby/shared/process/fork.rb
index 8dbb3d0da43db6..35e712572f105f 100644
--- a/spec/ruby/shared/process/fork.rb
+++ b/spec/ruby/shared/process/fork.rb
@@ -74,16 +74,19 @@
it "marks threads from the parent as killed" do
t = Thread.new { sleep }
- pid = @object.fork {
- touch(@file) do |f|
- f.write Thread.current.alive?
- f.write t.alive?
- end
- Process.exit!
- }
- Process.waitpid(pid)
- t.kill
- t.join
+ begin
+ pid = @object.fork {
+ touch(@file) do |f|
+ f.write Thread.current.alive?
+ f.write t.alive?
+ end
+ Process.exit!
+ }
+ Process.waitpid(pid)
+ ensure
+ t.kill
+ t.join
+ end
File.read(@file).should == "truefalse"
end
end
diff --git a/test/prism/errors/match_predicate_after_rescue_with_dot_method_call.txt b/test/prism/errors/match_predicate_after_rescue_with_dot_method_call.txt
index fead8aaf234069..f599dc476bd607 100644
--- a/test/prism/errors/match_predicate_after_rescue_with_dot_method_call.txt
+++ b/test/prism/errors/match_predicate_after_rescue_with_dot_method_call.txt
@@ -1,3 +1,4 @@
'a' rescue 2 in 3.upcase
^ unexpected '.', expecting end-of-input
+ ^ unexpected '.', ignoring it
diff --git a/test/prism/errors/match_predicate_after_rescue_with_opreator.txt b/test/prism/errors/match_predicate_after_rescue_with_opreator.txt
index b2363a544d0c75..44a4ba848823a9 100644
--- a/test/prism/errors/match_predicate_after_rescue_with_opreator.txt
+++ b/test/prism/errors/match_predicate_after_rescue_with_opreator.txt
@@ -1,3 +1,4 @@
1 rescue 2 in 3 << 4
^~ unexpected <<, expecting end-of-input
+ ^~ unexpected <<, ignoring it
diff --git a/test/prism/errors/match_required_after_rescue_with_dot_method_call.txt b/test/prism/errors/match_required_after_rescue_with_dot_method_call.txt
index d72d72ce606d48..abcfaf094d30b2 100644
--- a/test/prism/errors/match_required_after_rescue_with_dot_method_call.txt
+++ b/test/prism/errors/match_required_after_rescue_with_dot_method_call.txt
@@ -1,3 +1,4 @@
1 rescue 2 => 3.inspect
^ unexpected '.', expecting end-of-input
+ ^ unexpected '.', ignoring it
diff --git a/test/prism/errors/match_required_after_rescue_with_opreator.txt b/test/prism/errors/match_required_after_rescue_with_opreator.txt
index 903e2ccc8e6dc4..5e6387ca4d33ef 100644
--- a/test/prism/errors/match_required_after_rescue_with_opreator.txt
+++ b/test/prism/errors/match_required_after_rescue_with_opreator.txt
@@ -1,3 +1,4 @@
1 rescue 2 => 3 ** 4
^~ unexpected '**', expecting end-of-input
+ ^~ unexpected '**', ignoring it
diff --git a/test/prism/errors/rescue_pattern.txt b/test/prism/errors/rescue_pattern.txt
new file mode 100644
index 00000000000000..c85feb27bdf11b
--- /dev/null
+++ b/test/prism/errors/rescue_pattern.txt
@@ -0,0 +1,4 @@
+a rescue b => c in d
+ ^~ unexpected 'in', expecting end-of-input
+ ^~ unexpected 'in', ignoring it
+
diff --git a/tool/zjit_diff.rb b/tool/zjit_diff.rb
new file mode 100755
index 00000000000000..4f8f74d20f6225
--- /dev/null
+++ b/tool/zjit_diff.rb
@@ -0,0 +1,272 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require 'fileutils'
+require 'optparse'
+require 'tmpdir'
+require 'logger'
+require 'digest'
+require 'shellwords'
+
+GitRef = Struct.new(:ref, :commit_hash)
+
+RUBIES_DIR = File.join(Dir.home, '.zjit-diff')
+BEFORE_NAME = 'ruby-zjit-before'
+AFTER_NAME = 'ruby-zjit-after'
+
+LOG = Logger.new($stderr)
+
+def macos?
+ Gem::Platform.local == 'darwin'
+end
+
+class CommandRunner
+ def initialize(quiet: false)
+ @quiet = quiet
+ end
+
+ def cmd(*args, **options)
+ options[:out] ||= @quiet ? File::NULL : $stderr
+ options = options.merge(exception: true)
+ system(*args, **options)
+ end
+end
+
+class ZJITDiff
+ DATA_FILENAME = File.join('data', 'zjit_diff')
+ RUBY_BENCH_REPO_URL = 'https://github.com/ruby/ruby-bench.git'
+
+ def initialize(before_hash:, after_hash:, runner:, options:)
+ @before_hash = before_hash
+ @after_hash = after_hash
+ @runner = runner
+ @options = options
+ end
+
+ def bench!
+ LOG.info('Running benchmarks')
+ ruby_bench_path = @options[:bench_path] || setup_ruby_bench
+ run_benchmarks(ruby_bench_path)
+ end
+
+ private
+
+ def run_benchmarks(ruby_bench_path)
+ Dir.chdir(ruby_bench_path) do
+ @runner.cmd({ 'RUBIES_DIR' => RUBIES_DIR },
+ './run_benchmarks.rb',
+ '--chruby',
+ "before::#{@before_hash} --zjit-stats;after::#{@after_hash} --zjit-stats",
+ '--out-name',
+ DATA_FILENAME,
+ *@options[:bench_args],
+ *@options[:name_filters])
+
+ @runner.cmd('./misc/zjit_diff.rb', "#{DATA_FILENAME}.json", out: $stdout)
+ end
+ end
+
+ def setup_ruby_bench
+ path = File.join(Dir.tmpdir, 'ruby-bench')
+ if Dir.exist?(path)
+ LOG.info('ruby-bench already cloned, pulling from upstream')
+ Dir.chdir(path) do
+ @runner.cmd('git', 'pull')
+ end
+ else
+ LOG.info("ruby-bench not cloned yet, cloning repository to #{path}")
+ @runner.cmd('git', 'clone', RUBY_BENCH_REPO_URL, path)
+ end
+ path
+ end
+end
+
+class RubyWorktree
+ attr_reader :hash
+
+ BREW_REQUIRED_PACKAGES = %w[openssl readline libyaml].freeze
+
+ def initialize(name:, ref:, runner:, force_rebuild: false)
+ @path = File.join(Dir.tmpdir, name)
+ @ref = ref
+ @force_rebuild = force_rebuild
+ @runner = runner
+ @hash = nil
+
+ setup_worktree
+ end
+
+ def build!
+ Dir.chdir(@path) do
+ configure_cmd_args = ['--enable-zjit=dev', '--disable-install-doc']
+ if macos?
+ brew_prefixes = BREW_REQUIRED_PACKAGES.map do |pkg|
+ `brew --prefix #{pkg}`.strip
+ end
+ configure_cmd_args << "--with-opt-dir=#{brew_prefixes.join(':')}"
+ end
+ configure_cmd_hash = Digest::MD5.hexdigest(configure_cmd_args.join(''))
+
+ build_cmd_args = ['-j', 'miniruby']
+ build_cmd_hash = Digest::MD5.hexdigest(build_cmd_args.join(''))
+
+ @hash = "#{configure_cmd_hash}-#{build_cmd_hash}-#{@ref.commit_hash}"
+ prefix = File.join(RUBIES_DIR, @hash)
+
+ if Dir.exist?(prefix) && !@force_rebuild
+ LOG.info("Found existing build for #{@ref.ref}, skipping build")
+ return
+ end
+
+ @runner.cmd('./autogen.sh')
+
+ cmd = [
+ './configure',
+ *configure_cmd_args,
+ "--prefix=#{prefix}"
+ ]
+
+ @runner.cmd(*cmd)
+ @runner.cmd('make', *build_cmd_args)
+ @runner.cmd('make', 'install')
+ end
+ end
+
+ private
+
+ def setup_worktree
+ if Dir.exist?(@path)
+ LOG.info("Existing worktree found at #{@path}")
+ Dir.chdir(@path) do
+ @runner.cmd('git', 'checkout', @ref.commit_hash)
+ end
+ else
+ LOG.info("Creating worktree for ref '#{@ref.ref}' at #{@path}")
+ @runner.cmd('git', 'worktree', 'add', '--detach', @path, @ref.commit_hash)
+ end
+ end
+end
+
+def clean!
+ [BEFORE_NAME, AFTER_NAME].each do |name|
+ path = File.join(Dir.tmpdir, name)
+ if Dir.exist?(path)
+ LOG.info("Removing worktree at #{path}")
+ system('git', 'worktree', 'remove', '--force', path)
+ end
+ end
+
+ if Dir.exist?(RUBIES_DIR)
+ LOG.info("Removing ruby installations from #{RUBIES_DIR}")
+ FileUtils.rm_rf(RUBIES_DIR)
+ end
+
+ bench_path = File.join(Dir.tmpdir, 'ruby-bench')
+ return unless Dir.exist?(bench_path)
+
+ LOG.info("Removing ruby-bench clone at #{bench_path}")
+ FileUtils.rm_rf(bench_path)
+end
+
+def parse_ref(ref)
+ out = `git rev-parse --verify #{ref}`
+ return nil unless $?.success?
+
+ GitRef.new(ref: ref, commit_hash: out.strip)
+end
+
+DEFAULT_BENCHMARKS = %w[lobsters railsbench].freeze
+
+options = {}
+
+subtext = <<~HELP
+ Subcommands:
+ bench : Run benchmarks
+ clean : Clean temporary files created by benchmarks
+ See '#{$PROGRAM_NAME} COMMAND --help' for more information on a specific command.
+HELP
+
+top_level = OptionParser.new do |opts|
+ opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
+ opts.separator('')
+ opts.separator(subtext)
+end
+
+subcommands = {
+ 'bench' => OptionParser.new do |opts|
+ opts.banner = "Usage: #{$PROGRAM_NAME} [options] "
+
+ opts.on('--before REF', 'Git ref for ruby (before)') do |ref|
+ git_ref = parse_ref ref
+ if git_ref.nil?
+ warn "Error: '#{ref}' is not a valid git ref"
+ exit 1
+ end
+
+ options[:before] = git_ref
+ end
+
+ opts.on('--after REF', 'Git ref for ruby (after)') do |ref|
+ git_ref = parse_ref ref
+ if git_ref.nil?
+ warn "Error: '#{ref}' is not a valid git ref"
+ exit 1
+ end
+
+ options[:after] = git_ref
+ end
+
+ opts.on('--bench-path PATH',
+ 'Path to an existing ruby-bench repository clone ' \
+ '(if not specified, ruby-bench will be cloned automatically to a temporary directory)') do |path|
+ options[:bench_path] = path
+ end
+
+ opts.on('--bench-args ARGS', 'Args to pass to ruby-bench') do |bench_args|
+ options[:bench_args] = bench_args.shellsplit
+ end
+
+ opts.on('--force-rebuild',
+ 'Force building ruby again instead of using even if existing builds exist in the cache at ~/.diffs') do
+ options[:force_rebuild] = true
+ end
+
+ opts.on('--quiet', 'Silence output of commands except for benchmark result') do
+ options[:quiet] = true
+ end
+
+ opts.separator('')
+ opts.separator('If no benchmarks are specified, the benchmarks that will be run are:')
+ opts.separator(DEFAULT_BENCHMARKS.join(', '))
+ end,
+ 'clean' => OptionParser.new do |opts|
+ end
+}
+
+top_level.order!
+command = ARGV.shift
+subcommands[command].order!
+
+case command
+when 'bench'
+ options[:name_filters] = ARGV.empty? ? DEFAULT_BENCHMARKS : ARGV
+ options[:after] ||= parse_ref('HEAD')
+
+ runner = CommandRunner.new(quiet: options[:quiet])
+
+ before = RubyWorktree.new(name: BEFORE_NAME,
+ ref: options[:before],
+ runner: runner,
+ force_rebuild: options[:force_rebuild])
+ before.build!
+ after = RubyWorktree.new(name: AFTER_NAME,
+ ref: options[:after],
+ runner: runner,
+ force_rebuild: options[:force_rebuild])
+ after.build!
+
+ zjit_diff = ZJITDiff.new(runner: runner, before_hash: before.hash, after_hash: after.hash, options: options)
+ zjit_diff.bench!
+when 'clean'
+ clean!
+end
diff --git a/vm_callinfo.h b/vm_callinfo.h
index 3df4b4eb0e9500..9f147522815d50 100644
--- a/vm_callinfo.h
+++ b/vm_callinfo.h
@@ -66,8 +66,8 @@ struct rb_callinfo {
VALUE flags;
const struct rb_callinfo_kwarg *kwarg;
VALUE mid;
- VALUE flag;
- VALUE argc;
+ unsigned int flag;
+ unsigned int argc;
};
#if !defined(USE_EMBED_CI) || (USE_EMBED_CI+0)
@@ -146,7 +146,7 @@ vm_ci_flag(const struct rb_callinfo *ci)
return (unsigned int)((((VALUE)ci) >> CI_EMBED_FLAG_SHFT) & CI_EMBED_FLAG_MASK);
}
else {
- return (unsigned int)ci->flag;
+ return ci->flag;
}
}
@@ -157,7 +157,7 @@ vm_ci_argc(const struct rb_callinfo *ci)
return (unsigned int)((((VALUE)ci) >> CI_EMBED_ARGC_SHFT) & CI_EMBED_ARGC_MASK);
}
else {
- return (unsigned int)ci->argc;
+ return ci->argc;
}
}
diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs
index 88919ac8748f5d..32ca5137305339 100644
--- a/yjit/src/cruby_bindings.inc.rs
+++ b/yjit/src/cruby_bindings.inc.rs
@@ -635,7 +635,7 @@ pub const VM_ENV_FLAG_ISOLATED: vm_frame_env_flags = 16;
pub type vm_frame_env_flags = u32;
pub type attr_index_t = u16;
pub type shape_id_t = u32;
-pub const SHAPE_ID_HAS_IVAR_MASK: shape_id_mask = 134742014;
+pub const SHAPE_ID_HAS_IVAR_MASK: shape_id_mask = 67633150;
pub type shape_id_mask = u32;
#[repr(C)]
pub struct rb_cvar_class_tbl_entry {
@@ -671,8 +671,8 @@ pub struct rb_callinfo {
pub flags: VALUE,
pub kwarg: *const rb_callinfo_kwarg,
pub mid: VALUE,
- pub flag: VALUE,
- pub argc: VALUE,
+ pub flag: ::std::os::raw::c_uint,
+ pub argc: ::std::os::raw::c_uint,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs
index 5bac9fdf19d1c7..baf39100f48d71 100644
--- a/zjit/src/cruby_bindings.inc.rs
+++ b/zjit/src/cruby_bindings.inc.rs
@@ -1464,12 +1464,12 @@ pub const VM_ENV_FLAG_ISOLATED: vm_frame_env_flags = 16;
pub type vm_frame_env_flags = u32;
pub type attr_index_t = u16;
pub type shape_id_t = u32;
-pub const SHAPE_ID_HEAP_INDEX_MASK: shape_id_fl_type = 29360128;
-pub const SHAPE_ID_FL_FROZEN: shape_id_fl_type = 33554432;
-pub const SHAPE_ID_FL_HAS_OBJECT_ID: shape_id_fl_type = 67108864;
-pub const SHAPE_ID_FL_TOO_COMPLEX: shape_id_fl_type = 134217728;
-pub const SHAPE_ID_FL_NON_CANONICAL_MASK: shape_id_fl_type = 100663296;
-pub const SHAPE_ID_FLAGS_MASK: shape_id_fl_type = 264241152;
+pub const SHAPE_ID_HEAP_INDEX_MASK: shape_id_fl_type = 16252928;
+pub const SHAPE_ID_FL_FROZEN: shape_id_fl_type = 16777216;
+pub const SHAPE_ID_FL_HAS_OBJECT_ID: shape_id_fl_type = 33554432;
+pub const SHAPE_ID_FL_TOO_COMPLEX: shape_id_fl_type = 67108864;
+pub const SHAPE_ID_FL_NON_CANONICAL_MASK: shape_id_fl_type = 50331648;
+pub const SHAPE_ID_FLAGS_MASK: shape_id_fl_type = 133693440;
pub type shape_id_fl_type = u32;
#[repr(C)]
pub struct rb_cvar_class_tbl_entry {
@@ -1505,8 +1505,8 @@ pub struct rb_callinfo {
pub flags: VALUE,
pub kwarg: *const rb_callinfo_kwarg,
pub mid: VALUE,
- pub flag: VALUE,
- pub argc: VALUE,
+ pub flag: ::std::os::raw::c_uint,
+ pub argc: ::std::os::raw::c_uint,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs
index a88eee26d9101f..7487f8c3e3d26e 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -4679,6 +4679,24 @@ impl Function {
// Don't bother re-inferring the type of str; we already know it.
continue;
}
+ Insn::IsA { val, class } => 'is_a: {
+ let class_type = self.type_of(class);
+ if !class_type.is_subtype(types::Class) {
+ break 'is_a insn_id;
+ }
+ let Some(class_value) = class_type.ruby_object() else {
+ break 'is_a insn_id;
+ };
+ let val_type = self.type_of(val);
+ let the_class = Type::from_class_inexact(class_value);
+ if val_type.is_subtype(the_class) {
+ self.new_insn(Insn::Const { val: Const::Value(Qtrue) })
+ } else if !val_type.could_be(the_class) {
+ self.new_insn(Insn::Const { val: Const::Value(Qfalse) })
+ } else {
+ insn_id
+ }
+ }
Insn::FixnumAdd { left, right, .. } => {
self.fold_fixnum_bop(insn_id, left, right, |l, r| match (l, r) {
(Some(l), Some(r)) => l.checked_add(r),
diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs
index 53f9e4a138f019..16298db6a28871 100644
--- a/zjit/src/hir/opt_tests.rs
+++ b/zjit/src/hir/opt_tests.rs
@@ -957,7 +957,7 @@ mod hir_opt_tests {
custom.count
");
assert_eq!(VALUE::fixnum_from_usize(2), result);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:13:
bb1():
EntryPoint interpreter
@@ -973,7 +973,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint NoSingletonClass(CustomEq@0x1008)
PatchPoint MethodRedefined(CustomEq@0x1008, !=@0x1010, cme:0x1018)
- v30:HeapObject[class_exact:CustomEq] = GuardType v10, HeapObject[class_exact:CustomEq]
+ v30:ObjectSubclass[class_exact:CustomEq] = GuardType v10, ObjectSubclass[class_exact:CustomEq]
v31:BoolExact = CCallWithFrame v30, :BasicObject#!=@0x1040, v10
v21:NilClass = Const Value(nil)
CheckInterrupts
@@ -1133,7 +1133,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v19:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v19:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v20:BasicObject = SendDirect v19, 0x1038, :foo (0x1048)
CheckInterrupts
Return v20
@@ -1162,7 +1162,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, baz@0x1008, cme:0x1010)
- v19:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v19:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
v22:Fixnum[1] = Const Value(1)
CheckInterrupts
@@ -1191,7 +1191,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, baz@0x1008, cme:0x1010)
- v20:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v20:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_cfunc_optimized_send_count
CheckInterrupts
Return v20
@@ -1230,7 +1230,7 @@ mod hir_opt_tests {
v11:Fixnum[1] = Const Value(1)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v21:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v21:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v22:BasicObject = SendDirect v21, 0x1038, :foo (0x1048), v11
CheckInterrupts
Return v22
@@ -1282,7 +1282,7 @@ mod hir_opt_tests {
def test(o) = o.bar { |x| x }
test C.new; test C.new
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:7:
bb1():
EntryPoint interpreter
@@ -1298,7 +1298,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, bar@0x1010, cme:0x1018)
- v26:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v26:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
v27:BasicObject = CCallWithFrame v26, :Enumerable#bar@0x1040, block=0x1048
v16:CPtr = GetEP 0
v17:BasicObject = LoadField v16, :o@0x1050
@@ -1392,7 +1392,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v19:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v19:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v20:BasicObject = SendDirect v19, 0x1038, :foo (0x1048)
CheckInterrupts
Return v20
@@ -1421,7 +1421,7 @@ mod hir_opt_tests {
v11:Fixnum[3] = Const Value(3)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, Integer@0x1008, cme:0x1010)
- v21:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v21:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v22:BasicObject = SendDirect v21, 0x1038, :Integer (0x1048), v11
CheckInterrupts
Return v22
@@ -1452,7 +1452,7 @@ mod hir_opt_tests {
v13:Fixnum[2] = Const Value(2)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v23:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v23:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v24:BasicObject = SendDirect v23, 0x1038, :foo (0x1048), v11, v13
CheckInterrupts
Return v24
@@ -1483,11 +1483,11 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v24:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v24:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v25:BasicObject = SendDirect v24, 0x1038, :foo (0x1048)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, bar@0x1050, cme:0x1058)
- v28:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v28:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v29:BasicObject = SendDirect v28, 0x1038, :bar (0x1048)
CheckInterrupts
Return v29
@@ -1514,7 +1514,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v19:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v19:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v20:BasicObject = SendDirect v19, 0x1038, :foo (0x1048)
CheckInterrupts
Return v20
@@ -1542,7 +1542,7 @@ mod hir_opt_tests {
v11:Fixnum[3] = Const Value(3)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v21:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v21:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v22:BasicObject = SendDirect v21, 0x1038, :foo (0x1048), v11
CheckInterrupts
Return v22
@@ -1571,7 +1571,7 @@ mod hir_opt_tests {
v13:Fixnum[4] = Const Value(4)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v23:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v23:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v24:BasicObject = SendDirect v23, 0x1038, :foo (0x1048), v11, v13
CheckInterrupts
Return v24
@@ -1599,14 +1599,14 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, target@0x1008, cme:0x1010)
- v45:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v45:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v46:BasicObject = SendDirect v45, 0x1038, :target (0x1048)
v14:Fixnum[10] = Const Value(10)
v16:Fixnum[20] = Const Value(20)
v18:Fixnum[30] = Const Value(30)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, target@0x1008, cme:0x1010)
- v49:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v49:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v50:BasicObject = SendDirect v49, 0x1038, :target (0x1048), v14, v16, v18
v24:Fixnum[10] = Const Value(10)
v26:Fixnum[20] = Const Value(20)
@@ -1643,7 +1643,7 @@ mod hir_opt_tests {
v12:StringExact = StringCopy v11
PatchPoint NoSingletonClass(Object@0x1008)
PatchPoint MethodRedefined(Object@0x1008, puts@0x1010, cme:0x1018)
- v23:HeapObject[class_exact*:Object@VALUE(0x1008)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1008)]
+ v23:ObjectSubclass[class_exact*:Object@VALUE(0x1008)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1008)]
v24:BasicObject = CCallVariadic v23, :Kernel#puts@0x1040, v12
CheckInterrupts
Return v24
@@ -3325,7 +3325,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, block_given?@0x1008, cme:0x1010)
- v20:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v20:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v21:CPtr = GetEP 0
v22:BoolExact = IsBlockGiven v21
IncrCounter inline_cfunc_optimized_send_count
@@ -3353,7 +3353,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, block_given?@0x1008, cme:0x1010)
- v20:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v20:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v21:FalseClass = Const Value(false)
IncrCounter inline_cfunc_optimized_send_count
CheckInterrupts
@@ -3383,7 +3383,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, block_given?@0x1008, cme:0x1010)
- v24:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v24:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_cfunc_optimized_send_count
v15:Fixnum[5] = Const Value(5)
CheckInterrupts
@@ -3499,7 +3499,7 @@ mod hir_opt_tests {
test c
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:6:
bb1():
EntryPoint interpreter
@@ -3515,7 +3515,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, foo@0x1010, cme:0x1018)
- v23:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v23:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
v24:BasicObject = SendDirect v23, 0x1040, :foo (0x1050)
CheckInterrupts
Return v24
@@ -3531,7 +3531,7 @@ mod hir_opt_tests {
test
");
assert_eq!(VALUE::fixnum_from_usize(3), result);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:3:
bb1():
EntryPoint interpreter
@@ -3546,7 +3546,7 @@ mod hir_opt_tests {
v13:Fixnum[2] = Const Value(2)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v24:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v24:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v25:BasicObject = SendDirect v24, 0x1038, :foo (0x1048), v11, v13
CheckInterrupts
Return v25
@@ -3565,7 +3565,7 @@ mod hir_opt_tests {
test
test
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:4:
bb1():
EntryPoint interpreter
@@ -3581,7 +3581,7 @@ mod hir_opt_tests {
v13:Fixnum[1] = Const Value(1)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v33:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v8, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v33:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v8, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
v19:CPtr = GetEP 0
v20:BasicObject = LoadField v19, :a@0x1038
@@ -3667,7 +3667,7 @@ mod hir_opt_tests {
v13:Fixnum[2] = Const Value(2)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v23:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v23:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v24:BasicObject = SendDirect v23, 0x1038, :foo (0x1048), v11, v13
CheckInterrupts
Return v24
@@ -3698,7 +3698,7 @@ mod hir_opt_tests {
v15:Fixnum[2] = Const Value(2)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v26:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v26:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v27:BasicObject = SendDirect v26, 0x1038, :foo (0x1048), v13, v15, v11
CheckInterrupts
Return v27
@@ -3729,7 +3729,7 @@ mod hir_opt_tests {
v15:Fixnum[1] = Const Value(1)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v26:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v26:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v27:BasicObject = SendDirect v26, 0x1038, :foo (0x1048), v11, v15, v13
CheckInterrupts
Return v27
@@ -3759,7 +3759,7 @@ mod hir_opt_tests {
v13:Fixnum[2] = Const Value(2)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v23:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v23:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v24:BasicObject = SendDirect v23, 0x1038, :foo (0x1048), v11, v13
CheckInterrupts
Return v24
@@ -3790,7 +3790,7 @@ mod hir_opt_tests {
v15:Fixnum[4] = Const Value(4)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v38:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v38:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v39:BasicObject = SendDirect v38, 0x1038, :foo (0x1048), v11, v13, v15
v20:Fixnum[1] = Const Value(1)
v22:Fixnum[2] = Const Value(2)
@@ -3798,7 +3798,7 @@ mod hir_opt_tests {
v26:Fixnum[3] = Const Value(3)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v43:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v43:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v44:BasicObject = SendDirect v43, 0x1038, :foo (0x1048), v20, v22, v26, v24
v30:ArrayExact = NewArray v39, v44
CheckInterrupts
@@ -3830,7 +3830,7 @@ mod hir_opt_tests {
v34:Fixnum[4] = Const Value(4)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v38:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v38:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v39:BasicObject = SendDirect v38, 0x1038, :foo (0x1048), v11, v13, v34
v18:Fixnum[1] = Const Value(1)
v20:Fixnum[2] = Const Value(2)
@@ -3838,7 +3838,7 @@ mod hir_opt_tests {
v24:Fixnum[30] = Const Value(30)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v43:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v43:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v44:BasicObject = SendDirect v43, 0x1038, :foo (0x1048), v18, v20, v24, v22
v28:ArrayExact = NewArray v39, v44
CheckInterrupts
@@ -3868,7 +3868,7 @@ mod hir_opt_tests {
v11:Fixnum[6] = Const Value(6)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, target@0x1008, cme:0x1010)
- v49:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v49:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v50:BasicObject = SendDirect v49, 0x1038, :target (0x1048), v11
v16:Fixnum[10] = Const Value(10)
v18:Fixnum[20] = Const Value(20)
@@ -3876,7 +3876,7 @@ mod hir_opt_tests {
v22:Fixnum[6] = Const Value(6)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, target@0x1008, cme:0x1010)
- v53:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v53:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v54:BasicObject = SendDirect v53, 0x1038, :target (0x1048), v16, v18, v20, v22
v27:Fixnum[10] = Const Value(10)
v29:Fixnum[20] = Const Value(20)
@@ -3913,7 +3913,7 @@ mod hir_opt_tests {
v11:Fixnum[2] = Const Value(2)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v21:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v21:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v22:BasicObject = SendDirect v21, 0x1038, :foo (0x1048), v11
CheckInterrupts
Return v22
@@ -4023,7 +4023,7 @@ mod hir_opt_tests {
v17:Fixnum[1] = Const Value(1)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v21:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v21:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v22:BasicObject = SendDirect v21, 0x1038, :foo (0x1048), v17
CheckInterrupts
Return v22
@@ -4277,7 +4277,7 @@ mod hir_opt_tests {
v43:Class[C@0x1008] = Const Value(VALUE(0x1008))
v12:NilClass = Const Value(nil)
PatchPoint MethodRedefined(C@0x1008, new@0x1009, cme:0x1010)
- v46:HeapObject[class_exact:C] = ObjectAllocClass C:VALUE(0x1008)
+ v46:ObjectSubclass[class_exact:C] = ObjectAllocClass C:VALUE(0x1008)
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, initialize@0x1038, cme:0x1040)
v50:NilClass = Const Value(nil)
@@ -4316,7 +4316,7 @@ mod hir_opt_tests {
v12:NilClass = Const Value(nil)
v15:Fixnum[1] = Const Value(1)
PatchPoint MethodRedefined(C@0x1008, new@0x1009, cme:0x1010)
- v49:HeapObject[class_exact:C] = ObjectAllocClass C:VALUE(0x1008)
+ v49:ObjectSubclass[class_exact:C] = ObjectAllocClass C:VALUE(0x1008)
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, initialize@0x1038, cme:0x1040)
v52:BasicObject = SendDirect v49, 0x1068, :initialize (0x1078), v15
@@ -4557,7 +4557,7 @@ mod hir_opt_tests {
eval("
def test(a,b) = [a,b].length
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:2:
bb1():
EntryPoint interpreter
@@ -4589,7 +4589,7 @@ mod hir_opt_tests {
eval("
def test(a,b) = [a,b].size
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:2:
bb1():
EntryPoint interpreter
@@ -4621,7 +4621,7 @@ mod hir_opt_tests {
eval("
def test(&block) = tap(&block)
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:2:
bb1():
EntryPoint interpreter
@@ -4640,7 +4640,7 @@ mod hir_opt_tests {
v17:CInt64 = GuardNoBitsSet v16, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM=CUInt64(512)
v18:CInt64 = LoadField v15, :_env_data_index_specval@0x1002
v19:CInt64 = GuardAnyBitSet v18, CUInt64(1)
- v20:HeapObject[BlockParamProxy] = Const Value(VALUE(0x1008))
+ v20:ObjectSubclass[BlockParamProxy] = Const Value(VALUE(0x1008))
v22:BasicObject = Send v9, 0x1001, :tap, v20 # SendFallbackReason: Uncategorized(send)
CheckInterrupts
Return v22
@@ -4827,7 +4827,7 @@ mod hir_opt_tests {
end
test p
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:4:
bb1():
EntryPoint interpreter
@@ -4844,7 +4844,7 @@ mod hir_opt_tests {
v15:Fixnum[1] = Const Value(1)
PatchPoint NoSingletonClass(Proc@0x1008)
PatchPoint MethodRedefined(Proc@0x1008, call@0x1010, cme:0x1018)
- v25:HeapObject[class_exact:Proc] = GuardType v10, HeapObject[class_exact:Proc]
+ v25:ObjectSubclass[class_exact:Proc] = GuardType v10, ObjectSubclass[class_exact:Proc]
v26:BasicObject = InvokeProc v25, v15
CheckInterrupts
Return v26
@@ -4860,7 +4860,7 @@ mod hir_opt_tests {
end
test p
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:4:
bb1():
EntryPoint interpreter
@@ -4877,7 +4877,7 @@ mod hir_opt_tests {
v15:Fixnum[2] = Const Value(2)
PatchPoint NoSingletonClass(Proc@0x1008)
PatchPoint MethodRedefined(Proc@0x1008, []@0x1010, cme:0x1018)
- v26:HeapObject[class_exact:Proc] = GuardType v10, HeapObject[class_exact:Proc]
+ v26:ObjectSubclass[class_exact:Proc] = GuardType v10, ObjectSubclass[class_exact:Proc]
v27:BasicObject = InvokeProc v26, v15
CheckInterrupts
Return v27
@@ -4893,7 +4893,7 @@ mod hir_opt_tests {
end
test p
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:4:
bb1():
EntryPoint interpreter
@@ -4910,7 +4910,7 @@ mod hir_opt_tests {
v15:Fixnum[3] = Const Value(3)
PatchPoint NoSingletonClass(Proc@0x1008)
PatchPoint MethodRedefined(Proc@0x1008, yield@0x1010, cme:0x1018)
- v25:HeapObject[class_exact:Proc] = GuardType v10, HeapObject[class_exact:Proc]
+ v25:ObjectSubclass[class_exact:Proc] = GuardType v10, ObjectSubclass[class_exact:Proc]
v26:BasicObject = InvokeProc v25, v15
CheckInterrupts
Return v26
@@ -4926,7 +4926,7 @@ mod hir_opt_tests {
end
test p
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:4:
bb1():
EntryPoint interpreter
@@ -4943,7 +4943,7 @@ mod hir_opt_tests {
v15:Fixnum[1] = Const Value(1)
PatchPoint NoSingletonClass(Proc@0x1008)
PatchPoint MethodRedefined(Proc@0x1008, ===@0x1010, cme:0x1018)
- v25:HeapObject[class_exact:Proc] = GuardType v10, HeapObject[class_exact:Proc]
+ v25:ObjectSubclass[class_exact:Proc] = GuardType v10, ObjectSubclass[class_exact:Proc]
v26:BasicObject = InvokeProc v25, v15
CheckInterrupts
Return v26
@@ -6289,11 +6289,11 @@ mod hir_opt_tests {
PatchPoint SingleRactorMode
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, zero@0x1008, cme:0x1010)
- v23:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v23:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
v31:StaticSymbol[:b] = Const Value(VALUE(0x1038))
PatchPoint MethodRedefined(Object@0x1000, one@0x1040, cme:0x1048)
- v28:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v28:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
CheckInterrupts
Return v31
@@ -6909,7 +6909,7 @@ mod hir_opt_tests {
test(C.new, C.new)
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:3:
bb1():
EntryPoint interpreter
@@ -6927,7 +6927,7 @@ mod hir_opt_tests {
bb3(v11:BasicObject, v12:BasicObject, v13:BasicObject):
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, ==@0x1010, cme:0x1018)
- v29:HeapObject[class_exact:C] = GuardType v12, HeapObject[class_exact:C]
+ v29:ObjectSubclass[class_exact:C] = GuardType v12, ObjectSubclass[class_exact:C]
v30:CBool = IsBitEqual v29, v13
v31:BoolExact = BoxBool v30
IncrCounter inline_cfunc_optimized_send_count
@@ -7024,7 +7024,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v19:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v19:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
v22:NilClass = Const Value(nil)
CheckInterrupts
@@ -7047,7 +7047,7 @@ mod hir_opt_tests {
test O
test O
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:10:
bb1():
EntryPoint interpreter
@@ -7063,7 +7063,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, foo@0x1010, cme:0x1018)
- v23:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v23:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
v26:CShape = LoadField v23, :_shape_id@0x1040
v27:CShape[0x1041] = GuardBitEquals v26, CShape(0x1041)
v28:BasicObject = LoadField v23, :@foo@0x1042
@@ -7090,7 +7090,7 @@ mod hir_opt_tests {
test O
test O
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:13:
bb1():
EntryPoint interpreter
@@ -7106,7 +7106,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, foo@0x1010, cme:0x1018)
- v23:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v23:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
v26:CShape = LoadField v23, :_shape_id@0x1040
v27:CShape[0x1041] = GuardBitEquals v26, CShape(0x1041)
v28:CPtr = LoadField v23, :_as_heap@0x1042
@@ -7439,7 +7439,7 @@ mod hir_opt_tests {
test O1
test O2
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:20:
bb1():
EntryPoint interpreter
@@ -7453,21 +7453,21 @@ mod hir_opt_tests {
v7:BasicObject = LoadArg :o@1
Jump bb3(v6, v7)
bb3(v9:BasicObject, v10:BasicObject):
- v15:CBool = HasType v10, HeapObject[class_exact:C]
+ v15:CBool = HasType v10, ObjectSubclass[class_exact:C]
IfTrue v15, bb5(v9, v10, v10)
- v24:CBool = HasType v10, HeapObject[class_exact:C]
+ v24:CBool = HasType v10, ObjectSubclass[class_exact:C]
IfTrue v24, bb6(v9, v10, v10)
v33:BasicObject = Send v10, :foo # SendFallbackReason: SendWithoutBlock: polymorphic fallback
Jump bb4(v9, v10, v33)
bb5(v16:BasicObject, v17:BasicObject, v18:BasicObject):
- v20:HeapObject[class_exact:C] = RefineType v18, HeapObject[class_exact:C]
+ v20:ObjectSubclass[class_exact:C] = RefineType v18, ObjectSubclass[class_exact:C]
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, foo@0x1010, cme:0x1018)
IncrCounter getivar_fallback_not_monomorphic
v46:BasicObject = GetIvar v20, :@foo
Jump bb4(v16, v17, v46)
bb6(v25:BasicObject, v26:BasicObject, v27:BasicObject):
- v29:HeapObject[class_exact:C] = RefineType v27, HeapObject[class_exact:C]
+ v29:ObjectSubclass[class_exact:C] = RefineType v27, ObjectSubclass[class_exact:C]
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, foo@0x1010, cme:0x1018)
IncrCounter getivar_fallback_not_monomorphic
@@ -7495,7 +7495,7 @@ mod hir_opt_tests {
def test(o) = o.foo
test obj
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:12:
bb1():
EntryPoint interpreter
@@ -7511,7 +7511,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, foo@0x1010, cme:0x1018)
- v23:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v23:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
IncrCounter getivar_fallback_too_complex
v24:BasicObject = GetIvar v23, :@foo
CheckInterrupts
@@ -7596,7 +7596,7 @@ mod hir_opt_tests {
def test(&block) = [].map(&block)
test { |x| x }; test { |x| x }
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:2:
bb1():
EntryPoint interpreter
@@ -7616,7 +7616,7 @@ mod hir_opt_tests {
v18:CInt64 = GuardNoBitsSet v17, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM=CUInt64(512)
v19:CInt64 = LoadField v16, :_env_data_index_specval@0x1002
v20:CInt64 = GuardAnyBitSet v19, CUInt64(1)
- v21:HeapObject[BlockParamProxy] = Const Value(VALUE(0x1008))
+ v21:ObjectSubclass[BlockParamProxy] = Const Value(VALUE(0x1008))
IncrCounter complex_arg_pass_caller_blockarg
v23:BasicObject = Send v14, 0x1001, :map, v21 # SendFallbackReason: Complex argument passing
CheckInterrupts
@@ -7685,7 +7685,7 @@ mod hir_opt_tests {
v14:CInt64 = GuardNoBitsSet v13, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM=CUInt64(512)
v15:CInt64 = LoadField v12, :_env_data_index_specval@0x1001
v16:CInt64 = GuardAnyBitSet v15, CUInt64(1)
- v17:HeapObject[BlockParamProxy] = Const Value(VALUE(0x1008))
+ v17:ObjectSubclass[BlockParamProxy] = Const Value(VALUE(0x1008))
IncrCounter complex_arg_pass_caller_blockarg
v19:BasicObject = Send v10, 0x1000, :map, v17 # SendFallbackReason: Complex argument passing
CheckInterrupts
@@ -7704,7 +7704,7 @@ mod hir_opt_tests {
test; test
"#);
assert_eq!(VALUE::fixnum_from_usize(2), result);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:6:
bb1():
EntryPoint interpreter
@@ -7717,7 +7717,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
- v20:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v20:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
v21:BasicObject = SendDirect v20, 0x1038, :foo (0x1048)
CheckInterrupts
Return v21
@@ -7749,7 +7749,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, O)
- v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(C@0x1010)
PatchPoint MethodRedefined(C@0x1010, foo@0x1018, cme:0x1020)
v25:CShape = LoadField v20, :_shape_id@0x1048
@@ -7785,7 +7785,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, O)
- v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(C@0x1010)
PatchPoint MethodRedefined(C@0x1010, foo@0x1018, cme:0x1020)
v25:CShape = LoadField v20, :_shape_id@0x1048
@@ -7807,7 +7807,7 @@ mod hir_opt_tests {
test C.new
test C.new
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:6:
bb1():
EntryPoint interpreter
@@ -7823,7 +7823,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, foo@0x1010, cme:0x1018)
- v23:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v23:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
v26:CShape = LoadField v23, :_shape_id@0x1040
v27:CShape[0x1041] = GuardBitEquals v26, CShape(0x1041)
v28:NilClass = Const Value(nil)
@@ -7843,7 +7843,7 @@ mod hir_opt_tests {
test C.new
test C.new
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:6:
bb1():
EntryPoint interpreter
@@ -7859,7 +7859,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, foo@0x1010, cme:0x1018)
- v23:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v23:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
v26:CShape = LoadField v23, :_shape_id@0x1040
v27:CShape[0x1041] = GuardBitEquals v26, CShape(0x1041)
v28:NilClass = Const Value(nil)
@@ -7879,7 +7879,7 @@ mod hir_opt_tests {
test C.new
test C.new
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:6:
bb1():
EntryPoint interpreter
@@ -7895,7 +7895,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
v17:Fixnum[5] = Const Value(5)
PatchPoint MethodRedefined(C@0x1008, foo=@0x1010, cme:0x1018)
- v28:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v28:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
v31:CShape = LoadField v28, :_shape_id@0x1040
v32:CShape[0x1041] = GuardBitEquals v31, CShape(0x1041)
StoreField v28, :@foo@0x1042, v17
@@ -7918,7 +7918,7 @@ mod hir_opt_tests {
test C.new
test C.new
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:6:
bb1():
EntryPoint interpreter
@@ -7934,7 +7934,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
v17:Fixnum[5] = Const Value(5)
PatchPoint MethodRedefined(C@0x1008, foo=@0x1010, cme:0x1018)
- v28:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v28:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
v31:CShape = LoadField v28, :_shape_id@0x1040
v32:CShape[0x1041] = GuardBitEquals v31, CShape(0x1041)
StoreField v28, :@foo@0x1042, v17
@@ -7954,7 +7954,7 @@ mod hir_opt_tests {
test C.new
test C.new
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:3:
bb1():
EntryPoint interpreter
@@ -7970,7 +7970,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, foo@0x1010, cme:0x1018)
- v23:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v23:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
v24:BasicObject = LoadField v23, :foo@0x1040
CheckInterrupts
Return v24
@@ -7985,7 +7985,7 @@ mod hir_opt_tests {
test C.new
test C.new
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:3:
bb1():
EntryPoint interpreter
@@ -8001,7 +8001,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, foo@0x1010, cme:0x1018)
- v23:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v23:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
v24:CPtr = LoadField v23, :_as_heap@0x1040
v25:BasicObject = LoadField v24, :foo@0x1041
CheckInterrupts
@@ -8020,7 +8020,7 @@ mod hir_opt_tests {
test C.new
test C.new
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:4:
bb1():
EntryPoint interpreter
@@ -8036,7 +8036,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, foo@0x1010, cme:0x1018)
- v27:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v27:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
v19:Fixnum[5] = Const Value(5)
CheckInterrupts
Return v19
@@ -8052,7 +8052,7 @@ mod hir_opt_tests {
test C.new, value
test C.new, value
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:3:
bb1():
EntryPoint interpreter
@@ -8070,7 +8070,7 @@ mod hir_opt_tests {
bb3(v11:BasicObject, v12:BasicObject, v13:BasicObject):
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, foo=@0x1010, cme:0x1018)
- v31:HeapObject[class_exact:C] = GuardType v12, HeapObject[class_exact:C]
+ v31:ObjectSubclass[class_exact:C] = GuardType v12, ObjectSubclass[class_exact:C]
v32:CUInt64 = LoadField v31, :_rbasic_flags@0x1040
v33:CUInt64 = GuardNoBitsSet v32, RUBY_FL_FREEZE=CUInt64(2048)
StoreField v31, :foo=@0x1041, v13
@@ -8089,7 +8089,7 @@ mod hir_opt_tests {
test C.new, value
test C.new, value
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:3:
bb1():
EntryPoint interpreter
@@ -8107,7 +8107,7 @@ mod hir_opt_tests {
bb3(v11:BasicObject, v12:BasicObject, v13:BasicObject):
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, foo=@0x1010, cme:0x1018)
- v31:HeapObject[class_exact:C] = GuardType v12, HeapObject[class_exact:C]
+ v31:ObjectSubclass[class_exact:C] = GuardType v12, ObjectSubclass[class_exact:C]
v32:CUInt64 = LoadField v31, :_rbasic_flags@0x1040
v33:CUInt64 = GuardNoBitsSet v32, RUBY_FL_FREEZE=CUInt64(2048)
v34:CPtr = LoadField v31, :_as_heap@0x1041
@@ -8313,7 +8313,7 @@ mod hir_opt_tests {
def test(x) = x.to_s
test (2**65)
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:2:
bb1():
EntryPoint interpreter
@@ -8328,7 +8328,7 @@ mod hir_opt_tests {
Jump bb3(v6, v7)
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint MethodRedefined(Integer@0x1008, to_s@0x1010, cme:0x1018)
- v23:Integer = GuardType v10, Integer
+ v23:Bignum = GuardType v10, Bignum
v24:StringExact = CCallVariadic v23, :Integer#to_s@0x1040
CheckInterrupts
Return v24
@@ -9149,7 +9149,7 @@ mod hir_opt_tests {
test([])
");
assert_contains_opcode("test", YARVINSN_opt_length);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:2:
bb1():
EntryPoint interpreter
@@ -9181,7 +9181,7 @@ mod hir_opt_tests {
test([])
");
assert_contains_opcode("test", YARVINSN_opt_size);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:2:
bb1():
EntryPoint interpreter
@@ -9549,7 +9549,7 @@ mod hir_opt_tests {
test(4 << 70)
");
assert_contains_opcode("test", YARVINSN_opt_succ);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:2:
bb1():
EntryPoint interpreter
@@ -9564,7 +9564,7 @@ mod hir_opt_tests {
Jump bb3(v6, v7)
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint MethodRedefined(Integer@0x1008, succ@0x1010, cme:0x1018)
- v24:Integer = GuardType v10, Integer
+ v24:Bignum = GuardType v10, Bignum
v25:BasicObject = CCallWithFrame v24, :Integer#succ@0x1040
CheckInterrupts
Return v25
@@ -10150,7 +10150,7 @@ mod hir_opt_tests {
def test(x, y) = x ^ y
test(4 << 70, 1)
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:2:
bb1():
EntryPoint interpreter
@@ -10167,7 +10167,7 @@ mod hir_opt_tests {
Jump bb3(v7, v8, v9)
bb3(v11:BasicObject, v12:BasicObject, v13:BasicObject):
PatchPoint MethodRedefined(Integer@0x1008, ^@0x1010, cme:0x1018)
- v27:Integer = GuardType v12, Integer
+ v27:Bignum = GuardType v12, Bignum
v28:BasicObject = CCallWithFrame v27, :Integer#^@0x1040, v13
CheckInterrupts
Return v28
@@ -10327,7 +10327,7 @@ mod hir_opt_tests {
def test(o) = o.respond_to?(:foo)
test(C.new)
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:5:
bb1():
EntryPoint interpreter
@@ -10344,7 +10344,7 @@ mod hir_opt_tests {
v15:StaticSymbol[:foo] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(C@0x1010)
PatchPoint MethodRedefined(C@0x1010, respond_to?@0x1018, cme:0x1020)
- v26:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v26:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
PatchPoint MethodRedefined(C@0x1010, foo@0x1048, cme:0x1050)
v30:TrueClass = Const Value(true)
IncrCounter inline_cfunc_optimized_send_count
@@ -10361,7 +10361,7 @@ mod hir_opt_tests {
def test(o) = o.respond_to?(:foo)
test(C.new)
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:4:
bb1():
EntryPoint interpreter
@@ -10378,7 +10378,7 @@ mod hir_opt_tests {
v15:StaticSymbol[:foo] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(C@0x1010)
PatchPoint MethodRedefined(C@0x1010, respond_to?@0x1018, cme:0x1020)
- v26:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v26:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
PatchPoint MethodRedefined(C@0x1010, respond_to_missing?@0x1048, cme:0x1050)
PatchPoint MethodRedefined(C@0x1010, foo@0x1078, cme:0x1080)
v32:FalseClass = Const Value(false)
@@ -10398,7 +10398,7 @@ mod hir_opt_tests {
def test(o) = o.respond_to?(:foo)
test(C.new)
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:6:
bb1():
EntryPoint interpreter
@@ -10415,7 +10415,7 @@ mod hir_opt_tests {
v15:StaticSymbol[:foo] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(C@0x1010)
PatchPoint MethodRedefined(C@0x1010, respond_to?@0x1018, cme:0x1020)
- v26:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v26:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
PatchPoint MethodRedefined(C@0x1010, foo@0x1048, cme:0x1050)
v30:FalseClass = Const Value(false)
IncrCounter inline_cfunc_optimized_send_count
@@ -10434,7 +10434,7 @@ mod hir_opt_tests {
def test(o) = o.respond_to?(:foo, false)
test(C.new)
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:6:
bb1():
EntryPoint interpreter
@@ -10452,7 +10452,7 @@ mod hir_opt_tests {
v17:FalseClass = Const Value(false)
PatchPoint NoSingletonClass(C@0x1010)
PatchPoint MethodRedefined(C@0x1010, respond_to?@0x1018, cme:0x1020)
- v28:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v28:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
PatchPoint MethodRedefined(C@0x1010, foo@0x1048, cme:0x1050)
v32:FalseClass = Const Value(false)
IncrCounter inline_cfunc_optimized_send_count
@@ -10471,7 +10471,7 @@ mod hir_opt_tests {
def test(o) = o.respond_to?(:foo, nil)
test(C.new)
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:6:
bb1():
EntryPoint interpreter
@@ -10489,7 +10489,7 @@ mod hir_opt_tests {
v17:NilClass = Const Value(nil)
PatchPoint NoSingletonClass(C@0x1010)
PatchPoint MethodRedefined(C@0x1010, respond_to?@0x1018, cme:0x1020)
- v28:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v28:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
PatchPoint MethodRedefined(C@0x1010, foo@0x1048, cme:0x1050)
v32:FalseClass = Const Value(false)
IncrCounter inline_cfunc_optimized_send_count
@@ -10508,7 +10508,7 @@ mod hir_opt_tests {
def test(o) = o.respond_to?(:foo, true)
test(C.new)
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:6:
bb1():
EntryPoint interpreter
@@ -10526,7 +10526,7 @@ mod hir_opt_tests {
v17:TrueClass = Const Value(true)
PatchPoint NoSingletonClass(C@0x1010)
PatchPoint MethodRedefined(C@0x1010, respond_to?@0x1018, cme:0x1020)
- v28:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v28:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
PatchPoint MethodRedefined(C@0x1010, foo@0x1048, cme:0x1050)
v32:TrueClass = Const Value(true)
IncrCounter inline_cfunc_optimized_send_count
@@ -10544,7 +10544,7 @@ mod hir_opt_tests {
def test(o) = o.respond_to?(:foo, 4)
test(C.new)
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:5:
bb1():
EntryPoint interpreter
@@ -10562,7 +10562,7 @@ mod hir_opt_tests {
v17:Fixnum[4] = Const Value(4)
PatchPoint NoSingletonClass(C@0x1010)
PatchPoint MethodRedefined(C@0x1010, respond_to?@0x1018, cme:0x1020)
- v28:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v28:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
PatchPoint MethodRedefined(C@0x1010, foo@0x1048, cme:0x1050)
v32:TrueClass = Const Value(true)
IncrCounter inline_cfunc_optimized_send_count
@@ -10580,7 +10580,7 @@ mod hir_opt_tests {
def test(o) = o.respond_to?(:foo, nil)
test(C.new)
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:5:
bb1():
EntryPoint interpreter
@@ -10598,7 +10598,7 @@ mod hir_opt_tests {
v17:NilClass = Const Value(nil)
PatchPoint NoSingletonClass(C@0x1010)
PatchPoint MethodRedefined(C@0x1010, respond_to?@0x1018, cme:0x1020)
- v28:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v28:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
PatchPoint MethodRedefined(C@0x1010, foo@0x1048, cme:0x1050)
v32:TrueClass = Const Value(true)
IncrCounter inline_cfunc_optimized_send_count
@@ -10615,7 +10615,7 @@ mod hir_opt_tests {
def test(o) = o.respond_to?(:foo)
test(C.new)
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:4:
bb1():
EntryPoint interpreter
@@ -10632,7 +10632,7 @@ mod hir_opt_tests {
v15:StaticSymbol[:foo] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(C@0x1010)
PatchPoint MethodRedefined(C@0x1010, respond_to?@0x1018, cme:0x1020)
- v26:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v26:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
PatchPoint MethodRedefined(C@0x1010, respond_to_missing?@0x1048, cme:0x1050)
PatchPoint MethodRedefined(C@0x1010, foo@0x1078, cme:0x1080)
v32:FalseClass = Const Value(false)
@@ -10653,7 +10653,7 @@ mod hir_opt_tests {
def test(o) = o.respond_to?(:foo)
test(C.new)
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:7:
bb1():
EntryPoint interpreter
@@ -10670,7 +10670,7 @@ mod hir_opt_tests {
v15:StaticSymbol[:foo] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(C@0x1010)
PatchPoint MethodRedefined(C@0x1010, respond_to?@0x1018, cme:0x1020)
- v26:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v26:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
v27:BasicObject = CCallVariadic v26, :Kernel#respond_to?@0x1048, v15
CheckInterrupts
Return v27
@@ -10697,7 +10697,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, callee@0x1008, cme:0x1010)
- v19:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v19:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
CheckInterrupts
Return v19
@@ -10725,7 +10725,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, callee@0x1008, cme:0x1010)
- v19:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v19:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
v22:StringExact[VALUE(0x1038)] = Const Value(VALUE(0x1038))
CheckInterrupts
@@ -10753,7 +10753,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, callee@0x1008, cme:0x1010)
- v19:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v19:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
v22:NilClass = Const Value(nil)
CheckInterrupts
@@ -10781,7 +10781,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, callee@0x1008, cme:0x1010)
- v19:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v19:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
v22:TrueClass = Const Value(true)
CheckInterrupts
@@ -10809,7 +10809,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, callee@0x1008, cme:0x1010)
- v19:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v19:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
v22:FalseClass = Const Value(false)
CheckInterrupts
@@ -10837,7 +10837,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, callee@0x1008, cme:0x1010)
- v19:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v19:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
v22:Fixnum[0] = Const Value(0)
CheckInterrupts
@@ -10865,7 +10865,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, callee@0x1008, cme:0x1010)
- v19:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v19:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
v22:Fixnum[1] = Const Value(1)
CheckInterrupts
@@ -10894,7 +10894,7 @@ mod hir_opt_tests {
v11:Fixnum[3] = Const Value(3)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, callee@0x1008, cme:0x1010)
- v21:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v21:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
CheckInterrupts
Return v11
@@ -10924,7 +10924,7 @@ mod hir_opt_tests {
v15:Fixnum[3] = Const Value(3)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, callee@0x1008, cme:0x1010)
- v25:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v25:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
CheckInterrupts
Return v15
@@ -11043,7 +11043,7 @@ mod hir_opt_tests {
end
test
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:4:
bb1():
EntryPoint interpreter
@@ -11056,7 +11056,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, callee@0x1008, cme:0x1010)
- v20:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v20:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
v23:Fixnum[123] = Const Value(123)
CheckInterrupts
@@ -11074,7 +11074,7 @@ mod hir_opt_tests {
end
test
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:4:
bb1():
EntryPoint interpreter
@@ -11087,7 +11087,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, callee@0x1008, cme:0x1010)
- v20:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v20:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
v23:Fixnum[123] = Const Value(123)
CheckInterrupts
@@ -11105,7 +11105,7 @@ mod hir_opt_tests {
end
test
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:4:
bb1():
EntryPoint interpreter
@@ -11118,7 +11118,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, callee@0x1008, cme:0x1010)
- v20:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v20:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
v23:Fixnum[123] = Const Value(123)
CheckInterrupts
@@ -11827,6 +11827,161 @@ mod hir_opt_tests {
");
}
+ #[test]
+ fn test_fold_is_a_true() {
+ eval(r#"
+ def test = 5.is_a?(Integer)
+ test
+ "#);
+ assert_snapshot!(hir_string("test"), @r"
+ fn test@:2:
+ bb1():
+ EntryPoint interpreter
+ v1:BasicObject = LoadSelf
+ Jump bb3(v1)
+ bb2():
+ EntryPoint JIT(0)
+ v4:BasicObject = LoadArg :self@0
+ Jump bb3(v4)
+ bb3(v6:BasicObject):
+ v10:Fixnum[5] = Const Value(5)
+ PatchPoint SingleRactorMode
+ PatchPoint StableConstantNames(0x1000, Integer)
+ v22:Class[Integer@0x1008] = Const Value(VALUE(0x1008))
+ PatchPoint MethodRedefined(Integer@0x1008, is_a?@0x1009, cme:0x1010)
+ v27:TrueClass = Const Value(true)
+ IncrCounter inline_cfunc_optimized_send_count
+ CheckInterrupts
+ Return v27
+ ");
+ }
+
+ #[test]
+ fn test_fold_is_a_false() {
+ eval(r#"
+ def test = 5.is_a?(String)
+ test
+ "#);
+ assert_snapshot!(hir_string("test"), @r"
+ fn test@:2:
+ bb1():
+ EntryPoint interpreter
+ v1:BasicObject = LoadSelf
+ Jump bb3(v1)
+ bb2():
+ EntryPoint JIT(0)
+ v4:BasicObject = LoadArg :self@0
+ Jump bb3(v4)
+ bb3(v6:BasicObject):
+ v10:Fixnum[5] = Const Value(5)
+ PatchPoint SingleRactorMode
+ PatchPoint StableConstantNames(0x1000, String)
+ v22:Class[String@0x1008] = Const Value(VALUE(0x1008))
+ PatchPoint MethodRedefined(Integer@0x1010, is_a?@0x1018, cme:0x1020)
+ v27:FalseClass = Const Value(false)
+ IncrCounter inline_cfunc_optimized_send_count
+ CheckInterrupts
+ Return v27
+ ");
+ }
+
+ #[test]
+ fn test_is_a_array_subclass_folds_to_true() {
+ eval(r#"
+ class C < Array; end
+ O = C.new
+ def test = O.is_a?(Array)
+ test
+ "#);
+ assert_snapshot!(hir_string("test"), @r"
+ fn test@:4:
+ bb1():
+ EntryPoint interpreter
+ v1:BasicObject = LoadSelf
+ Jump bb3(v1)
+ bb2():
+ EntryPoint JIT(0)
+ v4:BasicObject = LoadArg :self@0
+ Jump bb3(v4)
+ bb3(v6:BasicObject):
+ PatchPoint SingleRactorMode
+ PatchPoint StableConstantNames(0x1000, O)
+ v22:ArraySubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ PatchPoint StableConstantNames(0x1010, Array)
+ v25:Class[Array@0x1018] = Const Value(VALUE(0x1018))
+ PatchPoint NoSingletonClass(C@0x1020)
+ PatchPoint MethodRedefined(C@0x1020, is_a?@0x1028, cme:0x1030)
+ v31:TrueClass = Const Value(true)
+ IncrCounter inline_cfunc_optimized_send_count
+ CheckInterrupts
+ Return v31
+ ");
+ }
+
+ #[test]
+ fn test_is_a_user_defined_class_folds_to_true() {
+ eval(r#"
+ class C; end
+ O = C.new
+ def test = O.is_a?(C)
+ test
+ "#);
+ assert_snapshot!(hir_string("test"), @r"
+ fn test@:4:
+ bb1():
+ EntryPoint interpreter
+ v1:BasicObject = LoadSelf
+ Jump bb3(v1)
+ bb2():
+ EntryPoint JIT(0)
+ v4:BasicObject = LoadArg :self@0
+ Jump bb3(v4)
+ bb3(v6:BasicObject):
+ PatchPoint SingleRactorMode
+ PatchPoint StableConstantNames(0x1000, O)
+ v22:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ PatchPoint StableConstantNames(0x1010, C)
+ v25:Class[C@0x1018] = Const Value(VALUE(0x1018))
+ PatchPoint NoSingletonClass(C@0x1018)
+ PatchPoint MethodRedefined(C@0x1018, is_a?@0x1019, cme:0x1020)
+ v31:TrueClass = Const Value(true)
+ IncrCounter inline_cfunc_optimized_send_count
+ CheckInterrupts
+ Return v31
+ ");
+ }
+
+ #[test]
+ fn test_is_a_symbol_folds_to_true() {
+ eval(r#"
+ O = :my_static_symbol
+ def test = O.is_a?(Symbol)
+ test
+ "#);
+ assert_snapshot!(hir_string("test"), @r"
+ fn test@:3:
+ bb1():
+ EntryPoint interpreter
+ v1:BasicObject = LoadSelf
+ Jump bb3(v1)
+ bb2():
+ EntryPoint JIT(0)
+ v4:BasicObject = LoadArg :self@0
+ Jump bb3(v4)
+ bb3(v6:BasicObject):
+ PatchPoint SingleRactorMode
+ PatchPoint StableConstantNames(0x1000, O)
+ v22:StaticSymbol[:my_static_symbol] = Const Value(VALUE(0x1008))
+ PatchPoint StableConstantNames(0x1010, Symbol)
+ v25:Class[Symbol@0x1018] = Const Value(VALUE(0x1018))
+ PatchPoint MethodRedefined(Symbol@0x1018, is_a?@0x1019, cme:0x1020)
+ v30:TrueClass = Const Value(true)
+ IncrCounter inline_cfunc_optimized_send_count
+ CheckInterrupts
+ Return v30
+ ");
+ }
+
#[test]
fn counting_complex_feature_use_for_fallback() {
eval("
@@ -11946,7 +12101,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(C@0x1000)
PatchPoint MethodRedefined(C@0x1000, class@0x1008, cme:0x1010)
- v43:HeapObject[class_exact:C] = GuardType v6, HeapObject[class_exact:C]
+ v43:ObjectSubclass[class_exact:C] = GuardType v6, ObjectSubclass[class_exact:C]
IncrCounter inline_iseq_optimized_send_count
v47:Class[C@0x1000] = Const Value(VALUE(0x1000))
IncrCounter inline_cfunc_optimized_send_count
@@ -11971,7 +12126,7 @@ mod hir_opt_tests {
def test(o) = o.class.name
test(C.new)
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:3:
bb1():
EntryPoint interpreter
@@ -11987,7 +12142,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, class@0x1010, cme:0x1018)
- v25:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v25:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
IncrCounter inline_iseq_optimized_send_count
v29:Class[C@0x1008] = Const Value(VALUE(0x1008))
IncrCounter inline_cfunc_optimized_send_count
@@ -12007,7 +12162,7 @@ mod hir_opt_tests {
def test(o) = o.class
test(C.new)
"#);
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:3:
bb1():
EntryPoint interpreter
@@ -12023,7 +12178,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, class@0x1010, cme:0x1018)
- v23:HeapObject[class_exact:C] = GuardType v10, HeapObject[class_exact:C]
+ v23:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
IncrCounter inline_iseq_optimized_send_count
v27:Class[C@0x1008] = Const Value(VALUE(0x1008))
IncrCounter inline_cfunc_optimized_send_count
@@ -12078,7 +12233,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, class@0x1008, cme:0x1010)
- v19:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v19:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
IncrCounter inline_iseq_optimized_send_count
v23:Class[Object@0x1038] = Const Value(VALUE(0x1038))
IncrCounter inline_cfunc_optimized_send_count
@@ -12180,7 +12335,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, FROZEN_OBJ)
- v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestFrozen@0x1010)
PatchPoint MethodRedefined(TestFrozen@0x1010, a@0x1018, cme:0x1020)
v29:Fixnum[1] = Const Value(1)
@@ -12221,7 +12376,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, MULTI_FROZEN)
- v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestMultiIvars@0x1010)
PatchPoint MethodRedefined(TestMultiIvars@0x1010, b@0x1018, cme:0x1020)
v29:Fixnum[20] = Const Value(20)
@@ -12260,7 +12415,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, FROZEN_STR)
- v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestFrozenStr@0x1010)
PatchPoint MethodRedefined(TestFrozenStr@0x1010, name@0x1018, cme:0x1020)
v29:StringExact[VALUE(0x1048)] = Const Value(VALUE(0x1048))
@@ -12299,7 +12454,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, FROZEN_NIL)
- v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestFrozenNil@0x1010)
PatchPoint MethodRedefined(TestFrozenNil@0x1010, value@0x1018, cme:0x1020)
v29:NilClass = Const Value(nil)
@@ -12338,7 +12493,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, UNFROZEN_OBJ)
- v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestUnfrozen@0x1010)
PatchPoint MethodRedefined(TestUnfrozen@0x1010, a@0x1018, cme:0x1020)
v25:CShape = LoadField v20, :_shape_id@0x1048
@@ -12379,7 +12534,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, FROZEN_READER)
- v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestAttrReader@0x1010)
PatchPoint MethodRedefined(TestAttrReader@0x1010, value@0x1018, cme:0x1020)
v29:Fixnum[42] = Const Value(42)
@@ -12418,7 +12573,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, FROZEN_SYM)
- v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestFrozenSym@0x1010)
PatchPoint MethodRedefined(TestFrozenSym@0x1010, sym@0x1018, cme:0x1020)
v29:StaticSymbol[:hello] = Const Value(VALUE(0x1048))
@@ -12457,7 +12612,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, FROZEN_TRUE)
- v20:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestFrozenBool@0x1010)
PatchPoint MethodRedefined(TestFrozenBool@0x1010, flag@0x1018, cme:0x1020)
v29:TrueClass = Const Value(true)
@@ -12482,7 +12637,7 @@ mod hir_opt_tests {
test o
test o
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:9:
bb1():
EntryPoint interpreter
@@ -12498,7 +12653,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint NoSingletonClass(TestDynamic@0x1008)
PatchPoint MethodRedefined(TestDynamic@0x1008, val@0x1010, cme:0x1018)
- v23:HeapObject[class_exact:TestDynamic] = GuardType v10, HeapObject[class_exact:TestDynamic]
+ v23:ObjectSubclass[class_exact:TestDynamic] = GuardType v10, ObjectSubclass[class_exact:TestDynamic]
v26:CShape = LoadField v23, :_shape_id@0x1040
v27:CShape[0x1041] = GuardBitEquals v26, CShape(0x1041)
v28:BasicObject = LoadField v23, :@val@0x1042
@@ -12538,12 +12693,12 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, NESTED_FROZEN)
- v27:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v27:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestNestedAccess@0x1010)
PatchPoint MethodRedefined(TestNestedAccess@0x1010, x@0x1018, cme:0x1020)
v52:Fixnum[100] = Const Value(100)
PatchPoint StableConstantNames(0x1048, NESTED_FROZEN)
- v33:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v33:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(TestNestedAccess@0x1010, y@0x1050, cme:0x1058)
v54:Fixnum[200] = Const Value(200)
PatchPoint MethodRedefined(Integer@0x1080, +@0x1088, cme:0x1090)
@@ -12607,7 +12762,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(C@0x1000)
PatchPoint MethodRedefined(C@0x1000, secret@0x1008, cme:0x1010)
- v19:HeapObject[class_exact:C] = GuardType v6, HeapObject[class_exact:C]
+ v19:ObjectSubclass[class_exact:C] = GuardType v6, ObjectSubclass[class_exact:C]
IncrCounter inline_iseq_optimized_send_count
v22:Fixnum[42] = Const Value(42)
CheckInterrupts
@@ -12638,7 +12793,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Obj)
- v21:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v21:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
v12:BasicObject = Send v21, :secret # SendFallbackReason: SendWithoutBlock: method private or protected and no FCALL
CheckInterrupts
Return v12
@@ -12751,7 +12906,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint NoSingletonClass(C@0x1000)
PatchPoint MethodRedefined(C@0x1000, secret@0x1008, cme:0x1010)
- v19:HeapObject[class_exact:C] = GuardType v6, HeapObject[class_exact:C]
+ v19:ObjectSubclass[class_exact:C] = GuardType v6, ObjectSubclass[class_exact:C]
IncrCounter inline_iseq_optimized_send_count
v22:Fixnum[42] = Const Value(42)
CheckInterrupts
@@ -12782,7 +12937,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Obj)
- v21:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v21:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
v12:BasicObject = Send v21, :secret # SendFallbackReason: SendWithoutBlock: method private or protected and no FCALL
CheckInterrupts
Return v12
@@ -13191,7 +13346,7 @@ mod hir_opt_tests {
assert!(hir.contains("InvokeSuper "), "Expected unoptimized InvokeSuper but got:\n{hir}");
assert!(!hir.contains("SendDirect"), "Should not optimize to SendDirect for explicit blockarg:\n{hir}");
- assert_snapshot!(hir, @"
+ assert_snapshot!(hir, @r"
fn foo@:10:
bb1():
EntryPoint interpreter
@@ -13209,7 +13364,7 @@ mod hir_opt_tests {
bb3(v11:BasicObject, v12:BasicObject, v13:NilClass):
PatchPoint NoSingletonClass(B@0x1008)
PatchPoint MethodRedefined(B@0x1008, proc@0x1010, cme:0x1018)
- v39:HeapObject[class_exact:B] = GuardType v11, HeapObject[class_exact:B]
+ v39:ObjectSubclass[class_exact:B] = GuardType v11, ObjectSubclass[class_exact:B]
v40:BasicObject = CCallWithFrame v39, :Kernel#proc@0x1040, block=0x1048
v19:CPtr = GetEP 0
v20:BasicObject = LoadField v19, :blk@0x1050
@@ -13389,7 +13544,7 @@ mod hir_opt_tests {
test C.new; test D.new; test C.new; test D.new
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:11:
bb1():
EntryPoint interpreter
@@ -13403,9 +13558,9 @@ mod hir_opt_tests {
v7:BasicObject = LoadArg :o@1
Jump bb3(v6, v7)
bb3(v9:BasicObject, v10:BasicObject):
- v15:CBool = HasType v10, HeapObject[class_exact:C]
+ v15:CBool = HasType v10, ObjectSubclass[class_exact:C]
IfTrue v15, bb5(v9, v10, v10)
- v24:CBool = HasType v10, HeapObject[class_exact:D]
+ v24:CBool = HasType v10, ObjectSubclass[class_exact:D]
IfTrue v24, bb6(v9, v10, v10)
v33:BasicObject = Send v10, :foo # SendFallbackReason: SendWithoutBlock: polymorphic fallback
Jump bb4(v9, v10, v33)
@@ -13444,7 +13599,7 @@ mod hir_opt_tests {
test C.new; test 3; test C.new; test 4
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:5:
bb1():
EntryPoint interpreter
@@ -13458,14 +13613,14 @@ mod hir_opt_tests {
v7:BasicObject = LoadArg :o@1
Jump bb3(v6, v7)
bb3(v9:BasicObject, v10:BasicObject):
- v15:CBool = HasType v10, HeapObject[class_exact:C]
+ v15:CBool = HasType v10, ObjectSubclass[class_exact:C]
IfTrue v15, bb5(v9, v10, v10)
v24:CBool = HasType v10, Fixnum
IfTrue v24, bb6(v9, v10, v10)
v33:BasicObject = Send v10, :itself # SendFallbackReason: SendWithoutBlock: polymorphic fallback
Jump bb4(v9, v10, v33)
bb5(v16:BasicObject, v17:BasicObject, v18:BasicObject):
- v20:HeapObject[class_exact:C] = RefineType v18, HeapObject[class_exact:C]
+ v20:ObjectSubclass[class_exact:C] = RefineType v18, ObjectSubclass[class_exact:C]
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, itself@0x1010, cme:0x1018)
IncrCounter inline_cfunc_optimized_send_count
@@ -13561,7 +13716,7 @@ mod hir_opt_tests {
test_ep_escape([1], lambda { }) { |x| }
}
");
- assert_snapshot!(hir_string("test_ep_escape"), @"
+ assert_snapshot!(hir_string("test_ep_escape"), @r"
fn test_ep_escape@:3:
bb1():
EntryPoint interpreter
@@ -13619,7 +13774,7 @@ mod hir_opt_tests {
v71:Falsy = RefineType v60, Falsy
PatchPoint NoSingletonClass(Object@0x1020)
PatchPoint MethodRedefined(Object@0x1020, lambda@0x1028, cme:0x1030)
- v119:HeapObject[class_exact*:Object@VALUE(0x1020)] = GuardType v58, HeapObject[class_exact*:Object@VALUE(0x1020)]
+ v119:ObjectSubclass[class_exact*:Object@VALUE(0x1020)] = GuardType v58, ObjectSubclass[class_exact*:Object@VALUE(0x1020)]
v120:BasicObject = CCallWithFrame v119, :Kernel#lambda@0x1058, block=0x1060
v75:CPtr = GetEP 0
v76:BasicObject = LoadField v75, :list@0x1001
diff --git a/zjit/src/hir/tests.rs b/zjit/src/hir/tests.rs
index 2e4a457a47e131..358cae1f6d053c 100644
--- a/zjit/src/hir/tests.rs
+++ b/zjit/src/hir/tests.rs
@@ -123,7 +123,7 @@ mod snapshot_tests {
v23:Any = Snapshot FrameState { pc: 0x1008, stack: [v6, v13, v15, v11], locals: [] }
PatchPoint NoSingletonClass(Object@0x1010)
PatchPoint MethodRedefined(Object@0x1010, foo@0x1018, cme:0x1020)
- v26:HeapObject[class_exact*:Object@VALUE(0x1010)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1010)]
+ v26:ObjectSubclass[class_exact*:Object@VALUE(0x1010)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1010)]
v27:BasicObject = SendDirect v26, 0x1048, :foo (0x1058), v13, v15, v11
v18:Any = Snapshot FrameState { pc: 0x1060, stack: [v27], locals: [] }
PatchPoint NoTracePoint
@@ -160,7 +160,7 @@ mod snapshot_tests {
v14:Any = Snapshot FrameState { pc: 0x1008, stack: [v6, v11, v13], locals: [] }
PatchPoint NoSingletonClass(Object@0x1010)
PatchPoint MethodRedefined(Object@0x1010, foo@0x1018, cme:0x1020)
- v23:HeapObject[class_exact*:Object@VALUE(0x1010)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1010)]
+ v23:ObjectSubclass[class_exact*:Object@VALUE(0x1010)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1010)]
v24:BasicObject = SendDirect v23, 0x1048, :foo (0x1058), v11, v13
v16:Any = Snapshot FrameState { pc: 0x1060, stack: [v24], locals: [] }
PatchPoint NoTracePoint
@@ -2310,7 +2310,7 @@ pub mod hir_build_tests {
eval("
def test(a, ...) = foo(a, ...)
");
- assert_snapshot!(hir_string("test"), @"
+ assert_snapshot!(hir_string("test"), @r"
fn test@:2:
bb1():
EntryPoint interpreter
@@ -2339,7 +2339,7 @@ pub mod hir_build_tests {
v36:CInt64 = GuardNoBitsSet v35, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM=CUInt64(512)
v37:CInt64 = LoadField v34, :_env_data_index_specval@0x1005
v38:CInt64 = GuardAnyBitSet v37, CUInt64(1)
- v39:HeapObject[BlockParamProxy] = Const Value(VALUE(0x1008))
+ v39:ObjectSubclass[BlockParamProxy] = Const Value(VALUE(0x1008))
SideExit SplatKwNotProfiled
");
}
@@ -3232,7 +3232,7 @@ pub mod hir_build_tests {
v21:CInt64 = GuardNoBitsSet v20, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM=CUInt64(512)
v22:CInt64 = LoadField v19, :_env_data_index_specval@0x1003
v23:CInt64 = GuardAnyBitSet v22, CUInt64(1)
- v24:HeapObject[BlockParamProxy] = Const Value(VALUE(0x1008))
+ v24:ObjectSubclass[BlockParamProxy] = Const Value(VALUE(0x1008))
SideExit SplatKwNotProfiled
");
}
@@ -3311,7 +3311,7 @@ pub mod hir_build_tests {
v21:CInt64 = GuardNoBitsSet v20, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM=CUInt64(512)
v22:CInt64 = LoadField v19, :_env_data_index_specval@0x1003
v23:CInt64 = GuardAnyBitSet v22, CUInt64(1)
- v24:HeapObject[BlockParamProxy] = Const Value(VALUE(0x1008))
+ v24:ObjectSubclass[BlockParamProxy] = Const Value(VALUE(0x1008))
v26:HashExact = GuardType v12, HashExact
v28:BasicObject = Send v11, 0x1002, :foo, v26, v24 # SendFallbackReason: Uncategorized(send)
CheckInterrupts
@@ -3348,7 +3348,7 @@ pub mod hir_build_tests {
v21:CInt64 = GuardNoBitsSet v20, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM=CUInt64(512)
v22:CInt64 = LoadField v19, :_env_data_index_specval@0x1003
v23:CInt64 = GuardAnyBitSet v22, CUInt64(1)
- v24:HeapObject[BlockParamProxy] = Const Value(VALUE(0x1008))
+ v24:ObjectSubclass[BlockParamProxy] = Const Value(VALUE(0x1008))
v26:HashExact = GuardType v12, HashExact
v28:BasicObject = Send v11, 0x1002, :foo, v26, v24 # SendFallbackReason: Uncategorized(send)
CheckInterrupts
@@ -3431,7 +3431,7 @@ pub mod hir_build_tests {
v21:CInt64 = GuardNoBitsSet v20, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM=CUInt64(512)
v22:CInt64 = LoadField v19, :_env_data_index_specval@0x1003
v23:CInt64 = GuardAnyBitSet v22, CUInt64(1)
- v24:HeapObject[BlockParamProxy] = Const Value(VALUE(0x1008))
+ v24:ObjectSubclass[BlockParamProxy] = Const Value(VALUE(0x1008))
SideExit SplatKwNotNilOrHash
");
}
@@ -4084,7 +4084,7 @@ pub mod hir_build_tests {
let iseq = crate::cruby::with_rubyvm(|| get_method_iseq("Dir", "open"));
assert!(iseq_contains_opcode(iseq, YARVINSN_opt_invokebuiltin_delegate), "iseq Dir.open does not contain invokebuiltin");
let function = iseq_to_hir(iseq).unwrap();
- assert_snapshot!(hir_string_function(&function), @"
+ assert_snapshot!(hir_string_function(&function), @r"
fn open@:
bb1():
EntryPoint interpreter
@@ -4114,12 +4114,12 @@ pub mod hir_build_tests {
v35:CInt64 = GuardNoBitsSet v34, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM=CUInt64(512)
v36:CInt64 = LoadField v33, :_env_data_index_specval@0x1005
v37:CInt64 = GuardAnyBitSet v36, CUInt64(1)
- v38:HeapObject[BlockParamProxy] = Const Value(VALUE(0x1008))
+ v38:ObjectSubclass[BlockParamProxy] = Const Value(VALUE(0x1008))
CheckInterrupts
v41:CBool[true] = Test v38
v42 = RefineType v38, Falsy
IfFalse v41, bb4(v18, v19, v20, v21, v22, v27)
- v44:HeapObject[BlockParamProxy] = RefineType v38, Truthy
+ v44:ObjectSubclass[BlockParamProxy] = RefineType v38, Truthy
v48:BasicObject = InvokeBlock, v27 # SendFallbackReason: Uncategorized(invokeblock)
v51:BasicObject = InvokeBuiltin dir_s_close, v18, v27
CheckInterrupts
diff --git a/zjit/src/hir_type/gen_hir_type.rb b/zjit/src/hir_type/gen_hir_type.rb
index f952a8b71561fe..5934dcb2d0ea41 100644
--- a/zjit/src/hir_type/gen_hir_type.rb
+++ b/zjit/src/hir_type/gen_hir_type.rb
@@ -63,6 +63,11 @@ def to_graphviz type, f
"BasicObjectExact" => "rb_cBasicObject",
}
+$subclass_c_names = {
+ "ObjectSubclass" => "rb_cObject",
+ "BasicObjectSubclass" => "rb_cBasicObject",
+}
+
$inexact_c_names = {
"Object" => "rb_cObject",
"BasicObject" => "rb_cBasicObject",
@@ -76,7 +81,8 @@ def base_type name, c_name: nil
subclass = type.subtype(name+"Subclass")
if c_name
$exact_c_names[exact.name] = c_name
- $inexact_c_names[subclass.name] = c_name
+ $subclass_c_names[subclass.name] = c_name
+ $inexact_c_names[type.name] = c_name
end
$builtin_exact << exact.name
$subclass << subclass.name
@@ -88,6 +94,8 @@ def base_type name, c_name: nil
def final_type name, base: $object, c_name: nil
if c_name
$exact_c_names[name] = c_name
+ $subclass_c_names[name] = c_name
+ $inexact_c_names[name] = c_name
end
type = base.subtype name
$builtin_exact << type.name
@@ -217,7 +225,13 @@ def add_union name, type_names
puts " (bits::#{type_name}, &raw const crate::cruby::#{c_name}),"
}
puts " ];"
-$inexact_c_names = $inexact_c_names.to_a.sort_by {|name, _| $bits[name]}.to_h
+$subclass_c_names = $subclass_c_names.to_a.sort_by {|name, _| $numeric_bits[name.sub("Subclass", "")]}.to_h
+puts " pub const SubclassBitsAndClass: [(u64, *const VALUE); #{$subclass_c_names.size}] = ["
+$subclass_c_names.each {|type_name, c_name|
+ puts " (bits::#{type_name}, &raw const crate::cruby::#{c_name}),"
+}
+puts " ];"
+$inexact_c_names = $inexact_c_names.to_a.sort_by {|name, _| $numeric_bits[name]}.to_h
puts " pub const InexactBitsAndClass: [(u64, *const VALUE); #{$inexact_c_names.size}] = ["
$inexact_c_names.each {|type_name, c_name|
puts " (bits::#{type_name}, &raw const crate::cruby::#{c_name}),"
diff --git a/zjit/src/hir_type/hir_type.inc.rs b/zjit/src/hir_type/hir_type.inc.rs
index 886b4b54dd2811..99697deb82a23b 100644
--- a/zjit/src/hir_type/hir_type.inc.rs
+++ b/zjit/src/hir_type/hir_type.inc.rs
@@ -247,15 +247,41 @@ pub mod types {
(bits::TrueClass, &raw const crate::cruby::rb_cTrueClass),
(bits::FalseClass, &raw const crate::cruby::rb_cFalseClass),
];
- pub const InexactBitsAndClass: [(u64, *const VALUE); 10] = [
+ pub const SubclassBitsAndClass: [(u64, *const VALUE); 17] = [
(bits::ArraySubclass, &raw const crate::cruby::rb_cArray),
+ (bits::Class, &raw const crate::cruby::rb_cClass),
+ (bits::FalseClass, &raw const crate::cruby::rb_cFalseClass),
+ (bits::Integer, &raw const crate::cruby::rb_cInteger),
(bits::HashSubclass, &raw const crate::cruby::rb_cHash),
+ (bits::Float, &raw const crate::cruby::rb_cFloat),
(bits::ModuleSubclass, &raw const crate::cruby::rb_cModule),
+ (bits::NilClass, &raw const crate::cruby::rb_cNilClass),
(bits::NumericSubclass, &raw const crate::cruby::rb_cNumeric),
(bits::RangeSubclass, &raw const crate::cruby::rb_cRange),
(bits::RegexpSubclass, &raw const crate::cruby::rb_cRegexp),
(bits::SetSubclass, &raw const crate::cruby::rb_cSet),
+ (bits::Symbol, &raw const crate::cruby::rb_cSymbol),
(bits::StringSubclass, &raw const crate::cruby::rb_cString),
+ (bits::TrueClass, &raw const crate::cruby::rb_cTrueClass),
+ (bits::ObjectSubclass, &raw const crate::cruby::rb_cObject),
+ (bits::BasicObjectSubclass, &raw const crate::cruby::rb_cBasicObject),
+ ];
+ pub const InexactBitsAndClass: [(u64, *const VALUE); 17] = [
+ (bits::Array, &raw const crate::cruby::rb_cArray),
+ (bits::Class, &raw const crate::cruby::rb_cClass),
+ (bits::FalseClass, &raw const crate::cruby::rb_cFalseClass),
+ (bits::Integer, &raw const crate::cruby::rb_cInteger),
+ (bits::Hash, &raw const crate::cruby::rb_cHash),
+ (bits::Float, &raw const crate::cruby::rb_cFloat),
+ (bits::Module, &raw const crate::cruby::rb_cModule),
+ (bits::NilClass, &raw const crate::cruby::rb_cNilClass),
+ (bits::Numeric, &raw const crate::cruby::rb_cNumeric),
+ (bits::Range, &raw const crate::cruby::rb_cRange),
+ (bits::Regexp, &raw const crate::cruby::rb_cRegexp),
+ (bits::Set, &raw const crate::cruby::rb_cSet),
+ (bits::Symbol, &raw const crate::cruby::rb_cSymbol),
+ (bits::String, &raw const crate::cruby::rb_cString),
+ (bits::TrueClass, &raw const crate::cruby::rb_cTrueClass),
(bits::Object, &raw const crate::cruby::rb_cObject),
(bits::BasicObject, &raw const crate::cruby::rb_cBasicObject),
];
diff --git a/zjit/src/hir_type/mod.rs b/zjit/src/hir_type/mod.rs
index cc6a208bcd413e..e1e2c1a8104d51 100644
--- a/zjit/src/hir_type/mod.rs
+++ b/zjit/src/hir_type/mod.rs
@@ -190,7 +190,7 @@ impl Type {
}
fn bits_from_subclass(class: VALUE) -> Option {
- types::InexactBitsAndClass
+ types::SubclassBitsAndClass
.iter()
.find(|&(_, class_object)| class.is_subclass_of(unsafe { **class_object }) == ClassRelationship::Subclass)
// Can't be an immediate if it's a subclass.
@@ -274,7 +274,8 @@ impl Type {
else if val.is_nil() { types::NilClass }
else if val.is_true() { types::TrueClass }
else if val.is_false() { types::FalseClass }
- else { Self::from_class(val.class()) }
+ // TODO(max): Revisit and maybe specialize to *not* an immediate
+ else { Self::from_class(val.class()).intersection(types::HeapBasicObject) }
}
pub fn from_class(class: VALUE) -> Type {
@@ -288,6 +289,14 @@ impl Type {
get_class_name(class))
}
+ pub fn from_class_inexact(class: VALUE) -> Type {
+ let bits = types::InexactBitsAndClass
+ .iter()
+ .find(|&(_, class_object)| class.is_subclass_of(unsafe { **class_object }) == ClassRelationship::Subclass)
+ .unwrap_or_else(|| panic!("Class {} is not a subclass of BasicObject! Don't know what to do.", get_class_name(class))).0;
+ Type { bits, spec: Specialization::Type(class) }
+ }
+
/// Private. Only for creating type globals.
const fn from_bits(bits: u64) -> Type {
Type {
@@ -801,7 +810,7 @@ mod tests {
assert_bit_equal(Type::from_class(unsafe { rb_cTrueClass }), types::TrueClass);
assert_bit_equal(Type::from_class(unsafe { rb_cFalseClass }), types::FalseClass);
let c_class = define_class("C", unsafe { rb_cObject });
- assert_bit_equal(Type::from_class(c_class), Type { bits: bits::HeapObject, spec: Specialization::TypeExact(c_class) });
+ assert_bit_equal(Type::from_class(c_class), Type { bits: bits::ObjectSubclass, spec: Specialization::TypeExact(c_class) });
});
}