Branch: refs/heads/virtend
Home: https://github.com/OpenSmalltalk/opensmalltalk-vm
Commit: a494666757928142c5740133c28df4d8e1929ec4
https://github.com/OpenSmalltalk/opensmalltalk-vm/commit/a494666757928142c5…
Author: Eliot Miranda <eliot.miranda(a)gmail.com>
Date: 2023-02-02 (Thu, 02 Feb 2023)
Changed paths:
M building/linux64ARMv8/squeak.cog.spur/plugins.ext
M src/spur32.cog.lowcode/cogit.h
M src/spur32.cog.lowcode/cogitARMv5.c
M src/spur32.cog.lowcode/cogitIA32.c
M src/spur32.cog.lowcode/cointerp.c
M src/spur32.cog.lowcode/cointerp.h
M src/spur32.cog.lowcode/gcc3x-cointerp.c
M src/spur32.cog/cogit.h
M src/spur32.cog/cogitARMv5.c
M src/spur32.cog/cogitIA32.c
M src/spur32.cog/cointerp.c
M src/spur32.cog/cointerp.h
M src/spur32.cog/cointerpmt.c
M src/spur32.cog/cointerpmt.h
M src/spur32.cog/gcc3x-cointerp.c
M src/spur32.cog/gcc3x-cointerpmt.c
M src/spur32.sista/cogit.h
M src/spur32.sista/cogitARMv5.c
M src/spur32.sista/cogitIA32.c
M src/spur32.sista/cointerp.c
M src/spur32.sista/cointerp.h
M src/spur32.sista/gcc3x-cointerp.c
M src/spur32.stack.lowcode/gcc3x-interp.c
M src/spur32.stack.lowcode/interp.c
M src/spur32.stack/gcc3x-interp.c
M src/spur32.stack/interp.c
M src/spur32.stack/validImage.c
M src/spur64.cog.lowcode/cogit.h
M src/spur64.cog.lowcode/cogitARMv8.c
M src/spur64.cog.lowcode/cogitX64SysV.c
M src/spur64.cog.lowcode/cogitX64WIN64.c
M src/spur64.cog.lowcode/cointerp.c
M src/spur64.cog.lowcode/cointerp.h
M src/spur64.cog.lowcode/gcc3x-cointerp.c
M src/spur64.cog/cogit.h
M src/spur64.cog/cogitARMv8.c
M src/spur64.cog/cogitX64SysV.c
M src/spur64.cog/cogitX64WIN64.c
M src/spur64.cog/cointerp.c
M src/spur64.cog/cointerp.h
M src/spur64.cog/cointerpmt.c
M src/spur64.cog/cointerpmt.h
M src/spur64.cog/gcc3x-cointerp.c
M src/spur64.cog/gcc3x-cointerpmt.c
M src/spur64.sista/cogit.h
M src/spur64.sista/cogitARMv8.c
M src/spur64.sista/cogitX64SysV.c
M src/spur64.sista/cogitX64WIN64.c
M src/spur64.sista/cointerp.c
M src/spur64.sista/cointerp.h
M src/spur64.sista/gcc3x-cointerp.c
M src/spur64.stack.lowcode/gcc3x-interp.c
M src/spur64.stack.lowcode/interp.c
M src/spur64.stack/gcc3x-interp.c
M src/spur64.stack/interp.c
M src/spur64.stack/validImage.c
M src/v3.cog/cogit.h
M src/v3.cog/cogitARMv5.c
M src/v3.cog/cogitIA32.c
M src/v3.cog/cointerp.c
M src/v3.cog/cointerp.h
M src/v3.cog/gcc3x-cointerp.c
M src/v3.stack/gcc3x-interp.c
M src/v3.stack/interp.c
Log Message:
-----------
CogVM source as per VMMaker.oscog-eem.3302
StackInterpreter: fix a bad bug introduced by VMMaker.oscog-eem.3287.
VMMaker.oscog-eem.3287 fixed relocating the instructionPointer by remapping
either relative to method or newMethod, depending on which one contains
instructionPointer. But if not done carefully, it is possible to relocate
the instructionPointer twice.
Spur: add a halt to a objectsReachableFromRoots: failure case, agreeing with
the convention elsewhere in the ImageSegment primitives.
Cogit: inline StackToRegisterMappingCogit>>genPushLiteral: which simply calls
ssPushConstant:
Branch: refs/heads/Cog
Home: https://github.com/OpenSmalltalk/opensmalltalk-vm
Commit: a5a7a12e19d9507712d46de9f6b6b84d249ab1bd
https://github.com/OpenSmalltalk/opensmalltalk-vm/commit/a5a7a12e19d9507712…
Author: Eliot Miranda <eliot.miranda(a)gmail.com>
Date: 2023-02-02 (Thu, 02 Feb 2023)
Changed paths:
M building/linux64ARMv8/squeak.cog.spur/plugins.ext
M src/spur32.cog.lowcode/cogit.h
M src/spur32.cog.lowcode/cogitARMv5.c
M src/spur32.cog.lowcode/cogitIA32.c
M src/spur32.cog.lowcode/cointerp.c
M src/spur32.cog.lowcode/cointerp.h
M src/spur32.cog.lowcode/gcc3x-cointerp.c
M src/spur32.cog/cogit.h
M src/spur32.cog/cogitARMv5.c
M src/spur32.cog/cogitIA32.c
M src/spur32.cog/cointerp.c
M src/spur32.cog/cointerp.h
M src/spur32.cog/cointerpmt.c
M src/spur32.cog/cointerpmt.h
M src/spur32.cog/gcc3x-cointerp.c
M src/spur32.cog/gcc3x-cointerpmt.c
M src/spur32.sista/cogit.h
M src/spur32.sista/cogitARMv5.c
M src/spur32.sista/cogitIA32.c
M src/spur32.sista/cointerp.c
M src/spur32.sista/cointerp.h
M src/spur32.sista/gcc3x-cointerp.c
M src/spur32.stack.lowcode/gcc3x-interp.c
M src/spur32.stack.lowcode/interp.c
M src/spur32.stack/gcc3x-interp.c
M src/spur32.stack/interp.c
M src/spur32.stack/validImage.c
M src/spur64.cog.lowcode/cogit.h
M src/spur64.cog.lowcode/cogitARMv8.c
M src/spur64.cog.lowcode/cogitX64SysV.c
M src/spur64.cog.lowcode/cogitX64WIN64.c
M src/spur64.cog.lowcode/cointerp.c
M src/spur64.cog.lowcode/cointerp.h
M src/spur64.cog.lowcode/gcc3x-cointerp.c
M src/spur64.cog/cogit.h
M src/spur64.cog/cogitARMv8.c
M src/spur64.cog/cogitX64SysV.c
M src/spur64.cog/cogitX64WIN64.c
M src/spur64.cog/cointerp.c
M src/spur64.cog/cointerp.h
M src/spur64.cog/cointerpmt.c
M src/spur64.cog/cointerpmt.h
M src/spur64.cog/gcc3x-cointerp.c
M src/spur64.cog/gcc3x-cointerpmt.c
M src/spur64.sista/cogit.h
M src/spur64.sista/cogitARMv8.c
M src/spur64.sista/cogitX64SysV.c
M src/spur64.sista/cogitX64WIN64.c
M src/spur64.sista/cointerp.c
M src/spur64.sista/cointerp.h
M src/spur64.sista/gcc3x-cointerp.c
M src/spur64.stack.lowcode/gcc3x-interp.c
M src/spur64.stack.lowcode/interp.c
M src/spur64.stack/gcc3x-interp.c
M src/spur64.stack/interp.c
M src/spur64.stack/validImage.c
M src/v3.cog/cogit.h
M src/v3.cog/cogitARMv5.c
M src/v3.cog/cogitIA32.c
M src/v3.cog/cointerp.c
M src/v3.cog/cointerp.h
M src/v3.cog/gcc3x-cointerp.c
M src/v3.stack/gcc3x-interp.c
M src/v3.stack/interp.c
Log Message:
-----------
CogVM source as per VMMaker.oscog-eem.3302
StackInterpreter: fix a bad bug introduced by VMMaker.oscog-eem.3287.
VMMaker.oscog-eem.3287 fixed relocating the instructionPointer by remapping
either relative to method or newMethod, depending on which one contains
instructionPointer. But if not done carefully, it is possible to relocate
the instructionPointer twice.
Spur: add a halt to a objectsReachableFromRoots: failure case, agreeing with
the convention elsewhere in the ImageSegment primitives.
Cogit: inline StackToRegisterMappingCogit>>genPushLiteral: which simply calls
ssPushConstant:
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.3302.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.3302
Author: eem
Time: 2 February 2023, 6:34:06.327588 pm
UUID: 66c9a94d-c30b-41ca-b89c-297646db25f7
Ancestors: VMMaker.oscog-eem.3301
StackInterpreter: fix a bad bug introduced by VMMaker.oscog-eem.3287. VMMaker.oscog-eem.3287 fixed relocating the instructionPointer by remapping either relative to method or newMethod, depending on which one contains instructionPointer. But if not done carefully, it is possible to relocate the instructionPointer twice.
Spur: add a halt to a objectsReachableFromRoots: failure case, agreeing with the comnvention elsewhere in the ImageSegment primitives.
Cogit: inline StackToRegisterMappingCogit>>genPushLiteral: which simply calls ssPushConstant:
=============== Diff against VMMaker.oscog-eem.3301 ===============
Item was changed:
----- Method: SpurMemoryManager>>storeImageSegmentInto:outPointers:roots: (in category 'image segment in/out') -----
storeImageSegmentInto: segmentWordArrayArg outPointers: outPointerArrayArg roots: arrayOfRootsArg
"This primitive is called from Squeak as...
<imageSegment> storeSegmentFor: arrayOfRoots into: aWordArray outPointers: anArray.
This primitive will store a binary image segment (in the same format as objects in the heap) of the
set of objects in arrayOfObjects. All pointers from within the set to objects outside the set will be
copied into the array of outPointers. In their place in the image segment will be an oop equal to the
offset in the outPointer array (the first would be 8), but with the high bit set.
Since Spur has a class table the load primitive must insert classes that have instances into the
class table. This primitive marks such classes using the isRemembered bit, which isn't meaningful
as a remembered bit in the segment.
The primitive expects the segmentWordArray and outPointerArray to be more than adequately long.
In this case it returns normally, and truncates the two arrays to exactly the right size.
The primitive can fail for the following reasons with the specified failure codes:
PrimErrGenericError: the segmentWordArray is too small for the version stamp
PrimErrWritePastObject: the segmentWordArray is too small to contain the reachable objects
PrimErrBadIndex: the outPointerArray is too small
PrimErrNoMemory: additional allocations failed
PrimErrLimitExceeded: there is no room in the hash field to store out pointer indices or class references."
<inline: false>
| segmentWordArray outPointerArray arrayOfRoots
arrayOfObjects savedFirstFields savedOutHashes segStart segAddr endSeg outIndex numClassesInSegment |
<var: 'segAddr' type: #usqInt>
((self isObjImmutable: segmentWordArrayArg)
or: [self isObjImmutable: outPointerArrayArg]) ifTrue:
[^PrimErrNoModification].
"Since segmentWordArrayArg & outPointerArrayArg may get shortened, they can't be pinned."
((self isPinned: segmentWordArrayArg)
or: [self isPinned: outPointerArrayArg]) ifTrue:
[^PrimErrObjectIsPinned].
(self numSlotsOf: outPointerArrayArg) > self maxIdentityHash ifTrue:
[^PrimErrLimitExceeded].
self runLeakCheckerFor: GCCheckImageSegment.
"First scavenge to collect any new space garbage that refers to the graph."
self scavengingGC.
segmentWordArray := self updatePostScavenge: segmentWordArrayArg.
outPointerArray := self updatePostScavenge: outPointerArrayArg.
arrayOfRoots := self updatePostScavenge: arrayOfRootsArg.
self deny: (self forwardersIn: outPointerArray).
self deny: (self forwardersIn: arrayOfRoots).
"Now compute the transitive closure, collecting the sequence of objects to be stored in the arrayOfObjects array.
Included in arrayOfObjects are the arrayOfRoots and all its contents. All objects have been unmarked."
arrayOfObjects := self objectsReachableFromRoots: arrayOfRoots.
arrayOfObjects ifNil:
+ [^PrimErrNoMemory halt].
- [^PrimErrNoMemory].
"If objectsReachableFromRoots: answers an integer there is not enough continuous free space in which to allocate the
reachable objects. If there is sufficient free space then answer an error code to prompt a compacting GC and a retry."
(self isIntegerObject: arrayOfObjects) ifTrue:
[totalFreeOldSpace - self allocationUnit >= (self integerValueOf: arrayOfObjects) ifTrue:
[^PrimErrNeedCompaction].
^PrimErrNoMemory halt].
self assert: self allObjectsUnmarked. "work to be done when the incremental GC is written"
self deny: (self forwardersIn: arrayOfObjects).
"Both to expand the max size of segment and to reduce the length of the
load-time pass that adds classes to the class table, move classes to the
front of arrayOfObjects, leaving the root array as the first element."
numClassesInSegment := self moveClassesForwardsIn: arrayOfObjects.
"The scheme is to copy the objects into segmentWordArray, and then map the oops in segmentWordArray.
Therefore the primitive needs to both map efficiently originals to copies in segmentWordArray and
be able to undo any side-effects if the primitive fails because either segmentWordArray or outPointerArray
is too small. The mapping is done by having the objects to be stored in arrayOfObjects refer to their mapped
locations through their first field, just like a forwarding pointer, but without becoming a forwarder, saving their
first field in savedFirstFields, and the objects in outPointerArray pointing to their locations in the outPointerArray
through their identityHashes, saved in savedOutHashes.
Since arrayOfObjects and its savedFirstFields, and outPointerArray and its saved hashes, can be enumerated
side-by-side, the hashes can be restored to the originals. So the first field of the heap object corresponding to
an object in arrayOfObjects is set to its location in segmentWordArray, and the hash of an object in outPointerArray
is set to its index in outPointerArray plus the top hash bit. Classes in arrayOfObjects have their marked bit set.
Oops in objects in segmentWordArray are therefore mapped by accessing the original oop, and following its first
field. Class indices in segmentWordArray are mapped by fetching the original class, and testing its marked bit.
If marked, the first field is followed to access the class copy in the segment. Out pointers (objects and classes,
which are unmarked), the object's identityHash is set (eek!!!!) to its index in the outPointerArray. So savedOutHashes
parallels the outPointerArray. The saved hash array is initialized with an out-of-range hash value so that the first
unused entry can be identified."
savedFirstFields := self noInlineAllocateSlots: (self numSlotsOf: arrayOfObjects)
format: self wordIndexableFormat
classIndex: self wordSizeClassIndexPun.
savedOutHashes := self noInlineAllocateSlots: (self numSlotsForBytes: (self numSlotsOf: outPointerArray) * 4)
format: self firstLongFormat
classIndex: self thirtyTwoBitLongsClassIndexPun.
(savedFirstFields isNil or: [savedOutHashes isNil]) ifTrue:
[self freeObject: arrayOfObjects.
(savedFirstFields notNil and: [self isInOldSpace: savedFirstFields]) ifTrue:
[self freeObject: savedFirstFields].
(savedOutHashes notNil and: [self isInOldSpace: savedOutHashes]) ifTrue:
[self freeObject: savedOutHashes].
^PrimErrNoMemory halt].
self fillObj: savedFirstFields numSlots: (self numSlotsOf: savedFirstFields) with: 0.
self fillObj: savedOutHashes numSlots: (self numSlotsOf: savedOutHashes) with: self savedOutHashFillValue.
segAddr := segmentWordArray + self baseHeaderSize.
endSeg := self addressAfter: segmentWordArray.
"Write a version number for byte order and version check."
segAddr >= endSeg ifTrue: [^PrimErrGenericFailure].
self long32At: segAddr put: self imageSegmentVersion.
self long32At: segAddr + 4 put: self imageSegmentVersion.
segStart := segAddr := segAddr + self allocationUnit.
self assert: arrayOfRoots = (self fetchPointer: 0 ofObject: arrayOfObjects).
"Copy all reachable objects to the segment, setting the marked bit for all objects (clones) in the segment,
and the remembered bit for all classes (clones) in the segment."
0 to: (self numSlotsOf: arrayOfObjects) - 1 do:
[:i| | newSegAddrOrError objOop |
"Check that classes in the segment are addressable. Since the top bit of the hash field is used to tag
classes external to the segment, the segment offset must not inadvertently set this bit. This limit still
allows for a million or more classes."
(i = numClassesInSegment
and: [segAddr - segStart / self allocationUnit + self lastClassIndexPun >= TopHashBit]) ifTrue:
[^self return: PrimErrLimitExceeded
restoringObjectsIn: arrayOfObjects upTo: i savedFirstFields: savedFirstFields].
objOop := self fetchPointer: i ofObject: arrayOfObjects.
self deny: ((self isImmediate: objOop) or: [self isForwarded: objOop]).
newSegAddrOrError := self copyObj: objOop
toAddr: segAddr
stopAt: endSeg
savedFirstFields: savedFirstFields
index: i.
(self oop: newSegAddrOrError isLessThan: segStart) ifTrue:
[^self return: newSegAddrOrError
restoringObjectsIn: arrayOfObjects upTo: i savedFirstFields: savedFirstFields].
segAddr := newSegAddrOrError].
"Check that it can be safely shortened."
(endSeg ~= segAddr
and: [endSeg - segAddr < (self baseHeaderSize + self bytesPerOop)]) ifTrue:
[^self return: PrimErrWritePastObject
restoringObjectsIn: arrayOfObjects upTo: -1 savedFirstFields: savedFirstFields].
"Now scan, adding out pointers to the outPointersArray; all objects in arrayOfObjects
have their first field pointing to the corresponding copy in segmentWordArray."
(outIndex := self mapOopsFrom: segStart
to: segAddr
outPointers: outPointerArray
outHashes: savedOutHashes) < 0 ifTrue: "no room in outPointers; fail"
[^self return: PrimErrBadIndex
restoringObjectsIn: arrayOfObjects savedFirstFields: savedFirstFields
and: outPointerArray savedHashes: savedOutHashes].
"We're done. Shorten the results, restore hashes and return."
self shorten: segmentWordArray toIndexableSize: segAddr - (segmentWordArray + self baseHeaderSize) / 4.
self shorten: outPointerArray toIndexableSize: outIndex.
^self return: PrimNoErr
restoringObjectsIn: arrayOfObjects savedFirstFields: savedFirstFields
and: outPointerArray savedHashes: savedOutHashes!
Item was changed:
----- Method: StackInterpreter>>mapVMRegisters (in category 'object memory support') -----
mapVMRegisters
"Map the oops in the interpreter's vm ``registers'' to their new values
during garbage collection or a become: operation."
"Assume: All traced variables contain valid oops.
N.B. Don't trace messageSelector and lkupClass; these are ephemeral, live
only during message lookup and because createActualMessageTo will not
cause a GC these cannot change during message lookup.
c.f. followMethodNewMethodAndInstructionPointer"
| ipdelta |
(objectMemory shouldRemapObj: method) ifTrue:
[ipdelta := (self method: method includesAddress: instructionPointer) ifTrue:
[instructionPointer - method].
method := objectMemory remapObj: method.
ipdelta ifNotNil:
[instructionPointer := method + ipdelta]].
(objectMemory shouldRemapOop: newMethod) ifTrue: "maybe oop due to object-as-method"
+ [ipdelta := (ipdelta isNil "don't relocate twice!!!!"
+ and: [self method: newMethod includesAddress: instructionPointer]) ifTrue:
- [ipdelta := (self method: newMethod includesAddress: instructionPointer) ifTrue:
[instructionPointer - newMethod].
newMethod := objectMemory remapObj: newMethod.
ipdelta ifNotNil:
[instructionPointer := newMethod + ipdelta]]!
Item was changed:
----- Method: StackToRegisterMappingCogit>>genPushLiteral: (in category 'bytecode generator support') -----
genPushLiteral: literal
+ <inline: #always>
^self ssPushConstant: literal!
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog.seperateMarking-eem.3314.mcz
==================== Summary ====================
Name: VMMaker.oscog.seperateMarking-eem.3314
Author: eem
Time: 31 January 2023, 5:43:06.479622 pm
UUID: 19d4b92f-6399-4ce0-bf90-edd88349b29b
Ancestors: VMMaker.oscog.seperateMarking-eem.3313
Implement an optional TempVectReadBarrier for the IGC. If spurPostBecomeAction: uses followReceiverAndTemporaryForwardingPointersInStackZone then the read barrier is not needed. Slang must resolve "objectMemory gc" within StackInterpreter for this to work.
Slang: add a class variable to control the diagnostic output of the polymorphic message resolver. It produces a *lot* of output.
=============== Diff against VMMaker.oscog.seperateMarking-eem.3313 ===============
Item was changed:
Object subclass: #CCodeGenerator
instanceVariableNames: 'vmClass structClasses translationDict asArgumentTranslationDict inlineList constants variables variableDeclarations scopeStack methods macros apiMethods apiVariables kernelReturnTypes currentMethod headerFiles globalVariableUsage useSymbolicConstants generateDeadCode requiredSelectors previousCommentMarksInlining previousCommenter logger suppressAsmLabels asmLabelCounts pools selectorTranslations staticallyResolvedPolymorphicReceivers recursivelyResolvedPolymorphicReceivers optionsDictionary breakSrcInlineSelectors breakDestInlineSelectors breakOnInline vmMaker accessorDepthCache beganInlining mappingForRecursivePolymophism removedForPolymorphism recursivePolymorphicMethodsMap toGenerate classesToBeGenerated'
+ classVariableNames: 'NoRegParmsInAssertVMs VerbosePolymorphismResolution'
- classVariableNames: 'NoRegParmsInAssertVMs'
poolDictionaries: 'VMBasicConstants'
category: 'VMMaker-Translation to C'!
!CCodeGenerator commentStamp: 'tpr 5/2/2003 14:30' prior: 0!
This class oversees the translation of a subset of Smalltalk to C, allowing the comforts of Smalltalk during development and the efficiency and portability of C for the resulting interpreter.
See VMMaker for more useful info!
Item was changed:
----- Method: CCodeGenerator class>>initialize (in category 'class initialization') -----
initialize
"CCodeGenerator initialize"
+ NoRegParmsInAssertVMs := true.
+ "If NoRegParmsInAssertVMs is true the generator spits out an attribute turning off register parameters for static functions in the Assert and Debug VMs which makes debugging easier, since all functions can be safely called from gdb. One might hope that -mregparm=0 would work but at least on Mac OS X's gcc 4.2.1 it does not and hence we have to use a per function attribute. Sigh..."
+ "Set this to true to get information on polymorphic message resolution printed to the transcript."
+ VerbosePolymorphismResolution := false!
- NoRegParmsInAssertVMs := true
- "If NoRegParmsInAssertVMs is true the generator spits out an attribute turning off register parameters for static functions in the Assert and Debug VMs which makes debugging easier, since all functions can be safely called from gdb. One might hope that -mregparm=0 would work but at least on Mac OS X's gcc 4.2.1 it does not and hence we have to use a per function attribute. Sigh..."!
Item was changed:
----- Method: CCodeGenerator>>resolveRecursivePolymorphism:in:fromMethod:in:ifMatch: (in category 'helpers polymorphic resolving') -----
resolveRecursivePolymorphism: receiverSymbol in: aSendNode fromMethod: aTMethod in: aClass ifMatch: aReturnBlock
"- if the current TMethod is a base method we want to resolve it to the default
- if the current TMethod is a polymorphic method, meaning it got a type to resolve for, apply this type to submethods
- if the called method (from SendNode) is a polymorphic base method we resolve it to the default if we are not in a class associated with only one type. Should this be the case we resolve the method to this type"
"((aTMethod selector = #globalGarbageCollect) and: [aSendNode selector = #preGlobalGCActions]) ifTrue: [0 halt]."
aTMethod isPolymorphicBase
ifTrue: [self resolve: receiverSymbol inSelfSend: aSendNode in: aClass to: aTMethod default ifFound: aReturnBlock.
"if the polymorphic receiver is mentioned we resolve the method to the default"
self resolve: aSendNode to: aTMethod default ifFound: aReturnBlock.
"now get desperate. look if there is a method with the selectors name that is mentioned in a polymorphic context"
removedForPolymorphism at: aSendNode selector
ifPresent: [:dictionary | dictionary at: aTMethod default
ifPresent: [:selector |
aSendNode
setSelectorForPolymorphism: selector.
aReturnBlock value].
"is the TMethods receiverClass associated with one of the polymorphic classes implementing aSendNode selector?"
(mappingForRecursivePolymophism associationsSelect: [:assoc | assoc value = aTMethod default]) keys
detect: [:key | dictionary keys anySatisfy: [:ea | key includesBehavior: ea]]
ifFound: [:class | | actualClass |
actualClass := dictionary keys detect: [:ea | class includesBehavior: ea].
aSendNode
setSelectorForPolymorphism: (dictionary at: actualClass).
aReturnBlock value]].
(self hasPolymorphicMethod: aSendNode selector in: aTMethod default)
ifTrue: [self halt]].
aTMethod isPolymorphic
ifTrue: [self resolvePolymorphicMethod: receiverSymbol in: aSendNode fromMethod: aTMethod in: aClass ifMatch: aReturnBlock].
methods at: aSendNode selector
ifPresent: [:calledMethod |
calledMethod isPolymorphicBase
ifTrue: [ | alternativeClass matchingClass |
"we have type info and the calledMethod does not care which type it is -> use type info"
aTMethod isPolymorphic
ifTrue: [
aSendNode
setSelectorForPolymorphism: (calledMethod polymorphicSelectorForClass: aTMethod receiverClass).
aReturnBlock value ].
"should we or one of our superclasses define the called method use the default because we call it ourself and there is no other info"
self resolve: receiverSymbol inSelfSend: aSendNode in: aClass to: calledMethod default ifFound: aReturnBlock.
"should the class be mapped to a fixed type use it to resolve the type of the method"
alternativeClass := mappingForRecursivePolymophism at: aClass ifAbsent: [nil].
(calledMethod classes includes: aClass)
ifTrue: [matchingClass := aClass]
ifFalse: [(calledMethod classes includes: alternativeClass)
ifTrue: [matchingClass := alternativeClass]].
matchingClass ifNotNil: [
aSendNode
setSelectorForPolymorphism: (calledMethod polymorphicSelectorForClass: matchingClass).
aReturnBlock value].
"we have no info about the method, but we know it is a polymorphic base -> resolve to default because we assume everyone wants the default"
+ VerbosePolymorphismResolution ifTrue:
+ [Transcript show: 'Resolved ' , aSendNode asString.
+ aSendNode setSelectorForPolymorphism: (calledMethod polymorphicSelectorForClass: calledMethod default).
+ Transcript
+ show: ' to ' , aSendNode asString , ' in ' , aTMethod asString , ' because it is the default for the defined polymorphic method.';
+ cr].
- Transcript show: 'Resolved ' , aSendNode asString.
- aSendNode setSelectorForPolymorphism: (calledMethod polymorphicSelectorForClass: calledMethod default).
- Transcript
- show: ' to ' , aSendNode asString , ' in ' , aTMethod asString , ' because it is the default for the defined polymorphic method.';
- cr.
aReturnBlock value
]]
+ ifAbsent: [] .!
- ifAbsent: [] .
-
- !
Item was changed:
----- Method: CCodeGenerator>>writeCallGraphCSV: (in category 'call graph') -----
writeCallGraphCSV: connections
+ FileStream
+ fileNamed: 'output.csv'
+ do: [:file|
+ file
+ nextPutAll: 'caller';
+ tab;
+ nextPutAll: 'callee';
+ cr; lf.
+
+ connections keysAndValuesDo: [:callee :callers |
+ "self halt."
+ callers do: [:caller |
+ file
+ nextPutAll: caller asString;
+ tab;
+ nextPutAll: callee asString;
+ cr; lf]]].
+
- | file |
- file := FileStream fileNamed: 'output.csv'.
-
- file
- nextPutAll: 'source';
- nextPut: Character tab;
- nextPutAll: 'target';
- cr; lf.
-
- connections keysAndValuesDo: [:key :value |
- "self halt."
- value do: [:ea |
- file
- nextPutAll: ea asString;
- nextPut: Character tab;
- nextPutAll: key asString;
- cr; lf]].
-
-
^ connections!
Item was changed:
----- Method: SpurMemoryManager class>>declareCVarsIn: (in category 'translation') -----
declareCVarsIn: aCCodeGenerator
self wantsIncrementalGC
ifTrue: [aCCodeGenerator
recursivelyResolvePolymorpicReceiver: 'gc' toVariants: {SpurIncrementalGarbageCollector. SpurStopTheWorldGarbageCollector} in: self default: SpurIncrementalGarbageCollector;
staticallyResolvedPolymorphicReceiver: 'gc' to: self markerClass in: SpurIncrementalGarbageCollector;
staticallyResolvedPolymorphicReceiver: 'compactor' to: self compactorClass in: self;
staticallyResolvedPolymorphicReceiver: 'marker' to: self markerClass in: self].
self class == thisContext methodClass ifFalse: [^self]. "Don't duplicate decls in subclasses"
aCCodeGenerator removeVariable: 'memory'. "memory is a simulation time thing only"
self declareCAsOop: #( freeStart scavengeThreshold newSpaceStart pastSpaceStart
oldSpaceStart lowSpaceThreshold freeOldSpaceStart endOfMemory)
in: aCCodeGenerator.
self declareCAsUSqLong: (self allInstVarNames select: [:ivn| ivn endsWith: 'Usecs']), #(statAllocatedBytes)
in: aCCodeGenerator.
aCCodeGenerator
var: #lastHash type: #usqInt;
var: #freeListsMask type: #usqInt;
var: #freeLists type: #'sqInt *';
var: #objStackInvalidBecause type: #'char *';
var: #unscannedEphemerons type: #SpurContiguousObjStack;
var: #heapGrowthToSizeGCRatio type: #float;
var: #heapSizeAtPreviousGC type: #usqInt;
var: #totalFreeOldSpace type: #usqInt;
var: #maxOldSpaceSize type: #usqInt.
aCCodeGenerator
var: #oldSpaceUsePriorToScavenge type: #sqLong.
aCCodeGenerator
var: #remapBuffer
declareC: 'sqInt remapBuffer[RemapBufferSize + 1 /* ', (RemapBufferSize + 1) printString, ' */]'.
aCCodeGenerator
var: #extraRoots
declareC: 'sqInt *extraRoots[ExtraRootsSize + 1 /* ', (ExtraRootsSize + 1) printString, ' */]'.
+
+ aCCodeGenerator
+ staticallyResolvedPolymorphicReceiver: 'objectMemory gc'
+ to: (Smalltalk classNamed: (InitializationOptions at: 'gcClass'))
+ in: StackInterpreter.
-
self wantsIncrementalGC
ifTrue: [aCCodeGenerator
staticallyResolvedPolymorphicReceiver: 'manager gc' to: SpurIncrementalGarbageCollector in: SpurSegmentManager;
"the vm needs (from handwritten C code) the method fullGC. Generate it later on"
generate: #fullGC from: #SIGC_fullGC]!
Item was changed:
----- Method: StackInterpreter>>spurPostBecomeAction: (in category 'object memory support') -----
spurPostBecomeAction: theBecomeEffectsFlags
"Insulate the stack zone from the effects of a become.
All receivers must be unfollowed for two reasons:
1. inst var access is direct with no read barrier
2. super sends (always to the receiver) have no class check and so don't trap
for forwarded receivers. This is an issue for primitives that assume their receiver
is valid and don't validate.
Super sends require an explicit check to ensure receivers in super sends are unforwarded.
e.g. super doSomethingWith: (self become: other) forwards the receiver self pushed on the
stack. So we could avoid following non-pointer receivers. But this is too tricky, Instead, we
always follow receivers.
Methods must be unfollowed since bytecode access is direct with no read barrier.
But this only needs to be done if the becomeEffectsFlags indicate that a
CompiledMethod was becommed.
The scheduler state must be followed, but only if the becomeEffectsFlags indicate
that a pointer object was becommed."
<option: #SpurObjectMemory>
<inline: false> "For VM profiling"
self flushAtCache.
theBecomeEffectsFlags ~= 0 ifTrue:
[(theBecomeEffectsFlags anyMask: BecameActiveClassFlag) ifTrue:
[self flushBecommedClassesInMethodCache].
(theBecomeEffectsFlags anyMask: BecamePointerObjectFlag) ifTrue:
[self followForwardingPointersInScheduler.
self followForwardingPointersInSpecialObjectsArray].
(theBecomeEffectsFlags anyMask: BecamePointerObjectFlag + BecameCompiledMethodFlag) ifTrue:
[self followForwardingPointersInProfileState.
(theBecomeEffectsFlags anyMask: BecameCompiledMethodFlag) ifTrue:
[self followForwardedMethodsInMethodCache.
self followMethodNewMethodAndInstructionPointer]]].
+ "There are two scans of the stack zone post become, and three cases to consider.
+ There is no way of naming an indirection vector in a context/stack frame, so if the GC is not
+ incremental (if incremental compaction is not done), indirection vectors should never be forwarded.
+ Yes, one could forward explicitly via thisContext, but we copnsider that shooting onesself in the foot.
+ If the GC is incremental then indirection vectors can be forwarded. To cope with this we can either
+ have an explicit read barrier (TempVectReadBarrier) or we can follow temporary variables as well
+ as the receiver. Performance measurements indicate that following tempoiraries as well as the
+ method and receiver won't increase the time spent in become very much. So we implement both
+ and will decide what's better when we can do real performance tests."
+ objectMemory gc isIncremental
+ ifTrue:
+ [TempVectReadBarrier
+ ifTrue: [self followForwardingPointersInStackZone]
+ ifFalse: [self followReceiverAndTemporaryForwardingPointersInStackZone]]
+ ifFalse:
+ [self followForwardingPointersInStackZone]!
- self followForwardingPointersInStackZone!
Item was changed:
----- Method: VMClass class>>initializeMiscConstants (in category 'initialization') -----
initializeMiscConstants
"Falsify the `what type of VM is this?' flags that are defined in the various interp.h files.
Subclass implementations need to include a super initializeMiscConstants"
| omc |
VMBIGENDIAN class. "Mention this for the benefit of CCodeGenerator>>emitCConstantsOn:"
SPURVM := STACKVM := COGVM := COGMTVM := false.
InitializationOptions ifNil: [InitializationOptions := Dictionary new].
omc := InitializationOptions at: #ObjectMemory ifAbsent: nil.
(omc isNil and: [self defaultObjectMemoryClass notNil]) ifTrue:
[omc := InitializationOptions at: #ObjectMemory put: self defaultObjectMemoryClass name].
omc := omc ifNotNil: [Smalltalk at: omc].
InitializationOptions
at: #SqueakV3ObjectMemory "the good ole default"
ifAbsentPut: (omc
ifNil: [true]
ifNotNil: [omc includesBehavior: ObjectMemory]);
at: #SpurObjectMemory "the new contender"
ifAbsentPut: (omc
ifNil: [false]
ifNotNil: [omc includesBehavior: SpurMemoryManager]).
omc validateInitializationOptions. "hack around edge cases"
"Use ifAbsentPut: so that they will get copied back to the
VMMaker's options and dead code will likely be eliminated."
PharoVM := InitializationOptions at: #PharoVM ifAbsentPut: [false].
NewspeakVM := InitializationOptions at: #NewspeakVM ifAbsentPut: [false].
SistaVM := InitializationOptions at: #SistaVM ifAbsentPut: [false].
TempVectReadBarrier := InitializationOptions at: #TempVectReadBarrier ifAbsentPut: [false].
LowcodeVM := InitializationOptions at: #LowcodeVM ifAbsentPut: [false].
MULTIPLEBYTECODESETS := InitializationOptions at: #MULTIPLEBYTECODESETS ifAbsentPut: [false].
"Simulation only; on by default..."
CloneOnGC := InitializationOptions at: #CloneOnGC ifAbsentPut: [true].
CloneOnScavenge := InitializationOptions at: #CloneOnScavenge ifAbsentPut: [true].
"These must be set only if specified, not defaulted, because they are set on the command line or in include files."
InitializationOptions
at: #VMBIGENDIAN ifPresent: [:value| VMBIGENDIAN := value];
at: #ObjectMemory ifPresent: [:value| SPURVM := value beginsWith: 'Spur'];
at: #STACKVM ifPresent: [:value| STACKVM := value];
at: #COGVM ifPresent: [:value| COGVM := InitializationOptions at: #COGVM];
at: #COGMTVM ifPresent: [:value| COGMTVM := InitializationOptions at: #COGMTVM].
"consistency checks"
+ SPURVM ifFalse:
+ [TempVectReadBarrier ifTrue: [self error: 'read barrier works with spur VM only...'].
+ SistaVM ifTrue: [self error: 'Sista VM works with spur VM only...']].
- SPURVM
- ifTrue:
- [(TempVectReadBarrier not
- and: [{SpurMemoryManager compactorClass}, (SpurMemoryManager compactorClass ancilliaryClasses) anySatisfy:
- [:c| c == SpurSelectiveCompactor or: [c == SpurIncrementalSweepAndCompact]]]) ifTrue:
- [self error: 'Selective compactor requires read barrier']]
- ifFalse:
- [TempVectReadBarrier ifTrue: [self error: 'read barrier works with spur VM only...'].
- SistaVM ifTrue: [self error: 'Sista VM works with spur VM only...']].
"And not these; they're compile-time"
IMMUTABILITY := InitializationOptions at: #IMMUTABILITY ifAbsent: [SPURVM] "Default as enabled for Spur VMs"!