From 0d43987005f1c44bbffb35919923a8110f134303 Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Sat, 15 Apr 2017 20:58:39 +0300 Subject: [PATCH] start to compile send still very hacked version of simple call, but a start --- lib/mom/instruction.rb | 1 + lib/mom/simple_call.rb | 18 ++++++++ lib/parfait/message.rb | 4 +- lib/vool/ruby_compiler.rb | 2 +- lib/vool/statements/send_statement.rb | 60 ++++++++++++++++++++++++++- stash/message.rb | 38 ----------------- test/vool/to_mom/test_return.rb | 13 ++++++ test/vool/to_mom/test_send.rb | 37 +++++++++++++++++ 8 files changed, 130 insertions(+), 43 deletions(-) create mode 100644 lib/mom/simple_call.rb delete mode 100644 stash/message.rb create mode 100644 test/vool/to_mom/test_send.rb diff --git a/lib/mom/instruction.rb b/lib/mom/instruction.rb index 0c3609cf..df1cce24 100644 --- a/lib/mom/instruction.rb +++ b/lib/mom/instruction.rb @@ -6,5 +6,6 @@ module Mom end +require_relative "simple_call" require_relative "slot_load" require_relative "return_sequence" diff --git a/lib/mom/simple_call.rb b/lib/mom/simple_call.rb new file mode 100644 index 00000000..111ea94c --- /dev/null +++ b/lib/mom/simple_call.rb @@ -0,0 +1,18 @@ +module Mom + + # A SimpleCall is just that, a simple call. This could be called a function call too, + # meaning we managed to resolve the function at compile time and all we have to do is + # actually call it. + # + # As the call setup is done beforehand (for both simple and cached call), the + # calling really means just jumping to the address. Simple. + # + class SimpleCall < Instruction + attr_reader :method + + def initialize(method) + @method = method + end + end + +end diff --git a/lib/parfait/message.rb b/lib/parfait/message.rb index 32d34431..ba147e8c 100644 --- a/lib/parfait/message.rb +++ b/lib/parfait/message.rb @@ -1,6 +1,6 @@ -# A message is what is sent when you invoke a method. Args and stuff are packed up in to a Message -# and the Message is sent to the receiver. +# A message is what is created when a message is sent. Args and stuff are packed up in to a +# Message and the Message is activated (by swapping it into the machine). # Part of the housekeeping (see attributes) makes messages a double linked list (next_message and # caller) , and maybe surprisingly this means that we can create all messages at runtime diff --git a/lib/vool/ruby_compiler.rb b/lib/vool/ruby_compiler.rb index 2866d47a..d17c727e 100644 --- a/lib/vool/ruby_compiler.rb +++ b/lib/vool/ruby_compiler.rb @@ -167,7 +167,7 @@ module Vool # this is a call to super without args (z = zero arity) def on_zsuper exp - SendStatement.new( nil , SuperStatement.new ) + SendStatement.new( nil , SuperStatement.new , nil) end # this is a call to super with args and diff --git a/lib/vool/statements/send_statement.rb b/lib/vool/statements/send_statement.rb index b0a5235d..a9900fe3 100644 --- a/lib/vool/statements/send_statement.rb +++ b/lib/vool/statements/send_statement.rb @@ -2,15 +2,71 @@ module Vool class SendStatement < Statement attr_reader :name , :receiver , :arguments - def initialize(name , receiver , arguments = []) + def initialize(name , receiver , arguments ) @name , @receiver , @arguments = name , receiver , arguments + @arguments ||= [] end def collect(arr) @receiver.collect(arr) - @arguments.collect(arr) + @arguments.each do |arg| + puts "ARG#{arg}" + arg.collect(arr) + end super end + # Sending in a dynamic language is off course not as simple as just calling. + # The function that needs to be called depends after all on the receiver, + # and no guarantees can be made on what that is. + # + # It helps to know that usually (>99%) the class of the receiver does not change. + # Our stategy then is to cache the functions and only dynamically determine it in + # case of a miss (the 1%, and first invocation) + # + # As cache key we must use the type of the object (which is the first word of _every_ object) + # as that is constant, and function implementations depend on the type (not class) + # + # A Send breaks down to 2 steps: + # - Setting up the next message, with receiver, arguments, and (importantly) return address + # - a CachedCall , or a SimpleCall, depending on weather the receiver type can be determined + # + # FIXME: we now presume direct (assignable) values for the arguments and receiver. + # in a not so distant future, temporary variables will have to be created + # and complex statements hoisted to assign to them. pps: same as in conditions + def to_mom( method ) + message_setup + call_instruction + end + + def message_setup + pops = [Mom::SlotConstant.new([:message , :next_message , :receiver] , @receiver) ] + @arguments.each_with_index do |arg , index| + arg_target = [:message , :next_message , :arguments] + pops << Mom::SlotConstant.new( arg_target + index , @arg) + end + pops + end + + def call_instruction + if(receiver_type) + simple_call + else + cached_call + end + end + + def receiver_type + Parfait.object_space.get_class_by_name(:Integer).instance_type + end + def simple_call + type = receiver_type + method = type.get_method(@name) + [Mom::SimpleCall.new( method) ] + end + + def cached_call + [Mom::SlotConstant.new([:message , :next_message , :receiver] , @receiver) ] + end + end end diff --git a/stash/message.rb b/stash/message.rb deleted file mode 100644 index 01c2c852..00000000 --- a/stash/message.rb +++ /dev/null @@ -1,38 +0,0 @@ -module Risc - # So when an object calls a method, or sends a message, this is what it sends: a Message - - # A message contains the sender, return and exceptional return addresses,the arguments, - # and a slot for the named_list. - - # As such it is a very run-time object, deep in the machinery as it were, and does not have - # meaningful methods you could call at compile time. - - # The methods that are there, are nevertheless meant to be called at compile time and generate - # code, rather than executing it. - - # The caller creates the Message and passes control to the receiver's method - - # The receiver create a new NamedList to hold local and temporary variables and (later) creates - # default values for arguments that were not passed - - # How the actual finding of the method takes place (acording to the ruby rules) is not simple, - # but as there is a guaranteed result (be it method_missing) it does not matter to the passing - # mechanism described - - # During compilation Message and named_list objects are created to do type analysis - - class Message - - def initialize me , normal , exceptional - @me = me - @next_normal = normal - @next_exception = exceptional - @arguments = arguments - # a named_list represents the local and temporary variables at a point in the program. - @named_list = nil - end - attr_reader :me, :next_normal, :next_exception, :arguments , :locals - - # - end -end diff --git a/test/vool/to_mom/test_return.rb b/test/vool/to_mom/test_return.rb index 43a08259..6da63f43 100644 --- a/test/vool/to_mom/test_return.rb +++ b/test/vool/to_mom/test_return.rb @@ -34,4 +34,17 @@ module Vool assert_equal IntegerStatement , @stats.first.right.class end end + class TestReturnSendMom < MiniTest::Test + include MomCompile + + def setup + Risc.machine.boot + @stats = compile_first_method( "return foo").first + end + + def test_two_instructions_are_returned +#need to implement send first +# assert_equal 2 , @stats.length + end + end end diff --git a/test/vool/to_mom/test_send.rb b/test/vool/to_mom/test_send.rb new file mode 100644 index 00000000..0c130321 --- /dev/null +++ b/test/vool/to_mom/test_send.rb @@ -0,0 +1,37 @@ +require_relative "helper" + +module Vool + class TestSendMom < MiniTest::Test + include MomCompile + + def setup + Risc.machine.boot + @stats = compile_first_method( "5.mod4").first + end + + def test_class_compiles + assert_equal Mom::SlotConstant , @stats.first.class , @stats + end + def test_slot_is_set + assert @stats.first.left + end + def test_two_instructions_are_returned + assert_equal 2 , @stats.length + end + def test_receiver_class + assert_equal Mom::SlotConstant, @stats.first.class + end + def test_receiver_move + assert_equal :receiver, @stats.first.left[2] + end + def test_call_is + assert_equal Mom::SimpleCall, @stats[1].class + end + def test_call_has_method + assert_equal Parfait::TypedMethod, @stats[1].method.class + end + def test_call_has_right_method + assert_equal :mod4, @stats[1].method.name + end + end +end