[squeak-dev] Exception and defaultAction

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

[squeak-dev] Exception and defaultAction

Bergel, Alexandre
Dear List,

I wish to understand a crucial (and difficult) point of the Squeak  
exception handling mechanism.
Basically, my question is: How a debugger gets opened when an  
exception is thrown?

Clearly, the method Error>>defaultAction gets invoked somehow. By  
UndefinedObject>>handleSignal: when reaching the bottom of the method  
call stack I suspect.
I suspect that this handleSignal: is called by a Exception>>pass. So,  
my question is where? in PasteUpMorph>>becomeActiveDuring: ?

This is not easy to figure out since when a debugger gets opened, the  
part of the stack used to open it is discarded (how?).

Cheers,
Alexandre

--
_,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:
Alexandre Bergel  http://www.bergel.eu
^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;.






Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Exception and defaultAction

Lukas Renggli
>  This is not easy to figure out since when a debugger gets opened, the part
> of the stack used to open it is discarded (how?).

Error>>#defaultAction raises a new exception, the UnhandledError.
UnhandledError has an instance-variable to remember the original
exception.

UnhandledError opens the debugger as part of the #defaultAction. The
debugger uses the stack-frame of the original exception to display at
the top level. That's why you don't see the handling code itself.

Lukas

--
Lukas Renggli
http://www.lukas-renggli.ch

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Exception and defaultAction

Bergel, Alexandre
Thanks Lukas!

Cheers,
Alexandre

On 6 Aug 2008, at 14:55, Lukas Renggli wrote:

>> This is not easy to figure out since when a debugger gets opened,  
>> the part
>> of the stack used to open it is discarded (how?).
>
> Error>>#defaultAction raises a new exception, the UnhandledError.
> UnhandledError has an instance-variable to remember the original
> exception.
>
> UnhandledError opens the debugger as part of the #defaultAction. The
> debugger uses the stack-frame of the original exception to display at
> the top level. That's why you don't see the handling code itself.
>
> Lukas
>
> --
> Lukas Renggli
> http://www.lukas-renggli.ch
>

--
_,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:
Alexandre Bergel  http://www.bergel.eu
^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;.






Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Exception and defaultAction

stephane ducasse
In reply to this post by Lukas Renggli
Lukas

This was not the exact question. We were discussing to know who is  
really calling defaultAction (I know how the debugger
is raised). The question is who is calling defaultAction when the  
stack is empty.
Is it the VM or something else.

Now in the image the only sender is

UndefinedObject>>handleSignal: exception
        "When no more handler (on:do:) context left in sender chain this gets  
called.  Return from signal with default action."

        ^ exception resumeUnchecked: exception defaultAction

Who is calling handleSignal:

Exception>>pass
        "Yield control to the enclosing exception action for the receiver."

        handlerContext nextHandlerContext handleSignal: self

Exception>>signal
        "Ask ContextHandlers in the sender chain to handle this signal.  The  
default is to execute and return my defaultAction."

        signalContext := thisContext contextTag.
        ^ thisContext nextHandlerContext handleSignal: self

ContextPart>>handleSignal: exception
        "Sent to handler (on:do:) contexts only.  If my exception class  
(first arg) handles exception then execute my handle block (second  
arg), otherwise forward this message to the next handler context.  If  
none left, execute exception's defaultAction (see nil>>handleSignal:)."

        | val |
        (((self tempAt: 1) handles: exception) and: [self tempAt: 3])  
ifFalse: [
                ^ self nextHandlerContext handleSignal: exception].

        exception privHandlerContext: self contextTag.
        self tempAt: 3 put: false.  "disable self while executing handle block"
        val := [(self tempAt: 2) valueWithPossibleArgs: {exception}]
                ensure: [self tempAt: 3 put: true].
        self return: val.  "return from self if not otherwise directed in  
handle block"

So it seems that this is signal and when handleSignal: arrives on nil  
then the default action is fetch.

Can somebody with a VM knowledge validate my hypothesis?

Setf





On Aug 6, 2008, at 2:55 PM, Lukas Renggli wrote:

>> This is not easy to figure out since when a debugger gets opened,  
>> the part
>> of the stack used to open it is discarded (how?).
>
> Error>>#defaultAction raises a new exception, the UnhandledError.
> UnhandledError has an instance-variable to remember the original
> exception.
>
> UnhandledError opens the debugger as part of the #defaultAction. The
> debugger uses the stack-frame of the original exception to display at
> the top level. That's why you don't see the handling code itself.
>
> Lukas
>
> --
> Lukas Renggli
> http://www.lukas-renggli.ch
>
>


Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Exception and defaultAction

Bergel, Alexandre
Stef, defaultAction is called by either ContextPart>>handleSignal: and  
UndefinedObject>>handleSignal:
At the bottom of the method call stack (when looking for an  
appropriate handler), the latter gets invoked. This method is defined  
as:

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
UndefinedObject>>handleSignal: exception
        "When no more handler (on:do:) context left in sender chain this gets  
called.  Return from signal with default action."

        ^ exception resumeUnchecked: exception defaultAction
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

The question is who call this handleSignal: ?
It could either be Exception>>pass and Exception>>signal.

But I feel this is Exception>>pass according to what I can find by  
inspecting the stack of a "self halt" in a workspace:
PasteUpMorph>>becomeActiveDuring:

Anyone can confirm or infirm that?

Cheers,
Alexandre


On 7 Aug 2008, at 18:03, stephane ducasse wrote:

> Lukas
>
> This was not the exact question. We were discussing to know who is  
> really calling defaultAction (I know how the debugger
> is raised). The question is who is calling defaultAction when the  
> stack is empty.
> Is it the VM or something else.
>
> Now in the image the only sender is
>
> UndefinedObject>>handleSignal: exception
> "When no more handler (on:do:) context left in sender chain this  
> gets called.  Return from signal with default action."
>
> ^ exception resumeUnchecked: exception defaultAction
>
> Who is calling handleSignal:
>
> Exception>>pass
> "Yield control to the enclosing exception action for the receiver."
>
> handlerContext nextHandlerContext handleSignal: self
>
> Exception>>signal
> "Ask ContextHandlers in the sender chain to handle this signal.  
> The default is to execute and return my defaultAction."
>
> signalContext := thisContext contextTag.
> ^ thisContext nextHandlerContext handleSignal: self
>
> ContextPart>>handleSignal: exception
> "Sent to handler (on:do:) contexts only.  If my exception class  
> (first arg) handles exception then execute my handle block (second  
> arg), otherwise forward this message to the next handler context.  
> If none left, execute exception's defaultAction (see  
> nil>>handleSignal:)."
>
> | val |
> (((self tempAt: 1) handles: exception) and: [self tempAt: 3])  
> ifFalse: [
> ^ self nextHandlerContext handleSignal: exception].
>
> exception privHandlerContext: self contextTag.
> self tempAt: 3 put: false.  "disable self while executing handle  
> block"
> val := [(self tempAt: 2) valueWithPossibleArgs: {exception}]
> ensure: [self tempAt: 3 put: true].
> self return: val.  "return from self if not otherwise directed in  
> handle block"
>
> So it seems that this is signal and when handleSignal: arrives on  
> nil then the default action is fetch.
>
> Can somebody with a VM knowledge validate my hypothesis?
>
> Setf
>
>
>
>
>
> On Aug 6, 2008, at 2:55 PM, Lukas Renggli wrote:
>
>>> This is not easy to figure out since when a debugger gets opened,  
>>> the part
>>> of the stack used to open it is discarded (how?).
>>
>> Error>>#defaultAction raises a new exception, the UnhandledError.
>> UnhandledError has an instance-variable to remember the original
>> exception.
>>
>> UnhandledError opens the debugger as part of the #defaultAction. The
>> debugger uses the stack-frame of the original exception to display at
>> the top level. That's why you don't see the handling code itself.
>>
>> Lukas
>>
>> --
>> Lukas Renggli
>> http://www.lukas-renggli.ch
>>
>>
>

--
_,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:
Alexandre Bergel  http://www.bergel.eu
^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;.






Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Exception and defaultAction

Igor Stasenko
In reply to this post by stephane ducasse
2008/8/7 stephane ducasse <[hidden email]>:

> Lukas
>
> This was not the exact question. We were discussing to know who is really
> calling defaultAction (I know how the debugger
> is raised). The question is who is calling defaultAction when the stack is
> empty.
> Is it the VM or something else.
>
> Now in the image the only sender is
>
> UndefinedObject>>handleSignal: exception
>        "When no more handler (on:do:) context left in sender chain this gets
> called.  Return from signal with default action."
>
>        ^ exception resumeUnchecked: exception defaultAction
>
> Who is calling handleSignal:
>
> Exception>>pass
>        "Yield control to the enclosing exception action for the receiver."
>
>        handlerContext nextHandlerContext handleSignal: self
>
> Exception>>signal
>        "Ask ContextHandlers in the sender chain to handle this signal.  The
> default is to execute and return my defaultAction."
>
>        signalContext := thisContext contextTag.
>        ^ thisContext nextHandlerContext handleSignal: self
>
> ContextPart>>handleSignal: exception
>        "Sent to handler (on:do:) contexts only.  If my exception class
> (first arg) handles exception then execute my handle block (second arg),
> otherwise forward this message to the next handler context.  If none left,
> execute exception's defaultAction (see nil>>handleSignal:)."
>
>        | val |
>        (((self tempAt: 1) handles: exception) and: [self tempAt: 3])
> ifFalse: [
>                ^ self nextHandlerContext handleSignal: exception].
>
>        exception privHandlerContext: self contextTag.
>        self tempAt: 3 put: false.  "disable self while executing handle
> block"
>        val := [(self tempAt: 2) valueWithPossibleArgs: {exception}]
>                ensure: [self tempAt: 3 put: true].
>        self return: val.  "return from self if not otherwise directed in
> handle block"
>
> So it seems that this is signal and when handleSignal: arrives on nil then
> the default action is fetch.
>
> Can somebody with a VM knowledge validate my hypothesis?
>

The primitive, which sits in #findNextHandlerContextStarting which is
get called from #nextHandlerContext
Does following:

primitiveFindHandlerContext
        "Primitive. Search up the context stack for the next method context
marked for exception handling starting at the receiver. Return nil if
none found"
        | thisCntx nilOop |
        thisCntx := self popStack.
        nilOop := nilObj.

        [(self isHandlerMarked: thisCntx) ifTrue:[
                        self push: thisCntx.
                        ^nil].
                thisCntx := self fetchPointer: SenderIndex ofObject: thisCntx.
                thisCntx = nilOop] whileFalse.

        ^self push: nilObj
----

This primitive is done just for speed reasons. You can see, that if
primitive fails (not exists in VM), the method's code does exactly
same:

findNextHandlerContextStarting
        "Return the next handler marked context, returning nil if there is
none.  Search starts with self and proceeds up to nil."

        | ctx |
        <primitive: 197>
        ctx := self.
                [ctx isHandlerContext ifTrue:[^ctx].
                (ctx := ctx sender) == nil ] whileFalse.
        ^nil


> Setf
>
>
>
>
>
> On Aug 6, 2008, at 2:55 PM, Lukas Renggli wrote:
>
>>> This is not easy to figure out since when a debugger gets opened, the
>>> part
>>> of the stack used to open it is discarded (how?).
>>
>> Error>>#defaultAction raises a new exception, the UnhandledError.
>> UnhandledError has an instance-variable to remember the original
>> exception.
>>
>> UnhandledError opens the debugger as part of the #defaultAction. The
>> debugger uses the stack-frame of the original exception to display at
>> the top level. That's why you don't see the handling code itself.
>>
>> Lukas
>>
>> --
>> Lukas Renggli
>> http://www.lukas-renggli.ch
>>
>>
>
>
>



--
Best regards,
Igor Stasenko AKA sig.

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Exception and defaultAction

stephane ducasse
thanks igor.
I should really install VM Maker.

Stef

On Aug 7, 2008, at 6:36 PM, Igor Stasenko wrote:

> 2008/8/7 stephane ducasse <[hidden email]>:
>> Lukas
>>
>> This was not the exact question. We were discussing to know who is  
>> really
>> calling defaultAction (I know how the debugger
>> is raised). The question is who is calling defaultAction when the  
>> stack is
>> empty.
>> Is it the VM or something else.
>>
>> Now in the image the only sender is
>>
>> UndefinedObject>>handleSignal: exception
>>      "When no more handler (on:do:) context left in sender chain  
>> this gets
>> called.  Return from signal with default action."
>>
>>      ^ exception resumeUnchecked: exception defaultAction
>>
>> Who is calling handleSignal:
>>
>> Exception>>pass
>>      "Yield control to the enclosing exception action for the  
>> receiver."
>>
>>      handlerContext nextHandlerContext handleSignal: self
>>
>> Exception>>signal
>>      "Ask ContextHandlers in the sender chain to handle this  
>> signal.  The
>> default is to execute and return my defaultAction."
>>
>>      signalContext := thisContext contextTag.
>>      ^ thisContext nextHandlerContext handleSignal: self
>>
>> ContextPart>>handleSignal: exception
>>      "Sent to handler (on:do:) contexts only.  If my exception class
>> (first arg) handles exception then execute my handle block (second  
>> arg),
>> otherwise forward this message to the next handler context.  If  
>> none left,
>> execute exception's defaultAction (see nil>>handleSignal:)."
>>
>>      | val |
>>      (((self tempAt: 1) handles: exception) and: [self tempAt: 3])
>> ifFalse: [
>>              ^ self nextHandlerContext handleSignal: exception].
>>
>>      exception privHandlerContext: self contextTag.
>>      self tempAt: 3 put: false.  "disable self while executing handle
>> block"
>>      val := [(self tempAt: 2) valueWithPossibleArgs: {exception}]
>>              ensure: [self tempAt: 3 put: true].
>>      self return: val.  "return from self if not otherwise directed  
>> in
>> handle block"
>>
>> So it seems that this is signal and when handleSignal: arrives on  
>> nil then
>> the default action is fetch.
>>
>> Can somebody with a VM knowledge validate my hypothesis?
>>
>
> The primitive, which sits in #findNextHandlerContextStarting which is
> get called from #nextHandlerContext
> Does following:
>
> primitiveFindHandlerContext
> "Primitive. Search up the context stack for the next method context
> marked for exception handling starting at the receiver. Return nil if
> none found"
> | thisCntx nilOop |
> thisCntx := self popStack.
> nilOop := nilObj.
>
> [(self isHandlerMarked: thisCntx) ifTrue:[
> self push: thisCntx.
> ^nil].
> thisCntx := self fetchPointer: SenderIndex ofObject: thisCntx.
> thisCntx = nilOop] whileFalse.
>
> ^self push: nilObj
> ----
>
> This primitive is done just for speed reasons. You can see, that if
> primitive fails (not exists in VM), the method's code does exactly
> same:
>
> findNextHandlerContextStarting
> "Return the next handler marked context, returning nil if there is
> none.  Search starts with self and proceeds up to nil."
>
> | ctx |
> <primitive: 197>
> ctx := self.
> [ctx isHandlerContext ifTrue:[^ctx].
> (ctx := ctx sender) == nil ] whileFalse.
> ^nil
>
>
>> Setf
>>
>>
>>
>>
>>
>> On Aug 6, 2008, at 2:55 PM, Lukas Renggli wrote:
>>
>>>> This is not easy to figure out since when a debugger gets opened,  
>>>> the
>>>> part
>>>> of the stack used to open it is discarded (how?).
>>>
>>> Error>>#defaultAction raises a new exception, the UnhandledError.
>>> UnhandledError has an instance-variable to remember the original
>>> exception.
>>>
>>> UnhandledError opens the debugger as part of the #defaultAction. The
>>> debugger uses the stack-frame of the original exception to display  
>>> at
>>> the top level. That's why you don't see the handling code itself.
>>>
>>> Lukas
>>>
>>> --
>>> Lukas Renggli
>>> http://www.lukas-renggli.ch
>>>
>>>
>>
>>
>>
>
>
>
> --
> Best regards,
> Igor Stasenko AKA sig.
>
>