mirror of
https://github.com/ruby/ruby.git
synced 2025-08-25 05:55:46 +02:00
Optimize BasicObject#!
This commit is contained in:
parent
e8a36eb4f6
commit
db4a8afa5e
Notes:
git
2023-03-06 07:29:46 +00:00
3 changed files with 73 additions and 0 deletions
|
@ -11,6 +11,8 @@ module RubyVM::MJIT
|
||||||
@ocb.write(asm)
|
@ocb.write(asm)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@cfunc_codegen_table = {}
|
||||||
|
register_cfunc_codegen_funcs
|
||||||
# freeze # workaround a binding.irb issue. TODO: resurrect this
|
# freeze # workaround a binding.irb issue. TODO: resurrect this
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1675,10 +1677,49 @@ module RubyVM::MJIT
|
||||||
putobject(jit, ctx, asm, val: C.to_value(1))
|
putobject(jit, ctx, asm, val: C.to_value(1))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# C func
|
||||||
|
#
|
||||||
|
|
||||||
|
# @param jit [RubyVM::MJIT::JITState]
|
||||||
|
# @param ctx [RubyVM::MJIT::Context]
|
||||||
|
# @param asm [RubyVM::MJIT::Assembler]
|
||||||
|
def jit_rb_obj_not(jit, ctx, asm)
|
||||||
|
recv = ctx.stack_pop
|
||||||
|
# This `test` sets ZF only for Qnil and Qfalse, which let cmovz set.
|
||||||
|
asm.test(recv, ~Qnil)
|
||||||
|
asm.mov(:rax, Qfalse)
|
||||||
|
asm.mov(:rcx, Qtrue)
|
||||||
|
asm.cmovz(:rax, :rcx)
|
||||||
|
asm.mov(ctx.stack_push, :rax)
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Helpers
|
# Helpers
|
||||||
#
|
#
|
||||||
|
|
||||||
|
def register_cfunc_codegen_funcs
|
||||||
|
register_cfunc_method(BasicObject, '!', :jit_rb_obj_not)
|
||||||
|
end
|
||||||
|
|
||||||
|
def register_cfunc_method(klass, mid_str, func)
|
||||||
|
mid = C.rb_intern(mid_str)
|
||||||
|
me = C.rb_method_entry_at(klass, mid)
|
||||||
|
|
||||||
|
assert_equal(false, me.nil?)
|
||||||
|
|
||||||
|
# Only cfuncs are supported
|
||||||
|
method_serial = me.def.method_serial
|
||||||
|
|
||||||
|
@cfunc_codegen_table[method_serial] = method(func)
|
||||||
|
end
|
||||||
|
|
||||||
|
def lookup_cfunc_codegen(cme_def)
|
||||||
|
@cfunc_codegen_table[cme_def.method_serial]
|
||||||
|
end
|
||||||
|
|
||||||
def jit_getlocal_generic(jit, ctx, asm, idx:, level:)
|
def jit_getlocal_generic(jit, ctx, asm, idx:, level:)
|
||||||
# Load environment pointer EP at level
|
# Load environment pointer EP at level
|
||||||
ep_reg = :rax
|
ep_reg = :rax
|
||||||
|
@ -2545,6 +2586,17 @@ module RubyVM::MJIT
|
||||||
return CantCompile
|
return CantCompile
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Delegate to codegen for C methods if we have it.
|
||||||
|
if flags & C.VM_CALL_KWARG == 0 && flags & C.VM_CALL_OPT_SEND == 0
|
||||||
|
known_cfunc_codegen = lookup_cfunc_codegen(cme.def)
|
||||||
|
if known_cfunc_codegen&.call(jit, ctx, asm)
|
||||||
|
# cfunc codegen generated code. Terminate the block so
|
||||||
|
# there isn't multiple calls in the same block.
|
||||||
|
jump_to_next_insn(jit, ctx, asm)
|
||||||
|
return EndBlock
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# We will not have side exits from here. Adjust the stack.
|
# We will not have side exits from here. Adjust the stack.
|
||||||
if flags & C.VM_CALL_OPT_SEND != 0
|
if flags & C.VM_CALL_OPT_SEND != 0
|
||||||
jit_call_opt_send_shift_stack(ctx, asm, argc, send_shift:)
|
jit_call_opt_send_shift_stack(ctx, asm, argc, send_shift:)
|
||||||
|
|
20
mjit_c.rb
20
mjit_c.rb
|
@ -269,6 +269,15 @@ module RubyVM::MJIT # :nodoc: all
|
||||||
Primitive.cexpr! 'rb_obj_frozen_p(obj)'
|
Primitive.cexpr! 'rb_obj_frozen_p(obj)'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def rb_intern(str)
|
||||||
|
Primitive.cexpr! 'SIZET2NUM((size_t)rb_intern(RSTRING_PTR(str)))'
|
||||||
|
end
|
||||||
|
|
||||||
|
def rb_method_entry_at(klass, mid)
|
||||||
|
me_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_method_entry_at(klass, (ID)NUM2SIZET(mid)))'
|
||||||
|
me_addr == 0 ? nil : rb_method_entry_t.new(me_addr)
|
||||||
|
end
|
||||||
|
|
||||||
#========================================================================================
|
#========================================================================================
|
||||||
#
|
#
|
||||||
# Old stuff
|
# Old stuff
|
||||||
|
@ -1235,6 +1244,17 @@ module RubyVM::MJIT # :nodoc: all
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def C.rb_method_entry_t
|
||||||
|
@rb_method_entry_t ||= CType::Struct.new(
|
||||||
|
"rb_method_entry_struct", Primitive.cexpr!("SIZEOF(struct rb_method_entry_struct)"),
|
||||||
|
flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_method_entry_struct *)NULL)), flags)")],
|
||||||
|
defined_class: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_method_entry_struct *)NULL)), defined_class)")],
|
||||||
|
def: [CType::Pointer.new { self.rb_method_definition_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_method_entry_struct *)NULL)), def)")],
|
||||||
|
called_id: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_method_entry_struct *)NULL)), called_id)")],
|
||||||
|
owner: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_method_entry_struct *)NULL)), owner)")],
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def C.rb_method_iseq_t
|
def C.rb_method_iseq_t
|
||||||
@rb_method_iseq_t ||= CType::Struct.new(
|
@rb_method_iseq_t ||= CType::Struct.new(
|
||||||
"rb_method_iseq_struct", Primitive.cexpr!("SIZEOF(struct rb_method_iseq_struct)"),
|
"rb_method_iseq_struct", Primitive.cexpr!("SIZEOF(struct rb_method_iseq_struct)"),
|
||||||
|
|
|
@ -471,6 +471,7 @@ generator = BindingGenerator.new(
|
||||||
rb_call_data
|
rb_call_data
|
||||||
rb_callable_method_entry_struct
|
rb_callable_method_entry_struct
|
||||||
rb_callable_method_entry_t
|
rb_callable_method_entry_t
|
||||||
|
rb_method_entry_t
|
||||||
rb_callcache
|
rb_callcache
|
||||||
rb_callinfo
|
rb_callinfo
|
||||||
rb_control_frame_t
|
rb_control_frame_t
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue