From b980def84e12ccea248becb56f2b381f4ee4dd9c Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Tue, 12 May 2015 15:36:44 +0300 Subject: [PATCH] move space to parfait Also make the machine the singleton and space hang off it Many repercussions, not all fixed in this commit --- lib/arm/passes/call_implementation.rb | 2 +- lib/arm/passes/constant_implementation.rb | 2 +- lib/arm/passes/get_implementation.rb | 2 +- lib/arm/passes/main_implementation.rb | 2 +- lib/arm/passes/return_implementation.rb | 2 +- lib/arm/passes/save_implementation.rb | 2 +- lib/arm/passes/set_implementation.rb | 2 +- lib/arm/passes/transfer_implementation.rb | 2 +- lib/elf/object_writer.rb | 11 +- lib/parfait.rb | 1 + lib/parfait/class.rb | 2 +- lib/parfait/space.rb | 57 +++++++- lib/register/README.md | 2 +- lib/register/assembler.rb | 20 +-- lib/register/builtin/kernel.rb | 2 +- lib/register/builtin/object.rb | 2 +- lib/register/passes/call_implementation.rb | 2 +- lib/register/passes/return_implementation.rb | 2 +- lib/register/passes/set_implementation.rb | 2 +- lib/virtual.rb | 1 - lib/virtual/README.md | 2 +- lib/virtual/boot_space.rb | 139 ------------------- lib/virtual/compiler/basic_expressions.rb | 4 +- lib/virtual/compiler/function_expression.rb | 2 +- lib/virtual/compiler/module_expression.rb | 2 +- lib/virtual/constants.rb | 2 +- lib/virtual/machine.rb | 87 +++++++++++- lib/virtual/object.rb | 4 +- lib/virtual/passes/enter_implementation.rb | 2 +- lib/virtual/passes/frame_implementation.rb | 4 +- lib/virtual/passes/get_implementation.rb | 2 +- lib/virtual/passes/send_implementation.rb | 2 +- test/fragments/helper.rb | 2 +- test/virtual/hello.rb | 4 +- test/virtual/virtual_helper.rb | 2 +- 35 files changed, 185 insertions(+), 195 deletions(-) delete mode 100644 lib/virtual/boot_space.rb diff --git a/lib/arm/passes/call_implementation.rb b/lib/arm/passes/call_implementation.rb index 84a344b3..e8e9fb35 100644 --- a/lib/arm/passes/call_implementation.rb +++ b/lib/arm/passes/call_implementation.rb @@ -15,5 +15,5 @@ module Arm end end end - Virtual::BootSpace.space.add_pass "Arm::CallImplementation" + Virtual::Machine.instance.add_pass "Arm::CallImplementation" end diff --git a/lib/arm/passes/constant_implementation.rb b/lib/arm/passes/constant_implementation.rb index c9b0ee16..4cee17f8 100644 --- a/lib/arm/passes/constant_implementation.rb +++ b/lib/arm/passes/constant_implementation.rb @@ -9,5 +9,5 @@ module Arm end end end - Virtual::BootSpace.space.add_pass "Arm::ConstantImplementation" + Virtual::Machine.instance.add_pass "Arm::ConstantImplementation" end diff --git a/lib/arm/passes/get_implementation.rb b/lib/arm/passes/get_implementation.rb index 17274162..5ced4a9b 100644 --- a/lib/arm/passes/get_implementation.rb +++ b/lib/arm/passes/get_implementation.rb @@ -9,5 +9,5 @@ module Arm end end end - Virtual::BootSpace.space.add_pass "Arm::GetImplementation" + Virtual::Machine.instance.add_pass "Arm::GetImplementation" end diff --git a/lib/arm/passes/main_implementation.rb b/lib/arm/passes/main_implementation.rb index d7b1943a..b30c0598 100644 --- a/lib/arm/passes/main_implementation.rb +++ b/lib/arm/passes/main_implementation.rb @@ -11,5 +11,5 @@ module Arm end end end - Virtual::BootSpace.space.add_pass "Arm::MainImplementation" + Virtual::Machine.instance.add_pass "Arm::MainImplementation" end diff --git a/lib/arm/passes/return_implementation.rb b/lib/arm/passes/return_implementation.rb index 20e067f4..37bb7bd6 100644 --- a/lib/arm/passes/return_implementation.rb +++ b/lib/arm/passes/return_implementation.rb @@ -9,5 +9,5 @@ module Arm end end end - Virtual::BootSpace.space.add_pass "Arm::ReturnImplementation" + Virtual::Machine.instance.add_pass "Arm::ReturnImplementation" end diff --git a/lib/arm/passes/save_implementation.rb b/lib/arm/passes/save_implementation.rb index 11170f69..73aea7d0 100644 --- a/lib/arm/passes/save_implementation.rb +++ b/lib/arm/passes/save_implementation.rb @@ -14,5 +14,5 @@ module Arm end end end - Virtual::BootSpace.space.add_pass "Arm::SaveImplementation" + Virtual::Machine.instance.add_pass "Arm::SaveImplementation" end diff --git a/lib/arm/passes/set_implementation.rb b/lib/arm/passes/set_implementation.rb index d07acd17..a1f46e32 100644 --- a/lib/arm/passes/set_implementation.rb +++ b/lib/arm/passes/set_implementation.rb @@ -9,5 +9,5 @@ module Arm end end end - Virtual::BootSpace.space.add_pass "Arm::SetImplementation" + Virtual::Machine.instance.add_pass "Arm::SetImplementation" end diff --git a/lib/arm/passes/transfer_implementation.rb b/lib/arm/passes/transfer_implementation.rb index 46cfa9d8..534b50fb 100644 --- a/lib/arm/passes/transfer_implementation.rb +++ b/lib/arm/passes/transfer_implementation.rb @@ -9,5 +9,5 @@ module Arm end end end - Virtual::BootSpace.space.add_pass "Arm::TransferImplementation" + Virtual::Machine.instance.add_pass "Arm::TransferImplementation" end diff --git a/lib/elf/object_writer.rb b/lib/elf/object_writer.rb index cb8b61e6..281c1358 100644 --- a/lib/elf/object_writer.rb +++ b/lib/elf/object_writer.rb @@ -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 \ No newline at end of file +end diff --git a/lib/parfait.rb b/lib/parfait.rb index e05d40bd..d51e9692 100644 --- a/lib/parfait.rb +++ b/lib/parfait.rb @@ -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 diff --git a/lib/parfait/class.rb b/lib/parfait/class.rb index 6fd20c04..ad3bee29 100644 --- a/lib/parfait/class.rb +++ b/lib/parfait/class.rb @@ -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 diff --git a/lib/parfait/space.rb b/lib/parfait/space.rb index fac48c1b..e2db7ff5 100644 --- a/lib/parfait/space.rb +++ b/lib/parfait/space.rb @@ -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 diff --git a/lib/register/README.md b/lib/register/README.md index 0e6693ff..59e7c1a2 100644 --- a/lib/register/README.md +++ b/lib/register/README.md @@ -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 diff --git a/lib/register/assembler.rb b/lib/register/assembler.rb index 7e6551ec..be0a524a 100644 --- a/lib/register/assembler.rb +++ b/lib/register/assembler.rb @@ -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 diff --git a/lib/register/builtin/kernel.rb b/lib/register/builtin/kernel.rb index 54426efe..9020a5ee 100644 --- a/lib/register/builtin/kernel.rb +++ b/lib/register/builtin/kernel.rb @@ -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) diff --git a/lib/register/builtin/object.rb b/lib/register/builtin/object.rb index 63a60927..16aaf8bb 100644 --- a/lib/register/builtin/object.rb +++ b/lib/register/builtin/object.rb @@ -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 ) diff --git a/lib/register/passes/call_implementation.rb b/lib/register/passes/call_implementation.rb index 81b37246..519fab22 100644 --- a/lib/register/passes/call_implementation.rb +++ b/lib/register/passes/call_implementation.rb @@ -23,5 +23,5 @@ module Register end end end - Virtual::BootSpace.space.add_pass "Register::CallImplementation" + Virtual::Machine.instance.add_pass "Register::CallImplementation" end diff --git a/lib/register/passes/return_implementation.rb b/lib/register/passes/return_implementation.rb index 062a6f36..c77f5d57 100644 --- a/lib/register/passes/return_implementation.rb +++ b/lib/register/passes/return_implementation.rb @@ -18,5 +18,5 @@ module Register end end end - Virtual::BootSpace.space.add_pass "Register::ReturnImplementation" + Virtual::Machine.instance.add_pass "Register::ReturnImplementation" end diff --git a/lib/register/passes/set_implementation.rb b/lib/register/passes/set_implementation.rb index 39a92f06..7672abb5 100644 --- a/lib/register/passes/set_implementation.rb +++ b/lib/register/passes/set_implementation.rb @@ -42,5 +42,5 @@ module Register end end end - Virtual::BootSpace.space.add_pass "Register::SetImplementation" + Virtual::Machine.instance.add_pass "Register::SetImplementation" end diff --git a/lib/virtual.rb b/lib/virtual.rb index b046bea5..e4d24a5b 100644 --- a/lib/virtual.rb +++ b/lib/virtual.rb @@ -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" diff --git a/lib/virtual/README.md b/lib/virtual/README.md index 3a2d8d20..3c15c638 100644 --- a/lib/virtual/README.md +++ b/lib/virtual/README.md @@ -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. diff --git a/lib/virtual/boot_space.rb b/lib/virtual/boot_space.rb deleted file mode 100644 index 25ab2e12..00000000 --- a/lib/virtual/boot_space.rb +++ /dev/null @@ -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 diff --git a/lib/virtual/compiler/basic_expressions.rb b/lib/virtual/compiler/basic_expressions.rb index 50d33ad0..cd4a5e7e 100644 --- a/lib/virtual/compiler/basic_expressions.rb +++ b/lib/virtual/compiler/basic_expressions.rb @@ -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 diff --git a/lib/virtual/compiler/function_expression.rb b/lib/virtual/compiler/function_expression.rb index 9dc4aa73..57e7d3dc 100644 --- a/lib/virtual/compiler/function_expression.rb +++ b/lib/virtual/compiler/function_expression.rb @@ -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 diff --git a/lib/virtual/compiler/module_expression.rb b/lib/virtual/compiler/module_expression.rb index 64b4b72f..5b97a265 100644 --- a/lib/virtual/compiler/module_expression.rb +++ b/lib/virtual/compiler/module_expression.rb @@ -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 diff --git a/lib/virtual/constants.rb b/lib/virtual/constants.rb index e744db0c..2766f135 100644 --- a/lib/virtual/constants.rb +++ b/lib/virtual/constants.rb @@ -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 diff --git a/lib/virtual/machine.rb b/lib/virtual/machine.rb index d3c2881e..9b11ecae 100644 --- a/lib/virtual/machine.rb +++ b/lib/virtual/machine.rb @@ -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 diff --git a/lib/virtual/object.rb b/lib/virtual/object.rb index cf52878f..c7c41b93 100644 --- a/lib/virtual/object.rb +++ b/lib/virtual/object.rb @@ -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}" diff --git a/lib/virtual/passes/enter_implementation.rb b/lib/virtual/passes/enter_implementation.rb index 833a5872..e306c01d 100644 --- a/lib/virtual/passes/enter_implementation.rb +++ b/lib/virtual/passes/enter_implementation.rb @@ -13,5 +13,5 @@ module Virtual end end end - Virtual::BootSpace.space.add_pass "Virtual::EnterImplementation" + Virtual::Machine.instance.add_pass "Virtual::EnterImplementation" end diff --git a/lib/virtual/passes/frame_implementation.rb b/lib/virtual/passes/frame_implementation.rb index c22f6d81..7a21d01c 100644 --- a/lib/virtual/passes/frame_implementation.rb +++ b/lib/virtual/passes/frame_implementation.rb @@ -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 diff --git a/lib/virtual/passes/get_implementation.rb b/lib/virtual/passes/get_implementation.rb index 05e073d7..4f7b8e15 100644 --- a/lib/virtual/passes/get_implementation.rb +++ b/lib/virtual/passes/get_implementation.rb @@ -11,5 +11,5 @@ module Virtual end end end - Virtual::BootSpace.space.add_pass "Virtual::GetImplementation" + Virtual::Machine.instance.add_pass "Virtual::GetImplementation" end diff --git a/lib/virtual/passes/send_implementation.rb b/lib/virtual/passes/send_implementation.rb index 899273d6..4befee8c 100644 --- a/lib/virtual/passes/send_implementation.rb +++ b/lib/virtual/passes/send_implementation.rb @@ -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}" diff --git a/test/fragments/helper.rb b/test/fragments/helper.rb index 0b8baa2c..bae10a30 100644 --- a/test/fragments/helper.rb +++ b/test/fragments/helper.rb @@ -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 diff --git a/test/virtual/hello.rb b/test/virtual/hello.rb index 92cd5a2a..1b179f1d 100644 --- a/test/virtual/hello.rb +++ b/test/virtual/hello.rb @@ -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 diff --git a/test/virtual/virtual_helper.rb b/test/virtual/virtual_helper.rb index 8510ab8e..e7ff56fa 100644 --- a/test/virtual/virtual_helper.rb +++ b/test/virtual/virtual_helper.rb @@ -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