--- a/Context.st Wed Aug 24 01:08:09 1994 +0200
+++ b/Context.st Wed Aug 24 01:08:34 1994 +0200
@@ -22,7 +22,7 @@
COPYRIGHT (c) 1988 by Claus Gittinger
All Rights Reserved
-$Header: /cvs/stx/stx/libbasic/Context.st,v 1.17 1994-08-11 21:35:18 claus Exp $
+$Header: /cvs/stx/stx/libbasic/Context.st,v 1.18 1994-08-23 23:08:34 claus Exp $
'!
!Context class methodsFor:'documentation'!
@@ -43,7 +43,7 @@
version
"
-$Header: /cvs/stx/stx/libbasic/Context.st,v 1.17 1994-08-11 21:35:18 claus Exp $
+$Header: /cvs/stx/stx/libbasic/Context.st,v 1.18 1994-08-23 23:08:34 claus Exp $
"
!
@@ -51,15 +51,29 @@
"
Context represents the stack context objects; each message send adds a context
to a chain, which can be traced back via the sender field.
- (The actual implementation uses the machines stack for this, building real contexts
- when needed only).
+ (The actual implementation uses the machines stack for this, building real
+ contexts when needed only).
For both method- and block-contexts, the layout is the same.
- For method contexts, the home-field is nil, while for blockcontexts the home-field is either
- the context of its surrounding block (i.e. the context of the block, in which the receiving
- block was created, if its a nested block) or of its method.
+ For method contexts, the home-field is nil, while for blockcontexts the home-
+ field is either the context of its surrounding block (i.e. the context of the
+ block, in which the receiving block was created, if its a nested block) or of
+ its home method.
+
+ Contexts of cheap blocks do not have a home context - their home field is
+ also nil.
- Contexts of cheap blocks do not have a home context - their home field is also nil.
+ Currently, contexts do not contain a reference to the method or block which
+ created it - this is not needed for program execution, but could get the debugger
+ somewhat into trouble: it has to search the class hierarchy for receiver/selector
+ combinations to find the method. This usually works, but fails in case of methods
+ which are not anchored in any class - especially leading to problems with wrapper-
+ and lazy methods. Also, Method>>valueWithReceiver - type of invocations cannot
+ be easily debugged.
+ Therefore, the implementation will be changed in the near future, to include a
+ field for the method/block, and set it in the VM during program execution.
+ (there may be some small performance penalty for this, though).
+
instance variables:
flags <SmallInteger> - used by the VM; never touch.
@@ -71,9 +85,13 @@
selector <Symbol> - the selector of this message
searchClass <Class> - the class, where the message lookup started
(for super sends) or nil, for regular sends.
+
lineNr <SmallInteger> - the position where the context left off
(kind of p-counter)
+
retValTemp nil - temporary - always nil, when you see the context
+ (used in the VM as temporary)
+
handle *noObject* - used by the VM; not accessable, not an object
<indexed> - arguments of the send followed by
@@ -96,6 +114,9 @@
!Context class methodsFor:'signal access'!
invalidReturnSignal
+ "return the signal used when a method is tried to be returned twice
+ or, when some dead context is unwound or restarted."
+
^ InvalidReturnSignal
! !
@@ -124,7 +145,7 @@
isRecursive
"return true, if this context is one of a recursive send of the same
selector to the same receiver before.
- Used to detect recursive errors - for example."
+ Used to detect recursive errors or recursive printing - for example."
|c rec cls1 cls2|
@@ -150,7 +171,7 @@
"
rec := rec + 1.
rec >= 100000 ifTrue:[
- 'bad context chain' errorPrintNewline.
+ 'bad context chain' errorPrintNL.
^ true
]
].
@@ -449,13 +470,14 @@
which has already returned is about to return again.
(i.e. about to execute a return from an already returned
method in a block).
- We raise a signal here, to allow catching of that exception"
+ We raise a signal here, to allow catching of that situation."
- "in previous versions of ST/X and ST-80, this was no error;
- comment out the error to get that (old) behavior
+ "
+ in previous versions of ST/X and ST-80, this was no error;
+ comment out the raise to get that (old) behavior
"
" "
- InvalidReturnSignal raiseRequestWith:returnValue.
+ ^ InvalidReturnSignal raiseRequestWith:returnValue.
" "
^ returnValue
! !
@@ -465,88 +487,140 @@
restart
"restart the receiver - i.e. the method is evaluated again.
if the context to restart already died - do nothing.
- LIMITATION: currently a context can only be restarted by
- the owning process - not from outside."
+ This is a low level helper for unwindAndRestart.
+
+ NOTICE:
+ NO unwind actions are performed - this is usually not
+ what you want (see Context>>unwindAndRestart).
+
+ LIMITATION:
+ currently a context can only be restarted by
+ the owning process - not from outside."
sender isNil ifTrue:[^ nil].
%{
- __RESUMECONTEXT(SND_COMMA self, RESTART_VALUE);
+ __RESUMECONTEXT__(SND_COMMA self, RESTART_VALUE, 0);
/* when we reach here, something went wrong */
%}
.
- 'restart: context not on calling chain' errorPrintNewline.
"
debugging ...
"
- self error:'restart: context not on calling chain'.
- ^ nil
+"
+ 'restart: context not on calling chain' errorPrintNL.
+ ^ self error:'restart: context not on calling chain'.
+"
+ "
+ tried to restart a context which is already dead
+ (i.e. the method/block has already executed a return)
+ "
+ ^ InvalidReturnSignal
+ raiseRequestWith:nil
+ errorString:'restart: context not on calling chain'
!
return
- "return from this context with nil.
- NO unwind actions are performed.
- LIMITATION: currently a context can only be returned by
- the owning process - not from outside."
+ "return from this context with nil. I.e. as if it did a ^ nil.
+ NOTICE:
+ NO unwind actions are performed - this is usually not
+ what you want (See Context>>unwind).
+ This is a low level method - a helper for unwind.
- self return:nil
+ LIMITATION:
+ currently a context can only be returned by
+ the owning process - not from outside."
+
+ ^ self return:nil
!
return:value
"return from this context as if it did a '^ value'.
- NO unwind actions are performed.
- LIMITATION: currently a context can only be returned by
- the owning process - not from outside."
+ NOTICE:
+ NO unwind actions are performed- this is usually not
+ what you want (See Context>>unwind:).
+ This is a low level method - a helper for unwind.
+
+ LIMITATION:
+ currently a context can only be returned by
+ the owning process - not from outside."
sender isNil ifTrue:[^ nil].
%{
- __RESUMECONTEXT(SND_COMMA self, value);
+ __RESUMECONTEXT__(SND_COMMA self, value, 0);
/* when we reach here, something went wrong */
%}
.
- 'return: context not on calling chain' errorPrintNewline.
"
debugging ...
"
- self error:'restart: context not on calling chain'.
- ^ nil
+"
+ 'return: context not on calling chain' errorPrintNL.
+ ^ self error:'return: context not on calling chain'.
+"
+ "
+ tried to return a context which is already dead
+ (i.e. the method/block has already executed a return)
+ "
+ ^ InvalidReturnSignal
+ raiseRequestWith:value
+ errorString:'return: context not on calling chain'
!
resume
- "resume execution in this context.
- NO unwind actions are performed.
+ "resume execution in this context. I.e. as if the method called
+ last by the receiver did a ^ nil.
If the context has already returned, do nothing.
- LIMITATION: currently a context can only be resumed by
- the owning process - not from outside."
+
+ NOTICE:
+ NO unwind actions are performed (see Context>>unwind).
- self resume:nil
+ LIMITATION:
+ currently a context can only be resumed by
+ the owning process - not from outside."
+
+ ^ self resume:nil
!
resume:value
"resume the receiver - as if it got 'value' from whatever
it called.
- If the context has already died - do nothing.
- NO unwind actions are performed (see unwind: in this class).
- LIMITATION: currently a context can only be resumed by
- the owning process - not from outside."
+ If the context has already returned - do nothing.
+
+ NOTICE:
+ NO unwind actions are performed (see Context>>unwind:).
+
+ LIMITATION:
+ currently a context can only be resumed by
+ the owning process - not from outside."
|con|
- "start with this context, find the one below and return from it"
+ "
+ starting with this context, find the one below and return from it
+ "
con := thisContext.
[con notNil and:[con sender ~~ self]] whileTrue:[
con := con sender
].
con isNil ifTrue:[
- 'resume: context not on calling chain' errorPrintNewline.
"
debugging ...
"
- self error:'resume: context not on calling chain'.
- ^ nil
+"
+ 'resume: context not on calling chain' errorPrintNL.
+ ^ self error:'resume: context not on calling chain'.
+"
+ "
+ tried to continue in context which is already dead
+ (i.e. the method/block has already executed a return)
+ "
+ ^ InvalidReturnSignal
+ raiseRequestWith:value
+ errorString:'resume: context not on calling chain'
].
- con return:value
+ ^ con return:value
!
unwind
@@ -554,10 +628,12 @@
If the context has already retruned, do nothing.
Evaluate all unwind-blocks as specified in Block>>valueNowOrOnUnwind:
and Block>>valueOnUnwindDo: on the way.
- LIMITATION: currently a context can only be unwound by
- the owning process - not from outside."
- self unwind:nil
+ LIMITATION:
+ currently a context can only be unwound by
+ the owning process - not from outside."
+
+ ^ self unwind:nil
!
unwind:value
@@ -565,36 +641,125 @@
If the context has already returned , do nothing.
Evaluate all unwind-blocks as specified in Block>>valueNowOrOnUnwind:
and Block>>valueOnUnwindDo: on the way.
- LIMITATION: currently a context can only be unwound by
- the owning process - not from outside."
+
+ LIMITATION:
+ currently a context can only be unwound by
+ the owning process - not from outside."
|con sel|
- sender isNil ifTrue:[^ nil].
+ sender isNil ifTrue:[
+ "
+ tried to return to a context which is already dead
+ (i.e. the method/block has already executed a return)
+ "
+ ^ InvalidReturnSignal
+ raiseRequestWith:value
+ errorString:'unwind: no sender to unwind to'
+ ].
- "start with this context, moving up"
+ "
+ start with this context, moving up, looking for unwind actions
+ "
con := thisContext.
[con notNil and:[con ~~ self]] whileTrue:[
con isBlockContext ifFalse:[
-
- "the way we find those unwind contexts seems kludgy ..."
+ "
+ the way we find those unwind contexts seems kludgy ...
+ "
sel := con selector.
((sel == #valueNowOrOnUnwindDo:) or:[sel == #valueOnUnwindDo:]) ifTrue:[
- "... the way we evaluate the unwind blocks too"
+ "
+ ... the way we evaluate the unwind blocks too
+ "
(con argAt:1) value
]
].
con := con sender
].
- "this should be avoided"
+ "oops, I am not on the calling chain
+ (should we check for this situation first and NOT evaluate
+ the unwind actions in this case ?)
+ "
con isNil ifTrue:[
- 'unwind: context not on calling chain' errorPrintNewline.
"
debugging ...
"
- self error:'unwind: context not on calling chain'.
- ^ nil
+"
+ 'unwind: context not on calling chain' errorPrintNL.
+ ^ self error:'unwind: context not on calling chain'.
+"
+ "
+ tried to return to a context which is already dead
+ (i.e. the method/block has already executed a return)
+ "
+ ^ InvalidReturnSignal
+ raiseRequestWith:value
+ errorString:'unwind: context not on calling chain'
].
- self return:value
+ "
+ now, that all unwind-actions are done, I can use the
+ low-level return ...
+ "
+ ^ self return:value
+!
+
+unwindAndRestart
+ "restart the receiver - i.e. the method is evaluated again.
+ if the context to restart already died - do nothing.
+ Evaluate all unwind-blocks as specified in Block>>valueNowOrOnUnwind:
+ and Block>>valueOnUnwindDo: before restarting.
+
+ LIMITATION:
+ currently a context can only be restarted by
+ the owning process - not from outside."
+
+ |con sel|
+
+ "
+ start with this context, moving up, looking for unwind actions
+ "
+ con := thisContext.
+ [con notNil and:[con ~~ self]] whileTrue:[
+ con isBlockContext ifFalse:[
+ "
+ the way we find those unwind contexts seems kludgy ...
+ "
+ sel := con selector.
+ ((sel == #valueNowOrOnUnwindDo:) or:[sel == #valueOnUnwindDo:]) ifTrue:[
+ "
+ ... the way we evaluate the unwind blocks too
+ "
+ (con argAt:1) value
+ ]
+ ].
+ con := con sender
+ ].
+
+ "oops, I am not on the calling chain
+ (should we check for this situation first and NOT evaluate
+ the unwind actions in this case ?)
+ "
+ con isNil ifTrue:[
+ "
+ debugging ...
+ "
+"
+ 'unwindAndRestart: context not on calling chain' errorPrintNL.
+ ^ self error:'unwindAndRestart: context not on calling chain'.
+"
+ "
+ tried to return to a context which is already dead
+ (i.e. the method/block has already executed a return)
+ "
+ ^ InvalidReturnSignal
+ raiseRequestWith:nil
+ errorString:'unwindAndRestart: context not on calling chain'
+ ].
+ "
+ now, that all unwind-actions are done, I can use the
+ low-level restart ...
+ "
+ ^ self restart
! !