[Vm-dev] [Pharo-project] is there a way to avoid all the #tryNamedPrimitive:with: * in ProtoObject

Mariano Martinez Peck marianopeck at gmail.com
Thu Jan 26 19:11:03 UTC 2012


Well. My final proposal is in:
http://code.google.com/p/pharo/issues/detail?id=5223
With comments and some small refactors. As said, I would love if someone
can take a view before integrating.

Cheers

On Thu, Jan 26, 2012 at 7:25 PM, Eliot Miranda <eliot.miranda at gmail.com>wrote:

>
>
>
> On Thu, Jan 26, 2012 at 6:00 AM, Igor Stasenko <siguctua at gmail.com> wrote:
>
>>
>> On 26 January 2012 14:42, Mariano Martinez Peck <marianopeck at gmail.com>
>> wrote:
>> >
>> >
>> >
>> > On Thu, Jan 26, 2012 at 11:38 AM, Igor Stasenko <siguctua at gmail.com>
>> wrote:
>> >>
>> >>
>> >> On 26 January 2012 11:25, stephane ducasse <stephane.ducasse at gmail.com>
>> wrote:
>> >> >
>> >> >> phew... done reading through overquoting :)
>> >> >>
>> >> >> +1000 to removing tryXYZprimitive:
>> >> >>
>> >> >> I was always wondering what those methods for, until i met a need to
>> >> >> support debugging when invoking nativeboost-prim methods,
>> >> >> because it needs special handing when invoking methods with native
>> >> >> code via debugger.
>> >> >>
>> >> >> Then i understood that this mechanism is necessary.. yet a bit
>> awkward..
>> >> >>
>> >> >> Funny. Even after implementing the fix, I still do not understand
>> why all these is needed. Can someone explain to a newbie why invoking
>> primitives (whether they are normal primitives, named primitives or NB
>> primitives) from the debugger is different than invoking them normally (as
>> when they are invoked by normal code)
>> >> >
>> >> > Yes I want to understand too.
>> >> >
>> >>
>> >> Here the hint for you:
>> >>  - what should happen when you doing 'step in' on method, which has a
>> primitive?
>> >>
>> >> Apparently, it should invoke that primitive , otherwise you will have
>> >> difference between running and debugging modes,
>> >> and will have different results, which makes debugger useless.
>> >> So debugger should detect "somehow" if primitive was failed, and then
>> >> step in into given method,
>> >> or if its not, then step in = step over.
>> >>
>> >> And these 'tryXYZ ... ' is exactly for solving this dilemma.
>> >
>> >
>> > Thanks Igor. So I wrote what I understood. Problem is that I always
>> write for newbies (like me) so if it is too obvios or too long to put it as
>> comment, let me know.
>> > I would appreaciate if someone can validate what I wrote.
>> > Today I will create a slice with mentioned solution + comments +
>> removal of all those tryNamedPrimitive*.
>> >
>> > ----
>> >
>> > "When using the debugger we want to run a method step by step. But what
>> happens when we do a step into a CompiledMethod which has a primitive? If
>> such a method is executed form outside the Debugger (normal scenario) the
>> VM knows that such CompiledMethod has a primitive declaration and hence
>> executes it. If it fails, then it continues executing all the bytecodes of
>> the method. Otherwise, it just returns.
>> >
>> > Now, what is the problem with the Debugger? The problem is that if the
>> primitive fail, we don't want that the VM directly executes all the
>> remaining bytecodes of the method. Instead, we would like to go step by
>> step with he Debugger, just as happens with normal methods.
>> >
>> > To solve the mentioned problem, we use the following trick: We have the
>> original compiled method (the one that has a primitive invocation), the
>> receiver and the arguments. So the idea is to use a template compiled
>> method that ONLY contains the primitive declaration (it doesn't include all
>> the original smalltalk code after the primitive).
>> #tryNamedPrimitiveTemplateMethod answers such a template method which looks
>> like:
>> >
>> > tryNamedPrimitive
>> >     <primitive:'to be set later' module:'to be ser later'>
>> >     ^ ContextPart primitiveFailToken'
>> >
>> >  Since this method does not change its bytecodes for every invocation,
>> we can reuse it for all methods with primitives. There are only 2 things we
>> have to change in the template: the number of arguments and the primitive
>> declaration (to use the correct primitive name and module name).
>> >
>> > Then what we do is to run that compiled method with the receiver and
>> arguments we have. The result is that we will be invoking almost the same
>> original method but a slightly different version that does not have the
>> smalltalk part after the primitive and that in contrast is sends
>> #primitiveFailToken (which tells the Debugger what to do after). If this
>> method invocation does not fail, then the Debugger continues debugging the
>> sender of the primitive method. In this case, the step in is the same as
>> step over. If the primitive fails, then the debugger continues executing
>> the smalltalk part after the primitive method. In this case, step in is a
>> real step in.  "
>> >
>> >
>> There's another problem with using "tryXYZ" when primitive doing
>> something weird with contexts (like block's #value)
>> because then debugger cannot intercept switching contexts so easily,
>> when primitive doing manipulation with contexts,
>> because debugger have no idea where to put his next "break point" to
>> do step-by-step evaluation.
>>
>> I thinking that there should be special primitive which:
>>  - takes a context, a receiver, a method and arguments (or just a
>> context, if debugger ensures to pass it in prepared state i.e.
>> receiver and args already on stack)
>>  - invokes method's primitive
>>  - answers a nil if primitive failed or a new context object, which
>> holds an updated context state after primitive possibly manipulated
>> with context(s)
>>
>
> No, not needed.  Manipulation of contexts does not require primitives
> since contexts are first-class, and the effect of these primitives can be
> simulated in Smalltalk (just as the effect of executing bytecodes can be
> simulated).  Look at the caller of tryPrimitive:withArgs: and
> tryNamedPrimitiveIn:for:withArgs:, namely
> ContextPart>doPrimitive:method:receiver:args:.  It handles all these
> primitives such as perform:[*], value[:value:*], withArgs:executeMethod:.
>
>
>
>> so, then debugger will use it like:
>>
>> contextOrNil := self invokeMethodPrimitive: method context:
>> currentContext receiver: recvr arguments: args
>> contextOrNil ifNil: [ primitive failed .. ]
>> ifNotNil: [
>>  currentContext := contextOrNil
>> ].
>>
>> --
>> Best regards,
>> Igor Stasenko.
>>
>
>
>
> --
> best,
> Eliot
>
>
>


-- 
Mariano
http://marianopeck.wordpress.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20120126/8a199688/attachment-0001.htm


More information about the Vm-dev mailing list