add position_chaning to event interface

by reacting to the change _before it happens, we can move any BinaryCode out of the way

So when Instruction are inserted and code gets inserted, we don't need to set up the correct listener explicitly (which is tricky across mathods and changing chains), but instead just move anything that is in the way along
This commit is contained in:
Torsten Ruger 2018-06-09 08:10:41 +03:00
parent 74c15d45a3
commit ad3040a846
9 changed files with 65 additions and 48 deletions

View File

@ -130,6 +130,6 @@ module Arm
def byte_length
4
end
alias :padded_length :byte_length
end
end

View File

@ -117,16 +117,14 @@ module Risc
#
# start at code_start.
def position_code(code_start)
prev_code = nil
Parfait.object_space.types.values.each do |type|
next unless type.methods
type.methods.each_method do |method|
Position.log.debug "Position starts for method #{method.name}"
last_code = CodeListener.init(method.binary)
last_code.set(code_start)
first_position = InstructionListener.init(method.cpu_instructions, method.binary)
first_position.set( code_start + Parfait::BinaryCode.byte_offset)
last_code.position_listener( prev_code.object) if prev_code
prev_code = last_code
code_start = last_code.next_slot
end
end

View File

@ -9,34 +9,6 @@ module Risc
#
class CodeListener
def set(at)
raise "Called"
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
end
# insert a jump to the next instruction, at the last instruction
# thus hopping over the object header
def set_jump_for(position)
at = position.at
code = position.object
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 position_inserted(position)
Position.log.debug "extending one in #{self}"
pos = CodeListener.init( position.object.next )
@ -46,8 +18,28 @@ module Risc
end
def position_changed(position)
return unless position.object.next
raise "Called"
set_jump_for(position)
end
def position_changing(position , to)
move_along = Position.at( to )
return unless move_along
raise "Not BinaryCode at (#{to.to_s(16)}), but is #{move_along.object.class}" unless move_along.object.is_a?(Parfait::BinaryCode)
move_along.set(move_along + move_along.object.padded_length)
end
# insert a jump to the next instruction, at the last instruction
# thus hopping over the object header
def set_jump_for(position)
at = position.at
code = position.object
return unless code.next #dont jump beyond and
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.new(cpu_jump , pos)
cpu_jump.assemble(JumpWriter.new(code))
end
# Create Position for the given BinaryCode object

View File

@ -19,6 +19,10 @@ module Risc
@binary = binary
end
def position_changing(position , to)
end
# if the position of the instruction before us changes, we need to
# adjust the position of this instruction accordingly
# Taking into account that BinaryCodes only take 13 instructions,

View File

@ -67,13 +67,20 @@ module Risc
def set(int)
return int if int == self.at
trigger_changing( int )
Position.set_to(self , int)
@at = int
trigger_changed
int
end
# helper to fire the event that the position changed
# helper to fire the event that the position is about to change
# the argument is the new position (as int)
def trigger_changing( to )
event_table[:position_changed].each { |handler| handler.position_changing( self , to) }
end
# helper to fire the event that the position has changed
# Note: set checks if the position actually has changed, before fireing
# but during insert it is helpful to trigger just to set the next
def trigger_changed
@ -116,8 +123,9 @@ module Risc
def next_slot
return -1 if at < 0
self.log.debug "Next Slot @#{at.to_s(16)} for #{object.class} == #{(at + object.byte_length).to_s(16)}"
at + object.byte_length
slot = at + object.padded_length
self.log.debug "Next Slot @#{at.to_s(16)} for #{object.class}(#{object.padded_length.to_s(16)}) == #{(slot).to_s(16)}"
slot
end
## class level forward and reverse cache

View File

@ -16,15 +16,18 @@ module Risc
@object = object
end
def position_changing(position , to)
end
# when the argument changes position, we update the objects
# position to reflect that change
#
def position_changed(previous)
add = previous.object ? previous.object.padded_length : 0
me = previous.at + add
my_pos = previous.at + add
object_pos = Position.get(@object)
return if me == object_pos.at
Position.set_to(@object , me)
return if my_pos == object_pos.at
Position.set_to(object_pos , my_pos)
end
end
end

View File

@ -30,9 +30,5 @@ module Risc
pos = Position.get(@binary)
assert_equal CodeListener , pos.event_table[:position_changed].first.class
end
def test_extends_creates_jump
@binary.extend_one
CodeListener.init(@binary)
end
end
end

View File

@ -4,25 +4,29 @@ module Risc
# tests that require a boot and test propagation
class TestCodeListenerFull < MiniTest::Test
def setup
#@machine = DummyPlatform.boot
@machine = Risc.machine.boot
@binary = Parfait::BinaryCode.new(1)
@method = Parfait.object_space.types.values.first.methods
@label = Risc.label("hi","ho")
#@machine.set_translated
@machine.translate(:interpreter)
@machine.position_all
end
def test_listener_after_extend
CodeListener.init(@binary).set(0)
CodeListener.init(@binary).set(10)
@binary.extend_one
pos = Position.get(@binary.next)
assert_equal CodeListener , pos.event_table[:position_changed].first.class
end
def test_extend_sets_next_pos
CodeListener.init(@binary).set(0)
CodeListener.init(@binary).set(10)
@binary.extend_one
assert Position.get(@binary.next)
end
def test_extends_creates_jump
CodeListener.init(@binary).set(10)
assert_equal 0 , @binary.get_last
@binary.extend_one
assert 0 != @binary.get_last
end
end
end

View File

@ -36,11 +36,23 @@ module Risc
@position.trigger_inserted
assert_equal @position , @trigger
end
def test_position_set_triggers
@object = @instruction
Position.new(self, 0)
@position.register_event(:position_changed , self)#can't use helper
@position.set(10)
assert_equal @position , @trigger
assert_equal @to , 10
end
def position_changed(pos)
@trigger = pos
end
def position_inserted(pos)
@trigger = pos
end
def position_changing(pos , to)
@trigger = pos
@to = to
end
end
end