[squeak-dev] The Trunk: Kernel-eem.1360.mcz

Thiede, Christoph Christoph.Thiede at student.hpi.uni-potsdam.de
Mon Jan 3 12:18:53 UTC 2022


Hi Eliot, hi all,


something that was still on my to-do list before the next release is to address the changed behavior of Context >> #ruinSimulated:contextAtEachStep:.


A short recap:


TestCase new
assert: thisContext
equals: (thisContext runSimulated: [thisContext sender] contextAtEachStep: [:x|])


This assertion passes in Squeak 5.3, but since I have changed the behavior of #runSimulated:..., you have to insert a second "sender" inside the simulated block.


Question: Do you think this breaking change is fine (because without it, we were not able to detect any of the non-local returns? And is this change important enough to be noted in the release notes? :-)


Best,

Christoph

________________________________
Von: Thiede, Christoph
Gesendet: Dienstag, 3. November 2020 22:28:13
An: Eliot Miranda
Betreff: AW: [squeak-dev] The Trunk: Kernel-eem.1360.mcz


Hi Eliot,


if you executed some block using the old #runSimulated: version, there was literally no difference that could be observed from within the block:


thisContext runSimulated: [thisContext sender] contextAtEachStep: [:ctxt|]. "UndefinedObject>>DoIt"
[thisContext sender] value. "UndefinedObject>>DoIt"


With my version, this transparency does no longer persist:


thisContext runSimulated: [thisContext sender] contextAtEachStep: [:ctxt|]. "FullBlockClosure(BlockClosure)>>ensure:"


Well, you could argue that this would be the price for handling exceptions and all you need to do to fix the existing implementation would be to append one additional #sender call to "thisContext":


thisContext runSimulated: [thisContext sender sender] contextAtEachStep: [:ctxt|]. "UndefinedObject>>DoIt"


However, this violates the principle of simulation to be invisible to the code being simulated (or maybe not being similated but executed regularly instead). That's pretty sad ... Or am I wrong with this principle?


And there is even another, much more severe issue.

In the past, this worked, of course:


(thisContext sender runSimulated: [thisContext sender] contextAtEachStep: [:ctxt|]) selector "#evaluateCue:ifFail:"


Now let's retry this sample for my ill-conveived change, so I'm adding a #sender call to "thisContext", and will be the output?


(thisContext sender runSimulated: [thisContext sender sender] contextAtEachStep: [:ctxt|]) selector "Compiler>>evaluateCue:ifFail:"


Panic! After performing #runSimulated:contextAtEachStep:, the execution won't continue on the calling method, but on the Context receiver instance which #runSimulated:contextAtEachStep: was sent to!

I'm going to push a fix for the latter issue right now, but still, I'm not sure whether we want to lose the simulator transparency here, see above ...


> Hey, did you try the mandala example I added to Context class>>#runSimulated: ?  So cool :-) (not that one can squash fillWhite, but that it is so fast).


Really cool :-) The TimeProfileBrowser says that 75% of time is spent in #isPrimFailToken:, by the way. Any chance to make this even faster? :D

<http://www.hpi.de/>


PS: You sent me this message off-list, if this was not intended, please feel free to reply on-list again :-)


Best,
Christoph
________________________________
Von: Eliot Miranda <eliot.miranda at gmail.com>
Gesendet: Montag, 2. November 2020 22:08:11
An: Thiede, Christoph
Betreff: Re: [squeak-dev] The Trunk: Kernel-eem.1360.mcz

Hi Christoph,

On Nov 2, 2020, at 10:36 AM, Thiede, Christoph <Christoph.Thiede at student.hpi.uni-potsdam.de> wrote:



Hi Eliot,


I already had noticed the broken tests but did not yet complete the work on it. I now realize that the old version of #runSimulated:...: had a real relation to the receiver instance of the Context invoked on and things like this no longer work:

thisContext sender runSimulated: [thisContext sender] contextAtEachStep: [:x|]

In fact, my new proposed version is nearly static, and I admit it's a pity to lose this option.

Hmm, I don’t really understand this point.  Can you explain a bit more?  thisContext sender still exists while we run simulated with the new version so I don’t quite see why it doesn’t work.  If the intent is this:

    | baseContext |
    (baseContext := thisContext) runSimulated: [baseContext sender] contextAtEachStep: [:x|]

should work right?

If you remove the "thisContext sender" from the other users of #runSimulated:contextAtEachStep:, the stack frame won't be preserved during the simulation of aBlock.

Which context isn’t preserved?


If you like to rework it, I'll hand over it to you with pleasure because this task got larger than I would have assumed; otherwise, please let me know, and I broke it, so I'll fix it, too. :-)

I wish I had the time!  What u like in the current state of affairs is that all the tests are green.  That’s good enough for me for now.

Hey, did you try the mandala example I added to Context class>>#runSimulated: ?  So cool :-) (not that one can squash fillWhite, but that it is so fast).


Best,

Christoph

________________________________
Von: Eliot Miranda <eliot.miranda at gmail.com>
Gesendet: Montag, 2. November 2020 19:15 Uhr
An: Thiede, Christoph
Betreff: Re: [squeak-dev] The Trunk: Kernel-eem.1360.mcz

Hi Christoph,

   I found the bug in the odl code.  It was the use of thisContext sender runSimulated: ... instead of thisContext runSimulated:.  Now all the tests pass.  Thanks for pushing to get this working.  It's an important and beautiful facility.

On Mon, Nov 2, 2020 at 10:11 AM <commits at source.squeak.org<mailto:commits at source.squeak.org>> wrote:
Eliot Miranda uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-eem.1360.mcz

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

Name: Kernel-eem.1360
Author: eem
Time: 2 November 2020, 10:10:50.874417 am
UUID: 2041d4e1-746a-49f9-9098-8fbd6ba2f787
Ancestors: Kernel-eem.1359, Kernel-ct.1359

Merge Kernel-ct.1359 from inbox
Author: ct
Time: 1 November 2020, 7:50:24.183428 pm
UUID: 3b12b316-79f3-de41-8765-8296d964b821
Ancestors: Kernel-mt.1353

Revise and extend Context #runSimulated: implementation. Remove restriction to blocks that do not have a method return. Add support for exception signaling during the execution, which caused unterminated simulation of the calling process in the past. Support argless contextAtEachStep blocks.

Benchmarks:
        code:
                [Context runSimulated: [100 at 100 corner: 200 at 200]] bench
        before:
                16.7 ms/run
        after:
                19.8 ms/run
I think this should be okay, given the fact that the primary purpose of simulation is providing explorability but not efficiency ...

eem: Fix a bug in the use of runSimulated:contextAtEachStep:.  Presumably because of the pre-closure block model existing senders were of the form
        thisContext sender
                runSimulated: aBlock
                contextAtEachStep: [....]
but this caused the jump at the end of runSimulated:contextAtEachStep: to short-cut any processing done after runSimulated:contextAtEachStep:.  So rewrite all users of runSimulated:contextAtEachStep: in this form:
        thisContext
                runSimulated: aBlock
                contextAtEachStep: [....]
                and consequently have tallyInstruction: rallyMethods: et al answer their intended results.

=============== Diff against Kernel-eem.1359 ===============

Item was changed:
  ----- Method: Context class>>runSimulated: (in category 'simulation') -----
  runSimulated: aBlock
+       "Simulate the execution of aBlock, until it ends or is curtailed. Answer the result it returns."
-       "Simulate the execution of the argument, current. Answer the result it
-       returns."

+       ^thisContext
-       ^ thisContext sender
                runSimulated: aBlock
+               contextAtEachStep: []
-               contextAtEachStep: [:ignored]

        "Context runSimulated: [Pen new defaultNib: 5; go: 100]"!

Item was changed:
  ----- Method: Context class>>tallyInstructions: (in category 'examples') -----
  tallyInstructions: aBlock
        "This method uses the simulator to count the number of occurrences of
        each of the Smalltalk instructions executed during evaluation of aBlock.
        Results appear in order of the byteCode set."
        | tallies |
        tallies := Bag new.
+       thisContext
-       thisContext sender
                runSimulated: aBlock
                contextAtEachStep:
                        [:current | tallies add: current nextByte].
        ^tallies sortedElements

        "Context tallyInstructions: [3.14159 printString]"!

Item was changed:
  ----- Method: Context class>>tallyMethods: (in category 'examples') -----
  tallyMethods: aBlock
        "This method uses the simulator to count the number of calls on each method
        invoked in evaluating aBlock. Results are given in order of decreasing counts."
        | prev tallies |
        tallies := Bag new.
        prev := aBlock.
+       thisContext
-       thisContext sender
                runSimulated: aBlock
                contextAtEachStep:
                        [:current |
                        current == prev ifFalse: "call or return"
                                [prev sender == nil ifFalse: "call only"
                                        [tallies add: current printString].
                                prev := current]].
        ^tallies sortedCounts

        "Context tallyMethods: [3.14159 printString]"!

Item was changed:
  ----- Method: Context class>>trace:on: (in category 'examples') -----
  trace: aBlock on: aStream             "Context trace: [3 factorial]"
        "This method uses the simulator to print calls to a file."
        | prev |
        prev := aBlock.
+       ^thisContext
-       ^ thisContext sender
                runSimulated: aBlock
                contextAtEachStep:
                        [:current |
+                       Sensor anyButtonPressed ifTrue: [^nil].
+                       current == prev ifFalse:
+                               [prev sender ifNil:
+                                       [aStream space; nextPut: $^.
+                                        self carefullyPrint: current top on: aStream].
+                               aStream cr.
+                               (current depthBelow: aBlock) timesRepeat: [aStream space].
+                               self carefullyPrint: current receiver on: aStream.
+                               aStream space; nextPutAll: current selector; flush.
+                               prev := current]]!
-                       Sensor anyButtonPressed ifTrue: [^ nil].
-                       current == prev
-                               ifFalse:
-                                       [prev sender ifNil:
-                                               [aStream space; nextPut: $^.
-                                               self carefullyPrint: current top on: aStream].
-                                       aStream cr.
-                                       (current depthBelow: aBlock) timesRepeat: [aStream space].
-                                       self carefullyPrint: current receiver on: aStream.
-                                       aStream space; nextPutAll: current selector; flush.
-                                       prev := current]]!

Item was changed:
  ----- Method: Context>>runSimulated:contextAtEachStep: (in category 'system simulation') -----
+ runSimulated: aBlock contextAtEachStep: anotherBlock
+       "Simulate the execution of the argument, aBlock, until it ends or is curtailed. If any exception is signaled during the execution, simulate it being handled on the present caller stack. Evaluate anotherBlock with the current context prior to each instruction executed. Answer the simulated value of aBlock."
+
+       | current resume ensure |
+       resume := false.
- runSimulated: aBlock contextAtEachStep: block2
-       "Simulate the execution of the argument, aBlock, until it ends. aBlock
-       MUST NOT contain an '^'. Evaluate block2 with the current context
-       prior to each instruction executed. Answer the simulated value of aBlock."
-       | current |
-       aBlock hasMethodReturn
-               ifTrue: [self error: 'simulation of blocks with ^ can run loose'].
        current := aBlock asContext.
+       ensure := current insertSender: (Context contextEnsure: [resume := true]).
+       ensure sender ifNil: [ensure privSender: self]. "For backward compatibility, do not fail if aBlock is dead."
+
+       (anotherBlock numArgs = 0
+               ifTrue: ["optimized" [resume]]
+               ifFalse: ["stop execution on time, don't expose simulation details to caller"
+                       [current == ensure or:
+                               ["Context >> #resume:"
+                               current size >= 2 and:
+                                       [(current at: 2) == ensure]]]   ])
-       current pushArgs: Array new from: self.
-       [current == self]
                whileFalse:
+                       [anotherBlock cull: current.
-                       [block2 value: current.
                        current := current step].
+
+       ^ current jump!
-       ^self pop!




--
_,,,^..^,,,_
best, Eliot
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20220103/81d4b44d/attachment.html>


More information about the Squeak-dev mailing list