turned out to be a rewrite of boot process
and also attribute handling and fake_memory luckily there are tests and all is green again
This commit is contained in:
@@ -16,80 +16,114 @@ module Virtual
|
||||
#
|
||||
# The way out is to build empty shell objects and stuff the neccessary data into them
|
||||
# (not use the normal initialize way)
|
||||
#
|
||||
# There are some helpers below, but the roadmap is something like:
|
||||
# - create all the layouts, with thier layouts, but no classes
|
||||
# - create a space by "hand" , using allocate, not new
|
||||
# - create the class objects and assign them to the layouts
|
||||
def boot_space
|
||||
space_dict = object_with_layout Parfait::Dictionary
|
||||
space_dict.keys = object_with_layout Parfait::List
|
||||
space_dict.values = object_with_layout Parfait::List
|
||||
|
||||
@space = object_with_layout Parfait::Space
|
||||
@space.classes = space_dict
|
||||
Parfait::Space.set_object_space @space
|
||||
end
|
||||
def boot_layouts
|
||||
@layouts = {}
|
||||
layout_names.each do |name , ivars |
|
||||
@layouts[name] = layout_for( name , ivars)
|
||||
end
|
||||
layout_layout = @layouts[:Layout]
|
||||
@layouts.each do |name , layout |
|
||||
layout.set_layout(layout_layout)
|
||||
end
|
||||
end
|
||||
|
||||
def boot_classes
|
||||
# when running code instantiates a class, a layout is created automatically
|
||||
# but even to get our space up, we have already instantiated all layouts
|
||||
# so we have to continue and allocate classes and fill the data by hand
|
||||
# and off cource we can't use space.create_class , but still they need to go there
|
||||
classes = space.classes
|
||||
layout_names.each do |name , vars|
|
||||
cl = object_with_layout Parfait::Class
|
||||
cl.object_layout = @layouts[name]
|
||||
@layouts[name].object_class = cl
|
||||
cl.instance_methods = object_with_layout Parfait::List
|
||||
# puts "instance_methods is #{cl.instance_methods.class}"
|
||||
cl.name = name
|
||||
classes[name] = cl
|
||||
end
|
||||
object_class = classes[:Object]
|
||||
# superclasses other than default object
|
||||
supers = { :BinaryCode => :Word , :Layout => :List , :Class => :Module ,
|
||||
:Object => :Kernel , :Kernel => :Value, :Integer => :Value }
|
||||
layout_names.each do |classname , ivar|
|
||||
next if classname == :Value # has no superclass
|
||||
clazz = classes[classname]
|
||||
super_name = supers[classname]
|
||||
if super_name
|
||||
clazz.set_super_class classes[super_name]
|
||||
else
|
||||
clazz.set_super_class object_class
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def boot_parfait!
|
||||
@space = Parfait::Space.new
|
||||
# map from the vm - class_name to the Parfait class (which carries parfait name)
|
||||
class_mappings = {} #will later become instance variable
|
||||
|
||||
values = [ :Value , :Integer , :Kernel , :Object]
|
||||
value_classes = values.collect { |cl| @space.create_class(cl,nil) }
|
||||
layouts = { :Word => [] ,
|
||||
:List => [] ,
|
||||
# Assumtion is that name is the last of message
|
||||
:Message => [:next_message , :receiver , :frame , :return_address , :return_value,
|
||||
:caller , :name ],
|
||||
:MetaClass => [],
|
||||
:BinaryCode => [],
|
||||
:Space => [:classes , :first_message ],
|
||||
:Frame => [:next_frame ],
|
||||
:Layout => [:object_class] ,
|
||||
:Class => [:object_layout ],
|
||||
:Dictionary => [:keys , :values ] ,
|
||||
:Method => [:name , :code ,:arg_names , :locals , :tmps ] ,
|
||||
:Module => [:name , :instance_methods , :super_class , :meta_class ]
|
||||
}
|
||||
layouts.each do |name , layout|
|
||||
class_mappings[name] = @space.create_class(name , nil)
|
||||
end
|
||||
value_classes[1].set_super_class( value_classes[0] ) # #set superclass (value) for integer
|
||||
value_classes[2].set_super_class( value_classes[0] ) # and kernel (TODO is module)
|
||||
value_classes[3].set_super_class( value_classes[2] ) # and object (TODO hacked to kernel)
|
||||
class_mappings.each do |name , clazz| # and the rest
|
||||
clazz.set_super_class(value_classes[3]) # superclasses are object
|
||||
end
|
||||
# next create layouts by adding instance variable names to the layouts
|
||||
class_mappings.each do |name , clazz|
|
||||
variables = layouts[name]
|
||||
variables.each do |var_name|
|
||||
clazz.object_layout.add_instance_variable var_name
|
||||
end
|
||||
end
|
||||
# superclass and layout corrections
|
||||
supers = { :BinaryCode => :Word , :Layout => :List , :Class => :Module }
|
||||
supers.each do |classname , superclass_name|
|
||||
clazz = class_mappings[classname]
|
||||
super_class = class_mappings[superclass_name]
|
||||
# set_super_class has no sideeffects, so setting twice ok
|
||||
clazz.set_super_class super_class
|
||||
# Add superclass layout too
|
||||
super_class.object_layout.each do |var|
|
||||
clazz.object_layout.add_instance_variable var
|
||||
end
|
||||
end
|
||||
|
||||
# now store the classes so we can hand them out later during object creation
|
||||
# this can not be done earlier, as parfait objects are all the time created and would
|
||||
# lookup half created class info
|
||||
# but it must be done before going through the objects (next step)
|
||||
@class_mappings = class_mappings
|
||||
class_mappings[:Integer ] = value_classes[1] #need for further booting
|
||||
class_mappings[:Kernel ] = value_classes[2] #need for further booting
|
||||
class_mappings[:Object ] = value_classes[3] #need for further booting
|
||||
boot_layouts
|
||||
boot_space
|
||||
boot_classes
|
||||
|
||||
@space.late_init
|
||||
|
||||
# add_object @space
|
||||
|
||||
class_mappings.values.each {|v| v.init_layout }
|
||||
|
||||
# now update the layout on all objects created so far,
|
||||
# go through objects in space
|
||||
@objects.each do | o |
|
||||
o.init_layout
|
||||
end
|
||||
#puts Sof.write(@space)
|
||||
boot_functions!
|
||||
end
|
||||
|
||||
# helper to create a Layout, name is the parfait name, ie :Layout
|
||||
def layout_for( name , ivars )
|
||||
l = Parfait::Layout.allocate.fake_init
|
||||
l.add_instance_variable :layout
|
||||
ivars.each {|n| l.add_instance_variable n }
|
||||
l
|
||||
end
|
||||
|
||||
# create an object with layout (ie allocate it and assign layout)
|
||||
# meaning the lauouts have to be booted, @layouts filled
|
||||
# here we pass the actual (ruby) class
|
||||
def object_with_layout(cl)
|
||||
o = cl.allocate.fake_init
|
||||
name = cl.name.split("::").last.to_sym
|
||||
o.set_layout @layouts[name]
|
||||
o
|
||||
end
|
||||
|
||||
def layout_names
|
||||
{ :Word => [] ,
|
||||
:List => [] ,
|
||||
# Assumtion is that name is the last of message
|
||||
:Message => [:next_message , :receiver , :frame , :return_address , :return_value,
|
||||
:caller , :name ],
|
||||
:MetaClass => [],
|
||||
:Integer => [],
|
||||
:Object => [],
|
||||
:Kernel => [], #fix, kernel is a class, but should be a module
|
||||
:BinaryCode => [],
|
||||
:Space => [:classes , :first_message ],
|
||||
:Frame => [:next_frame ],
|
||||
:Layout => [:object_class] ,
|
||||
# TODO fix layouts for inherited classes. Currently only :Class and the
|
||||
# instances are copied (shame on you)
|
||||
:Class => [:object_layout , :name , :instance_methods , :super_class , :meta_class],
|
||||
:Dictionary => [:keys , :values ] ,
|
||||
:Method => [:name , :code ,:arg_names , :for_class, :locals , :tmps ] ,
|
||||
:Module => [:name , :instance_methods , :super_class , :meta_class ]
|
||||
}
|
||||
end
|
||||
|
||||
# classes have booted, now create a minimal set of functions
|
||||
# minimal means only that which can not be coded in ruby
|
||||
# Methods are grabbed from respective modules by sending the method name. This should return the
|
||||
@@ -99,19 +133,19 @@ module Virtual
|
||||
# very fiddly chicken 'n egg problem. Functions need to be in the right order, and in fact we
|
||||
# have to define some dummies, just for the other to compile
|
||||
# TODO go through the virtual parfait layer and adjust function names to what they really are
|
||||
obj = @class_mappings[:Object ]
|
||||
obj = @space.get_class_by_name(:Object)
|
||||
[:main , :_get_instance_variable , :_set_instance_variable].each do |f|
|
||||
obj.add_instance_method Register::Builtin::Object.send(f , nil)
|
||||
end
|
||||
obj = @class_mappings[:Kernel ]
|
||||
obj = @space.get_class_by_name(:Kernel)
|
||||
# create dummy main first, __init__ calls it
|
||||
[:exit,:__send , :__init__ ].each do |f|
|
||||
obj.add_instance_method Register::Builtin::Kernel.send(f , nil)
|
||||
end
|
||||
|
||||
@class_mappings[:Word].add_instance_method Register::Builtin::Word.send(:putstring , nil)
|
||||
@space.get_class_by_name(:Word).add_instance_method Register::Builtin::Word.send(:putstring , nil)
|
||||
|
||||
obj = @class_mappings[:Integer ]
|
||||
obj = @space.get_class_by_name(:Integer)
|
||||
[:putint,:fibo].each do |f|
|
||||
obj.add_instance_method Register::Builtin::Integer.send(f , nil)
|
||||
end
|
||||
|
Reference in New Issue
Block a user