2 require 'nanovm/nano.rb'
4 # $: << "../ruby_parser-1.0.0/lib"
5 # require "ruby_parser"
11 require 'src/bench.rb'
14 require '3rdparty/breakpoint/breakpoint'
17 require 'yaml/store.rb' # including this shaves a few seconds of testing, why?
24 Context.debug = $nanovm_debug
28 def self.md_metadata func
32 def self.md_get_id func
33 func.metadata[:path_range].first
36 def self.md_get_path_range func
37 func.metadata[:path_range]
40 def self.md_set_path_range func, new_path_range
41 func.metadata[:path_range] = new_path_range
44 def self.md_init_and_add_to_caller_map_and_return_size func, str
45 func.metadata[:caller_map] ||= ([nil] * 8)
46 func.metadata[:caller_map] << str
47 func.metadata[:caller_map].size
50 def self.md_add_to_lookup_for_debug func, name
51 func.metadata[:lookup_for] ||= []
52 func.metadata[:lookup_for] << [name]
55 def self.md_add_to_static_scope func, scope, scope_id, sym
56 func.metadata[:used_scope_template] = scope
57 func.metadata[:used_static_scopes] ||= []
58 func.metadata[:used_static_scopes] << [scope_id, sym]
61 def self.md_find_in_caller_map func, slow_id
62 (func.metadata[:caller_map].index [:id, slow_id]) + 1
65 def self.md_set_next_id func, curr_id
66 func.metadata[:next_id] = curr_id
69 def self.md_set_is_bouncer func
70 func.metadata[:is_bouncer] = true
73 def self.md_add_assumption func, obj
74 func.metadata[:assumptions] << obj
77 def self.md_set_specifalized func, on
78 func.metadata[:specialized] = on
81 def self.md_add_to_static_continuation_points func, next_id
82 func.metadata[:static_continuation_point] ||= []
83 func.metadata[:static_continuation_point] << next_id
86 def self.md_add_to_bouncing_cont_points func, next_id
87 func.metadata[:bouncing_continuation_point] ||= []
88 func.metadata[:bouncing_continuation_point] << next_id
91 def self.md_made_scope func
92 func.metadata[:made_scope] = true
95 def self.md_made_scope? func
96 func.metadata[:made_scope]
99 def self.md_init_or_increase_bouncer_count func
100 func.metadata[:func] ||= 0
101 func.metadata[:func] += 1
104 def self.md_unset_made_scope func
105 func.metadata.delete :made_scope
108 def self.md_init_init_func func
109 func.metadata[:init_func] = []
112 def self.md_set_atom_main_label func, atom_main_label
113 func.metadata[:atom_main_label] = atom_main_label
115 def self.md_get_statically_dispatches_to func
116 func.metadata[:statically_dispatches_to]
119 def self.md_get_static_continuation_point func
120 func.metadata[:static_continuation_point]
123 def self.md_get_slow_dispatches func
124 func.metadata[:slow_dispatch_to]
127 def self.md_set_last_hit_count func, count
128 func.metadata[:last_hit_count] = count
131 def self.md_inc_rebuild_count func
132 rebuild_count = func.metadata[:rebuild_count] || 0
133 func.metadata[:rebuild_count] = rebuild_count + 1
136 def self.md_get_num_params func
137 func.metadata[:num_params]
140 def self.md_get_prev_id func
141 func.metadata[:prev_id]
144 def self.md_get_was_generated_by func
145 func.metadata[:was_generated_by]
148 def self.md_get_creates_bouncer_to func
149 func.metadata[:creates_bouncer_to]
152 def self.md_get_next_ids func
153 func.metadata[:next_ids]
156 def self.md_has_slow_dispatches func
157 func.metadata.has_key? :slow_dispatch_to
160 def self.md_get_next_id func
161 func.metadata[:next_id]
164 def self.md_get_last_hit_count func
165 func.metadata[:last_hit_count]
168 def self.md_get_assumptions func
169 func.metadata[:assumptions]
172 def self.md_get_generated_by func
173 func.metadata[:bouncer_generated_by]
176 def self.md_set_generated_by func, bouncer_generated_by
177 func.metadata[:bouncer_generated_by] = bouncer_generated_by
180 def self.md_has_no_bouncer_generated_annotation func
181 func.metadata[:bouncer_generated_by].nil?
184 def self.md_has_init_func func
185 func.metadata.has_key?(:init_func)
188 def self.md_is_not_real? func
189 (func.metadata[:assumptions].include? [:not_real])
192 def self.md_mark_not_real func
193 func.metadata[:assumptions] << [:not_real]
196 def self.md_no_assumptions? func
197 (func.metadata[:assumptions].empty?)
200 def self.md_not_all_static_lookups? func
201 (func.metadata[:lookup_for] and !func.metadata[:lookup_for].empty?)
204 # currently no setter!
205 def self.md_optimal_return? func
206 (!func.metadata[:optimal_return].nil? and func.metadata[:optimal_return] == true)
209 def self.md_lookups func
210 func.metadata[:lookup_for]
213 def self.md_atom_main_label func
214 func.metadata[:atom_main_label]
217 def self.md_set_with_initial func, symbol, initial, &new_value
218 func.metadata[symbol] ||= initial
219 func.metadata[symbol] = (new_value.call func.metadata[symbol])
222 def self.md_force_data_inspect func
223 func.metadata[:force_data_inspect] = true
226 def self.md_forced_data_inspect func
227 func.metadata[:force_data_inspect]
230 def self.md_set_create_scope_template func, scope
231 func.metadata[:create_scope_template] = scope
234 def self.metadata_filter notes
235 notes.reject { |(a,b)| (a == :caller_map) }
238 def self.md_inspect notes
239 (self.metadata_filter notes).inspect
244 class ProfilingFunction < Function
245 attr_accessor :mem_ctx
251 path_range = ProfFuncWithMd::md_get_path_range(@func).inspect
252 "PFunction::[#{path_range}]- #{ProfFuncWithMd::md_inspect @func.metadata}>"
254 def self.record_hit func, str
255 top_val = ProfFuncWithMd::md_init_and_add_to_caller_map_and_return_size func, str
256 func.insn_hit NN::mk_constant(func, :int, top_val)
258 instance_methods.each {
260 conditional = (meth =~ /insn_/ and meth != "insn_hit")
262 define_method(meth) {
264 fail "no mem_ctx!!!" unless mem_ctx
265 appending_not_hacking = (@func.pos == @func.size)
266 if appending_not_hacking and $profile
267 ProfilingFunction.record_hit(@func, (caller[1..1].join ", "))
269 if appending_not_hacking and meth == "insn_call_indirect_vtable_blah"
270 trace_stack_ptr = Value.new
271 self.insn_load_elem trace_stack_ptr, mem_ctx.stack_mem,
272 NN::mk_constant(self, :int, 7), :void_ptr
273 trace_stack = RbStack.new self, trace_stack_ptr, :alt
274 old_func_ptr, new_func_ptr = Value.new, Value.new
275 self.insn_load_elem new_func_ptr, mem_ctx.stack_mem,
276 NN::mk_constant(self, :int, 8), :void_ptr
277 self.insn_load_elem old_func_ptr, mem_ctx.stack_mem,
278 NN::mk_constant(self, :int, 9), :void_ptr
279 trace_stack.push new_func_ptr, old_func_ptr
289 Annotation = Struct.new :type
294 attr_accessor :path, :sexp_elt, :curr_id
295 def initialize crawler, path2anon_block, curr_id
298 @path = crawler.id2path curr_id
299 @sexp_elt = crawler.find_path_sexp @path
301 @path2anon_block = path2anon_block
304 @anon_block = @path2anon_block[@path] if @anon_block == Unset
317 elt.is_a? Array and elt[0].is_a? Symbol
327 def self.translate src
328 RubyParser.new.parse(src)
333 attr_accessor :ast, :id2path_hash
335 @sexp = ast_hacks sexp
338 preload_ast @sexp, []
339 @id2path_hash[@id2path_hash.length] = []
342 insides = sexp.sexp_body.map { |elt| is_a_sexp?(elt) ? ast_hacks(elt) : elt }
343 # turn blocks with > 2 children into [:block, child1, [:block, child2, child3]]
344 if sexp.first == :block && sexp[1].first == :dasgn_curr
345 # emulate legacy node, not produced by ParseTree and can probably be removed later on
347 s(:dasgn_curr_hacked, sexp[1][1], nil),
348 (ast_hacks s(:block, s(:dasgn_curr_hacked, *sexp[1][1..-1]), *sexp[2..-1])))
349 elsif sexp.first == :block && sexp.length > 3 # when more than two elements in block
350 return s(:block, insides[0], ast_hacks(s(:block, *sexp[2..-1])))
351 elsif sexp.first == :scope
352 return s(:scope, [], *insides)
353 elsif sexp.first == :class
354 return s(:class, s(:colon2, nil, sexp[1]), *insides[1..-1])
355 elsif sexp.first == :while
356 return s(:while, *insides[0..-2])
357 elsif sexp.first == :defn
358 blocks = sexp[2][1][2..-1]
360 blocks = [ast_hacks(s(:block, *blocks))]
362 return s(:defn_hacked, insides[0], sexp[2][1][1].sexp_body.to_a, *blocks)
364 return s(sexp.first, *insides)
367 def self.find_subpaths path_list, subpath_root, inclusive = false
368 bench("find_subpaths") {
369 return path_list.find_all {
371 prefix = path.slice 0, subpath_root.length
372 (path.length > subpath_root.length) \
373 and (prefix === subpath_root)
374 } + (inclusive ? [subpath_root] : [])
377 def preload_ast sexp, path
378 # puts "preload_ast: #{path.inspect}: #{ast.inspect}\n\t: #{sexp.inspect}"
379 rest = (sexp.empty?) ? [] : sexp[1..-1]
380 s_order_arr = rest.inject([]) { |oarr, elt| oarr << [elt, oarr.size]; oarr }
381 s_order_arr << s_order_arr.slice!(0) if (sexp.first == :call)
384 new_path = path + [idx]
385 if inner_sexp.class.to_s =~ /(Sexp|Array)/
386 preload_ast inner_sexp, new_path
387 if (sexp.first == :call) and idx == 0 # push before the first param
389 assoc_path = path + [-1]
390 fail "already associated something with #{assoc_path.inspect}" if @associated.has_key? assoc_path
391 @associated[assoc_path] = :push_block
392 @id2path_hash[@id2path_hash.length] = assoc_path
395 @id2path_hash[@id2path_hash.length] = new_path
397 if [:vcall,:fcall].include? sexp.first
399 assoc_path = path + [-1]
400 fail "already associated something with #{assoc_path.inspect}" if @associated.has_key? assoc_path
401 @associated[assoc_path] = :push_block
402 @id2path_hash[@id2path_hash.length] = assoc_path
406 @id2path_hash.index path
411 def find_path_sexp to_find, sexp = nil, path = nil
412 # puts "sexp finding:#{to_find.inspect} child-of:#{sexp.inspect} current:#{path.inspect}"
413 return @associated[to_find] if @associated.has_key? to_find
414 sexp = @sexp if sexp.nil?
415 path = [] if path.nil?
416 return sexp if to_find.empty?
417 arr = is_a_sexp?(sexp) ? sexp.sexp_body : sexp
418 arr.each_with_index {
420 # if the current element of to_find == the current idx
421 if idx == to_find[path.length]
422 if (path.length + 1) == to_find.length
425 return find_path_sexp(to_find, inner_sexp, path + [idx])
429 raise "couldn't find index! find:#{to_find.inspect} childof:#{sexp.inspect} curr:#{path.inspect}"
431 def paths2orderdesc paths
435 #{path.inspect} (#{path2id path}),
436 # => #{find_path_sexp(path).inspect}
444 attr_accessor :ast_id
445 def initialize ast_id
448 def hits_for_id func, slow_id
449 idx = ProfFuncWithMd::md_find_in_caller_map func, slow_id
450 idx.nil? ? 0 : func.profile_hash[idx]
452 def id_hit? old_functions, get_count = false
456 next if ProfFuncWithMd::md_get_path_range(func).nil? or func.profile_hash.nil?
457 if ProfFuncWithMd::md_get_path_range(func).include? @ast_id
458 count += hits_for_id func, @ast_id
459 break if !get_count and count > 0
462 get_count ? count : (count > 0)
466 class LoggedHash < Hash
471 puts cyan("Hash::#{@name} -- setting key #{a.inspect} with value #{b.inspect}")
476 puts cyan("Hash::#{@name} -- (key #{a} -> #{tmp})")
482 def self.mk_type func, type_sym
483 fail "sorry #{type_sym.inspect} is an invalid type!" unless Typing::ID_MAP.has_key? type_sym
484 return mk_constant(func, :int, Typing::ID_MAP[type_sym])
486 def self.mk_constant func, constant_type, integer
487 return_value = Value.new
488 func.fill_value_with_constant return_value, constant_type, integer
491 def self.mk_bytearray func, length
493 func.fill_value_with_constant size, :int, length
494 alloced_global_addr = Value.new
495 func.insn_call_alloc_bytearray alloced_global_addr, size
502 :nil, :bool, :int, :type, :block, :const, :bytearray, :undef, :multi_arg
503 ].inject({}) { |h,s| h.merge({s=>h.size+1}) }
507 CHAR = proc { |id| id.chr }
508 ID = proc { |id| id.id2name }
509 NULL = proc { |id| id.to_s }
510 TYPE = proc { |type_id| Typing::ID_MAP.index(type_id).to_s }
513 RuntimePrintCallback = Struct.new :postproc, :value # rename - RuntimePrinter
516 $message_hash, $message_hash_post_proc = {}, {}
518 def self.add_message id, string, &block
519 $message_hash[id] = string
521 $message_hash_post_proc[id] = block
525 def self.runtime_print_string func, *values, &block
526 if values.first.is_a? Symbol
527 stream = values.shift
528 return unless check_dbg(stream)
530 # puts "GOING TO ADD SOMETHING ARGH! - #{values.inspect}"
531 values.unshift "RT: " if $debug
534 if value.is_a? String
535 DebugLogger::add_message value.object_id, value, &block
536 func.insn_call_print_int NN::mk_constant(func, :int, value.object_id)
537 elsif value.is_a? RuntimePrintCallback
538 DebugLogger::add_message value.postproc.object_id, "", &value.postproc
539 func.insn_call_print_int NN::mk_constant(func, :int, value.postproc.object_id)
541 func.insn_call_print_int value.value
543 func.insn_call_print_int NN::mk_constant(func, :int, 0)
546 DebugLogger::add_message value.object_id, "", &PostProcs::NULL
547 func.insn_call_print_int NN::mk_constant(func, :int, value.object_id)
548 func.insn_call_print_int value
555 attr_accessor :stack_mem, :return_stack_mem, :all_locals_mem,
556 :locals_mem, :return_rbstack, :locals_dict
557 def initialize stack_mem, return_stack_mem, all_locals_mem, locals_mem
558 @stack_mem, @return_stack_mem, @all_locals_mem, @locals_mem = \
559 stack_mem, return_stack_mem, all_locals_mem, locals_mem
562 @return_rbstack.flush if @return_rbstack
563 @locals_dict.flush if @locals_dict
566 (!@return_rbstack.nil? || !@locals_dict.nil?)
572 ARGV.include? "--right"
575 ARGV.include? "--left"
589 def initialize func, mem, sym, clever = false
591 @func, @mem, @sym, @clever = func, mem, sym, clever
592 @clever = false if (ARGV.include? "--slow")
600 fail "push_stack called with an already used stack!?" unless @virtual_stack.empty?
601 @virtual_stack = stack
606 name = "return_stack"
607 postproc = PostProcs::TYPE
610 postproc = PostProcs::NULL
612 return name, postproc
615 puts "push_to_stack - #{caller[0..1].join " -- "}" if check_dbg(:rt_primitives)
617 # puts "#{self}: PUSHING on to the stack"
618 @virtual_stack.push [value, type]
619 # puts "#{self}: virtual stack -> #{@virtual_stack.inspect}"
624 def push_raw value, type
626 orig_stack_position = Value.new
627 @func.insn_load_elem orig_stack_position, @mem, NN::mk_constant(@func, :int, 0), :int
629 @func.insn_add temp, orig_stack_position, NN::mk_constant(@func, :int, 1)
630 @func.insn_store_elem @mem, temp, value
632 @func.insn_add temp, orig_stack_position, NN::mk_constant(@func, :int, 2)
633 @func.insn_store_elem @mem, temp, type
634 if check_dbg(:rt_stack)
635 name, postproc = stack_sym_info
636 DebugLogger::runtime_print_string @func, name, ".push( ", temp, " => ", value,
637 " : type ", RuntimePrintCallback.new(postproc, type), " )\n"
639 @func.insn_store_elem @mem, NN::mk_constant(@func, :int, 0), temp
643 puts "pop_from_stack - #{caller.first}" if check_dbg(:rt_primitives)
645 if @virtual_stack.empty?
646 # TODO - find out if its valid that this is frequently the clause followed true!
647 # puts "#{self}: POPPING from below the stack!"
649 # puts "#{self}: A Normal Pop"
650 value, type = *(@virtual_stack.pop)
651 # puts "#{self}: virtual stack -> #{@virtual_stack.inspect}"
656 orig_stack_position, type, value = Value.new, Value.new, Value.new
657 @func.insn_load_elem orig_stack_position, @mem, NN::mk_constant(@func, :int, 0), :int
658 # FIXME - rename temp to new_position
661 @func.insn_load_elem type, @mem, orig_stack_position, :int
662 @func.insn_sub temp, orig_stack_position, NN::mk_constant(@func, :int, 1)
663 @func.insn_load_elem value, @mem, temp, :int
664 @func.insn_sub temp, orig_stack_position, NN::mk_constant(@func, :int, 2)
665 if check_dbg(:rt_stack)
666 name, postproc = stack_sym_info
667 zero = NN::mk_constant(@func, :int, 0)
668 lt_result = Value.new
669 skip_fail = Label.new
670 DebugLogger::runtime_print_string @func, name, ".pop( ", temp, " => ", value,
671 " : type ", RuntimePrintCallback.new(postproc, type), " )\n"
672 @func.insn_lt lt_result, temp, zero
673 @func.insn_branch_if_not lt_result, skip_fail
675 @func.insn_label skip_fail
677 @func.insn_store_elem @mem, NN::mk_constant(@func, :int, 0), temp
682 # puts "#{self}: PUSHING exit stack [#{@virtual_stack.inspect}] - #{caller.first}"
683 @virtual_stack.each { |top| push_raw *top }
689 attr_reader :position, :type
690 def initialize position, type
691 @position, @type = position, type
695 func.insn_load_elem tmp, mem, NN::mk_constant(func, :int, @position), @type
698 def store func, mem, value
699 func.insn_store_elem mem, NN::mk_constant(func, :int, @position), value
703 TypedLocal = Struct.new :value, :type
707 attr_accessor :func, :scope_linkage, :mem_ctx, :scope_ast_id, :needs_new_scope
708 FIELD__CURRENT_SCOPE_ID = FieldDesc.new 1, :int # stack_mem
709 def initialize eval_ctx, func, scope_linkage, mem_ctx
710 idbg(:dbg_dictlookup) { magenta("----------- DICTIONARY CREATED -----------") }
711 @eval_ctx, @func, @scope_linkage, @mem_ctx = eval_ctx, func, scope_linkage, mem_ctx
713 @switched, @taken = false, false
714 @needs_new_scope = false
716 def get_scope_from_id func, mem_ctx, current_scope_id
718 idx_into_scopesstack = Value.new
719 func.insn_add idx_into_scopesstack, current_scope_id, NN::mk_constant(func, :int, 1)
720 func.insn_load_elem mem_tmp, mem_ctx.all_locals_mem, idx_into_scopesstack, :void_ptr
721 DebugLogger::runtime_print_string func, :dict_lookup, "LOADED THE CURRENT SCOPE - ",
722 current_scope_id, " (", mem_tmp , ")\n"
726 fail "erm. locals_mem was already set!" if !mem_ctx.locals_mem.nil?
727 scope_mem, new_scope_id = @eval_ctx.create_new_scope @func, @mem_ctx, @scope_ast_id
728 FIELD__CURRENT_SCOPE_ID.store @func, @mem_ctx.stack_mem, new_scope_id
729 mem_ctx.locals_mem = scope_mem
730 @needs_new_scope = false
733 def load_current_scope
734 fail "erm. locals_mem was already set!" if !mem_ctx.locals_mem.nil?
735 current_scope_id = FIELD__CURRENT_SCOPE_ID.load func, mem_ctx.stack_mem
736 mem_tmp = get_scope_from_id(func, mem_ctx, current_scope_id)
737 mem_ctx.locals_mem = mem_tmp
740 return if @needs_new_scope
741 idbg(:dbg_dictlookup) { magenta("----------- CREATING SCOPE -----------") }
744 raw_assign_value sym, local.value, local.type
747 def assign_value local_sym, popped_int, type
748 fail "sorry, you switched scope and then tried to use it directly after!" if @switched
749 idbg(:dbg_dictlookup) { magenta("----------- #{local_sym} := <> -----------") }
750 if not (@temps.has_key? local_sym)
751 @temps[local_sym] = TypedLocal.new Value.new, Value.new
752 @func.create_local @temps[local_sym].value, :int
753 @func.create_local @temps[local_sym].type, :int
755 @func.insn_store @temps[local_sym].value, popped_int
756 @func.insn_store @temps[local_sym].type, type
758 def raw_assign_value local_sym, popped_int, type, mem = nil
759 mem ||= @mem_ctx.locals_mem
761 DebugLogger::runtime_print_string @func, :rt_assign, "new value created successfully!\n"
763 current_idx = DictHelpers::lookup_id_in_dict(@eval_ctx, @func,
764 local_sym.to_i, mem, @scope_linkage, &create)
766 @func.insn_store_elem mem, current_idx, popped_int
767 @func.insn_add temp, current_idx, NN::mk_constant(@func, :int, 1)
768 @func.insn_store_elem mem, temp, type
769 if check_dbg(:rt_assign)
770 type_sym = RuntimePrintCallback.new(PostProcs::TYPE, type)
771 DebugLogger::runtime_print_string @func,
772 "conditionally popping and locally assigning a value (",
773 popped_int, ":", type_sym, ") to: #{local_sym} in mem ", mem, "\n"
776 def load_local_var dict_id
777 fail "sorry, you switched scope and then tried to use it directly after!" if @switched
778 idbg(:dbg_dictlookup) { magenta("----------- #{dict_id} == ? -----------") }
779 if @temps.has_key? dict_id
780 return @temps[dict_id].value, @temps[dict_id].type
782 return raw_load_local_var(dict_id)
785 def raw_load_local_var dict_id
787 DebugLogger::runtime_print_string @func, "#{dict_id.to_s} not found in scope (",
788 @mem_ctx.locals_mem, ") - NB. this can cause creation of the item as nil\n"
789 @eval_ctx.gen_data_inspect @func, @mem_ctx
790 @func.insn_return NN::mk_constant(@func, :int, 911)
792 current_idx = DictHelpers::lookup_id_in_dict(@eval_ctx, @func, dict_id.to_i,
793 @mem_ctx.locals_mem, @scope_linkage, &access)
794 addr_plus_one, proc_addr, type = Value.new, Value.new, Value.new
795 @func.insn_load_elem proc_addr, @mem_ctx.locals_mem, current_idx, :int
796 @func.insn_add addr_plus_one, current_idx, NN::mk_constant(@func, :int, 1)
797 @func.insn_load_elem type, @mem_ctx.locals_mem, addr_plus_one, :int
798 return proc_addr, type
800 def switch_to_scope_with_id func, scope_val, mem_ctx
801 FIELD__CURRENT_SCOPE_ID.store func, mem_ctx.stack_mem, scope_val
805 create_scope if @needs_new_scope
807 def take_scope_id func, mem_ctx
808 # at this point a delayed scope creation must actually be
809 # performed in order that we have a newly allocated scope id
811 return create_scope if @needs_new_scope
812 return FIELD__CURRENT_SCOPE_ID.load(func, mem_ctx.stack_mem)
816 Hints = Struct.new(:opt_call_cnt, :opt_call_dst, :opt_call_src)
821 self.send("#{key}=".to_sym, val)
828 def self.append_to_dict func, dict_mem, int_id, state_cache = nil
829 ret, temp, count, temp_mult3, end_byte = Value.new, Value.new, nil, Value.new, Value.new
830 DebugLogger::runtime_print_string func, :rt_find_index, "creating!\n"
831 # dict_mem[0] := dict_mem[0] + 1
833 if state_cache.count_local.nil?
834 count = state_cache.count_local = Value.new
835 func.create_local state_cache.count_local, :int
836 func.insn_load_elem count, dict_mem, NN::mk_constant(func, :int, DICT_LENGTH_IDX), :int
838 count = state_cache.count_local
842 func.insn_load_elem count, dict_mem, NN::mk_constant(func, :int, DICT_LENGTH_IDX), :int
844 func.insn_add temp, count, NN::mk_constant(func, :int, 1)
845 # end_byte = (count * 3) + 1
846 func.insn_mul temp_mult3, count, NN::mk_constant(func, :int, 3)
847 func.insn_add end_byte, temp_mult3, NN::mk_constant(func, :int, 1)
848 # dict_mem[end_byte] = id
849 func.insn_store_elem dict_mem, end_byte, int_id
850 func.insn_add ret, end_byte, NN::mk_constant(func, :int, 1)
852 func.insn_store_elem dict_mem, NN::mk_constant(func, :int, 0), temp
857 def self.lookup_id_in_dict eval_ctx, func, int_id, dict_mem, scope_linkage
858 actual_int_id = int_id
859 if (!int_id.is_a? Value) && $opt_scope_templates
860 scope_hash = eval_ctx.scope_hash
861 idbg(:scope_templates) { "CHECKING IF WE CAN REUSE!!! #{int_id} -> #{int_id.id2name} - " +
862 "#{ProfFuncWithMd::md_inspect func.metadata}\n#{scope_hash.inspect}" }
863 if int_id.id2name.nil?
864 puts "EEK, NO SYMBOL! #{caller[0..2]}"
866 scope_id = ProfFuncWithMd::md_get_path_range(func).first
867 pair_chained_to = scope_linkage.detect { |(k,v)| v.include? scope_id }
869 scope_creation_id = pair_chained_to[0]
870 scope_id = scope_creation_id
872 if scope_hash && scope = scope_hash[scope_id] # FIXME
873 if int_id.id2name && sym = int_id.id2name.to_sym
874 idx = scope.index sym
876 current_byte = 2 + 3*(idx)
877 idbg(:scope_templates) { "using #{sym} -> #{current_byte} : for scope #{scope_id}" }
878 ProfFuncWithMd::md_add_to_static_scope func, scope, scope_id, sym
879 pos_val = NN::mk_constant(func, :int, current_byte)
885 puts "dbg_lookup_id_in_dict - #{caller.first}" if check_dbg(:rt_primitives)
886 int_id = int_id.is_a?(Value) ? int_id : NN::mk_constant(func, :int, int_id)
887 current_byte = Value.new
888 bench("dbg_lookup_id_in_dict") {
889 # predeclare label(s)
890 found, continue_looping, empty = Label.new, Label.new, Label.new
891 temp, end_byte, cond_result, current_id = Value.new, Value.new, Value.new, Value.new, Value.new
892 # end byte := (dict_mem[0] * 3) + 1
893 func.insn_load_elem end_byte, dict_mem, NN::mk_constant(func, :int, 0), :int
894 DebugLogger::runtime_print_string func, :rt_find_index_fine, "len = ", end_byte, "\n"
895 # if (len == 0) goto empty
896 DebugLogger::runtime_print_string func, :rt_find_index_fine, "blub= ", end_byte, "\n"
897 func.insn_eq cond_result, end_byte, NN::mk_constant(func, :int, 0)
898 func.insn_branch_if cond_result, empty
899 func.insn_sub temp, end_byte, NN::mk_constant(func, :int, 1)
900 func.insn_store end_byte, temp
901 DebugLogger::runtime_print_string func, :rt_find_index_fine, "subbibg= ", end_byte, "\n"
902 func.insn_mul temp, end_byte, NN::mk_constant(func, :int, 3)
903 func.insn_store end_byte, temp
904 func.insn_add temp, end_byte, NN::mk_constant(func, :int, 1)
905 func.insn_store end_byte, temp
906 DebugLogger::runtime_print_string func, :rt_find_index_fine, "current_byte = end_byte = ",
908 # set end_byte to 1, we start the search there
909 func.create_local current_byte, :int
910 func.insn_store current_byte, temp
913 loop_again = Label.new
914 func.insn_label loop_again
915 # at_end := (current_byte == initial_byte)
916 func.insn_eq cond_result, current_byte, NN::mk_constant(func, :int, 1)
917 DebugLogger::runtime_print_string func, :rt_find_index_fine, "should finish? == ",
919 # comparable := (dict_mem[current_byte + 0] == int_id)
920 func.insn_load_elem current_id, dict_mem, current_byte, :int
921 id_comparison_result = Value.new
922 func.insn_eq id_comparison_result, current_id, int_id
924 func.insn_branch_if_not id_comparison_result, continue_looping
925 sym = RuntimePrintCallback.new(PostProcs::ID, int_id)
926 DebugLogger::runtime_print_string func, :rt_find_index_fine,
927 "it ", sym, "(", int_id, ") matches! at position ", current_byte, "\n"
928 # current_byte := current_byte + 1
929 func.insn_add temp, current_byte, NN::mk_constant(func, :int, 1)
930 func.insn_store current_byte, temp
932 func.insn_branch found
934 func.insn_label continue_looping
935 # current_byte := current_byte + 3
936 func.insn_sub temp, current_byte, NN::mk_constant(func, :int, 3)
937 # decrement by 3 each time
938 func.insn_store current_byte, temp
940 DebugLogger::runtime_print_string func, :rt_find_index_fine,
941 "checking loop.. (", cond_result, ")\n"
944 func.insn_branch_if_not cond_result, loop_again
945 func.insn_label empty
946 append_temp = DictHelpers::append_to_dict func, dict_mem, int_id
947 func.insn_store current_byte, append_temp
948 # callback to generate more runtime
949 yield func if block_given?
951 # done with looping or found section is finished
952 func.insn_label found
954 if !actual_int_id.is_a? Value
955 DebugLogger::runtime_print_string func,
956 :rt_find_index, "rt lookup for #{actual_int_id.id2name} result pos: ", current_byte, "\n"
957 ProfFuncWithMd::md_add_to_lookup_for_debug func, actual_int_id.id2name
958 DebugLogger::runtime_print_string func,
959 :rt_data_inspect_force, "forcing data inspect, due to lookup of #{actual_int_id.id2name}\n"
961 ProfFuncWithMd::md_force_data_inspect func
967 CACHE_FILE = "/tmp/rubydium.pstore"
969 def self.save_cache machine
970 y = PStore.new CACHE_FILE
972 y['cache_id'] = machine.cache_id
973 y['scope_hash'] = machine.scope_hash
974 y['node2type_cache'] = machine.node2type_cache
975 y['scope_linkage'] = machine.scope_linkage
976 if dbg_on :cache_store
983 def self.load_cache machine
985 y = PStore.new CACHE_FILE
987 return false if machine.cache_id != y['cache_id'] or (ARGV.include? "--ignore-cache")
988 machine.scope_hash = y['scope_hash']
989 machine.node2type_cache = y['node2type_cache']
990 machine.scope_linkage = y['scope_linkage']
991 if dbg_on :cache_store
997 puts "FAILURE LOADING CACHE - REMOVING"
998 File.delete(CACHE_FILE)
1006 DictAppendCache = Struct.new :count_local