Hi Yoshiki,  Hi Hans-Martin, Hi All,

On Tue, Mar 13, 2012 at 10:25 AM, Yoshiki Ohshima
<[email protected]>wrote:

> At Tue, 13 Mar 2012 10:08:12 -0700,
> Eliot Miranda wrote:
> >
> > In this case runUntilErrorOrReturnFrom: aContext should return the
> sender of the activation of Foo>test and the result to be returned (42).
>  But instead it answers the activation of Foo>test
> > and nil.  Hence the return in ContextPart>return: isn't simulated and
> control passes to the next statement, ^666.
> >
> > Once again I'm drawn into the bowels of runUntilErrorOrReturnFrom:
> > :) It is my nemesis.
>
> This seems close to the realm of magic to me.  Thank you for looking
> into it!
>

Alas, I find it near to magic too.  I understand what's going on.  The
terminateTo: call in resume: doesn't trip the unwind-protect
in runUntilErrorOrReturnFrom: (as it shouldn't; terminateTo: specifically
doesn't run unwinds by design).  So runUntilErrorOrReturnFrom: doesn't
answer the right context to resume.  It answers Foo>test instead of
Foo>test's sender.

What I don't understand is what is a valid criterion for determining these
cases.  I can hack the method, special casing it for ContextPart>return:
and ContextPart>resume:, but that's not acceptable.  So if anyone has the
desire to pair on this let me know.  Perhaps we could have a go at it over
skype sometime soon (not today; already blown a lot of time looking at this
;) ).

In any case I've attached two versions of runUntilErrorOrReturnFrom:, one
instrumented, one not, containing a hack that gets the right answer (in
this case).  Yoshiki, you might play with the uninstrumented one to get you
going.  Hans-Martin, I think you're one of very few people who could shed
light on this.

To use the instrumented one (which prints its arguments and halts between
evaluation and deciding what to return) step the debugger up to e.g. the
send of return:, inspect thisContext (the context about to be sent return:)
and set ContextPart's class var QuickStep to that context (in the inspector
evaluate QuickStep := self).  Then do step.

At least the hack doesn't make things worse; the tests appear the same.

So one thing to do is to play with the hack, ad see if it causes problems.
 Another thing to do is to think about the criterion in the
hacked runUntilErrorOrReturnFrom: when one should return from the
receiver's receiver, rather from aSender's sender.

I'm cc'ing the Pharo list.  Here's Yoshiki's original message and a
substantive reply of mine:


On Tue, Mar 13, 2012 at 3:27 AM, Yoshiki Ohshima <[email protected]>
 wrote:

>  Hello,

>
I noticed that step executing the following code in debugger yields

> different results:

>
-------------------

> test

>
       3 < 4 ifTrue: [

>                thisContext return: 42].

>        ^ 666.

> -------------------

>
In the normal execution, you get 42 as expected, but if you debug it

> and step execute, #return: does not actually return and you get 666.

>
It appears that the primitive for #terminateTo: is the culprit...

-- Yoshiki

On Tue, Mar 13, 2012 at 10:08 AM, Eliot Miranda <[email protected]>
 wrote:

> Hi Yoshiki,

>From what I can see so far it is the return value from
runUntilErrorOrReturnFrom: in complete: when the debugger executes test's
return: call.  i.e. the debugged process is in Foo>>test at pc 43:

37 <22> pushConstant: 3
38 <23> pushConstant: 4
39 <B2> send: <
40 <9B> jumpFalse: 45
41 <89> pushThisContext:
42 <21> pushConstant: 42
43 <E0> send: return:
44 <87> pop
45 <24> pushConstant: 666
46 <7C> returnTop

The stack in the debugger is
Process>>complete:
Process>>completeStep:
Debugger>>doStep



and Process>complete: is

complete: aContext
"Run self until aContext is popped or an unhandled error is raised.  Return
self's new top context, unless an unhandled error was raised then return
the signaler context (rather than open a debugger)."

| ctxt pair error |
ctxt := suspendedContext.
suspendedContext := nil.  "disable this process while running its stack in
active process below"
pair := ctxt runUntilErrorOrReturnFrom: aContext.
suspendedContext := pair first.
error := pair second.
error ifNotNil: [^ error signalerContext].
^ suspendedContext

where the receiver is the activation of Foo>test, and aContext is the
activation of ContextPart>return: (whose receiver is also the receiver of
complete:, the activation of Foo>test).

In this case runUntilErrorOrReturnFrom: aContext should return the sender
of the activation of Foo>test and the result to be returned (42).  But
instead it answers the activation of Foo>test and nil.  Hence the return in
ContextPart>return: isn't simulated and control passes to the next
statement, ^666.

Once again I'm drawn into the bowels of runUntilErrorOrReturnFrom: :) It is
my nemesis.
-- 
best,
Eliot
-- 
best,
Eliot

Attachment: ContextPart-runUntilErrorOrReturnFrom.st
Description: Binary data

Attachment: ContextPart-runUntilErrorOrReturnFrom-instrumented.st
Description: Binary data

Reply via email to