[squeak-dev] The Inbox: Kernel-nice.857.mcz

commits at source.squeak.org commits at source.squeak.org
Fri Jun 6 01:57:56 UTC 2014


A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-nice.857.mcz

==================== Summary ====================

Name: Kernel-nice.857
Author: nice
Time: 6 June 2014, 3:56:46.41 am
UUID: 58fb31c3-1c03-4cf6-80d3-1f51f41f6d95
Ancestors: Kernel-cmm.855

Resolve ExceptionTests>>testHandlerFromAction.

Implementation details:

Do so by intercepting any exception raised by the handle block in the context which is invoking this block (see #handleSignal:) and by allways propagating this new exception to a previously recorded outerHandler (temp at: 3). Since this context is above the handlers (on:do:) on the stack, it just has to be marked as a fake handler (<primitive: 199>) to do its interceptor/propagator job.
 
Do not use (temp at: 3) of handler (on:do:) as a marker of enablement (true) or temporary disablement (false) during handle block execution, since this is completely superseded by above mechanism. We should rather rename the (temp at: 3) as outerHandler and set it to nil.
Since load order counts, and since some #on:do: context down the processes stacks are not going to die soon, we have equipped #handleSignal: with a workaround, so this change can wait.

Attempt to preserve the possibility for an exception to rearmHandlerDuring: aBlock by temporarily resetting the outerHandler temp in the interceptorContext (which must be a new inst.var. recorded by the Exception). 

Alas, the #testHandlerReentrancy is now failing, because it expects an inner handler to be triggered by an exception raised from an outer handle block, which is forbidden by above implementation. This test is hardly compatible with testHandlerFromAction.

I suggest adding an expected failure to document the change of behavior, and creating a new test demonstrating how rearmHandlerDuring: could be used.
If we don't find a real interest in this message now that it cannot pass then intercept, we can as well deprecate it.

=============== Diff against Kernel-cmm.855 ===============

Item was changed:
  ----- Method: ContextPart>>canHandleSignal: (in category 'private-exceptions') -----
  canHandleSignal: exception
  	"Sent to handler (on:do:) contexts only.  If my exception class (first arg) handles exception then return true, otherwise forward this message to the next handler context.  If none left, return false (see nil>>canHandleSignal:)"
  
+ 	^ (((self tempAt: 1) handles: exception))
- 	^ (((self tempAt: 1) handles: exception) and: [self tempAt: 3])
  		or: [self nextHandlerContext canHandleSignal: exception].
  !

Item was changed:
  ----- Method: ContextPart>>handleSignal: (in category 'private-exceptions') -----
  handleSignal: exception
+ 	"Sent to handler (on:do:) and propagator (handleSignal:) contexts only.
+ 	If I am a handler (on:do:), and 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:).
+ 	If I am a propagator (handleSignal:) I just forward the handling to the outerHandler (temp at: 3). The propagator is allways above the handlers on the stack. If an exception occurs while executing the handle block, it will be intercepted by the propagator and redirected to the previously recorded outer handler, effectively bypassing all inner and current handler."
- 	"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 outerHandler |
+ 	<primitive: 199>
+ 	(self tempAt: 3) == true ifTrue: [self tempAt: 3 put: nil].	"preserve compatibility with old handlerContext"
+ 	((self tempAt: 1) handles: exception) ifFalse: [
+ 		^((self tempAt: 3) ifNil: [self nextHandlerContext]) handleSignal: exception].
+ 	
+ 	exception privHandlerContext: self contextTag from: thisContext contextTag.
+ 	outerHandler := self nextHandlerContext.  "disable self and all inner handlers while executing handle block"
+ 	val := (self tempAt: 2) cull: exception.
- 	| 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) cull: exception ]
- 		ensure: [self tempAt: 3 put: true].
  	self return: val.  "return from self if not otherwise directed in handle block"
  !

Item was added:
+ ----- Method: ContextPart>>rearmHandler:during: (in category 'private-exceptions') -----
+ rearmHandler: aHandlerContext during: aBlock
+ 	"Sent to interceptor (handleSignal:) contexts only, with a handler context (on:do:) parameter.
+ 	Makes aHandlerContext re-entrant for the duration of aBlock. Only works in a closure-enabled image"
+ 
+ 	| oldHandler |
+ 	oldHandler := self tempAt: 3.
+ 	^ [self tempAt: 3 put: aHandlerContext. aBlock value]
+ 		ensure: [self tempAt: 3 put: oldHandler]!

Item was removed:
- ----- Method: ContextPart>>rearmHandlerDuring: (in category 'private-exceptions') -----
- rearmHandlerDuring: aBlock
- 	"Sent to handler (on:do:) contexts only. Makes me re-entrant for the duration of aBlock. Only works in a closure-enabled image"
- 
- 	^ [self tempAt: 3 put: true. aBlock value]
- 		ensure: [self tempAt: 3 put: false]!

Item was changed:
  Object subclass: #Exception
+ 	instanceVariableNames: 'messageText tag signalContext handlerContext outerContext interceptorContext'
- 	instanceVariableNames: 'messageText tag signalContext handlerContext outerContext'
  	classVariableNames: ''
  	poolDictionaries: ''
  	category: 'Kernel-Exceptions-Kernel'!
  
  !Exception commentStamp: '<historical>' prior: 0!
  This is the main class used to implement the exception handling system (EHS).  It plays two distinct roles:  that of the exception, and that of the exception handler.  More specifically, it implements the bulk of the protocols laid out in the ANSI specification - those protocol names are reflected in the message categories.
  
  Exception is an abstract class.  Instances should neither be created nor trapped.  In most cases, subclasses should inherit from Error or Notification rather than directly from Exception.
  
  In implementing this EHS, The Fourth Estate Inc. incorporated some ideas and code from Craig Latta's EHS.  His insights were crucial in allowing us to implement BlockContext>>valueUninterruptably (and by extension, #ensure: and #ifCurtailed:), and we imported the following methods with little or no modification:
  
  ContextPart>>terminateTo:
  ContextPart>>terminate
  MethodContext>>receiver:
  MethodContext>>answer:
  
  Thanks, Craig!!!

Item was removed:
- ----- Method: Exception>>privHandlerContext: (in category 'priv handling') -----
- privHandlerContext: aContextTag
- 
- 	handlerContext := aContextTag!

Item was added:
+ ----- Method: Exception>>privHandlerContext:from: (in category 'priv handling') -----
+ privHandlerContext: aContextTag from: anotherContextTag
+ 
+ 	handlerContext := aContextTag.
+ 	interceptorContext := anotherContextTag!

Item was changed:
  ----- Method: Exception>>rearmHandlerDuring: (in category 'handling') -----
  rearmHandlerDuring: aBlock
  "Make the current error handler re-entrant while it is running aBlock. Only works in a closure-enabled image"
  
+ 	^ interceptorContext rearmHandler: handlerContext during: aBlock!
- 	^ handlerContext rearmHandlerDuring: aBlock!



More information about the Squeak-dev mailing list