3 require 'src/bench' if !(defined? $labels)
7 def dump_caller caller_array
8 puts caller_array.reject{|line| line =~ /\/test\/unit/}.reverse.join("\n").indent 3
9 caller_array.first =~ /(.*):(.*?):in/
10 fname, line_num = $1, $2.to_i
11 File.open(fname, "r") {
13 num_to_get = [line_num - 4, line_num].min
14 num_to_get.times { file.gets }
16 print ((file.lineno+1) == line_num ? "[+] " : " ")
29 attr_accessor :top_ident
40 attr_reader :ranges, :hits, :misses
48 print "Memory report: #{@misses}/#{@hits} (m/h)"
51 @ranges.map{|rng|rng.inspect}.join("\n").indent 3
53 def yield_correct_range addr
54 if !@previous_rng.nil? and @previous_rng === addr
56 yield @previous_rng, @ranges[@previous_rng]
63 next unless rng === addr
69 def load_elem addr, offs
70 found, value = false, nil
72 yield_correct_range(addr) {
75 raise "loaded a nil element!" if value.nil?
76 puts "LOADED #{value} AT #{addr} + #{offs}\nFROM\n#{format_ranges}" if $debug_on
79 raise "can't find ptr!!!! - #{addr} + #{offs}" unless found
83 def store_elem addr, offs, value
86 yield_correct_range(addr) {
88 puts "STORING #{value} AT #{addr} + #{offs}\nIN\n#{format_ranges}, WAS == #{data[offs]}" if $debug_on
93 raise "can't find ptr!!!! - #{addr} + #{offs}" unless found
95 def ptr2string ptr, size
96 found, value = nil, nil
98 yield_correct_range(ptr) {
100 subset = data[(ptr - rng.first) / 4, size / 4] || [] # range with zero size -> nil || []
101 ((size / 4) - subset.size).times { subset << nil } if subset.size != (size / 4)
102 raise "ARGH! - #{subset.size} != #{(size / 4)}" if subset.size != (size / 4)
103 puts "LOADING #{subset.inspect} AT #{ptr}..#{ptr + size}\nFROM\n#{format_ranges}" if $debug_on
105 value = subset.map { |int| (int.is_a? Function) ? -666 : int }.pack("i*")
108 raise "can't find ptr!!!! - #{ptr} .. #{ptr + size}" unless found
112 bytes = [str.length, 2]
113 str.each_byte { |b| bytes += [b, 2] }
114 allocate str.length + 1, bytes
116 def allocate size, object
117 raise "argh, out of memory!" if @top_addr > 2**32
118 # raise "eek! size isn't a multiple of 4!" if (size % 4) != 0
120 @ranges[address...(@top_addr + (size*4))] = object
121 @top_addr += (size*4) + 2**10
126 attr_accessor :data_inspector, :builder_function, :my_callback
134 attr_accessor :ident, :type, :size, :ref
136 @ident = IdentGen::instance.get_ident
145 def self.ptr2string ptr, size
146 $memory.ptr2string ptr, size
148 def self.string2ptr str
149 $memory.string2ptr str
153 attr_accessor :ident, :pos
155 @ident = IdentGen::instance.get_ident
158 Prototype = Struct.new :ret_type, :param_types
159 Instruction = Struct.new :caller, :insn, :params
162 Struct.new(:insn, :params).new(insn, params.map { |param| ((param.ref.data.is_a? Function) rescue false) ? "<Function>" : param }).inspect
165 return "<too much output>" if insn == :insn_call_indirect_vtable_blah
167 "Instruction :: #{insn}" + ([nil] + params).map{|param|param.nil? ? "" : param.inspect}.join("\n#{indent}")
171 attr_accessor :context
172 def initialize context
176 $times = Hash.new { 0 }
185 def fill_value_with_constant val, type, value
186 val.type, val.value = type, value
188 def fill_value_with_param val, idx
189 val.ref = @params[idx].ref
191 def create_with_prototype ret_type, param_types
192 @prototype = Prototype.new ret_type, param_types
193 @params = param_types.map {
197 param.ref = Ref.new -1
201 def method_missing name, *params
202 raise "u gotta call create_with_prototype!" if @prototype.nil?
207 label.pos = @code.length
209 @code << Instruction.new($caller_on ? caller : nil, name, params)
211 def create_local value, type
221 func, params = func.exec params
222 return params if func.nil?
225 def exec params # note - param unused, maybe abstract in layer above, this is the wrong layer!
229 params.each_with_index {
231 @params[idx].ref.data = value
235 puts @code.map {|instr| instr.to_s }.join("\n").indent 3
246 :insn_ne => :==, # see below
250 math_operators = hash_math.keys + hash_comp.keys
253 new_position = position + 1
254 instr = @code[position]
259 ret, src1, src2 = *instr.params
260 bool_result = hash_comp.has_key? instr.insn
261 value = src1.value.send((hash_math.merge hash_comp)[instr.insn], src2.value)
262 ret.value = bool_result ? (value ? 1 : 0) : value
263 ret.value = (1 - ret.value) if instr.insn == :insn_ne
264 when :insn_branch_if, :insn_branch_if_not
265 cond, label = *instr.params
266 expected_value = (instr.insn == :insn_branch_if_not) ? 0 : 1
267 new_position = label.pos if cond.value == expected_value
269 label = *instr.params
270 new_position = label.pos
273 result = [nil, val.value]
276 dst, src = *instr.params
277 dst.value = src.value
278 when :insn_call_print_int
280 if @context.my_callback.nil?
283 @context.my_callback.call val.value
285 when :insn_call_alloc_bytearray
286 addr, size = *instr.params
287 addr.size = size.value
288 addr.value = @context.memory.allocate(size.value, [])
289 when :insn_call_data_inspect
290 p1, p2, p3, p4 = *instr.params
291 @context.data_inspector.call p1.value, p2.value, p3.value, p4.value
292 when :insn_call_build_function
293 ret, p2, p3, p4 = *instr.params
294 bench("builder_function") {
295 ret.value = @context.builder_function.call p2.value, p3.value, p4.value
297 when :insn_call_indirect_vtable_blah
299 ret, func, ret_type, func_prototype, params = *instr.params
300 result = [func.value, params.map{ |param| param.value }]
302 when :insn_store_elem
303 puts "BEFORE store: - #{$memory.ranges.inspect}" if $debug_on
304 addr, idx, src = *instr.params
305 raise "out of bounds! - #{idx.value}" if !addr.size.nil? and idx.value > addr.size
306 $memory.store_elem(addr.value, idx.value, src.value)
307 puts "AFTER store: - #{$memory.ranges.inspect}" if $debug_on
309 puts "DURING load: - #{$memory.ranges.inspect}" if $debug_on
310 dst, addr, idx, type = *instr.params
311 raise "out of bounds! - #{idx.value}" if !addr.size.nil? and idx.value > addr.size
313 dst.value = $memory.load_elem(addr.value, idx.value)
317 raise "INSTRUCTION #{instr.inspect} NOT HANDLED"
320 $times[instr.insn] += (new_time - time).to_f unless time.nil?
321 position = new_position
323 dump_caller instr.caller if $caller_on
324 puts "Post-instruction State ::"
330 dump_caller instr.caller
332 puts "SWITCH ON DEBUGGING! if you want to know more!"
335 puts e.backtrace.join("\n").indent 3
336 puts "Current instruction:"
338 puts "Exception: #{e.inspect}"
348 def mk_constant func, constant_type, integer
349 return_value = Value.new
350 func.fill_value_with_constant return_value, constant_type, integer
354 def get_param func, param_idx
356 func.fill_value_with_param val, param_idx
362 class LoggingContext < Context
367 self.my_callback = proc { |b| @log << b }
371 class Test_All < Test::Unit::TestCase
373 context = Context.new
374 func = Function.new context
375 func.create_with_prototype :int, [:int, :int]
378 val1 = get_param func, 0
379 val2 = get_param func, 1
380 func.insn_add ret, val1, val2
384 assert_equal 7, (func.apply [2, 5])
388 context = Context.new
389 context.builder_function = proc {
391 s_context = Context.new
392 s_func = Function.new s_context
393 s_func.create_with_prototype :int, []
395 s_ret, s_val1, s_val2 = Value.new, Value.new, Value.new
396 s_func.fill_value_with_constant s_val1, :int, p2
397 s_func.fill_value_with_constant s_val2, :int, p3
398 s_func.insn_add s_ret, s_val1, s_val2
399 s_func.insn_return s_ret
404 func = Function.new context
405 func.create_with_prototype :int, []
408 func.insn_call_alloc_bytearray mem_addr, mk_constant(func, :int, 2)
409 func.insn_store_elem mem_addr, mk_constant(func, :int, 0), mk_constant(func, :int, 32)
410 func.insn_store_elem mem_addr, mk_constant(func, :int, 1), mk_constant(func, :int, 64)
412 func.insn_call_build_function func_ptr, mk_constant(func, :int, 2), mk_constant(func, :int, 3), mk_constant(func, :int, -1)
413 ret_value = Value.new
414 func.insn_call_indirect_vtable_blah ret_value, func_ptr, nil, nil, []
415 func.insn_return ret_value
418 assert_equal 5, (func.apply [])
422 context = Context.new
423 context.builder_function = proc {
427 func = Function.new context
428 func.create_with_prototype :int, []
431 func.insn_call_alloc_bytearray mem_addr, mk_constant(func, :int, 2)
432 func.insn_store_elem mem_addr, mk_constant(func, :int, 0), mk_constant(func, :int, 32)
433 func.insn_store_elem mem_addr, mk_constant(func, :int, 1), mk_constant(func, :int, 64)
435 func.insn_call_build_function func_ptr, mk_constant(func, :int, 0), mk_constant(func, :int, 2), mk_constant(func, :int, 3)
436 func.insn_return func_ptr
439 assert_equal 5, (func.apply [])
443 context = Context.new
444 inspect_results = nil
445 context.data_inspector = proc {
447 inspect_results = [p1, p2, p3, p4]
449 func = Function.new context
450 func.create_with_prototype :int, []
453 func.insn_call_alloc_bytearray mem_addr, mk_constant(func, :int, 2)
454 func.insn_store_elem mem_addr, mk_constant(func, :int, 0), mk_constant(func, :int, 32)
455 func.insn_store_elem mem_addr, mk_constant(func, :int, 1), mk_constant(func, :int, 64)
456 func.insn_call_data_inspect mem_addr, mem_addr, mem_addr, mem_addr
460 assert_equal [256, 256, 256, 256], inspect_results
464 context = LoggingContext.new
465 func = Function.new context
466 func.create_with_prototype :int, []
469 func.insn_call_alloc_bytearray mem_addr, mk_constant(func, :int, 4096)
470 func.insn_store_elem mem_addr, mk_constant(func, :int, 0), mk_constant(func, :int, 32)
471 func.insn_store_elem mem_addr, mk_constant(func, :int, 1), mk_constant(func, :int, 64)
473 func.insn_load_elem temp, mem_addr, mk_constant(func, :int, 0), :int
474 func.insn_call_print_int temp
475 func.insn_load_elem temp, mem_addr, mk_constant(func, :int, 1), :int
476 func.insn_call_print_int temp
480 assert_equal [32, 64], context.log
484 context = LoggingContext.new
485 func = Function.new context
486 func.create_with_prototype :int, []
488 counter, temp = Value.new, Value.new
489 func.create_local counter, :int
490 func.fill_value_with_constant temp, :int, 0
491 func.insn_store counter, temp
492 # while loop, with a counter
493 loop_again = Label.new
494 func.insn_label loop_again
495 func.insn_add temp, counter, mk_constant(func, :int, 1)
496 func.insn_store counter, temp
497 func.insn_call_print_int counter
499 func.insn_eq cond, counter, mk_constant(func, :int, 5)
500 func.insn_branch_if_not cond, loop_again
504 assert_equal [1, 2, 3, 4, 5], context.log
508 context = LoggingContext.new
509 func = Function.new context
510 func.create_with_prototype :int, []
512 ret, val1, val2 = Value.new, Value.new, Value.new
513 func.fill_value_with_constant val1, :int, 2
514 func.fill_value_with_constant val2, :int, 3
515 func.insn_add ret, val1, val2
517 # test if ne, if not branch to next
520 func.insn_ne cond, ret, mk_constant(func, :int, 4)
521 func.insn_branch_if cond, skip_4
522 # else print it and we're finished
523 func.insn_call_print_int mk_constant(func, :int, 4)
524 func.insn_branch finished
525 func.insn_label skip_4
526 # test if ne if not branch to next
528 func.insn_eq cond, ret, mk_constant(func, :int, 5)
529 func.insn_branch_if_not cond, skip_5
530 # else print it and we're finished
531 func.insn_call_print_int mk_constant(func, :int, 5)
532 func.insn_label skip_5
533 func.insn_label finished
537 assert_equal [5], context.log
541 context = Context.new
542 func = Function.new context
543 func.create_with_prototype :int, []
545 ret, val1, val2 = Value.new, Value.new, Value.new
546 func.fill_value_with_constant val1, :int, 2
547 func.fill_value_with_constant val2, :int, 3
548 func.insn_add ret, val1, val2
552 assert_equal 5, (func.apply [])