diff --git a/mjit_compiler.rb b/mjit_compiler.rb index 4996e773dc..0a558f67e4 100644 --- a/mjit_compiler.rb +++ b/mjit_compiler.rb @@ -14,124 +14,6 @@ if RubyVM::MJIT.enabled? require 'mjit/c_32' end - class << RubyVM::MJIT::C - def ROBJECT_EMBED_LEN_MAX - Primitive.cexpr! 'INT2NUM(RBIMPL_EMBED_LEN_MAX_OF(VALUE))' - end - - def cdhash_to_hash(cdhash_addr) - Primitive.cdhash_to_hash(cdhash_addr) - end - - def builtin_compiler(f, bf, index, stack_size, builtin_inline_p) - Primitive.builtin_compile(f, bf.to_i, index, stack_size, builtin_inline_p) - end - - def has_cache_for_send(cc, insn) - Primitive.has_cache_for_send(cc.to_i, insn) - end - - def rb_iseq_check(iseq) - _iseq_addr = iseq.to_i - iseq_addr = Primitive.cexpr! 'PTR2NUM((VALUE)rb_iseq_check((rb_iseq_t *)NUM2PTR(_iseq_addr)))' - rb_iseq_t.new(iseq_addr) - end - - def rb_iseq_path(iseq) - _iseq_addr = iseq.to_i - Primitive.cexpr! 'rb_iseq_path((rb_iseq_t *)NUM2PTR(_iseq_addr))' - end - - def vm_ci_argc(ci) - _ci_addr = ci.to_i - Primitive.cexpr! 'UINT2NUM(vm_ci_argc((CALL_INFO)NUM2PTR(_ci_addr)))' - end - - def vm_ci_flag(ci) - _ci_addr = ci.to_i - Primitive.cexpr! 'UINT2NUM(vm_ci_flag((CALL_INFO)NUM2PTR(_ci_addr)))' - end - - def rb_splat_or_kwargs_p(ci) - _ci_addr = ci.to_i - Primitive.cexpr! 'RBOOL(rb_splat_or_kwargs_p((CALL_INFO)NUM2PTR(_ci_addr)))' - end - - def fastpath_applied_iseq_p(ci, cc, iseq) - _ci_addr = ci.to_i - _cc_addr = cc.to_i - _iseq_addr = iseq.to_i - Primitive.cexpr! 'RBOOL(fastpath_applied_iseq_p((CALL_INFO)NUM2PTR(_ci_addr), (CALL_CACHE)NUM2PTR(_cc_addr), (rb_iseq_t *)NUM2PTR(_iseq_addr)))' - end - - def mjit_opts - addr = Primitive.cexpr! 'PTR2NUM((VALUE)&mjit_opts)' - mjit_options.new(addr) - end - - def mjit_call_attribute_sp_inc(insn, operands) - _operands_addr = operands.to_i - Primitive.cexpr! 'LONG2NUM(mjit_call_attribute_sp_inc(NUM2INT(insn), (VALUE *)NUM2PTR(_operands_addr)))' - end - - def mjit_capture_cc_entries(compiled_body, captured_body) - _compiled_body_addr = compiled_body.to_i - _captured_body_addr = captured_body.to_i - Primitive.cexpr! 'INT2NUM(mjit_capture_cc_entries((struct rb_iseq_constant_body *)NUM2PTR(_compiled_body_addr), (struct rb_iseq_constant_body *)NUM2PTR(_captured_body_addr)))' - end - - #const struct rb_iseq_constant_body *body, union iseq_inline_storage_entry *is_entries - def mjit_capture_is_entries(body, is_entries) - _body_addr = body.to_i - _is_entries_addr = is_entries.to_i - Primitive.cstmt! %{ - mjit_capture_is_entries((struct rb_iseq_constant_body *)NUM2PTR(_body_addr), (union iseq_inline_storage_entry *)NUM2PTR(_is_entries_addr)); - return Qnil; - } - end - - # Convert encoded VM pointers to insn BINs. - def rb_vm_insn_decode(encoded) - Primitive.cexpr! 'INT2NUM(rb_vm_insn_decode(NUM2PTR(encoded)))' - end - - # Convert insn BINs to encoded VM pointers. This one is not used by the compiler, but useful for debugging. - def rb_vm_insn_encode(bin) - Primitive.cexpr! 'PTR2NUM((VALUE)rb_vm_get_insns_address_table()[NUM2INT(bin)])' - end - - def insn_may_depend_on_sp_or_pc(insn, opes) - _opes_addr = opes.to_i - Primitive.cexpr! 'RBOOL(insn_may_depend_on_sp_or_pc(NUM2INT(insn), (VALUE *)NUM2PTR(_opes_addr)))' - end - - # Convert Integer VALUE to an actual Ruby object - def to_ruby(value) - Primitive.cexpr! '(VALUE)NUM2PTR(value)' - end - - # Convert RubyVM::InstructionSequence to C.rb_iseq_t. Not used by the compiler, but useful for debugging. - def rb_iseqw_to_iseq(iseqw) - iseq_addr = Primitive.cexpr! 'PTR2NUM((VALUE)rb_iseqw_to_iseq(iseqw))' - rb_iseq_t.new(iseq_addr) - end - - # TODO: remove this after migration - def fprintf(f, str) - Primitive.cstmt! %{ - fprintf((FILE *)NUM2PTR(f), "%s", RSTRING_PTR(str)); - return Qnil; - } - end - - def rb_cFalseClass; Primitive.cexpr! 'PTR2NUM(rb_cFalseClass)' end - def rb_cNilClass; Primitive.cexpr! 'PTR2NUM(rb_cNilClass)' end - def rb_cTrueClass; Primitive.cexpr! 'PTR2NUM(rb_cTrueClass)' end - def rb_cInteger; Primitive.cexpr! 'PTR2NUM(rb_cInteger)' end - def rb_cSymbol; Primitive.cexpr! 'PTR2NUM(rb_cSymbol)' end - def rb_cFloat; Primitive.cexpr! 'PTR2NUM(rb_cFloat)' end - end - require "mjit/instruction" require "mjit/compiler" end diff --git a/tool/mjit/bindgen.rb b/tool/mjit/bindgen.rb index 32a487d4bb..8fa20fe64c 100755 --- a/tool/mjit/bindgen.rb +++ b/tool/mjit/bindgen.rb @@ -100,16 +100,20 @@ end # Convert Node objects to a Ruby binding source. class BindingGenerator + BINDGEN_BEG = '### MJIT bindgen begin ###' + BINDGEN_END = '### MJIT bindgen end ###' DEFAULTS = { '_Bool' => 'CType::Bool.new' } DEFAULTS.default_proc = proc { |_h, k| "CType::Stub.new(:#{k})" } attr_reader :src + # @param src_path [String] Source path used for preamble/postamble # @param macros [Array] Imported macros # @param enums [Hash{ Symbol => Array }] Imported enum values # @param types [Array] Imported types # @param ruby_fields [Hash{ Symbol => Array }] Struct VALUE fields that are considered Ruby objects - def initialize(macros:, enums:, types:, ruby_fields:) + def initialize(src_path:, macros:, enums:, types:, ruby_fields:) + @preamble, @postamble = split_ambles(src_path) @src = String.new @macros = macros.sort @enums = enums.transform_keys(&:to_s).transform_values(&:sort).sort.to_h @@ -119,9 +123,7 @@ class BindingGenerator end def generate(_nodes) - println "module RubyVM::MJIT" - println " C = Object.new" - println + println @preamble # Define macros @macros.each do |macro| @@ -129,8 +131,7 @@ class BindingGenerator println end - chomp - println "end if RubyVM::MJIT.enabled?" + print @postamble end # TODO: Remove this @@ -176,6 +177,20 @@ class BindingGenerator private + # Return code before BINDGEN_BEG and code after BINDGEN_END + def split_ambles(src_path) + lines = File.read(src_path).lines + + preamble_end = lines.index { |l| l.include?(BINDGEN_BEG) } + raise "`#{BINDGEN_BEG}` was not found in '#{src_path}'" if preamble_end.nil? + + postamble_beg = lines.index { |l| l.include?(BINDGEN_END) } + raise "`#{BINDGEN_END}` was not found in '#{src_path}'" if postamble_beg.nil? + raise "`#{BINDGEN_BEG}` was found after `#{BINDGEN_END}`" if preamble_end >= postamble_beg + + return lines[0..preamble_end].join, lines[postamble_beg..-1].join + end + def generate_macro(macro) if macro.start_with?('USE_') "Primitive.cexpr! %q{ RBOOL(#{macro} != 0) }" @@ -293,6 +308,7 @@ class BindingGenerator end src_dir = File.expand_path('../..', __dir__) +src_path = File.join(src_dir, 'tool/ruby_vm/views/mjit_c.rb.erb') build_dir = File.expand_path(build_dir) cflags = [ src_dir, @@ -303,6 +319,7 @@ cflags = [ nodes = HeaderParser.new(File.join(src_dir, 'mjit_compiler.h'), cflags: cflags).parse generator = BindingGenerator.new( + src_path: src_path, macros: %w[ NOT_COMPILED_STACK_SIZE USE_LAZY_LOAD @@ -366,4 +383,4 @@ generator = BindingGenerator.new( ) generator.generate(nodes) -File.write(File.join(src_dir, 'tool/ruby_vm/views/mjit_c.rb.erb'), generator.src) +File.write(src_path, generator.src) diff --git a/tool/ruby_vm/views/mjit_c.rb.erb b/tool/ruby_vm/views/mjit_c.rb.erb index 416f8bfeaf..5def975dcc 100644 --- a/tool/ruby_vm/views/mjit_c.rb.erb +++ b/tool/ruby_vm/views/mjit_c.rb.erb @@ -1,6 +1,128 @@ +# Part of this file is generated by tool/mjit/bindgen.rb. +# Run `make mjit-bindgen` to update code between "MJIT bindgen begin" and "MJIT bindgen end". module RubyVM::MJIT C = Object.new + class << C + def ROBJECT_EMBED_LEN_MAX + Primitive.cexpr! 'INT2NUM(RBIMPL_EMBED_LEN_MAX_OF(VALUE))' + end + + def cdhash_to_hash(cdhash_addr) + Primitive.cdhash_to_hash(cdhash_addr) + end + + def builtin_compiler(f, bf, index, stack_size, builtin_inline_p) + Primitive.builtin_compile(f, bf.to_i, index, stack_size, builtin_inline_p) + end + + def has_cache_for_send(cc, insn) + Primitive.has_cache_for_send(cc.to_i, insn) + end + + def rb_iseq_check(iseq) + _iseq_addr = iseq.to_i + iseq_addr = Primitive.cexpr! 'PTR2NUM((VALUE)rb_iseq_check((rb_iseq_t *)NUM2PTR(_iseq_addr)))' + rb_iseq_t.new(iseq_addr) + end + + def rb_iseq_path(iseq) + _iseq_addr = iseq.to_i + Primitive.cexpr! 'rb_iseq_path((rb_iseq_t *)NUM2PTR(_iseq_addr))' + end + + def vm_ci_argc(ci) + _ci_addr = ci.to_i + Primitive.cexpr! 'UINT2NUM(vm_ci_argc((CALL_INFO)NUM2PTR(_ci_addr)))' + end + + def vm_ci_flag(ci) + _ci_addr = ci.to_i + Primitive.cexpr! 'UINT2NUM(vm_ci_flag((CALL_INFO)NUM2PTR(_ci_addr)))' + end + + def rb_splat_or_kwargs_p(ci) + _ci_addr = ci.to_i + Primitive.cexpr! 'RBOOL(rb_splat_or_kwargs_p((CALL_INFO)NUM2PTR(_ci_addr)))' + end + + def fastpath_applied_iseq_p(ci, cc, iseq) + _ci_addr = ci.to_i + _cc_addr = cc.to_i + _iseq_addr = iseq.to_i + Primitive.cexpr! 'RBOOL(fastpath_applied_iseq_p((CALL_INFO)NUM2PTR(_ci_addr), (CALL_CACHE)NUM2PTR(_cc_addr), (rb_iseq_t *)NUM2PTR(_iseq_addr)))' + end + + def mjit_opts + addr = Primitive.cexpr! 'PTR2NUM((VALUE)&mjit_opts)' + mjit_options.new(addr) + end + + def mjit_call_attribute_sp_inc(insn, operands) + _operands_addr = operands.to_i + Primitive.cexpr! 'LONG2NUM(mjit_call_attribute_sp_inc(NUM2INT(insn), (VALUE *)NUM2PTR(_operands_addr)))' + end + + def mjit_capture_cc_entries(compiled_body, captured_body) + _compiled_body_addr = compiled_body.to_i + _captured_body_addr = captured_body.to_i + Primitive.cexpr! 'INT2NUM(mjit_capture_cc_entries((struct rb_iseq_constant_body *)NUM2PTR(_compiled_body_addr), (struct rb_iseq_constant_body *)NUM2PTR(_captured_body_addr)))' + end + + #const struct rb_iseq_constant_body *body, union iseq_inline_storage_entry *is_entries + def mjit_capture_is_entries(body, is_entries) + _body_addr = body.to_i + _is_entries_addr = is_entries.to_i + Primitive.cstmt! %{ + mjit_capture_is_entries((struct rb_iseq_constant_body *)NUM2PTR(_body_addr), (union iseq_inline_storage_entry *)NUM2PTR(_is_entries_addr)); + return Qnil; + } + end + + # Convert encoded VM pointers to insn BINs. + def rb_vm_insn_decode(encoded) + Primitive.cexpr! 'INT2NUM(rb_vm_insn_decode(NUM2PTR(encoded)))' + end + + # Convert insn BINs to encoded VM pointers. This one is not used by the compiler, but useful for debugging. + def rb_vm_insn_encode(bin) + Primitive.cexpr! 'PTR2NUM((VALUE)rb_vm_get_insns_address_table()[NUM2INT(bin)])' + end + + def insn_may_depend_on_sp_or_pc(insn, opes) + _opes_addr = opes.to_i + Primitive.cexpr! 'RBOOL(insn_may_depend_on_sp_or_pc(NUM2INT(insn), (VALUE *)NUM2PTR(_opes_addr)))' + end + + # Convert Integer VALUE to an actual Ruby object + def to_ruby(value) + Primitive.cexpr! '(VALUE)NUM2PTR(value)' + end + + # Convert RubyVM::InstructionSequence to C.rb_iseq_t. Not used by the compiler, but useful for debugging. + def rb_iseqw_to_iseq(iseqw) + iseq_addr = Primitive.cexpr! 'PTR2NUM((VALUE)rb_iseqw_to_iseq(iseqw))' + rb_iseq_t.new(iseq_addr) + end + + # TODO: remove this after migration + def fprintf(f, str) + Primitive.cstmt! %{ + fprintf((FILE *)NUM2PTR(f), "%s", RSTRING_PTR(str)); + return Qnil; + } + end + + def rb_cFalseClass; Primitive.cexpr! 'PTR2NUM(rb_cFalseClass)' end + def rb_cNilClass; Primitive.cexpr! 'PTR2NUM(rb_cNilClass)' end + def rb_cTrueClass; Primitive.cexpr! 'PTR2NUM(rb_cTrueClass)' end + def rb_cInteger; Primitive.cexpr! 'PTR2NUM(rb_cInteger)' end + def rb_cSymbol; Primitive.cexpr! 'PTR2NUM(rb_cSymbol)' end + def rb_cFloat; Primitive.cexpr! 'PTR2NUM(rb_cFloat)' end + end + + ### MJIT bindgen begin ### + def C.NOT_COMPILED_STACK_SIZE = Primitive.cexpr! %q{ INT2NUM(NOT_COMPILED_STACK_SIZE) } def C.USE_LAZY_LOAD = Primitive.cexpr! %q{ RBOOL(USE_LAZY_LOAD != 0) } @@ -10,4 +132,6 @@ module RubyVM::MJIT def C.VM_CALL_KW_SPLAT = Primitive.cexpr! %q{ INT2NUM(VM_CALL_KW_SPLAT) } def C.VM_CALL_TAILCALL = Primitive.cexpr! %q{ INT2NUM(VM_CALL_TAILCALL) } + + ### MJIT bindgen end ### end if RubyVM::MJIT.enabled?