summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Patterson <tenderlove@ruby-lang.org>2021-09-03 16:06:32 -0700
committerAlan Wu <XrXr@users.noreply.github.com>2021-10-20 18:19:39 -0400
commit640b162b51a704d890c44af9c76fffa4eaf28ca9 (patch)
tree94614f3d8f56a4bb13905cfe78d8b9f3ed00845b
parent376f5ec1a1c744ca6a78726dbf9886e30b3400fa (diff)
Exit when the object is frozen
Exit when the object is frozen, also add tests
-rw-r--r--bootstraptest/test_yjit.rb22
-rw-r--r--test/ruby/test_yjit.rb14
-rw-r--r--yjit_codegen.c5
3 files changed, 41 insertions, 0 deletions
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index 96141e315c..866d7e2558 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -1,3 +1,25 @@
+# Check that frozen objects are respected
+assert_equal 'great', %q{
+ class Foo
+ attr_accessor :bar
+ def initialize
+ @bar = 1
+ freeze
+ end
+ end
+
+ foo = Foo.new
+
+ 5.times do
+ begin
+ foo.bar = 2
+ rescue FrozenError
+ end
+ end
+
+ foo.bar == 1 ? "great" : "NG"
+}
+
# Check that global variable set works
assert_equal 'string', %q{
def foo
diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb
index 587e6d3f1d..90940009e2 100644
--- a/test/ruby/test_yjit.rb
+++ b/test/ruby/test_yjit.rb
@@ -75,6 +75,20 @@ class TestYJIT < Test::Unit::TestCase
assert_no_exits('"i am a string #{true}"')
end
+ def test_compile_attr_set
+ assert_no_exits(<<~EORB)
+ class Foo
+ attr_accessor :bar
+ end
+
+ foo = Foo.new
+ foo.bar = 3
+ foo.bar = 3
+ foo.bar = 3
+ foo.bar = 3
+ EORB
+ end
+
def test_compile_regexp
assert_no_exits('/#{true}/')
end
diff --git a/yjit_codegen.c b/yjit_codegen.c
index 2d31fd03de..c0734fddaf 100644
--- a/yjit_codegen.c
+++ b/yjit_codegen.c
@@ -1447,6 +1447,11 @@ gen_set_ivar(jitstate_t *jit, ctx_t *ctx, const int max_chain_depth, VALUE compt
VALUE comptime_val_klass = CLASS_OF(comptime_receiver);
const ctx_t starting_context = *ctx; // make a copy for use with jit_chain_guard
+ ADD_COMMENT(cb, "guard self is not frozen");
+ x86opnd_t flags_opnd = member_opnd(REG0, struct RBasic, flags);
+ test(cb, flags_opnd, imm_opnd(RUBY_FL_FREEZE));
+ jnz_ptr(cb, COUNTED_EXIT(side_exit, setivar_frozen));
+
// If the class uses the default allocator, instances should all be T_OBJECT
// NOTE: This assumes nobody changes the allocator of the class after allocation.
// Eventually, we can encode whether an object is T_OBJECT or not