Eliot Miranda uploaded a new version of System to project The Trunk:
http://source.squeak.org/trunk/System-eem.1450.mcz
==================== Summary ====================
Name: System-eem.1450
Author: eem
Time: 21 March 2024, 9:59:04.230117 pm
UUID: 8a307197-4ed6-4876-a204-4922ff405e1d
Ancestors: System-cmm.1449
Eliminate hyper-active low space notification by not notifying if after a GC there is at least 1/5 more free space than the low space threshold, in the case where there are no memoryHogs.
Document parameters 50 & 51 in vmParameterAt:[put:].
Improve the comment for snapshotPrimitive.
=============== Diff against System-cmm.1449 ===============
Item was changed:
----- Method: LowSpaceWatcher>>notifyMemoryHogs (in category 'process steps') -----
notifyMemoryHogs
+ "Try to clean up memory hogs. Answer if sufficient memory was released."
- "Try to clean up memory hogs. Answer true if sufficient memory was released."
| free |
+ free := Smalltalk bytesLeft.
+ self memoryHogs isEmpty ifTrue:
+ [^free >= (Smalltalk lowSpaceThreshold * 5 // 4)].
+ self memoryHogs do:
+ [ :hog | hog freeSomeSpace ].
+ ^Smalltalk bytesLeft > free!
- self memoryHogs isEmpty
- ifTrue: [ ^ false ]
- ifFalse: [ free := Smalltalk bytesLeft.
- self memoryHogs
- do: [ :hog | hog freeSomeSpace ].
- ^ Smalltalk bytesLeft > free ]
-
- !
Item was changed:
----- Method: SmalltalkImage>>snapshotPrimitive (in category 'snapshot and quit') -----
snapshotPrimitive
+ "Primitive. Write the current state of the object memory on a file in the same format
+ as the Smalltalk-80 release. Return normally after writing the file, and answer false.
+ The file can later be resumed, returning you to this exact state except for answering
+ true. Essential. See Object documentation whatIsAPrimitive."
- "Primitive. Write the current state of the object memory on a file in the
- same format as the Smalltalk-80 release. The file can later be resumed,
- returning you to this exact state. Return normally after writing the file.
- Essential. See Object documentation whatIsAPrimitive."
<primitive: 97>
^nil "indicates error writing image file"!
Item was changed:
----- Method: SmalltalkImage>>vmParameterAt: (in category 'vm parameters') -----
vmParameterAt: parameterIndex
"parameterIndex is a positive integer corresponding to one of the VM's internal parameter/metric registers.
Answer with the current value of that register. Fail if parameterIndex is invalid or has no corresponding register.
Coerce positive integers for parameterIndices unknown to teh VM to nil.
VM parameters are numbered as follows:
1 byte size of old-space (read-only)
2 byte size of young-space (read-only)
3 byte size of object memory (read-only)
4 allocationCount (read-only; nil in Cog VMs)
5 allocations between GCs (read-write; nil in Cog VMs)
6 survivor count tenuring threshold (read-write)
7 full GCs since startup (read-only)
8 total milliseconds in full GCs since startup (read-only)
9 incremental GCs since startup (read-only; scavenging GCs on Spur)
10 total milliseconds in incremental/scavenging GCs since startup (read-only)
11 tenures of surving objects since startup/last write (read-write)
12 event trace mask; if 1 << eventType is set in the mask then event received by primGetNextEvent: will be printed to stderr.
13 VM ticker start microseconds (Croquet/QwaqVM only)
14 VM ticker count (Croquet/QwaqVM only)
15 VM ticker call count (Croquet/QwaqVM only)
16 total microseconds in idle since startup
17 proportion of code zone available for use (Sista VMs only; read-write)
18 total milliseconds in full GC compaction since startup (a portion of parameter 8)
19 scavenge threshold; the effective size of eden
20 utc microseconds at VM start-up (actually at time initialization, which precedes image load) (newer Cog VMs only).
21 root (remembered) table size (read-only)
22 root (remembered) table overflows since startup (read-only)
23 bytes of extra memory to reserve for VM buffers, plugins, etc.
24 memory threshold above which to shrink object memory (read-write)
25 ammount to grow by when growing object memory (read-write)
26 interruptChecksEveryNms - force an ioProcessEvents every N milliseconds (read-write)
27 number of times mark loop iterated for current IGC/FGC (read-only) includes ALL marking
28 number of times sweep loop iterated for current IGC/FGC (read-only)
29 number of times make forward loop iterated for current IGC/FGC (read-only)
30 number of times compact move loop iterated for current IGC/FGC (read-only)
31 number of grow memory requests (read-only)
32 number of shrink memory requests (read-only)
33 number of root table entries used for current IGC/FGC (read-only)
34 bytes allocated in total since start-up or reset (read-write)
35 number of survivor objects after current IGC/FGC (read-only)
36 millisecond clock when current IGC/FGC completed (read-only)
37 number of marked objects for Roots of the world, not including Root Table entries for current IGC/FGC (read-only)
38 milliseconds taken by current IGC (read-only)
39 Number of finalization signals for Weak Objects pending when current IGC/FGC completed (read-only)
40 BytesPerWord for this image
41 imageFormatVersion for the VM
42 number of stack pages in use (Cog Stack VM only, otherwise nil)
43 desired number of stack pages (stored in image file header, max 65535; Cog VMs only, otherwise nil)
44 size of eden, in bytes (Cog VMs only, otherwise nil)
45 desired size of eden, in bytes (stored in image file header; Cog VMs only, otherwise nil)
46 size of machine code zone, in bytes (stored in image file header; Cog JIT VM only, otherwise nil)
47 desired size of machine code zone, in bytes (applies at startup only, stored in image file header; Cog JIT VM only)
48 various properties stored in the image header (that instruct the VM) as an integer encoding an array of bit flags.
Bit 0: in a threaded VM, if set, tells the VM that the image's Process class has threadAffinity as its 5th inst var
(after nextLink, suspendedContext, priority & myList)
Bit 1: in Cog JIT VMs, if set, asks the VM to set the flag bit in interpreted methods
Bit 2: if set, preempting a process puts it to the head of its run queue, not the back,
i.e. preempting a process by a higher priority one will not cause the preempted process to yield
to others at the same priority.
Bit 3: (unassigned)
Bit 4: in a Spur VM, if set, causes weaklings and ephemerons to be queued individually for finalization
Bit 5: if set, implies wheel events will be delivered as such and not mapped to arrow key events
Bit 6: if set, implies arithmetic primitives will fail if given arguments of different types (float vs int)
Bit 7: if set, causes times delivered from file primitives to be in UTC rather than local time
Bit 8: if set, implies the VM will not upscale the display on high DPI monitors; older VMs did this by default.
49 the size of the external semaphore table (read-write; Cog VMs only)
+ 50 the maximum number of literals in a method for it to be considered for JIT compilation (Cog JIT VM only, otherwise nil)
+ 51 a set of bit flags describing the state of the image load (read-only; later Cog VMs only; otherwise nil)
+ Bit 0: image needed swizzling on load
+ Bit 1: image is embedded (e.g. as a resource) in this VM
- 50-51 reserved for VM parameters that persist in the image (such as eden above)
52 root (remembered) table maximum size (read-only)
+ 53 the number of oldSpace segments (read-only; Spur only, otherwise nil)
- 53 the number of oldSpace segments (Spur only, otherwise nil)
54 total size of free old space (Spur only, otherwise nil)
55 ratio of growth and image size at or above which a GC will be performed post scavenge (Spur only, otherwise nil)
56 number of process switches since startup (read-only)
57 number of ioProcessEvents calls since startup (read-only)
58 number of forceInterruptCheck (Cog VMs) or quickCheckInterruptCalls (non-Cog VMs) calls since startup (read-only)
59 number of check event calls since startup (read-only)
60 number of stack page overflows since startup (read-only; Cog VMs only)
61 number of stack page divorces since startup (read-only; Cog VMs only)
62 number of machine code zone compactions since startup (read-only; Cog VMs only)
63 milliseconds taken by machine code zone compactions since startup (read-only; Cog VMs only)
64 current number of machine code methods (read-only; Cog VMs only)
65 In newer Cog VMs a set of flags describing VM features,
if non-zero bit 0 implies multiple bytecode set support;
if non-zero bit 1 implies read-only object support;
if non-zero bit 2 implies the VM suffers from using an ITIMER heartbeat (if 0 it has a thread that provides the heartbeat)
(read-only; Cog VMs only; nil in older Cog VMs, a boolean answering multiple bytecode support in not so old Cog VMs)
if non-zero bit 3 implies the VM supports cross-platform BIT_IDENTICAL_FLOATING_POINT arithmetic
if non-zero bit 4 implies the VM can catch exceptions in FFI calls and answer them as primitive failures
if non-zero bit 5 implies the VM's suspend primitive backs up the process to before the wait if it was waiting on a condition variable
66 the byte size of a stack page in the stack zone (read-only; Cog VMs only)
67 the maximum allowed size of old space in bytes, 0 implies no internal limit (Spur VMs only).
68 the average number of live stack pages when scanned by GC (at scavenge/gc/become et al)
69 the maximum number of live stack pages when scanned by GC (at scavenge/gc/become et al)
70 the value of VM_PROXY_MAJOR (the interpreterProxy major version number)
71 the value of VM_PROXY_MINOR (the interpreterProxy minor version number)
72 total milliseconds in full GCs Mark phase since startup (read-only)
73 total milliseconds in full GCs Sweep phase since startup (read-only, can be 0 depending on compactors)
74 maximum pause time due to segment allocation
75 whether arithmetic primitives will do mixed type arithmetic; if false they fail for different receiver and argument types
76 the minimum unused headroom in all stack pages; Cog VMs only"
<primitive: 254>
(parameterIndex isInteger
and: [parameterIndex > 0]) ifTrue:
[^nil].
self primitiveFailed!
Item was changed:
----- Method: SmalltalkImage>>vmParameterAt:put: (in category 'vm parameters') -----
vmParameterAt: parameterIndex put: newValue
"parameterIndex is a positive integer corresponding to one of the VM's internal
parameter/metric registers. Store newValue (a positive integer) into that
register and answer with the previous value that was stored there.
Fail if newValue is out of range, if parameterIndex has no corresponding
register, or if the corresponding register is read-only.
As of late 2020 the parameters which can be set are
5 allocations between GCs (read-write; nil in Cog VMs)
6 survivor count tenuring threshold (read-write)
11 tenures of surving objects since startup/last write (read-write)
12 event trace mask; if 1 << eventType is set in the mask then event received by primGetNextEvent: will be printed to stderr.
17 proportion of code zone available for use (Sista VMs only)
23 bytes of extra memory to reserve for VM buffers, plugins, etc.
24 memory threshold above whichto shrink object memory (read-write)
25 memory headroom when growing object memory (read-write)
26 interruptChecksEveryNms - force an ioProcessEvents every N milliseconds (read-write)
34 bytes allocated in total since start-up or reset (read-write)
43 desired number of stack pages (stored in image file header, max 65535; Cog VMs only, otherwise nil)
45 desired size of eden, in bytes (stored in image file header; Cog VMs only, otherwise nil)
47 desired size of machine code zone, in bytes (applies at startup only, stored in image file header; Cog JIT VM only)
48 various properties of the Cog VM as an integer encoding an array of bit flags; see commentary in #vmParameterAt:
49 the size of the external semaphore table (read-write; Cog VMs only)
+ 50 the maximum number of literals in a method for it to be considered for JIT compilation (Cog JIT VM only, otherwise nil)
55 ratio of growth and image size at or above which a GC will be performed post scavenge (Spur only, otherwise nil)
67 the maximum allowed size of old space in bytes, 0 implies no internal limit (Spur only).
68 the average number of live stack pages when scanned by GC (at scavenge/gc/become et al)
69 the maximum number of live stack pages when scanned by GC (at scavenge/gc/become et al)
74 maximum pause time due to segment allocation
75 whether arithmetic primitives will do mixed type arithmetic; if false they fail for different receiver and argument types"
<primitive: 254>
self primitiveFailed!
Christoph Thiede uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-jar.1550.mcz
==================== Summary ====================
Name: Kernel-jar.1550
Author: jar
Time: 9 January 2024, 8:36:02.1473 pm
UUID: f53ab664-7278-8944-8a7c-90660a08f773
Ancestors: Kernel-ct.1549
fix and rename private method #stepToCalleeOrNil to #stepToSenderOrNil
if you debug and do step through to ^2 and then step over in
[^2] ensure: []
the debugger incorrectly stops at #resume:through:.
The reason is #resume:through: sends a block as an argument and #stepToCalleeOrNil is just not right for this situation: the purpose of the #stepToSenderOrNil method is to remove the top context from the stack by stepping until the context returns. This means we're not interested in detecting stack increases provided by #stepToCalleeOrNil.
It is only used as a helper method in runUntilErrorOrReturnFrom:
=============== Diff against Kernel-ct.1549 ===============
Item was changed:
----- Method: Context>>runUntilErrorOrReturnFrom: (in category 'controlling') -----
runUntilErrorOrReturnFrom: aSender
"ASSUMES aSender is a sender of self. Execute self's stack until aSender returns or an unhandled exception is raised. Return a pair containing the new top context and a possibly nil exception. The exception is not nil if it was raised before aSender returned and it was not handled. The exception is returned rather than openning the debugger, giving the caller the choice of how to handle it."
"Self is run by jumping directly to it (the active process abandons thisContext and executes self). However, before jumping to self we insert an ensure block under aSender that jumps back to thisContext when evaluated. We also insert an exception handler under aSender that jumps back to thisContext when an unhandled exception is raised. In either case, the inserted ensure and exception handler are removed once control jumps back to thisContext."
| error ctxt here topContext |
here := thisContext.
"Insert ensure and exception handler contexts under aSender"
error := nil.
ctxt := aSender insertSender: (Context
contextOn: UnhandledError do: [:ex |
error ifNil: [
error := ex exception.
topContext := thisContext.
ex resumeUnchecked: here jump]
ifNotNil: [ex pass]
]).
ctxt := ctxt insertSender: (Context
contextEnsure: [error ifNil: [
topContext := thisContext.
here jump]
]).
self jump. "Control jumps to self"
"Control resumes here once above ensure block or exception handler is executed"
^ error ifNil: [
"No error was raised, remove ensure context by stepping until popped"
+ [ctxt isDead or: [topContext isNil]] whileFalse: [topContext := topContext stepToSenderOrNil].
- [ctxt isDead or: [topContext isNil]] whileFalse: [topContext := topContext stepToCalleeOrNil].
{topContext. nil}
] ifNotNil: [
"Error was raised, remove inserted above contexts then return signaler context"
aSender terminateTo: ctxt sender. "remove above ensure and handler contexts"
{topContext. error}
]!
Item was removed:
- ----- Method: Context>>stepToCalleeOrNil (in category 'private') -----
- stepToCalleeOrNil
- "Step to callee or sender; step to return and answer nil in case sender cannot be returned to."
-
- | ctxt |
- ctxt := self.
- [(ctxt willReturn and: [ctxt sender isNil or: [ctxt sender isDead]]) not and: [(ctxt := ctxt step) == self]] whileTrue.
- ctxt == self ifTrue: [^nil].
- ^ctxt!
Item was added:
+ ----- Method: Context>>stepToSenderOrNil (in category 'private') -----
+ stepToSenderOrNil
+ "Step to sender or step to return and answer nil in case sender cannot be returned to."
+
+ | ctxt |
+ ctxt := self.
+ [(ctxt willReturn and: [ctxt sender isNil or: [ctxt sender isDead]]) not and: [(ctxt := ctxt step) == self or: [ctxt hasSender: self]]] whileTrue.
+ ctxt == self ifTrue: [^nil].
+ ^ctxt!
Christoph Thiede uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-ct.1561.mcz
==================== Summary ====================
Name: Kernel-ct.1561
Author: ct
Time: 5 March 2024, 9:36:04.183802 pm
UUID: 066dbe81-44ca-7e44-8623-4652ec3e655e
Ancestors: Kernel-ct.1559, Kernel-jar.1550
Merges Kernel-jar.1550 (avoids halting in #resume:through: when stepping over non-local return).
See: https://lists.squeakfoundation.org/archives/list/squeak-dev@lists.squeakfou….
=============== Diff against Kernel-ct.1559 ===============
Item was changed:
----- Method: Context>>runUntilErrorOrReturnFrom: (in category 'controlling') -----
runUntilErrorOrReturnFrom: aSender
"ASSUMES aSender is a sender of self. Execute self's stack until aSender returns or an unhandled exception is raised. Return a pair containing the new top context and a possibly nil exception. The exception is not nil if it was raised before aSender returned and it was not handled. The exception is returned rather than openning the debugger, giving the caller the choice of how to handle it."
"Self is run by jumping directly to it (the active process abandons thisContext and executes self). However, before jumping to self we insert an ensure block under aSender that jumps back to thisContext when evaluated. We also insert an exception handler under aSender that jumps back to thisContext when an unhandled exception is raised. In either case, the inserted ensure and exception handler are removed once control jumps back to thisContext."
| error ctxt here topContext |
here := thisContext.
"Insert ensure and exception handler contexts under aSender"
error := nil.
ctxt := aSender insertSender: (Context
contextOn: UnhandledError do: [:ex |
error ifNil: [
error := ex exception.
topContext := thisContext.
ex resumeUnchecked: here jump]
ifNotNil: [ex pass]
]).
ctxt := ctxt insertSender: (Context
contextEnsure: [error ifNil: [
topContext := thisContext.
here jump]
]).
self jump. "Control jumps to self"
"Control resumes here once above ensure block or exception handler is executed"
^ error ifNil: [
"No error was raised, remove ensure context by stepping until popped"
+ [ctxt isDead or: [topContext isNil]] whileFalse: [topContext := topContext stepToSenderOrNil].
- [ctxt isDead or: [topContext isNil]] whileFalse: [topContext := topContext stepToCalleeOrNil].
{topContext. nil}
] ifNotNil: [
"Error was raised, remove inserted above contexts then return signaler context"
aSender terminateTo: ctxt sender. "remove above ensure and handler contexts"
{topContext. error}
]!
Item was removed:
- ----- Method: Context>>stepToCalleeOrNil (in category 'private') -----
- stepToCalleeOrNil
- "Step to callee or sender; step to return and answer nil in case sender cannot be returned to."
-
- | ctxt |
- ctxt := self.
- [(ctxt willReturn and: [ctxt sender isNil or: [ctxt sender isDead]]) not and: [(ctxt := ctxt step) == self]] whileTrue.
- ctxt == self ifTrue: [^nil].
- ^ctxt!
Item was added:
+ ----- Method: Context>>stepToSenderOrNil (in category 'private') -----
+ stepToSenderOrNil
+ "Step to sender or step to return and answer nil in case sender cannot be returned to."
+
+ | ctxt |
+ ctxt := self.
+ [(ctxt willReturn and: [ctxt sender isNil or: [ctxt sender isDead]]) not and: [(ctxt := ctxt step) == self or: [ctxt hasSender: self]]] whileTrue.
+ ctxt == self ifTrue: [^nil].
+ ^ctxt!
Christoph Thiede uploaded a new version of Tools to project The Treated Inbox:
http://source.squeak.org/treated/Tools-jar.1240.mcz
==================== Summary ====================
Name: Tools-jar.1240
Author: jar
Time: 19 November 2023, 6:34:25.961053 pm
UUID: 0ab90bee-c185-d547-96ef-3e1fefb3147c
Ancestors: Tools-ct.1239
Complement Kernel-jar.1535
(Fix incorrect / inconsistent behavior after resuming from BCR exception.)
In case you find the location I've chosen for the fix not appropriate, I'm all ears. This fix is not essential for Kernel-jar.1535; the point is just to get rid of a confusing error the debugger opens with when debugging BCR resumption.
=============== Diff against Tools-ct.1239 ===============
Item was changed:
----- Method: Debugger>>checkContextSelection (in category 'private') -----
checkContextSelection
contextStackIndex = 0 ifTrue: [self contextStackIndex: 1 oldContextWas: nil].
+ "The following line supports debugging of the resumption of the BlockCannotReturn exception.
+ Check Context >> #cannotReturn for more detailed notes:"
+ (self selectedContext method selector = #cannotReturn: and: [self selectedContext sender isDead]) ifTrue:
+ [Processor debugWithTitle: 'Illegal return following a BCR exception' translated full: false]!
- !
Christoph Thiede uploaded a new version of Kernel to project The Treated Inbox:
http://source.squeak.org/treated/Kernel-jar.1545.mcz
==================== Summary ====================
Name: Kernel-jar.1545
Author: jar
Time: 28 December 2023, 7:35:53.222247 pm
UUID: 467e9c01-0094-c141-9980-1703a639d5a5
Ancestors: Kernel-mt.1544
fix the "stepOver bug" (Cannot #stepOver '^2' in example '[^2] ensure: []')
This is a more conceptual solution and replaces the previous patch in Kernel-jar.1503 which departed from exact mimicking the VM behavior (thanks to Christoph for pointing this out).
Detailed description:
The whole issue emerged probably in 2012 when #aboutToReturn:through: started using the `firstUnwindContext` argument, I guess as an optimization, and forced a starting point to searching for unwind contexts in the resumtion logic (#resumeEvaluating:through:) - which was inconsistent with inserting the ensure guard context **before** this starting point during simulation (by #runUntilErrorOrReturnFrom: called by stepping methods). This resulted in erroneous skipping over the inserted guard ensure context during stepOver simulation and the unexpected behavior.
The idea is for the resumption logic (#resumeEvaluating:through:) to recognize a simulated execution and search for a potential guard (i.e. #ensure:) context inserted during the simulation. I suggest using a `simulationFlag` tempVar in #ensure: which would be set in #return:from:, i.e. if, and only if, the `firstUnwindContext` is supplied in simulaton (i.e. potentially dangerous). When the resumption logic recognizes a simulation supplied `firstUnwindContext` it recomputes the real first unwind context at the moment and proceeds as expected.
=============== Diff against Kernel-mt.1544 ===============
Item was changed:
----- Method: BlockClosure>>ensure: (in category 'exceptions') -----
ensure: aBlock
"Evaluate a termination block after evaluating the receiver, regardless of
whether the receiver's evaluation completes. N.B. This method is *not*
implemented as a primitive. Primitive 198 always fails. The VM uses prim
198 in a context's method as the mark for an ensure:/ifCurtailed: activation."
+ | complete returnValue simulationFlag |
- | complete returnValue |
<primitive: 198>
returnValue := self valueNoContextSwitch.
complete ifNil:[
complete := true.
aBlock value.
].
^ returnValue!
Item was changed:
----- Method: BlockClosure>>ifCurtailed: (in category 'exceptions') -----
ifCurtailed: aBlock
"Evaluate the receiver with an abnormal termination action.
Evaluate aBlock only if execution is unwound during execution
of the receiver. If execution of the receiver finishes normally do
not evaluate aBlock. N.B. This method is *not* implemented as a
primitive. Primitive 198 always fails. The VM uses prim 198 in a
context's method as the mark for an ensure:/ifCurtailed: activation."
+ | complete result simulationFlag |
- | complete result |
<primitive: 198>
result := self valueNoContextSwitch.
complete := true.
^result!
Item was added:
+ ----- Method: Context>>isSimulationFlagSet (in category 'controlling') -----
+ isSimulationFlagSet
+
+ ^self numTemps >= 3 and: [(self tempAt: 3) notNil]!
Item was changed:
----- Method: Context>>resumeEvaluating: (in category 'controlling') -----
resumeEvaluating: aBlock
"Unwind thisContext to self and resume with value as result of last send.
Execute unwind blocks when unwinding.
ASSUMES self is a sender of thisContext"
+ ^self resumeEvaluating: aBlock through: thisContext!
- ^self resumeEvaluating: aBlock through: nil!
Item was changed:
----- Method: Context>>resumeEvaluating:through: (in category 'controlling') -----
+ resumeEvaluating: aBlock through: aContext
- resumeEvaluating: aBlock through: firstUnwindCtxtOrNil
"Unwind thisContext to self and resume with value as result of last send.
Execute unwind blocks when unwinding.
ASSUMES self is a sender of thisContext."
self isDead ifTrue: [self cannotReturn: aBlock value to: self].
+ (aContext isSimulationFlagSet ifTrue: [thisContext] ifFalse: [aContext])
+ unwindTo: self safely: false.
- (firstUnwindCtxtOrNil ifNil: thisContext) unwindTo: self safely: false.
thisContext terminateTo: self.
^aBlock value!
Item was changed:
----- Method: Context>>return:from: (in category 'instruction decoding') -----
return: value from: aSender
"For simulation. Roll back self to aSender and return value from it. Execute any unwind blocks on the way. ASSUMES aSender is a sender of self"
| newTop |
aSender isDead ifTrue:
[^self send: #cannotReturn: to: self with: {value}].
newTop := aSender sender.
(self findNextUnwindContextUpTo: newTop) ifNotNil:
+ [:firstUnwindContext | firstUnwindContext tempAt: 3 put: true. "simulation flag"
+ ^self send: #aboutToReturn:through: to: self with: {value. firstUnwindContext}].
- "Send #aboutToReturn:through: with nil as the second argument to avoid this bug:
- Cannot #stepOver '^2' in example '[^2] ensure: []'.
- See http://lists.squeakfoundation.org/pipermail/squeak-dev/2022-June/220975.html"
- [^self send: #aboutToReturn:through: to: self with: {value. nil}].
self releaseTo: newTop.
newTop ifNotNil: [newTop push: value].
^newTop!
Christoph Thiede uploaded a new version of Kernel to project The Treated Inbox:
http://source.squeak.org/treated/Kernel-jar.1552.mcz
==================== Summary ====================
Name: Kernel-jar.1552
Author: jar
Time: 17 January 2024, 12:12:05.464149 am
UUID: c03919ae-db2f-1842-a906-a917a9fb1821
Ancestors: Kernel-mt.1551
for discussion (Christoph): remove code fragility.
Christoph observed disruptions during process terminations at random positions in a heavily multithreded environment.
The root cause has been tracked down to Context>>#contextEnsure. When a process gets terminated at the moment it's in the middle of inserting this ensure guard context the unwind procedure during the termination fails - precisely because the sender chain is momentarily in a disconnected state before being stitched back. The sequence building the ensure guard is replaced by a manual creation of the context.
This is just a first draft; if this is the right concept, the code will be polished before merging.
=============== Diff against Kernel-mt.1551 ===============
Item was changed:
----- Method: Context class>>contextEnsure: (in category 'special context creation') -----
contextEnsure: block
+ "Create an #ensure: context that is ready to return from executing its receiver."
- "Create an #ensure: context that is ready to return from executing its receiver.
+ ^(Context
+ sender: nil
+ receiver: nil
+ method: (BlockClosure>>#ensure:)
+ arguments: {block}) nextInstruction; nextInstruction; nextInstruction; yourself!
- As ctxt is *not* a top context as required by #jump, we need to put a (fake) return value (nil) on its stack. Otherwise, #jump will pop something different from the stack. Concretely, this caused the bug described in [1] (Scenario 1) because the latest stack top was the closure vector {chain}. This closure vector was accidently popped away so that in the final return statement, #pushRemoteTemp:inVectorAt: raised an error subscript bounds (because the next stack item was not variable). Read the linked bug report for more details.
-
- [1] http://forum.world.st/BUG-s-in-Context-control-jump-runUntilErrorOrReturnFr…"
-
- | ctxt chain |
- ctxt := thisContext.
- [chain := thisContext sender cut: ctxt.
- ctxt push: nil. "fake return value"
- ctxt jump] ensure: block.
- "jump above will resume here without unwinding chain"
- ^ chain!
Christoph Thiede uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-ct.1301.mcz
==================== Summary ====================
Name: Kernel-ct.1301
Author: ct
Time: 16 February 2020, 11:36:54.104878 pm
UUID: e766ce27-fd99-2c4b-ac94-408d4bde8d4f
Ancestors: Kernel-tonyg.1293
Documents the small but essential difference between #sendTo: and #sentTo:
Refactored against Kent's Type Suggesting Parameter Name idiom. Thanks to Chris for the reminder!
Committed again due to broken ancestry.
=============== Diff against Kernel-tonyg.1293 ===============
Item was changed:
----- Method: Message>>sendTo: (in category 'sending') -----
+ sendTo: receiverObject
+ "Answer the result of sending this message to receiverObject"
- sendTo: receiver
- "answer the result of sending this message to receiver"
+ ^ receiverObject perform: selector withArguments: args!
- ^ receiver perform: selector withArguments: args!
Item was changed:
----- Method: Message>>sentTo: (in category 'sending') -----
+ sentTo: receiverObject
+ "Answer the result of sending this message to receiver. Kind of private!! To send the message to a different receiver (for example, via #doesNotUnderstand:), use #sendTo: instead."
- sentTo: receiver
- "answer the result of sending this message to receiver"
+ ^ lookupClass == nil
+ ifTrue: [receiverObject perform: selector withArguments: args]
+ ifFalse: [receiverObject perform: selector withArguments: args inSuperclass: lookupClass]!
- lookupClass == nil
- ifTrue: [^ receiver perform: selector withArguments: args]
- ifFalse: [^ receiver perform: selector withArguments: args inSuperclass: lookupClass]!