VM Maker: VMMaker.oscog-eem.2037.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

VM Maker: VMMaker.oscog-eem.2037.mcz

commits-2
 
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2037.mcz

==================== Summary ====================

Name: VMMaker.oscog-eem.2037
Author: eem
Time: 12 December 2016, 11:34:29.281549 am
UUID: bf1aec4c-021e-42cc-b72a-0e329bf20287
Ancestors: VMMaker.oscog-eem.2036

SistaRegisterAllocatingCogit:
Check-in the autogenerated code in SistaCogitClone.

=============== Diff against VMMaker.oscog-eem.2036 ===============

Item was added:
+ ----- Method: SistaCogitClone class>>additionalHeadersDo: (in category 'translation') -----
+ additionalHeadersDo: aBinaryBlock
+ "Evaluate aBinaryBlock with the names and contents of
+ any additional header files that need to be generated."
+ aBinaryBlock
+ value: 'cogmethod.h'
+ value: SistaCogMethod cogMethodHeader!

Item was added:
+ ----- Method: SistaCogitClone class>>ancilliaryClasses: (in category 'translation') -----
+ ancilliaryClasses: options
+ ^(super ancilliaryClasses: options) copyWith: SistaCogMethod!

Item was added:
+ ----- Method: SistaCogitClone class>>declareCVarsIn: (in category 'translation') -----
+ declareCVarsIn: aCodeGen
+ aCodeGen var: 'counters' type: #usqInt!

Item was added:
+ ----- Method: SistaCogitClone class>>initializeWithOptions: (in category 'class initialization') -----
+ initializeWithOptions: optionsDictionary
+
+ super initializeWithOptions: optionsDictionary.
+ CounterBytes := 4.
+ MaxCounterValue := (1 << 16) - 1!

Item was added:
+ ----- Method: SistaCogitClone class>>numTrampolines (in category 'accessing') -----
+ numTrampolines
+ ^super numTrampolines + 1
+
+ "Cogit withAllSubclasses collect: [:c| {c. (c instVarNames select: [:ea| ea beginsWith: 'ce']) size}]"
+ "self instVarNames select: [:ea| ea beginsWith: 'ce']"!

Item was added:
+ ----- Method: SistaCogitClone>>allowEarlyOpenPICPromotion (in category 'in-line cacheing') -----
+ allowEarlyOpenPICPromotion
+ <inline: true>
+ ^ false!

Item was added:
+ ----- Method: SistaCogitClone>>compileCogFullBlockMethod: (in category 'compile abstract instructions') -----
+ compileCogFullBlockMethod: numCopied
+ <option: #SistaV1BytecodeSet>
+ counters := 0.
+ ^super compileCogFullBlockMethod: numCopied!

Item was added:
+ ----- Method: SistaCogitClone>>compileCogMethod: (in category 'compile abstract instructions') -----
+ compileCogMethod: selector
+ counters := 0.
+ ^super compileCogMethod: selector!

Item was added:
+ ----- Method: SistaCogitClone>>compileFrameBuild (in category 'compile abstract instructions') -----
+ compileFrameBuild
+ "Override to prefetch counters, if any."
+ super compileFrameBuild.
+ counters ~= 0 ifTrue:
+ [self PrefetchAw: counters]!

Item was added:
+ ----- Method: SistaCogitClone>>compileFullBlockMethodFrameBuild: (in category 'compile abstract instructions') -----
+ compileFullBlockMethodFrameBuild: numCopied
+ "Override to prefetch counters if any"
+ super compileFullBlockMethodFrameBuild: numCopied.
+ counters ~= 0 ifTrue:
+ [self PrefetchAw: counters]!

Item was added:
+ ----- Method: SistaCogitClone>>disassembleMethod:on: (in category 'disassembly') -----
+ disassembleMethod: surrogateOrAddress on: aStream
+ <doNotGenerate>
+ | cogMethod |
+ cogMethod := super disassembleMethod: surrogateOrAddress on: aStream.
+ (cogMethod cmType = CMMethod
+ and: [cogMethod counters ~= 0]) ifTrue:
+ [aStream nextPutAll: 'counters:'; cr.
+ numCounters := objectRepresentation numCountersFor: counters.
+ 0 to: numCounters - 1 do:
+ [:i| | addr |
+ addr := i * CounterBytes + counters.
+ addr printOn: aStream base: 16.
+ aStream nextPut: $:; space.
+ (objectMemory long32At: addr) printOn: aStream base: 16.
+ aStream cr].
+ aStream flush]!

Item was added:
+ ----- Method: SistaCogitClone>>estimateOfAbstractOpcodesPerBytecodes (in category 'accessing') -----
+ estimateOfAbstractOpcodesPerBytecodes
+ "Due to the counter logic, the estimation is higher"
+ <inline: true>
+ ^ 11!

Item was added:
+ ----- Method: SistaCogitClone>>fillInCPICHeader:numArgs:numCases:hasMNUCase:selector: (in category 'generate machine code') -----
+ fillInCPICHeader: pic numArgs: numArgs numCases: numCases hasMNUCase: hasMNUCase selector: selector
+ pic counters: 0.
+ ^super fillInCPICHeader: pic numArgs: numArgs numCases: numCases hasMNUCase: hasMNUCase selector: selector!

Item was added:
+ ----- Method: SistaCogitClone>>fillInCounters:atEndAddress: (in category 'generate machine code') -----
+ fillInCounters: nCounters atEndAddress: endAddress
+ endAddress - (nCounters * CounterBytes)
+ to: endAddress - CounterBytes
+ by: CounterBytes
+ do: [:address|
+ objectMemory
+ long32At: address
+ put: (initialCounterValue << 16 + initialCounterValue)]!

Item was added:
+ ----- Method: SistaCogitClone>>fillInCounters:atStartAddress: (in category 'generate machine code') -----
+ fillInCounters: nCounters atStartAddress: startAddress
+ startAddress
+ to: startAddress + (nCounters - 1 * CounterBytes)
+ by: CounterBytes
+ do: [:address|
+ objectMemory
+ long32At: address
+ put: (initialCounterValue << 16 + initialCounterValue)]!

Item was added:
+ ----- Method: SistaCogitClone>>fillInMethodHeader:size:selector: (in category 'generate machine code') -----
+ fillInMethodHeader: method size: size selector: selector
+ super fillInMethodHeader: method size: size selector: selector.
+ self fillInCounters: numCounters atStartAddress: counters.
+ method counters: counters.
+ ^method!

Item was added:
+ ----- Method: SistaCogitClone>>fillInOPICHeader:numArgs:selector: (in category 'generate machine code') -----
+ fillInOPICHeader: pic numArgs: numArgs selector: selector
+ pic counters: 0.
+ ^super fillInOPICHeader: pic numArgs: numArgs selector: selector!

Item was added:
+ ----- Method: SistaCogitClone>>genBinaryConstOpVarInlinePrimitive: (in category 'inline primitive generators') -----
+ genBinaryConstOpVarInlinePrimitive: prim
+ "Const op var version of binary inline primitives."
+ "SistaV1: 248 11111000 iiiiiiii mjjjjjjj Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution.
+ See EncoderForSistaV1's class comment and StackInterpreter>>#binaryInlinePrimitive:"
+ <option: #SistaVM>
+ | ra val untaggedVal adjust |
+ ra := self allocateRegForStackEntryAt: 0.
+ self ssTop popToReg: ra.
+ self ssPop: 1.
+ val := self ssTop constant.
+ self ssPop: 1.
+ untaggedVal := val - objectMemory smallIntegerTag.
+ prim caseOf: {
+ "0 through 6, +, -, *, /, //, \\, quo:, SmallInteger op SmallInteger => SmallInteger, no overflow"
+ [0] -> [self AddCq: untaggedVal R: ra].
+ [1] -> [self MoveCq: val R: TempReg.
+ self SubR: ra R: TempReg.
+ objectRepresentation genAddSmallIntegerTagsTo: TempReg.
+ self MoveR: TempReg R: ra].
+ [2] -> [objectRepresentation genShiftAwaySmallIntegerTagsInScratchReg: ra.
+ self MoveCq: untaggedVal R: TempReg.
+ self MulR: TempReg R: ra.
+ objectRepresentation genSetSmallIntegerTagsIn: ra].
+
+ "2016 through 2019, bitAnd:, bitOr:, bitXor, bitShift:, SmallInteger op SmallInteger => SmallInteger, no overflow"
+ [16] -> [ self AndCq: val R: ra ].
+ [17] -> [ self OrCq: val R: ra ].
+ [18] -> [ self XorCw: untaggedVal R: ra. ].
+
+ "2032 through 2037, >, <, >=, <=. =, ~=, SmallInteger op SmallInteger => Boolean (flags?? then in jump bytecodes if ssTop is a flags value, just generate the instruction!!!!)"
+ "CmpCqR is SubRCq so everything is reversed, but because no CmpRCq things are reversed again and we invert the sense of the jumps."
+ [32] -> [ self CmpCq: val R: ra.
+ self genBinaryInlineComparison: JumpLess opFalse: JumpGreaterOrEqual destReg: ra ].
+ [33] -> [ self CmpCq: val R: ra.
+ self genBinaryInlineComparison: JumpGreater opFalse: JumpLessOrEqual destReg: ra ].
+ [34] -> [ self CmpCq: val R: ra.
+ self genBinaryInlineComparison: JumpLessOrEqual opFalse: JumpGreater destReg: ra ].
+ [35] -> [ self CmpCq: val R: ra.
+ self genBinaryInlineComparison: JumpGreaterOrEqual opFalse: JumpLess destReg: ra ].
+ [36] -> [ self CmpCq: val R: ra.
+ self genBinaryInlineComparison: JumpZero opFalse: JumpNonZero destReg: ra ].
+ [37] -> [ self CmpCq: val R: ra.
+ self genBinaryInlineComparison: JumpNonZero opFalse: JumpZero destReg: ra ].
+
+ "2064 through 2068, Pointer Object>>at:, Byte Object>>at:, Short16 Word Object>>at: LongWord32 Object>>at: Quad64Word Object>>at:. obj op 0-rel SmallInteger => oop"
+ [64] -> [objectRepresentation genConvertSmallIntegerToIntegerInReg: ra.
+ adjust := (objectMemory baseHeaderSize >> objectMemory shiftForWord) - 1. "shift by baseHeaderSize and then move from 1 relative to zero relative"
+ adjust ~= 0 ifTrue: [ self AddCq: adjust R: ra. ].
+ self genMoveConstant: val R: TempReg.
+ self MoveXwr: ra R: TempReg R: ra].
+ [65] -> [objectRepresentation genConvertSmallIntegerToIntegerInReg: ra.
+ adjust := objectMemory baseHeaderSize - 1. "shift by baseHeaderSize and then move from 1 relative to zero relative"
+ self AddCq: adjust R: ra.
+ self genMoveConstant: val R: TempReg.
+ self MoveXbr: ra R: TempReg R: ra.
+ objectRepresentation genConvertIntegerToSmallIntegerInReg: ra]
+ }
+ otherwise: [^EncounteredUnknownBytecode].
+ self ssPushRegister: ra.
+ ^0!

Item was added:
+ ----- Method: SistaCogitClone>>genBinaryInlineComparison:opFalse:destReg: (in category 'inline primitive generators') -----
+ genBinaryInlineComparison: opTrue opFalse: opFalse destReg: destReg
+ "Inlined comparison. opTrue = jump for true and opFalse = jump for false"
+ <var: #branchDescriptor type: #'BytecodeDescriptor *'>
+ | nextPC branchDescriptor targetBytecodePC postBranchPC |
+
+ self extractMaybeBranchDescriptorInto: [ :descr :next :postBranch :target |
+ branchDescriptor := descr. nextPC := next. postBranchPC := postBranch. targetBytecodePC := target ].
+
+ (branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse])
+ ifTrue: "This is the path where the inlined comparison is followed immediately by a branch"
+ [ (self fixupAt: nextPC - initialPC) notAFixup
+ ifTrue: "The next instruction is dead.  we can skip it."
+ [deadCode := true.
+ self ensureFixupAt: targetBytecodePC - initialPC.
+ self ensureFixupAt: postBranchPC - initialPC ]
+ ifFalse:
+ [self ssPushConstant: objectMemory trueObject]. "dummy value"
+ self genConditionalBranch: (branchDescriptor isBranchTrue ifTrue: [opTrue] ifFalse: [opFalse])
+ operand: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
+ deadCode ifFalse: [ self Jump: (self ensureNonMergeFixupAt: postBranchPC - initialPC) ] ]
+ ifFalse: "This is the path where the inlined comparison is *not* followed immediately by a branch"
+ [| condJump jump |
+ condJump := self genConditionalBranch: opTrue operand: 0.
+ self genMoveFalseR: destReg.
+ jump := self Jump: 0.
+ condJump jmpTarget: (self genMoveTrueR: destReg).
+ jump jmpTarget: self Label].
+ ^ 0!

Item was added:
+ ----- Method: SistaCogitClone>>genBinaryVarOpConstInlinePrimitive: (in category 'inline primitive generators') -----
+ genBinaryVarOpConstInlinePrimitive: prim
+ "Var op const version of inline binary inline primitives."
+ "SistaV1: 248 11111000 iiiiiiii mjjjjjjj Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution.
+ See EncoderForSistaV1's class comment and StackInterpreter>>#binaryInlinePrimitive:"
+ <option: #SistaVM>
+ | rr val untaggedVal |
+ val := self ssTop constant.
+ self ssPop: 1.
+ rr := self allocateRegForStackEntryAt: 0.
+ self ssTop popToReg: rr.
+ self ssPop: 1.
+ untaggedVal := val - objectMemory smallIntegerTag.
+ prim caseOf: {
+ "0 through 6, +, -, *, /, //, \\, quo:, SmallInteger op SmallInteger => SmallInteger, no overflow"
+ [0] -> [self AddCq: untaggedVal R: rr].
+ [1] -> [self SubCq: untaggedVal R: rr ].
+ [2] -> [self flag: 'could use MulCq:R'.
+ objectRepresentation genShiftAwaySmallIntegerTagsInScratchReg: rr.
+ self MoveCq: untaggedVal R: TempReg.
+ self MulR: TempReg R: rr.
+ objectRepresentation genSetSmallIntegerTagsIn: rr].
+
+ "2016 through 2019, bitAnd:, bitOr:, bitXor, bitShift:, SmallInteger op SmallInteger => SmallInteger, no overflow"
+ [16] -> [ self AndCq: val R: rr ].
+ [17] -> [ self OrCq: val R: rr ].
+ [18] -> [ self flag: 'could use XorCq:'.
+ self XorCw: untaggedVal R: rr. ].
+
+ "2032 through 2037, >, <, >=, <=. =, ~=, SmallInteger op SmallInteger => Boolean (flags?? then in jump bytecodes if ssTop is a flags value, just generate the instruction!!!!)"
+ "CmpCqR is SubRCq so everything is reversed."
+ [32] -> [ self CmpCq: val R: rr.
+ self genBinaryInlineComparison: JumpGreater opFalse: JumpLessOrEqual destReg: rr ].
+ [33] -> [ self CmpCq: val R: rr.
+ self genBinaryInlineComparison: JumpLess opFalse: JumpGreaterOrEqual destReg: rr ].
+ [34] -> [ self CmpCq: val R: rr.
+ self genBinaryInlineComparison: JumpGreaterOrEqual opFalse: JumpLess destReg: rr ].
+ [35] -> [ self CmpCq: val R: rr.
+ self genBinaryInlineComparison: JumpLessOrEqual opFalse: JumpGreater destReg: rr ].
+ [36] -> [ self CmpCq: val R: rr.
+ self genBinaryInlineComparison: JumpZero opFalse: JumpNonZero destReg: rr ].
+ [37] -> [ self CmpCq: val R: rr.
+ self genBinaryInlineComparison: JumpNonZero opFalse: JumpZero destReg: rr ].
+
+ "2064 through 2068, Pointer Object>>at:, Byte Object>>at:, Short16 Word Object>>at: LongWord32 Object>>at: Quad64Word Object>>at:. obj op 0-rel SmallInteger => oop"
+ [64] -> [objectRepresentation genLoadSlot: (objectMemory integerValueOf: val) - 1 sourceReg: rr destReg: rr].
+ [65] -> [self MoveCq: (objectMemory integerValueOf: val) + objectMemory baseHeaderSize - 1 R: TempReg.
+ self MoveXbr: TempReg R: rr R: rr.
+ objectRepresentation genConvertIntegerToSmallIntegerInReg: rr]
+
+ }
+ otherwise: [^EncounteredUnknownBytecode].
+ self ssPushRegister: rr.
+ ^0!

Item was added:
+ ----- Method: SistaCogitClone>>genBinaryVarOpVarInlinePrimitive: (in category 'inline primitive generators') -----
+ genBinaryVarOpVarInlinePrimitive: prim
+ "Var op var version of binary inline primitives."
+ "SistaV1: 248 11111000 iiiiiiii mjjjjjjj Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution.
+ See EncoderForSistaV1's class comment and StackInterpreter>>#binaryInlinePrimitive:"
+ <option: #SistaVM>
+ | ra rr adjust |
+ self allocateRegForStackTopTwoEntriesInto: [:rTop :rNext | ra := rTop. rr := rNext ].
+ self ssTop popToReg: ra.
+ self ssPop: 1.
+ self ssTop popToReg: rr.
+ self ssPop: 1.
+ prim caseOf: {
+ "0 through 6, +, -, *, /, //, \\, quo:, SmallInteger op SmallInteger => SmallInteger, no overflow"
+ [0] -> [objectRepresentation genRemoveSmallIntegerTagsInScratchReg: ra.
+ self AddR: ra R: rr].
+ [1] -> [self SubR: ra R: rr.
+ objectRepresentation genAddSmallIntegerTagsTo: rr].
+ [2] -> [self genShiftAwaySmallIntegerTagsInScratchReg: rr.
+ self genRemoveSmallIntegerTagsInScratchReg: ra.
+ self MulR: ra R: rr.
+ self genSetSmallIntegerTagsIn: rr].
+
+ "2016 through 2019, bitAnd:, bitOr:, bitXor, bitShift:, SmallInteger op SmallInteger => SmallInteger, no overflow"
+ [16] -> [ self AndR: ra R: rr ].
+ [17] -> [ self OrR: ra R: rr ].
+ [18] -> [objectRepresentation genRemoveSmallIntegerTagsInScratchReg: ra.
+ self XorR: ra R: rr. ].
+
+
+ "2032 through 2037, >, <, >=, <=. =, ~=, SmallInteger op SmallInteger => Boolean (flags?? then in jump bytecodes if ssTop is a flags value, just generate the instruction!!!!)"
+ "CmpCqR is SubRCq so everything is reversed."
+ [32] -> [ self CmpR: ra R: rr.
+ self genBinaryInlineComparison: JumpGreater opFalse: JumpLessOrEqual destReg: rr ].
+ [33] -> [ self CmpR: ra R: rr.
+ self genBinaryInlineComparison: JumpLess opFalse: JumpGreaterOrEqual destReg: rr ].
+ [34] -> [ self CmpR: ra R: rr.
+ self genBinaryInlineComparison: JumpGreaterOrEqual opFalse: JumpLess destReg: rr ].
+ [35] -> [ self CmpR: ra R: rr.
+ self genBinaryInlineComparison: JumpLessOrEqual opFalse: JumpGreater destReg: rr ].
+ [36] -> [ self CmpR: ra R: rr.
+ self genBinaryInlineComparison: JumpZero opFalse: JumpNonZero destReg: rr ].
+ [37] -> [ self CmpR: ra R: rr.
+ self genBinaryInlineComparison: JumpNonZero opFalse: JumpZero destReg: rr ].
+
+ "2064 through 2068, Pointer Object>>at:, Byte Object>>at:, Short16 Word Object>>at: LongWord32 Object>>at: Quad64Word Object>>at:. obj op 0-rel SmallInteger => oop"
+ [64] -> [objectRepresentation genConvertSmallIntegerToIntegerInReg: ra.
+ adjust := (objectMemory baseHeaderSize >> objectMemory shiftForWord) - 1. "shift by baseHeaderSize and then move from 1 relative to zero relative"
+ adjust ~= 0 ifTrue: [ self AddCq: adjust R: ra. ].
+ self MoveXwr: ra R: rr R: rr ].
+ [65] -> [objectRepresentation genConvertSmallIntegerToIntegerInReg: ra.
+ adjust := objectMemory baseHeaderSize - 1. "shift by baseHeaderSize and then move from 1 relative to zero relative"
+ self AddCq: adjust R: ra.
+ self MoveXbr: ra R: rr R: rr.
+ objectRepresentation genConvertIntegerToSmallIntegerInReg: rr]
+
+ }
+ otherwise: [^EncounteredUnknownBytecode].
+ self ssPushRegister: rr.
+ ^0!

Item was added:
+ ----- Method: SistaCogitClone>>genCallPrimitiveBytecode (in category 'bytecode generators') -----
+ genCallPrimitiveBytecode
+ "SistaV1: 248 11111000 iiiiiiii mjjjjjjj Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution.
+ See EncoderForSistaV1's class comment and StackInterpreter>>#inlinePrimitiveBytecode:"
+ | prim |
+ byte2 < 128 ifTrue:
+ [^bytecodePC = initialPC
+ ifTrue: [0]
+ ifFalse: [EncounteredUnknownBytecode]].
+ prim := byte2 - 128 << 8 + byte1.
+
+ prim < 1000 ifTrue:
+ [^self genNullaryInlinePrimitive: prim].
+
+ prim < 2000 ifTrue:
+ [^self genUnaryInlinePrimitive: prim - 1000].
+
+ prim < 3000 ifTrue:
+ [self ssTop type = SSConstant ifTrue:
+ [^self genBinaryVarOpConstInlinePrimitive: prim - 2000].
+ (self ssValue: 1) type = SSConstant ifTrue:
+ [^self genBinaryConstOpVarInlinePrimitive: prim - 2000].
+ ^self genBinaryVarOpVarInlinePrimitive: prim - 2000].
+
+ prim < 4000 ifTrue:
+ [^self genTrinaryInlinePrimitive: prim - 3000].
+
+ ^EncounteredUnknownBytecode!

Item was added:
+ ----- Method: SistaCogitClone>>genCounterTripOnlyJumpIf:to: (in category 'bytecode generator support') -----
+ genCounterTripOnlyJumpIf: boolean to: targetBytecodePC
+ "Specific version if the branch is only reached while falling through if the counter trips after an inlined #== branch. We do not regenerate the counter logic in this case to avoid 24 bytes instructions."
+
+ <var: #ok type: #'AbstractInstruction *'>
+ <var: #mustBeBooleanTrampoline type: #'AbstractInstruction *'>
+
+ | ok mustBeBooleanTrampoline |
+
+ extA := 0.
+
+ self ssFlushTo: simStackPtr - 1.
+
+ self ssTop popToReg: TempReg.
+
+ self ssPop: 1.
+
+ counterIndex := counterIndex + 1. "counters are increased / decreased in the inlined branch"
+
+ "We need SendNumArgsReg because of the mustBeBooleanTrampoline"
+ self ssAllocateRequiredReg: SendNumArgsReg.
+ self MoveCq: 1 R: SendNumArgsReg.
+
+ "The first time this is reached, it calls necessarily the counter trip for the trampoline because SendNumArgsReg is non zero"
+ mustBeBooleanTrampoline := self CallRT: (boolean == objectMemory falseObject
+ ifTrue: [ceSendMustBeBooleanAddFalseTrampoline]
+ ifFalse: [ceSendMustBeBooleanAddTrueTrampoline]).
+
+ self annotateBytecode: self Label.
+
+ "Cunning trick by LPD.  If true and false are contiguous subtract the smaller.
+ Correct result is either 0 or the distance between them.  If result is not 0 or
+ their distance send mustBeBoolean."
+ self assert: (objectMemory objectAfter: objectMemory falseObject) = objectMemory trueObject.
+ self genSubConstant: boolean R: TempReg.
+ self JumpZero: (self ensureFixupAt: targetBytecodePC - initialPC).
+
+ self CmpCq: (boolean == objectMemory falseObject
+ ifTrue: [objectMemory trueObject - objectMemory falseObject]
+ ifFalse: [objectMemory falseObject - objectMemory trueObject])
+ R: TempReg.
+
+ ok := self JumpZero: 0.
+ self MoveCq: 0 R: SendNumArgsReg. "if counterReg is 0 this is a mustBeBoolean, not a counter trip."
+
+ self Jump: mustBeBooleanTrampoline.
+
+ ok jmpTarget: self Label.
+ ^0!

Item was added:
+ ----- Method: SistaCogitClone>>genExecutionCountLogicInto:counterReg: (in category 'bytecode generator support') -----
+ genExecutionCountLogicInto: binaryBlock counterReg: counterReg
+ <var: #countTripped type: #'AbstractInstruction *'>
+ <inline: true>
+ | counterAddress countTripped |
+ counterAddress := counters + (CounterBytes * counterIndex).
+ self MoveA32: counterAddress R: counterReg.
+ self SubCq: 16r10000 R: counterReg. "Count executed"
+ "If counter trips simply abort the comparison continuing to the following
+ branch *without* writing back.  A double decrement will not trip the second time."
+ countTripped := self JumpCarry: 0.
+ self MoveR: counterReg A32: counterAddress. "write back"
+ binaryBlock value: counterAddress value: countTripped!

Item was added:
+ ----- Method: SistaCogitClone>>genExtJumpIfNotInstanceOfBehaviorsBytecode (in category 'bytecode generators') -----
+ genExtJumpIfNotInstanceOfBehaviorsBytecode
+ "SistaV1: * 254 11111110 kkkkkkkk jjjjjjjj branch If Not Instance Of Behavior/Array Of Behavior kkkkkkkk (+ Extend A * 256, where Extend A >= 0) distance jjjjjjjj (+ Extend B * 256, where Extend B >= 0)"
+
+ | reg literal distance targetFixUp inverse |
+
+ "We loose the information of in which register is stack top
+ when jitting the branch target so we need to flush everything.
+ We could use a fixed register here...."
+ reg := self allocateRegForStackEntryAt: 0.
+ self ssTop popToReg: reg.
+ self ssFlushTo: simStackPtr. "flushed but the value is still in reg"
+
+ self genPopStackBytecode.
+
+ literal := self getLiteral: (extA * 256 + byte1).
+ extA := 0.
+ extB < 0
+ ifTrue: [extB := extB + 128. inverse := true]
+ ifFalse: [inverse := false].
+ distance := extB * 256 + byte2.
+ extB := 0.
+
+ targetFixUp := self cCoerceSimple: (self ensureFixupAt: bytecodePC + 3 + distance - initialPC) to: #'AbstractInstruction *'.
+ inverse
+ ifFalse:
+ [(objectMemory isArrayNonImm: literal)
+ ifTrue: [objectRepresentation branchIf: reg notInstanceOfBehaviors: literal target: targetFixUp]
+ ifFalse: [objectRepresentation branchIf: reg notInstanceOfBehavior: literal target: targetFixUp] ]
+ ifTrue:
+ [(objectMemory isArrayNonImm: literal)
+ ifTrue: [objectRepresentation branchIf: reg instanceOfBehaviors: literal target: targetFixUp]
+ ifFalse: [objectRepresentation branchIf: reg instanceOfBehavior: literal target: targetFixUp]].
+
+
+
+ ^0!

Item was added:
+ ----- Method: SistaCogitClone>>genFallsThroughCountLogicCounterReg:counterAddress: (in category 'bytecode generator support') -----
+ genFallsThroughCountLogicCounterReg: counterReg counterAddress: counterAddress
+ <inline: true>
+ "Gen this when the branch has not been taken and forwarders have been followed."
+ self SubCq: 1 R: counterReg. "Count untaken"
+ self MoveR: counterReg A32: counterAddress. "write back"!

Item was added:
+ ----- Method: SistaCogitClone>>genForwardersInlinedIdenticalOrNotIf: (in category 'bytecode generators') -----
+ genForwardersInlinedIdenticalOrNotIf: orNot
+ "Override to count inlined branches if followed by a conditional branch.
+ We borrow the following conditional branch's counter and when about to
+ inline the comparison we decrement the counter (without writing it back)
+ and if it trips simply abort the inlining, falling back to the normal send which
+ will then continue to the conditional branch which will trip and enter the abort."
+ | nextPC postBranchPC targetBytecodePC branchDescriptor counterReg fixup jumpEqual jumpNotEqual
+  counterAddress countTripped unforwardArg unforwardRcvr argReg rcvrReg regMask |
+ <var: #fixup type: #'BytecodeFixup *'>
+ <var: #countTripped type: #'AbstractInstruction *'>
+ <var: #label type: #'AbstractInstruction *'>
+ <var: #branchDescriptor type: #'BytecodeDescriptor *'>
+ <var: #jumpEqual type: #'AbstractInstruction *'>
+ <var: #jumpNotEqual type: #'AbstractInstruction *'>
+
+ ((coInterpreter isOptimizedMethod: methodObj) or: [needsFrame not]) ifTrue:
+ [^super genForwardersInlinedIdenticalOrNotIf: orNot].
+
+ regMask := 0.
+
+ self extractMaybeBranchDescriptorInto: [ :descr :next :postBranch :target |
+ branchDescriptor := descr. nextPC := next. postBranchPC := postBranch. targetBytecodePC := target ].
+
+ unforwardRcvr := (objectRepresentation isUnannotatableConstant: (self ssValue: 1)) not.
+ unforwardArg := (objectRepresentation isUnannotatableConstant: self ssTop) not.
+
+ "If an operand is an annotable constant, it may be forwarded, so we need to store it into a
+ register so the forwarder check can jump back to the comparison after unforwarding the constant.
+ However, if one of the operand is an unnanotable constant, does not allocate a register for it
+ (machine code will use operations on constants)."
+ rcvrReg:= argReg := NoReg.
+ self
+ allocateEqualsEqualsRegistersArgNeedsReg: unforwardArg
+ rcvrNeedsReg: unforwardRcvr
+ into: [ :rcvr :arg | rcvrReg:= rcvr. argReg := arg ].
+
+ argReg ~= NoReg ifTrue: [ regMask := self registerMaskFor: argReg ].
+ rcvrReg ~= NoReg ifTrue: [ regMask := regMask bitOr: (self registerMaskFor: rcvrReg) ].
+
+ "Only interested in inlining if followed by a conditional branch."
+ (branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse]) ifFalse:
+ [^ self
+ genIdenticalNoBranchArgIsConstant: unforwardArg not
+ rcvrIsConstant: unforwardRcvr not
+ argReg: argReg
+ rcvrReg: rcvrReg
+ orNotIf: orNot].
+
+ "If branching the stack must be flushed for the merge"
+ self ssFlushTo: simStackPtr - 2.
+
+ unforwardArg ifTrue: [ objectRepresentation genEnsureOopInRegNotForwarded: argReg scratchReg: TempReg ].
+ unforwardRcvr ifTrue: [ objectRepresentation genEnsureOopInRegNotForwarded: rcvrReg scratchReg: TempReg ].
+
+ counterReg := self allocateRegNotConflictingWith: regMask.
+ self
+ genExecutionCountLogicInto: [ :cAddress :countTripBranch |
+ counterAddress := cAddress.
+ countTripped := countTripBranch ]
+ counterReg: counterReg.
+
+ self assert: (unforwardArg or: [ unforwardRcvr ]).
+ self genCmpArgIsConstant: unforwardArg not rcvrIsConstant: unforwardRcvr not argReg: argReg rcvrReg: rcvrReg.
+ self ssPop: 2.
+
+ "We could use (branchDescriptor isBranchTrue xor: orNot) to simplify this."
+ orNot
+ ifFalse: [branchDescriptor isBranchTrue
+ ifTrue:
+ [ fixup := (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger.
+ self JumpZero:  (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger ]
+ ifFalse: "branchDescriptor is branchFalse"
+ [ fixup := (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
+ self JumpZero: (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger ]]
+ ifTrue: [branchDescriptor isBranchTrue
+ ifFalse: "branchDescriptor is branchFalse"
+ [ fixup := (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger.
+ self JumpZero:  (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger ]
+ ifTrue:
+ [ fixup := (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
+ self JumpZero: (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger ]].
+
+ self genFallsThroughCountLogicCounterReg: counterReg counterAddress: counterAddress.
+ self Jump: fixup.
+
+ countTripped jmpTarget: self Label.
+
+ "inlined version of #== ignoring the branchDescriptor if the counter trips to have normal state for the optimizer"
+ self ssPop: -2.
+ self genCmpArgIsConstant: unforwardArg not rcvrIsConstant: unforwardRcvr not argReg: argReg rcvrReg: rcvrReg.
+ self ssPop: 2.
+
+ "This code necessarily directly falls through the jumpIf: code which pops the top of the stack into TempReg.
+ We therefore directly assign the result to TempReg to save one move instruction"
+ jumpEqual := orNot ifFalse: [self JumpZero: 0] ifTrue: [self JumpNonZero: 0].
+ self genMoveFalseR: TempReg.
+ jumpNotEqual := self Jump: 0.
+ jumpEqual jmpTarget: (self genMoveTrueR: TempReg).
+ jumpNotEqual jmpTarget: self Label.
+ self ssPushRegister: TempReg.
+
+ (self fixupAt: nextPC - initialPC) notAFixup ifTrue: [ branchReachedOnlyForCounterTrip := true ].
+
+ ^ 0!

Item was added:
+ ----- Method: SistaCogitClone>>genJumpIf:to: (in category 'bytecode generator support') -----
+ genJumpIf: boolean to: targetBytecodePC
+ "The heart of performance counting in Sista.  Conditional branches are 6 times less
+ frequent than sends and can provide basic block frequencies (send counters can't).
+ Each conditional has a 32-bit counter split into an upper 16 bits counting executions
+ and a lower half counting untaken executions of the branch.  Executing the branch
+ decrements the upper half, tripping if the count goes negative.  Not taking the branch
+ decrements the lower half.  N.B. We *do not* eliminate dead branches (true ifTrue:/true ifFalse:)
+ so that scanning for send and branch data is simplified and that branch data is correct."
+ <inline: false>
+ | ok counterAddress countTripped retry nextPC nextDescriptor desc |
+ <var: #ok type: #'AbstractInstruction *'>
+ <var: #desc type: #'CogSimStackEntry *'>
+ <var: #retry type: #'AbstractInstruction *'>
+ <var: #countTripped type: #'AbstractInstruction *'>
+ <var: #nextDescriptor type: #'BytecodeDescriptor *'>
+
+ "In optimized code we don't generate counters to improve performance"
+ (coInterpreter isOptimizedMethod: methodObj) ifTrue: [ ^ super genJumpIf: boolean to: targetBytecodePC ].
+
+ "If the branch is reached only for the counter trip trampoline
+ (typically, var1 == var2 ifTrue: falls through to the branch only for the trampoline)
+ we generate a specific path to drastically reduce the number of machine instructions"
+ branchReachedOnlyForCounterTrip ifTrue:
+ [ branchReachedOnlyForCounterTrip := false.
+ ^ self genCounterTripOnlyJumpIf: boolean to: targetBytecodePC ].
+
+ "We detect and: / or:, if found, we don't generate the counters to avoid pathological counter slow down"
+ boolean == objectMemory falseObject ifTrue:
+ [ nextPC := bytecodePC + (self generatorAt: byte0) numBytes.
+  nextDescriptor := self generatorAt: (objectMemory fetchByte: nextPC ofObject: methodObj) + bytecodeSetOffset.
+  nextDescriptor generator ==  #genPushConstantTrueBytecode ifTrue: [ ^ super genJumpIf: boolean to: targetBytecodePC ].
+  nextDescriptor := self generatorAt: (objectMemory fetchByte: targetBytecodePC ofObject: methodObj) + bytecodeSetOffset.
+  nextDescriptor generator ==  #genPushConstantFalseBytecode ifTrue: [ ^ super genJumpIf: boolean to: targetBytecodePC ].  ].
+
+ extA := 0. "We ignore the noMustBeBoolean flag. It should not be present in methods with counters, and if it is we don't care."
+
+ "We don't generate counters on branches on true/false, the basicblock usage can be inferred"
+ desc := self ssTop.
+ (desc type == SSConstant
+ and: [desc constant = objectMemory trueObject or: [desc constant = objectMemory falseObject]]) ifTrue:
+ [ ^ super genJumpIf: boolean to: targetBytecodePC ].
+
+ self ssFlushTo: simStackPtr - 1.
+ desc popToReg: TempReg.
+ self ssPop: 1.
+
+ "We need SendNumArgsReg because of the mustBeBooleanTrampoline"
+ self ssAllocateRequiredReg: SendNumArgsReg.
+
+ retry := self Label.
+ self
+ genExecutionCountLogicInto: [ :cAddress :countTripBranch |
+ counterAddress := cAddress.
+ countTripped := countTripBranch ]
+ counterReg: SendNumArgsReg.
+ counterIndex := counterIndex + 1.
+
+ "Cunning trick by LPD.  If true and false are contiguous subtract the smaller.
+ Correct result is either 0 or the distance between them.  If result is not 0 or
+ their distance send mustBeBoolean."
+ self assert: (objectMemory objectAfter: objectMemory falseObject) = objectMemory trueObject.
+ self genSubConstant: boolean R: TempReg.
+ self JumpZero: (self ensureFixupAt: targetBytecodePC - initialPC).
+
+ self genFallsThroughCountLogicCounterReg: SendNumArgsReg counterAddress: counterAddress.
+
+ self CmpCq: (boolean = objectMemory falseObject
+ ifTrue: [objectMemory trueObject - objectMemory falseObject]
+ ifFalse: [objectMemory falseObject - objectMemory trueObject])
+ R: TempReg.
+ ok := self JumpZero: 0.
+ self MoveCq: 0 R: SendNumArgsReg. "if counterReg is 0 this is a mustBeBoolean, not a counter trip."
+
+ countTripped jmpTarget: (self genCallMustBeBooleanFor: boolean).
+
+ "If we're in an image which hasn't got the Sista code loaded then the ceCounterTripped:
+ trampoline will return directly to machine code, returning the boolean.  So the code should
+ jump back to the retry point. The trampoline makes sure that TempReg has been reloaded."
+ self annotateBytecode: self Label. "For some reason if I write self annotateBytecode: (self Jump: retry) the annotation is not at the correct place."
+ self Jump: retry.
+
+ ok jmpTarget: self Label.
+ ^0!

Item was added:
+ ----- Method: SistaCogitClone>>genMustBeBooleanTrampolineFor:called: (in category 'initialization') -----
+ genMustBeBooleanTrampolineFor: boolean called: trampolineName
+ "This can be entered in one of two states, depending on SendNumArgsReg. See
+ e.g. genJumpIf:to:.  If SendNumArgsReg is non-zero then this has been entered via
+ the initial test of the counter in the jump executed count (i.e. the counter has
+ tripped).  In this case TempReg contains the boolean to be tested and should not
+ be offset, and ceCounterTripped should be invoked with the unoffset TempReg.
+ If SendNumArgsReg is zero then this has been entered for must-be-boolean
+ processing. TempReg has been offset by boolean and must be corrected and
+ ceSendMustBeBoolean: invoked with the corrected value."
+ <var: #trampolineName type: #'char *'>
+ | jumpMBB |
+ <var: #jumpMBB type: #'AbstractInstruction *'>
+ <inline: false>
+ self zeroOpcodeIndex.
+ self CmpCq: 0 R: SendNumArgsReg.
+ jumpMBB := self JumpZero: 0.
+ "Open-code self compileTrampolineFor: #ceCounterTripped: numArgs: 1 arg: TempReg ...
+ so we can restore ResultReceiverReg."
+ self genSmalltalkToCStackSwitch: true.
+ self
+ compileCallFor: #ceCounterTripped:
+ numArgs: 1
+ arg: TempReg
+ arg: nil
+ arg: nil
+ arg: nil
+ resultReg: TempReg "(*)"
+ regsToSave: self emptyRegisterMask.
+ "(*) For the case where the ceCounterTripped: call returns (e.g. because there's no callback selector
+ installed), the call to the ceSendMustBeBooleanAddTrue/FalseTrampoline is followed by a jump
+ back to the start of the counter/condition test sequence.  For this case copy the C result to
+ TempReg (the register that is tested), to reload it with the boolean to be tested."
+ backEnd genLoadStackPointers.
+ backEnd hasLinkRegister ifTrue:
+ [self PopR: LinkReg].
+ "To keep ResultReceiverReg live if optStatus thought it was, simply reload it
+ from the frame pointer.  This avoids having to reload it in the common case
+ (counter does not trip) if it was live.  Note we can't use putSelfInReceiverResultReg
+ when generating trampolines because simSelf has not yet been initialized."
+ self MoveMw: FoxMFReceiver r: FPReg R: ReceiverResultReg.
+ self RetN: 0.
+ "If the objectRepresentation does want true & false to be mobile then we need to record these addresses."
+ self assert: (objectRepresentation shouldAnnotateObjectReference: boolean) not.
+ jumpMBB jmpTarget: (self AddCq: boolean R: TempReg).
+ ^self genTrampolineFor: #ceSendMustBeBoolean:
+ called: trampolineName
+ numArgs: 1
+ arg: TempReg
+ arg: nil
+ arg: nil
+ arg: nil
+ regsToSave: self emptyRegisterMask
+ pushLinkReg: true
+ resultReg: NoReg
+ appendOpcodes: true!

Item was added:
+ ----- Method: SistaCogitClone>>genNullaryInlinePrimitive: (in category 'inline primitive generators') -----
+ genNullaryInlinePrimitive: prim
+ "Nullary inline primitives."
+ "SistaV1: 248 11111000 iiiiiiii mjjjjjjj Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution.
+ See EncoderForSistaV1's class comment and StackInterpreter>>#nullaryInlinePrimitive:"
+
+ <option: #SistaVM>
+ ^EncounteredUnknownBytecode!

Item was added:
+ ----- Method: SistaCogitClone>>genSpecialSelectorComparison (in category 'bytecode generators') -----
+ genSpecialSelectorComparison
+ "Override to count inlined branches if followed by a conditional branch.
+ We borrow the following conditional branch's counter and when about to
+ inline the comparison we decrement the counter (without writing it back)
+ and if it trips simply abort the inlining, falling back to the normal send which
+ will then continue to the conditional branch which will trip and enter the abort."
+ | nextPC postBranchPC targetBytecodePC primDescriptor branchDescriptor
+  rcvrIsInt argIsInt argInt jumpNotSmallInts inlineCAB
+  counterAddress countTripped counterReg index |
+ <var: #countTripped type: #'AbstractInstruction *'>
+ <var: #primDescriptor type: #'BytecodeDescriptor *'>
+ <var: #jumpNotSmallInts type: #'AbstractInstruction *'>
+ <var: #branchDescriptor type: #'BytecodeDescriptor *'>
+
+ (coInterpreter isOptimizedMethod: methodObj) ifTrue: [ ^ self genSpecialSelectorComparisonWithoutCounters ].
+
+ self ssFlushTo: simStackPtr - 2.
+ primDescriptor := self generatorAt: byte0.
+ argIsInt := self ssTop type = SSConstant
+ and: [objectMemory isIntegerObject: (argInt := self ssTop constant)].
+ rcvrIsInt := (self ssValue: 1) type = SSConstant
+ and: [objectMemory isIntegerObject: (self ssValue: 1) constant].
+
+ "short-cut the jump if operands are SmallInteger constants."
+ (argIsInt and: [rcvrIsInt]) ifTrue:
+ [^ self genStaticallyResolvedSpecialSelectorComparison].
+
+ self extractMaybeBranchDescriptorInto: [ :descr :next :postBranch :target |
+ branchDescriptor := descr. nextPC := next. postBranchPC := postBranch. targetBytecodePC := target ].
+
+ "Only interested in inlining if followed by a conditional branch."
+ inlineCAB := branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse].
+ "Further, only interested in inlining = and ~= if there's a SmallInteger constant involved.
+ The relational operators successfully statically predict SmallIntegers; the equality operators do not."
+ (inlineCAB and: [primDescriptor opcode = JumpZero or: [primDescriptor opcode = JumpNonZero]]) ifTrue:
+ [inlineCAB := argIsInt or: [rcvrIsInt]].
+ inlineCAB ifFalse:
+ [^self genSpecialSelectorSend].
+
+ argIsInt
+ ifTrue:
+ [(self ssValue: 1) popToReg: ReceiverResultReg.
+ self ssPop: 2.
+ self MoveR: ReceiverResultReg R: TempReg]
+ ifFalse:
+ [self marshallSendArguments: 1.
+ self MoveR: Arg0Reg R: TempReg].
+ jumpNotSmallInts := (argIsInt or: [rcvrIsInt])
+ ifTrue: [objectRepresentation genJumpNotSmallIntegerInScratchReg: TempReg]
+ ifFalse: [objectRepresentation genJumpNotSmallIntegersIn: ReceiverResultReg andScratch: TempReg scratch: ClassReg].
+
+ counterReg := self allocateRegNotConflictingWith: (self registerMaskFor: ReceiverResultReg and: Arg0Reg).
+ self
+ genExecutionCountLogicInto: [ :cAddress :countTripBranch |
+ counterAddress := cAddress.
+ countTripped := countTripBranch ]
+ counterReg: counterReg.
+
+ argIsInt
+ ifTrue: [self CmpCq: argInt R: ReceiverResultReg]
+ ifFalse: [self CmpR: Arg0Reg R: ReceiverResultReg].
+ "Cmp is weird/backwards so invert the comparison.  Further since there is a following conditional
+ jump bytecode define non-merge fixups and leave the cond bytecode to set the mergeness."
+ self genConditionalBranch: (branchDescriptor isBranchTrue
+ ifTrue: [primDescriptor opcode]
+ ifFalse: [self inverseBranchFor: primDescriptor opcode])
+ operand: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
+
+ self genFallsThroughCountLogicCounterReg: counterReg counterAddress: counterAddress.
+
+ self Jump: (self ensureNonMergeFixupAt: postBranchPC - initialPC).
+ countTripped jmpTarget: (jumpNotSmallInts jmpTarget: self Label).
+
+ argIsInt ifTrue:
+ [self MoveCq: argInt R: Arg0Reg].
+ index := byte0 - self firstSpecialSelectorBytecodeOffset.
+ ^self genMarshalledSend: index negated - 1 numArgs: 1 sendTable: ordinarySendTrampolines!

Item was added:
+ ----- Method: SistaCogitClone>>genSpecialSelectorComparisonWithoutCounters (in category 'bytecode generators') -----
+ genSpecialSelectorComparisonWithoutCounters
+ "This method is there because if I put directly the super send in genSpecialSelectorComparison Slang does not correctly translte the code to C, it does not correctly type one of the branchDescriptor to BytecodeDescriptor"
+ ^ super genSpecialSelectorComparison!

Item was added:
+ ----- Method: SistaCogitClone>>genTrinaryInlinePrimitive: (in category 'inline primitive generators') -----
+ genTrinaryInlinePrimitive: prim
+ "Unary inline primitives."
+ "SistaV1: 248 11111000 iiiiiiii mjjjjjjj Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution.
+ See EncoderForSistaV1's class comment and StackInterpreter>>#trinaryInlinePrimitive:"
+ | ra1 ra2 rr adjust needsStoreCheck |
+ "The store check requires rr to be ReceiverResultReg"
+ needsStoreCheck := (objectRepresentation isUnannotatableConstant: self ssTop) not.
+ self
+ allocateRegForStackTopThreeEntriesInto: [:rTop :rNext :rThird | ra2 := rTop. ra1 := rNext. rr := rThird ]
+ thirdIsReceiver: (prim = 0 and: [ needsStoreCheck ]).
+ self assert: (rr ~= ra1 and: [rr ~= ra2 and: [ra1 ~= ra2]]).
+ self ssTop popToReg: ra2.
+ self ssPop: 1.
+ self ssTop popToReg: ra1.
+ self ssPop: 1.
+ self ssTop popToReg: rr.
+ self ssPop: 1.
+ objectRepresentation genConvertSmallIntegerToIntegerInReg: ra1.
+ "Now: ra is the variable object, rr is long, TempReg holds the value to store."
+ self flag: #TODO. "This is not really working as the immutability and store check needs to be present. "
+ prim caseOf: {
+ "0 - 1 pointerAt:put: and byteAt:Put:"
+ [0] -> [ adjust := (objectMemory baseHeaderSize >> objectMemory shiftForWord) - 1. "shift by baseHeaderSize and then move from 1 relative to zero relative"
+ adjust ~= 0 ifTrue: [ self AddCq: adjust R: ra1. ].
+ self MoveR: ra2 Xwr: ra1 R: rr.
+ "I added needsStoreCheck so if you initialize an array with a Smi such as 0 or a boolean you don't need the store check"
+ needsStoreCheck ifTrue:
+ [ self assert: needsFrame.
+ objectRepresentation genStoreCheckReceiverReg: rr valueReg: ra2 scratchReg: TempReg inFrame: true] ].
+ [1] -> [ objectRepresentation genConvertSmallIntegerToIntegerInReg: ra2.
+ adjust := objectMemory baseHeaderSize - 1. "shift by baseHeaderSize and then move from 1 relative to zero relative"
+ self AddCq: adjust R: ra1.
+ self MoveR: ra2 Xbr: ra1 R: rr.
+ objectRepresentation genConvertIntegerToSmallIntegerInReg: ra2. ]
+ }
+ otherwise: [^EncounteredUnknownBytecode].
+ self ssPushRegister: ra2.
+ ^0!

Item was added:
+ ----- Method: SistaCogitClone>>genUnaryInlinePrimitive: (in category 'inline primitive generators') -----
+ genUnaryInlinePrimitive: prim
+ "Unary inline primitives."
+ "SistaV1: 248 11111000 iiiiiiii mjjjjjjj Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution.
+ See EncoderForSistaV1's class comment and StackInterpreter>>#unaryInlinePrimitive:"
+ | rcvrReg resultReg |
+ rcvrReg := self allocateRegForStackEntryAt: 0.
+ resultReg := self allocateRegNotConflictingWith: (self registerMaskFor: rcvrReg).
+ prim
+ caseOf: {
+ "00 unchecked class"
+ [1] -> "01 unchecked pointer numSlots"
+ [self ssTop popToReg: rcvrReg.
+ self ssPop: 1.
+ objectRepresentation
+ genGetNumSlotsOf: rcvrReg into: resultReg;
+ genConvertIntegerToSmallIntegerInReg: resultReg].
+ "02 unchecked pointer basicSize"
+ [3] -> "03 unchecked byte numBytes"
+ [self ssTop popToReg: rcvrReg.
+ self ssPop: 1.
+ objectRepresentation
+ genGetNumBytesOf: rcvrReg into: resultReg;
+ genConvertIntegerToSmallIntegerInReg: resultReg].
+ "04 unchecked short16Type format numShorts"
+ "05 unchecked word32Type format numWords"
+ "06 unchecked doubleWord64Type format numDoubleWords"
+ [11] -> "11 unchecked fixed pointer basicNew"
+ [self ssTop type ~= SSConstant ifTrue:
+ [^EncounteredUnknownBytecode].
+ (objectRepresentation
+ genGetInstanceOf: self ssTop constant
+ into: resultReg
+ initializingIf: self extBSpecifiesInitializeInstance) ~= 0 ifTrue:
+ [^ShouldNotJIT]. "e.g. bad class"
+ self ssPop: 1]
+  }
+ otherwise:
+ [^EncounteredUnknownBytecode].
+ extB := 0.
+ self ssPushRegister: resultReg.
+ ^0!

Item was added:
+ ----- Method: SistaCogitClone>>genUnconditionalTrapBytecode (in category 'bytecode generators') -----
+ genUnconditionalTrapBytecode
+ "SistaV1: * 217 Trap"
+ self ssFlushTo: simStackPtr.
+ self CallRT: ceTrapTrampoline.
+ self annotateBytecode: self Label.
+ ^0!

Item was added:
+ ----- Method: SistaCogitClone>>genUnoptimizedSpecialSelectorComparison (in category 'bytecode generators') -----
+ genUnoptimizedSpecialSelectorComparison
+ "This method is there because if I put directly the super send in genSpecialSelectorComparison Slang does not correctly translte the code to C, it does not correctly type one of the branchDescriptor to BytecodeDescriptor"
+ ^ super genSpecialSelectorComparison!

Item was added:
+ ----- Method: SistaCogitClone>>generateSistaRuntime (in category 'initialization') -----
+ generateSistaRuntime
+ "Trap sends Sista trap message to context with top of stack, so we don't need any arguments..."
+ ceTrapTrampoline := self genTrampolineFor: #ceSistaTrap called: 'ceSistaTrapTrampoline'!

Item was added:
+ ----- Method: SistaCogitClone>>getJumpTargetPCAt: (in category 'method introspection') -----
+ getJumpTargetPCAt: pc
+ <api>
+ ^backEnd jumpTargetPCAt: pc!

Item was added:
+ ----- Method: SistaCogitClone>>initialize (in category 'initialization') -----
+ initialize
+ super initialize.
+ branchReachedOnlyForCounterTrip := false.
+ cogMethodSurrogateClass := (objectMemory ifNil: [self class objectMemoryClass]) wordSize = 4
+ ifTrue: [CogSistaMethodSurrogate32]
+ ifFalse: [CogSistaMethodSurrogate64]!

Item was added:
+ ----- Method: SistaCogitClone>>initializeCodeZoneFrom:upTo: (in category 'initialization') -----
+ initializeCodeZoneFrom: startAddress upTo: endAddress
+ initialCounterValue := MaxCounterValue.
+ super initializeCodeZoneFrom: startAddress upTo: endAddress!

Item was added:
+ ----- Method: SistaCogitClone>>maybeAllocAndInitCounters (in category 'compile abstract instructions') -----
+ maybeAllocAndInitCounters
+ <inline: true>
+ self assert: counters = 0.
+ counterIndex := 0.
+ numCounters = 0 ifTrue:
+ [^true].
+ counters := objectRepresentation allocateCounters: numCounters.
+ ^counters ~= 0!

Item was added:
+ ----- Method: SistaCogitClone>>maybeCountCounter (in category 'compile abstract instructions') -----
+ maybeCountCounter
+ <inline: true>
+ numCounters := numCounters + 1!

Item was added:
+ ----- Method: SistaCogitClone>>maybeCounterIndex (in category 'compile abstract instructions') -----
+ maybeCounterIndex
+ <inline: true>
+ ^counterIndex!

Item was added:
+ ----- Method: SistaCogitClone>>maybeFreeCounters (in category 'compile abstract instructions') -----
+ maybeFreeCounters
+ <inline: true>
+ counters ~= 0 ifTrue:
+ [objectRepresentation freeCounters: counters]!

Item was added:
+ ----- Method: SistaCogitClone>>maybeFreeCountersOf: (in category 'compaction') -----
+ maybeFreeCountersOf: aCogMethod
+ "Free any counters in the method."
+ <inline: true>
+ objectRepresentation freeCounters: aCogMethod counters!

Item was added:
+ ----- Method: SistaCogitClone>>maybeInitNumCounters (in category 'compile abstract instructions') -----
+ maybeInitNumCounters
+ <inline: true>
+ numCounters := 0!

Item was added:
+ ----- Method: SistaCogitClone>>maybeMarkCountersIn: (in category 'garbage collection') -----
+ maybeMarkCountersIn: cogMethod
+ "In SIsta Spur counters are held on the heap in pinned objects which must be marked
+ to avoid them being garbage collected.  This is the hook through which that happens."
+ <var: #cogMethod type: #'CogMethod *'>
+ <inline: true>
+ objectRepresentation maybeMarkCounters: cogMethod counters!

Item was added:
+ ----- Method: SistaCogitClone>>maybeSetCounterIndex: (in category 'compile abstract instructions') -----
+ maybeSetCounterIndex: value
+ <inline: true>
+ counterIndex := value!

Item was added:
+ ----- Method: SistaCogitClone>>methodsCompiledToMachineCodeInto: (in category 'simulation only') -----
+ methodsCompiledToMachineCodeInto: arrayObject
+ <doNotGenerate>
+ ^methodZone methodsCompiledToMachineCodeInto: arrayObject!

Item was added:
+ ----- Method: SistaCogitClone>>numMethods (in category 'simulation only') -----
+ numMethods
+ <doNotGenerate>
+ ^methodZone numMethods!

Item was added:
+ ----- Method: SistaCogitClone>>picDataFor:Annotation:Mcpc:Bcpc:Method: (in category 'method introspection') -----
+ picDataFor: descriptor Annotation: isBackwardBranchAndAnnotation Mcpc: mcpc Bcpc: bcpc Method: cogMethodArg
+ <var: #descriptor type: #'BytecodeDescriptor *'>
+ <var: #mcpc type: #'char *'>
+ <var: #cogMethodArg type: #'void *'>
+ | annotation entryPoint tuple counter |
+ "N.B. Counters are always 32-bits, having two 16-bit halves for the reached and taken counts."
+ <var: #counter type: #'unsigned int'>
+
+ descriptor ifNil:
+ [^0].
+ descriptor isBranch ifTrue:
+ ["it's a branch; conditional?"
+ (descriptor isBranchTrue or: [descriptor isBranchFalse]) ifTrue:
+ [counter := (self
+ cCoerce: ((self
+ cCoerceSimple: cogMethodArg
+ to: #'CogMethod *') counters)
+ to: #'usqInt *')
+ at: counterIndex.
+ tuple := self picDataForCounter: counter at: bcpc + 1.
+ tuple = 0 ifTrue: [^PrimErrNoMemory].
+ objectMemory storePointer: introspectionDataIndex ofObject: introspectionData withValue: tuple.
+ introspectionDataIndex := introspectionDataIndex + 1.
+ counterIndex := counterIndex + 1].
+ ^0].
+ annotation := isBackwardBranchAndAnnotation >> 1.
+ ((self isPureSendAnnotation: annotation)
+ and: [entryPoint := backEnd callTargetFromReturnAddress: mcpc asUnsignedInteger.
+ entryPoint > methodZoneBase]) ifFalse: "send is not linked, or is not a send"
+ [^0].
+ self targetMethodAndSendTableFor: entryPoint "It's a linked send; find which kind."
+ annotation: annotation
+ into: [:targetMethod :sendTable| | methodClassIfSuper association |
+ methodClassIfSuper := nil.
+ sendTable = superSendTrampolines ifTrue:
+ [methodClassIfSuper := coInterpreter methodClassOf: (self cCoerceSimple: cogMethodArg to: #'CogMethod *') methodObject].
+ sendTable = directedSuperSendTrampolines ifTrue:
+ [association := backEnd literalBeforeInlineCacheTagAt: mcpc asUnsignedInteger.
+ methodClassIfSuper := objectRepresentation valueOfAssociation: association].
+ tuple := self picDataForSendTo: targetMethod
+ methodClassIfSuper: methodClassIfSuper
+ at: mcpc
+ bcpc: bcpc + 1].
+ tuple = 0 ifTrue: [^PrimErrNoMemory].
+ objectMemory storePointer: introspectionDataIndex ofObject: introspectionData withValue: tuple.
+ introspectionDataIndex := introspectionDataIndex + 1.
+ ^0!

Item was added:
+ ----- Method: SistaCogitClone>>picDataFor:into: (in category 'method introspection') -----
+ picDataFor: cogMethod into: arrayObj
+ "Collect the branch and send data for cogMethod, storing it into arrayObj."
+ <api>
+ <var: #cogMethod type: #'CogMethod *'>
+ | errCode |
+ cogMethod stackCheckOffset = 0 ifTrue:
+ [^0].
+ introspectionDataIndex := counterIndex := 0.
+ introspectionData := arrayObj.
+ errCode := self
+ mapFor: (self cCoerceSimple: cogMethod to: #'CogBlockMethod *')
+ bcpc: (coInterpreter startPCOfMethod: cogMethod methodObject)
+ performUntil: #picDataFor:Annotation:Mcpc:Bcpc:Method:
+ arg: cogMethod asVoidPointer.
+ errCode ~= 0 ifTrue:
+ [self assert: errCode = PrimErrNoMemory.
+ ^-1].
+ cogMethod blockEntryOffset ~= 0 ifTrue:
+ [errCode := self blockDispatchTargetsFor: cogMethod
+ perform: #picDataForBlockEntry:Method:
+ arg: cogMethod asInteger.
+ errCode ~= 0 ifTrue:
+ [self assert: errCode = PrimErrNoMemory.
+ ^-1]].
+ ^introspectionDataIndex!

Item was added:
+ ----- Method: SistaCogitClone>>picDataForBlockEntry:Method: (in category 'method introspection') -----
+ picDataForBlockEntry: blockEntryMcpc Method: cogMethod
+ "Collect the branch and send data for the block method starting at blockEntryMcpc, storing it into picData."
+ <returnTypeC: #usqInt>
+ | cogBlockMethod |
+ <var: #cogBlockMethod type: #'CogBlockMethod *'>
+ cogBlockMethod := self cCoerceSimple: blockEntryMcpc - (self sizeof: CogBlockMethod)
+  to: #'CogBlockMethod *'.
+ cogBlockMethod stackCheckOffset = 0 ifTrue:
+ [^0].
+ ^self
+ mapFor: cogBlockMethod
+ bcpc: cogBlockMethod startpc
+ performUntil: #picDataFor:Annotation:Mcpc:Bcpc:Method:
+ arg: cogMethod asVoidPointer!

Item was added:
+ ----- Method: SistaCogitClone>>picDataForCounter:at: (in category 'method introspection') -----
+ picDataForCounter: counter at: bcpc
+ | executedCount tuple untakenCount |
+ "N.B. Counters are always 32-bits, having two 16-bit halves for the reached and taken counts."
+ <var: #counter type: #'unsigned int'>
+ tuple := objectMemory
+ eeInstantiateClassIndex: ClassArrayCompactIndex
+ format: objectMemory arrayFormat
+ numSlots: 3.
+ tuple = 0 ifTrue:
+ [^0].
+ self assert: CounterBytes = 4.
+ executedCount := initialCounterValue - (counter >> 16).
+ untakenCount := initialCounterValue - (counter bitAnd: 16rFFFF).
+ objectMemory
+ storePointerUnchecked: 0 ofObject: tuple withValue: (objectMemory integerObjectOf: bcpc);
+ storePointerUnchecked: 1 ofObject: tuple withValue: (objectMemory integerObjectOf: executedCount);
+ storePointerUnchecked: 2 ofObject: tuple withValue: (objectMemory integerObjectOf: untakenCount).
+ ^tuple!

Item was added:
+ ----- Method: SistaCogitClone>>picDataForSendTo:methodClassIfSuper:at:bcpc: (in category 'method introspection') -----
+ picDataForSendTo: cogMethod methodClassIfSuper: methodClassOrNil at: sendMcpc bcpc: sendBcpc
+ "Answer a tuple with the send data for a linked send to cogMethod.
+ If the target is a CogMethod (monomorphic send) answer
+ { bytecode pc, inline cache class, target method }
+ If the target is an open PIC (megamorphic send) answer
+ { bytecode pc, nil, send selector }
+ If the target is a closed PIC (polymorphic send) answer
+ { bytecode pc, first class, target method, second class, second target method, ... }"
+ <var: #cogMethod type: #'CogMethod *'>
+ <var: #sendMcpc type: #'char *'>
+ | tuple class |
+ tuple := objectMemory
+ eeInstantiateClassIndex: ClassArrayCompactIndex
+ format: objectMemory arrayFormat
+ numSlots: (cogMethod cmType = CMClosedPIC
+ ifTrue: [2 * cogMethod cPICNumCases + 1]
+ ifFalse: [3]).
+ tuple = 0 ifTrue:
+ [^0].
+ objectMemory storePointerUnchecked: 0 ofObject: tuple withValue: (objectMemory integerObjectOf: sendBcpc).
+ cogMethod cmType = CMMethod ifTrue:
+ [class := methodClassOrNil ifNil:
+ [objectRepresentation classForInlineCacheTag: (backEnd inlineCacheTagAt: sendMcpc asUnsignedInteger)].
+ objectMemory
+ storePointer: 1 ofObject: tuple withValue: class;
+ storePointer: 2 ofObject: tuple withValue: cogMethod methodObject.
+ ^tuple].
+ cogMethod cmType = CMClosedPIC ifTrue:
+ [self populate: tuple withPICInfoFor: cogMethod firstCacheTag: (backEnd inlineCacheTagAt: sendMcpc asUnsignedInteger).
+ ^tuple].
+ cogMethod cmType = CMOpenPIC ifTrue:
+ [objectMemory
+ storePointerUnchecked: 1 ofObject: tuple withValue: objectMemory nilObject;
+ storePointer: 2 ofObject: tuple withValue: cogMethod selector.
+ ^tuple].
+ self error: 'invalid method type'.
+ ^0 "to get Slang to type this method as answering sqInt"!

Item was added:
+ ----- Method: SistaCogitClone>>populate:withPICInfoFor:firstCacheTag: (in category 'method introspection') -----
+ populate: tuple withPICInfoFor: cPIC firstCacheTag: firstCacheTag
+ "Populate tuple (which must be large enough) with the ClosedPIC's target method class pairs.
+ The first entry in tuple contains the bytecode pc for the send, so skip the tuple's first field."
+ <var: #cPIC type: #'CogMethod *'>
+ | pc cacheTag classOop entryPoint targetMethod value |
+ <var: #targetMethod type: #'CogMethod *'>
+
+ 1 to: cPIC cPICNumCases do:
+ [:i|
+ pc := self addressOfEndOfCase: i inCPIC: cPIC.
+ cacheTag := i = 1
+ ifTrue: [firstCacheTag]
+ ifFalse: [backEnd literalBeforeFollowingAddress: pc - backEnd jumpLongConditionalByteSize].
+ classOop := objectRepresentation classForInlineCacheTag: cacheTag.
+ objectMemory storePointer: i * 2 - 1 ofObject: tuple withValue: classOop.
+ entryPoint := i = 1
+ ifTrue: [backEnd jumpLongTargetBeforeFollowingAddress: pc]
+ ifFalse: [backEnd jumpLongConditionalTargetBeforeFollowingAddress: pc].
+ "Find target from jump.  A jump to the MNU entry-point should collect #doesNotUnderstand:"
+ (cPIC containsAddress: entryPoint)
+ ifTrue:
+ [value := objectMemory splObj: SelectorDoesNotUnderstand]
+ ifFalse:
+ [targetMethod := self cCoerceSimple: entryPoint - cmNoCheckEntryOffset to: #'CogMethod *'.
+ self assert: targetMethod cmType = CMMethod.
+ value := targetMethod methodObject].
+ objectMemory storePointer: i * 2 ofObject: tuple withValue: value]!

Item was added:
+ ----- Method: SistaCogitClone>>printPICDataForMethods (in category 'tests') -----
+ printPICDataForMethods
+ <doNotGenerate>
+ methodZone methodsDo:
+ [:cogMethod|
+ cogMethod cmType = CMMethod ifTrue:
+ [(coInterpreter picDataFor: cogMethod) ifNotNil:
+ [:thePicData|
+ coInterpreter printOop: thePicData]]]!

Item was added:
+ ----- Method: SistaCogitClone>>resetCountersIn: (in category 'sista callbacks') -----
+ resetCountersIn: cogMethod
+ <doNotGenerate>
+ objectRepresentation resetCountersIn: cogMethod!