summaryrefslogtreecommitdiff
path: root/lib/ruby_vm/mjit/insn_compiler.rb
diff options
context:
space:
mode:
authorTakashi Kokubun <[email protected]>2023-03-02 23:44:57 -0800
committerTakashi Kokubun <[email protected]>2023-03-05 23:28:59 -0800
commit49f336f468659af722d473f3e3073a4e97719f76 (patch)
treed290a34b510827fa19e4e6a9abcfae3bf1a20c22 /lib/ruby_vm/mjit/insn_compiler.rb
parent6d59cac4ad8944a725762165d470953dd534528b (diff)
Implement new ivars on setivar
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/7448
Diffstat (limited to 'lib/ruby_vm/mjit/insn_compiler.rb')
-rw-r--r--lib/ruby_vm/mjit/insn_compiler.rb81
1 files changed, 57 insertions, 24 deletions
diff --git a/lib/ruby_vm/mjit/insn_compiler.rb b/lib/ruby_vm/mjit/insn_compiler.rb
index 38ba71a964..a06614450b 100644
--- a/lib/ruby_vm/mjit/insn_compiler.rb
+++ b/lib/ruby_vm/mjit/insn_compiler.rb
@@ -185,24 +185,6 @@ module RubyVM::MJIT
jit_getivar(jit, ctx, asm, comptime_obj, id)
end
- #id = jit.operand(0)
- #ivc = jit.operand(1)
-
- ## rb_vm_setinstancevariable could raise exceptions
- #jit_prepare_routine_call(jit, ctx, asm)
-
- #val_opnd = ctx.stack_pop
-
- #asm.comment('rb_vm_setinstancevariable')
- #asm.mov(:rdi, jit.iseq.to_i)
- #asm.mov(:rsi, [CFP, C.rb_control_frame_t.offsetof(:self)])
- #asm.mov(:rdx, id)
- #asm.mov(:rcx, val_opnd)
- #asm.mov(:r8, ivc)
- #asm.call(C.rb_vm_setinstancevariable)
-
- #KeepCompiling
-
# @param jit [RubyVM::MJIT::JITState]
# @param ctx [RubyVM::MJIT::Context]
# @param asm [RubyVM::MJIT::Assembler]
@@ -273,8 +255,59 @@ module RubyVM::MJIT
# If we don't have an instance variable index, then we need to
# transition out of the current shape.
if ivar_index.nil?
- asm.incr_counter(:setivar_no_index)
- return CantCompile
+ shape = C.rb_shape_get_shape_by_id(shape_id)
+
+ current_capacity = shape.capacity
+ new_capacity = current_capacity * 2
+
+ # If the object doesn't have the capacity to store the IV,
+ # then we'll need to allocate it.
+ needs_extension = shape.next_iv_index >= current_capacity
+
+ # We can write to the object, but we need to transition the shape
+ ivar_index = shape.next_iv_index
+
+ capa_shape =
+ if needs_extension
+ # We need to add an extended table to the object
+ # First, create an outgoing transition that increases the capacity
+ C.rb_shape_transition_shape_capa(shape, new_capacity)
+ else
+ nil
+ end
+
+ dest_shape =
+ if capa_shape
+ C.rb_shape_get_next(capa_shape, comptime_receiver, ivar_name)
+ else
+ C.rb_shape_get_next(shape, comptime_receiver, ivar_name)
+ end
+ new_shape_id = C.rb_shape_id(dest_shape)
+
+ if new_shape_id == C.OBJ_TOO_COMPLEX_SHAPE_ID
+ asm.incr_counter(:setivar_too_complex)
+ return CantCompile
+ end
+
+ if needs_extension
+ # Generate the C call so that runtime code will increase
+ # the capacity and set the buffer.
+ asm.mov(C_ARGS[0], :rax)
+ asm.mov(C_ARGS[1], current_capacity)
+ asm.mov(C_ARGS[2], new_capacity)
+ asm.call(C.rb_ensure_iv_list_size)
+
+ # Load the receiver again after the function call
+ asm.mov(:rax, [CFP, C.rb_control_frame_t.offsetof(:self)])
+ end
+
+ write_val = ctx.stack_pop(1)
+ jit_write_iv(asm, comptime_receiver, :rax, :rcx, ivar_index, write_val, needs_extension)
+
+ # Store the new shape
+ asm.comment('write shape')
+ asm.mov(:rax, [CFP, C.rb_control_frame_t.offsetof(:self)]) # reload after jit_write_iv
+ asm.mov(DwordPtr[:rax, C.rb_shape_id_offset], new_shape_id)
else
# If the iv index already exists, then we don't need to
# transition to a new shape. The reason is because we find
@@ -282,7 +315,7 @@ module RubyVM::MJIT
# made the transition already, then there's no reason to
# update the shape on the object. Just set the IV.
write_val = ctx.stack_pop(1)
- jit_write_iv(asm, comptime_receiver, :rax, :rcx, ivar_index, write_val)
+ jit_write_iv(asm, comptime_receiver, :rax, :rcx, ivar_index, write_val, false)
end
skip_wb = asm.new_label('skip_wb')
@@ -295,7 +328,7 @@ module RubyVM::MJIT
asm.jbe(skip_wb)
asm.comment('write barrier')
- asm.mov(C_ARGS[0], [CFP, C.rb_control_frame_t.offsetof(:self)])
+ asm.mov(C_ARGS[0], [CFP, C.rb_control_frame_t.offsetof(:self)]) # reload after jit_write_iv
asm.mov(C_ARGS[1], write_val)
asm.call(C.rb_gc_writebarrier)
@@ -2351,9 +2384,9 @@ module RubyVM::MJIT
EndBlock
end
- def jit_write_iv(asm, comptime_receiver, recv_reg, temp_reg, ivar_index, set_value)
+ def jit_write_iv(asm, comptime_receiver, recv_reg, temp_reg, ivar_index, set_value, needs_extension)
# Compile time self is embedded and the ivar index lands within the object
- embed_test_result = C.FL_TEST_RAW(comptime_receiver, C.ROBJECT_EMBED)
+ embed_test_result = C.FL_TEST_RAW(comptime_receiver, C.ROBJECT_EMBED) && !needs_extension
if embed_test_result
# Find the IV offset