diff -r a947150ba171 -r abbcac10730e Context.st --- 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