Hi Christoph, Hi Jaromir, Hi All,
On May 15, 2021, at 6:56 AM, commits@source.squeak.org wrote:
A new version of Kernel was added to project The Inbox: http://source.squeak.org/inbox/Kernel-ct.1405.mcz
==================== Summary ====================
Name: Kernel-ct.1405 Author: ct Time: 15 May 2021, 3:56:24.713389 pm UUID: 9a92be9b-d778-b54f-b659-713451a2ddb2 Ancestors: Kernel-nice.1402
Counterproposal to Kernel-jar.1404 for fixing VM crashes when resuming from a BlockCannotReturn. Instead of enforcing retrial, repair the context stack if the receiver has ended. There are two reasons for that:
- Not in all situations, the receiver of #cannotReturn: is actually unable to resume. Consider this example for a disproof: a := [true ifTrue: [^ 1]. 2]. "Both statements need to be executed separately in a Workspace so that [a outerContext sender] becomes nil!" a value.
In this situation, it is valid to resume from BlockCannotReturn and currently also possible in the Trunk. Note that BlockCannotReturn even overrides #isResumable to answer true, though the class comment discrecommends resuming it.
- The pattern proposed by Jaromir reminds me of the current implementation of Object >> #doesNotUnderstand: or Object >> #at:, that is, when the error was resumed, just try it again in the manner of a (potentially) infinite recursion. While the issue with infinite debuggers (which was eventually tripped by exactly this pattern) has been solved some time ago [1], I do not really agree with the pattern in general - it makes it unnecessarily hard for ToolSet implementors to consciously resume from an error instead of retrying it (which we have an extra selector on Exception for).
But the pattern is a really useful one in a dynamic environment where one is doing edit and continue. I don’t see any practical alternative, having lived for several years without it, and been frustrated at not being able to catch MessageNotUnderstood, do something (become the receiver, create a method, etc), and continue.
To solve the infinite recursion problem we could implement a wrapper around the message sentTo: receiver e.g. [aMessage sentTo: receiver] on: MessageNotUnderstood do: [:ex| | args | args := ex message arguments. (ex receiver == self and: [ex message selector == aMessage selector and: [(1 to: aMessage size) allSatisfy: [:i| (args at: i) == (aMessage argumentAt: i)]]]) ifFalse: [ex pass]. self error: ‘infinite recursion in doesNotUnderstand:’]
(& similarly in at: etc). Right?
[1] http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-co...
=============== Diff against Kernel-nice.1402 ===============
Item was added:
- ----- Method: BlockCannotReturn>>defaultResumeValue (in category 'defaults') -----
- defaultResumeValue
- ^ self result!
Item was changed: ----- Method: Context>>cannotReturn: (in category 'private-exceptions') ----- cannotReturn: result
- closureOrNil ifNotNil: [
| resumptionValue |
resumptionValue := self cannotReturn: result to: self home sender.
self pc > self endPC ifTrue: [
"This block has ended, continue with sender"
thisContext privSender: self sender].
^ resumptionValue].
- closureOrNil ifNotNil: [^ self cannotReturn: result to: self home sender]. Processor debugWithTitle: 'Computation has been terminated!!' translated full: false.!