fold position module and object position

simpler that way, aslo code is moving to listners
This commit is contained in:
Torsten Ruger 2018-06-02 21:59:41 +03:00
parent 24f6e30b54
commit c2d450f779
17 changed files with 381 additions and 441 deletions

View File

@ -25,7 +25,7 @@ module Arm
super super
my_pos = Risc::Position.get(self) my_pos = Risc::Position.get(self)
# set my position to set next according to rules # set my position to set next according to rules
Risc::Position::InstructionListener.init(instruction , my_pos.get_code) Risc::InstructionListener.init(instruction , my_pos.get_code)
end end
end end
end end

View File

@ -42,7 +42,7 @@ module Parfait
if Risc::Position.set?(self) if Risc::Position.set?(self)
Risc::Position.log.debug "extending one in #{self}" Risc::Position.log.debug "extending one in #{self}"
my_pos = Risc::Position.get(self) my_pos = Risc::Position.get(self)
Risc::Position.reset(my_pos , my_pos.at , my_pos.method) Risc::CodeListener.init( @next , my_pos + self.padded_length)
end end
end end

View File

@ -49,12 +49,12 @@ module Risc
raise "Not int #{pos}" unless pos.is_a? Numeric raise "Not int #{pos}" unless pos.is_a? Numeric
position = Position.at(pos) position = Position.at(pos)
raise "No position #{pos.to_s(16)}" unless position raise "No position #{pos.to_s(16)}" unless position
if position.is_a?(Position::CodePosition) if position.is_a?(CodePosition)
raise "Setting Code #{clock}-#{position}, #{position.method}" raise "Setting Code #{clock}-#{position}, #{position.method}"
#return set_pc(position.at + Parfait::BinaryCode.byte_offset) #return set_pc(position.at + Parfait::BinaryCode.byte_offset)
end end
log.debug "Setting Position #{clock}-#{position}, #{position.binary}" log.debug "Setting Position #{clock}-#{position}, #{position.binary}"
raise "not instruction position #{position}-#{position.class}-#{position.object.class}" unless position.is_a?(Position::InstructionPosition) raise "not instruction position #{position}-#{position.class}-#{position.object.class}" unless position.is_a?(InstructionPosition)
set_instruction( position.instruction ) set_instruction( position.instruction )
@clock += 1 @clock += 1
@pc = position.at @pc = position.at

View File

@ -85,7 +85,7 @@ module Risc
def position_all def position_all
raise "Not translated " unless @translated raise "Not translated " unless @translated
#need the initial jump at 0 and then functions #need the initial jump at 0 and then functions
Position::ObjectPosition.init(cpu_init , -1) Position.init(cpu_init , -1)
code_start = position_objects( @platform.padding ) code_start = position_objects( @platform.padding )
# and then everything code # and then everything code
position_code(code_start) position_code(code_start)
@ -101,8 +101,8 @@ module Risc
sorted.each do | objekt| sorted.each do | objekt|
next if objekt.is_a?( Parfait::BinaryCode) or objekt.is_a?( Risc::Label ) next if objekt.is_a?( Parfait::BinaryCode) or objekt.is_a?( Risc::Label )
before = at before = at
position = Position::ObjectPosition.init(objekt,at) position = Position.init(objekt,at)
previous.register_event(:position_changed , Position::ObjectListener.new(objekt)) if previous previous.register_event(:position_changed , PositionListener.new(objekt)) if previous
previous = position previous = position
at += objekt.padded_length at += objekt.padded_length
log.debug "Object #{objekt.class}:#{before.to_s(16)} len: #{(at - before).to_s(16)}" log.debug "Object #{objekt.class}:#{before.to_s(16)} len: #{(at - before).to_s(16)}"
@ -121,8 +121,8 @@ module Risc
Parfait.object_space.types.values.each do |type| Parfait.object_space.types.values.each do |type|
next unless type.methods next unless type.methods
type.methods.each_method do |method| type.methods.each_method do |method|
last_code = Position::CodeListener.init(method.binary , code_start) last_code = CodeListener.init(method.binary , code_start)
Position::InstructionListener.init(method.cpu_instructions, method.binary) InstructionListener.init(method.cpu_instructions, method.binary)
last_code.register_event(:position_changed , prev_code.object) if prev_code last_code.register_event(:position_changed , prev_code.object) if prev_code
prev_code = last_code prev_code = last_code
code_start = last_code.next_slot code_start = last_code.next_slot

View File

@ -1,5 +1,4 @@
module Risc module Risc
module Position
# BinaryCodes form a linked list # BinaryCodes form a linked list
# #
@ -43,30 +42,12 @@ module Risc
cpu_jump.assemble(JumpWriter.new(code)) cpu_jump.assemble(JumpWriter.new(code))
end 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) def self.init( code , at = -1)
while code while code
position = ObjectPosition.new(code , at) position = Position.new(code , at)
Position.set_to(position , at) Position.set_to(position , at)
if code.next if code.next
listener = ObjectListener.new(code.next) listener = PositionListener.new(code.next)
position.register_event(:position_changed , listener) position.register_event(:position_changed , listener)
end end
at += code.padded_length unless at < 0 at += code.padded_length unless at < 0
@ -76,4 +57,3 @@ module Risc
end end
end end
end end
end

View File

@ -1,6 +1,4 @@
module Risc module Risc
module Position
# Instructions are also a linked list, but their position is not really # Instructions are also a linked list, but their position is not really
# the position of the object. # the position of the object.
# Rather it is the position of the assembled code in the binary. # Rather it is the position of the assembled code in the binary.
@ -49,7 +47,7 @@ module Risc
# initialize the dependency graph for instructions # initialize the dependency graph for instructions
# #
# starting from the given instruction, create ObjectPositions # starting from the given instruction, create Positions
# for it and the whole chain. Then attach InstructionListeners # for it and the whole chain. Then attach InstructionListeners
# for dependency tracking. All positions are initialized with -1 # for dependency tracking. All positions are initialized with -1
# and so setting the first will trigger a chain reaction # and so setting the first will trigger a chain reaction
@ -59,7 +57,7 @@ module Risc
def self.init( instruction , code ) def self.init( instruction , code )
first = nil first = nil
while(instruction) while(instruction)
position = ObjectPosition.new(instruction , -1) position = Position.new(instruction , -1)
first = position unless first first = position unless first
nekst = instruction.next nekst = instruction.next
if nekst if nekst
@ -72,4 +70,3 @@ module Risc
end end
end end
end end
end

View File

@ -1,6 +1,5 @@
module Risc module Risc
module Position
# Listeners localise the changes that need to happen. # Listeners localise the changes that need to happen.
# #
@ -10,7 +9,7 @@ module Risc
# This is handy, since the "normal" chaining of object is forward # This is handy, since the "normal" chaining of object is forward
# But the dependencies are backwards. This way we don't clutter the # But the dependencies are backwards. This way we don't clutter the
# actual object (or even the position), but keep the logic seperate. # actual object (or even the position), but keep the logic seperate.
class ObjectListener class PositionListener
# initialize with the object that needs to react to change # initialize with the object that needs to react to change
def initialize(object) def initialize(object)
@ -28,4 +27,3 @@ module Risc
end end
end end
end end
end

View File

@ -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

View File

@ -1,3 +1,5 @@
require "util/eventable"
module Risc module Risc
# Positions are very different during compilation and run-time. # Positions are very different during compilation and run-time.
# At run-time they are inherrent to the object, and fixed. # 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 # While the (different)Position objects transmit the change that (re) positioning
# entails to affected objects. # entails to affected objects.
module Position class Position
include Util::Logging include Util::Logging
log_level :info 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 = {} @positions = {}
@reverse_cache = {} @reverse_cache = {}
@ -41,7 +83,7 @@ module Risc
def self.get(object) def self.get(object)
pos = self.positions[object] pos = self.positions[object]
if pos == nil 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 += "0x#{object.object_id.to_s(16)}\n"
str += "for #{object.class} " str += "for #{object.class} "
str += "byte_length #{object.byte_length}" if object.respond_to?(:byte_length) str += "byte_length #{object.byte_length}" if object.respond_to?(:byte_length)
@ -51,16 +93,11 @@ module Risc
pos pos
end end
def self.reset(obj)
old = self.get(obj)
old.reset_to( old.at )
end
def self.set_to( position , to) 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 raise "Mismatch #{position}" if postest and postest != position
@reverse_cache.delete(position.at) unless position.object.is_a? Label @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 if testing and testing.class != position.class
raise "Mismatch (at #{pos.to_s(16)}) was:#{position} #{position.class} #{position.object} , should #{testing}#{testing.class}" raise "Mismatch (at #{pos.to_s(16)}) was:#{position} #{position.class} #{position.object} , should #{testing}#{testing.class}"
end end
@ -71,7 +108,6 @@ module Risc
end end
end end
end end
require_relative "object_position"
require_relative "object_listener" require_relative "object_listener"
require_relative "instruction_listener" require_relative "instruction_listener"
require_relative "code_listener" require_relative "code_listener"

View File

@ -1,11 +1,9 @@
require_relative "../helper" require_relative "../helper"
module Risc module Risc
module Position
class Dummy class Dummy
def padded_length def padded_length
4 4
end end
end end
end end
end

View File

@ -1,7 +1,6 @@
require_relative "helper" require_relative "helper"
module Risc module Risc
module Position
# tests that require a boot and test propagation # tests that require a boot and test propagation
class TestcodeListener < MiniTest::Test class TestcodeListener < MiniTest::Test
def setup def setup
@ -17,7 +16,7 @@ module Risc
end end
def test_init_returns_position def test_init_returns_position
assert_equal Position::ObjectPosition , CodeListener.init(@binary).class assert_equal Position , CodeListener.init(@binary).class
end end
def test_init_listner def test_init_listner
@binary.extend_one @binary.extend_one
@ -32,4 +31,3 @@ module Risc
end end
end end
end end
end

View File

@ -11,7 +11,7 @@ module Risc
end end
def test_set_bin def test_set_bin
pos = Position.set( @binary , 0 , @method) pos = Position.set( @binary , 0 , @method)
assert_equal Position::CodePosition , pos.class assert_equal CodePosition , pos.class
end end
def test_type def test_type
pos = Position.set( @binary , 0 , @method) pos = Position.set( @binary , 0 , @method)

View File

@ -1,7 +1,6 @@
require_relative "helper" require_relative "helper"
module Risc module Risc
module Position
# tests that require a boot and test propagation # tests that require a boot and test propagation
class TestInstructionListener < MiniTest::Test class TestInstructionListener < MiniTest::Test
def setup def setup
@ -60,4 +59,3 @@ module Risc
end end
end end
end end
end

View File

@ -1,15 +1,14 @@
require_relative "helper" require_relative "helper"
module Risc module Risc
module Position class TestPositionListener < MiniTest::Test
class TestObjectListener < MiniTest::Test
def setup def setup
@object = Dummy.new @object = Dummy.new
@dependent = Dummy.new @dependent = Dummy.new
@pos = ObjectPosition.new(@object,0) @pos = Position.new(@object,0)
ObjectPosition.new(@dependent,0) Position.new(@dependent,0)
@listener = ObjectListener.new(@dependent) @listener = PositionListener.new(@dependent)
end end
def test_register def test_register
assert @pos.register_event(:position_changed , @listener) assert @pos.register_event(:position_changed , @listener)
@ -26,4 +25,3 @@ module Risc
end end
end end
end end
end

View File

@ -1,89 +0,0 @@
require_relative "helper"
module Risc
module Position
# tests that do no require a boot and only test basic positioning
class TestObjectPosition < MiniTest::Test
def test_init
assert ObjectPosition.init(self , -1)
end
def test_next_slot
mov = Arm::ArmMachine.mov(:r1 , :r1)
position = ObjectPosition.new(mov , 0)
assert_equal 4, position.next_slot
end
def test_has_get_code
assert_nil ObjectPosition.init(self , -1).get_code
end
def pest_creation_ok
assert ObjectPosition.new(self,0)
end
def pest_creation_fail
assert_raises {Position.new("0")}
end
def pest_add
res = ObjectPosition.new(self,0) + 5
assert_equal 5 , res
end
def pest_sub
res = ObjectPosition.new(self,0) - 1
assert_equal -1 , res
end
def pest_sub_pos
res = ObjectPosition.new(self,0) - ObjectPosition.new(self,0)
assert_equal 0 , res
end
def pest_set
pos = Position.set(self , 5)
assert_equal 5 , pos.at
end
def tet_tos
assert_equal "0x10" , Position.set(self).to_s
end
def pest_reset_ok
pos = Position.set(self , 5)
pos = Position.set(self , 10)
assert_equal 10 , pos.at
end
def pest_reset_fail
Position.set(self , 5)
assert_raises{Position.set(self , 10000)}
end
def pest_raises_set_nil
assert_raises { Position.set(self,nil)}
end
def pest_at
pos = Position.set(self , 5)
pos = Position.at(5)
assert_equal 5 , pos.at
end
end
class TestPositionEvents < MiniTest::Test
def setup
@position = ObjectPosition.new(self)
end
def pest_has_register
assert @position.register_event(:position_changed , self)
end
def pest_can_unregister
assert @position.register_event(:position_changed ,self)
assert @position.unregister_event(:position_changed ,self)
end
def pest_fires
@position.register_event(:position_changed ,self)
@position.trigger(:position_changed , @position)
assert_equal @position , @trigger
end
def pest_no_fire_after_unregister
assert @position.register_event(:position_changed ,self)
assert @position.unregister_event(:position_changed ,self)
@position.trigger(:position_changed , @position)
assert_nil @trigger
end
def position_changed(pos)
@trigger = pos
end
end
end
end

View File

@ -1,5 +1,91 @@
require_relative "helper" require_relative "helper"
module Risc
# tests that do no require a boot and only test basic positioning
class TestPosition < MiniTest::Test
def test_new
assert Position.new(self , -1)
end
def test_next_slot
mov = Arm::ArmMachine.mov(:r1 , :r1)
position = Position.new(mov , 0)
assert_equal 4, position.next_slot
end
def test_has_get_code
assert_nil Position.new(self , -1).get_code
end
def pest_creation_ok
assert Position.new(self,0)
end
def pest_creation_fail
assert_raises {Position.new("0")}
end
def pest_add
res = Position.new(self,0) + 5
assert_equal 5 , res
end
def pest_sub
res = Position.new(self,0) - 1
assert_equal -1 , res
end
def pest_sub_pos
res = Position.new(self,0) - Position.new(self,0)
assert_equal 0 , res
end
def pest_set
pos = Position.set(self , 5)
assert_equal 5 , pos.at
end
def tet_tos
assert_equal "0x10" , Position.set(self).to_s
end
def pest_reset_ok
pos = Position.set(self , 5)
pos = Position.set(self , 10)
assert_equal 10 , pos.at
end
def pest_reset_fail
Position.set(self , 5)
assert_raises{Position.set(self , 10000)}
end
def pest_raises_set_nil
assert_raises { Position.set(self,nil)}
end
def pest_at
pos = Position.set(self , 5)
pos = Position.at(5)
assert_equal 5 , pos.at
end
end
class TestPositionEvents < MiniTest::Test
def setup
@position = Position.new(self)
end
def pest_has_register
assert @position.register_event(:position_changed , self)
end
def pest_can_unregister
assert @position.register_event(:position_changed ,self)
assert @position.unregister_event(:position_changed ,self)
end
def pest_fires
@position.register_event(:position_changed ,self)
@position.trigger(:position_changed , @position)
assert_equal @position , @trigger
end
def pest_no_fire_after_unregister
assert @position.register_event(:position_changed ,self)
assert @position.unregister_event(:position_changed ,self)
@position.trigger(:position_changed , @position)
assert_nil @trigger
end
def position_changed(pos)
@trigger = pos
end
end
end
module Risc module Risc
class TestMachinePositions < MiniTest::Test class TestMachinePositions < MiniTest::Test
def setup def setup

View File

@ -51,7 +51,7 @@ module Risc
assert_equal "0x5ecc" , Position.get(Position.get(@machine.cpu_init.first).binary).to_s assert_equal "0x5ecc" , Position.get(Position.get(@machine.cpu_init.first).binary).to_s
end end
def test_cpu_label def test_cpu_label
assert_equal Position::InstructionPosition , Position.get(@machine.cpu_init.first).class assert_equal InstructionPosition , Position.get(@machine.cpu_init.first).class
end end
def test_first_binary_jump def test_first_binary_jump
bin = Parfait.object_space.get_init.binary bin = Parfait.object_space.get_init.binary