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 def byte_length
4 4
end end
alias :padded_length :byte_length
end end
end end

View File

@ -117,16 +117,14 @@ module Risc
# #
# start at code_start. # start at code_start.
def position_code(code_start) def position_code(code_start)
prev_code = nil
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|
Position.log.debug "Position starts for method #{method.name}"
last_code = CodeListener.init(method.binary) last_code = CodeListener.init(method.binary)
last_code.set(code_start) last_code.set(code_start)
first_position = InstructionListener.init(method.cpu_instructions, method.binary) first_position = InstructionListener.init(method.cpu_instructions, method.binary)
first_position.set( code_start + Parfait::BinaryCode.byte_offset) 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 code_start = last_code.next_slot
end end
end end

View File

@ -9,34 +9,6 @@ module Risc
# #
class CodeListener 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) def position_inserted(position)
Position.log.debug "extending one in #{self}" Position.log.debug "extending one in #{self}"
pos = CodeListener.init( position.object.next ) pos = CodeListener.init( position.object.next )
@ -46,8 +18,28 @@ module Risc
end end
def position_changed(position) def position_changed(position)
return unless position.object.next set_jump_for(position)
raise "Called" 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 end
# Create Position for the given BinaryCode object # Create Position for the given BinaryCode object

View File

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

View File

@ -67,13 +67,20 @@ module Risc
def set(int) def set(int)
return int if int == self.at return int if int == self.at
trigger_changing( int )
Position.set_to(self , int) Position.set_to(self , int)
@at = int @at = int
trigger_changed trigger_changed
int int
end 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 # Note: set checks if the position actually has changed, before fireing
# but during insert it is helpful to trigger just to set the next # but during insert it is helpful to trigger just to set the next
def trigger_changed def trigger_changed
@ -116,8 +123,9 @@ module Risc
def next_slot def next_slot
return -1 if at < 0 return -1 if at < 0
self.log.debug "Next Slot @#{at.to_s(16)} for #{object.class} == #{(at + object.byte_length).to_s(16)}" slot = at + object.padded_length
at + object.byte_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 end
## class level forward and reverse cache ## class level forward and reverse cache

View File

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

View File

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

View File

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

View File

@ -36,11 +36,23 @@ module Risc
@position.trigger_inserted @position.trigger_inserted
assert_equal @position , @trigger assert_equal @position , @trigger
end 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) def position_changed(pos)
@trigger = pos @trigger = pos
end end
def position_inserted(pos) def position_inserted(pos)
@trigger = pos @trigger = pos
end end
def position_changing(pos , to)
@trigger = pos
@to = to
end
end end
end end