From f8e3f1766072b4d64258d28d0dbbc1e1b9038926 Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Thu, 17 Jul 2014 00:53:19 +0300 Subject: [PATCH] split frame into message (caller) and frame (receiver) --- lib/virtual/frame.rb | 57 +++++++++++------------------------------- lib/virtual/machine.rb | 3 ++- lib/virtual/message.rb | 54 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 43 deletions(-) create mode 100644 lib/virtual/message.rb diff --git a/lib/virtual/frame.rb b/lib/virtual/frame.rb index ba382492..99c339f3 100644 --- a/lib/virtual/frame.rb +++ b/lib/virtual/frame.rb @@ -1,48 +1,21 @@ module Virtual - # A frame, or activation frame, represents a function call during calling. So not the static definition of the function - # but the dynamic invokation of it. + # A Message and a Frame make up the two sides of message passing: + # A Message (see details there) is created by the sender and control is transferred + # A Frame is created by the receiver + + # In static languages these two objects are one, because the method is known at compile time. + # In that case the whole frame is usually on the stack, for leaves even omitted and all data is held in registers # - # In a minimal c world this would be just the return address, but with exceptions and continuations things get more - # complicated. How much more we shall see - # - # The current list comprises - # - next normal instruction - # - next exception instruction - # - self (me) - # - argument mappings - # - local variable mapping, together with last called binding + # In a dynamic language the method is dynamically resolved, and so the size of the frame is not know to the caller + # Also exceptions (with the possibility of retry) and the idea of being able to take and store bindings + # make it to say the very least unsensibly tricky to store them on the stack. So we don't. + + # Also at runtime Messages and frames remain completely "normal" objects + class Frame - def initialize normal , exceptional , me - @next_normal = normal - @next_exception = exceptional - @me = me - # a binding represents the local variables at a point in the program. - # The amount of local variables is assumed to be relatively small, and so the - # storage is a linked list. Has the same api as a ha - @binding = List.new - end - attr_reader :next_normal, :next_exception, :me, :binding - - # dummy for the eventual - def new_frame - self - end - # - def compile_get method , name - method.add FrameGet.new(name) - method.get_var(name) - end - - def compile_send method , name , me , with = [] - method.add Virtual::LoadSelf.new(me) - method.add FrameSend.new(name , with ) - Return.new( method.return_type ) - end - - def compile_set method , name , val - method.set_var(name,val) - method.add FrameSet.new(name , val ) - method.get_var(name) + def initialize variables + @variables = variables end + attr_accessor :variables end end diff --git a/lib/virtual/machine.rb b/lib/virtual/machine.rb index 671ed2ac..d2bd98a9 100644 --- a/lib/virtual/machine.rb +++ b/lib/virtual/machine.rb @@ -34,7 +34,7 @@ module Virtual def initialize the_end = Halt.new - @frame = Frame.new(the_end , the_end , :Object) + @frame = Message.new(the_end , the_end , :Object) end attr_reader :frame @@ -54,6 +54,7 @@ require_relative "list" require_relative "instruction" require_relative "method_definition" require_relative "frame" +require_relative "message" require_relative "value" require_relative "type" require_relative "object" diff --git a/lib/virtual/message.rb b/lib/virtual/message.rb new file mode 100644 index 00000000..ef88a59d --- /dev/null +++ b/lib/virtual/message.rb @@ -0,0 +1,54 @@ +module Virtual + # So when an object calls a method, or sends a message, this is what a sends: a Message + + # A message contains the sender, return and exceptional return addresses,the arguments, and a slot for the frame. + + # 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 Frame 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 frame objects are created to do type analysis + + class Message + def initialize me , normal , exceptional + @me = me + @next_normal = normal + @next_exception = exceptional + # a frame represents the local and temporary variables at a point in the program. + @frame = [] + end + attr_reader :me, :next_normal, :next_exception, :frame + + # dummy for the eventual + def new_frame + self + end + # + def compile_get method , name + method.add FrameGet.new(name) + method.get_var(name) + end + + def compile_send method , name , me , with = [] + method.add Virtual::LoadSelf.new(me) + method.add FrameSend.new(name , with ) + Return.new( method.return_type ) + end + + def compile_set method , name , val + method.set_var(name,val) + method.add FrameSet.new(name , val ) + method.get_var(name) + end + end +end