From 2ccbea04b9c1542008a4256d2948874a41a73959 Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Sun, 24 May 2015 18:05:20 +0300 Subject: [PATCH] fixing assembly position code changed and linking too passes not working --- lib/arm/instructions/move_instruction.rb | 33 +++--- lib/parfait/class.rb | 4 - lib/parfait/module.rb | 2 +- lib/parfait/object.rb | 4 + lib/parfait/space.rb | 4 - lib/register/assembler.rb | 11 +- lib/virtual.rb | 2 +- lib/virtual/block.rb | 2 +- lib/virtual/compiled_method_info.rb | 8 +- lib/virtual/instruction.rb | 25 ----- lib/virtual/machine.rb | 2 + lib/virtual/parfait_adapter.rb | 35 ++++++ lib/virtual/positioned.rb | 129 ++--------------------- test/helper.rb | 6 +- test/virtual/virtual_helper.rb | 26 +++++ 15 files changed, 111 insertions(+), 182 deletions(-) diff --git a/lib/arm/instructions/move_instruction.rb b/lib/arm/instructions/move_instruction.rb index 2323a508..ef23af34 100644 --- a/lib/arm/instructions/move_instruction.rb +++ b/lib/arm/instructions/move_instruction.rb @@ -5,15 +5,14 @@ module Arm def initialize to , from , options = {} super(options) @to = to - raise "old code, fix this to use LoadConstant" if from.is_a? Virtual::ObjectConstant - @from = from.is_a?(Fixnum) ? Virtual::IntegerConstant.new(from) : from + @from = from #from.is_a?(Fixnum) ? Virtual::IntegerConstant.new(from) : from raise "move must have from set #{inspect}" unless from @attributes[:update_status] = 0 if @attributes[:update_status] == nil @attributes[:condition_code] = :al if @attributes[:condition_code] == nil @attributes[:opcode] = attributes[:opcode] @operand = 0 - @immediate = 0 + @immediate = 0 @rn = :r0 # register zero = zero bit pattern @from = Virtual::IntegerConstant.new( @from ) if( @from.is_a? Fixnum ) @extra = nil @@ -22,11 +21,11 @@ module Arm # arm intructions are pretty sensible, and always 4 bytes (thumb not supported) # but not all constants fit into the part of the instruction that is left after the instruction code, - # so large moves have to be split into two instructions. + # so large moves have to be split into two instructions. # we handle this "transparently", just this instruction looks longer # alas, full transparency is not achieved as we only know when to use 2 instruction once we know where the - # other object is, and that position is only set after code positions have been determined (in link) and so - # see below in assemble + # other object is, and that position is only set after code positions have been determined (in link) and so + # see below in assemble def mem_length @extra ? 8 : 4 end @@ -60,15 +59,15 @@ module Arm #armv7 operand = (right.integer & 0xFFF) #armv7 immediate = 1 #armv7 rn = (right.integer >> 12) - # a little STRANGE, that the armv7 movw (move a 2 byte word) is an old test opcode, but there it is + # a little STRANGE, that the armv7 movw (move a 2 byte word) is an old test opcode, but there it is #armv7 @attributes[:opcode] = :tst raise "No negatives implemented #{right} " if right.integer < 0 - # and so it continues: when we notice that the const doesn't fit, first time we raise an + # and so it continues: when we notice that the const doesn't fit, first time we raise an # error,but set the extra flag, to say the instruction is now 8 bytes # then on subsequent assemblies we can assemble unless @extra @extra = 1 - raise ::Register::LinkException.new("cannot fit numeric literal argument in operand #{right.inspect}") + raise ::Register::LinkException.new("cannot fit numeric literal argument in operand #{right.inspect}") end # now we can do the actual breaking of instruction, by splitting the operand first = Virtual::IntegerConstant.new(right.integer & 0xFFFFFF00) @@ -80,7 +79,7 @@ module Arm # is to check that the first part is doabe with u8_with_rr AND leaves a u8 remainder end elsif (right.is_a?(Symbol) or right.is_a?(::Register::RegisterReference)) - operand = reg_code(right) + operand = reg_code(right) immediate = 0 # ie not immediate is register else raise "invalid operand argument #{right.class} , #{self.class}" @@ -89,17 +88,17 @@ module Arm instuction_class = 0b00 # OPC_DATA_PROCESSING val = shift(operand , 0) val |= shift(op , 0) # any barrel action, is already shifted - val |= shift(reg_code(@to) , 12) - val |= shift(reg_code(rn) , 12+4) - val |= shift(@attributes[:update_status] , 12+4+4)#20 + val |= shift(reg_code(@to) , 12) + val |= shift(reg_code(rn) , 12+4) + val |= shift(@attributes[:update_status] , 12+4+4)#20 val |= shift(op_bit_code , 12+4+4 +1) - val |= shift(immediate , 12+4+4 +1+4) - val |= shift(instuction_class , 12+4+4 +1+4+1) + val |= shift(immediate , 12+4+4 +1+4) + val |= shift(instuction_class , 12+4+4 +1+4+1) val |= shift(cond_bit_code , 12+4+4 +1+4+1+2) io.write_uint32 val # by now we have the extra add so assemble that if(@extra) - @extra.assemble(io) + @extra.assemble(io) #puts "Assemble extra at #{val.to_s(16)}" end end @@ -115,4 +114,4 @@ module Arm [@to.register] end end -end \ No newline at end of file +end diff --git a/lib/parfait/class.rb b/lib/parfait/class.rb index e9f1c1f4..d66922be 100644 --- a/lib/parfait/class.rb +++ b/lib/parfait/class.rb @@ -34,10 +34,6 @@ module Parfait @object_layout.push name end - def mem_length - padded_words(3) - end - # ruby 2.1 list (just for reference, keep at bottom) #:allocate, :new, :superclass end diff --git a/lib/parfait/module.rb b/lib/parfait/module.rb index 8a49dc6b..7157ebcf 100644 --- a/lib/parfait/module.rb +++ b/lib/parfait/module.rb @@ -33,7 +33,7 @@ module Parfait raise "not a method #{method.class} #{method.inspect}" unless method.is_a? Method raise "syserr #{method.name.class}" unless method.name.is_a? Word @instance_methods << method - puts "#{self.name} add #{method.name}" + #puts "#{self.name} add #{method.name}" method end diff --git a/lib/parfait/object.rb b/lib/parfait/object.rb index 58c86f9e..7dc27d47 100644 --- a/lib/parfait/object.rb +++ b/lib/parfait/object.rb @@ -71,6 +71,10 @@ module Parfait get_layout().index_of(name) end + def mem_length + padded_words( get_layout().get_length() + 2 ) + end + # Object # :nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup, :taint, :tainted?, :untaint, # :untrust, :untrusted?, :trust, :freeze, :frozen?, :to_s, :inspect, :methods, :singleton_methods, :protected_methods, diff --git a/lib/parfait/space.rb b/lib/parfait/space.rb index 36667b0b..330916e7 100644 --- a/lib/parfait/space.rb +++ b/lib/parfait/space.rb @@ -74,10 +74,6 @@ module Parfait raise "uups " if name.is_a? String @classes[name] = c end - - def mem_length - padded_words( 5 ) - end end # ObjectSpace # :each_object, :garbage_collect, :define_finalizer, :undefine_finalizer, :_id2ref, :count_objects diff --git a/lib/register/assembler.rb b/lib/register/assembler.rb index 7b74df14..fbe1aa00 100644 --- a/lib/register/assembler.rb +++ b/lib/register/assembler.rb @@ -22,14 +22,13 @@ module Register @space.set_position(0) at = @space.mem_length # first jump instruction # then all functions - @objects.each_value do | objekt| - next unless objekt.is_a? Virtual::CompiledMethod - objekt.set_position(at) - at += objekt.mem_length + @space.objects.each do | objekt| + next unless objekt.is_a? Parfait::Method + objekt.info.set_position(at) + at += objekt.info.mem_length end #and then all data object - @objects.each_value do | objekt| - next if objekt.is_a? Virtual::CompiledMethod + @objects.each do | objekt| objekt.set_position at at += objekt.mem_length end diff --git a/lib/virtual.rb b/lib/virtual.rb index fca4fda0..02debe3d 100644 --- a/lib/virtual.rb +++ b/lib/virtual.rb @@ -1,3 +1,4 @@ +require "parfait" require "virtual/machine" require "virtual/compiler" @@ -5,7 +6,6 @@ require "virtual/instruction" require "virtual/compiled_method_info" require "virtual/slots/slot" require "virtual/type" -require "virtual/constants" # the passes _are_ order dependant require "virtual/passes/send_implementation" require "virtual/passes/get_implementation" diff --git a/lib/virtual/block.rb b/lib/virtual/block.rb index 1ee07459..4ba11935 100644 --- a/lib/virtual/block.rb +++ b/lib/virtual/block.rb @@ -7,7 +7,7 @@ module Virtual # Blocks form a graph, which is managed by the method - class Block < Virtual::Object + class Block def initialize(name , method ) super() diff --git a/lib/virtual/compiled_method_info.rb b/lib/virtual/compiled_method_info.rb index c8c35912..bf5b6905 100644 --- a/lib/virtual/compiled_method_info.rb +++ b/lib/virtual/compiled_method_info.rb @@ -140,9 +140,15 @@ module Virtual l = @blocks.inject(0) { |c , block| c += block.mem_length } padded(l) end + + def padded len + a = 32 * (1 + (len + 7)/32 ) + #puts "#{a} for #{len}" + a + end + # position of the function is the position of the entry block, is where we call def set_position at - super at += 8 #for the 2 header words @blocks.each do |block| block.set_position at diff --git a/lib/virtual/instruction.rb b/lib/virtual/instruction.rb index 5b0cf2fc..8607f6f9 100644 --- a/lib/virtual/instruction.rb +++ b/lib/virtual/instruction.rb @@ -1,4 +1,3 @@ - require_relative "positioned" module Virtual @@ -12,30 +11,6 @@ module Virtual class Instruction include Positioned - - # simple thought: don't recurse for Blocks, just check their names - def == other - return false unless other.class == self.class - Sof::Util.attributes(self).each do |a| - begin - left = send(a) - rescue NoMethodError - next # not using instance variables that are not defined as attr_readers for equality - end - begin - right = other.send(a) - rescue NoMethodError - return false - end - return false unless left.class == right.class - if( left.is_a? Block) - return false unless left.name == right.name - else - return false unless left == right - end - end - return true - end end end diff --git a/lib/virtual/machine.rb b/lib/virtual/machine.rb index 56d69db5..46a0439f 100644 --- a/lib/virtual/machine.rb +++ b/lib/virtual/machine.rb @@ -42,7 +42,9 @@ module Virtual def run_passes #TODO puts "INIT #{@init}" + @passes.each do |pass_class| + puts "run pass #{pass_class}" blocks = []#[@init] #TODO + @main.blocks @space.classes.values.each do |c| c.instance_methods.each do |f| diff --git a/lib/virtual/parfait_adapter.rb b/lib/virtual/parfait_adapter.rb index 1cde5560..5d48cbcd 100644 --- a/lib/virtual/parfait_adapter.rb +++ b/lib/virtual/parfait_adapter.rb @@ -7,6 +7,8 @@ module FakeMem def initialize @memory = [0,nil] + @position = nil + @length = -1 if Parfait::Space.object_space and Parfait::Space.object_space.objects Parfait::Space.object_space.add_object self else @@ -21,6 +23,30 @@ module FakeMem raise "Class not found #{vm_name}" unless clazz self.set_layout clazz.object_layout end + def position + raise "position accessed but not set at #{length} for #{self.inspect[0...500]}" if @position == nil + @position + end + def set_position pos + # resetting of position used to be error, but since relink and dynamic instruction size it is ok. + # in measures (of 32) + if @position != nil and ((@position - pos).abs > 32) + raise "position set again #{pos}!=#{@position} for #{self}" + end + @position = pos + end + # objects only come in lengths of multiple of 8 words + # but there is a constant overhead of 2 words, one for type, one for layout + # and as we would have to subtract 1 to make it work without overhead, we now have to add 7 + def padded len + a = 32 * (1 + (len + 7)/32 ) + #puts "#{a} for #{len}" + a + end + + def padded_words words + padded(words*4) # 4 == word length, a constant waiting for a home + end end module Parfait @@ -29,6 +55,7 @@ module Parfait # These are the same functions that Builtin implements at run-time class Object include FakeMem + # these internal functions are _really_ internal # they respresent the smallest code needed to build larger functionality # but should _never_ be used outside parfait. in fact that should be impossible @@ -67,6 +94,9 @@ module Parfait end class List + def mem_length + Virtual::Object.new.padded_words(length()) + end def to_sof_node(writer , level , ref ) Sof.array_to_sof_node(self , writer , level , ref ) end @@ -91,6 +121,10 @@ module Parfait end class Word + def mem_length + Virtual::Object.new.padded(1 + length()) + end + def == other return false unless other.is_a?(String) or other.is_a?(Word) as_string = self.to_s @@ -112,6 +146,7 @@ module Parfait end end + module Virtual # Functions to generate parfait objects def self.new_word( string ) diff --git a/lib/virtual/positioned.rb b/lib/virtual/positioned.rb index c7101334..638f67fa 100644 --- a/lib/virtual/positioned.rb +++ b/lib/virtual/positioned.rb @@ -1,5 +1,4 @@ require_relative "type" -require "parfait" module Positioned def position @@ -14,124 +13,16 @@ module Positioned end @position = pos end -end + # objects only come in lengths of multiple of 8 words + # but there is a constant overhead of 2 words, one for type, one for layout + # and as we would have to subtract 1 to make it work without overhead, we now have to add 7 + def padded len + a = 32 * (1 + (len + 7)/32 ) + #puts "#{a} for #{len}" + a + end -module Virtual - # our machine is made up of objects, some of which are code, some data - # - # during compilation objects are module Virtual objects, but during execution they are not scoped - # - # So compiling/linking/assembly turns ::virtual objects into binary that represents ruby objects at runtime - # The equivalence is listed below (i'll try and work on clearer correspondence later) - # ::Virtual Runtime / parfait - # Object Object - # BootClass Class - # MetaClass self/Object - # Space ObjectSpace - # CompiledMethod Function - # (ruby)Array Array - # String String - class Object - include Positioned - def initialize - @position = nil - @length = -1 - end - attr_accessor :length , :layout - def inspect - Sof::Writer.write(self) - end - def to_s - inspect[0..300] - end - def mem_length - raise "abstract #{self.class}" - end - @@EMPTY = { :names => [] , :types => []} - def old_layout - raise "Find me #{self}" - self.class.layout - end - def self.layout - @@EMPTY - end - # class variables to have _identical_ objects passed back (stops recursion) - @@ARRAY = { :names => [] , :types => []} -# @@HASH = { :names => [:keys,:values] , :types => [Virtual::Reference,Virtual::Reference]} -# @@CLAZZ = { :names => [:name , :super_class_name , :instance_methods] , :types => [Virtual::Reference,Virtual::Reference,Virtual::Reference]} -# @@SPACE = { :names => [:classes,:objects] , :types => [Virtual::Reference,Virtual::Reference]} - - def old_layout_for(object) - case object - when Array , Symbol , String , Virtual::CompiledMethod , Virtual::Block , Parfait::Word - @@ARRAY - when Hash - @@HASH.merge :keys => object.keys , :values => object.values - when Virtual::BootClass - @@CLAZZ - when Virtual::Space - @@SPACE - else - raise "linker encounters unknown class #{object.class}" - end - end - # objects only come in lengths of multiple of 8 words - # but there is a constant overhead of 2 words, one for type, one for layout - # and as we would have to subtract 1 to make it work without overhead, we now have to add 7 - def padded len - a = 32 * (1 + (len + 7)/32 ) - #puts "#{a} for #{len}" - a - end - - def padded_words words - padded(words*4) # 4 == word length, a constant waiting for a home - end - end -end -::Parfait::Message.class_eval do - include Positioned - def old_layout - Virtual::Object.layout - end - def mem_length - Virtual::Object.new.padded_words(2) - end -end -::Parfait::Frame.class_eval do - include Positioned - def old_layout - Virtual::Object.layout - end - def mem_length - Virtual::Object.new.padded_words(2) - end -end -Parfait::Dictionary.class_eval do - include Positioned - HASH = { :names => [:keys,:values] , :types => [Virtual::Reference,Virtual::Reference]} - def old_layout - HASH - end - def mem_length - Virtual::Object.new.padded_words(2) - end -end -::Parfait::List.class_eval do - include Positioned - def old_layout - Virtual::Object.layout - end - def mem_length - Virtual::Object.new.padded_words(length()) - end -end -::Parfait::Word.class_eval do - include Positioned - def old_layout - Virtual::Object.layout - end - def mem_length - Virtual::Object.new.padded(1 + length()) + def padded_words words + padded(words*4) # 4 == word length, a constant waiting for a home end end diff --git a/test/helper.rb b/test/helper.rb index 84c4e004..255fadab 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -30,9 +30,9 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'test')) require 'salama' -Virtual::Object.class_eval do +class Ignored def == other - return false unless other.class == self.class + return false unless other.class == self.class Sof::Util.attributes(self).each do |a| begin left = send(a) @@ -44,7 +44,7 @@ Virtual::Object.class_eval do rescue NoMethodError return false end - return false unless left.class == right.class + return false unless left.class == right.class return false unless left == right end return true diff --git a/test/virtual/virtual_helper.rb b/test/virtual/virtual_helper.rb index dc4b1259..fcebe661 100644 --- a/test/virtual/virtual_helper.rb +++ b/test/virtual/virtual_helper.rb @@ -28,3 +28,29 @@ module VirtualHelper end end + +class UnusedSofEquality + # simple thought: don't recurse for Blocks, just check their names + def == other + return false unless other.class == self.class + Sof::Util.attributes(self).each do |a| + begin + left = send(a) + rescue NoMethodError + next # not using instance variables that are not defined as attr_readers for equality + end + begin + right = other.send(a) + rescue NoMethodError + return false + end + return false unless left.class == right.class + if( left.is_a? Block) + return false unless left.name == right.name + else + return false unless left == right + end + end + return true + end +end