fold position module and object position
simpler that way, aslo code is moving to listners
This commit is contained in:
@ -1,79 +1,59 @@
|
||||
module Risc
|
||||
module Position
|
||||
|
||||
# BinaryCodes form a linked list
|
||||
#
|
||||
# We want to keep all code for a method continous, so we propagate Positions
|
||||
#
|
||||
# At the end of the list the propagation spills into the next methods
|
||||
# binary and so on
|
||||
#
|
||||
class CodeListener
|
||||
# BinaryCodes form a linked list
|
||||
#
|
||||
# We want to keep all code for a method continous, so we propagate Positions
|
||||
#
|
||||
# At the end of the list the propagation spills into the next methods
|
||||
# binary and so on
|
||||
#
|
||||
class CodeListener
|
||||
|
||||
attr_reader :code , :method
|
||||
attr_reader :code , :method
|
||||
|
||||
def initialize(code , method)
|
||||
super(code,pos)
|
||||
@code = code
|
||||
@method = method
|
||||
raise "Method nil" unless method
|
||||
def initialize(code , method)
|
||||
super(code,pos)
|
||||
@code = code
|
||||
@method = method
|
||||
raise "Method nil" unless method
|
||||
end
|
||||
def set(at )
|
||||
next_pos = at + code.padded_length
|
||||
if code.next
|
||||
Position.set(code.next , next_pos, method)
|
||||
set_jump(at)
|
||||
else
|
||||
next_meth = next_method
|
||||
return unless next_meth
|
||||
Position.set( next_meth.binary , next_pos , next_meth)
|
||||
next_cpu_pos = next_pos + Parfait::BinaryCode.byte_offset
|
||||
Position.set( next_meth.cpu_instructions, next_cpu_pos , next_meth.binary)
|
||||
end
|
||||
def set(at )
|
||||
next_pos = at + code.padded_length
|
||||
end
|
||||
|
||||
# insert a jump to the next instruction, at the last instruction
|
||||
# thus hopping over the object header
|
||||
def set_jump(at)
|
||||
jump = Branch.new("BinaryCode #{at.to_s(16)}" , code.next)
|
||||
translator = Risc.machine.platform.translator
|
||||
cpu_jump = translator.translate(jump)
|
||||
pos = at + code.padded_length - cpu_jump.byte_length
|
||||
Position.set( cpu_jump , pos , code)
|
||||
cpu_jump.assemble(JumpWriter.new(code))
|
||||
end
|
||||
|
||||
def self.init( code , at = -1)
|
||||
while code
|
||||
position = Position.new(code , at)
|
||||
Position.set_to(position , at)
|
||||
if code.next
|
||||
Position.set(code.next , next_pos, method)
|
||||
set_jump(at)
|
||||
else
|
||||
next_meth = next_method
|
||||
return unless next_meth
|
||||
Position.set( next_meth.binary , next_pos , next_meth)
|
||||
next_cpu_pos = next_pos + Parfait::BinaryCode.byte_offset
|
||||
Position.set( next_meth.cpu_instructions, next_cpu_pos , next_meth.binary)
|
||||
listener = PositionListener.new(code.next)
|
||||
position.register_event(:position_changed , listener)
|
||||
end
|
||||
at += code.padded_length unless at < 0
|
||||
code = code.next
|
||||
end
|
||||
|
||||
# insert a jump to the next instruction, at the last instruction
|
||||
# thus hopping over the object header
|
||||
def set_jump(at)
|
||||
jump = Branch.new("BinaryCode #{at.to_s(16)}" , code.next)
|
||||
translator = Risc.machine.platform.translator
|
||||
cpu_jump = translator.translate(jump)
|
||||
pos = at + code.padded_length - cpu_jump.byte_length
|
||||
Position.set( cpu_jump , pos , code)
|
||||
cpu_jump.assemble(JumpWriter.new(code))
|
||||
end
|
||||
|
||||
def next_method
|
||||
next_m = @method.next_method
|
||||
return next_m if next_m
|
||||
Position.log.debug "Type now #{@method.for_type.name}"
|
||||
type = next_type(@method.for_type)
|
||||
if type
|
||||
Position.log.debug "Position for #{type.name}"
|
||||
return type.methods
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
def next_type(type)
|
||||
nekst = Parfait.object_space.types.next_value(type)
|
||||
return nil unless nekst
|
||||
return nekst if nekst.methods
|
||||
return next_type(nekst)
|
||||
end
|
||||
def self.init( code , at = -1)
|
||||
while code
|
||||
position = ObjectPosition.new(code , at)
|
||||
Position.set_to(position , at)
|
||||
if code.next
|
||||
listener = ObjectListener.new(code.next)
|
||||
position.register_event(:position_changed , listener)
|
||||
end
|
||||
at += code.padded_length unless at < 0
|
||||
code = code.next
|
||||
end
|
||||
position
|
||||
end
|
||||
position
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,75 +1,72 @@
|
||||
module Risc
|
||||
module Position
|
||||
|
||||
# Instructions are also a linked list, but their position is not really
|
||||
# the position of the object.
|
||||
# Rather it is the position of the assembled code in the binary.
|
||||
# (Luckily arm is sane, so this is realtively simple)
|
||||
#
|
||||
# Really we only need to calculate Positions at a jump, so between the
|
||||
# Jump and the label it jumps too. The other instructions are "just" fill.
|
||||
# But off course we need to propagate positions to get it right.
|
||||
#
|
||||
# Assembled instructions are kept in BinaryCode objects.
|
||||
# When propagating positions we have to see that the next position assembles into
|
||||
# the same BinaryCode, or else move it and the code along
|
||||
#
|
||||
class InstructionListener
|
||||
attr_reader :instruction , :binary
|
||||
def initialize(instruction , binary)
|
||||
pos = 0
|
||||
@instruction = instruction
|
||||
@binary = binary
|
||||
# Instructions are also a linked list, but their position is not really
|
||||
# the position of the object.
|
||||
# Rather it is the position of the assembled code in the binary.
|
||||
# (Luckily arm is sane, so this is realtively simple)
|
||||
#
|
||||
# Really we only need to calculate Positions at a jump, so between the
|
||||
# Jump and the label it jumps too. The other instructions are "just" fill.
|
||||
# But off course we need to propagate positions to get it right.
|
||||
#
|
||||
# Assembled instructions are kept in BinaryCode objects.
|
||||
# When propagating positions we have to see that the next position assembles into
|
||||
# the same BinaryCode, or else move it and the code along
|
||||
#
|
||||
class InstructionListener
|
||||
attr_reader :instruction , :binary
|
||||
def initialize(instruction , binary)
|
||||
pos = 0
|
||||
@instruction = instruction
|
||||
@binary = binary
|
||||
end
|
||||
def init(at, binary)
|
||||
@binary = binary
|
||||
instruction.address.set_value(at) if instruction.is_a?(Label)
|
||||
return if at == 0 and binary.nil?
|
||||
raise "faux pas" if at < Position.get(binary).at
|
||||
return unless @instruction.next
|
||||
nekst = at + @instruction.byte_length
|
||||
diff = nekst - Position.get(@binary).at
|
||||
Position.log.debug "Diff: #{diff.to_s(16)} , next #{nekst.to_s(16)} , binary #{Position.get(@binary)}"
|
||||
raise "Invalid position #{diff.to_s(16)} , next #{nekst.to_s(16)} #{self}" if diff < 8
|
||||
if( (diff % (binary.padded_length - @instruction.byte_length)) == 0 )
|
||||
binary.extend_one unless binary.next
|
||||
binary = binary.next
|
||||
raise "end of line " unless binary
|
||||
nekst = Position.get(binary).at + Parfait::BinaryCode.byte_offset
|
||||
Position.log.debug "Jump to: #{nekst.to_s(16)}"
|
||||
end
|
||||
def init(at, binary)
|
||||
@binary = binary
|
||||
instruction.address.set_value(at) if instruction.is_a?(Label)
|
||||
return if at == 0 and binary.nil?
|
||||
raise "faux pas" if at < Position.get(binary).at
|
||||
return unless @instruction.next
|
||||
nekst = at + @instruction.byte_length
|
||||
diff = nekst - Position.get(@binary).at
|
||||
Position.log.debug "Diff: #{diff.to_s(16)} , next #{nekst.to_s(16)} , binary #{Position.get(@binary)}"
|
||||
raise "Invalid position #{diff.to_s(16)} , next #{nekst.to_s(16)} #{self}" if diff < 8
|
||||
if( (diff % (binary.padded_length - @instruction.byte_length)) == 0 )
|
||||
binary.extend_one unless binary.next
|
||||
binary = binary.next
|
||||
raise "end of line " unless binary
|
||||
nekst = Position.get(binary).at + Parfait::BinaryCode.byte_offset
|
||||
Position.log.debug "Jump to: #{nekst.to_s(16)}"
|
||||
Position.set(@instruction.next, nekst , binary)
|
||||
end
|
||||
|
||||
def reset_to(pos , binary)
|
||||
super(pos , binary)
|
||||
init(pos , binary)
|
||||
Position.log.debug "ResetInstruction (#{pos.to_s(16)}) #{instruction}"
|
||||
end
|
||||
|
||||
# initialize the dependency graph for instructions
|
||||
#
|
||||
# starting from the given instruction, create Positions
|
||||
# for it and the whole chain. Then attach InstructionListeners
|
||||
# for dependency tracking. All positions are initialized with -1
|
||||
# and so setting the first will trigger a chain reaction
|
||||
#
|
||||
# return the position for the first instruction which may be used to
|
||||
# set all positions in the chain
|
||||
def self.init( instruction , code )
|
||||
first = nil
|
||||
while(instruction)
|
||||
position = Position.new(instruction , -1)
|
||||
first = position unless first
|
||||
nekst = instruction.next
|
||||
if nekst
|
||||
listener = InstructionListener.new( nekst , code )
|
||||
position.register_event(:position_changed , listener)
|
||||
end
|
||||
Position.set(@instruction.next, nekst , binary)
|
||||
end
|
||||
|
||||
def reset_to(pos , binary)
|
||||
super(pos , binary)
|
||||
init(pos , binary)
|
||||
Position.log.debug "ResetInstruction (#{pos.to_s(16)}) #{instruction}"
|
||||
end
|
||||
|
||||
# initialize the dependency graph for instructions
|
||||
#
|
||||
# starting from the given instruction, create ObjectPositions
|
||||
# for it and the whole chain. Then attach InstructionListeners
|
||||
# for dependency tracking. All positions are initialized with -1
|
||||
# and so setting the first will trigger a chain reaction
|
||||
#
|
||||
# return the position for the first instruction which may be used to
|
||||
# set all positions in the chain
|
||||
def self.init( instruction , code )
|
||||
first = nil
|
||||
while(instruction)
|
||||
position = ObjectPosition.new(instruction , -1)
|
||||
first = position unless first
|
||||
nekst = instruction.next
|
||||
if nekst
|
||||
listener = InstructionListener.new( nekst , code )
|
||||
position.register_event(:position_changed , listener)
|
||||
end
|
||||
instruction = nekst
|
||||
end
|
||||
first
|
||||
instruction = nekst
|
||||
end
|
||||
first
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,31 +1,29 @@
|
||||
|
||||
module Risc
|
||||
module Position
|
||||
|
||||
# Listeners localise the changes that need to happen.
|
||||
# Listeners localise the changes that need to happen.
|
||||
#
|
||||
# An object listener assmes it is set up to the previous object.
|
||||
# so when position changes, it places itself just behind the previous object
|
||||
#
|
||||
# This is handy, since the "normal" chaining of object is forward
|
||||
# But the dependencies are backwards. This way we don't clutter the
|
||||
# actual object (or even the position), but keep the logic seperate.
|
||||
class PositionListener
|
||||
|
||||
# initialize with the object that needs to react to change
|
||||
def initialize(object)
|
||||
@object = object
|
||||
end
|
||||
|
||||
# when the argument changes position, we update the objects
|
||||
# position to reflect that change
|
||||
#
|
||||
# An object listener assmes it is set up to the previous object.
|
||||
# so when position changes, it places itself just behind the previous object
|
||||
#
|
||||
# This is handy, since the "normal" chaining of object is forward
|
||||
# But the dependencies are backwards. This way we don't clutter the
|
||||
# actual object (or even the position), but keep the logic seperate.
|
||||
class ObjectListener
|
||||
|
||||
# initialize with the object that needs to react to change
|
||||
def initialize(object)
|
||||
@object = object
|
||||
end
|
||||
|
||||
# when the argument changes position, we update the objects
|
||||
# position to reflect that change
|
||||
#
|
||||
def position_changed(previous)
|
||||
me = previous.at + previous.object.padded_length
|
||||
object_pos = Position.get(@object)
|
||||
return if me == object_pos.at
|
||||
Position.set(@object , me)
|
||||
end
|
||||
def position_changed(previous)
|
||||
me = previous.at + previous.object.padded_length
|
||||
object_pos = Position.get(@object)
|
||||
return if me == object_pos.at
|
||||
Position.set(@object , me)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,60 +0,0 @@
|
||||
require "util/eventable"
|
||||
|
||||
module Risc
|
||||
module Position
|
||||
class ObjectPosition
|
||||
include Util::Eventable
|
||||
|
||||
attr_reader :at , :object
|
||||
|
||||
# initialize with a given object, first parameter
|
||||
# The object ill be the key in global position map
|
||||
# Give an integer as the actual position, where -1
|
||||
# which means no legal position known
|
||||
def initialize(object , pos )
|
||||
@at = pos
|
||||
@object = object
|
||||
Position.set_to(self , pos)
|
||||
end
|
||||
|
||||
#look for InstructionListener and return its code if found
|
||||
def get_code
|
||||
listener = event_table.find{|one| one.class == InstructionListener}
|
||||
return nil unless listener
|
||||
listener.code
|
||||
end
|
||||
def +(offset)
|
||||
offset = offset.at if offset.is_a?(ObjectPosition)
|
||||
@at + offset
|
||||
end
|
||||
|
||||
def -(offset)
|
||||
offset = offset.at if offset.is_a?(ObjectPosition)
|
||||
@at - offset
|
||||
end
|
||||
def to_s
|
||||
"0x#{@at.to_s(16)}"
|
||||
end
|
||||
# just a callback after creation AND insertion
|
||||
def init(pos , is_nil)
|
||||
end
|
||||
def reset_to(pos , guaranteed_nil )
|
||||
return false if pos == at
|
||||
if((at - pos).abs > 1000)
|
||||
raise "position set too far off #{pos}!=#{at} for #{object}:#{object.class}"
|
||||
end
|
||||
@at = pos
|
||||
trigger(:position_changed , self)
|
||||
true
|
||||
end
|
||||
def next_slot
|
||||
return -1 if at < 0
|
||||
at + object.byte_length
|
||||
end
|
||||
def self.init(object , at = -1)
|
||||
position = ObjectPosition.new(object , at)
|
||||
Position.set_to( position , at)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,3 +1,5 @@
|
||||
require "util/eventable"
|
||||
|
||||
module Risc
|
||||
# Positions are very different during compilation and run-time.
|
||||
# At run-time they are inherrent to the object, and fixed.
|
||||
@ -14,10 +16,50 @@ module Risc
|
||||
# While the (different)Position objects transmit the change that (re) positioning
|
||||
# entails to affected objects.
|
||||
|
||||
module Position
|
||||
class Position
|
||||
include Util::Logging
|
||||
log_level :info
|
||||
|
||||
include Util::Eventable
|
||||
|
||||
attr_reader :at , :object
|
||||
|
||||
# initialize with a given object, first parameter
|
||||
# The object ill be the key in global position map
|
||||
# Give an integer as the actual position, where -1
|
||||
# which means no legal position known
|
||||
def initialize(object , pos )
|
||||
@at = pos
|
||||
@object = object
|
||||
Position.set_to(self , pos)
|
||||
end
|
||||
|
||||
#look for InstructionListener and return its code if found
|
||||
def get_code
|
||||
listener = event_table.find{|one| one.class == InstructionListener}
|
||||
return nil unless listener
|
||||
listener.code
|
||||
end
|
||||
|
||||
def +(offset)
|
||||
offset = offset.at if offset.is_a?(Position)
|
||||
@at + offset
|
||||
end
|
||||
|
||||
def -(offset)
|
||||
offset = offset.at if offset.is_a?(Position)
|
||||
@at - offset
|
||||
end
|
||||
def to_s
|
||||
"0x#{@at.to_s(16)}"
|
||||
end
|
||||
|
||||
def next_slot
|
||||
return -1 if at < 0
|
||||
at + object.byte_length
|
||||
end
|
||||
|
||||
## class level forward and reverse cache
|
||||
@positions = {}
|
||||
@reverse_cache = {}
|
||||
|
||||
@ -41,7 +83,7 @@ module Risc
|
||||
def self.get(object)
|
||||
pos = self.positions[object]
|
||||
if pos == nil
|
||||
str = "position accessed but not set, "
|
||||
str = "position accessed but not initialized, "
|
||||
str += "0x#{object.object_id.to_s(16)}\n"
|
||||
str += "for #{object.class} "
|
||||
str += "byte_length #{object.byte_length}" if object.respond_to?(:byte_length)
|
||||
@ -51,16 +93,11 @@ module Risc
|
||||
pos
|
||||
end
|
||||
|
||||
def self.reset(obj)
|
||||
old = self.get(obj)
|
||||
old.reset_to( old.at )
|
||||
end
|
||||
|
||||
def self.set_to( position , to)
|
||||
postest = Position.positions[position.object] unless to < 0
|
||||
postest = Position.positions[position.object] unless to < 0
|
||||
raise "Mismatch #{position}" if postest and postest != position
|
||||
@reverse_cache.delete(position.at) unless position.object.is_a? Label
|
||||
testing = self.at( position.at ) if position.at >= 0
|
||||
testing = self.at( position.at ) unless position.at < 0
|
||||
if testing and testing.class != position.class
|
||||
raise "Mismatch (at #{pos.to_s(16)}) was:#{position} #{position.class} #{position.object} , should #{testing}#{testing.class}"
|
||||
end
|
||||
@ -71,7 +108,6 @@ module Risc
|
||||
end
|
||||
end
|
||||
end
|
||||
require_relative "object_position"
|
||||
require_relative "object_listener"
|
||||
require_relative "instruction_listener"
|
||||
require_relative "code_listener"
|
||||
|
Reference in New Issue
Block a user