From ad3040a8464ab842d9ec5881e3891b1b3ea4daed Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Sat, 9 Jun 2018 08:10:41 +0300 Subject: [PATCH] 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 --- lib/arm/constants.rb | 2 +- lib/risc/machine.rb | 4 +- lib/risc/position/code_listener.rb | 52 ++++++++++------------- lib/risc/position/instruction_listener.rb | 4 ++ lib/risc/position/position.rb | 14 ++++-- lib/risc/position/position_listener.rb | 9 ++-- test/risc/position/test_code_listener.rb | 4 -- test/risc/position/test_code_listener1.rb | 12 ++++-- test/risc/position/test_position1.rb | 12 ++++++ 9 files changed, 65 insertions(+), 48 deletions(-) diff --git a/lib/arm/constants.rb b/lib/arm/constants.rb index d16cc4af..ec139abc 100644 --- a/lib/arm/constants.rb +++ b/lib/arm/constants.rb @@ -130,6 +130,6 @@ module Arm def byte_length 4 end - + alias :padded_length :byte_length end end diff --git a/lib/risc/machine.rb b/lib/risc/machine.rb index 2754e340..d6d8818c 100644 --- a/lib/risc/machine.rb +++ b/lib/risc/machine.rb @@ -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 diff --git a/lib/risc/position/code_listener.rb b/lib/risc/position/code_listener.rb index 0da5cce5..54f4f73f 100644 --- a/lib/risc/position/code_listener.rb +++ b/lib/risc/position/code_listener.rb @@ -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 diff --git a/lib/risc/position/instruction_listener.rb b/lib/risc/position/instruction_listener.rb index 3919862a..cf7d0e73 100644 --- a/lib/risc/position/instruction_listener.rb +++ b/lib/risc/position/instruction_listener.rb @@ -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, diff --git a/lib/risc/position/position.rb b/lib/risc/position/position.rb index 77f54f13..44bf55ac 100644 --- a/lib/risc/position/position.rb +++ b/lib/risc/position/position.rb @@ -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 diff --git a/lib/risc/position/position_listener.rb b/lib/risc/position/position_listener.rb index e6cf228d..d92dd1c5 100644 --- a/lib/risc/position/position_listener.rb +++ b/lib/risc/position/position_listener.rb @@ -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 diff --git a/test/risc/position/test_code_listener.rb b/test/risc/position/test_code_listener.rb index 350eb6bb..8ccc2824 100644 --- a/test/risc/position/test_code_listener.rb +++ b/test/risc/position/test_code_listener.rb @@ -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 diff --git a/test/risc/position/test_code_listener1.rb b/test/risc/position/test_code_listener1.rb index 97bd8c2a..ff335586 100644 --- a/test/risc/position/test_code_listener1.rb +++ b/test/risc/position/test_code_listener1.rb @@ -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 diff --git a/test/risc/position/test_position1.rb b/test/risc/position/test_position1.rb index d2e5e77e..0a15dbf2 100644 --- a/test/risc/position/test_position1.rb +++ b/test/risc/position/test_position1.rb @@ -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