diff --git a/lib/parfait/behaviour.rb b/lib/parfait/behaviour.rb index 703399bd..03f075bc 100644 --- a/lib/parfait/behaviour.rb +++ b/lib/parfait/behaviour.rb @@ -41,7 +41,7 @@ module Parfait end # get the method and if not found, try superclasses. raise error if not found - def resolve_method m_name + def resolve_method( m_name ) raise "resolve_method #{m_name}.#{m_name.class}" unless m_name.is_a?(Symbol) method = get_instance_method(m_name) return method if method diff --git a/lib/parfait/space.rb b/lib/parfait/space.rb index b6adee99..2dbade79 100644 --- a/lib/parfait/space.rb +++ b/lib/parfait/space.rb @@ -29,7 +29,7 @@ module Parfait # 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 + class Space < Object def initialize( classes ) @classes = classes @@ -83,13 +83,13 @@ module Parfait end def get_main - kernel = get_class_by_name :Space - kernel.instance_type.get_method :main + space = get_class_by_name :Space + space.instance_type.get_method :main end def get_init - kernel = get_class_by_name :Kernel - kernel.instance_type.get_method :__init__ + object = get_class_by_name :Object + object.instance_type.get_method :__init__ end # get a class by name (symbol) diff --git a/lib/risc/boot.rb b/lib/risc/boot.rb index 3af37483..66abc3f7 100644 --- a/lib/risc/boot.rb +++ b/lib/risc/boot.rb @@ -116,8 +116,9 @@ module Risc # superclasses other than default object def super_class_names - { Object: :Kernel , Kernel: :Value , BinaryCode: :Word , - Data4: :DataObject ,Data8: :DataObject , Integer: :Data4, Word: :Data8} + { Data4: :DataObject , Data8: :DataObject ,Data16: :DataObject , + BinaryCode: :Data16 , Integer: :Data4, Word: :Data8 , + Object: :BasicObject} end # the function really just returns a constant (just avoiding the constant) @@ -137,7 +138,6 @@ module Risc FalseClass: {}, NilClass: {}, Object: {}, - Kernel: {}, #fix, kernel is a class, but should be a module BinaryCode: {next: :BinaryCode} , Space: {classes: :Dictionary , types: :Dictionary , first_message: :Message , next_integer: :Integer , @@ -170,14 +170,10 @@ module Risc space_class.instance_type.add_method Builtin::Space.send(:main, nil) obj = space.get_class_by_name(:Object) - [ :get_internal_word , :set_internal_word , :_method_missing].each do |f| + [ :get_internal_word , :set_internal_word , :_method_missing, + :exit , :__init__].each do |f| obj.instance_type.add_method Builtin::Object.send(f , nil) end - obj = space.get_class_by_name(:Kernel) - # create __init__ main first, __init__ calls it - [:exit , :__init__ ].each do |f| - obj.instance_type.add_method Builtin::Kernel.send(f , nil) - end obj = space.get_class_by_name(:Word) [:putstring , :get_internal_byte , :set_internal_byte , :resolve_method].each do |f| diff --git a/lib/risc/builtin/kernel.rb b/lib/risc/builtin/kernel.rb deleted file mode 100644 index 841aee25..00000000 --- a/lib/risc/builtin/kernel.rb +++ /dev/null @@ -1,74 +0,0 @@ -module Risc - module Builtin - module Kernel - module ClassMethods - include CompileHelper - # this is the really really first place the machine starts (apart from the jump here) - # it isn't really a function, ie it is jumped to (not called), exits and may not return - # so it is responsible for initial setup - def __init__ context - compiler = Risc::MethodCompiler.create_method(:Kernel,:__init__ , - Parfait::NamedList.type_for({}) , Parfait::NamedList.type_for({})) - space = Parfait.object_space - space_reg = compiler.use_reg(:Space) #Set up the Space as self upon init - compiler.add_load_constant("__init__ load Space", space , space_reg) - message_ind = Risc.resolve_to_index( :space , :first_message ) - #load the first_message (instance of space) - compiler.add_slot_to_reg( "__init__ load 1st message" , space_reg , message_ind , :message) - compiler.add_mom( Mom::MessageSetup.new(compiler.method)) - # but use it's next message, so main can return normally - compiler.add_slot_to_reg( "__init__ load 2nd message" , :message , :next_message , :message) - - compiler.add_reg_to_slot( "__init__ store Space in message", space_reg , :message , :receiver) - #fixme: should add arg type here, as done in call_site (which this sort of is) - exit_label = Risc.label("_exit_label for __init__" , "#{compiler.type.object_class.name}.#{compiler.method.name}" ) - ret_tmp = compiler.use_reg(:Label) - compiler.add_load_constant("__init__ load return", exit_label , ret_tmp) - compiler.add_reg_to_slot("__init__ store return", ret_tmp , :message , :return_address) - compiler.add_function_call( "__init__ issue call" , Parfait.object_space.get_main , ret_tmp) - compiler.add_code exit_label - emit_syscall( compiler , :exit ) - return compiler.method - end - - def exit( context ) - compiler = compiler_for(:Kernel,:exit ,{}) - emit_syscall( compiler , :exit ) - return compiler.method - end - - def emit_syscall( compiler , name ) - save_message( compiler ) - compiler.add_code Syscall.new("emit_syscall(#{name})", name ) - restore_message(compiler) - return unless (@clazz and @method) - compiler.add_label( "#{@clazz.name}.#{@message.name}" , "return_syscall" ) - end - - # save the current message, as the syscall destroys all context - # - # This relies on linux to save and restore all registers - # - def save_message(compiler) - r8 = RiscValue.new( :r8 , :Message) - compiler.add_transfer("save_message", Risc.message_reg , r8 ) - end - - def restore_message(compiler) - r8 = RiscValue.new( :r8 , :Message) - return_tmp = compiler.use_reg :fixnum - source = "_restore_message" - # get the sys return out of the way - compiler.add_transfer(source, Risc.message_reg , return_tmp ) - # load the stored message into the base register - compiler.add_transfer(source, r8 , Risc.message_reg ) - int = compiler.use_reg(:Integer) - compiler.add_new_int(source , return_tmp , int ) - # save the return value into the message - compiler.add_reg_to_slot( source , int , :message , :return_value ) - end - end - extend ClassMethods - end - end -end diff --git a/lib/risc/builtin/object.rb b/lib/risc/builtin/object.rb index cda5cd1f..05c3dd13 100644 --- a/lib/risc/builtin/object.rb +++ b/lib/risc/builtin/object.rb @@ -37,9 +37,74 @@ module Risc # Even if it's just this one, sys_exit (later raise) def _method_missing( context ) compiler = compiler_for(:Object,:method_missing ,{}) - Risc::Builtin::Kernel.emit_syscall( compiler , :exit ) + emit_syscall( compiler , :exit ) return compiler.method end + # this is the really really first place the machine starts (apart from the jump here) + # it isn't really a function, ie it is jumped to (not called), exits and may not return + # so it is responsible for initial setup + def __init__ context + compiler = Risc::MethodCompiler.create_method(:Object,:__init__ , + Parfait::NamedList.type_for({}) , Parfait::NamedList.type_for({})) + space = Parfait.object_space + space_reg = compiler.use_reg(:Space) #Set up the Space as self upon init + compiler.add_load_constant("__init__ load Space", space , space_reg) + message_ind = Risc.resolve_to_index( :space , :first_message ) + #load the first_message (instance of space) + compiler.add_slot_to_reg( "__init__ load 1st message" , space_reg , message_ind , :message) + compiler.add_mom( Mom::MessageSetup.new(compiler.method)) + # but use it's next message, so main can return normally + compiler.add_slot_to_reg( "__init__ load 2nd message" , :message , :next_message , :message) + + compiler.add_reg_to_slot( "__init__ store Space in message", space_reg , :message , :receiver) + #fixme: should add arg type here, as done in call_site (which this sort of is) + exit_label = Risc.label("_exit_label for __init__" , "#{compiler.type.object_class.name}.#{compiler.method.name}" ) + ret_tmp = compiler.use_reg(:Label) + compiler.add_load_constant("__init__ load return", exit_label , ret_tmp) + compiler.add_reg_to_slot("__init__ store return", ret_tmp , :message , :return_address) + compiler.add_function_call( "__init__ issue call" , Parfait.object_space.get_main , ret_tmp) + compiler.add_code exit_label + emit_syscall( compiler , :exit ) + return compiler.method + end + + def exit( context ) + compiler = compiler_for(:Object,:exit ,{}) + emit_syscall( compiler , :exit ) + return compiler.method + end + + def emit_syscall( compiler , name ) + save_message( compiler ) + compiler.add_code Syscall.new("emit_syscall(#{name})", name ) + restore_message(compiler) + return unless (@clazz and @method) + compiler.add_label( "#{@clazz.name}.#{@message.name}" , "return_syscall" ) + end + + # save the current message, as the syscall destroys all context + # + # This relies on linux to save and restore all registers + # + def save_message(compiler) + r8 = RiscValue.new( :r8 , :Message) + compiler.add_transfer("save_message", Risc.message_reg , r8 ) + end + + def restore_message(compiler) + r8 = RiscValue.new( :r8 , :Message) + return_tmp = compiler.use_reg :fixnum + source = "_restore_message" + # get the sys return out of the way + compiler.add_transfer(source, Risc.message_reg , return_tmp ) + # load the stored message into the base register + compiler.add_transfer(source, r8 , Risc.message_reg ) + int = compiler.use_reg(:Integer) + compiler.add_new_int(source , return_tmp , int ) + # save the return value into the message + compiler.add_reg_to_slot( source , int , :message , :return_value ) + end + end extend ClassMethods end diff --git a/lib/risc/builtin/space.rb b/lib/risc/builtin/space.rb index b87ff216..ccfe9758 100644 --- a/lib/risc/builtin/space.rb +++ b/lib/risc/builtin/space.rb @@ -24,5 +24,4 @@ end require_relative "integer" require_relative "object" -require_relative "kernel" require_relative "word" diff --git a/lib/risc/builtin/word.rb b/lib/risc/builtin/word.rb index a77db484..1ccd2df9 100644 --- a/lib/risc/builtin/word.rb +++ b/lib/risc/builtin/word.rb @@ -10,7 +10,7 @@ module Risc index = Parfait::Word.get_length_index reg = RiscValue.new(:r2 , :Integer) compiler.add_slot_to_reg( "putstring" , :new_message , index , reg ) - Kernel.emit_syscall( compiler , :putstring ) + Risc::Builtin::Object.emit_syscall( compiler , :putstring ) compiler.add_mom( Mom::ReturnSequence.new) compiler.method end diff --git a/test/parfait/test_space.rb b/test/parfait/test_space.rb index 74de4807..c2aa8cb4 100644 --- a/test/parfait/test_space.rb +++ b/test/parfait/test_space.rb @@ -8,7 +8,7 @@ class TestSpace < MiniTest::Test end def classes - [:Kernel,:Word,:List,:Message,:NamedList,:Type,:Object,:Class,:Dictionary,:TypedMethod , :Integer] + [:Word,:List,:Message,:NamedList,:Type,:Object,:Class,:Dictionary,:TypedMethod , :Integer] end def test_booted diff --git a/test/parfait/type/test_method_api.rb b/test/parfait/type/test_method_api.rb index 8ab08345..1f9beb7e 100644 --- a/test/parfait/type/test_method_api.rb +++ b/test/parfait/type/test_method_api.rb @@ -77,6 +77,6 @@ class TestMethodApi < MiniTest::Test assert_equal :foo , @try_class.instance_type.get_method( :foo ).name end def test_resolve_fail - assert_nil object_type.resolve_method( :foo ) + assert_nil object_type.resolve_method( :foo ) end end