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:
parent
74c15d45a3
commit
ad3040a846
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user