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
- @@autoload_running_p =
false
- @@compilation_threshold =
100
- @@autocompile_proc =
nil
- @@original_instance_method_iseq =
{}
- @@original_singleton_method_iseq =
{}
- @@loaded_binary =
{}
- @@mls =
{}
Instance Method Summary collapse
- #autocompile ⇒ Object
- #autocompile_running? ⇒ Boolean
- #autoload ⇒ Object
- #autoload_running? ⇒ Boolean
- #clear ⇒ Object
- #compilation_threshold=(num) ⇒ Object
- #compile(target, mid, bind_or_typemap = nil, typemap = nil, force_compilation = false) ⇒ Object
- #compile_instance_methods(klass, bind = nil, skip = []) ⇒ Object
- #compile_singleton_method(obj, mid, bind_or_typemap = nil, typemap = nil, force_compilation = false) ⇒ Object
- #compiler_running? ⇒ Boolean
- #create_method_invocation_callback ⇒ Object
- #delete_original_instance_method_iseq(target, mid) ⇒ Object
- #delete_original_singleton_method_iseq(obj, mid) ⇒ Object
- #do_alias ⇒ Object
- #execute(typemap = nil, &block) ⇒ Object
- #hook_method_definition ⇒ Object
- #method_aliasing? ⇒ Boolean
- #method_replacing? ⇒ Boolean
- #re_compile_all ⇒ Object
- #replace_method_invocation(obj, mid, singleton_p) ⇒ Object
- #restore_method(target, mid, me) ⇒ Object
- #set_suggestion_io(io) ⇒ Object
- #verbose(b) ⇒ Object
Methods included from Util
Instance Method Details
#autocompile ⇒ Object
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/cast_off/compile.rb', line 40 def autocompile() return false if autoload_running? return true if autocompile_running? class_table = {} number = 0 @@autocompile_proc = lambda {|klass, mid, bind| # trace method invocation # TODO should handle singleton class method_table = (class_table[klass] ||= Hash.new(-1)) count = (method_table[mid] += 1) #count = @@compilation_threshold if contain_loop?(klass, mid) if count == 0 if count == @@compilation_threshold bug() unless bind.nil? return true # re-call this proc with binding end __autocompile(klass, mid, bind, (number += 1)) if bind false } hook_method_invocation(@@autocompile_proc) true end |
#autocompile_running? ⇒ Boolean
271 272 273 |
# File 'lib/cast_off/compile.rb', line 271 def autocompile_running? !!@@autocompile_proc end |
#autoload ⇒ Object
26 27 28 29 30 |
# File 'lib/cast_off/compile.rb', line 26 def autoload() return false if autocompile_running? @@autoload_running_p = true true end |
#autoload_running? ⇒ Boolean
275 276 277 |
# File 'lib/cast_off/compile.rb', line 275 def autoload_running? !!@@autoload_running_p end |
#clear ⇒ Object
21 22 23 |
# File 'lib/cast_off/compile.rb', line 21 def clear() CodeManager.clear() end |
#compilation_threshold=(num) ⇒ Object
33 34 35 36 37 |
# File 'lib/cast_off/compile.rb', line 33 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
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/cast_off/compile.rb', line 87 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
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/cast_off/compile.rb', line 63 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
116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/cast_off/compile.rb', line 116 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
279 280 281 |
# File 'lib/cast_off/compile.rb', line 279 def compiler_running? !!Thread.current[COMPILER_RUNNING_KEY] end |
#create_method_invocation_callback ⇒ Object
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/cast_off/compile.rb', line 215 def create_method_invocation_callback() proc{|*args, &block| hook_proc = CastOff.current_bmethod_proc() current_method_id = CastOff.current_method_id() target = CastOff.override_target_of_current_method(self) me = @@mls[hook_proc] CastOff.bug() unless me.instance_of?(UnboundMethod) if target && CastOff.singleton_class?(target) compilation_method_id = :compile_singleton_method separator = '.' singleton = true else compilation_method_id = :compile separator = '#' singleton = false unless target # from method object methods = ObjectSpace.each_object(Method).select{|mobj| CastOff.rewrite_method_object(mobj, me, hook_proc)} me = methods.find{|m| m.receiver.__id__ == self.__id__} CastOff.bug() unless me.instance_of?(Method) CastOff.vlog("rewrite method object #{me}") return me.call(*args, &block) end end CastOff.bug() unless CastOff.instance_bmethod_proc(target.instance_method(current_method_id)) == hook_proc CastOff.restore_method(target, current_method_id, me) CastOff.bug() unless CastOff.get_compilable_iseq(target, current_method_id, false) begin CastOff.__send__(compilation_method_id, singleton ? self : target, current_method_id) rescue CastOff.vlog("failed to load #{target}#{separator}#{current_method_id}") end target.instance_method(current_method_id).bind(self).call(*args, &block) } end |
#delete_original_instance_method_iseq(target, mid) ⇒ Object
82 83 84 85 |
# File 'lib/cast_off/compile.rb', line 82 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
112 113 114 |
# File 'lib/cast_off/compile.rb', line 112 def delete_original_singleton_method_iseq(obj, mid) @@original_singleton_method_iseq.delete([obj, mid]) end |
#do_alias ⇒ Object
187 188 189 190 191 192 193 194 195 196 |
# File 'lib/cast_off/compile.rb', line 187 def do_alias() bug() unless block_given? begin bug() if method_aliasing? method_aliasing(true) yield ensure method_aliasing(false) end end |
#execute(typemap = nil, &block) ⇒ Object
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/cast_off/compile.rb', line 132 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 |
#hook_method_definition ⇒ Object
173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/cast_off/compile.rb', line 173 def hook_method_definition() Module.class_eval do def method_added(mid) return unless CastOff.autoload_running? && !CastOff.compiler_running? && !CastOff.method_aliasing? CastOff.replace_method_invocation(self, mid, false) end def singleton_method_added(mid) return unless CastOff.autoload_running? && !CastOff.compiler_running? && !CastOff.method_aliasing? CastOff.replace_method_invocation(self, mid, true) end end end |
#method_aliasing? ⇒ Boolean
287 288 289 |
# File 'lib/cast_off/compile.rb', line 287 def method_aliasing? !!Thread.current[METHOD_ALIASING_KEY] end |
#method_replacing? ⇒ Boolean
283 284 285 |
# File 'lib/cast_off/compile.rb', line 283 def method_replacing? !!Thread.current[METHOD_REPLACING_KEY] end |
#re_compile_all ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/cast_off/compile.rb', line 149 def re_compile_all() all = @@original_singleton_method_iseq.map{|(target, mid), v| [target, mid, true] } + @@original_instance_method_iseq.map{|(target, mid), v| [target, mid, false] } all.each do |(target, mid, singleton)| compilation_method_name = "compile#{singleton ? '_singleton_method' : ''}" separator = singleton ? '.' : '#' begin CastOff.__send__(compilation_method_name, target, mid) rescue ArgumentError, NameError, CompileError => e # ArgumentError: dependency の Marshal.load に失敗 # NameError: prefetch constant での定数参照に失敗 # CompileError: メソッドが undef されて未定義になってしまった場合 vlog("Skip: #{target}#{separator}#{mid}") rescue UnsupportedError => e vlog("Unsupported: #{target}#{separator}#{mid} => #{e}") rescue => e vlog("Catch exception #{e.class}: #{e}\n#{e.backtrace.join("\n")}") end end end |
#replace_method_invocation(obj, mid, singleton_p) ⇒ Object
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
# File 'lib/cast_off/compile.rb', line 251 def replace_method_invocation(obj, mid, singleton_p) iseq = get_compilable_iseq(obj, mid, singleton_p) return unless iseq filepath = get_iseq_filepath(iseq) line_no = get_iseq_line(iseq) return unless CodeManager.compiled_method_exist?(filepath, line_no) target = singleton_p ? obj.singleton_class : override_target(obj, mid) begin original_method = target.instance_method(mid) rescue => e CastOff.bug(e) end do_alias do hook_proc = create_method_invocation_callback() target.__send__(:define_method, mid, &hook_proc) CastOff.bug() if @@mls[hook_proc] @@mls[hook_proc] = original_method end end |
#restore_method(target, mid, me) ⇒ Object
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/cast_off/compile.rb', line 198 def restore_method(target, mid, me) do_alias do begin target.__send__(:define_method, mid, me) rescue me = me.clone CastOff.rewrite_rclass_of_unbound_method_object(me, target) begin target.__send__(:define_method, mid, me) rescue => e CastOff.bug("#{target}, #{mid}, #{e}:\n#{e.backtrace}") end end end 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 |