aboutsummaryrefslogtreecommitdiffstats
path: root/tool/mk_builtin_loader.rb
blob: 4f140a6f6b262ccbed29a9a98eb7fd51b6b710bd (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
def collect_builtin iseq_ary, bs
  code = iseq_ary[13]

  code.each{|insn|
    next unless Array === insn
    case insn[0]
    when :send
      ci = insn[1]
      if /\A__builtin_(.+)/ =~ ci[:mid]
        func_name = $1
        argc = ci[:orig_argc]

        if bs[func_name] && bs[func_name] != argc
          raise
        end
        bs[func_name] = argc
      end
    else
      insn[1..-1].each{|op|
        if op.is_a?(Array) && op[0] == "YARVInstructionSequence/SimpleDataFormat"
          collect_builtin op, bs
        end
      }
    end
  }
end
# ruby mk_builtin_loader.rb TARGET_FILE.rb
# #=> generate TARGET_FILE.rbinc
#

def mk_builtin_header file
  base = File.basename(file, '.rb')
  ofile = "#{base}.rbinc"

  collect_builtin(RubyVM::InstructionSequence.compile_file(file, false).to_a, bs = {})

  open(ofile, 'w'){|f|
    f.puts "// -*- c -*-"
    f.puts "// DO NOT MODIFY THIS FILE DIRECTLY."
    f.puts "// auto-generated file"
    f.puts "//   by #{__FILE__}"
    f.puts "//   with #{file}"
    f.puts

    f.puts "static void load_#{base}(void)"
    f.puts "{"

    table = "#{base}_table"
    f.puts "  // table definition"
    f.puts "  static const struct rb_builtin_function #{table}[] = {"
    bs.each.with_index{|(func, argc), i|
      f.puts "    RB_BUILTIN_FUNCTION(#{i}, #{func}, #{argc}),"
    }
    f.puts "    RB_BUILTIN_FUNCTION(-1, NULL, 0),"
    f.puts "  };"

    f.puts
    f.puts "  // arity_check"
    f.puts "COMPILER_WARNING_PUSH"
    f.puts "#if GCC_VERSION_SINCE(5, 1, 0) || __clang__"
    f.puts "COMPILER_WARNING_ERROR(-Wincompatible-pointer-types)"
    f.puts "#endif"
    bs.each{|func, argc|
      f.puts "  if (0) rb_builtin_function_check_arity#{argc}(#{func});"
    }
    f.puts "COMPILER_WARNING_POP"


    f.puts
    f.puts "  // load"
    f.puts "  rb_load_with_builtin_functions(#{base.dump}, #{table});"

    f.puts "}"
  }
end

ARGV.each{|file|
  # feature.rb => load_feature.inc
  mk_builtin_header file
}