From ecae1cd74e2f60f07399df8bf2023967bd605abf Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Wed, 8 Feb 2023 14:36:55 -0800 Subject: [PATCH] Implement attr_reader --- lib/ruby_vm/mjit/insn_compiler.rb | 53 +++++++++++++++++++++++++++---- mjit_c.h | 7 +++- mjit_c.rb | 30 +++++++++++------ tool/mjit/bindgen.rb | 3 ++ 4 files changed, 76 insertions(+), 17 deletions(-) diff --git a/lib/ruby_vm/mjit/insn_compiler.rb b/lib/ruby_vm/mjit/insn_compiler.rb index 2606f84c6c..8553f644a6 100644 --- a/lib/ruby_vm/mjit/insn_compiler.rb +++ b/lib/ruby_vm/mjit/insn_compiler.rb @@ -859,7 +859,7 @@ module RubyVM::MJIT # @param jit [RubyVM::MJIT::JITState] # @param ctx [RubyVM::MJIT::Context] # @param asm [RubyVM::MJIT::Assembler] - def jit_getivar(jit, ctx, asm, comptime_obj, ivar_id) + def jit_getivar(jit, ctx, asm, comptime_obj, ivar_id, obj_opnd = nil) side_exit = side_exit(jit, ctx) starting_ctx = ctx.dup # copy for jit_chain_guard @@ -868,7 +868,11 @@ module RubyVM::MJIT asm.incr_counter(:getivar_special_const) return CantCompile end - asm.mov(:rax, [CFP, C.rb_control_frame_t.offsetof(:self)]) + if obj_opnd.nil? # getivar + asm.mov(:rax, [CFP, C.rb_control_frame_t.offsetof(:self)]) + else # attr_reader + asm.mov(:rax, obj_opnd) + end guard_object_is_heap(asm, :rax, counted_exit(side_exit, :getivar_not_heap)) case C.BUILTIN_TYPE(comptime_obj) @@ -891,7 +895,7 @@ module RubyVM::MJIT index = C.rb_shape_get_iv_index(shape_id, ivar_id) if index - # See ROBJECT_IVPTR + asm.comment('ROBJECT_IVPTR') if C.FL_TEST_RAW(comptime_obj, C.ROBJECT_EMBED) # Access embedded array asm.mov(:rax, [:rax, C.RObject.offsetof(:as, :ary) + (index * C.VALUE.size)]) @@ -906,6 +910,9 @@ module RubyVM::MJIT val_opnd = Qnil end + if obj_opnd + ctx.stack_pop # pop receiver for attr_reader + end stack_opnd = ctx.stack_push asm.mov(stack_opnd, val_opnd) @@ -981,14 +988,14 @@ module RubyVM::MJIT # Invalidate on redefinition (part of vm_search_method_fastpath) @invariants.assume_method_lookup_stable(jit, cme) - jit_call_method_each_type(jit, ctx, asm, ci, argc, flags, cme) + jit_call_method_each_type(jit, ctx, asm, ci, argc, flags, cme, comptime_recv, recv_opnd) end # vm_call_method_each_type # @param jit [RubyVM::MJIT::JITState] # @param ctx [RubyVM::MJIT::Context] # @param asm [RubyVM::MJIT::Assembler] - def jit_call_method_each_type(jit, ctx, asm, ci, argc, flags, cme) + def jit_call_method_each_type(jit, ctx, asm, ci, argc, flags, cme, comptime_recv, recv_opnd) case cme.def.type when C.VM_METHOD_TYPE_ISEQ jit_call_iseq_setup(jit, ctx, asm, ci, cme, flags, argc) @@ -1000,8 +1007,7 @@ module RubyVM::MJIT asm.incr_counter(:send_attrset) return CantCompile when C.VM_METHOD_TYPE_IVAR - asm.incr_counter(:send_ivar) - return CantCompile + jit_call_ivar(jit, ctx, asm, ci, cme, flags, argc, comptime_recv, recv_opnd) # when C.VM_METHOD_TYPE_MISSING when C.VM_METHOD_TYPE_BMETHOD asm.incr_counter(:send_bmethod) @@ -1046,6 +1052,9 @@ module RubyVM::MJIT end # vm_call_iseq_setup_normal (vm_call_iseq_setup_2 -> vm_call_iseq_setup_normal) + # @param jit [RubyVM::MJIT::JITState] + # @param ctx [RubyVM::MJIT::Context] + # @param asm [RubyVM::MJIT::Assembler] def jit_call_iseq_setup_normal(jit, ctx, asm, ci, cme, flags, argc, iseq) # Save caller SP and PC before pushing a callee frame for backtrace and side exits asm.comment('save SP to caller CFP') @@ -1062,6 +1071,36 @@ module RubyVM::MJIT jit_push_frame(jit, ctx, asm, ci, cme, flags, argc, iseq, frame_type, next_pc) end + # vm_call_ivar + # @param jit [RubyVM::MJIT::JITState] + # @param ctx [RubyVM::MJIT::Context] + # @param asm [RubyVM::MJIT::Assembler] + def jit_call_ivar(jit, ctx, asm, ci, cme, flags, argc, comptime_recv, recv_opnd) + if flags & C.VM_CALL_ARGS_SPLAT != 0 + asm.incr_counter(:send_ivar_splat) + return CantCompile + end + + if argc != 0 + asm.incr_counter(:send_ivar_arity) + return CantCompile + end + + if flags & C.VM_CALL_OPT_SEND != 0 + asm.incr_counter(:send_ivar_opt_send) + return CantCompile + end + + ivar_id = cme.def.body.attr.id + + if flags & C.VM_CALL_OPT_SEND != 0 + asm.incr_counter(:send_ivar_blockarg) + return CantCompile + end + + jit_getivar(jit, ctx, asm, comptime_recv, ivar_id, recv_opnd) + end + # vm_push_frame # # Frame structure: diff --git a/mjit_c.h b/mjit_c.h index 20f4c0bf90..659701d038 100644 --- a/mjit_c.h +++ b/mjit_c.h @@ -119,7 +119,6 @@ MJIT_RUNTIME_COUNTERS( send_tailcall, send_not_implemented_type, send_cfunc, - send_ivar, send_attrset, send_bmethod, send_alias, @@ -127,6 +126,12 @@ MJIT_RUNTIME_COUNTERS( send_zsuper, send_refined, + send_ivar, + send_ivar_splat, + send_ivar_arity, + send_ivar_opt_send, + send_ivar_blockarg, + send_guard_nil, send_guard_true, send_guard_false, diff --git a/mjit_c.rb b/mjit_c.rb index c5220561ee..21c2a0c840 100644 --- a/mjit_c.rb +++ b/mjit_c.rb @@ -395,6 +395,10 @@ module RubyVM::MJIT # :nodoc: all Primitive.cexpr! %q{ UINT2NUM(VM_CALL_KW_SPLAT_bit) } end + def C.VM_CALL_OPT_SEND + Primitive.cexpr! %q{ UINT2NUM(VM_CALL_OPT_SEND) } + end + def C.VM_CALL_TAILCALL Primitive.cexpr! %q{ UINT2NUM(VM_CALL_TAILCALL) } end @@ -499,6 +503,10 @@ module RubyVM::MJIT # :nodoc: all @IC ||= self.iseq_inline_constant_cache end + def C.ID + @ID ||= CType::Immediate.parse("unsigned long") + end + def C.IVC @IVC ||= self.iseq_inline_iv_cache_entry end @@ -856,6 +864,14 @@ module RubyVM::MJIT # :nodoc: all @rb_iseq_t ||= self.rb_iseq_struct end + def C.rb_method_attr_t + @rb_method_attr_t ||= CType::Struct.new( + "rb_method_attr_struct", Primitive.cexpr!("SIZEOF(struct rb_method_attr_struct)"), + id: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_method_attr_struct *)NULL)), id)")], + location: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_method_attr_struct *)NULL)), location)")], + ) + end + def C.rb_method_definition_struct @rb_method_definition_struct ||= CType::Struct.new( "rb_method_definition_struct", Primitive.cexpr!("SIZEOF(struct rb_method_definition_struct)"), @@ -917,13 +933,17 @@ module RubyVM::MJIT # :nodoc: all send_tailcall: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_tailcall)")], send_not_implemented_type: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_not_implemented_type)")], send_cfunc: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_cfunc)")], - send_ivar: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_ivar)")], send_attrset: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_attrset)")], send_bmethod: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_bmethod)")], send_alias: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_alias)")], send_optimized: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_optimized)")], send_zsuper: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_zsuper)")], send_refined: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_refined)")], + send_ivar: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_ivar)")], + send_ivar_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_ivar_splat)")], + send_ivar_arity: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_ivar_arity)")], + send_ivar_opt_send: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_ivar_opt_send)")], + send_ivar_blockarg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_ivar_blockarg)")], send_guard_nil: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_guard_nil)")], send_guard_true: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_guard_true)")], send_guard_false: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), send_guard_false)")], @@ -996,10 +1016,6 @@ module RubyVM::MJIT # :nodoc: all CType::Bool.new end - def C.ID - CType::Stub.new(:ID) - end - def C.rb_thread_struct CType::Stub.new(:rb_thread_struct) end @@ -1088,10 +1104,6 @@ module RubyVM::MJIT # :nodoc: all CType::Stub.new(:rb_method_cfunc_t) end - def C.rb_method_attr_t - CType::Stub.new(:rb_method_attr_t) - end - def C.rb_method_alias_t CType::Stub.new(:rb_method_alias_t) end diff --git a/tool/mjit/bindgen.rb b/tool/mjit/bindgen.rb index 2c4fef82d9..0d8cdee83f 100755 --- a/tool/mjit/bindgen.rb +++ b/tool/mjit/bindgen.rb @@ -376,6 +376,7 @@ generator = BindingGenerator.new( VM_CALL_KW_SPLAT_bit VM_CALL_TAILCALL VM_CALL_TAILCALL_bit + VM_CALL_OPT_SEND VM_ENV_FLAG_LOCAL VM_FRAME_MAGIC_METHOD VM_METHOD_TYPE_CFUNC @@ -407,6 +408,7 @@ generator = BindingGenerator.new( types: %w[ CALL_DATA IC + ID IVC RB_BUILTIN RBasic @@ -442,6 +444,7 @@ generator = BindingGenerator.new( rb_serial_t rb_shape rb_shape_t + rb_method_attr_t ], dynamic_types: %w[ VALUE