Branch: refs/heads/Cog
Home: https://github.com/OpenSmalltalk/opensmalltalk-vm
Commit: 4adbe56d3b850524689b6d893e5cb28c6e9e82c4
https://github.com/OpenSmalltalk/opensmalltalk-vm/commit/4adbe56d3b85052468…
Author: Eliot Miranda <eliot.miranda(a)gmail.com>
Date: 2021-08-01 (Sun, 01 Aug 2021)
Changed paths:
M spur64src/vm/cogit.h
M spur64src/vm/cogitARMv8.c
M spur64src/vm/cogitX64SysV.c
M spur64src/vm/cogitX64WIN64.c
M spur64src/vm/cointerp.c
M spur64src/vm/cointerp.h
M spur64src/vm/cointerpmt.c
M spur64src/vm/cointerpmt.h
M spur64src/vm/gcc3x-cointerp.c
M spur64src/vm/gcc3x-cointerpmt.c
M spurlowcode64src/vm/cogit.h
M spurlowcode64src/vm/cogitARMv8.c
M spurlowcode64src/vm/cogitX64SysV.c
M spurlowcode64src/vm/cogitX64WIN64.c
M spurlowcode64src/vm/cointerp.c
M spurlowcode64src/vm/cointerp.h
M spurlowcode64src/vm/gcc3x-cointerp.c
M spurlowcodesrc/vm/cogit.h
M spurlowcodesrc/vm/cogitARMv5.c
M spurlowcodesrc/vm/cogitIA32.c
M spurlowcodesrc/vm/cogitMIPSEL.c
M spurlowcodesrc/vm/cointerp.c
M spurlowcodesrc/vm/cointerp.h
M spurlowcodesrc/vm/gcc3x-cointerp.c
M spurlowcodestack64src/vm/gcc3x-interp.c
M spurlowcodestack64src/vm/interp.c
M spurlowcodestacksrc/vm/gcc3x-interp.c
M spurlowcodestacksrc/vm/interp.c
M spursista64src/vm/cogit.h
M spursista64src/vm/cogitARMv8.c
M spursista64src/vm/cogitX64SysV.c
M spursista64src/vm/cogitX64WIN64.c
M spursista64src/vm/cointerp.c
M spursista64src/vm/cointerp.h
M spursista64src/vm/gcc3x-cointerp.c
M spursistasrc/vm/cogit.h
M spursistasrc/vm/cogitARMv5.c
M spursistasrc/vm/cogitIA32.c
M spursistasrc/vm/cogitMIPSEL.c
M spursistasrc/vm/cointerp.c
M spursistasrc/vm/cointerp.h
M spursistasrc/vm/gcc3x-cointerp.c
M spursrc/vm/cogit.h
M spursrc/vm/cogitARMv5.c
M spursrc/vm/cogitIA32.c
M spursrc/vm/cogitMIPSEL.c
M spursrc/vm/cointerp.c
M spursrc/vm/cointerp.h
M spursrc/vm/cointerpmt.c
M spursrc/vm/cointerpmt.h
M spursrc/vm/gcc3x-cointerp.c
M spursrc/vm/gcc3x-cointerpmt.c
M spurstack64src/vm/gcc3x-interp.c
M spurstack64src/vm/interp.c
M spurstack64src/vm/validImage.c
M spurstacksrc/vm/gcc3x-interp.c
M spurstacksrc/vm/interp.c
M spurstacksrc/vm/validImage.c
M src/plugins/SqueakFFIPrims/ARM32FFIPlugin.c
M src/plugins/SqueakFFIPrims/ARM64FFIPlugin.c
M src/plugins/SqueakFFIPrims/IA32FFIPlugin.c
M src/plugins/SqueakFFIPrims/X64SysVFFIPlugin.c
M src/plugins/SqueakFFIPrims/X64Win64FFIPlugin.c
M src/vm/cogit.h
M src/vm/cogitARMv5.c
M src/vm/cogitIA32.c
M src/vm/cogitMIPSEL.c
M src/vm/cointerp.c
M src/vm/cointerp.h
M src/vm/gcc3x-cointerp.c
Log Message:
-----------
CogVM source as per VMMaker.oscog-eem.3011
Cogit: Get the stack adjustment after primitive success right for
FastCPrimitiveFlag primitives, with or without the FastCPrimitiveAlignForFloatsFlag.
Support a FastCPrimitiveAlignForFloatsFlag to accompany FastCPrimitiveFlag.
Use the facility in primitiveFFI{Double,Float}At[Put]. On win32 clang emits
instructions that insist on at least a 16 byte aligned stack.
Hence identify fast machine code primitives with the FastCPrimitiveUseCABIFlag
flag, refactor compileOnStackExternalPrimitive: to
compileOnStackExternalPrimitive:flags:, extend the set of PrimCall flags, etc.
Remember to set the native stack pointer for a FastCPrimitive on ARMv8.
This is almost certainly the cause of current Cog crashes on ARMv8.
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.3011.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.3011
Author: eem
Time: 1 August 2021, 10:51:32.195381 pm
UUID: c31b5783-0c4c-472a-a602-4eeb7922c5cb
Ancestors: VMMaker.oscog-eem.3010
Cogit: Get the stack adjustment after primitive success right for FastCPrimitiveFlag primitives, with or without the FastCPrimitiveAlignForFloatsFlag.
=============== Diff against VMMaker.oscog-eem.3010 ===============
Item was changed:
----- Method: CogAbstractInstruction>>genLoadStackPointersForFastPrimCall: (in category 'smalltalk calling convention') -----
genLoadStackPointersForFastPrimCall: spareReg
"Switch back to the Smalltalk stack where there may be a C return address on top of stack below
the last primitive argument. Assign SPReg first because typically it is used immediately afterwards."
self hasLinkRegister
ifTrue: [self genLoadStackPointers]
ifFalse:
[cogit
MoveAw: cogit stackPointerAddress R: spareReg;
"N.B. dont use SubCq:R:R: since it may generate MoveR:spareRegR:SPReg;SubCq:wordSize R:SPReg
+ which allows for the ret addr to be smashed by an interrupt between the two instructions."
- which allows for the ret addr to be smashed by an interrupt between the two insructions."
SubCq: objectMemory wordSize R: spareReg;
MoveR: spareReg R: SPReg;
MoveAw: cogit framePointerAddress R: FPReg].
^0!
Item was changed:
----- Method: SimpleStackBasedCogit>>compileOnStackExternalPrimitive:flags: (in category 'primitive generators') -----
compileOnStackExternalPrimitive: primitiveRoutine flags: flags
"Compile a fast call of a C primitive using the current stack page, avoiding the stack switch except on failure.
This convention still uses stackPointer and argumentCount to access operands. Push all operands to the stack,
assign stackPointer, argumentCount, and zero primFailCode. Make the call (saving a LinkReg if required).
Test for failure and return. On failure on Spur, if there is an accessor depth, assign framePointer and newMethod,
do the stack switch, call checkForAndFollowForwardedPrimitiveState, and loop back if forwarders are found.
Fall through to frame build."
<var: #primitiveRoutine declareC: 'void (*primitiveRoutine)(void)'>
| jmp retry calleeSavedReg |
+ self assert: (objectRepresentation hasSpurMemoryManagerAPI and: [flags anyMask: PrimCallOnSmalltalkStack]).
- self assert: (flags anyMask: PrimCallOnSmalltalkStack).
"Clear the primFailCode and set argumentCount"
self MoveCq: 0 R: TempReg.
self MoveR: TempReg Aw: coInterpreter primFailCodeAddress.
methodOrBlockNumArgs ~= 0 ifTrue:
[self MoveCq: methodOrBlockNumArgs R: TempReg].
self MoveR: TempReg Aw: coInterpreter argumentCountAddress.
self genExternalizeStackPointerForFastPrimitiveCall.
backEnd hasLinkRegister ifTrue:
[self PushR: LinkReg].
retry := self Label.
calleeSavedReg := NoReg.
(SPReg ~= NativeSPReg
and: [(self isCalleeSavedReg: SPReg) not]) ifTrue:
[calleeSavedReg := self availableRegisterOrNoneIn: ABICalleeSavedRegisterMask.
self deny: calleeSavedReg = NoReg.
self MoveR: SPReg R: calleeSavedReg].
(flags anyMask: PrimCallOnSmalltalkStackAlign2x)
ifTrue: [self AndCq: (objectMemory wordSize * 2 - 1) bitInvert R: SPReg R: NativeSPReg]
ifFalse:
[SPReg ~= NativeSPReg ifTrue:
[backEnd genLoadNativeSPRegWithAlignedSPReg]].
self CallFullRT: primitiveRoutine.
self MoveAw: coInterpreter primFailCodeAddress R: TempReg.
calleeSavedReg ~= NoReg ifTrue:
[self MoveR: calleeSavedReg R: SPReg].
self CmpCq: 0 R: TempReg.
jmp := self JumpNonZero: 0.
+ "At this point the primitive has cut back stackPointer to point to the result.
+ The original retpc is (argumentCount + 1) words beneath it."
+ self MoveAw: coInterpreter stackPointerAddress R: TempReg.
+ self MoveMw: (methodOrBlockNumArgs + 1 * objectMemory wordSize) negated
+ r: TempReg
+ R: (backEnd hasLinkRegister ifTrue: [LinkReg] ifFalse: [ClassReg]).
+ self MoveR: TempReg R: SPReg.
backEnd hasLinkRegister
+ ifTrue: [self PopR: ReceiverResultReg] "i.e. get result"
+ ifFalse:
+ [self MoveMw: 0 r: TempReg R: ReceiverResultReg;
+ MoveR: ClassReg Mw: 0 r: TempReg]. "i.e. get result and restore retpc"
- ifTrue: [self PopR: LinkReg]
- ifFalse: [self PopR: TempReg]. "i.e. save retpc"
- self MoveAw: coInterpreter stackPointerAddress R: SPReg.
- self PopR: ReceiverResultReg.
- backEnd hasLinkRegister ifFalse: [self PushR: TempReg]. "i.e. restore retpc"
self RetN: 0.
jmp jmpTarget: self Label.
+ (coInterpreter accessorDepthForExternalPrimitiveMethod: methodObj) >= 0
+ ifTrue:
+ [| skip |
+ "Given that following primitive state to the accessor depth is recursive, we're asking for
+ trouble if we run the fixup on the Smalltalk stack page. Run it on the full C stack instead.
+ This won't be a performance issue since primitive failure should be very rare."
+ self MoveR: FPReg Aw: coInterpreter framePointerAddress.
+ self MoveCw: primitiveRoutine asInteger R: TempReg.
+ self MoveR: TempReg Aw: coInterpreter primitiveFunctionPointerAddress.
+ self genLoadCStackPointersForPrimCall.
+ methodLabel addDependent:
+ (self annotateAbsolutePCRef:
+ (self MoveCw: methodLabel asInteger R: ClassReg)).
+ self MoveMw: (self offset: CogMethod of: #methodObject) r: ClassReg R: TempReg.
+ self MoveR: TempReg Aw: coInterpreter newMethodAddress.
+ self CallFullRT: (self cCode: [#checkForAndFollowForwardedPrimitiveState asUnsignedIntegerPtr]
+ inSmalltalk: [self simulatedTrampolineFor: #checkForAndFollowForwardedPrimitiveState]).
+ backEnd genLoadStackPointersForFastPrimCall: ClassReg.
+ self CmpCq: 0 R: ABIResultReg.
+ skip := self JumpZero: 0.
+ self MoveCq: 0 R: TempReg.
+ self MoveR: TempReg Aw: coInterpreter primFailCodeAddress.
+ self Jump: retry.
+ skip jmpTarget: self Label]
+ ifFalse: "must reload SPReg to undo any alignment change,"
+ [(flags anyMask: PrimCallOnSmalltalkStackAlign2x) ifTrue:
+ [backEnd genLoadStackPointersForFastPrimCall: ClassReg]].
- (objectRepresentation hasSpurMemoryManagerAPI
- and: [(coInterpreter accessorDepthForExternalPrimitiveMethod: methodObj) >= 0]) ifTrue:
- [| skip |
- "Given that following primitive state to the accessor depth is recursive, we're asking for
- trouble if we run the fixup on the Smalltalk stack page. Run it on the full C stack instead.
- This won't be a performance issue since primitive failure should be very rare."
- self MoveR: FPReg Aw: coInterpreter framePointerAddress.
- self MoveCw: primitiveRoutine asInteger R: TempReg.
- self MoveR: TempReg Aw: coInterpreter primitiveFunctionPointerAddress.
- self genLoadCStackPointersForPrimCall.
- methodLabel addDependent:
- (self annotateAbsolutePCRef:
- (self MoveCw: methodLabel asInteger R: ClassReg)).
- self MoveMw: (self offset: CogMethod of: #methodObject) r: ClassReg R: TempReg.
- self MoveR: TempReg Aw: coInterpreter newMethodAddress.
- self CallFullRT: (self cCode: [#checkForAndFollowForwardedPrimitiveState asUnsignedIntegerPtr]
- inSmalltalk: [self simulatedTrampolineFor: #checkForAndFollowForwardedPrimitiveState]).
- backEnd genLoadStackPointersForFastPrimCall: ClassReg.
- self CmpCq: 0 R: ABIResultReg.
- skip := self JumpZero: 0.
- self MoveCq: 0 R: TempReg.
- self MoveR: TempReg Aw: coInterpreter primFailCodeAddress.
- self Jump: retry.
- skip jmpTarget: self Label].
"Finally remember to reload ReceiverResultReg if required. Even if
arguments have been pushed, the prolog sequence assumes it is live."
(self register: ReceiverResultReg isInMask: ABICallerSavedRegisterMask) ifTrue:
[self MoveMw: (backEnd hasLinkRegister ifTrue: [methodOrBlockNumArgs] ifFalse: [methodOrBlockNumArgs + 1]) * objectMemory wordSize
r: SPReg
R: ReceiverResultReg].
^0!
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
OpenSmalltalk updated binaries for OpenIndiana available at:
http://pkg.openindiana.org/hipster/en/search.shtml?token=cog-spur&action=Se…
The cog-spur and stack-spur are both updated to 5.0.3003.
However the cog-spur is actually a stub that still refers to the older 2967.
The stack-spur from oscog-eem.3003 seems to work fine.
Also the VEP (VectorEnginePlugin) separate package was updated to the latest
"Cuis" VectorEnginePlugin; this package is optional.
Regards,
David Stes
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
iQEcBAEBCAAGBQJhBxMdAAoJENdFDkXGicizRWIH/0+RyYTIY/j8VQ7PvKXDgHwy
7Y5pLh+A+2ppKj8hrRYqLpMtzzdD+2qidDAWw7X5MoghN6b/BPQgsbhd5K1r2Hu+
frvozGZq7sC5DBFtOMdNZWi4F25/888+lz2gRLxfQ6GxrQM3nzroPOov/YbZzMsJ
PQ2VRMKIR64MWEo1hMe46/WeHP2486VIpET9Kwx1Lz4wAHRO4UunvIkoMvjnS372
T/9eJpqu4ApgY63XO4QAvNwsHX3s0wEEC2GCUc3QBhiUMcJKsdWwR/ZV1aMg2F3T
JVcdFN/HKZd1R0i4ih7xkiG7b0fj4yAjGLQnjlx2G0hpxWcRRQyjQk3JSQLtp2E=
=IcGh
-----END PGP SIGNATURE-----
Branch: refs/heads/Cog
Home: https://github.com/OpenSmalltalk/opensmalltalk-vm
Commit: 62c17ce555bbb79bea9bc3576eafbd78ba913551
https://github.com/OpenSmalltalk/opensmalltalk-vm/commit/62c17ce555bbb79bea…
Author: Eliot Miranda <eliot.miranda(a)gmail.com>
Date: 2021-08-01 (Sun, 01 Aug 2021)
Changed paths:
M platforms/Cross/vm/sq.h
M platforms/Mac OS/vm/sqMacUnixExternalPrims.c
M platforms/minheadless/common/sqExternalPrimitives.c
M platforms/unix/vm/sqUnixExternalPrims.c
M platforms/win32/vm/sqWin32ExternalPrims.c
Log Message:
-----------
Fix the value of null Spur primitive metadata. Provide some defines in sq.h
for comprehension.
Branch: refs/heads/Cog
Home: https://github.com/OpenSmalltalk/opensmalltalk-vm
Commit: 03c4ef31be60a30edc1e2beb5be8e28becd8c1e5
https://github.com/OpenSmalltalk/opensmalltalk-vm/commit/03c4ef31be60a30edc…
Author: Eliot Miranda <eliot.miranda(a)gmail.com>
Date: 2021-07-31 (Sat, 31 Jul 2021)
Changed paths:
M spur64src/vm/cogit.h
M spur64src/vm/cointerp.c
M spur64src/vm/cointerp.h
M spur64src/vm/cointerpmt.c
M spur64src/vm/cointerpmt.h
M spur64src/vm/gcc3x-cointerp.c
M spur64src/vm/gcc3x-cointerpmt.c
M spurlowcode64src/vm/cogit.h
M spurlowcode64src/vm/cointerp.c
M spurlowcode64src/vm/cointerp.h
M spurlowcode64src/vm/gcc3x-cointerp.c
M spurlowcodesrc/vm/cogit.h
M spurlowcodesrc/vm/cointerp.c
M spurlowcodesrc/vm/cointerp.h
M spurlowcodesrc/vm/gcc3x-cointerp.c
M spurlowcodestack64src/vm/gcc3x-interp.c
M spurlowcodestack64src/vm/interp.c
M spurlowcodestacksrc/vm/gcc3x-interp.c
M spurlowcodestacksrc/vm/interp.c
M spursista64src/vm/cogit.h
M spursista64src/vm/cointerp.c
M spursista64src/vm/cointerp.h
M spursista64src/vm/gcc3x-cointerp.c
M spursistasrc/vm/cogit.h
M spursistasrc/vm/cointerp.c
M spursistasrc/vm/cointerp.h
M spursistasrc/vm/gcc3x-cointerp.c
M spursrc/vm/cogit.h
M spursrc/vm/cointerp.c
M spursrc/vm/cointerp.h
M spursrc/vm/cointerpmt.c
M spursrc/vm/cointerpmt.h
M spursrc/vm/gcc3x-cointerp.c
M spursrc/vm/gcc3x-cointerpmt.c
M spurstack64src/vm/gcc3x-interp.c
M spurstack64src/vm/interp.c
M spurstacksrc/vm/gcc3x-interp.c
M spurstacksrc/vm/interp.c
M src/plugins/ADPCMCodecPlugin/ADPCMCodecPlugin.c
M src/plugins/AsynchFilePlugin/AsynchFilePlugin.c
M src/plugins/B2DPlugin/B2DPlugin.c
M src/plugins/BitBltPlugin/BitBltPlugin.c
M src/plugins/CroquetPlugin/CroquetPlugin.c
M src/plugins/FFTPlugin/FFTPlugin.c
M src/plugins/FileAttributesPlugin/FileAttributesPlugin.c
M src/plugins/FilePlugin/FilePlugin.c
M src/plugins/IA32ABI/IA32ABI.c
M src/plugins/ImmX11Plugin/ImmX11Plugin.c
M src/plugins/JPEGReaderPlugin/JPEGReaderPlugin.c
M src/plugins/LargeIntegers/LargeIntegers.c
M src/plugins/MIDIPlugin/MIDIPlugin.c
M src/plugins/RePlugin/RePlugin.c
M src/plugins/ScratchPlugin/ScratchPlugin.c
M src/plugins/SocketPlugin/SocketPlugin.c
M src/plugins/SoundGenerationPlugin/SoundGenerationPlugin.c
M src/plugins/SoundPlugin/SoundPlugin.c
M src/plugins/Squeak3D/Squeak3D.c
M src/plugins/SqueakFFIPrims/ARM32FFIPlugin.c
M src/plugins/SqueakFFIPrims/ARM64FFIPlugin.c
M src/plugins/SqueakFFIPrims/IA32FFIPlugin.c
M src/plugins/SqueakFFIPrims/X64SysVFFIPlugin.c
M src/plugins/SqueakFFIPrims/X64Win64FFIPlugin.c
M src/plugins/StarSqueakPlugin/StarSqueakPlugin.c
M src/plugins/UnicodePlugin/UnicodePlugin.c
M src/plugins/UnixOSProcessPlugin/UnixOSProcessPlugin.c
M src/vm/cogit.h
M src/vm/cointerp.c
M src/vm/cointerp.h
M src/vm/gcc3x-cointerp.c
M stacksrc/vm/gcc3x-interp.c
M stacksrc/vm/interp.c
Log Message:
-----------
CogVM source as per VMMaker.oscog-eem.3009
Spur: Fix a bad bug with computing accessor depths. Exported primitives in the
StackInterpreter and subclasses had their accessor depths computed after
inlining, which is too late.
Add VM parameter 76 to answer the minimumUnusedHeadroom on a stack page.
This is useful in checking that a FastCPrimitiveFlag primitive has not
consumed too much stack.
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.3009.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.3009
Author: eem
Time: 31 July 2021, 10:06:09.440839 pm
UUID: d75b453d-0170-480a-bcb1-d7a2721e1a10
Ancestors: VMMaker.oscog-eem.3008
Slang: fix bug in copying of TBraceCaseNode, which was forgetting to do any kind of copy at all. This caused destructive update of the parse tree of ThreadedX64SysVFFIPlugin>>#ffiCalloutTo:SpecOnStack:in: when computing its accessor depth.
=============== Diff against VMMaker.oscog-eem.3008 ===============
Item was added:
+ ----- Method: TBraceCaseNode>>postCopy (in category 'copying') -----
+ postCopy
+ caseLabels := caseLabels collect: [:ea| ea copy].
+ cases := cases collect: [:ea| ea copy]!
Item was added:
+ ----- Method: TBraceCaseNode>>printOn:level: (in category 'printing') -----
+ printOn: aStream level: level
+ aStream crtab: level; nextPut: ${.
+ caseLabels with: cases do:
+ [:caseLabel :case|
+ caseLabel printOn: aStream.
+ aStream nextPutAll: ' -> '.
+ case printOn: aStream level: level + 1.
+ aStream nextPut: $.].
+ aStream space; nextPut: $}!
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.3008.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.3008
Author: eem
Time: 31 July 2021, 8:34:40.390618 pm
UUID: 1e79edb0-7b90-41e3-8c4c-bf737b4b23a6
Ancestors: VMMaker.oscog-eem.3007
And in computing accessor depths at the right time make sure to use a TMethod's smalltalkSelector to not be confused by smart syntax.
=============== Diff against VMMaker.oscog-eem.3007 ===============
Item was changed:
----- Method: CCodeGenerator>>accessorDepthForMethod: (in category 'spur primitive compilation') -----
accessorDepthForMethod: method
"Compute the depth the method traverses object structure, assuming it is a primitive.
This is in support of Spur's lazy become. A primitive may fail because it may encounter
a forwarder. The primitive failure code needs to know to what depth it must follow
arguments to follow forwarders and, if any are found and followed, retry the primitive.
This method determines that depth. It starts by collecting references to the stack and
then follows these through assignments to variables and use of accessor methods
such as fetchPointer:ofObject:. For example
| obj field |
obj := self stackTop.
field := objectMemory fetchPointer: 1 ofObject: obj.
self storePointer: 1 ofObject: field withValue: (self stackValue: 1)
has depth 2, since field is accessed, and field is an element of obj.
The information is cached since it needs to be computed *before* inlining"
^accessorDepthCache
at: method smalltalkSelector
ifAbsentPut:
[beganInlining
ifTrue:
[((vmClass primitiveTable includes: method smalltalkSelector)
or: [method export])
ifTrue: [-1]
ifFalse: [self error: 'it is too late to compute accessor depths!!']]
ifFalse:
[((method definingClass includesSelector: method smalltalkSelector) ifTrue:
+ [(method definingClass >> method smalltalkSelector) pragmaAt: #accessorDepth:])
- [(method definingClass >> method selector) pragmaAt: #accessorDepth:])
ifNil:
[((self
accessorChainsForMethod: method
interpreterClass: (vmClass ifNil: [StackInterpreter]))
inject: 0
into: [:length :chain| length max: (self accessorDepthForChain: chain)]) - 1]
ifNotNil: [:pragma| pragma arguments first]]]!
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.3007.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.3007
Author: eem
Time: 31 July 2021, 8:25:08.230439 pm
UUID: f4cf3c82-08f5-4cbb-b32a-14e7d8d60a1b
Ancestors: VMMaker.oscog-eem.3006
Spur: Fix a bad bug with computing accessor depths. Exported primitives in the StackInterpreter and suclasses had their accessor depths computed after inlining, which is too late. Compute and cache accessor depths before inlining. Fix a bad regression in primitiveAccessorDepthForExternalPrimitiveMethod:. Now that this needs a shift to eliminate the primitive flags, it must use a signed shift.
Add VM parameter 76 to answer the minimumUnusedHeadroom on a stack page. This is useful in checking that a FastCPrimitiveFlag primitive has not consumed too much stack.
=============== Diff against VMMaker.oscog-eem.3006 ===============
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 optionsDictionary breakSrcInlineSelectors breakDestInlineSelectors breakOnInline vmMaker accessorDepthCache beganInlining'
- 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 optionsDictionary breakSrcInlineSelectors breakDestInlineSelectors breakOnInline vmMaker'
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>>accessorDepthForMethod: (in category 'spur primitive compilation') -----
accessorDepthForMethod: method
"Compute the depth the method traverses object structure, assuming it is a primitive.
This is in support of Spur's lazy become. A primitive may fail because it may encounter
a forwarder. The primitive failure code needs to know to what depth it must follow
arguments to follow forwarders and, if any are found and followed, retry the primitive.
This method determines that depth. It starts by collecting references to the stack and
then follows these through assignments to variables and use of accessor methods
such as fetchPointer:ofObject:. For example
| obj field |
obj := self stackTop.
field := objectMemory fetchPointer: 1 ofObject: obj.
self storePointer: 1 ofObject: field withValue: (self stackValue: 1)
+ has depth 2, since field is accessed, and field is an element of obj.
- has depth 2, since field is accessed, and field is an element of obj."
+ The information is cached since it needs to be computed *before* inlining"
+ ^accessorDepthCache
+ at: method smalltalkSelector
+ ifAbsentPut:
+ [beganInlining
+ ifTrue:
+ [((vmClass primitiveTable includes: method smalltalkSelector)
+ or: [method export])
+ ifTrue: [-1]
+ ifFalse: [self error: 'it is too late to compute accessor depths!!']]
+ ifFalse:
+ [((method definingClass includesSelector: method smalltalkSelector) ifTrue:
+ [(method definingClass >> method selector) pragmaAt: #accessorDepth:])
+ ifNil:
+ [((self
+ accessorChainsForMethod: method
+ interpreterClass: (vmClass ifNil: [StackInterpreter]))
+ inject: 0
+ into: [:length :chain| length max: (self accessorDepthForChain: chain)]) - 1]
+ ifNotNil: [:pragma| pragma arguments first]]]!
- ^((method definingClass includesSelector: method selector) ifTrue:
- [(method definingClass >> method selector) pragmaAt: #accessorDepth:])
- ifNil:
- [((self
- accessorChainsForMethod: method
- interpreterClass: (vmClass ifNil: [StackInterpreter]))
- inject: 0
- into: [:length :chain| length max: (self accessorDepthForChain: chain)]) - 1]
- ifNotNil: [:pragma| pragma arguments first]!
Item was changed:
----- Method: CCodeGenerator>>doBasicInlining: (in category 'inlining') -----
doBasicInlining: inlineFlagOrSymbol
"Inline the bodies of all methods that are suitable for inlining.
This method does only the basic inlining suitable for both the core VM and plugins - no bytecode inlining etc"
| pass progress |
+ beganInlining := true.
self collectInlineList: inlineFlagOrSymbol.
pass := 0.
progress := true.
[progress] whileTrue: [
"repeatedly attempt to inline methods until no further progress is made"
progress := false.
('Inlining pass ', (pass := pass + 1) printString, '...')
displayProgressAt: Sensor cursorPoint
from: 0 to: methods size
during: [:bar |
(self sortMethods: methods) withIndexDo: [:m :i |
bar value: i.
currentMethod := m.
(m tryToInlineMethodsIn: self)
ifTrue: [progress := true]]]].
!
Item was changed:
----- Method: CCodeGenerator>>doInlining: (in category 'inlining') -----
doInlining: inlineFlagOrSymbol
"Inline the bodies of all methods that are suitable for inlining."
"Modified slightly for the core VM translator, since the first level of inlining for the interpret loop must be performed in order that the instruction implementations can easily discover their addresses. Remember to inline the bytecode routines as well"
| removed |
+ beganInlining := true.
inlineFlagOrSymbol isSymbol ifTrue:
[self inlineDispatchesInMethodNamed: #interpret localizingVars: #().
self doBasicInlining: inlineFlagOrSymbol.
self pruneUnreachableMethods.
^self].
inlineFlagOrSymbol ifFalse:
[self inlineDispatchesInMethodNamed: #interpret localizingVars: #().
self pruneUnreachableMethods.
^self].
self doBasicInlining: inlineFlagOrSymbol.
vmClass ifNil: [^self].
'Inlining bytecodes'
displayProgressAt: Sensor cursorPoint
from: 1 to: 2
during: [:bar |
self inlineDispatchesInMethodNamed: #interpret
localizingVars: vmClass namesOfVariablesToLocalize.
bar value: 1.
removed := self removeMethodsReferingToGlobals: vmClass namesOfVariablesToLocalize
except: #interpret.
bar value: 2].
"only prune when generating the interpreter itself"
self pruneUnreachableMethods.
self reportShouldNotBeRemoved: removed varList: vmClass namesOfVariablesToLocalize!
Item was changed:
----- Method: CCodeGenerator>>initialize (in category 'initialize-release') -----
initialize
translationDict := Dictionary new.
inlineList := Array new.
constants := Dictionary new: 100.
variables := Set new: 100.
variableDeclarations := Dictionary new: 100.
methods := Dictionary new: 500.
kernelReturnTypes := self computeKernelReturnTypes.
macros := Dictionary new.
self initializeCTranslationDictionary.
headerFiles := OrderedCollection new.
globalVariableUsage := Dictionary new.
useSymbolicConstants := true.
generateDeadCode := true.
scopeStack := OrderedCollection new.
self getLogger.
pools := IdentitySet new.
selectorTranslations := IdentityDictionary new.
+ accessorDepthCache := IdentityDictionary new.
+ beganInlining := false.
suppressAsmLabels := false.
previousCommentMarksInlining := false.
previousCommenter := nil.
breakSrcInlineSelectors := IdentitySet new.
breakDestInlineSelectors := IdentitySet new!
Item was changed:
+ ----- Method: CoInterpreter>>minimumUnusedHeadroom (in category 'stack pages') -----
- ----- Method: CoInterpreter>>minimumUnusedHeadroom (in category 'debug support') -----
minimumUnusedHeadroom
"Traverse all stack pages looking for non-zero bytes in the headroom part of each page.
Answer the minimum size of unused headroom (zero bytes) in the pages. This is for
checking that there is enough headroom allocated in stack pages."
| minUnused page |
+ <inline: #never>
- <var: #page type: #'StackPage *'>
<var: #p type: #'char *'>
minUnused := (stackPages stackPageAt: 0) baseAddress - (stackPages stackPageAt: 0) lastAddress.
0 to: numStackPages - 1 do:
[:i| | p unused |
page := stackPages stackPageAt: i.
p := page lastAddress.
[p := p + objectMemory wordSize.
(self longAtPointer: p) = 0
and: [p <= page baseAddress]] whileTrue.
unused := p - objectMemory wordSize - page lastAddress.
unused < minUnused ifTrue:
[minUnused := unused]].
^minUnused!
Item was changed:
----- Method: StackInterpreter>>primitiveAccessorDepthForExternalPrimitiveMethod: (in category 'primitive support') -----
primitiveAccessorDepthForExternalPrimitiveMethod: methodObj
^(objectMemory integerValueOf:
(objectMemory
fetchPointer: 2
+ ofObject: (self literal: 0 ofMethod: methodObj))) >>> 8!
- ofObject: (self literal: 0 ofMethod: methodObj))) bitShift: -8!
Item was added:
+ ----- Method: StackInterpreterPrimitives>>minimumUnusedHeadroom (in category 'system control primitives') -----
+ minimumUnusedHeadroom
+ <inline: #always>
+ ^-1!
Item was changed:
----- Method: StackInterpreterPrimitives>>primitiveAllVMParameters: (in category 'system control primitives') -----
(excessive size, no diff calculated)
Item was changed:
----- Method: StackInterpreterPrimitives>>primitiveGetVMParameter: (in category 'system control primitives') -----
primitiveGetVMParameter: arg
"See primitiveVMParameter method comment.
N.B. written as a returning case to avoid branch limits in the V3 bytecode set."
arg caseOf: {
[1] -> [^self positiveMachineIntegerFor: objectMemory oldSpaceSize].
[2] -> [^objectMemory integerObjectOf: objectMemory newSpaceSize].
[3] -> [^self positiveMachineIntegerFor: objectMemory totalMemorySize].
[6] -> [^objectMemory integerObjectOf: objectMemory tenuringThreshold].
[7] -> [^objectMemory integerObjectOf: objectMemory statFullGCs].
[8] -> [^objectMemory integerObjectOf: objectMemory statFullGCUsecs + 500 // 1000].
[9] -> [^objectMemory integerObjectOf: (objectMemory hasSpurMemoryManagerAPI
ifTrue: [objectMemory statScavenges]
ifFalse: [objectMemory statIncrGCs])].
[10] -> [^objectMemory integerObjectOf: (objectMemory hasSpurMemoryManagerAPI
ifTrue: [objectMemory statScavengeGCUsecs]
ifFalse: [objectMemory statIncrGCUsecs]) + 500 // 1000].
[11] -> [^objectMemory integerObjectOf: objectMemory statTenures].
[12] -> [^objectMemory integerObjectOf: eventTraceMask].
[13] -> [^self getVMTickerStartUSecs].
[14] -> [^self getVMTickerCount].
[15] -> [^self getVMTickeeCallCount].
[16] -> [^self positive64BitIntegerFor: statIdleUsecs].
[17] -> [^(SistaVM and: [self isCog])
ifTrue: [objectMemory floatObjectOf: self getCogCodeZoneThreshold]
ifFalse: [ConstZero]].
[18] -> [^objectMemory hasSpurMemoryManagerAPI
ifTrue: [objectMemory integerObjectOf: objectMemory statCompactionUsecs + 500 // 1000]
ifFalse: [ConstZero]].
[19] -> [^objectMemory hasSpurMemoryManagerAPI
ifTrue: [objectMemory integerObjectOf: objectMemory scavengeThresholdAsExtent]
ifFalse: [ConstZero]].
[20] -> [^objectMemory positive64BitIntegerFor: self ioUTCStartMicroseconds].
[21] -> [^objectMemory integerObjectOf: objectMemory rootTableCount].
[22] -> [^objectMemory integerObjectOf: objectMemory statRootTableOverflows].
[23] -> [^objectMemory integerObjectOf: extraVMMemory].
[24] -> [^objectMemory integerObjectOf: objectMemory shrinkThreshold].
[25] -> [^objectMemory integerObjectOf: objectMemory growHeadroom].
[26] -> [^objectMemory integerObjectOf: self ioHeartbeatMilliseconds].
[27] -> [^objectMemory integerObjectOf: objectMemory statMarkCount].
[28] -> [^objectMemory integerObjectOf: objectMemory statSweepCount].
[29] -> [^objectMemory integerObjectOf: objectMemory statMkFwdCount].
[30] -> [^objectMemory integerObjectOf: objectMemory statCompMoveCount].
[31] -> [^objectMemory integerObjectOf: objectMemory statGrowMemory].
[32] -> [^objectMemory integerObjectOf: objectMemory statShrinkMemory].
[33] -> [^objectMemory integerObjectOf: objectMemory statRootTableCount].
[34] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue:"was statAllocationCount"
[objectMemory positive64BitIntegerFor: objectMemory currentAllocatedBytes]].
[35] -> [^objectMemory integerObjectOf: objectMemory statSurvivorCount].
[36] -> [^objectMemory integerObjectOf: (self microsecondsToMilliseconds: objectMemory statGCEndUsecs)].
[37] -> [^objectMemory integerObjectOf: objectMemory statSpecialMarkCount].
[38] -> [^objectMemory integerObjectOf: objectMemory statIGCDeltaUsecs + 500 // 1000].
[39] -> [^objectMemory integerObjectOf: statPendingFinalizationSignals].
[40] -> [^objectMemory integerObjectOf: objectMemory wordSize].
[41] -> [^objectMemory integerObjectOf: self imageFormatVersion].
[42] -> [^objectMemory integerObjectOf: numStackPages].
[43] -> [^objectMemory integerObjectOf: desiredNumStackPages].
[44] -> [^objectMemory integerObjectOf: objectMemory edenBytes].
[45] -> [^objectMemory integerObjectOf: desiredEdenBytes].
[46] -> [^self getCogCodeSize].
[47] -> [^self getDesiredCogCodeSize].
[48] -> [^self getImageHeaderFlagsParameter].
[49] -> [^objectMemory integerObjectOf: self ioGetMaxExtSemTableSize].
[52] -> [^objectMemory integerObjectOf: objectMemory rootTableCapacity].
[53] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue:
[objectMemory integerObjectOf: objectMemory numSegments]].
[54] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue:
[objectMemory integerObjectOf: objectMemory freeSize]].
[55] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue:
[objectMemory floatObjectOf: objectMemory getHeapGrowthToSizeGCRatio]].
[56] -> [^self positive64BitIntegerFor: statProcessSwitch].
[57] -> [^self positive64BitIntegerFor: statIOProcessEvents].
[58] -> [^self positive64BitIntegerFor: statForceInterruptCheck].
[59] -> [^self positive64BitIntegerFor: statCheckForEvents].
[60] -> [^self positive64BitIntegerFor: statStackOverflow].
[61] -> [^self positive64BitIntegerFor: statStackPageDivorce].
[62] -> [^self getCodeCompactionCount].
[63] -> [^self getCodeCompactionMSecs].
[64] -> [^self getCogMethodCount].
[65] -> [^self getCogVMFeatureFlags].
[66] -> [^objectMemory integerObjectOf: self stackPageByteSize].
[67] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue:
[self positiveMachineIntegerFor: objectMemory maxOldSpaceSize]].
[68] -> [^objectMemory floatObjectOf: stackPages statAverageLivePagesWhenMapping].
[69] -> [^objectMemory integerObjectOf: stackPages statMaxPageCountWhenMapping].
[70] -> [^objectMemory integerObjectOf: self vmProxyMajorVersion].
[71] -> [^objectMemory integerObjectOf: self vmProxyMinorVersion].
[72] -> [^objectMemory integerObjectOf: objectMemory statMarkUsecs + 500 // 1000].
[73] -> [^objectMemory integerObjectOf: objectMemory statSweepUsecs + 500 // 1000].
[74] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue:
[objectMemory integerObjectOf: objectMemory statMaxAllocSegmentTime + 500 // 1000]].
+ [75] -> [^objectMemory booleanObjectOf: self primitiveDoMixedArithmetic].
+ [76] -> [^objectMemory integerObjectOf: self minimumUnusedHeadroom] }
- [75] -> [^objectMemory booleanObjectOf: self primitiveDoMixedArithmetic] }
otherwise: [^nil]!
Item was changed:
----- Method: StackInterpreterPrimitives>>primitiveVMParameter (in category 'system control primitives') -----
primitiveVMParameter
"Behaviour depends on argument count:
0 args: return an Array of VM parameter values;
1 arg: return the indicated VM parameter;
2 args: set the VM indicated parameter.
VM parameters are numbered as follows:
1 end (v3)/size(Spur) of old-space (0-based, read-only)
2 end (v3)/size(Spur) of young/new-space (read-only)
3 end (v3)/size(Spur) of heap (read-only)
4 nil (was allocationCount (read-only))
5 nil (was allocations between GCs (read-write)
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 (SqueakV3) or scavenges (Spur) since startup (read-only)
10 total milliseconds in incremental GCs (SqueakV3) or scavenges (Spur) since startup (read-only)
11 tenures of surving objects since startup or reset (read-write)
12-20 were specific to ikp's JITTER VM, now 12 16 open for use
13 if started, the start time in utc microseconds of the high-priority ticker
14 if started, the number of checkHighPriorityTickees calls
15 if started, the number of tickee calls from checkHighPriorityTickees
16 total microseconds at idle since start-up (if non-zero)
17 fraction of the code zone to use (Sista only; used to control code zone use to preserve sendAndBranchData on counter tripped callback)
18 total milliseconds in compaction phase of full GC since start-up (Spur only)
19 scavenge threshold, the effective size of eden. When eden fills to the threshold a scavenge is scheduled. Newer Spur VMs only.
20 utc microseconds at VM start-up (actually at time initialization, which precedes image load).
21 root/remembered table size (occupancy) (read-only)
22 root table overflows since startup (read-only)
23 bytes of extra memory to reserve for VM buffers, plugins, etc (stored in image file header).
24 memory threshold above which shrinking object memory (rw)
25 memory headroom when growing object memory (rw)
26 interruptChecksEveryNms - force an ioProcessEvents every N milliseconds (rw)
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 Spur: bytes allocated in total since start-up or reset (read-write) (Used to be number of allocations done before current IGC/FGC (read-only))
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 BytesPerOop for this image
41 imageFormatVersion for the VM
42 number of stack pages in use
43 desired number of stack pages (stored in image file header, max 65535)
44 size of eden, in bytes
45 desired size of eden, in bytes (stored in image file header)
46 machine code zone size, in bytes (Cog only; otherwise nil)
47 desired machine code zone size (stored in image file header; Cog only; otherwise nil)
48 various header flags. See getImageHeaderFlags.
49 max size the image promises to grow the external semaphore table to (0 sets to default, which is 256 as of writing)
50-51 nil; reserved for VM parameters that persist in the image (such as eden above)
52 root/remembered table capacity
53 number of 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
56 number of process switches since startup (read-only)
57 number of ioProcessEvents calls since startup (read-only)
58 number of ForceInterruptCheck 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)
61 number of stack page divorces since startup (read-only)
62 compiled code compactions since startup (read-only; Cog only; otherwise nil)
63 total milliseconds in compiled code compactions since startup (read-only; Cog only; otherwise nil)
64 the number of methods that currently have jitted machine-code
65 various VM feature flags; see getCogVMFeatureFlags
66 the byte size of a stack page
67 the max allowed size of old space (Spur only; nil otherwise; 0 implies no limit except that of the underlying platform)
68 the average number of live stack pages when scanned by GC (at scavenge/gc/become et al) (read-write)
69 the maximum number of live stack pages when scanned by GC (at scavenge/gc/become et al) (read-write)
70 the vmProxyMajorVersion (the interpreterProxy VM_MAJOR_VERSION)
71 the vmProxyMinorVersion (the interpreterProxy VM_MINOR_VERSION)
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 the arithmetic primitives perform conversion in case of mixed SmallInteger/Float (true) or fail (false)
+ 76 the minimum unused headroom in all stack pages; Cog VMs only
Note: Thanks to Ian Piumarta for this primitive."
| paramsArraySize index |
+ paramsArraySize := 76.
- paramsArraySize := 75.
argumentCount = 0 ifTrue: [^self primitiveAllVMParameters: paramsArraySize].
argumentCount > 2 ifTrue: [^self primitiveFailFor: PrimErrBadNumArgs].
"index read & checks"
index := self stackValue: (argumentCount = 1 ifTrue: [0] ifFalse: [1]).
(objectMemory isIntegerObject: index) ifFalse: [^self primitiveFailFor: PrimErrBadArgument].
index := objectMemory integerValueOf: index.
(index < 1 or: [index > paramsArraySize]) ifTrue: [^self primitiveFailFor: PrimErrBadIndex].
argumentCount = 1 ifTrue: "read VM parameter; written this way to avoid branch limits in V3 bytecode set"
[| result |
result := self primitiveGetVMParameter: index.
^self methodReturnValue: (result ifNil: [objectMemory nilObject])].
"write a VM parameter"
self primitiveSetVMParameter: index arg: self stackTop!
Item was changed:
----- Method: TMethod>>prepareMethodIn: (in category 'transformations') -----
prepareMethodIn: aCodeGen
"Record sends of builtin operators, map sends of the special selector dispatchOn:in:
with case statement nodes, and map sends of caseOf:[otherwise:] to switch statements.
Declare limit variables for to:[by:]do: loops with limits that potentially have side-effects.
As a hack also update the types of variables introduced to implement cascades correctly.
This has to be done at the same time as this is done, so why not piggy back here?"
extraVariableNumber ifNotNil:
[declarations keysAndValuesDo:
[:varName :decl|
decl isBlock ifTrue:
[self assert: ((varName beginsWith: 'cascade') and: [varName last isDigit]).
locals add: varName.
self declarationAt: varName
put: (decl value: self value: aCodeGen), ' ', varName]]].
aCodeGen
pushScope: declarations
while:"N.B. nodesWithParentsDo: is bottom-up, hence replacement is destructive and conserved."
[parseTree nodesWithParentsDo:
[:node :parent|
node isSend ifTrue:
[aCodeGen ifStaticallyResolvedPolymorphicReceiverThenUpdateSelectorIn: node.
(aCodeGen isBuiltinSelector: node selector)
ifTrue:
[node isBuiltinOperator: true.
"If a to:by:do:'s limit has side-effects, declare the limit variable, otherwise delete it from the args"
node selector = #to:by:do: ifTrue:
[self ensureToByDoLoopLimitIsSafeAndEfficient: node in: aCodeGen]]
ifFalse:
+ [(StackInterpreter isStackAccessor: node selector)
+ ifTrue: "compute and cache the accessor depth early, before inlining destroys the accessor chains"
+ [self export ifTrue:
+ [aCodeGen accessorDepthForMethod: self]]
+ ifFalse:
+ [(CaseStatements includes: node selector) ifTrue:
+ [parent replaceNodesIn: (Dictionary newFromPairs: { node. self buildCaseStmt: node in: aCodeGen})].
+ (#(caseOf: #caseOf:otherwise:) includes: node selector) ifTrue:
+ [parent replaceNodesIn: (Dictionary newFromPairs: { node. self buildSwitchStmt: node parent: parent })].
+ (#(printf: f:printf:) includes: node selector) ifTrue:
+ [self transformPrintf: node]]]]]]!
- [(CaseStatements includes: node selector) ifTrue:
- [parent replaceNodesIn: (Dictionary newFromPairs: { node. self buildCaseStmt: node in: aCodeGen})].
- (#(caseOf: #caseOf:otherwise:) includes: node selector) ifTrue:
- [parent replaceNodesIn: (Dictionary newFromPairs: { node. self buildSwitchStmt: node parent: parent })].
- (#(printf: f:printf:) includes: node selector) ifTrue:
- [self transformPrintf: node]]]]]!