Marcel Taeumel uploaded a new version of Kernel to project The Treated Inbox: http://source.squeak.org/treated/Kernel-jar.1478.mcz
==================== Summary ====================
Name: Kernel-jar.1478 Author: jar Time: 8 June 2022, 11:16:07.949882 pm UUID: f5720d99-9ce2-374c-adb0-811c23b2cfe5 Ancestors: Kernel-jar.1477
Fix a bug in #runUntilReturnFrom:: while searching for a context that cannot return (to avoid the VM crash) I forgot to limit the search to the relevant part of the stack only (i.e. search only *between* the contexts to be executed). As a result the following example currently fails to unwind:
p := [[[^2] on: BlockCannotReturn do: [Semaphore new wait]] ensure: [Transcript show: 'been here ']] fork. Processor yield. [p terminate] fork
Plus a minor change to allow unwinding even in this case:
p := [[] ensure: [[[^2] on: BlockCannotReturn do: [Semaphore new wait]] ensure: [Transcript show: 'been here ']]] fork. Processor yield. [p terminate] fork
A test will follow later.
=============== Diff against Kernel-jar.1477 ===============
Item was changed: ----- Method: Context>>runUntilReturnFrom: (in category 'private-exceptions') ----- runUntilReturnFrom: aContext "Run the receiver (which must be its stack top context) until aContext returns. Avoid a context that cannot return. Note: to avoid infinite recursion of MNU error inside unwind blocks, implement e.g. a wrapper around the message sentTo: receiver in #doesNotUnderstand:. Note: This method is a trivialized version of #runUntilErrorOrReturnFrom: and was intended to be used by #unwindTo as a helper method to unwind non-local returns inside unwind blocks."
| here unwindBottom newTop | here := thisContext. + "Avoid a context that cannot return between self and aContext (see Note 1 below)." + unwindBottom := self findContextSuchThat: [:ctx | ctx == aContext or: [ctx selector = #cannotReturn:]]. + newTop := unwindBottom sender. - "Avoid a context that cannot return (see Note 1 below)" - unwindBottom := (self findContextSuchThat: [:ctx | ctx selector = #cannotReturn:]) ifNil: [aContext]. - newTop := aContext sender. "Insert ensure context under unwindBottom in self's stack (see Note 2 below)" unwindBottom insertSender: (Context contextEnsure: [here jump]). self jump. "Control jumps to the receiver's stack (see Note 2 below)" "Control resumes here once the above inserted ensure block is executed (see #jump comments)" ^newTop "Return the new top context (see Note 3 below)"
"Note 1: returning from #cannotReturn's sender would crash the VM so we install a guard ensure context right above it; after returning here the unwind will continue safely. Try running and debugging this example (avoid Proceeding the BCR error though; it may indeed crash the image): [[[] ensure: [^2]] ensure: [^42]] fork"
"Note 2: the receiver (self) is run by jumping directly to it (the active process abandons thisContext and executes self on its own stack; self must be its top context). However, before jumping to self we insert an ensure block under unwindBottom context that will execute a jump back to thisContext when evaluated. The inserted guard ensure context is removed once control jumps back to thisContext."
"Note 3: it doesn't matter newTop is not a proper stack top context because #unwindTo will only use it as a starting point in the search for the next unwind context and the computation will never return here. We could make newTop a proper top context by pushing nil to its stack (^newTop push: nil) if need be (see #jump comments). Cf. the pattern in #runUntilErrorOrReturnFrom:: removing the inserted ensure context by stepping until popped when executing non-local returns wouldn't work here and would fail tests testTerminateInNestedEnsureWithReturn1 through 4."!
packages@lists.squeakfoundation.org