Simulation discrepancy with #return:

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Simulation discrepancy with #return:

Yoshiki Ohshima-3
  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 actuall return and you get 666.

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

-- Yoshiki

Reply | Threaded
Open this post in threaded view
|

Re: Simulation discrepancy with #return:

강진오

Yes, the code simulation still have errors that even the team had to put simulation guard in newProcess.

- Jin-oh -

2012. 3. 13. 오후 7:29에 "Yoshiki Ohshima" <[hidden email]>님이 작성:
 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 actuall return and you get 666.

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

-- Yoshiki



Reply | Threaded
Open this post in threaded view
|

Re: Simulation discrepancy with #return:

Eliot Miranda-2


2012/3/13 강진오 <[hidden email]>

Yes, the code simulation still have errors that even the team had to put simulation guard in newProcess.


This has nothing to do with that.  I think it has to do with simulating terminateTo: and getting the right return context.

- Jin-oh -

2012. 3. 13. 오후 7:29에 "Yoshiki Ohshima" <[hidden email]>님이 작성:

 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 actuall return and you get 666.

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

-- Yoshiki







--
best,
Eliot



Reply | Threaded
Open this post in threaded view
|

Re: Simulation discrepancy with #return:

Eliot Miranda-2
In reply to this post by Yoshiki Ohshima-3


On Tue, Mar 13, 2012 at 3:27 AM, Yoshiki Ohshima <[hidden email]> 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 actuall return and you get 666.

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

I think it is the surrounding usage in the debugger.  The primitive seems to work as advertised.  But the debugger gets confused as to what is the correct continuation afterwards.  i note that if one does step into resume: the right answer is returned, and when that happens doPrimitive:... runs terminateTo:.  When doing step over resume: then terminateTo: is I think run via perform:.

Once again this requires a careful (painful?) instrumenting of the debugger to see what actually happens ;)

 

-- Yoshiki




--
best,
Eliot



Reply | Threaded
Open this post in threaded view
|

Re: Simulation discrepancy with #return:

Eliot Miranda-2
In reply to this post by Yoshiki Ohshima-3
Hi Yoshiki,

On Tue, Mar 13, 2012 at 3:27 AM, Yoshiki Ohshima <[hidden email]> 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 actuall return and you get 666.

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

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.


-- Yoshiki




--
best,
Eliot



Reply | Threaded
Open this post in threaded view
|

Re: Simulation discrepancy with #return:

Yoshiki Ohshima-3
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!

-- Yoshiki

Reply | Threaded
Open this post in threaded view
|

Re: Simulation discrepancy with #return:

Eliot Miranda-2
Hi Yoshiki,  Hi Hans-Martin, Hi All,

On Tue, Mar 13, 2012 at 10:25 AM, Yoshiki Ohshima <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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




ContextPart-runUntilErrorOrReturnFrom.st (3K) Download Attachment
ContextPart-runUntilErrorOrReturnFrom-instrumented.st (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Simulation discrepancy with #return:

Igor Stasenko
Just found this mail.. :)
Will take a look tomorrow.
And, if we're speaking about debugger, there are problems with simulating
<primitive: module: error:>
vs
<primitive: module: >

i'm not sure, how good/bad things in squeak,
but in pharo, Mariano modified the code to get rid of many try:with:with..
but still it doesn't handling simulation of primitives with error codes right.

http://code.google.com/p/pharo/issues/detail?id=5459




--
Best regards,
Igor Stasenko.

Reply | Threaded
Open this post in threaded view
|

Re: Simulation discrepancy with #return:

강진오
In reply to this post by Eliot Miranda-2

I think if it interprets pushThisContext and a push and a send to #return:, It have to simulate return of the value of the push (next to pushThisContext) but I don't know how to hack it.

- Jin-oh -

2012. 3. 14. 오전 3:37에 "Eliot Miranda" <[hidden email]>님이 작성:
Hi Yoshiki,  Hi Hans-Martin, Hi All,

On Tue, Mar 13, 2012 at 10:25 AM, Yoshiki Ohshima <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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






Reply | Threaded
Open this post in threaded view
|

Re: Simulation discrepancy with #return:

Yoshiki Ohshima-3
In reply to this post by Eliot Miranda-2
At Tue, 13 Mar 2012 11:36:52 -0700,
Eliot Miranda wrote:

>
> Hi Yoshiki,  Hi Hans-Martin, Hi All,
>
> On Tue, Mar 13, 2012 at 10:25 AM, Yoshiki Ohshima <[hidden email]> 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.

Sorry for not replying sooner, but it certainly does what I want,
thanks!

OMeta has exhibited another kind of discrepancy between with and
without debugger and I had a slight hope that the same patch would fix
that problem, too; but it wasn't the case.  I'll try to come up with a
simple test case for it.

-- Yoshiki