mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Mix manual and auto-generated C APIs
This commit is contained in:
parent
00c441ce7a
commit
334b8bd459
Notes:
git
2022-09-23 06:45:09 +09:00
3 changed files with 148 additions and 125 deletions
118
mjit_compiler.rb
118
mjit_compiler.rb
|
@ -14,124 +14,6 @@ if RubyVM::MJIT.enabled?
|
||||||
require 'mjit/c_32'
|
require 'mjit/c_32'
|
||||||
end
|
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/instruction"
|
||||||
require "mjit/compiler"
|
require "mjit/compiler"
|
||||||
end
|
end
|
||||||
|
|
|
@ -100,16 +100,20 @@ end
|
||||||
|
|
||||||
# Convert Node objects to a Ruby binding source.
|
# Convert Node objects to a Ruby binding source.
|
||||||
class BindingGenerator
|
class BindingGenerator
|
||||||
|
BINDGEN_BEG = '### MJIT bindgen begin ###'
|
||||||
|
BINDGEN_END = '### MJIT bindgen end ###'
|
||||||
DEFAULTS = { '_Bool' => 'CType::Bool.new' }
|
DEFAULTS = { '_Bool' => 'CType::Bool.new' }
|
||||||
DEFAULTS.default_proc = proc { |_h, k| "CType::Stub.new(:#{k})" }
|
DEFAULTS.default_proc = proc { |_h, k| "CType::Stub.new(:#{k})" }
|
||||||
|
|
||||||
attr_reader :src
|
attr_reader :src
|
||||||
|
|
||||||
|
# @param src_path [String] Source path used for preamble/postamble
|
||||||
# @param macros [Array<String>] Imported macros
|
# @param macros [Array<String>] Imported macros
|
||||||
# @param enums [Hash{ Symbol => Array<String> }] Imported enum values
|
# @param enums [Hash{ Symbol => Array<String> }] Imported enum values
|
||||||
# @param types [Array<String>] Imported types
|
# @param types [Array<String>] Imported types
|
||||||
# @param ruby_fields [Hash{ Symbol => Array<String> }] Struct VALUE fields that are considered Ruby objects
|
# @param ruby_fields [Hash{ Symbol => Array<String> }] 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
|
@src = String.new
|
||||||
@macros = macros.sort
|
@macros = macros.sort
|
||||||
@enums = enums.transform_keys(&:to_s).transform_values(&:sort).sort.to_h
|
@enums = enums.transform_keys(&:to_s).transform_values(&:sort).sort.to_h
|
||||||
|
@ -119,9 +123,7 @@ class BindingGenerator
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate(_nodes)
|
def generate(_nodes)
|
||||||
println "module RubyVM::MJIT"
|
println @preamble
|
||||||
println " C = Object.new"
|
|
||||||
println
|
|
||||||
|
|
||||||
# Define macros
|
# Define macros
|
||||||
@macros.each do |macro|
|
@macros.each do |macro|
|
||||||
|
@ -129,8 +131,7 @@ class BindingGenerator
|
||||||
println
|
println
|
||||||
end
|
end
|
||||||
|
|
||||||
chomp
|
print @postamble
|
||||||
println "end if RubyVM::MJIT.enabled?"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: Remove this
|
# TODO: Remove this
|
||||||
|
@ -176,6 +177,20 @@ class BindingGenerator
|
||||||
|
|
||||||
private
|
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)
|
def generate_macro(macro)
|
||||||
if macro.start_with?('USE_')
|
if macro.start_with?('USE_')
|
||||||
"Primitive.cexpr! %q{ RBOOL(#{macro} != 0) }"
|
"Primitive.cexpr! %q{ RBOOL(#{macro} != 0) }"
|
||||||
|
@ -293,6 +308,7 @@ class BindingGenerator
|
||||||
end
|
end
|
||||||
|
|
||||||
src_dir = File.expand_path('../..', __dir__)
|
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)
|
build_dir = File.expand_path(build_dir)
|
||||||
cflags = [
|
cflags = [
|
||||||
src_dir,
|
src_dir,
|
||||||
|
@ -303,6 +319,7 @@ cflags = [
|
||||||
|
|
||||||
nodes = HeaderParser.new(File.join(src_dir, 'mjit_compiler.h'), cflags: cflags).parse
|
nodes = HeaderParser.new(File.join(src_dir, 'mjit_compiler.h'), cflags: cflags).parse
|
||||||
generator = BindingGenerator.new(
|
generator = BindingGenerator.new(
|
||||||
|
src_path: src_path,
|
||||||
macros: %w[
|
macros: %w[
|
||||||
NOT_COMPILED_STACK_SIZE
|
NOT_COMPILED_STACK_SIZE
|
||||||
USE_LAZY_LOAD
|
USE_LAZY_LOAD
|
||||||
|
@ -366,4 +383,4 @@ generator = BindingGenerator.new(
|
||||||
)
|
)
|
||||||
generator.generate(nodes)
|
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)
|
||||||
|
|
|
@ -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
|
module RubyVM::MJIT
|
||||||
C = Object.new
|
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.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) }
|
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_KW_SPLAT = Primitive.cexpr! %q{ INT2NUM(VM_CALL_KW_SPLAT) }
|
||||||
|
|
||||||
def C.VM_CALL_TAILCALL = Primitive.cexpr! %q{ INT2NUM(VM_CALL_TAILCALL) }
|
def C.VM_CALL_TAILCALL = Primitive.cexpr! %q{ INT2NUM(VM_CALL_TAILCALL) }
|
||||||
|
|
||||||
|
### MJIT bindgen end ###
|
||||||
end if RubyVM::MJIT.enabled?
|
end if RubyVM::MJIT.enabled?
|
||||||
|
|
Loading…
Reference in a new issue