Skip to content
  • Yorick Peterse's avatar
    Explicitly bind receivers to blocks and bindings · 79103c8e
    Yorick Peterse authored
    Prior to this commit, "self" was just syntax sugar for obtaining local
    variable 0. This variable in turn was populated by the (implicit)
    argument 0. In other words, this:
    
        def foo(bar) {
          self
        }
    
        foo
    
    Was more or less translated into the following:
    
        def foo(self_arg, bar) {
          self_arg
        }
    
        foo(self, bar)
    
    While fairly simple to implement, this poses two problems:
    
    1. "self" is an implicit argument, which can be confusing for users. For
       example, when using mirrors to obtain the list of method arguments,
       "self" would be included in the list.
    
    2. The VM could not schedule a Block for execution on its own, because
       it doesn't know what object to pass as the first argument (= self).
    
    Problem 2 made it impossible to implement panic hooks in a nice way, and
    any future features that require the VM to schedule blocks (e.g. when
    trapping signals).
    
    To work around this, "self" is now explicitly bound to blocks, when they
    are defined. To execute methods, we use a new instruction:
    RunBlockWithReceiver. This instruction takes a receiver (= the object to
    use for "self") to use when executing the method. The receiver in this
    case will be the object the method was invoked on.
    
    When a block is created, we no longer create a new binding for it.
    Instead, we store the binding that the block captures, which we later
    set as the parent for the new binding when executing the block. This
    removes the need for allocating a Binding for every block that is
    defined, even when never executed. The block also stores the receiver to
    use when executing said block.
    
    This setup also means we can remove quite a bit of nasty bits from the
    compiler, as we no longer need to generate implicit arguments and local
    variables. It also allows us to (in the future) obtain the receiver of a
    block (for meta programming), without having to rely on the exact local
    variable index used to store this object.
    79103c8e