From 3282e0ae06ba9714bc6c9bdfb0623806a1d0111a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20R=C3=BCger?= Date: Sun, 11 Aug 2019 20:36:10 +0300 Subject: [PATCH] transformed object builtins --- lib/risc/builtin.rb | 5 +- lib/risc/builtin/object.rb | 200 +++++++++++++++++-------------- lib/vool/yield_statement.rb | 2 +- test/risc/builtin/test_object.rb | 74 +++++++++++- test/risc/test_builtin.rb | 2 +- 5 files changed, 190 insertions(+), 93 deletions(-) diff --git a/lib/risc/builtin.rb b/lib/risc/builtin.rb index 75e763e5..b87b8813 100644 --- a/lib/risc/builtin.rb +++ b/lib/risc/builtin.rb @@ -37,9 +37,8 @@ module Risc end obj_type = space.get_type_by_class_name(:Object) - [ :get_internal_word , #:set_internal_word , :_method_missing, - #:exit , :__init__ - ].each do |f| + [ :get_internal_word , :set_internal_word , :_method_missing, + :exit , :__init__ ].each do |f| compilers << compiler_for( obj_type , Object , f) end diff --git a/lib/risc/builtin/object.rb b/lib/risc/builtin/object.rb index c8870a1b..b8a91b11 100644 --- a/lib/risc/builtin/object.rb +++ b/lib/risc/builtin/object.rb @@ -28,29 +28,42 @@ module Risc # return the value passed in def set_internal_word( context ) compiler = compiler_for(:Object , :set_internal_word , {at: :Integer, value: :Object} ) - compiler.builder(compiler.source).build do - object! << message[:receiver] - integer! << message[:arguments] - object_reg! << integer[Parfait::NamedList.type_length + 1] #"value" is at index 1 - integer << integer[Parfait::NamedList.type_length + 0] #"at" is at index 0 - integer.reduce_int - object[integer] << object_reg - message[:return_value] << object_reg - end - compiler.add_mom( Mom::ReturnSequence.new) + compiler.add_code SetInternalWord.new("set_internal_word") return compiler end + class SetInternalWord < ::Mom::Instruction + def to_risc(compiler) + compiler.builder(compiler.source).build do + object! << message[:receiver] + integer! << message[:arguments] + object_reg! << integer[Parfait::NamedList.type_length + 1] #"value" is at index 1 + integer << integer[Parfait::NamedList.type_length + 0] #"at" is at index 0 + integer.reduce_int + object[integer] << object_reg + message[:return_value] << object_reg + end + return compiler + end + end + # every object needs a method missing. # Even if it's just this one, sys_exit (later raise) def _method_missing( context ) compiler = compiler_for(:Object,:method_missing ,{}) - builder = compiler.builder(compiler.source) - builder.prepare_int_return # makes integer_tmp variable as return - emit_syscall( builder , :exit ) + compiler.add_code MethodMissing.new("missing") return compiler end + class MethodMissing < ::Mom::Instruction + def to_risc(compiler) + builder = compiler.builder(compiler.source) + builder.prepare_int_return # makes integer_tmp variable as return + Builtin.emit_syscall( builder , :exit ) + return compiler + end + 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: @@ -58,95 +71,108 @@ module Risc # - call main, ie set up message for that etc # - exit (exit_sequence) which passes a machine int out to c def __init__( context ) - compiler = MethodCompiler.compiler_for_class(:Object,:__init__ , + compiler = Mom::MethodCompiler.compiler_for_class(:Object,:__init__ , Parfait::NamedList.type_for({}) , Parfait::NamedList.type_for({})) - builder = compiler.builder(compiler.source) - builder.build do - factory! << Parfait.object_space.get_factory_for(:Message) - message << factory[:next_object] - next_message! << message[:next_message] - factory[:next_object] << next_message - end - - Mom::MessageSetup.new(Parfait.object_space.get_main).build_with( builder ) - - builder.build do - message << message[:next_message] - space? << Parfait.object_space - message[:receiver] << space - end - - exit_label = Risc.label(compiler.source , "#{compiler.receiver_type.object_class.name}.#{compiler.source.name}" ) - ret_tmp = compiler.use_reg(:Label).set_builder(builder) - builder.build do - ret_tmp << exit_label - message[:return_address] << ret_tmp - add_code Risc.function_call( "__init__ issue call" , Parfait.object_space.get_main) - add_code exit_label - end - compiler.reset_regs - exit_sequence(builder) + compiler.add_code MethodMissing.new("missing") return compiler end + class Init < ::Mom::Instruction + def to_risc(compiler) + builder = compiler.builder(compiler.source) + builder.build do + factory! << Parfait.object_space.get_factory_for(:Message) + message << factory[:next_object] + next_message! << message[:next_message] + factory[:next_object] << next_message + end + + Mom::MessageSetup.new(Parfait.object_space.get_main).build_with( builder ) + + builder.build do + message << message[:next_message] + space? << Parfait.object_space + message[:receiver] << space + end + + exit_label = Risc.label(compiler.source , "#{compiler.receiver_type.object_class.name}.#{compiler.source.name}" ) + ret_tmp = compiler.use_reg(:Label).set_builder(builder) + builder.build do + ret_tmp << exit_label + message[:return_address] << ret_tmp + add_code Risc.function_call( "__init__ issue call" , Parfait.object_space.get_main) + add_code exit_label + end + compiler.reset_regs + exit_sequence(builder) + return compiler + end + end + # the exit function # mainly calls exit_sequence def exit( context ) compiler = compiler_for(:Object,:exit ,{}) - builder = compiler.builder(compiler.source) - builder.prepare_int_return # makes integer_tmp variable as return - exit_sequence(builder) + compiler.add_code Exit.new("exit") return compiler end - # a sort of inline version of exit method. - # Used by exit and __init__ (so it doesn't have to call it) - # Assumes int return value and extracts the fixnum for process exit code - def exit_sequence(builder) - save_message( builder ) - builder.build do - message << message[:return_value] - message.reduce_int - add_code Syscall.new("emit_syscall(exit)", :exit ) + class Exit < ::Mom::Instruction + def to_risc(compiler) + builder = compiler.builder(compiler.source) + builder.prepare_int_return # makes integer_tmp variable as return + Builtin.exit_sequence(builder) + return compiler end end - - # emit the syscall with given name - # there is a Syscall instruction, but the message has to be saved and restored - def emit_syscall( builder , name ) - save_message( builder ) - builder.add_code Syscall.new("emit_syscall(#{name})", name ) - restore_message(builder) - return unless (@clazz and @method) - builder.add_code Risc.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(builder) - r8 = RegisterValue.new( :r8 , :Message).set_builder(builder) - builder.build {r8 << message} - end - - # restore the message that we save in r8 - # before th restore, the syscall return, a fixnum, is saved - # The caller of this method is assumed to caal prepare_int_return - # so that the return value already has an integer instance - # This instance is filled with os return value - def restore_message(builder) - r8 = RegisterValue.new( :r8 , :Message) - builder.build do - integer_reg! << message - message << r8 - integer_2! << message[:return_value] - integer_2[Parfait::Integer.integer_index] << integer_reg - end - end - end extend ClassMethods end + + # emit the syscall with given name + # there is a Syscall instruction, but the message has to be saved and restored + def self.emit_syscall( builder , name ) + save_message( builder ) + builder.add_code Syscall.new("emit_syscall(#{name})", name ) + restore_message(builder) + return unless (@clazz and @method) + builder.add_code Risc.label( "#{@clazz.name}.#{@message.name}" , "return_syscall" ) + end + + # a sort of inline version of exit method. + # Used by exit and __init__ (so it doesn't have to call it) + # Assumes int return value and extracts the fixnum for process exit code + def self.exit_sequence(builder) + save_message( builder ) + builder.build do + message << message[:return_value] + message.reduce_int + add_code Syscall.new("emit_syscall(exit)", :exit ) + end + end + + # save the current message, as the syscall destroys all context + # + # This relies on linux to save and restore all registers + # + def self.save_message(builder) + r8 = RegisterValue.new( :r8 , :Message).set_builder(builder) + builder.build {r8 << message} + end + + # restore the message that we save in r8 + # before th restore, the syscall return, a fixnum, is saved + # The caller of this method is assumed to caal prepare_int_return + # so that the return value already has an integer instance + # This instance is filled with os return value + def self.restore_message(builder) + r8 = RegisterValue.new( :r8 , :Message) + builder.build do + integer_reg! << message + message << r8 + integer_2! << message[:return_value] + integer_2[Parfait::Integer.integer_index] << integer_reg + end + end end end diff --git a/lib/vool/yield_statement.rb b/lib/vool/yield_statement.rb index e4e67f40..0170318c 100644 --- a/lib/vool/yield_statement.rb +++ b/lib/vool/yield_statement.rb @@ -39,7 +39,7 @@ module Vool check = Mom::NotSameCheck.new(compile_method , runtime_method, ok_label) # TODO? Maybe create mom instructions for this #builder = compiler.builder("yield") - #Risc::Builtin::Object.exit_sequence(builder) + #Risc::Builtin.exit_sequence(builder) #check << builder.built check << ok_label end diff --git a/test/risc/builtin/test_object.rb b/test/risc/builtin/test_object.rb index f09beb50..277942b6 100644 --- a/test/risc/builtin/test_object.rb +++ b/test/risc/builtin/test_object.rb @@ -2,7 +2,7 @@ require_relative "helper" module Risc module Builtin - class TestObjectFunction1 < BootTest + class TestObjectFunctionGet < BootTest def setup super @method = get_compiler(:get_internal_word) @@ -20,5 +20,77 @@ module Risc assert_equal 20 , @method.to_risc.risc_instructions.length end end + class TestObjectFunctionSet < BootTest + def setup + super + @method = get_compiler(:set_internal_word) + end + def test_has_get_internal + assert_equal Mom::MethodCompiler , @method.class + end + def test_mom_length + assert_equal 5 , @method.mom_instructions.length + end + def test_compile + assert_equal Risc::MethodCompiler , @method.to_risc.class + end + def test_risc_length + assert_equal 21 , @method.to_risc.risc_instructions.length + end + end + class TestObjectFunctionMissing < BootTest + def setup + super + @method = get_compiler(:method_missing) + end + def test_has_get_internal + assert_equal Mom::MethodCompiler , @method.class + end + def test_mom_length + assert_equal 5 , @method.mom_instructions.length + end + def test_compile + assert_equal Risc::MethodCompiler , @method.to_risc.class + end + def test_risc_length + assert_equal 48 , @method.to_risc.risc_instructions.length + end + end + class TestObjectFunctionExit < BootTest + def setup + super + @method = get_compiler(:exit) + end + def test_has_get_internal + assert_equal Mom::MethodCompiler , @method.class + end + def test_mom_length + assert_equal 5 , @method.mom_instructions.length + end + def test_compile + assert_equal Risc::MethodCompiler , @method.to_risc.class + end + def test_risc_length + assert_equal 46 , @method.to_risc.risc_instructions.length + end + end + class TestObjectFunctionInit < BootTest + def setup + super + @method = get_compiler(:__init__) + end + def test_has_get_internal + assert_equal Mom::MethodCompiler , @method.class + end + def test_mom_length + assert_equal 5 , @method.mom_instructions.length + end + def test_compile + assert_equal Risc::MethodCompiler , @method.to_risc.class + end + def test_risc_length + assert_equal 48 , @method.to_risc.risc_instructions.length + end + end end end diff --git a/test/risc/test_builtin.rb b/test/risc/test_builtin.rb index 9f50b286..d6ab2055 100644 --- a/test/risc/test_builtin.rb +++ b/test/risc/test_builtin.rb @@ -14,7 +14,7 @@ module Risc assert_equal Array, @functions.class end def test_boot_function_length - assert_equal 2, @functions.length + assert_equal 6, @functions.length end def test_boot_function_first assert_equal Mom::MethodCompiler, @functions.first.class