Eliot Miranda uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.oscog-eem.3332.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.3332 Author: eem Time: 16 July 2023, 7:15:08.57287 pm UUID: c611edf1-6978-4222-99d0-0370a8f40bec Ancestors: VMMaker.oscog-eem.3331
Cogit: When a link register is in use, fix the failure to save & restore the link register around the unforwarding call in a frameless block activation. Thanks to Tom Braun for finding this bug.
=============== Diff against VMMaker.oscog-eem.3331 ===============
Item was changed: ----- Method: CogObjectRepresentationForSpur>>genEnsureOopInRegNotForwarded:scratchReg: (in category 'compile abstract instructions') ----- genEnsureOopInRegNotForwarded: reg scratchReg: scratch + <inline: true> ^ self genEnsureOopInRegNotForwarded: reg scratchReg: scratch jumpBackTo: cogit Label "label is just before the forwarder check"!
Item was changed: ----- Method: CogObjectRepresentationForSpur>>genEnsureOopInRegNotForwarded:scratchReg:updatingSlot:in: (in category 'compile abstract instructions') ----- genEnsureOopInRegNotForwarded: reg scratchReg: scratch updatingSlot: index in: objReg "Make sure that the oop in reg is not forwarded, updating the slot in objReg with the value." | loop imm ok | <var: #ok type: #'AbstractInstruction *'> <var: #imm type: #'AbstractInstruction *'> <var: #loop type: #'AbstractInstruction *'> "Open-code self genEnsureOopInRegNotForwarded: reg scratchReg: scratch updatingMw: index * objectMemory wordSize + objectMemory baseHeaderSize r: objReg. to avoid calling the store check unless the receiver is forwarded." self assert: (reg ~= scratch and: [objReg ~= scratch]). loop := cogit Label. imm := self genJumpImmediate: reg. "notionally self genGetClassIndexOfNonImm: reg into: scratch. cogit CmpCq: objectMemory isForwardedObjectClassIndexPun R: TempReg. but the following is an instruction shorter:" cogit MoveMw: 0 r: reg R: scratch. cogit AndCq: objectMemory classIndexMask - objectMemory isForwardedObjectClassIndexPun R: scratch. ok := cogit JumpNonZero: 0. self genLoadSlot: 0 sourceReg: reg destReg: reg. cogit MoveR: reg Mw: index * objectMemory wordSize + objectMemory baseHeaderSize r: objReg.
"Check that we're meeting the contract of ceStoreCheckContextReceiverTrampoline." self assert: (reg = Arg0Reg and: [scratch = TempReg and: [objReg = ReceiverResultReg]]). + "If a frame has been built then (if a link register is in use) the link register has been saved. + If not it must be saved and restored around the call since it will be used to return from the method." + cogit needsFrame + ifTrue: + [cogit CallRT: ceStoreCheckContextReceiverTrampoline] + ifFalse: + [cogit backEnd saveAndRestoreLinkRegAround: + [cogit CallRT: ceStoreCheckContextReceiverTrampoline]]. - cogit CallRT: ceStoreCheckContextReceiverTrampoline.
cogit Jump: loop. ok jmpTarget: (imm jmpTarget: cogit Label). ^0!
Item was added: + ----- Method: Cogit class>>emptyBlockMethod (in category 'tests') ----- + emptyBlockMethod + "Tom Braun found a bug in the code generator in July '23 with generation of returns for frameless full blocks. + Answer a suiitable empty block for in-image compilation tests." + ^[]!
Item was changed: + ----- Method: Cogit class>>structureOfACogMethod (in category 'documentation') ----- - ----- Method: Cogit class>>structureOfACogMethod (in category 'tests') ----- structureOfACogMethod "A CogMethod is the machine code for executable code in the Cog VM, and in the simulator these are instances of CogMethod. In actuality they are structures in memory in the CogMethodZone.. There are four real kinds, defined by the cmType field, free space: CMFree, methods: CMMethod, closed PICs: CMClosedPIC (finite polymorphic inline caches with up to 6 entries), and open PICs: CMOpenPIC (infinite megamorphicinline caches that probe the first-level method lookup cache). There is a fifth + kind of method, which is merely a header, for old-style embedded (not full) blocks: CMBlock, one which + exists only within CMMethods, and exist only to allow block activations to refer to something that looks + like a CogMethod. - kind of method, which is merely a header, for blocks: CMBlock, one which exists only within CMMethods, - and exist only to allow block activations to refer to something that looks like a CogMethod.
+ The blockSize field in a CogMethod is the size in bytes of the entire method, including the header. Methods + are aligned to at least an 8 byte boundary in the CogMethodZone. See CogAbstractInstruction>> + #roundUpToMethodAlignment:. The size is used to iterate over the methods in the zone. - The blockSize field in a CogMethod is the size in bytes of the entire method, including the header. - Methods are aligned to an 8 byte boundary in the CogMethodZone. The size is used to iterate over - the methods in the zone.
+ Follwing the header is the abort and entry code. Starting immediately after the header is the call to the + abort routine called when either a send fails or a stack limit check fails. Following that is the checked + entry point that checks the receiver is of the right class, and this code ends in the unchecked entry point. + Following this is either primitive code, followed by frame building code, or frame-building code, or, for + frameless methods, the code for the frameless method. Following that is the code for the method. If the + method contains embedded blocks then following the method code will be a CMBlock header, followed by + code for the block, for each block, and following this will be the block dispatch code, which is indexed by + the blockEntryOffset field in the CogMethod. - Follwing the header is the abort and entry code. Starting immediately after the header is the call to - the abort routine called when either a send fails or a stack limit check fails. Following that is the - checked entry point that checks the receiver is of the right class, and this code ends in the unchecked - entry point. Following this is either primitive code, followed by frame building code, or frame-building - code, or, for frameless methods, the code for the frameless method. Following that is the code for the - method. If the method contains blocks then followng the method code will be a CMBlock header, - followed by code for the block, for each block, and following this will be the block dispatch code, - which is indexed by the blockEntryOffset field in the CogMethod.
Following either the return in the method, or the block dispatch, is the method map, the meta data which identifies interesting points in the machine code. The map starts at the end of the structure and is read + backwards towards the last instruction of the method, and is terminated by a null byte. So the blockSize - backwards towards the last instruftion of the method, and is terminated by a null byte. So the blockSize is used to find the start of the map. The map reveals where object references, sends and pc-mapping points exist in the machine code. The map is parsed when garbage collecting to find and update object + references, when unlinking sends for method cache flushing, and to convert between bytecode and - references, and when unlinking sends for method cache flushing, and to convert between bytecode and machine code pcs by scanning both bytecode and machine code looking for matching points in the map."!
Item was added: + Object subclass: #EmptyFullBlockBug + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'VMMaker-Tests'! + + !EmptyFullBlockBug commentStamp: 'eem 7/16/2023 19:11' prior: 0! + An EmptyFullBlockBug is an example of a code generator bug Tom Braun found in July of '23. A frameless full block unforwarding its receiver on entry failed to save and restore the link register (if in use) around the call to follow the receiver. + + Bug doit: + + | receiver block | + receiver := EmptyFullBlockBug new. + block := receiver emptyFullBlock. + 100 timesRepeat: + [receiver becomeForward: Morph new. + block value]!
Item was added: + ----- Method: EmptyFullBlockBug>>emptyFullBlock (in category 'accessing') ----- + emptyFullBlock + ^[]!
Item was removed: - ----- Method: RegisterAllocatingCogit>>needsFrame (in category 'accessing') ----- - needsFrame - "for asserts" - <cmacro: '() needsFrame'> - ^needsFrame!
Item was added: + ----- Method: SimpleStackBasedCogit>>needsFrame (in category 'accessing') ----- + needsFrame + "for asserts" + <cmacro: '() needsFrame'> + ^needsFrame!
vm-dev@lists.squeakfoundation.org