<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Sat, Jan 12, 2013 at 1:40 PM, Ryan Macnak <span dir="ltr">&lt;<a href="mailto:rmacnak@gmail.com" target="_blank">rmacnak@gmail.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"> <br>In Smalltalk, one knows at compile-time at which class to begin lookup for super sends. In Newspeak, we do not know this as all methods are defined by mixins, and the superclass of a mixin application is not known until runtime. Hence /dynamic/ super send.<div>

<br></div><div>In Newspeak&#39;s as-yet-unimplemented access control, super sends can activate protected members, but normal sends cannot. An /absent receiver/ send means that the receiver of the message is not on stack beneath the arguments like a normal send. This will allow the VM to implement access control without having to check whether the receiver is allowed for types of sends that access protected or private members, because the VM will provide the receiver during the send itself.<br>
</div></blockquote><div><br></div><div>+1.  But there&#39;s another aspect to it.  Newspeak, like self, does not require one to explicitly supply self as the receiver of self-sends.  Further, Newspeak is a lexically-scoped language (like Beta) so that one always writes methods within the scope of a class definition, and other than top-level classes, writes a class in the scope of an outer class.  The methods defined in outer classes are hence still in scope in inner methods.  e.g. in the following (excuse syntax errors)</div>
<div><br></div><div>    class Outer () (</div><div>        anOuterMethod = (^&#39;This is the result of an outer method&#39;)</div><div>        class Inner () (</div><div>            anInnerMethod = ( ^anOuterMethod )</div>
            anOtherInnerMethod = ( ^anInnerMethod )<div>        )</div><div>    )</div><div><br></div><div>the method anOuterMethod is in scope throughout class Inner.  So that when one writes ^anOuterMethod in anInnerMethod this is *not* equivalent to ^self anOuterMethod.  instead the receiver is actually the class Outer.</div>
<div><br></div><div>So in Newspeak sends without a receiver are &quot;absent receiver&quot; sends or &quot;implicit receiver&quot; and the binding machinery must find the implicit receiver for an implicit receiver send by searching along the lexical chain *not* the inheritance chain.  The class Inner does not inherit from class Outer; it inherits from whatever class we specify at module creation, e.g. its superclass could be some class imported into the module when it is instantiated.  We *don&#39;t* want an inherited definition of e.g. anOuterMethod to override anOuterMethod because then the language would no longer be lexically-scoped.</div>
<div><br></div><div>Now, in the first implementation of Newspeak above Squeak we added a bytecode pushImplicitReceiverForSelector that would do a lexical lookup of a selector and push the receiver along the lexical chain that implemented selector.  pushImplicitReceiverForSelector would always be paired with a subsequent send of selector.  But this is unsatisfactory, a) because of the security concerns Ryan mentions above, and b) because the two bytecodes are a waste; they always go together and c) there&#39;s a hole because if the method is removed between pushImplicitReceiverForSelector and its send we&#39;d get an erroneous MNU.</div>
<div><br></div><div>In the new bytecode set we therefore implemented absent receiver sends such that the receiver is actually determined by the send bytecode.  The compiler arranges to push the arguments, but not the receiver, and the receiver is pushed at send time (hence the arguments needs to be shuffled down the stack and the receiver inserted, something that the JIT can do efficiently in many cases since arguments are passed in registers for low arity sends and there is often nothing on the stack to shuffle).</div>
<div><br></div><div>So briefly, in Newspeak an implicit receiver send is a send without an explicit receiver that is found by looking up the lexical chain, not the inheritance chain.</div><div><br></div><div>See <a href="http://bracha.org/newspeak-spec.pdf">http://bracha.org/newspeak-spec.pdf</a>.</div>
<div><br></div><blockquote class="gmail_quote" style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div><div class="gmail_quote">On Sat, Jan 12, 2013 at 3:35 AM, stephane ducasse <span dir="ltr">&lt;<a href="mailto:stephane.ducasse@gmail.com" target="_blank">stephane.ducasse@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

<br>
Hi eliot<br>
<br>
I&#39;m curious: what is a absent receiver dynamic super send?<br>
<br>
Stef<br>
<div><div>On Jan 10, 2013, at 11:27 PM, <a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a> wrote:<br>
<br>
&gt;<br>
&gt; Eliot Miranda uploaded a new version of VMMaker to project VM Maker:<br>
&gt; <a href="http://source.squeak.org/VMMaker/VMMaker.oscog-eem.253.mcz" target="_blank">http://source.squeak.org/VMMaker/VMMaker.oscog-eem.253.mcz</a><br>
&gt;<br>
&gt; ==================== Summary ====================<br>
&gt;<br>
&gt; Name: VMMaker.oscog-eem.253<br>
&gt; Author: eem<br>
&gt; Time: 10 January 2013, 3:26:03.577 pm<br>
&gt; UUID: 4a3ac3fb-d367-478b-ad95-ad3bb8b6216f<br>
&gt; Ancestors: VMMaker.oscog-eem.252<br>
&gt;<br>
&gt; Implement absent receiver dynamic super send bytecode in the JIT.<br>
&gt; This was an oversight from implementing absent receiver send.<br>
&gt; Refactor the dynamic super send code to accomodate the new send.<br>
&gt;<br>
&gt; =============== Diff against VMMaker.oscog-eem.252 ===============<br>
&gt;<br>
&gt; Item was changed:<br>
&gt;  ----- Method: SimpleStackBasedCogit&gt;&gt;genDynamicSuperSendBytecode (in category &#39;bytecode generators&#39;) -----<br>
&gt;  genDynamicSuperSendBytecode<br>
&gt; +     ^self genSendDynamicSuper: (coInterpreter literal: byte2 ofMethod: methodObj) numArgs: byte1!<br>
&gt; -     | numArgs selector |<br>
&gt; -     numArgs := byte1.<br>
&gt; -     selector := coInterpreter literal: byte2 ofMethod: methodObj.<br>
&gt; -     (objectMemory isYoung: selector) ifTrue:<br>
&gt; -             [hasYoungReferent := true].<br>
&gt; -     self assert: needsFrame.<br>
&gt; -     self MoveMw: numArgs * BytesPerWord r: SPReg R: ReceiverResultReg.<br>
&gt; -     numArgs &gt; 2 ifTrue:<br>
&gt; -             [self MoveCq: numArgs R: SendNumArgsReg].<br>
&gt; -     self MoveCw: selector R: ClassReg.<br>
&gt; -     self CallNewspeakSend: (dynamicSuperSendTrampolines at: (numArgs min: NumSendTrampolines - 1)).<br>
&gt; -     self flag: &#39;currently caller pushes result&#39;.<br>
&gt; -     self PushR: ReceiverResultReg.<br>
&gt; -     ^0!<br>
&gt;<br>
&gt; Item was changed:<br>
&gt;  ----- Method: SimpleStackBasedCogit&gt;&gt;genExtSendAbsentDynamicSuperBytecode (in category &#39;bytecode generators&#39;) -----<br>
&gt;  genExtSendAbsentDynamicSuperBytecode<br>
&gt;       &quot;241            11110001        i i i i i j j j Send To Absent Dynamic Superclass Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments&quot;<br>
&gt; +     | litIndex nArgs |<br>
&gt; +     litIndex := (byte1 &gt;&gt; 3) + (extA &lt;&lt; 5).<br>
&gt; +     extA := 0.<br>
&gt; +     nArgs := (byte1 bitAnd: 7) + (extB &lt;&lt; 3).<br>
&gt; +     extB := 0.<br>
&gt; +     ^self genSendAbsentDynamicSuper: (coInterpreter literal: litIndex ofMethod: methodObj) numArgs: nArgs!<br>
&gt; -     self shouldBeImplemented.<br>
&gt; -     ^EncounteredUnknownBytecode!<br>
&gt;<br>
&gt; Item was added:<br>
&gt; + ----- Method: SimpleStackBasedCogit&gt;&gt;genSendAbsentDynamicSuper:numArgs: (in category &#39;bytecode generators&#39;) -----<br>
&gt; + genSendAbsentDynamicSuper: selector numArgs: numArgs<br>
&gt; +     &quot;Shuffle arguments if necessary and push receiver.<br>
&gt; +      Then send.&quot;<br>
&gt; +     &lt;inline: false&gt;<br>
&gt; +     numArgs = 0<br>
&gt; +             ifTrue:<br>
&gt; +                     [self PushR: ReceiverResultReg]<br>
&gt; +             ifFalse:<br>
&gt; +                     [self MoveMw: 0 r: SPReg R: TempReg.<br>
&gt; +                     self PushR: TempReg.<br>
&gt; +                     2 to: numArgs do:<br>
&gt; +                             [:index|<br>
&gt; +                             self MoveMw: index * BytesPerWord r: SPReg R: TempReg.<br>
&gt; +                             self MoveR: TempReg Mw: index - 1 * BytesPerWord r: SPReg].<br>
&gt; +                     &quot;if we copied the code in genSendDynamicSuper: we could save an instruction.<br>
&gt; +                     But we care not; the smarts are in StackToRegisterMappingCogit et al&quot;<br>
&gt; +                     self MoveR: ReceiverResultReg Mw: numArgs * BytesPerWord r: SPReg].<br>
&gt; +     ^self genSendDynamicSuper: selector numArgs: numArgs!<br>
&gt;<br>
&gt; Item was added:<br>
&gt; + ----- Method: SimpleStackBasedCogit&gt;&gt;genSendDynamicSuper:numArgs: (in category &#39;bytecode generators&#39;) -----<br>
&gt; + genSendDynamicSuper: selector numArgs: numArgs<br>
&gt; +     (objectMemory isYoung: selector) ifTrue:<br>
&gt; +             [hasYoungReferent := true].<br>
&gt; +     self assert: needsFrame.<br>
&gt; +     self MoveMw: numArgs * BytesPerWord r: SPReg R: ReceiverResultReg.<br>
&gt; +     numArgs &gt; 2 ifTrue:<br>
&gt; +             [self MoveCq: numArgs R: SendNumArgsReg].<br>
&gt; +     self MoveCw: selector R: ClassReg.<br>
&gt; +     self CallNewspeakSend: (dynamicSuperSendTrampolines at: (numArgs min: NumSendTrampolines - 1)).<br>
&gt; +     self flag: &#39;currently caller pushes result&#39;.<br>
&gt; +     self PushR: ReceiverResultReg.<br>
&gt; +     ^0!<br>
&gt;<br>
&gt; Item was removed:<br>
&gt; - ----- Method: StackToRegisterMappingCogit&gt;&gt;genDynamicSuperSendBytecode (in category &#39;bytecode generators&#39;) -----<br>
&gt; - genDynamicSuperSendBytecode<br>
&gt; -     | numArgs selector |<br>
&gt; -     numArgs := byte1.<br>
&gt; -     selector := coInterpreter literal: byte2 ofMethod: methodObj.<br>
&gt; -     self marshallSendArguments: numArgs.<br>
&gt; -     ^self genMarshalledSendDynamicSuper: selector numArgs: numArgs!<br>
&gt;<br>
&gt; Item was added:<br>
&gt; + ----- Method: StackToRegisterMappingCogit&gt;&gt;genSendAbsentDynamicSuper:numArgs: (in category &#39;bytecode generators&#39;) -----<br>
&gt; + genSendAbsentDynamicSuper: selector numArgs: numArgs<br>
&gt; +     &quot;OK, we could do better and avoid spilling ReceiverResultReg if we refactored<br>
&gt; +      marshallImplicitReceiverSendArguments: to take a flag saying whether the<br>
&gt; +      receiver was in ReceiverResultReg (absent receiver send) or on the stack<br>
&gt; +      (absent dynamic super send) and in the latter case loading ReceiverResultReg<br>
&gt; +      from the stack after marshalling.  But this is a rare bytecode so for the moment<br>
&gt; +      don&#39;t bother.&quot;<br>
&gt; +     self ssAllocateCallReg: ReceiverResultReg.<br>
&gt; +     self MoveMw: FoxMFReceiver r: FPReg R: ReceiverResultReg.<br>
&gt; +     self marshallImplicitReceiverSendArguments: numArgs.<br>
&gt; +     ^self genMarshalledSendDynamicSuper: selector numArgs: numArgs!<br>
&gt;<br>
&gt; Item was added:<br>
&gt; + ----- Method: StackToRegisterMappingCogit&gt;&gt;genSendDynamicSuper:numArgs: (in category &#39;bytecode generators&#39;) -----<br>
&gt; + genSendDynamicSuper: selector numArgs: numArgs<br>
&gt; +     self marshallSendArguments: numArgs.<br>
&gt; +     ^self genMarshalledSendDynamicSuper: selector numArgs: numArgs!<br>
&gt;<br>
<br>
</div></div></blockquote></div><br></div>
<br></blockquote></div><br><br clear="all"><div><br></div>-- <br>best,<div>Eliot</div>
</div></div>