module Virtual # Think flowcharts: blocks are the boxes. The smallest unit of linear code # Blocks must end in control instructions (jump/call/return). # And the only valid argument for a jump is a Block # Blocks form a graph, which is managed by the method class Block def initialize(name , method ) super() @method = method raise "Method is not Method, but #{method.class}" unless method == :__init__ or method.is_a?(Parfait::Method) @name = name.to_sym @branch = nil @codes = [] end attr_reader :name , :codes , :method , :position attr_accessor :branch def add_code kode @codes << kode self end # replace a code with an array of new codes. This is what happens in passes all the time def replace code , new_codes index = @codes.index code raise "Code not found #{code} in #{self}" unless index @codes.delete_at(index) if( new_codes.is_a? Array) new_codes.reverse.each {|c| @codes.insert(index , c)} else @codes.insert(index , new_codes) end end # returns if this is a block that ends in a call (and thus needs local variable handling) def call_block? raise "called" return false unless codes.last.is_a?(CallInstruction) return false unless codes.last.opcode == :call codes.dup.reverse.find{ |c| c.is_a? StackInstruction } end # position is what another block uses to jump to. this is determined by the assembler # the assembler allso assembles and assumes a linear instruction sequence # Note: this will have to change for plocks and maybe anyway. def set_position at @position = at @codes.each do |code| begin code.set_position( at) rescue => e puts "BLOCK #{self.to_s[0..5000]}" raise e end raise code.inspect unless code.byte_length at += code.byte_length end end def byte_length @codes.inject(0){|count , instruction| count += instruction.byte_length } end # def reachable ret = [] # add_next ret # add_branch ret # ret # end # # helper for determining reachable blocks # def add_next ret # return if @next.nil? # return if ret.include? @next # ret << @next # @next.reachable ret # end # # helper for determining reachable blocks # def add_branch ret # return if @branch.nil? # return if ret.include? @branch # ret << @branch # @branch.reachable ret # end end end