summaryrefslogtreecommitdiff
path: root/lib/ruby_vm/rjit/c_type.rb
blob: 3b313a658b489af3617cbc8db23e3602eeab954c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
require 'fiddle'
require 'fiddle/pack'
require_relative 'c_pointer'

module RubyVM::RJIT
  module CType
    module Struct
      # @param name [String]
      # @param members [Hash{ Symbol => [Integer, RubyVM::RJIT::CType::*] }]
      def self.new(name, sizeof, **members)
        name = members.keys.join('_') if name.empty?
        CPointer.with_class_name('Struct', name) do
          CPointer::Struct.define(sizeof, members)
        end
      end
    end

    module Union
      # @param name [String]
      # @param members [Hash{ Symbol => RubyVM::RJIT::CType::* }]
      def self.new(name, sizeof, **members)
        name = members.keys.join('_') if name.empty?
        CPointer.with_class_name('Union', name) do
          CPointer::Union.define(sizeof, members)
        end
      end
    end

    module Immediate
      # @param fiddle_type [Integer]
      def self.new(fiddle_type)
        name = Fiddle.constants.find do |const|
          const.start_with?('TYPE_') && Fiddle.const_get(const) == fiddle_type.abs
        end&.to_s
        name.delete_prefix!('TYPE_')
        if fiddle_type.negative?
          name.prepend('U')
        end
        CPointer.with_class_name('Immediate', name, cache: true) do
          CPointer::Immediate.define(fiddle_type)
        end
      end

      # @param type [String]
      def self.parse(ctype)
        new(Fiddle::Importer.parse_ctype(ctype))
      end

      def self.find(size, signed)
        fiddle_type = TYPE_MAP.fetch(size)
        fiddle_type = -fiddle_type unless signed
        new(fiddle_type)
      end

      TYPE_MAP = Fiddle::PackInfo::SIZE_MAP.map { |type, size| [size, type.abs] }.to_h
      private_constant :TYPE_MAP
    end

    module Bool
      def self.new
        CPointer::Bool
      end
    end

    class Array
      def self.new(&block)
        CPointer.with_class_name('Array', block.object_id.to_s) do
          CPointer::Array.define(block)
        end
      end
    end

    class Pointer
      # This takes a block to avoid "stack level too deep" on a cyclic reference
      # @param block [Proc]
      def self.new(&block)
        CPointer.with_class_name('Pointer', block.object_id.to_s) do
          CPointer::Pointer.define(block)
        end
      end
    end

    module BitField
      # @param width [Integer]
      # @param offset [Integer]
      def self.new(width, offset)
        CPointer.with_class_name('BitField', "#{offset}_#{width}") do
          CPointer::BitField.define(width, offset)
        end
      end
    end

    # Types that are referenced but not part of code generation targets
    Stub = ::Struct.new(:name)

    # Types that it failed to figure out from the header
    Unknown = Module.new
  end
end