diff --git a/lib/ruby_vm/mjit/assembler.rb b/lib/ruby_vm/mjit/assembler.rb index 543d94bef2..c9f179c3b9 100644 --- a/lib/ruby_vm/mjit/assembler.rb +++ b/lib/ruby_vm/mjit/assembler.rb @@ -136,6 +136,10 @@ module RubyVM::MJIT in Integer => dst_addr # E9 cd insn(opcode: 0xe9, imm: rel32(dst_addr)) + # JMP r/m64 (Mod 01: [reg]+disp8) + in [Symbol => dst_reg, Integer => dst_disp] if imm8?(dst_disp) + # FF /4 + insn(opcode: 0xff, mod_rm: ModRM[mod: Mod01, reg: 4, rm: dst_reg], disp: dst_disp) # JMP r/m64 (Mod 11: reg) in Symbol => dst_reg # FF /4 @@ -145,6 +149,17 @@ module RubyVM::MJIT end end + def jne(dst) + case dst + # JNE rel32 + in Integer => dst_addr + # 0F 85 cd + insn(opcode: [0x0f, 0x85], imm: rel32(dst_addr)) + else + raise NotImplementedError, "jne: not-implemented operands: #{dst.inspect}" + end + end + def jnz(dst) case dst # JNZ rel32 @@ -182,6 +197,23 @@ module RubyVM::MJIT end end + def lea(dst, src) + case [dst, src] + # LEA r64,m (Mod 01: [reg]+disp8) + in [Symbol => dst_reg, [Symbol => src_reg, Integer => src_disp]] if r64?(dst_reg) && r64?(src_reg) && imm8?(src_disp) + # REX.W + 8D /r + # RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r) + insn( + prefix: REX_W, + opcode: 0x8d, + mod_rm: ModRM[mod: Mod01, reg: dst_reg, rm: src_reg], + disp: src_disp, + ) + else + raise NotImplementedError, "lea: not-implemented operands: #{dst.inspect}, #{src.inspect}" + end + end + def mov(dst, src) case dst in Symbol => dst_reg diff --git a/lib/ruby_vm/mjit/block_stub.rb b/lib/ruby_vm/mjit/block_stub.rb index c44b66170b..f676374fa0 100644 --- a/lib/ruby_vm/mjit/block_stub.rb +++ b/lib/ruby_vm/mjit/block_stub.rb @@ -1,8 +1,9 @@ class RubyVM::MJIT::BlockStub < Struct.new( - :iseq, # @param [RubyVM::MJIT::CPointer::Struct_rb_iseq_struct] Stub target ISEQ - :ctx, # @param [RubyVM::MJIT::Context] Stub target context - :pc, # @param [Integer] Stub target pc - :start_addr, # @param [Integer] Stub source start address to be re-generated - :end_addr, # @param [Integer] Stub source end address to be re-generated + :iseq, # @param [RubyVM::MJIT::CPointer::Struct_rb_iseq_struct] Stub target ISEQ + :ctx, # @param [RubyVM::MJIT::Context] Stub target context + :pc, # @param [Integer] Stub target pc + :start_addr, # @param [Integer] Stub source start address to be re-generated + :end_addr, # @param [Integer] Stub source end address to be re-generated + :change_block, # @param [Proc] Recompile the source address with a new block address ) end diff --git a/lib/ruby_vm/mjit/compiler.rb b/lib/ruby_vm/mjit/compiler.rb index 5daa006aff..3fc56dac5e 100644 --- a/lib/ruby_vm/mjit/compiler.rb +++ b/lib/ruby_vm/mjit/compiler.rb @@ -44,6 +44,11 @@ module RubyVM::MJIT @ocb = CodeBlock.new(mem_block: mem_block + mem_size / 2, mem_size: mem_size / 2, outlined: true) @exit_compiler = ExitCompiler.new @insn_compiler = InsnCompiler.new(@ocb, @exit_compiler) + + @leave_exit = Assembler.new.then do |asm| + @exit_compiler.compile_leave_exit(asm) + @ocb.write(asm) + end end # Compile an ISEQ from its entry point. @@ -86,10 +91,10 @@ module RubyVM::MJIT new_addr = @cb.write(new_asm) @cb.with_write_addr(block_stub.start_addr) do asm = Assembler.new - asm.comment('regenerate block stub') - asm.jmp(new_addr) + block_stub.change_block.call(asm, new_addr) @cb.write(asm) end + new_addr end end @@ -181,6 +186,10 @@ module RubyVM::MJIT # Load sp to a dedicated register asm.mov(SP, [CFP, C.rb_control_frame_t.offsetof(:sp)]) # rbx = cfp->sp + + # Setup cfp->jit_return + asm.mov(:rax, @leave_exit) + asm.mov([CFP, C.rb_control_frame_t.offsetof(:jit_return)], :rax) end # @param asm [RubyVM::MJIT::Assembler] diff --git a/lib/ruby_vm/mjit/exit_compiler.rb b/lib/ruby_vm/mjit/exit_compiler.rb index 3a0c12f525..d49a293399 100644 --- a/lib/ruby_vm/mjit/exit_compiler.rb +++ b/lib/ruby_vm/mjit/exit_compiler.rb @@ -24,6 +24,17 @@ module RubyVM::MJIT asm.ret end + # @param ocb [CodeBlock] + def compile_leave_exit(asm) + # Restore callee-saved registers + asm.pop(SP) + asm.pop(EC) + asm.pop(CFP) + + # :rax is written by #leave + asm.ret + end + # @param jit [RubyVM::MJIT::JITState] # @param ctx [RubyVM::MJIT::Context] # @param asm [RubyVM::MJIT::Assembler] @@ -44,11 +55,10 @@ module RubyVM::MJIT asm.ret end - # @param jit [RubyVM::MJIT::JITState] # @param ctx [RubyVM::MJIT::Context] # @param asm [RubyVM::MJIT::Assembler] # @param block_stub [RubyVM::MJIT::BlockStub] - def compile_block_stub(jit, ctx, asm, block_stub) + def compile_block_stub(ctx, asm, block_stub) # Call rb_mjit_block_stub_hit asm.comment("block stub hit: #{block_stub.iseq.body.location.label}@#{C.rb_iseq_path(block_stub.iseq)}:#{iseq_lineno(block_stub.iseq, block_stub.pc)}") asm.mov(:rdi, to_value(block_stub)) @@ -98,7 +108,7 @@ module RubyVM::MJIT # @param asm [RubyVM::MJIT::Assembler] def save_pc_and_sp(jit, ctx, asm) # Update pc (TODO: manage PC offset?) - asm.comment("save pc #{'and sp' if ctx.sp_offset != 0}") + asm.comment("save PC#{' and SP' if ctx.sp_offset != 0} to CFP") asm.mov(:rax, jit.pc) # rax = jit.pc asm.mov([CFP, C.rb_control_frame_t.offsetof(:pc)], :rax) # cfp->pc = rax diff --git a/lib/ruby_vm/mjit/insn_compiler.rb b/lib/ruby_vm/mjit/insn_compiler.rb index db2be20f4c..ccfca5eaa1 100644 --- a/lib/ruby_vm/mjit/insn_compiler.rb +++ b/lib/ruby_vm/mjit/insn_compiler.rb @@ -6,7 +6,7 @@ module RubyVM::MJIT @ocb = ocb @exit_compiler = exit_compiler @invariants = Invariants.new(ocb, exit_compiler) - freeze + # freeze # workaround a binding.irb issue. TODO: resurrect this end # @param jit [RubyVM::MJIT::JITState] @@ -17,7 +17,7 @@ module RubyVM::MJIT asm.incr_counter(:mjit_insns_count) asm.comment("Insn: #{insn.name}") - # 10/101 + # 11/101 case insn.name # nop # getlocal @@ -70,7 +70,7 @@ module RubyVM::MJIT # definemethod # definesmethod # send - # opt_send_without_block + when :opt_send_without_block then opt_send_without_block(jit, ctx, asm) # objtostring # opt_str_freeze # opt_nil_p @@ -217,7 +217,16 @@ module RubyVM::MJIT # definemethod # definesmethod # send - # opt_send_without_block + + # @param jit [RubyVM::MJIT::JITState] + # @param ctx [RubyVM::MJIT::Context] + # @param asm [RubyVM::MJIT::Assembler] + # @param cd `RubyVM::MJIT::CPointer::Struct_rb_call_data` + def opt_send_without_block(jit, ctx, asm) + cd = C.rb_call_data.new(jit.operand(0)) + compile_send_general(jit, ctx, asm, cd) + end + # objtostring # opt_str_freeze # opt_nil_p @@ -233,24 +242,23 @@ module RubyVM::MJIT def leave(jit, ctx, asm) assert_eq!(ctx.stack_size, 1) - asm.comment('RUBY_VM_CHECK_INTS(ec)') - asm.mov(:eax, [EC, C.rb_execution_context_t.offsetof(:interrupt_flag)]) - asm.test(:eax, :eax) - asm.jnz(side_exit(jit, ctx)) + compile_check_ints(jit, ctx, asm) asm.comment('pop stack frame') - asm.add(CFP, C.rb_control_frame_t.size) # cfp = cfp + 1 - asm.mov([EC, C.rb_execution_context_t.offsetof(:cfp)], CFP) # ec->cfp = cfp + asm.lea(:rax, [CFP, C.rb_control_frame_t.size]) + asm.mov(CFP, :rax) + asm.mov([EC, C.rb_execution_context_t.offsetof(:cfp)], :rax) - # Return a value + # Return a value (for compile_leave_exit) asm.mov(:rax, [SP]) - # Restore callee-saved registers - asm.pop(SP) - asm.pop(EC) - asm.pop(CFP) + # Set caller's SP and push a value to its stack (for JIT) + asm.mov(SP, [CFP, C.rb_control_frame_t.offsetof(:sp)]) + asm.mov([SP], :rax) + + # Jump to cfp->jit_return + asm.jmp([CFP, -C.rb_control_frame_t.size + C.rb_control_frame_t.offsetof(:jit_return)]) - asm.ret EndBlock end @@ -471,6 +479,161 @@ module RubyVM::MJIT # Helpers # + # @param jit [RubyVM::MJIT::JITState] + # @param ctx [RubyVM::MJIT::Context] + # @param asm [RubyVM::MJIT::Assembler] + def compile_check_ints(jit, ctx, asm) + asm.comment('RUBY_VM_CHECK_INTS(ec)') + asm.mov(:eax, [EC, C.rb_execution_context_t.offsetof(:interrupt_flag)]) + asm.test(:eax, :eax) + asm.jnz(side_exit(jit, ctx)) + end + + # @param jit [RubyVM::MJIT::JITState] + # @param ctx [RubyVM::MJIT::Context] + # @param asm [RubyVM::MJIT::Assembler] + # @param cd `RubyVM::MJIT::CPointer::Struct_rb_call_data` + def compile_send_general(jit, ctx, asm, cd) + ci = cd.ci + argc = C.vm_ci_argc(ci) + mid = C.vm_ci_mid(ci) + flags = C.vm_ci_flag(ci) + + if flags & C.VM_CALL_KW_SPLAT != 0 + return CantCompile + end + + unless jit.at_current_insn? + defer_compilation(jit, ctx, asm) + return EndBlock + end + + raise 'sp_offset != stack_size' if ctx.sp_offset != ctx.stack_size # TODO: handle this + recv_depth = argc + ((flags & C.VM_CALL_ARGS_BLOCKARG == 0) ? 0 : 1) + recv_index = ctx.stack_size - 1 - recv_depth + + comptime_recv = jit.peek_at_stack(recv_depth) + comptime_recv_klass = C.rb_class_of(comptime_recv) + + # Guard known class + if comptime_recv_klass.singleton_class? + asm.comment('guard known object with singleton class') + asm.mov(:rax, C.to_value(comptime_recv)) + asm.cmp([SP, C.VALUE.size * recv_index], :rax) + asm.jne(side_exit(jit, ctx)) + else + return CantCompile + end + + # Do method lookup + cme = C.rb_callable_method_entry(comptime_recv_klass, mid) + if cme.nil? + return CantCompile + end + + case C.METHOD_ENTRY_VISI(cme) + when C.METHOD_VISI_PUBLIC + # You can always call public methods + when C.METHOD_VISI_PRIVATE + if flags & C.VM_CALL_FCALL == 0 + # VM_CALL_FCALL: Callsites without a receiver of an explicit `self` receiver + return CantCompile + end + when C.METHOD_VISI_PROTECTED + return CantCompile # TODO: support this + else + raise 'cmes should always have a visibility' + end + + # TODO: assume_method_lookup_stable + + if flags & C.VM_CALL_ARGS_SPLAT != 0 && cme.def.type != C.VM_METHOD_TYPE_ISEQ + return CantCompile + end + + case cme.def.type + when C.VM_METHOD_TYPE_ISEQ + iseq = def_iseq_ptr(cme.def) + frame_type = C.VM_FRAME_MAGIC_METHOD | C.VM_ENV_FLAG_LOCAL + compile_send_iseq(jit, ctx, asm, iseq, ci, frame_type, cme, flags, argc) + else + return CantCompile + end + end + + def compile_send_iseq(jit, ctx, asm, iseq, ci, frame_type, cme, flags, argc) + # TODO: check a bunch of CantCompile cases + + compile_check_ints(jit, ctx, asm) + + # TODO: stack overflow check + + # TODO: more flag checks + + # Pop arguments and a receiver for the current caller frame + raise 'sp_offset != stack_size' if ctx.sp_offset != ctx.stack_size # TODO: handle this + sp_index = ctx.stack_size - argc - 1 # arguments and receiver + asm.comment('save SP to caller CFP') + asm.lea(:rax, [SP, sp_index]) + asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], :rax) + # TODO: do something about ctx.sp_index + + asm.comment('save PC to CFP') + next_pc = jit.pc + jit.insn.len * C.VALUE.size + asm.mov(:rax, next_pc) + asm.mov([CFP, C.rb_control_frame_t.offsetof(:pc)], :rax) # cfp->pc = rax + + # TODO: push cme, specval, frame type + # TODO: push callee control frame + + asm.comment('switch to new CFP') + asm.lea(:rax, [CFP, -C.rb_control_frame_t.size]) + asm.mov(CFP, :rax); + asm.mov([EC, C.rb_execution_context_t.offsetof(:cfp)], :rax) + + asm.comment('save SP to callee CFP') + num_locals = 0 # TODO + sp_offset = C.VALUE.size * (3 + num_locals + ctx.stack_size) + asm.add(SP, sp_offset) + asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], SP) + + asm.comment('save ISEQ to callee CFP') + asm.mov(:rax, iseq.to_i) + asm.mov([CFP, C.rb_control_frame_t.offsetof(:iseq)], :rax) + + asm.comment('save EP to callee CFP') + asm.lea(:rax, [SP, -C.VALUE.size]) + asm.mov([CFP, C.rb_control_frame_t.offsetof(:ep)], :rax) + + asm.comment('set frame type') + asm.mov([SP, C.VALUE.size * -1], C.VM_FRAME_MAGIC_METHOD | C.VM_ENV_FLAG_LOCAL) + + asm.comment('set specval') + asm.mov([SP, C.VALUE.size * -2], C.VM_BLOCK_HANDLER_NONE) + + # Stub the return destination from the callee + # TODO: set up return ctx correctly + jit_return_stub = BlockStub.new(iseq: jit.iseq, pc: next_pc, ctx: ctx.dup) + jit_return = Assembler.new.then do |ocb_asm| + @exit_compiler.compile_block_stub(ctx, ocb_asm, jit_return_stub) + @ocb.write(ocb_asm) + end + + jit_return_stub.change_block = proc do |jump_asm, new_addr| + jump_asm.comment('update cfp->jit_return') + jump_asm.stub(jit_return_stub) do + jump_asm.mov(:rax, new_addr) + jump_asm.mov([CFP, C.rb_control_frame_t.offsetof(:jit_return)], :rax) + end + end + jit_return_stub.change_block.call(asm, jit_return) + + callee_ctx = Context.new + compile_block_stub(iseq, iseq.body.iseq_encoded.to_i, callee_ctx, asm) + + EndBlock + end + def assert_eq!(left, right) if left != right raise "'#{left.inspect}' was not '#{right.inspect}'" @@ -487,21 +650,24 @@ module RubyVM::MJIT # @param asm [RubyVM::MJIT::Assembler] def defer_compilation(jit, ctx, asm) # Make a stub to compile the current insn - block_stub = BlockStub.new( - iseq: jit.iseq, - ctx: ctx.dup, - pc: jit.pc, - ) + compile_block_stub(jit.iseq, jit.pc, ctx, asm, comment: 'defer_compilation: block stub') + end + + def compile_block_stub(iseq, pc, ctx, asm, comment: 'block stub') + block_stub = BlockStub.new(iseq:, pc:, ctx: ctx.dup) stub_hit = Assembler.new.then do |ocb_asm| - @exit_compiler.compile_block_stub(jit, ctx, ocb_asm, block_stub) + @exit_compiler.compile_block_stub(ctx, ocb_asm, block_stub) @ocb.write(ocb_asm) end - asm.comment('defer_compilation: block stub') - asm.stub(block_stub) do - asm.jmp(stub_hit) + block_stub.change_block = proc do |jump_asm, new_addr| + jump_asm.comment(comment) + jump_asm.stub(block_stub) do + jump_asm.jmp(new_addr) + end end + block_stub.change_block.call(asm, stub_hit) end # @param jit [RubyVM::MJIT::JITState] @@ -514,5 +680,9 @@ module RubyVM::MJIT @exit_compiler.compile_side_exit(jit, ctx, asm) jit.side_exits[jit.pc] = @ocb.write(asm) end + + def def_iseq_ptr(cme_def) + C.rb_iseq_check(cme_def.body.iseq.iseqptr) + end end end diff --git a/lib/ruby_vm/mjit/jit_state.rb b/lib/ruby_vm/mjit/jit_state.rb index ff48c2c107..1f888a02ae 100644 --- a/lib/ruby_vm/mjit/jit_state.rb +++ b/lib/ruby_vm/mjit/jit_state.rb @@ -20,9 +20,9 @@ module RubyVM::MJIT pc == cfp.pc.to_i end - def peek_at_stack(offset_from_top) + def peek_at_stack(depth_from_top) raise 'not at current insn' unless at_current_insn? - offset = -(1 + offset_from_top) + offset = -(1 + depth_from_top) value = (cfp.sp + offset).* C.to_ruby(value) end diff --git a/mjit_c.rb b/mjit_c.rb index 5d4a97c693..0282abbbda 100644 --- a/mjit_c.rb +++ b/mjit_c.rb @@ -81,6 +81,21 @@ module RubyVM::MJIT # :nodoc: all Primitive.cexpr! 'UINT2NUM(rb_iseq_line_no((const rb_iseq_t *)NUM2SIZET(_iseq_addr), NUM2SIZET(pos)))' end + def rb_class_of(obj) + Primitive.cexpr! 'rb_class_of(obj)' + end + + def rb_callable_method_entry(klass, mid) + cme_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_callable_method_entry(klass, NUM2UINT(mid)))' + return nil if cme_addr == 0 + rb_callable_method_entry_struct.new(cme_addr) + end + + def METHOD_ENTRY_VISI(cme) + _cme_addr = cme.to_i + Primitive.cexpr! 'UINT2NUM(METHOD_ENTRY_VISI((const rb_callable_method_entry_t *)NUM2SIZET(_cme_addr)))' + end + #======================================================================================== # # Old stuff @@ -142,6 +157,11 @@ module RubyVM::MJIT # :nodoc: all Primitive.cexpr! 'UINT2NUM(vm_ci_flag((CALL_INFO)NUM2PTR(_ci_addr)))' end + def vm_ci_mid(ci) + _ci_addr = ci.to_i + Primitive.cexpr! 'UINT2NUM(vm_ci_mid((CALL_INFO)NUM2PTR(_ci_addr)))' + end + def rb_splat_or_kwargs_p(ci) _ci_addr = ci.to_i Primitive.cstmt! %{ @@ -233,30 +253,6 @@ module RubyVM::MJIT # :nodoc: all Primitive.cexpr! %q{ INT2NUM(NOT_COMPILED_STACK_SIZE) } end - def C.VM_CALL_KW_SPLAT - Primitive.cexpr! %q{ INT2NUM(VM_CALL_KW_SPLAT) } - end - - def C.VM_CALL_KW_SPLAT_bit - Primitive.cexpr! %q{ INT2NUM(VM_CALL_KW_SPLAT_bit) } - end - - def C.VM_CALL_TAILCALL - Primitive.cexpr! %q{ INT2NUM(VM_CALL_TAILCALL) } - end - - def C.VM_CALL_TAILCALL_bit - Primitive.cexpr! %q{ INT2NUM(VM_CALL_TAILCALL_bit) } - end - - def C.VM_METHOD_TYPE_CFUNC - Primitive.cexpr! %q{ INT2NUM(VM_METHOD_TYPE_CFUNC) } - end - - def C.VM_METHOD_TYPE_ISEQ - Primitive.cexpr! %q{ INT2NUM(VM_METHOD_TYPE_ISEQ) } - end - def C.BOP_LT Primitive.cexpr! %q{ UINT2NUM(BOP_LT) } end @@ -269,6 +265,18 @@ module RubyVM::MJIT # :nodoc: all Primitive.cexpr! %q{ UINT2NUM(INTEGER_REDEFINED_OP_FLAG) } end + def C.METHOD_VISI_PRIVATE + Primitive.cexpr! %q{ UINT2NUM(METHOD_VISI_PRIVATE) } + end + + def C.METHOD_VISI_PROTECTED + Primitive.cexpr! %q{ UINT2NUM(METHOD_VISI_PROTECTED) } + end + + def C.METHOD_VISI_PUBLIC + Primitive.cexpr! %q{ UINT2NUM(METHOD_VISI_PUBLIC) } + end + def C.RUBY_EVENT_CLASS Primitive.cexpr! %q{ UINT2NUM(RUBY_EVENT_CLASS) } end @@ -301,6 +309,54 @@ module RubyVM::MJIT # :nodoc: all Primitive.cexpr! %q{ UINT2NUM(SHAPE_ROOT) } end + def C.VM_BLOCK_HANDLER_NONE + Primitive.cexpr! %q{ UINT2NUM(VM_BLOCK_HANDLER_NONE) } + end + + def C.VM_CALL_ARGS_BLOCKARG + Primitive.cexpr! %q{ UINT2NUM(VM_CALL_ARGS_BLOCKARG) } + end + + def C.VM_CALL_ARGS_SPLAT + Primitive.cexpr! %q{ UINT2NUM(VM_CALL_ARGS_SPLAT) } + end + + def C.VM_CALL_FCALL + Primitive.cexpr! %q{ UINT2NUM(VM_CALL_FCALL) } + end + + def C.VM_CALL_KW_SPLAT + Primitive.cexpr! %q{ UINT2NUM(VM_CALL_KW_SPLAT) } + end + + def C.VM_CALL_KW_SPLAT_bit + Primitive.cexpr! %q{ UINT2NUM(VM_CALL_KW_SPLAT_bit) } + end + + def C.VM_CALL_TAILCALL + Primitive.cexpr! %q{ UINT2NUM(VM_CALL_TAILCALL) } + end + + def C.VM_CALL_TAILCALL_bit + Primitive.cexpr! %q{ UINT2NUM(VM_CALL_TAILCALL_bit) } + end + + def C.VM_ENV_FLAG_LOCAL + Primitive.cexpr! %q{ UINT2NUM(VM_ENV_FLAG_LOCAL) } + end + + def C.VM_FRAME_MAGIC_METHOD + Primitive.cexpr! %q{ UINT2NUM(VM_FRAME_MAGIC_METHOD) } + end + + def C.VM_METHOD_TYPE_CFUNC + Primitive.cexpr! %q{ UINT2NUM(VM_METHOD_TYPE_CFUNC) } + end + + def C.VM_METHOD_TYPE_ISEQ + Primitive.cexpr! %q{ UINT2NUM(VM_METHOD_TYPE_ISEQ) } + end + def C.INVALID_SHAPE_ID Primitive.cexpr! %q{ ULONG2NUM(INVALID_SHAPE_ID) } end diff --git a/tool/mjit/bindgen.rb b/tool/mjit/bindgen.rb index 0705bae31d..4e1a29cb89 100755 --- a/tool/mjit/bindgen.rb +++ b/tool/mjit/bindgen.rb @@ -345,17 +345,14 @@ generator = BindingGenerator.new( values: { INT: %w[ NOT_COMPILED_STACK_SIZE - VM_CALL_KW_SPLAT - VM_CALL_KW_SPLAT_bit - VM_CALL_TAILCALL - VM_CALL_TAILCALL_bit - VM_METHOD_TYPE_CFUNC - VM_METHOD_TYPE_ISEQ ], UINT: %w[ BOP_LT BOP_MINUS INTEGER_REDEFINED_OP_FLAG + METHOD_VISI_PRIVATE + METHOD_VISI_PROTECTED + METHOD_VISI_PUBLIC RUBY_EVENT_CLASS SHAPE_CAPACITY_CHANGE SHAPE_FLAG_SHIFT @@ -364,6 +361,18 @@ generator = BindingGenerator.new( SHAPE_INITIAL_CAPACITY SHAPE_IVAR SHAPE_ROOT + VM_BLOCK_HANDLER_NONE + VM_CALL_ARGS_BLOCKARG + VM_CALL_ARGS_SPLAT + VM_CALL_FCALL + VM_CALL_KW_SPLAT + VM_CALL_KW_SPLAT_bit + VM_CALL_TAILCALL + VM_CALL_TAILCALL_bit + VM_ENV_FLAG_LOCAL + VM_FRAME_MAGIC_METHOD + VM_METHOD_TYPE_CFUNC + VM_METHOD_TYPE_ISEQ ], ULONG: %w[ INVALID_SHAPE_ID