rubyx/lib/virtual/block.rb

92 lines
2.5 KiB
Ruby
Raw Normal View History

module Virtual
2015-05-13 11:22:51 +02:00
# Think flowcharts: blocks are the boxes. The smallest unit of linear code
2015-05-13 11:22:51 +02:00
# 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
2015-05-13 11:22:51 +02:00
2015-05-24 19:00:11 +02:00
class Block
def initialize(name , method )
super()
@method = method
2015-07-26 17:28:39 +02:00
raise "Method is not Method, but #{method.class}" unless method == :dummy or method.is_a?(Parfait::Method)
@name = name.to_sym
@branch = nil
@codes = []
end
2015-06-09 11:38:03 +02:00
attr_reader :name , :codes , :method , :position
attr_accessor :branch
2015-05-13 11:22:51 +02:00
def reachable ret = []
add_next ret
add_branch ret
ret
end
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?
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
2015-05-24 19:00:11 +02:00
# Note: this will have to change for plocks and maybe anyway.
def set_position at
@position = at
@codes.each do |code|
2015-05-24 19:00:11 +02:00
begin
code.set_position( at)
rescue => e
2015-05-25 17:48:35 +02:00
puts "BLOCK #{self.to_s[0..5000]}"
2015-05-24 19:00:11 +02:00
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
private
2015-05-13 11:22:51 +02:00
# helper for determining reachable blocks
def add_next ret
return if @next.nil?
return if ret.include? @next
ret << @next
@next.reachable ret
end
2015-05-13 11:22:51 +02:00
# 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
2015-05-13 11:22:51 +02:00
end