diff --git a/lib/mjit/c_type.rb b/lib/mjit/c_type.rb index 8ccdfcc4d3..9e45d8d41c 100644 --- a/lib/mjit/c_type.rb +++ b/lib/mjit/c_type.rb @@ -46,9 +46,9 @@ module RubyVM::MJIT new(Fiddle::Importer.parse_ctype(ctype)) end - def self.find(size, unsigned) + def self.find(size, signed) fiddle_type = TYPE_MAP.fetch(size) - fiddle_type = -fiddle_type if unsigned + fiddle_type = -fiddle_type unless signed new(fiddle_type) end diff --git a/mjit_c.rb b/mjit_c.rb index 5c84b10331..6b316860be 100644 --- a/mjit_c.rb +++ b/mjit_c.rb @@ -372,14 +372,12 @@ module RubyVM::MJIT errinfo: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), errinfo)")], passed_block_handler: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), passed_block_handler)")], raised_flag: [CType::Immediate.parse("uint8_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), raised_flag)")], - method_missing_reason: [self.method_missing_reason, nil], private_const_reference: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), private_const_reference)")], machine: [CType::Struct.new( "", Primitive.cexpr!("SIZEOF(((struct rb_execution_context_struct *)NULL)->machine)"), stack_start: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_execution_context_struct *)NULL)->machine, stack_start)")], stack_end: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_execution_context_struct *)NULL)->machine, stack_end)")], stack_maxsize: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF(((struct rb_execution_context_struct *)NULL)->machine, stack_maxsize)")], - regs: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_execution_context_struct *)NULL)->machine, regs)")], ), Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), machine)")], ) end @@ -454,7 +452,6 @@ module RubyVM::MJIT jit_func: [CType::Immediate.parse("void *"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), jit_func)")], total_calls: [CType::Immediate.parse("unsigned long"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), total_calls)")], jit_unit: [CType::Pointer.new { self.rb_mjit_unit }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), jit_unit)")], - yjit_payload: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), yjit_payload)")], ) end diff --git a/tool/mjit/bindgen.rb b/tool/mjit/bindgen.rb index d6431f8c40..56369c2d98 100755 --- a/tool/mjit/bindgen.rb +++ b/tool/mjit/bindgen.rb @@ -12,20 +12,9 @@ unless build_dir = ARGV.first abort "Usage: #{$0} BUILD_DIR" end -if Fiddle::SIZEOF_VOIDP == 8 - arch_bits = 64 -else - arch_bits = 32 -end - # Help ffi-clang find libclang -if arch_bits == 64 - # apt install libclang1 - ENV['LIBCLANG'] ||= Dir.glob("/lib/#{RUBY_PLATFORM}-gnu/libclang-*.so*").grep_v(/-cpp/).sort.last -else - # apt install libclang1:i386 - ENV['LIBCLANG'] ||= Dir.glob("/lib/i386-linux-gnu/libclang-*.so*").sort.last -end +# Hint: apt install libclang1 +ENV['LIBCLANG'] ||= Dir.glob("/lib/#{RUBY_PLATFORM}-gnu/libclang-*.so*").grep_v(/-cpp/).sort.last require 'ffi/clang' class Node < Struct.new( @@ -116,14 +105,16 @@ class BindingGenerator # @param ints [Array] # @param types [Array] # @param dynamic_types [Array] #ifdef-dependent immediate types, which need Primitive.cexpr! for type detection + # @param skip_fields [Hash{ Symbol => Array }] Struct fields that are skipped from bindgen # @param ruby_fields [Hash{ Symbol => Array }] Struct VALUE fields that are considered Ruby objects - def initialize(src_path:, uses:, ints:, types:, dynamic_types:, ruby_fields:) + def initialize(src_path:, uses:, ints:, types:, dynamic_types:, skip_fields:, ruby_fields:) @preamble, @postamble = split_ambles(src_path) @src = String.new @uses = uses.sort @ints = ints.sort @types = types.sort @dynamic_types = dynamic_types.sort + @skip_fields = skip_fields.transform_keys(&:to_s) @ruby_fields = ruby_fields.transform_keys(&:to_s) @references = Set.new end @@ -209,12 +200,16 @@ class BindingGenerator buf << " \"#{node.spelling}\", Primitive.cexpr!(\"SIZEOF(#{sizeof_type || node.type})\"),\n" bit_fields_end = node.children.index { |c| c.bitwidth == -1 } || node.children.size # first non-bit field index node.children.each_with_index do |child, i| + skip_type = sizeof_type&.gsub(/\(\(struct ([^\)]+) \*\)NULL\)->/, '\1.') || node.spelling + next if @skip_fields.fetch(skip_type, []).include?(child.spelling) field_builder = proc do |field, type| if node.kind == :struct to_ruby = @ruby_fields.fetch(node.spelling, []).include?(field) if child.bitwidth > 0 - # give up offsetof calculation for non-leading bit fields - offsetof = (i < bit_fields_end ? node.offsetof.fetch(field) : nil).inspect + if bit_fields_end <= i # give up offsetof calculation for non-leading bit fields + raise "non-leading bit fields are not supported. consider including '#{field}' in skip_fields." + end + offsetof = node.offsetof.fetch(field) else off_type = sizeof_type || "(*((#{node.type} *)NULL))" offsetof = "Primitive.cexpr!(\"OFFSETOF(#{off_type}, #{field})\")" @@ -380,6 +375,11 @@ generator = BindingGenerator.new( dynamic_types: %w[ VALUE ], + skip_fields: { + 'rb_execution_context_struct.machine': %w[regs], # differs between macOS and Linux + rb_execution_context_struct: %w[method_missing_reason], # non-leading bit fields not supported + rb_iseq_constant_body: %w[yjit_payload], # conditionally defined + }, ruby_fields: { rb_iseq_location_struct: %w[ base_label