move space to parfait

Also make the machine the singleton
and space hang off it

Many repercussions, not all fixed in this commit
This commit is contained in:
Torsten Ruger 2015-05-12 15:36:44 +03:00
parent 2e8b514e9c
commit b980def84e
35 changed files with 185 additions and 195 deletions

View File

@ -15,5 +15,5 @@ module Arm
end
end
end
Virtual::BootSpace.space.add_pass "Arm::CallImplementation"
Virtual::Machine.instance.add_pass "Arm::CallImplementation"
end

View File

@ -9,5 +9,5 @@ module Arm
end
end
end
Virtual::BootSpace.space.add_pass "Arm::ConstantImplementation"
Virtual::Machine.instance.add_pass "Arm::ConstantImplementation"
end

View File

@ -9,5 +9,5 @@ module Arm
end
end
end
Virtual::BootSpace.space.add_pass "Arm::GetImplementation"
Virtual::Machine.instance.add_pass "Arm::GetImplementation"
end

View File

@ -11,5 +11,5 @@ module Arm
end
end
end
Virtual::BootSpace.space.add_pass "Arm::MainImplementation"
Virtual::Machine.instance.add_pass "Arm::MainImplementation"
end

View File

@ -9,5 +9,5 @@ module Arm
end
end
end
Virtual::BootSpace.space.add_pass "Arm::ReturnImplementation"
Virtual::Machine.instance.add_pass "Arm::ReturnImplementation"
end

View File

@ -14,5 +14,5 @@ module Arm
end
end
end
Virtual::BootSpace.space.add_pass "Arm::SaveImplementation"
Virtual::Machine.instance.add_pass "Arm::SaveImplementation"
end

View File

@ -9,5 +9,5 @@ module Arm
end
end
end
Virtual::BootSpace.space.add_pass "Arm::SetImplementation"
Virtual::Machine.instance.add_pass "Arm::SetImplementation"
end

View File

@ -9,5 +9,5 @@ module Arm
end
end
end
Virtual::BootSpace.space.add_pass "Arm::TransferImplementation"
Virtual::Machine.instance.add_pass "Arm::TransferImplementation"
end

View File

@ -16,13 +16,12 @@ module Elf
@text = Elf::TextSection.new(".text")
@object.add_section @text
@object_space.run_passes
assembler = Register::Assembler.new(@object_space)
set_text assembler.assemble
set_text assembler.assemble
# for debug add labels to the block positions
blocks = []
# for debug add labels to the block positions
space.classes.values.each do |clazz|
clazz.instance_methods.each do |f|
f.blocks.each do |b|
@ -51,10 +50,10 @@ module Elf
end
def save(filename)
to = File.open(filename, 'wb')
to = File.open(filename, 'wb')
@object.write to
to.close
end
end
end
end

View File

@ -7,6 +7,7 @@ require "parfait/array"
require "parfait/string"
require "parfait/message"
require "parfait/frame"
require "parfait/space"
# Below we define functions (in different classes) that are not part of the run-time
# They are used for the boot process, ie when this codes executes in the vm that builds salama

View File

@ -40,7 +40,7 @@ module Parfait
method = get_instance_method(m_name)
unless method
unless( @name == :Object)
supr = BootSpace.space.get_or_create_class(@super_class_name)
supr = Space.space.get_or_create_class(@super_class_name)
method = supr.resolve_method(m_name)
end
end

View File

@ -8,10 +8,63 @@
# "New" is slightly misleading in that normal operation only ever
# recycles objects.
require "register/builtin/object"
module Parfait
# The Space contains all objects for a program. In functional terms it is a program, but in oo
# it is a collection of objects, some of which are data, some classes, some functions
# The main entry is a function called (of all things) "main", This _must be supplied by the compling
# There is a start and exit block that call main, which receives an array of strings
# While data ususally would live in a .data section, we may also "inline" it into the code
# in an oo system all data is represented as objects
class Space < Object
# ObjectSpace
# :each_object, :garbage_collect, :define_finalizer, :undefine_finalizer, :_id2ref, :count_objects
def initialize
super()
@classes = Parfait::Hash.new_object
#global objects (data)
@objects = []
@symbols = []
@frames = 100.times.collect{ ::Parfait::Frame.new([],[])}
@messages = 100.times.collect{ ::Parfait::Message.new }
@next_message = @messages.first
@next_frame = @frames.first
end
attr_reader :init , :main , :classes , :objects , :symbols,:messages, :next_message , :next_frame
@@SPACE = { :names => [:classes,:objects,:symbols,:messages, :next_message , :next_frame] ,
:types => [Virtual::Reference,Virtual::Reference,Virtual::Reference,Virtual::Reference,Virtual::Reference]}
def layout
@@SPACE
end
# Objects are data and get assembled after functions
def add_object o
return if @objects.include?(o)
@objects << o
if o.is_a? Symbol
@symbols << o
end
end
# this is the way to instantiate classes (not BootClass.new)
# so we get and keep exactly one per name
def get_or_create_class name
raise "uups #{name}.#{name.class}" unless name.is_a? Symbol
c = @classes[name]
unless c
c = Class.new_object(name)
@classes[name] = c
end
c
end
def mem_length
padded_words( 5 )
end
end
# ObjectSpace
# :each_object, :garbage_collect, :define_finalizer, :undefine_finalizer, :_id2ref, :count_objects
end

View File

@ -7,7 +7,7 @@ There is a mechanism for an actual machine (derived class) to generate harware s
plain ones in this directory don't assemble to binary). Currently there is only the Arm module to actually do
that.
The elf module is used to generate the actual binary from the final BootSpace. BootSpace is a virtual class representing
The elf module is used to generate the actual binary from the final Space. Space is a virtual class representing
all objects that will be in the executable. Other than CompiledMethods, objects get transformed to data.
But CompiledMethods, which are made up of Blocks, are compiled into a stream of bytes, which are the binary code for the

View File

@ -12,7 +12,7 @@ module Register
TYPE_INT = 1
TYPE_BITS = 4
TYPE_LENGTH = 6
def initialize space
@space = space
@objects = {}
@ -41,7 +41,7 @@ module Register
begin
link
@stream = StringIO.new
mid , main = @objects.find{|k,objekt| objekt.is_a?(Virtual::CompiledMethod) and (objekt.name == :__init__ )}
#TODOmid , main = @objects.find{|k,objekt| objekt.is_a?(Virtual::CompiledMethod) and (objekt.name == :__init__ )}
initial_jump = @space.init
initial_jump.codes.each do |code|
code.assemble( @stream )
@ -54,7 +54,7 @@ module Register
next if objekt.is_a? Virtual::CompiledMethod
assemble_object( objekt )
end
rescue LinkException => e
rescue LinkException
# knowing that we fix the problem, we hope to get away with retry.
retry
end
@ -63,7 +63,7 @@ module Register
end
def assemble_object obj
#puts "Assemble #{obj.class}(#{obj.object_id}) at stream #{(@stream.length).to_s(16)} pos:#{obj.position.to_s(16)} , len:#{obj.mem_length}"
#puts "Assemble #{obj.class}(#{obj.object_id}) at stream #{(@stream.length).to_s(16)} pos:#{obj.position.to_s(16)} , len:#{obj.mem_length}"
raise "Assemble #{obj.class} at #{@stream.length.to_s(16)} not #{obj.position.to_s(16)}" if @stream.length != obj.position
clazz = obj.class.name.split("::").last
send("assemble_#{clazz}".to_sym , obj)
@ -111,11 +111,11 @@ module Register
assemble_self( hash , [ hash.keys , hash.values ] )
end
def assemble_BootSpace(space)
def assemble_Space(space)
assemble_self(space , [space.classes,space.objects, space.symbols,space.messages,space.next_message,space.next_frame] )
end
def assemble_BootClass(clazz)
def assemble_Class(clazz)
assemble_self( clazz , [clazz.name , clazz.super_class_name, clazz.instance_methods] )
end
@ -179,7 +179,7 @@ module Register
end
def add_Array( array )
# also array has constant overhead, the padded helper fixes it to multiple of 8
array.each do |elem|
array.each do |elem|
add_object(elem)
end
end
@ -189,7 +189,7 @@ module Register
add_object(hash.values)
end
def add_BootSpace(space)
def add_Space(space)
add_object(space.main)
add_object(space.classes)
add_object(space.objects)
@ -199,7 +199,7 @@ module Register
add_object(space.next_frame)
end
def add_BootClass(clazz)
def add_Class(clazz)
add_object(clazz.name )
add_object(clazz.super_class_name)
add_object(clazz.instance_methods)
@ -214,7 +214,7 @@ module Register
def add_StringConstant(sc)
end
private
private
# write means we write the resulting address straight into the assembler stream (ie don't return it)
# object means the object of which we write the address

View File

@ -12,7 +12,7 @@ module Builtin
# so it is responsible for initial setup (and relocation)
def __init__ context
function = Virtual::CompiledMethod.new(:__init__ , [] , Virtual::Integer)
clazz = Virtual::BootSpace.space.get_or_create_class :Kernel
clazz = Virtual::Space.space.get_or_create_class :Kernel
method = clazz.resolve_method :main
me = Virtual::Self.new(Virtual::Reference)
code = Virtual::Set.new(Virtual::Self.new(me.type), me)

View File

@ -29,7 +29,7 @@ module Builtin
var_name = get_function.args.first
return_to = get_function.return_type
index_function = ::Virtual::BootSpace.space.get_or_create_class(:Object).resolve_method(:index_of)
index_function = ::Virtual::Space.space.get_or_create_class(:Object).resolve_method(:index_of)
# get_function.push( [me] )
# index = get_function.call( index_function )

View File

@ -23,5 +23,5 @@ module Register
end
end
end
Virtual::BootSpace.space.add_pass "Register::CallImplementation"
Virtual::Machine.instance.add_pass "Register::CallImplementation"
end

View File

@ -18,5 +18,5 @@ module Register
end
end
end
Virtual::BootSpace.space.add_pass "Register::ReturnImplementation"
Virtual::Machine.instance.add_pass "Register::ReturnImplementation"
end

View File

@ -42,5 +42,5 @@ module Register
end
end
end
Virtual::BootSpace.space.add_pass "Register::SetImplementation"
Virtual::Machine.instance.add_pass "Register::SetImplementation"
end

View File

@ -7,7 +7,6 @@ require "virtual/slots/slot"
require "virtual/type"
require "virtual/object"
require "virtual/constants"
require "virtual/boot_space"
# the passes _are_ order dependant
require "virtual/passes/send_implementation"
require "virtual/passes/get_implementation"

View File

@ -20,7 +20,7 @@ also in an similar way that objects have their classes at runtime.
*Ast* instances get created by the salama-reader gem from source.
Here we add compile functions to ast classes and comile the ast layer into Virtual:: objects
The main objects are BootSpace (lots of objects), BootClass (represents a class),
The main objects are Space (lots of objects), BootClass (represents a class),
CompiledMethod (with Blocks and Instruction).
**Virtual** Instructions get further transformed into **register** instructions.

View File

@ -1,139 +0,0 @@
require "register/builtin/object"
module Virtual
# The BootSpace contains all objects for a program. In functional terms it is a program, but in oo
# it is a collection of objects, some of which are data, some classes, some functions
# The main entry is a function called (of all things) "main", This _must be supplied by the compling
# There is a start and exit block that call main, which receives an array of strings
# While data ususally would live in a .data section, we may also "inline" it into the code
# in an oo system all data is represented as objects
class BootSpace < Virtual::ObjectConstant
def initialize
super()
@classes = Parfait::Hash.new_object
#global objects (data)
@objects = []
@symbols = []
@frames = 100.times.collect{ ::Parfait::Frame.new([],[])}
@messages = 100.times.collect{ ::Parfait::Message.new }
@next_message = @messages.first
@next_frame = @frames.first
@passes = [ "Virtual::SendImplementation" ]
end
attr_reader :init , :main , :classes , :objects , :symbols,:messages, :next_message , :next_frame
def run_passes
@passes.each do |pass_class|
blocks = [@init] + main.blocks
@classes.values.each do |c|
c.instance_methods.each {|f| blocks += f.blocks }
end
#puts "running #{pass_class}"
all.each do |block|
pass = eval pass_class
raise "no such pass-class as #{pass_class}" unless pass
pass.new.run(block)
end
end
end
def self.space
if defined? @@space
@@space
else
@@space = BootSpace.new
@@space
end
end
# Passes may be added to by anyone who wants
# This is intentionally quite flexible, though one sometimes has to watch the order of them
# most ordering is achieved by ordering the requires and using add_pass
# but more precise control is possible with the _after and _before versions
def add_pass pass
@passes << pass
end
def add_pass_after( pass , after)
index = @passes.index(after)
raise "No such pass (#{pass}) to add after: #{after}" unless index
@passes.insert(index+1 , pass)
end
def add_pass_before( pass , after)
index = @passes.index(after)
raise "No such pass to add after: #{after}" unless index
@passes.insert(index , pass)
end
# boot the classes, ie create a minimal set of classes with a minimal set of functions
# minimal means only that which can not be coded in ruby
# CompiledMethods are grabbed from respective modules by sending the method name. This should return the
# implementation of the method (ie a method object), not actually try to implement it (as that's impossible in ruby)
def boot_classes!
# 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
obj = get_or_create_class :Object
[:index_of , :_get_instance_variable , :_set_instance_variable].each do |f|
obj.add_instance_method Builtin::Object.send(f , nil)
end
obj = get_or_create_class :Kernel
# create main first, __init__ calls it
@main = Builtin::Kernel.send(:main , @context)
obj.add_instance_method @main
underscore_init = Builtin::Kernel.send(:__init__ ,nil) #store , so we don't have to resolve it below
obj.add_instance_method underscore_init
[:putstring,:exit,:__send].each do |f|
obj.add_instance_method Builtin::Kernel.send(f , nil)
end
# and the @init block in turn _jumps_ to __init__
# the point of which is that by the time main executes, all is "normal"
@init = Virtual::Block.new(:_init_ , nil )
@init.add_code(Register::RegisterMain.new(underscore_init))
obj = get_or_create_class :Integer
[:putint,:fibo].each do |f|
obj.add_instance_method Builtin::Integer.send(f , nil)
end
obj = get_or_create_class :String
[:get , :set , :puts].each do |f|
obj.add_instance_method Builtin::String.send(f , nil)
end
obj = get_or_create_class :Array
[:get , :set , :push].each do |f|
obj.add_instance_method Builtin::Array.send(f , nil)
end
end
@@SPACE = { :names => [:classes,:objects,:symbols,:messages, :next_message , :next_frame] ,
:types => [Virtual::Reference,Virtual::Reference,Virtual::Reference,Virtual::Reference,Virtual::Reference]}
def layout
@@SPACE
end
# Objects are data and get assembled after functions
def add_object o
return if @objects.include?(o)
@objects << o
if o.is_a? Symbol
@symbols << o
end
end
# this is the way to instantiate classes (not BootClass.new)
# so we get and keep exactly one per name
def get_or_create_class name
raise "uups #{name}.#{name.class}" unless name.is_a? Symbol
c = @classes[name]
unless c
c = BootClass.new(name)
@classes[name] = c
end
c
end
def mem_length
padded_words( 5 )
end
end
end

View File

@ -62,7 +62,7 @@ module Virtual
def self.compile_module expression , method
clazz = BootSpace.space.get_or_create_class name
clazz = Space.space.get_or_create_class name
raise "uups #{clazz}.#{name}" unless clazz
to = Return.new(Reference , clazz )
method.add_code Set.new( to , clazz )
@ -73,7 +73,7 @@ module Virtual
def self.compile_string expression , method
value = StringConstant.new(expression.string)
to = Return.new(Reference , value)
BootSpace.space.add_object value
Space.space.add_object value
method.add_code Set.new( to , value )
to
end

View File

@ -9,7 +9,7 @@ module Virtual
r = expression.receiver ? Compiler.compile(expression.receiver, method ) : Self.new()
new_method = CompiledMethod.new(expression.name , args , r )
new_method.class_name = r.is_a?(BootClass) ? r.name : method.class_name
clazz = BootSpace.space.get_or_create_class(new_method.class_name)
clazz = Space.space.get_or_create_class(new_method.class_name)
clazz.add_instance_method new_method
#frame = frame.new_frame

View File

@ -6,7 +6,7 @@ module Virtual
end
def self.compile_class expression , method
clazz = ::BootSpace.space.get_or_create_class expression.name
clazz = ::Space.space.get_or_create_class expression.name
puts "Created class #{clazz.name.inspect}"
expression.expressions.each do |expr|
# check if it's a function definition and add

View File

@ -49,7 +49,7 @@ module Virtual
class_for(MoveInstruction).new(value , self , :opcode => :mov)
end
def clazz
BootSpace.space.get_or_create_class(:String)
Space.space.get_or_create_class(:String)
end
def layout
Virtual::Object.layout

View File

@ -35,15 +35,92 @@ module Virtual
def initialize
@parser = Parser::Salama.new
the_end = Halt.new
@passes = [ "Virtual::SendImplementation" ]
@space = Parfait::Space.new
# @message = Message.new(the_end , the_end , :Object)
end
attr_reader :message
attr_reader :message , :passes , :space
def run_passes
@passes.each do |pass_class|
blocks = [@init] + main.blocks
@classes.values.each do |c|
c.instance_methods.each {|f| blocks += f.blocks }
end
#puts "running #{pass_class}"
all.each do |block|
pass = eval pass_class
raise "no such pass-class as #{pass_class}" unless pass
pass.new.run(block)
end
end
end
# Passes may be added to by anyone who wants
# This is intentionally quite flexible, though one sometimes has to watch the order of them
# most ordering is achieved by ordering the requires and using add_pass
# but more precise control is possible with the _after and _before versions
def add_pass pass
@passes << pass
end
def add_pass_after( pass , after)
index = @passes.index(after)
raise "No such pass (#{pass}) to add after: #{after}" unless index
@passes.insert(index+1 , pass)
end
def add_pass_before( pass , after)
index = @passes.index(after)
raise "No such pass to add after: #{after}" unless index
@passes.insert(index , pass)
end
def self.boot
machine = Machine.new
BootSpace.space.boot_classes! # boot is a verb here
machine.boot
machine
instance = self.instance
instance.boot_classes! # boot is a verb here
instance.boot
instance
end
def self.instance
@instance ||= Machine.new
end
# boot the classes, ie create a minimal set of classes with a minimal set of functions
# minimal means only that which can not be coded in ruby
# CompiledMethods are grabbed from respective modules by sending the method name. This should return the
# implementation of the method (ie a method object), not actually try to implement it (as that's impossible in ruby)
def boot_classes!
# 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
obj = get_or_create_class :Object
[:index_of , :_get_instance_variable , :_set_instance_variable].each do |f|
obj.add_instance_method Builtin::Object.send(f , nil)
end
obj = get_or_create_class :Kernel
# create main first, __init__ calls it
@main = Builtin::Kernel.send(:main , @context)
obj.add_instance_method @main
underscore_init = Builtin::Kernel.send(:__init__ ,nil) #store , so we don't have to resolve it below
obj.add_instance_method underscore_init
[:putstring,:exit,:__send].each do |f|
obj.add_instance_method Builtin::Kernel.send(f , nil)
end
# and the @init block in turn _jumps_ to __init__
# the point of which is that by the time main executes, all is "normal"
@init = Virtual::Block.new(:_init_ , nil )
@init.add_code(Register::RegisterMain.new(underscore_init))
obj = get_or_create_class :Integer
[:putint,:fibo].each do |f|
obj.add_instance_method Builtin::Integer.send(f , nil)
end
obj = get_or_create_class :String
[:get , :set , :puts].each do |f|
obj.add_instance_method Builtin::String.send(f , nil)
end
obj = get_or_create_class :Array
[:get , :set , :push].each do |f|
obj.add_instance_method Builtin::Array.send(f , nil)
end
end
def boot

View File

@ -26,7 +26,7 @@ module Virtual
# Object Object
# BootClass Class
# MetaClass self/Object
# BootSpace ObjectSpace
# Space ObjectSpace
# CompiledMethod Function
# (ruby)Array Array
# String String
@ -68,7 +68,7 @@ module Virtual
@@HASH.merge :keys => object.keys , :values => object.values
when Virtual::BootClass
@@CLAZZ
when Virtual::BootSpace
when Virtual::Space
@@SPACE
else
raise "linker encounters unknown class #{object.class}"

View File

@ -13,5 +13,5 @@ module Virtual
end
end
end
Virtual::BootSpace.space.add_pass "Virtual::EnterImplementation"
Virtual::Machine.instance.add_pass "Virtual::EnterImplementation"
end

View File

@ -23,7 +23,7 @@ module Virtual
else
next
end
space = BootSpace.space
space = Space.space
slot = Virtual::Slot
# a place to store a reference to the space, we grab the next_frame from the space
space_tmp = Register::RegisterReference.new(Virtual::Message::TMP_REG)
@ -46,5 +46,5 @@ module Virtual
end
end
end
Virtual::BootSpace.space.add_pass "Virtual::FrameImplementation"
Virtual::Machine.instance.add_pass "Virtual::FrameImplementation"
end

View File

@ -11,5 +11,5 @@ module Virtual
end
end
end
Virtual::BootSpace.space.add_pass "Virtual::GetImplementation"
Virtual::Machine.instance.add_pass "Virtual::GetImplementation"
end

View File

@ -26,7 +26,7 @@ module Virtual
else
# note: this is the current view: call internal send, even the method name says else
# but send is "special" and accesses the internal method name and resolves.
kernel = Virtual::BootSpace.space.get_or_create_class(:Kernel)
kernel = Virtual::Space.space.get_or_create_class(:Kernel)
method = kernel.get_instance_method(:__send)
new_codes << MethodCall.new( method )
raise "unimplemented #{code}"

View File

@ -13,7 +13,7 @@ require 'parslet/convenience'
module Fragments
# need a code generator, for arm
def setup
@object_space = Boot::BootSpace.new "Arm"
@object_space = Boot::Space.new "Arm"
end
def parse

View File

@ -7,10 +7,10 @@ class HelloTest < MiniTest::Test
machine = Virtual::Machine.boot
expressions = machine.compile_main @string_input
writer = Elf::ObjectWriter.new(Virtual::BootSpace.space)
writer = Elf::ObjectWriter.new(Virtual::Space.space)
writer.save "hello.o"
# puts Sof::Writer.write(expressions)
puts Sof::Writer.write(Virtual::BootSpace.space)
puts Sof::Writer.write(Virtual::Space.space)
end
def qtest_simplest_function

View File

@ -5,7 +5,7 @@ require "yaml"
module VirtualHelper
# need a code generator, for arm
def setup
# @object_space = Boot::BootSpace.new "Arm"
# @object_space = Boot::Space.new "Arm"
end
def check