--- a/Context.st Fri Aug 23 17:31:58 2013 +0100
+++ b/Context.st Wed Aug 28 10:47:51 2013 +0100
@@ -42,8 +42,10 @@
Every message send adds a context to a chain, which can be traced back via
the sender field. The context of the currently active method is always
accessable via the pseuodoVariable called 'thisContext'.
- (The actual implementation uses the machines stack for this, building real
- contexts on demand only).
+ The actual implementation uses the machines stack for this, building real
+ contexts on demand only, whenever a contexts is needed. Also, initially these are
+ allocated on the stack and only moved to the heap, when a context outlives its
+ activation.
For both method- and block-contexts, the layout is the same.
For method contexts, the home-field is nil, while for block contexts the home-
@@ -51,19 +53,10 @@
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.
-
- 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 may 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).
+ Cheap blocks are blocks which do not refer to any locals or the receiver (currently),
+ but only access globals, class vars or arguments (for example: [:a :b | a < b] is a cheap block).
+ Cheap blocks do not need a home and therefore never require that their home context be moved
+ to the heap. Contexts of cheap blocks do not have a home context - their home field is also nil.
LineNumbers vs. program counter:
@@ -79,32 +72,36 @@
In previous versions (up to ST/X 2.10.5), every method stored enough
information in the context for that one to be restartable later (for example,
- via the debuggers restart button). With 2.10.6, this is now an stc-compiler
- option, and the system as delivered is compiled to only create restartable
- contexts for those which contain blocks. This resulted in an overall speedup of
- roughly 10-20% percent, depending on the type of CPU. However, it makes most
- methods non-restartable (however, abort, signal handling and unwind blocks work
- as usual).
+ via the debugger's restart button). As stc is supposed to generate portable C-code,
+ this means that technically, a setjmp needs to be done at the beginning of the method
+ in order to have a resumable (and portable) state (however, inline asm code does this setjmp,
+ so it is much faster than the libc-setjmo, which stores a lot of additional state, not needed here).
+ With 2.10.6, this is now an stc-compiler option, and the system as delivered is compiled
+ to only create restartable contexts for those which contain blocks or are marked as special
+ via a directive.
+ This resulted in an overall speedup of roughly 10-20% percent, depending on the type of CPU.
+ However, it makes most methods non-restartable (however, abort, signal handling and unwind blocks
+ work as usual).
In practice, this was reported to be not a severe limitation and all users were happy
to trade the increased performance for that slight inconvenience.
(during development, this is seldom a problem, since interpreted methods are always
returnable and restartable)
- If you do not like this (and you are a happy owner of the full distribution), you
- should recompile all classes with stc's '-optContext' flag.
+ If you do not like this, you should recompile all classes with stc's '-optContext' flag.
Resuming contexts:
- Strictly speaking, ST/X does not support a context to be resumed. However,
- it does support a forced return (i.e. non-local-return) from a context.
+ Strictly speaking, ST/X does not support a context to be resumed (because the setjmp is
+ not done on the caller side, but in the callee).
+ However, it does support a forced return (i.e. non-local-return) from a context.
Thus, resume of a context is implemented by forcing a return from the context
which was created by the method called from the first one. The effect is the same.
Returning from a dead method:
- Blockreturn from an outlived context (i.e. its home method has already returned)
+ Block-return from an outlived context (i.e. its home method has already returned)
is now rewarded by an invalidReturn exception - it used to be a noop in previous
- releases (The blue book described this to be a noop, but other smalltalk implementations
- changed this to be an invalid operation - good decision)
+ releases. The blue book described this to be a noop, but other Smalltalk implementations
+ changed this to be an invalid operation - a good decision, as it makes debugging much easier.
[instance variables:]
@@ -358,7 +355,7 @@
home
"return the immediate home of the receiver.
for block contexts, this is the methodcontext, where the block was created,
- for nested block contexts, its the surrounding blocks context.
+ for nested block contexts, it's the surrounding block's context.
for method-contexts this is nil."
^ nil "home"
@@ -1039,6 +1036,20 @@
^ con
!
+resend
+ "EXPERIMENTAL: resend the context's message (to the same receiver).
+ if the method's implementation has been changed in the meanwhile (for example, in the debugger),
+ the new code is executed. Otherwise the same code is reexecuted from the start."
+
+ self returnDoing:[ receiver perform:selector withArguments:(self args) ].
+
+ "
+ when we arrive here, something went wrong.
+ debugging ...
+ "
+ ^ self invalidReturnOrRestartError:#'resend' with:nil
+!
+
restart
"restart the receiver - i.e. the method is evaluated again.
if the context to restart already died, trigger an error.
@@ -1453,7 +1464,7 @@
Evaluate all unwind-blocks as specified in Block>>valueNowOrOnUnwind:
and Block>>valueOnUnwindDo: on the way.
The block is evaluated AFTER all unwind actions are performed
- (i.e. the blocks sender will be the receiving context, not the
+ (i.e. the block's sender will be the receiving context, not the
currently executing context)
LIMITATION:
@@ -1491,6 +1502,49 @@
low-level return ...
"
^ self returnDoing:aBlock
+!
+
+unwindThenResend
+ "EXPERIMENTAL: resend the context's message (to the same receiver).
+ if the method's implementation has been changed in the meanwhile (for example, in the debugger),
+ the new code is executed. Otherwise the same code is reexecuted from the start.
+ Evaluate all unwind-blocks as specified in Block>>valueNowOrOnUnwind:
+ and Block>>valueOnUnwindDo: on the way.
+ The resend happens AFTER all unwind actions are performed
+
+ LIMITATION:
+ currently a context can only be unwound by
+ the owning process - not from outside
+ i.e. it is not possible for one thread to unwindThenDo
+ another threads context - which does not make sense anyway.
+ However, you can force another thread to do this in its own process
+ context, by giving it an interrupt action - this does make sense.
+
+ Also, the compiler has an option (+optcontext) to create
+ non-returnable contexts (which are faster).
+ If such a context is restarted, a runtime error is raised."
+
+ |con|
+
+ self senderIsNil ifFalse:[
+ con := thisContext evaluateUnwindActionsUpTo:self.
+ ].
+
+ "oops, if nil, I am not on the calling chain;
+ (bad bad, unwind action have already been performed.
+ should we check for this situation first and NOT evaluate
+ the unwind actions in this case ?)
+ "
+ con isNil ifTrue:[
+ "
+ tried to return to a context which is already dead
+ (i.e. the method/block has already executed a return)
+ "
+ ^ self invalidReturnOrRestartError:#'unwindThenResend' with:nil
+ ].
+
+ "/ now, that all unwind-actions are done, I can use the low-level resend...
+ ^ self resend
! !
!Context methodsFor:'printing & storing'!
@@ -2493,11 +2547,11 @@
!Context class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic/Context.st,v 1.190 2013-08-20 15:02:27 stefan Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic/Context.st,v 1.191 2013-08-23 13:00:45 cg Exp $'
!
version_CVS
- ^ '$Header: /cvs/stx/stx/libbasic/Context.st,v 1.190 2013-08-20 15:02:27 stefan Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic/Context.st,v 1.191 2013-08-23 13:00:45 cg Exp $'
!
version_HG