From ab87806d086695ede6ac404b5399a9a3379c8ce9 Mon Sep 17 00:00:00 2001 From: Torsten Date: Sun, 28 Jul 2019 16:42:40 +0300 Subject: [PATCH] fixes #26 only recurse to 1k then come up for air an go again. Should allow for 1M objects on a 2k stack (previously exceptions at 3.6k) --- lib/risc/collector.rb | 67 +++++++++++++++++++++++++------------ lib/risc/parfait_boot.rb | 6 ++-- test/risc/test_collector.rb | 37 +++++++++++++++++++- 3 files changed, 85 insertions(+), 25 deletions(-) diff --git a/lib/risc/collector.rb b/lib/risc/collector.rb index 9dcc1310..66c274bb 100644 --- a/lib/risc/collector.rb +++ b/lib/risc/collector.rb @@ -1,43 +1,76 @@ module Risc - # collect anything that is in the space but and reachable from init + # collect anything that is in the space and reachable (linker constants) # # The place we collect in is the position map in Position class module Collector + # Collect all object that need to be added to the binary + # This means the object_space and aby constants the linker has + # we call keep on each object, see there for details + # return all positions def self.collect_space(linker) - keep Parfait.object_space , 0 + keep Parfait.object_space linker.constants.each do |obj| - keep(obj,0) + keep(obj) end Position.positions end - def self.keep( object , depth ) + # keep "collects" the object for "keeping". Such objects get written to binary + # keeping used to be done by adding to a hash, but now the object is + # given a position, and the Position class has a hash of all positions + # (the same hash has all objects, off course) + def self.keep( object) + collection = [] + mark_1k( object , 0 , collection) + collection.each do |obj| + #puts "obj #{obj.object_id}" + keep(obj) + end + end + + # marking object that make up the binary. + # "Only" up to 1k stack depth, collect object that make up the "border" + # + # Collection is an empty arry that is passed on. Objects below 1k get added + # So basically it "should" be a return, but then we would keep creating and adding + # arrays, most of which would be empty + def self.mark_1k(object , depth , collection) return if object.nil? - return unless add_object( object , depth ) + if depth > 1000 + collection << object + return + end + return unless position!( object ) return unless object.respond_to? :has_type? type = object.get_type - keep(type , depth + 1) + mark_1k(type , depth + 1 , collection) return if object.is_a? Symbol type.names.each do |name| - keep(name , depth + 1) + mark_1k(name , depth + 1, collection) inst = object.get_instance_variable name - keep(inst , depth + 1) + #puts "getting name #{name}, val=#{inst} #{inst.object_id}" + mark_1k(inst , depth + 1, collection) end if object.is_a? Parfait::List object.each do |item| - keep(item , depth + 1) + mark_1k(item , depth + 1, collection) end end end - # Objects are data and get assembled after functions - def self.add_object( objekt , depth) + # Give the object a position. Position class keeps a list of all positions + # and associated objects. The actual position is determined later, here a + # Position object is assigned. + # + # All Objects that end up in the binary must have a Position. + # + # return if the position was assigned (true) or had been assigned already (false) + def self.position!( objekt ) return false if Position.set?(objekt) return true if objekt.is_a? ::Integer return true if objekt.is_a?( Risc::Label) - #puts message(objekt , depth) - #puts "ADD #{objekt.inspect}, #{objekt.name}" if objekt.is_a? Parfait::CallableMethod + #puts "ADD #{objekt.class.name}" unless objekt.is_a?( Parfait::Object) or objekt.is_a?( Symbol) raise "adding non parfait #{objekt.class}:#{objekt}" end @@ -46,13 +79,5 @@ module Risc true end - def self.message(object , depth) - msg = "adding #{depth}#{' ' * depth}:" - if( object.respond_to?(:rxf_reference_name)) - msg + object.rxf_reference_name.to_s - else - msg + object.class.name - end - end end end diff --git a/lib/risc/parfait_boot.rb b/lib/risc/parfait_boot.rb index 71e9d7d9..16c7cb36 100644 --- a/lib/risc/parfait_boot.rb +++ b/lib/risc/parfait_boot.rb @@ -152,8 +152,10 @@ module Parfait Data8: {}, Data16: {}, Dictionary: {i_keys: :List , i_values: :List } , - Integer: {next_integer: :Integer}, FalseClass: {}, + Factory: { for_type: :Type , next_object: :Object , + reserve: :Object , attribute_name: :Word }, + Integer: {next_integer: :Integer}, List: {indexed_length: :Integer , next_list: :List} , Message: { next_message: :Message, receiver: :Object, frame: :NamedList , return_address: :Integer, return_value: :Object, @@ -162,8 +164,6 @@ module Parfait NamedList: {}, NilClass: {}, Object: {}, - Factory: { for_type: :Type , next_object: :Object , - reserve: :Object , attribute_name: :Word }, ReturnAddress: {next_integer: :ReturnAddress}, Space: {classes: :Dictionary , types: :Dictionary , factories: :Dictionary, true_object: :TrueClass, false_object: :FalseClass , nil_object: :NilClass}, diff --git a/test/risc/test_collector.rb b/test/risc/test_collector.rb index 61926aeb..bd45435d 100644 --- a/test/risc/test_collector.rb +++ b/test/risc/test_collector.rb @@ -11,7 +11,7 @@ module Risc def test_simple_collect objects = Collector.collect_space(@linker) - assert ((400 < objects.length) or (450 > objects.length)) , objects.length.to_s + assert_equal 600 , objects.length , objects.length.to_s end def test_collect_all_types @@ -34,5 +34,40 @@ module Risc assert !position.valid? end end + def test_integer_positions + objects = Collector.collect_space(@linker) + int = Parfait.object_space.get_next_for(:Integer) + while(int) + assert Position.set?(int) , "INt #{int.object_id}" + int = int.next_integer + end + end + end + class TestBigCollector < MiniTest::Test + + def setup + opt = Parfait.default_test_options + opt[:factory] = 4000 + Parfait.boot!(opt) + Risc.boot! + @linker = Mom::MomCompiler.new.translate(:arm) + end + + def test_simple_collect + objects = Collector.collect_space(@linker) + assert_equal 20329, objects.length , objects.length.to_s + end + + def test_integer_positions + objects = Collector.collect_space(@linker) + int = Parfait.object_space.get_next_for(:Integer) + count = 0 + while(int) + count += 1 + assert Position.set?(int) , "INT #{int.object_id} , count #{count}" + int = int.next_integer + end + end + end end