Context.st
branchjv
changeset 18091 abbcac10730e
parent 18087 1e8ed99fcbd3
parent 15688 1a99731256ba
child 18103 389203ee58fc
--- 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