Module: CastOff::Compiler

Includes:
Util
Included in:
CastOff
Defined in:
lib/cast_off/compile.rb,
lib/cast_off/compile/cfg.rb,
lib/cast_off/compile/iseq.rb,
lib/cast_off/compile/stack.rb,
lib/cast_off/compile/ir/sub_ir.rb,
lib/cast_off/compile/basicblock.rb,
lib/cast_off/compile/dependency.rb,
lib/cast_off/compile/ir/call_ir.rb,
lib/cast_off/compile/ir/jump_ir.rb,
lib/cast_off/compile/ir/operand.rb,
lib/cast_off/compile/translator.rb,
lib/cast_off/compile/information.rb,
lib/cast_off/compile/instruction.rb,
lib/cast_off/compile/ir/guard_ir.rb,
lib/cast_off/compile/ir/param_ir.rb,
lib/cast_off/compile/code_manager.rb,
lib/cast_off/compile/ir/return_ir.rb,
lib/cast_off/compile/ir/simple_ir.rb,
lib/cast_off/compile/configuration.rb,
lib/cast_off/compile/method_information.rb

Defined Under Namespace

Modules: Instruction, SimpleIR Classes: CodeManager, Configuration, Dependency, Iseq, MethodInformation, ReCompilation, SingletonClass, Translator

Constant Summary collapse

DefaultSuggestionIO =
Object.new
@@suggestion_io =
DefaultSuggestionIO
@@blacklist =
[
]
@@autoload_proc =
nil
@@compilation_threshold =
100
@@autocompile_proc =
nil
@@original_instance_method_iseq =
{}
@@original_singleton_method_iseq =
{}
@@loaded_binary =
{}

Instance Method Summary collapse

Methods included from Util

#bug, #dlog, #todo, #vlog

Instance Method Details

#autocompileObject



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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/cast_off/compile.rb', line 74

def autocompile()
  return false if autoload_running?
  return true if autocompile_running?
  class_table = {}
  bind_table = {}
  location_table = {}
  #cinfo_table = {}
  compiled = []
  #@@autocompile_proc = lambda {|file, line, mid, bind, klass, cinfo|
  @@autocompile_proc = lambda {|file, line, mid, bind, klass|
    # trace method invocation
    # TODO should handle singleton class

    method_table = (class_table[klass] ||= Hash.new(-1))
    count = (method_table[mid] += 1)
    if count == 0
      bug() unless bind.nil?
      return true # re-call this proc with binding
    end
    if count == 1
      #count = @@compilation_threshold if contain_loop?(klass, mid)
      bug() unless bind.instance_of?(Binding) || bind.nil?
      bind_table[[klass, mid]] = bind
      begin
        location_table[[klass, mid]] = (file =~ /\(/) ? nil : [File.expand_path(file), line]
      rescue Errno::ENOENT 
        location_table[[klass, mid]] = nil
      end
    end
    #if cinfo
      #table = (cinfo_table[[klass, mid]] ||= {})
      #table[cinfo] = true
    #end
    if count == @@compilation_threshold && @@compile_auto_incremental
      compiled << __autocompile(klass, mid, bind_table, location_table, compiled.size)
    end
    false
  }
  hook_method_invocation(@@autocompile_proc)
  at_exit do
    hook_method_invocation(nil) # clear trace
    unless @@compile_auto_incremental
      targets = []
      class_table.each do |klass, method_table|
        method_table.each do |mid, count|
          next unless count >= @@compilation_threshold
          targets << [klass, mid, count]
        end
      end
      #targets = sort_targets(targets, cinfo_table)
      targets.each_with_index do |(klass, mid, count), index|
        dlog("#{count}: #{klass} #{mid}")
        compiled << __autocompile(klass, mid, bind_table, location_table, index)
      end
    end
    compiled.compact!
    CodeManager.dump_auto_compiled(compiled)
  end
  true
end

#autocompile_running?Boolean

Returns:

  • (Boolean)


221
222
223
# File 'lib/cast_off/compile.rb', line 221

def autocompile_running?
  !!@@autocompile_proc
end

#autoloadObject



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/cast_off/compile.rb', line 29

def autoload()
  return false if autocompile_running?
  if autoload_running?
    @@autoload_proc.call()
    return true 
  end

  # Marshal.load で定数を参照したときに、クラス定義が走る可能性があるので、
  # @@autoload_proc を定義する前に、Marshal.load を呼び出しておく。
  compiled = CodeManager.load_autocompiled()
  @@autoload_proc = lambda {
    compiled = CodeManager.load_autocompiled() unless compiled
    return false unless compiled
    fin = __load(compiled)
    hook_class_definition_end(nil) if fin
    fin
  }
  hook_class_definition_end(@@autoload_proc) if RUBY_VERSION == "1.9.3"
  @@autoload_proc.call()
  true
end

#autoload_running?Boolean

Returns:

  • (Boolean)


225
226
227
# File 'lib/cast_off/compile.rb', line 225

def autoload_running?
  !!@@autoload_proc
end

#clearObject



21
22
23
# File 'lib/cast_off/compile.rb', line 21

def clear()
  CodeManager.clear()
end

#compilation_threshold=(num) ⇒ Object

Raises:

  • (ArgumentError)


58
59
60
61
62
# File 'lib/cast_off/compile.rb', line 58

def compilation_threshold=(num)
  raise(ArgumentError.new("first argument should be Integer")) unless num.is_a?(Integer)
  raise(ArgumentError.new("threshold should be more than 0")) unless num >= 0
  @@compilation_threshold = num
end

#compile(target, mid, bind_or_typemap = nil, typemap = nil, force_compilation = false) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/cast_off/compile.rb', line 159

def compile(target, mid, bind_or_typemap = nil, typemap = nil, force_compilation = false)
  execute_no_hook() do
    case target
    when Class, Module
      # ok
    else
      raise(ArgumentError.new("first argument should be Class or Module"))
    end
    mid, bind, typemap = parse_arguments(mid, bind_or_typemap, typemap)
    t = override_target(target, mid)
    iseq = @@original_instance_method_iseq[[t, mid]] || get_iseq(target, mid, false)
    manager, configuration, suggestion = compile_iseq(iseq, mid, typemap, false, bind, force_compilation)
    manager.compilation_target_is_a(t, mid, false)
    set_direct_call(target, mid, target.instance_of?(Class) ? :class : :module, manager, configuration)
    load_binary(manager, configuration, suggestion, iseq)
    t = override_target(target, mid)
    dlog("override target of #{target}##{mid} is #{t}")
    replace_method(t, manager, false)
    @@original_instance_method_iseq[[t, mid]] = iseq
    @@manager_table[manager.signiture] = manager
  end
  true
end

#compile_instance_methods(klass, bind = nil, skip = []) ⇒ Object

Raises:

  • (ArgumentError)


135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/cast_off/compile.rb', line 135

def compile_instance_methods(klass, bind = nil, skip = [])
  raise ArgumentError.new("first argument should be Class") unless klass.instance_of?(Class)
  raise ArgumentError.new("second argument should be Binding") unless !bind || bind.instance_of?(Binding)
  logger = self
  klass.class_eval do
    instance_methods(false).each_with_index do |mid, idx|
      next if skip.include?(mid)
      args = [klass, mid, bind]
      begin
        CastOff.compile(*args.compact())
        logger.vlog("#{idx}: compile #{mid}")
      rescue UnsupportedError => e
        logger.vlog("#{idx}: failed to compile #{self}##{mid} (#{e.message})")
      end
    end
  end
end

#compile_singleton_method(obj, mid, bind_or_typemap = nil, typemap = nil, force_compilation = false) ⇒ Object



188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/cast_off/compile.rb', line 188

def compile_singleton_method(obj, mid, bind_or_typemap = nil, typemap = nil, force_compilation = false)
  execute_no_hook() do
    mid, bind, typemap = parse_arguments(mid, bind_or_typemap, typemap)
    iseq = @@original_singleton_method_iseq[[obj, mid]] || get_iseq(obj, mid, true)
    manager, configuration, suggestion = compile_iseq(iseq, mid, typemap, false, bind, force_compilation)
    manager.compilation_target_is_a(obj, mid, true)
    set_direct_call(obj, mid, :singleton, manager, configuration)
    load_binary(manager, configuration, suggestion, iseq)
    replace_method(obj, manager, true)
    @@original_singleton_method_iseq[[obj, mid]] = iseq
    @@manager_table[manager.signiture] = manager
  end
  true
end

#compiler_running?Boolean

Returns:

  • (Boolean)


229
230
231
# File 'lib/cast_off/compile.rb', line 229

def compiler_running?
  !!Thread.current[COMPILER_RUNNING_KEY]
end

#delete_original_instance_method_iseq(target, mid) ⇒ Object



154
155
156
157
# File 'lib/cast_off/compile.rb', line 154

def delete_original_instance_method_iseq(target, mid)
  t = override_target(target, mid)
  @@original_instance_method_iseq.delete([t, mid])
end

#delete_original_singleton_method_iseq(obj, mid) ⇒ Object



184
185
186
# File 'lib/cast_off/compile.rb', line 184

def delete_original_singleton_method_iseq(obj, mid)
  @@original_singleton_method_iseq.delete([obj, mid])
end

#execute(typemap = nil, &block) ⇒ Object

Raises:

  • (ArgumentError)


204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/cast_off/compile.rb', line 204

def execute(typemap = nil, &block)
  raise(ArgumentError.new('no block given')) unless block
  iseq = get_iseq_from_block(block)
  key = iseq.__id__
  if !@@loaded_binary[key]
    execute_no_hook() do
      bind = block.binding
      manager, configuration, suggestion = compile_iseq(iseq, nil, typemap, false, bind, false)
      load_binary(manager, configuration, suggestion, iseq)
      @@loaded_binary[key] = manager.signiture
    end
  end
  sign = @@loaded_binary[key]
  recv = get_caller()
  __send__(sign, recv)
end

#loadObject



51
52
53
54
55
# File 'lib/cast_off/compile.rb', line 51

def load()
  compiled = CodeManager.load_autocompiled()
  return false unless compiled
  __load(compiled)
end

#method_replacing?Boolean

Returns:

  • (Boolean)


233
234
235
# File 'lib/cast_off/compile.rb', line 233

def method_replacing?
  !!Thread.current[METHOD_REPLACING_KEY]
end

#set_suggestion_io(io) ⇒ Object



13
14
15
# File 'lib/cast_off/compile.rb', line 13

def set_suggestion_io(io)
  @@suggestion_io = io
end

#verbose(b) ⇒ Object



17
18
19
# File 'lib/cast_off/compile.rb', line 17

def verbose(b)
  CastOff::Util.set_verbose_mode(b)
end