[Vm-dev] VM Maker: VMMaker.oscog-tpr.1511.mcz

Eliot Miranda eliot.miranda at gmail.com
Wed Nov 11 19:28:57 UTC 2015


Bravo Tim!  Such a nice improvement.  Thank you!

On Fri, Nov 6, 2015 at 12:08 PM, <commits at source.squeak.org> wrote:

>
> tim Rowledge uploaded a new version of VMMaker to project VM Maker:
> http://source.squeak.org/VMMaker/VMMaker.oscog-tpr.1511.mcz
>
> ==================== Summary ====================
>
> Name: VMMaker.oscog-tpr.1511
> Author: tpr
> Time: 6 November 2015, 1:08:47.44 pm
> UUID: c040c1b1-b67f-45ec-973e-4ffd34322ea5
> Ancestors: VMMaker.oscog-eem.1510
>
> Merge in a fairly large change to closed PICs; they are no longer compiled
> each time we make on or extend one, but rather  copied from a prototype and
> updated as needed.
> Take a look at  http://wiki.squeak.org/squeak/6205 for some explanations.
>
> Oh, and fix the div/mod simulation so it actually works. This makes
> simulating the stdio reading test images actually work on ARM.
>
> Clement - there is a single Sista related change in here that may or may
> not break things for you ;-)
>
> =============== Diff against VMMaker.oscog-eem.1510 ===============
>
> Item was changed:
>   ----- Method: CogARMCompiler>>aeabiDiv:Mod: (in category 'simulation')
> -----
>   aeabiDiv: dividend Mod: divisor
>   "simulate the __aeabi_idivmod call"
>         <doNotGenerate>
> +       |result top bottom|
> -       |result|
>
> +       top:= dividend signedIntFromLong.
> +       bottom := divisor signedIntFromLong.
> +
> +       cogit processor r0: (result :=(top quo: bottom) signedIntToLong).
> +       cogit processor r1: (top rem: bottom) signedIntToLong.
> -       cogit processor r0: (result :=dividend quo: divisor).
> -       cogit processor r1: (dividend rem: divisor).
>         ^result!
>
> Item was changed:
>   ----- Method: CogARMCompiler>>callTargetFromReturnAddress: (in category
> 'inline cacheing') -----
>   callTargetFromReturnAddress: callSiteReturnAddress
>         "Answer the address that the call immediately preceding
> callSiteReturnAddress will jump to."
>         "this is also used by #jumpLongTargetBeforeFollowingAddress:."
>         | callDistance call |
>         call := self instructionBeforeAddress: callSiteReturnAddress.
>         self assert: ((self instructionIsB: call) or: [self
> instructionIsBL: call]).
>         callDistance := self extractOffsetFromBL: call.
> +       ^callSiteReturnAddress + 4 "this is the pc's +8 offset, - the 4
> byte correction for the previous instruction address" + callDistance
> signedIntFromLong!
> -       ^callSiteReturnAddress + 4 + callDistance signedIntFromLong!
>
> Item was changed:
>   ----- Method: CogARMCompiler>>computeMaximumSize (in category 'generate
> machine code') -----
>   computeMaximumSize
>         "Because we don't use Thumb, each ARM instruction has 4 bytes. Many
>          abstract opcodes need more than one instruction. Instructions
> that refer
>          to constants and/or literals depend on literals being stored
> in-line or out-of-line.
>
>          N.B.  The ^N forms are to get around the bytecode compiler's long
> branch
>          limits which are exceeded when each case jumps around the
> otherwise."
>
>         opcode
>                 caseOf: {
>                 "Noops & Pseudo Ops"
>                 [Label]                                 -> [^0].
>                 [Literal]                                       -> [^4].
>                 [AlignmentNops]         -> [^(operands at: 0) - 4].
>                 [Fill16]                                        -> [^4].
>                 [Fill32]                                        -> [^4].
>                 [FillFromWord]                  -> [^4].
>                 [Nop]                                   -> [^4].
>                 "Control"
>                 [Call]                                  -> [^4].
>                 [CallFull]                              -> [^self
> literalLoadInstructionBytes + 4].
>                 [JumpR]                                 -> [^4].
>                 [Jump]                                  -> [^4].
>                 [JumpFull]                              -> [^self
> literalLoadInstructionBytes + 4].
>                 [JumpLong]                              -> [^4].
>                 [JumpZero]                              -> [^4].
>                 [JumpNonZero]                   -> [^4].
>                 [JumpNegative]                  -> [^4].
>                 [JumpNonNegative]               -> [^4].
>                 [JumpOverflow]                  -> [^4].
>                 [JumpNoOverflow]                -> [^4].
>                 [JumpCarry]                     -> [^4].
>                 [JumpNoCarry]                   -> [^4].
>                 [JumpLess]                              -> [^4].
>                 [JumpGreaterOrEqual]    -> [^4].
>                 [JumpGreater]                   -> [^4].
>                 [JumpLessOrEqual]               -> [^4].
>                 [JumpBelow]                     -> [^4].
>                 [JumpAboveOrEqual]      -> [^4].
>                 [JumpAbove]                     -> [^4].
>                 [JumpBelowOrEqual]      -> [^4].
>                 [JumpLongZero]          -> [^4].
>                 [JumpLongNonZero]       -> [^4].
>                 [JumpFPEqual]                   -> [^8].
>                 [JumpFPNotEqual]                -> [^8].
>                 [JumpFPLess]                    -> [^8].
>                 [JumpFPGreaterOrEqual]-> [^8].
>                 [JumpFPGreater]         -> [^8].
>                 [JumpFPLessOrEqual]     -> [^8].
>                 [JumpFPOrdered]         -> [^8].
>                 [JumpFPUnordered]               -> [^8].
>                 [RetN]                                  -> [^(operands at:
> 0) = 0 ifTrue: [4] ifFalse: [8]].
>                 [Stop]                                  -> [^4].
>
>                 "Arithmetic"
>                 [AddCqR]                                -> [^self
> rotateable8bitSignedImmediate: (operands at: 0)
>
>       ifTrue: [:r :i :n| 4]
>
>       ifFalse: [self literalLoadInstructionBytes + 4]].
>                 [AndCqR]                                -> [^self
> rotateable8bitBitwiseImmediate: (operands at: 0)
>
>       ifTrue: [:r :i :n| 4]
>
>       ifFalse:
>
>               [self literalLoadInstructionBytes = 4
>
>                       ifTrue: [8]
>
>                       ifFalse:
>
>                               [1 << (operands at: 0) highBit = ((operands
> at: 0) + 1)
>
>                                       ifTrue: [8]
>
>                                       ifFalse: [self
> literalLoadInstructionBytes + 4]]]].
>                 [AndCqRR]                               -> [^self
> rotateable8bitBitwiseImmediate: (operands at: 0)
>
>       ifTrue: [:r :i :n| 4]
>
>       ifFalse:
>
>               [self literalLoadInstructionBytes = 4
>
>                       ifTrue: [8]
>
>                       ifFalse:
>
>                               [1 << (operands at: 0) highBit = ((operands
> at: 0) + 1)
>
>                                       ifTrue: [8]
>
>                                       ifFalse: [self
> literalLoadInstructionBytes + 4]]]].
>                 [CmpCqR]                                -> [^self
> rotateable8bitSignedImmediate: (operands at: 0)
>
>               ifTrue: [:r :i :n| 4]
>
>               ifFalse: [self literalLoadInstructionBytes + 4]].
>                 [OrCqR]                                 -> [^self
> rotateable8bitImmediate: (operands at: 0)
>
>               ifTrue: [:r :i| 4]
>
>               ifFalse: [self literalLoadInstructionBytes + 4]].
>                 [SubCqR]                                -> [^self
> rotateable8bitSignedImmediate: (operands at: 0)
>
>               ifTrue: [:r :i :n| 4]
>
>               ifFalse: [self literalLoadInstructionBytes + 4]].
>                 [TstCqR]                                -> [^self
> rotateable8bitImmediate: (operands at: 0)
>
>               ifTrue: [:r :i| 4]
>
>               ifFalse: [self literalLoadInstructionBytes + 4]].
>                 [XorCqR]                                -> [^self
> rotateable8bitBitwiseImmediate: (operands at: 0)
>
>       ifTrue: [:r :i :n| 4]
>
>       ifFalse:
>
>               [self literalLoadInstructionBytes = 4
>
>                       ifTrue: [8]
>
>                       ifFalse:
>
>                               [1 << (operands at: 0) highBit = ((operands
> at: 0) + 1)
>
>                                       ifTrue: [8]
>
>                                       ifFalse: [self
> literalLoadInstructionBytes + 4]]]].
>                 [AddCwR]                                -> [^self
> literalLoadInstructionBytes + 4].
>                 [AndCwR]                                -> [^self
> literalLoadInstructionBytes + 4].
>                 [CmpCwR]                                -> [^self
> literalLoadInstructionBytes + 4].
>                 [OrCwR]                         -> [^self
> literalLoadInstructionBytes + 4].
>                 [SubCwR]                                -> [^self
> literalLoadInstructionBytes + 4].
>                 [XorCwR]                                -> [^self
> literalLoadInstructionBytes + 4].
>                 [AddRR]                                 -> [^4].
>                 [AndRR]                                 -> [^4].
>                 [CmpRR]                         -> [^4].
>                 [OrRR]                                  -> [^4].
>                 [XorRR]                                 -> [^4].
>                 [SubRR]                                 -> [^4].
>                 [NegateR]                               -> [^4].
>                 [LoadEffectiveAddressMwrR]
>                                                                         ->
> [^self rotateable8bitImmediate: (operands at: 0)
>
>               ifTrue: [:r :i| 4]
>
>               ifFalse: [self literalLoadInstructionBytes + 4]].
>
>                 [LogicalShiftLeftCqR]           -> [^4].
>                 [LogicalShiftRightCqR]          -> [^4].
>                 [ArithmeticShiftRightCqR]       -> [^4].
>                 [LogicalShiftLeftRR]                    -> [^4].
>                 [LogicalShiftRightRR]           -> [^4].
>                 [ArithmeticShiftRightRR]                -> [^4].
>                 [AddRdRd]                                       -> [^4].
>                 [CmpRdRd]                                       -> [^4].
>                 [SubRdRd]                                       -> [^4].
>                 [MulRdRd]                                       -> [^4].
>                 [DivRdRd]                                       -> [^4].
>                 [SqrtRd]                                        -> [^4].
>                 "ARM Specific Arithmetic"
>                 [SMULL]                         -> [^4].
>                 [MSR]                                   -> [^4].
>                 [CMPSMULL]                      -> [^4]. "special compare
> for genMulR:R: usage"
>                 "Data Movement"
>                 [MoveCqR]                               -> [^self
> literalLoadInstructionBytes = 4
>
>       ifTrue: [self literalLoadInstructionBytes]
>
>       ifFalse:
>
>               [self rotateable8bitBitwiseImmediate: (operands at: 0)
>
>                       ifTrue: [:r :i :n| 4]
>
>                       ifFalse: [self literalLoadInstructionBytes]]].
>                 [MoveCwR]                               -> [^self
> literalLoadInstructionBytes = 4
>
>       ifTrue: [self literalLoadInstructionBytes]
>
>       ifFalse:
>
>               [(self inCurrentCompilation: (operands at: 0))
>
>                       ifTrue: [4]
>
>                       ifFalse: [self literalLoadInstructionBytes]]].
>                 [MoveRR]                                -> [^4].
>                 [MoveRdRd]                              -> [^4].
>                 [MoveAwR]                               -> [^(self
> isAddressRelativeToVarBase: (operands at: 0))
>
>                               ifTrue: [4]
>
>                               ifFalse: [self literalLoadInstructionBytes +
> 4]].
>                 [MoveRAw]                               -> [^(self
> isAddressRelativeToVarBase: (operands at: 1))
>
>                               ifTrue: [4]
>
>                               ifFalse: [self literalLoadInstructionBytes +
> 4]].
> +               [MoveAbR]                               -> [^(self
> isAddressRelativeToVarBase: (operands at: 0))
> +
>                              ifTrue: [4]
> +
>                              ifFalse: [self literalLoadInstructionBytes +
> 4]].
> +               [MoveRAb]                               -> [^(self
> isAddressRelativeToVarBase: (operands at: 1))
> +
>                              ifTrue: [4]
> +
>                              ifFalse: [self literalLoadInstructionBytes +
> 4]].
>                 [MoveRMwr]                      -> [^self is12BitValue:
> (operands at: 1)
>
>       ifTrue: [:u :i| 4]
>
>       ifFalse: [self literalLoadInstructionBytes + 4]].
>                 [MoveRdM64r]                    -> [^self
> literalLoadInstructionBytes + 4].
>                 [MoveMbrR]                              -> [^self
> is12BitValue: (operands at: 0)
>
>       ifTrue: [:u :i| 4]
>
>       ifFalse: [self literalLoadInstructionBytes + 4]].
>                 [MoveRMbr]                              -> [^self
> is12BitValue: (operands at: 1)
>
>       ifTrue: [:u :i| 4]
>
>       ifFalse: [self literalLoadInstructionBytes + 4]].
>                 [MoveM16rR]                     -> [^self
> rotateable8bitImmediate: (operands at: 0)
>
>               ifTrue: [:r :i| 4]
>
>               ifFalse: [self literalLoadInstructionBytes + 4]].
>                 [MoveM64rRd]                    -> [^self
> literalLoadInstructionBytes + 4].
>                 [MoveMwrR]                      -> [^self is12BitValue:
> (operands at: 0)
>
>       ifTrue: [:u :i| 4]
>
>       ifFalse: [self literalLoadInstructionBytes + 4]].
>                 [MoveXbrRR]                     -> [^4].
>                 [MoveRXbrR]                     -> [^4].
>                 [MoveXwrRR]                     -> [^4].
>                 [MoveRXwrR]                     -> [^4].
>                 [PopR]                                  -> [^4].
>                 [PushR]                                 -> [^4].
>                 [PushCw]                                -> [^self
> literalLoadInstructionBytes = 4
>
>       ifTrue: [self literalLoadInstructionBytes + 4]
>
>       ifFalse:
>
>               [(self inCurrentCompilation: (operands at: 0))
>
>                       ifTrue: [8]
>
>                       ifFalse:
>
>                               [self rotateable8bitBitwiseImmediate:
> (operands at: 0)
>
>                                       ifTrue: [:r :i :n| 8]
>
>                                       ifFalse: [self
> literalLoadInstructionBytes + 4]]]].
>                 [PushCq]                                -> [^self
> literalLoadInstructionBytes = 4
>
>       ifTrue: [self literalLoadInstructionBytes + 4]
>
>       ifFalse:
>
>               [self rotateable8bitBitwiseImmediate: (operands at: 0)
>
>                       ifTrue: [:r :i :n| 8]
>
>                       ifFalse: [self literalLoadInstructionBytes + 4]]].
>                 [PrefetchAw]                    -> [^(self
> isAddressRelativeToVarBase: (operands at: 0))
>
>       ifTrue: [4]
>
>       ifFalse: [self literalLoadInstructionBytes + 4]].
>                 "Conversion"
>                 [ConvertRRd]                    -> [^8].
>                 }.
>         ^0 "to keep C compiler quiet"
>   !
>
> Item was added:
> + ----- Method: CogARMCompiler>>concretizeMoveAbR (in category 'generate
> machine code - concretize') -----
> + concretizeMoveAbR
> +       "Will get inlined into concretizeAt: switch."
> +       <inline: true>
> +       | srcAddr destReg instrOffset|
> +       srcAddr := operands at: 0.
> +       destReg := self concreteRegister: (operands at: 1).
> +       (self isAddressRelativeToVarBase: srcAddr) ifTrue:
> +               [self machineCodeAt: 0 put: (self ldrb: destReg rn:
> ConcreteVarBaseReg plus: 1 imm: srcAddr - cogit varBaseAddress).
> +                ^machineCodeSize := 4].
> +       "load the address into ConcreteIPReg"
> +       instrOffset := self moveCw: srcAddr intoR: ConcreteIPReg.
> +       "We *could* overwrite the last instruction above with a LDR a, b,
> last-byte-of-srcAddr BUT that would break if we change to loading literals
> instead of forming long constants"
> +       self machineCodeAt: instrOffset put: (self ldrb: destReg rn:
> ConcreteIPReg plus: 1 imm: 0).
> +       ^machineCodeSize := instrOffset + 4!
>
> Item was added:
> + ----- Method: CogARMCompiler>>concretizeMoveRAb (in category 'generate
> machine code - concretize') -----
> + concretizeMoveRAb
> +       "Will get inlined into concretizeAt: switch."
> +       "LEA ConcreteIPReg
> +       strb srcReg, [ConcreteIPReg]"
> +       <inline: true>
> +       | srcReg destAddr instrOffset|
> +       srcReg := self concreteRegister: (operands at: 0).
> +       destAddr := operands at: 1.
> +       (self isAddressRelativeToVarBase: destAddr) ifTrue:
> +               [self machineCodeAt: 0 put: (self strb: srcReg rn:
> ConcreteVarBaseReg plus: 1 imm: destAddr - cogit varBaseAddress).
> +                ^machineCodeSize := 4].
> +       "load the address into ConcreteIPReg"
> +       instrOffset := self moveCw: destAddr intoR: ConcreteIPReg.
> +       "We *could* overwrite the last instruction above with a LDR a, b,
> last-byte-of-srcAddr BUT that would break if we change to loading literals
> instead of forming long constants"
> +       self machineCodeAt: instrOffset put: (self strb: srcReg rn:
> ConcreteIPReg plus: 1 imm: 0).
> +       ^machineCodeSize := instrOffset + 4!
>
> Item was changed:
>   ----- Method: CogARMCompiler>>dispatchConcretize (in category 'generate
> machine code') -----
>   dispatchConcretize
>         "Attempt to generate concrete machine code for the instruction at
> address.
>          This is the inner dispatch of concretizeAt: actualAddress which
> exists only
>          to get around the branch size limits in the SqueakV3 (blue book
> derived)
>          bytecode set."
>         <returnTypeC: #void>
>         conditionOrNil ifNotNil:
>                 [self concretizeConditionalInstruction.
>                  ^self].
>
>         opcode caseOf: {
>                 "Noops & Pseudo Ops"
>                 [Label]                                 -> [^self
> concretizeLabel].
>                 [Literal]                                       -> [^self
> concretizeLiteral].
>                 [AlignmentNops]         -> [^self concretizeAlignmentNops].
>                 [Fill16]                                        -> [^self
> concretizeFill16].
>                 [Fill32]                                        -> [^self
> concretizeFill32].
>                 [FillFromWord]                  -> [^self
> concretizeFillFromWord].
>                 [Nop]                                   -> [^self
> concretizeNop].
>                 "Control"
>                 [Call]                                          -> [^self
> concretizeCall]. "call code within code space"
>                 [CallFull]                                      -> [^self
> concretizeCallFull]. "call code anywhere in address space"
>                 [JumpR]                                         -> [^self
> concretizeJumpR].
>                 [JumpFull]                                      -> [^self
> concretizeJumpFull]."jump within address space"
>                 [JumpLong]                                      -> [^self
> concretizeConditionalJump: AL]."jumps witihn code space"
>                 [JumpLongZero]                  -> [^self
> concretizeConditionalJump: EQ].
>                 [JumpLongNonZero]               -> [^self
> concretizeConditionalJump: NE].
>                 [Jump]                                          -> [^self
> concretizeConditionalJump: AL].
>                 [JumpZero]                                      -> [^self
> concretizeConditionalJump: EQ].
>                 [JumpNonZero]                           -> [^self
> concretizeConditionalJump: NE].
>                 [JumpNegative]                          -> [^self
> concretizeConditionalJump: MI].
>                 [JumpNonNegative]                       -> [^self
> concretizeConditionalJump: PL].
>                 [JumpOverflow]                          -> [^self
> concretizeConditionalJump: VS].
>                 [JumpNoOverflow]                        -> [^self
> concretizeConditionalJump: VC].
>                 [JumpCarry]                             -> [^self
> concretizeConditionalJump: CS].
>                 [JumpNoCarry]                           -> [^self
> concretizeConditionalJump: CC].
>                 [JumpLess]                                      -> [^self
> concretizeConditionalJump: LT].
>                 [JumpGreaterOrEqual]            -> [^self
> concretizeConditionalJump: GE].
>                 [JumpGreater]                           -> [^self
> concretizeConditionalJump: GT].
>                 [JumpLessOrEqual]                       -> [^self
> concretizeConditionalJump: LE].
>                 [JumpBelow]                             -> [^self
> concretizeConditionalJump: CC]. "unsigned lower"
>                 [JumpAboveOrEqual]              -> [^self
> concretizeConditionalJump: CS]. "unsigned greater or equal"
>                 [JumpAbove]                             -> [^self
> concretizeConditionalJump: HI].
>                 [JumpBelowOrEqual]              -> [^self
> concretizeConditionalJump: LS].
>                 [JumpFPEqual]                           -> [^self
> concretizeFPConditionalJump: EQ].
>                 [JumpFPNotEqual]                        -> [^self
> concretizeFPConditionalJump: NE].
>                 [JumpFPLess]                            -> [^self
> concretizeFPConditionalJump: LT].
>                 [JumpFPGreaterOrEqual]  -> [^self
> concretizeFPConditionalJump: GE].
>                 [JumpFPGreater]                 -> [^self
> concretizeFPConditionalJump: GT].
>                 [JumpFPLessOrEqual]             -> [^self
> concretizeFPConditionalJump: LE].
>                 [JumpFPOrdered]                 -> [^self
> concretizeFPConditionalJump: VC].
>                 [JumpFPUnordered]                       -> [^self
> concretizeFPConditionalJump: VS].
>                 [RetN]                                          -> [^self
> concretizeRetN].
>                 [Stop]                                          -> [^self
> concretizeStop].
>                 "Arithmetic"
>                 [AddCqR]                                        -> [^self
> concretizeNegateableDataOperationCqR: AddOpcode].
>                 [AndCqR]                                        -> [^self
> concretizeInvertibleDataOperationCqR: AndOpcode].
>                 [AndCqRR]                                       -> [^self
> concretizeAndCqRR].
>                 [CmpCqR]                                        -> [^self
> concretizeNegateableDataOperationCqR: CmpOpcode].
>                 [OrCqR]                                         -> [^self
> concretizeDataOperationCqR: OrOpcode].
>                 [SubCqR]                                        -> [^self
> concretizeSubCqR].
>                 [TstCqR]                                        -> [^self
> concretizeTstCqR].
>                 [XorCqR]                                        -> [^self
> concretizeInvertibleDataOperationCqR: XorOpcode].
>                 [AddCwR]                                        -> [^self
> concretizeDataOperationCwR: AddOpcode].
>                 [AndCwR]                                        -> [^self
> concretizeDataOperationCwR: AndOpcode].
>                 [CmpCwR]                                        -> [^self
> concretizeDataOperationCwR: CmpOpcode].
>                 [OrCwR]                                 -> [^self
> concretizeDataOperationCwR: OrOpcode].
>                 [SubCwR]                                        -> [^self
> concretizeDataOperationCwR: SubOpcode].
>                 [XorCwR]                                        -> [^self
> concretizeDataOperationCwR: XorOpcode].
>                 [AddRR]                                         -> [^self
> concretizeDataOperationRR: AddOpcode].
>                 [AndRR]                                         -> [^self
> concretizeDataOperationRR: AndOpcode].
>                 [CmpRR]                                 -> [^self
> concretizeDataOperationRR: CmpOpcode].
>                 [OrRR]                                          -> [^self
> concretizeDataOperationRR: OrOpcode].
>                 [SubRR]                                         -> [^self
> concretizeDataOperationRR: SubOpcode].
>                 [XorRR]                                         -> [^self
> concretizeDataOperationRR: XorOpcode].
>                 [AddRdRd]                                       -> [^self
> concretizeAddRdRd].
>                 [CmpRdRd]                                       -> [^self
> concretizeCmpRdRd].
>                 [DivRdRd]                                       -> [^self
> concretizeDivRdRd].
>                 [MulRdRd]                                       -> [^self
> concretizeMulRdRd].
>                 [SubRdRd]                                       -> [^self
> concretizeSubRdRd].
>                 [SqrtRd]                                        -> [^self
> concretizeSqrtRd].
>                 [NegateR]                                               ->
> [^self concretizeNegateR].
>                 [LoadEffectiveAddressMwrR]      -> [^self
> concretizeLoadEffectiveAddressMwrR].
>                 [ArithmeticShiftRightCqR]               -> [^self
> concretizeArithmeticShiftRightCqR].
>                 [LogicalShiftRightCqR]                  -> [^self
> concretizeLogicalShiftRightCqR].
>                 [LogicalShiftLeftCqR]                   -> [^self
> concretizeLogicalShiftLeftCqR].
>                 [ArithmeticShiftRightRR]                        -> [^self
> concretizeArithmeticShiftRightRR].
>                 [LogicalShiftLeftRR]                            -> [^self
> concretizeLogicalShiftLeftRR].
>                 [LogicalShiftRightRR]                   -> [^self
> concretizeLogicalShiftRightRR].
>                 "ARM Specific Arithmetic"
>                 [SMULL]                 -> [^self concretizeSMULL]      .
>                 [CMPSMULL]              -> [^self concretizeCMPSMULL].
>                 [MSR]                           -> [^self concretizeMSR].
>                 "Data Movement"
>                 [MoveCqR]                       -> [^self
> concretizeMoveCqR].
>                 [MoveCwR]                       -> [^self
> concretizeMoveCwR].
>                 [MoveRR]                        -> [^self
> concretizeMoveRR].
>                 [MoveAwR]                       -> [^self
> concretizeMoveAwR].
>                 [MoveRAw]                       -> [^self
> concretizeMoveRAw].
> +               [MoveAbR]                        -> [^self
> concretizeMoveAbR].
> +               [MoveRAb]                       -> [^self
> concretizeMoveRAb].
>                 [MoveMbrR]                      -> [^self
> concretizeMoveMbrR].
>                 [MoveRMbr]                      -> [^self
> concretizeMoveRMbr].
>                 [MoveM16rR]             -> [^self concretizeMoveM16rR].
>                 [MoveM64rRd]            -> [^self concretizeMoveM64rRd].
>                 [MoveMwrR]              -> [^self concretizeMoveMwrR].
>                 [MoveXbrRR]             -> [^self concretizeMoveXbrRR].
>                 [MoveRXbrR]             -> [^self concretizeMoveRXbrR].
>                 [MoveXwrRR]             -> [^self concretizeMoveXwrRR].
>                 [MoveRXwrR]             -> [^self concretizeMoveRXwrR].
>                 [MoveRMwr]              -> [^self concretizeMoveRMwr].
>                 [MoveRdM64r]            -> [^self concretizeMoveRdM64r].
>                 [PopR]                          -> [^self concretizePopR].
>                 [PushR]                         -> [^self concretizePushR].
>                 [PushCq]                        -> [^self
> concretizePushCq].
>                 [PushCw]                        -> [^self
> concretizePushCw].
>                 [PrefetchAw]            -> [^self concretizePrefetchAw].
>                 "Conversion"
>                 [ConvertRRd]            -> [^self concretizeConvertRRd]}!
>
> Item was added:
> + ----- Method: CogARMCompiler>>instructionAddressBefore: (in category
> 'inline cacheing') -----
> + instructionAddressBefore: followingAddress
> +       "Answer the instruction address immediately preceding
> followingAddress."
> +       <inline: true>
> +       ^followingAddress -4!
>
> Item was changed:
>   ----- Method: CogARMCompiler>>instructionBeforeAddress: (in category
> 'inline cacheing') -----
>   instructionBeforeAddress: followingAddress
>         "Answer the instruction immediately preceding followingAddress."
>         <inline: true>
> +       ^objectMemory longAt: (self instructionAddressBefore:
> followingAddress)!
> -       ^objectMemory longAt: followingAddress -4!
>
> Item was changed:
>   ----- Method: CogARMCompiler>>loadLiteralByteSize (in category
> 'accessing') -----
>   loadLiteralByteSize
> +       "Answer the byte size of a MoveCwR opcode's corresponding machine
> code. On ARM this is a single instruction pc-relative register load -
> unless we have made a mistake and not turned on the out of line literals
> manager"
> +       ^4!
> -       "Answer the byte size of a MoveCwR opcode's corresponding machine
> code"
> -       ^16!
>
> Item was changed:
>   ----- Method: CogARMCompiler>>relocateCallBeforeReturnPC:by: (in
> category 'inline cacheing') -----
>   relocateCallBeforeReturnPC: retpc by: delta
>         | instr distanceDiv4 |
>         self assert: delta \\ 4 = 0.
>         delta ~= 0 ifTrue:
>                 [instr := self instructionBeforeAddress: retpc.
>                  self assert: ((self instructionIsB: instr) or: [self
> instructionIsBL: instr]).
>                  distanceDiv4 := instr bitAnd: 16rFFFFFF.
>                  distanceDiv4 := distanceDiv4 + (delta // 4).
> +                objectMemory longAt: (self instructionAddressBefore:
> retpc ) put: ((instr bitAnd: 16rFF000000) bitOr: (distanceDiv4 bitAnd:
> 16rFFFFFF))]!
> -                objectMemory longAt: retpc - 4 put: ((instr bitAnd:
> 16rFF000000) bitOr: (distanceDiv4 bitAnd: 16rFFFFFF))]!
>
> Item was added:
> + ----- Method: CogARMCompiler>>rewriteCPICJumpAt:target: (in category
> 'inline cacheing') -----
> + rewriteCPICJumpAt: callSiteReturnAddress target: callTargetAddress
> +       "Rewrite a jump instruction to call a different target.  This
> variant is used to reset the
> +       jumps in the prototype CPIC to suit each use,.
> +       Answer the extent of the code change which is used to compute the
> range of the icache to flush."
> +       <var: #callSiteReturnAddress type: #usqInt>
> +       <var: #callTargetAddress type: #usqInt>
> +       ^self rewriteTransferAt: callSiteReturnAddress target:
> callTargetAddress!
>
> Item was changed:
>   ----- Method: CogARMCompiler>>rewriteCallAt:target: (in category 'inline
> cacheing') -----
>   rewriteCallAt: callSiteReturnAddress target: callTargetAddress
>         "Rewrite a call instruction to call a different target.  This
> variant is used to link PICs
> +        in ceSendMiss et al,.
> +       Answer the extent of the code change which is used to compute the
> range of the icache to flush."
> -        in ceSendMiss et al, and to rewrite cached primitive calls.
>  Answer the extent of
> -        the code change which is used to compute the range of the icache
> to flush."
>         <var: #callSiteReturnAddress type: #usqInt>
>         <var: #callTargetAddress type: #usqInt>
> +       ^self rewriteTransferAt: callSiteReturnAddress target:
> callTargetAddress!
> -       | callDistance call |
> -       "self cCode: ''
> -               inSmalltalk: [cogit disassembleFrom: callSiteReturnAddress
> - 10 to: callSiteReturnAddress - 1]."
> -       false
> -               ifTrue: [self assert: callTargetAddress >= cogit
> minCallAddress]
> -               ifFalse: [callTargetAddress >= cogit minCallAddress
> ifFalse:
> -                                       [self error: 'linking callsite to
> invalid address']].
> -       callDistance := (callTargetAddress - (callSiteReturnAddress + 8
> "pc offset"- 4 "return offset")) signedIntToLong.
> -       self assert: (self isInImmediateJumpRange: callDistance). "we
> don't support long call updates, yet"
> -       call := self bl: callDistance.
> -       objectMemory longAt:  callSiteReturnAddress - 4 put: call.
> -
> -       self assert: (self callTargetFromReturnAddress:
> callSiteReturnAddress) signedIntToLong = callTargetAddress.
> -       "self cCode: ''
> -               inSmalltalk: [cogit disassembleFrom: callSiteReturnAddress
> - 10 to: callSiteReturnAddress - 1]."
> -       ^4!
>
> Item was changed:
>   ----- Method: CogARMCompiler>>rewriteCallFullAt:target: (in category
> 'inline cacheing') -----
>   rewriteCallFullAt: callSiteReturnAddress target: callTargetAddress
>         "Rewrite a callFull instruction to jump to a different target.
> This variant
> +        is used to rewrite cached primitive calls where we load the
> target address into ip
> +       and use the 'blx ip' instruction for the actual call.
> +       Answer the extent of the
> -        is used to rewrite cached primitive calls.   Answer the extent of
> the
>          code change which is used to compute the range of the icache to
> flush."
>         <inline: true>
>         ^self
>                 rewriteFullTransferAt: callSiteReturnAddress
>                 target: callTargetAddress
>                 expectedInstruction: 16rE12FFF3C!
>
> Item was changed:
>   ----- Method: CogARMCompiler>>rewriteJumpFullAt:target: (in category
> 'inline cacheing') -----
>   rewriteJumpFullAt: callSiteReturnAddress target: callTargetAddress
>         "Rewrite a full jump instruction to jump to a different target.
> This variant
> +        is used to rewrite cached primitive calls where we load the
> target address into ip
> +       and use the 'bx ip' instruction for the actual jump.
> +       Answer the extent of the
> -        is used to rewrite cached primitive calls.   Answer the extent of
> the
>          code change which is used to compute the range of the icache to
> flush."
>         <inline: true>
>         ^self
>                 rewriteFullTransferAt: callSiteReturnAddress
>                 target: callTargetAddress
>                 expectedInstruction: 16rE12FFF1C!
>
> Item was added:
> + ----- Method: CogARMCompiler>>rewriteJumpLongAt:target: (in category
> 'inline cacheing') -----
> + rewriteJumpLongAt: callSiteReturnAddress target: callTargetAddress
> +       "Rewrite a jump instruction to call a different target.  This
> variant is used to reset the
> +       jumps in the prototype CPIC to suit each use,.
> +       Answer the extent of the code change which is used to compute the
> range of the icache to flush."
> +       <var: #callSiteReturnAddress type: #usqInt>
> +       <var: #callTargetAddress type: #usqInt>
> +       ^self rewriteTransferAt: callSiteReturnAddress target:
> callTargetAddress!
>
> Item was added:
> + ----- Method: CogARMCompiler>>rewriteTransferAt:target: (in category
> 'inline cacheing') -----
> + rewriteTransferAt: callSiteReturnAddress target: callTargetAddress
> +       "Rewrite a call/jump instruction to call a different target.  This
> variant is used to link PICs
> +        in ceSendMiss et al, and to rewrite call/jumps in CPICs.
> +       Answer the extent of
> +        the code change which is used to compute the range of the icache
> to flush."
> +       <var: #callSiteReturnAddress type: #usqInt>
> +       <var: #callTargetAddress type: #usqInt>
> +       | callDistance instr |
> +       "for debug - [cogit disassembleFrom: callSiteReturnAddress - 10
> to: callSiteReturnAddress - 1]."
> +       false
> +               ifTrue: [self assert: callTargetAddress >= cogit
> minCallAddress]
> +               ifFalse: [callTargetAddress >= cogit minCallAddress
> ifFalse:
> +                                       [self error: 'linking callsite to
> invalid address']].
> +
> +       callDistance := (callTargetAddress - (callSiteReturnAddress + 8
> "pc offset"- 4 "return offset")) signedIntToLong.
> +       self assert: (self isInImmediateJumpRange: callDistance). "we
> don't support long call updates, yet"
> +
> +       instr := self instructionBeforeAddress: callSiteReturnAddress.
> +       self assert: ((self instructionIsB: instr) or: [self
> instructionIsBL: instr]).
> +
> +       objectMemory longAt:  (self instructionAddressBefore:
> callSiteReturnAddress) put: ((instr bitAnd: 16rFF000000) bitOr:
> (callDistance // 4 bitAnd: 16rFFFFFF)).
> +
> +       self assert: (self callTargetFromReturnAddress:
> callSiteReturnAddress) signedIntToLong = callTargetAddress.
> +
> +       ^4!
>
> Item was added:
> + ----- Method:
> CogAbstractInstruction>>rewriteCPICCaseAt:tag:objRef:target: (in category
> 'inline cacheing') -----
> + rewriteCPICCaseAt: followingAddress tag: newTag objRef: newObjRef
> target: newTarget
> +       "rewrite the three values involved in a CPIC case. Used by the
> create & extend cpcic methods"
> +       self subclassResponsibility
> +       !
>
> Item was added:
> + ----- Method: CogIA32Compiler>>rewriteCPICCaseAt:tag:objRef:target: (in
> category 'inline cacheing') -----
> + rewriteCPICCaseAt: followingAddress tag: newTag objRef: newObjRef
> target: newTarget
> +       "rewrite the three values involved in a CPIC case. Used by the
> create & extend cpcic methods"
> +
> +       "IA32 CPIC cases are
> +       cmpl $0x newTag, %eax
> +       movl $0x newObjRef, %ebx
> +       jz .+0x newTarget (0x00010924)
> + "
> +       "rewite the tag via the first ldr"
> +       self storeLiteral: newTag beforeFollowingAddress:
> (followingAddress -11).
> +
> +       "write the obj ref/operand via the second ldr"
> +       self storeLiteral: newObjRef beforeFollowingAddress:
> (followingAddress - 6).
> +
> +       "write the jump address for the new target address"
> +       self rewriteJumpLongAt: followingAddress target: newTarget!
>
> Item was added:
> + ----- Method: CogIA32Compiler>>rewriteCPICJumpAt:target: (in category
> 'inline cacheing') -----
> + rewriteCPICJumpAt: callSiteReturnAddress target: callTargetAddress
> +       "Rewrite the short jump instruction to jump to a new cpic case
> target. "
> +       <var: #callSiteReturnAddress type: #usqInt>
> +       <var: #callTargetAddress type: #usqInt>
> +       | callDistance |
> +       callDistance := (callTargetAddress - callSiteReturnAddress)
> signedIntToLong.
> +       self assert: (callDistance < 256).
> +       objectMemory
> +               byteAt: callSiteReturnAddress - 1 put:  (callDistance
> bitAnd: 16rFF).
> +       "self cCode: ''
> +               inSmalltalk: [cogit disassembleFrom: callSiteReturnAddress
> - 10 to: callSiteReturnAddress - 1]."
> +       ^2!
>
> Item was changed:
>   ----- Method:
> CogInLineLiteralsARMCompiler>>rewriteInlineCacheAt:tag:target: (in category
> 'inline cacheing') -----
>   rewriteInlineCacheAt: callSiteReturnAddress tag: cacheTag target:
> callTargetAddress
>         "Rewrite an inline cache to call a different target for a new
> tag.  This variant is used
>          to link unlinked sends in ceSend:to:numArgs: et al.  Answer the
> extent of the code
>          change which is used to compute the range of the icache to flush."
>         <var: #callSiteReturnAddress type: #usqInt>
>         <var: #callTargetAddress type: #usqInt>
>         | call callDistance |
>         false
>                 ifTrue: [self assert: callTargetAddress >= cogit
> minCallAddress]
>                 ifFalse: [callTargetAddress >= cogit minCallAddress
> ifFalse:
>                                         [self error: 'linking callsite to
> invalid address']].
>         callDistance := (callTargetAddress - (callSiteReturnAddress + 8
> "pc offset"- 4 "return offset")) signedIntToLong.
>         self assert: (self isInImmediateJumpRange: callDistance). "we
> don't support long call updates here"
>         call := self bl: callDistance.
> +       objectMemory longAt: (self instructionAddressBefore:
> callSiteReturnAddress ) put: call.
> +       self insert32BitOperand: cacheTag into4InstructionsPreceding:
> (self instructionAddressBefore: callSiteReturnAddress ).
> -       objectMemory longAt: callSiteReturnAddress - 4 put: call.
> -       self insert32BitOperand: cacheTag into4InstructionsPreceding:
> callSiteReturnAddress - 4.
>         self assert: (self callTargetFromReturnAddress:
> callSiteReturnAddress) signedIntToLong = callTargetAddress.
> +       self assert: (self extract32BitOperandFrom4InstructionsPreceding:
> (self instructionAddressBefore: callSiteReturnAddress )) = cacheTag.
> -       self assert: (self extract32BitOperandFrom4InstructionsPreceding:
> callSiteReturnAddress - 4) = cacheTag.
>         "self cCode: ''
>                 inSmalltalk: [cogit disassembleFrom: callSiteReturnAddress
> - 20 to: callSiteReturnAddress - 1]."
>         ^20!
>
> Item was changed:
>   ----- Method: CogMethod>>containsAddress: (in category 'testing') -----
>   containsAddress: anAddress
> +       "is anAddress within my bounds; not a test of addresses referred
> to within instructions in the method"
>         <inline: true>
>         ^self asUnsignedInteger <= anAddress asUnsignedInteger
>           and: [self asUnsignedInteger + self blockSize >= anAddress
> asUnsignedInteger]!
>
> Item was changed:
>   ----- Method: CogMethodZone>>printOpenPICList (in category 'accessing')
> -----
>   printOpenPICList
>         <api>
>         | openPIC |
>         <var: #openPIC type: #'CogMethod *'>
>         openPIC := openPICList.
>         [openPIC == nil] whileFalse:
> +               [coInterpreter printCogMethod: openPIC.
> -               [self printCogMethod: openPIC.
>                  openPIC := self cCoerceSimple: openPIC nextOpenPIC to:
> #'CogMethod *']!
>
> Item was added:
> + ----- Method:
> CogOutOfLineLiteralsARMCompiler>>literalBeforeFollowingAddress: (in
> category 'inline cacheing') -----
> + literalBeforeFollowingAddress: followingAddress
> +       "Return the literal referenced by the instruction immediately
> preceding followingAddress."
> +       ^objectMemory longAt: (self pcRelativeAddressAt: (self
> instructionAddressBefore: followingAddress))!
>
> Item was added:
> + ----- Method:
> CogOutOfLineLiteralsARMCompiler>>rewriteCPICCaseAt:tag:objRef:target: (in
> category 'inline cacheing') -----
> + rewriteCPICCaseAt: followingAddress tag: newTag objRef: newObjRef
> target: newTarget
> +       "rewrite the three values involved in a CPIC case. Used by the
> create & extend cpcic methods"
> +
> +       "ARM CPIC cases are
> +       ldr TempReg, [pc relative -> tag]
> +       cmp TempReg0, TempReg
> +       ldr SendNumArgs, [pc relative -> obj ref]
> +       beq target"
> +       "rewite the tag via the first ldr"
> +       objectMemory longAt: (self pcRelativeAddressAt: followingAddress -
> 16) put: newTag.
> +
> +       "write the obj ref/operand via the second ldr"
> +       objectMemory longAt: (self pcRelativeAddressAt: followingAddress -
> 8) put: newObjRef.
> +
> +       "write the jump address for the new target address"
> +       self rewriteJumpLongAt: followingAddress target: newTarget!
>
> Item was changed:
>   ----- Method:
> CogOutOfLineLiteralsARMCompiler>>rewriteFullTransferAt:target:expectedInstruction:
> (in category 'inline cacheing') -----
>   rewriteFullTransferAt: callSiteReturnAddress target: callTargetAddress
> expectedInstruction: expectedInstruction
>         "Rewrite a CallFull or JumpFull instruction to transfer to a
> different target.
> +        This variant is used to rewrite cached primitive calls where we
> load the target address into ip
> +       and use the 'bx ip' or 'blx ip' instruction for the actual jump or
> call.
> +       Answer the extent
> -        This variant is used to rewrite cached primitive calls.   Answer
> the extent
>          of the code change which is used to compute the range of the
> icache to flush."
>         <var: #callSiteReturnAddress type: #usqInt>
>         <var: #callTargetAddress type: #usqInt>
>         self assert: (self instructionBeforeAddress:
> callSiteReturnAddress) = expectedInstruction.
>         objectMemory longAt: (self pcRelativeAddressAt:
> callSiteReturnAddress - 8) put: callTargetAddress.
>         "self cCode: ''
>                 inSmalltalk: [cogit disassembleFrom: callSiteReturnAddress
> - 8 to: (self pcRelativeAddressAt: callSiteReturnAddress - 8)]."
>         ^0!
>
> Item was changed:
>   ----- Method:
> CogOutOfLineLiteralsARMCompiler>>rewriteInlineCacheAt:tag:target: (in
> category 'inline cacheing') -----
>   rewriteInlineCacheAt: callSiteReturnAddress tag: cacheTag target:
> callTargetAddress
>         "Rewrite an inline cache to call a different target for a new
> tag.  This variant is used
>          to link unlinked sends in ceSend:to:numArgs: et al.  Answer the
> extent of the code
>          change which is used to compute the range of the icache to flush."
>         <var: #callSiteReturnAddress type: #usqInt>
>         <var: #callTargetAddress type: #usqInt>
>         | call callDistance |
>         callTargetAddress >= cogit minCallAddress ifFalse:
>                 [self error: 'linking callsite to invalid address'].
>         callDistance := (callTargetAddress - (callSiteReturnAddress + 8
> "pc offset"- 4 "return offset")) signedIntToLong.
>         self assert: (self isInImmediateJumpRange: callDistance). "we
> don't support long call updates here"
>         call := self bl: callDistance.
>         objectMemory
> +               longAt: (self instructionAddressBefore:
> callSiteReturnAddress ) put: call;
> -               longAt: callSiteReturnAddress - 4 put: call;
>                 longAt: (self pcRelativeAddressAt: callSiteReturnAddress -
> 8) put: cacheTag.
>         self assert: (self inlineCacheTagAt: callSiteReturnAddress) =
> cacheTag.
>         "self cCode: ''
>                 inSmalltalk: [cogit disassembleFrom: callSiteReturnAddress
> - 8 to: (self pcRelativeAddressAt: callSiteReturnAddress - 8)]."
>         ^4!
>
> Item was changed:
>   ----- Method:
> CogOutOfLineLiteralsARMCompiler>>storeLiteral:beforeFollowingAddress: (in
> category 'inline cacheing') -----
>   storeLiteral: literal beforeFollowingAddress: followingAddress
>         "Rewrite the literal in the instruction immediately preceding
> followingAddress."
> +       objectMemory longAt: (self pcRelativeAddressAt: (self
> instructionAddressBefore: followingAddress )) put: literal!
> -       objectMemory longAt: (self pcRelativeAddressAt: followingAddress -
> 4) put: literal!
>
> Item was changed:
>   CogClass subclass: #Cogit
> +       instanceVariableNames: 'coInterpreter objectMemory
> objectRepresentation processor threadManager methodZone methodZoneBase
> codeBase minValidCallAddress lastNInstructions simulatedAddresses
> simulatedTrampolines simulatedVariableGetters simulatedVariableSetters
> printRegisters printInstructions compilationTrace clickConfirm breakPC
> breakBlock singleStep guardPageSize traceFlags traceStores breakMethod
> methodObj initialPC endPC methodOrBlockNumArgs inBlock needsFrame
> hasYoungReferent primitiveIndex backEnd literalsManager callerSavedRegMask
> postCompileHook methodLabel stackCheckLabel blockEntryLabel
> blockEntryNoContextSwitch blockNoContextSwitchOffset stackOverflowCall
> sendMiss missOffset entryPointMask checkedEntryAlignment
> uncheckedEntryAlignment cmEntryOffset entry cmNoCheckEntryOffset
> noCheckEntry picMNUAbort picInterpretAbort endCPICCase0 endCPICCase1
> firstCPICCaseOffset cPICCaseSize cPICEndSize closedPICSize openPICSize
> fixups abstractOpcodes generatorTable primitiveGeneratorTable byte0 byte1
> byte2 byte3 bytecodePC bytecodeSetOffset opcodeIndex numAbstractOpcodes
> blockStarts blockCount labelCounter cStackAlignment expectedSPAlignment
> expectedFPAlignment codeModified maxLitIndex ceMethodAbortTrampoline
> cePICAbortTrampoline ceCheckForInterruptTrampoline ceCPICMissTrampoline
> ceReturnToInterpreterTrampoline ceBaseFrameReturnTrampoline
> ceSendMustBeBooleanAddTrueTrampoline ceSendMustBeBooleanAddFalseTrampoline
> ceCannotResumeTrampoline ceEnterCogCodePopReceiverReg
> ceCallCogCodePopReceiverReg ceCallCogCodePopReceiverAndClassRegs
> cePrimReturnEnterCogCode cePrimReturnEnterCogCodeProfiling
> ceNonLocalReturnTrampoline ceFetchContextInstVarTrampoline
> ceStoreContextInstVarTrampoline ceEnclosingObjectTrampoline
> ceCaptureCStackPointers ceFlushICache ceCheckFeaturesFunction
> ceTraceLinkedSendTrampoline ceTraceBlockActivationTrampoline
> ceTraceStoreTrampoline ceGetSP ordinarySendTrampolines superSendTrampolines
> directedSuperSendTrampolines dynamicSuperSendTrampolines
> outerSendTrampolines selfSendTrampolines firstSend lastSend
> realCEEnterCogCodePopReceiverReg realCECallCogCodePopReceiverReg
> realCECallCogCodePopReceiverAndClassRegs trampolineTableIndex
> trampolineAddresses objectReferencesInRuntime runtimeObjectRefIndex
> cFramePointerInUse debugPrimCallStackOffset ceTryLockVMOwner
> ceUnlockVMOwner extA extB tempOop numIRCs indexOfIRC theIRCs
> implicitReceiverSendTrampolines cogMethodSurrogateClass
> cogBlockMethodSurrogateClass nsSendCacheSurrogateClass CStackPointer
> CFramePointer cPICPrototype cPICEndOfCodeOffset cPICEndOfCodeLabel
> maxCPICCases'
> -       instanceVariableNames: 'coInterpreter objectMemory
> objectRepresentation processor threadManager methodZone methodZoneBase
> codeBase minValidCallAddress lastNInstructions simulatedAddresses
> simulatedTrampolines simulatedVariableGetters simulatedVariableSetters
> printRegisters printInstructions compilationTrace clickConfirm breakPC
> breakBlock singleStep guardPageSize traceFlags traceStores breakMethod
> methodObj initialPC endPC methodOrBlockNumArgs inBlock needsFrame
> hasYoungReferent primitiveIndex backEnd literalsManager callerSavedRegMask
> postCompileHook methodLabel stackCheckLabel blockEntryLabel
> blockEntryNoContextSwitch blockNoContextSwitchOffset stackOverflowCall
> sendMiss missOffset entryPointMask checkedEntryAlignment
> uncheckedEntryAlignment cmEntryOffset entry cmNoCheckEntryOffset
> noCheckEntry picMNUAbort picInterpretAbort endCPICCase0 endCPICCase1
> numPICCases firstCPICCaseOffset cPICCaseSize cPICEndSize closedPICSize
> openPICSize fixups abstractOpcodes generatorTable primitiveGeneratorTable
> byte0 byte1 byte2 byte3 bytecodePC bytecodeSetOffset opcodeIndex
> numAbstractOpcodes blockStarts blockCount labelCounter cStackAlignment
> expectedSPAlignment expectedFPAlignment codeModified maxLitIndex
> ceMethodAbortTrampoline cePICAbortTrampoline ceCheckForInterruptTrampoline
> ceCPICMissTrampoline ceReturnToInterpreterTrampoline
> ceBaseFrameReturnTrampoline ceSendMustBeBooleanAddTrueTrampoline
> ceSendMustBeBooleanAddFalseTrampoline ceCannotResumeTrampoline
> ceEnterCogCodePopReceiverReg ceCallCogCodePopReceiverReg
> ceCallCogCodePopReceiverAndClassRegs cePrimReturnEnterCogCode
> cePrimReturnEnterCogCodeProfiling ceNonLocalReturnTrampoline
> ceFetchContextInstVarTrampoline ceStoreContextInstVarTrampoline
> ceEnclosingObjectTrampoline ceCaptureCStackPointers ceFlushICache
> ceCheckFeaturesFunction ceTraceLinkedSendTrampoline
> ceTraceBlockActivationTrampoline ceTraceStoreTrampoline ceGetSP
> ordinarySendTrampolines superSendTrampolines directedSuperSendTrampolines
> dynamicSuperSendTrampolines outerSendTrampolines selfSendTrampolines
> firstSend lastSend realCEEnterCogCodePopReceiverReg
> realCECallCogCodePopReceiverReg realCECallCogCodePopReceiverAndClassRegs
> trampolineTableIndex trampolineAddresses objectReferencesInRuntime
> runtimeObjectRefIndex cFramePointerInUse debugPrimCallStackOffset
> ceTryLockVMOwner ceUnlockVMOwner extA extB tempOop numIRCs indexOfIRC
> theIRCs implicitReceiverSendTrampolines cogMethodSurrogateClass
> cogBlockMethodSurrogateClass nsSendCacheSurrogateClass CStackPointer
> CFramePointer'
>         classVariableNames: 'AltBlockCreationBytecodeSize
> AltFirstSpecialSelector AltNSSendIsPCAnnotated AltNumSpecialSelectors
> AnnotationConstantNames AnnotationShift AnnotationsWithBytecodePCs
> BlockCreationBytecodeSize Debug DisplacementMask DisplacementX2N
> EagerInstructionDecoration FirstAnnotation FirstSpecialSelector
> HasBytecodePC IsAbsPCReference IsAnnotationExtension IsDirectedSuperSend
> IsDisplacementX2N IsNSDynamicSuperSend IsNSImplicitReceiverSend
> IsNSSelfSend IsNSSendCall IsObjectReference IsRelativeCall IsSendCall
> IsSuperSend MapEnd MaxCompiledPrimitiveIndex MaxStackAllocSize
> MaxX2NDisplacement NSCClassTagIndex NSCEnclosingObjectIndex NSCNumArgsIndex
> NSCSelectorIndex NSCTargetIndex NSSendIsPCAnnotated NumObjRefsInRuntime
> NumOopsPerNSC NumSpecialSelectors NumTrampolines ProcessorClass'
>         poolDictionaries: 'CogCompilationConstants CogMethodConstants
> CogRTLOpcodes VMBasicConstants VMBytecodeConstants VMObjectIndices
> VMStackFrameOffsets'
>         category: 'VMMaker-JIT'!
>   Cogit class
>         instanceVariableNames: 'generatorTable primitiveTable'!
>
>   !Cogit commentStamp: 'eem 4/6/2015 15:56' prior: 0!
>   I am the code generator for the Cog VM.  My job is to produce machine
> code versions of methods for faster execution and to manage inline caches
> for faster send performance.  I can be tested in the current image using my
> class-side in-image compilation facilities.  e.g. try
>
>         StackToRegisterMappingCogit genAndDis: (Integer >> #benchFib)
>
>   I have concrete subclasses that implement different levels of
> optimization:
>         SimpleStackBasedCogit is the simplest code generator.
>
>         StackToRegisterMappingCogit is the current production code
> generator  It defers pushing operands
>         to the stack until necessary and implements a register-based
> calling convention for low-arity sends.
>
>         StackToRegisterMappingCogit is an experimental code generator with
> support for counting
>         conditional branches, intended to support adaptive optimization.
>
>   coInterpreter <CoInterpreterSimulator>
>         the VM's interpreter with which I cooperate
>   methodZoneManager <CogMethodZoneManager>
>         the manager of the machine code zone
>   objectRepresentation <CogObjectRepresentation>
>         the object used to generate object accesses
>   processor <BochsIA32Alien|?>
>         the simulator that executes the IA32/x86 machine code I generate
> when simulating execution in Smalltalk
>   simulatedTrampolines <Dictionary of Integer -> MessageSend>
>         the dictionary mapping trap jump addresses to run-time routines
> used to warp from simulated machine code in to the Smalltalk run-time.
>   simulatedVariableGetters <Dictionary of Integer -> MessageSend>
>         the dictionary mapping trap read addresses to variables in
> run-time objects used to allow simulated machine code to read variables in
> the Smalltalk run-time.
>   simulatedVariableSetters <Dictionary of Integer -> MessageSend>
>         the dictionary mapping trap write addresses to variables in
> run-time objects used to allow simulated machine code to write variables in
> the Smalltalk run-time.
>   printRegisters printInstructions clickConfirm <Boolean>
>         flags controlling debug printing and code simulation
>   breakPC <Integer>
>         machine code pc breakpoint
>   cFramePointer cStackPointer <Integer>
>         the variables representing the C stack & frame pointers, which
> must change on FFI callback and return
>   selectorOop <sqInt>
>         the oop of the methodObj being compiled
>   methodObj <sqInt>
>         the bytecode method being compiled
>   initialPC endPC <Integer>
>         the start and end pcs of the methodObj being compiled
>   methodOrBlockNumArgs <Integer>
>         argument count of current method or block being compiled
>   needsFrame <Boolean>
>         whether methodObj or block needs a frame to execute
>   primitiveIndex <Integer>
>         primitive index of current method being compiled
>   methodLabel <CogAbstractOpcode>
>         label for the method header
>   blockEntryLabel <CogAbstractOpcode>
>         label for the start of the block dispatch code
>   stackOverflowCall <CogAbstractOpcode>
>         label for the call of ceStackOverflow in the method prolog
>   sendMissCall <CogAbstractOpcode>
>         label for the call of ceSICMiss in the method prolog
>   entryOffset <Integer>
>         offset of method entry code from start (header) of method
>   entry <CogAbstractOpcode>
>         label for the first instruction of the method entry code
>   noCheckEntryOffset <Integer>
>         offset of the start of a method proper (after the method entry
> code) from start (header) of method
>   noCheckEntry <CogAbstractOpcode>
>         label for the first instruction of start of a method proper
>   fixups <Array of <AbstractOpcode Label | nil>>
>         the labels for forward jumps that will be fixed up when reaching
> the relevant bytecode.  fixup shas one element per byte in methodObj's
> bytecode
>   abstractOpcodes <Array of <AbstractOpcode>>
>         the code generated when compiling methodObj
>   byte0 byte1 byte2 byte3 <Integer>
>         individual bytes of current bytecode being compiled in methodObj
>   bytecodePointer <Integer>
>         bytecode pc (same as Smalltalk) of the current bytecode being
> compiled
>   opcodeIndex <Integer>
>         the index of the next free entry in abstractOpcodes (this code is
> translated into C where OrderedCollection et al do not exist)
>   numAbstractOpcodes <Integer>
>         the number of elements in abstractOpcocdes
>   blockStarts <Array of <BlockStart>>
>         the starts of blocks in the current method
>   blockCount
>         the index into blockStarts as they are being noted, and hence
> eventually the total number of blocks in the current method
>   labelCounter <Integer>
>         a nicety for numbering labels not needed in the production system
> but probably not expensive enough to worry about
>   ceStackOverflowTrampoline <Integer>
>   ceSend0ArgsTrampoline <Integer>
>   ceSend1ArgsTrampoline <Integer>
>   ceSend2ArgsTrampoline <Integer>
>   ceSendNArgsTrampoline <Integer>
>   ceSendSuper0ArgsTrampoline <Integer>
>   ceSendSuper1ArgsTrampoline <Integer>
>   ceSendSuper2ArgsTrampoline <Integer>
>   ceSendSuperNArgsTrampoline <Integer>
>   ceSICMissTrampoline <Integer>
>   ceCPICMissTrampoline <Integer>
>   ceStoreCheckTrampoline <Integer>
>   ceReturnToInterpreterTrampoline <Integer>
>   ceBaseFrameReturnTrampoline <Integer>
>   ceSendMustBeBooleanTrampoline <Integer>
>   ceClosureCopyTrampoline <Integer>
>         the various trampolines (system-call-like jumps from machine code
> to the run-time).
>         See Cogit>>generateTrampolines for the mapping from trampoline to
> run-time
>         routine and then read the run-time routine for a funcitonal
> description.
>   ceEnterCogCodePopReceiverReg <Integer>
>         the enilopmart (jump from run-time to machine-code)
>   methodZoneBase <Integer>
>   !
>   Cogit class
>         instanceVariableNames: 'generatorTable primitiveTable'!
>
> Item was changed:
>   ----- Method: Cogit class>>declareCVarsIn: (in category 'translation')
> -----
>   declareCVarsIn: aCCodeGenerator
>         #(      'coInterpreter' 'objectMemory' 'methodZone'
> 'objectRepresentation'
>                 'cogBlockMethodSurrogateClass' 'cogMethodSurrogateClass'
> 'nsSendCacheSurrogateClass'
>                 'threadManager' 'processor' 'lastNInstructions'
> 'simulatedAddresses'
>                 'simulatedTrampolines' 'simulatedVariableGetters'
> 'simulatedVariableSetters'
>                 'printRegisters' 'printInstructions' 'clickConfirm'
> 'singleStep') do:
>                         [:simulationVariableNotNeededForRealVM|
>                         aCCodeGenerator removeVariable:
> simulationVariableNotNeededForRealVM].
>         NewspeakVM ifFalse:
>                 [#(     'selfSendTrampolines' 'dynamicSuperSendTrampolines'
>                         'implicitReceiverSendTrampolines'
> 'outerSendTrampolines'
>                         'ceEnclosingObjectTrampoline' 'numIRCs'
> 'indexOfIRC' 'theIRCs') do:
>                                 [:variableNotNeededInNormalVM|
>                                 aCCodeGenerator removeVariable:
> variableNotNeededInNormalVM]].
>         aCCodeGenerator removeConstant: #COGMTVM. "this should be defined
> at compile time"
>         aCCodeGenerator
>                 addHeaderFile:'<stddef.h>'; "for e.g. offsetof"
>                 addHeaderFile:'"sqCogStackAlignment.h"';
>                 addHeaderFile:'"dispdbg.h"'; "must precede cointerp.h &
> cogit.h otherwise NoDbgRegParms gets screwed up"
>                 addHeaderFile:'"cogmethod.h"'.
>         NewspeakVM ifTrue:
>                 [aCCodeGenerator addHeaderFile:'"nssendcache.h"'].
>         aCCodeGenerator
>                 addHeaderFile:'#if COGMTVM';
>                 addHeaderFile:'"cointerpmt.h"';
>                 addHeaderFile:'#else';
>                 addHeaderFile:'"cointerp.h"';
>                 addHeaderFile:'#endif';
>                 addHeaderFile:'"cogit.h"'.
>         aCCodeGenerator
>                 var: #ceGetSP
>                         declareC: 'unsigned long (*ceGetSP)(void)';
>                 var: #ceCaptureCStackPointers
>                         declareC: 'void (*ceCaptureCStackPointers)(void)';
>                 var: #ceEnterCogCodePopReceiverReg
>                         declareC: 'void
> (*ceEnterCogCodePopReceiverReg)(void)';
>                 var: #realCEEnterCogCodePopReceiverReg
>                         declareC: 'void
> (*realCEEnterCogCodePopReceiverReg)(void)';
>                 var: #ceCallCogCodePopReceiverReg
>                         declareC: 'void
> (*ceCallCogCodePopReceiverReg)(void)';
>                 var: #realCECallCogCodePopReceiverReg
>                         declareC: 'void
> (*realCECallCogCodePopReceiverReg)(void)';
>                 var: #ceCallCogCodePopReceiverAndClassRegs
>                         declareC: 'void
> (*ceCallCogCodePopReceiverAndClassRegs)(void)';
>                 var: #realCECallCogCodePopReceiverAndClassRegs
>                         declareC: 'void
> (*realCECallCogCodePopReceiverAndClassRegs)(void)';
>                 var: #ceFlushICache
>                         declareC: 'static void (*ceFlushICache)(unsigned
> long from, unsigned long to)';
>                 var: #ceCheckFeaturesFunction
>                         declareC: 'static unsigned long
> (*ceCheckFeaturesFunction)(void)';
>                 var: #ceTryLockVMOwner
>                         declareC: 'unsigned long
> (*ceTryLockVMOwner)(void)';
>                 var: #ceUnlockVMOwner
>                         declareC: 'void (*ceUnlockVMOwner)(void)';
>                 var: #postCompileHook
>                         declareC: 'void (*postCompileHook)(CogMethod *)';
>                 var: #openPICList declareC: 'CogMethod *openPICList = 0';
>                 var: #maxMethodBefore type: #'CogBlockMethod *'.
>         aCCodeGenerator
>                 declareVar: 'aMethodLabel' type: #'AbstractInstruction';
> "Has to come lexicographically before backEnd & methodLabel"
>                 var: #backEnd declareC: 'AbstractInstruction * const
> backEnd = &aMethodLabel';
>                 var: #methodLabel declareC: 'AbstractInstruction * const
> methodLabel = &aMethodLabel'.
>         self declareC: #(abstractOpcodes stackCheckLabel
>                                         blockEntryLabel
> blockEntryNoContextSwitch
>                                         stackOverflowCall sendMiss
>                                         entry noCheckEntry selfSendEntry
> dynSuperEntry
> +                                       picMNUAbort picInterpretAbort
> endCPICCase0 endCPICCase1 cPICEndOfCodeLabel)
> -                                       picMNUAbort picInterpretAbort
> endCPICCase0 endCPICCase1)
>                         as: #'AbstractInstruction *'
>                                 in: aCCodeGenerator.
>         aCCodeGenerator
>                 declareVar: #blockStarts type: #'BlockStart *';
>                 declareVar: #fixups type: #'BytecodeFixup *'.
>         aCCodeGenerator
>                 var: #ordinarySendTrampolines
>                         declareC: 'sqInt
> ordinarySendTrampolines[NumSendTrampolines]';
>                 var: #superSendTrampolines
>                         declareC: 'sqInt
> superSendTrampolines[NumSendTrampolines]';
>                 var: #directedSuperSendTrampolines
>                         declareC: 'sqInt
> directedSuperSendTrampolines[NumSendTrampolines]';
>                 var: #selfSendTrampolines
>                         declareC: 'sqInt
> selfSendTrampolines[NumSendTrampolines]';
>                 var: #dynamicSuperSendTrampolines
>                         declareC: 'sqInt
> dynamicSuperSendTrampolines[NumSendTrampolines]';
>                 var: #implicitReceiverSendTrampolines
>                         declareC: 'sqInt
> implicitReceiverSendTrampolines[NumSendTrampolines]';
>                 var: #outerSendTrampolines
>                         declareC: 'sqInt
> outerSendTrampolines[NumSendTrampolines]';
>                 var: #trampolineAddresses
>                         declareC: 'static char
> *trampolineAddresses[NumTrampolines*2]';
>                 var: #objectReferencesInRuntime
>                         declareC: 'static usqInt
> objectReferencesInRuntime[NumObjRefsInRuntime]';
>                 var: #labelCounter
>                         type: #int;
>                 var: #traceFlags
>                         declareC: 'int traceFlags = 8 /* prim trace log on
> by default */';
>                 var: #cStackAlignment
>                         declareC: 'const int cStackAlignment =
> STACK_ALIGN_BYTES'.
>         aCCodeGenerator
>                 declareVar: #CFramePointer type: #'void *';
>                 declareVar: #CStackPointer type: #'void *';
>                 declareVar: #minValidCallAddress type: #'unsigned long';
>                 declareVar: #debugPrimCallStackOffset type: #'unsigned
> long'.
>         aCCodeGenerator vmClass generatorTable ifNotNil:
>                 [:bytecodeGenTable|
>                 aCCodeGenerator
>                         var: #generatorTable
>                                 declareC: 'static BytecodeDescriptor
> generatorTable[', bytecodeGenTable size, ']',
>                                                         (self
> tableInitializerFor: bytecodeGenTable
>                                                                 in:
> aCCodeGenerator);
>                         var: #primitiveGeneratorTable
>                                 declareC: 'static PrimitiveDescriptor
> primitiveGeneratorTable[MaxCompiledPrimitiveIndex+1]',
>                                                         (self
> tableInitializerFor: aCCodeGenerator vmClass primitiveTable
>                                                                 in:
> aCCodeGenerator)].
>         "In C the abstract opcode names clash with the Smalltak generator
> syntactic sugar.
>          Most of the syntactic sugar is inlined, but alas some remains.
> Rename the syntactic
>          sugar to avoid the clash."
>         (self organization listAtCategoryNamed: #'abstract instructions')
> do:
>                 [:s|
>                 aCCodeGenerator addSelectorTranslation: s to: 'g',
> (aCCodeGenerator cFunctionNameFor: s)].
>         aCCodeGenerator addSelectorTranslation: #halt: to: 'haltmsg'!
>
> Item was changed:
>   ----- Method: Cogit>>addressOfEndOfCase:inCPIC: (in category 'in-line
> cacheing') -----
> + addressOfEndOfCase: n inCPIC: cPIC
> +       "calculate the end of the n'th case statement - which is
> complicated because we have case 1 right at the top of our CPIC and then
> build up from the last one. Yes I know this sounds strange, but trust me -
> I'm an Engineer, we do things backwards all the emit"
> +
> - addressOfEndOfCase: n inCPIC: cPIC
> -       "N.B. zero-relative"
>         <var: #cPIC type: #'CogMethod *'>
> +       self assert: (n >= 1and: [n <= maxCPICCases]).
> +       n = 1
> +               ifTrue: [^ cPIC asInteger + firstCPICCaseOffset]
> +               ifFalse: [^ cPIC asInteger + firstCPICCaseOffset +
> (maxCPICCases + 1 - n * cPICCaseSize)]!
> -       ^cPIC asInteger + firstCPICCaseOffset + (n * cPICCaseSize)!
>
> Item was changed:
>   ----- Method: Cogit>>cPIC:HasTarget: (in category 'in-line cacheing')
> -----
>   cPIC: cPIC HasTarget: targetMethod
> +       "Are any of the jumps from this CPIC to targetMethod?"
>         <var: #cPIC type: #'CogMethod *'>
>         <var: #targetMethod type: #'CogMethod *'>
>         | pc target |
>         target := targetMethod asUnsignedInteger + cmNoCheckEntryOffset.
>         pc := cPIC asInteger + firstCPICCaseOffset.
> +       "Since this is a fast test doing simple compares we don't need to
> care that some
> +       cases have nonsense addresses in there. Just zip on through"
>         1 to: cPIC cPICNumCases do:
>                 [:i|
> +               target = (backEnd jumpLongTargetBeforeFollowingAddress:
> pc) ifTrue:
> -               target = (literalsManager cPICCase: i jumpTargetBefore:
> pc) ifTrue:
>                         [^true].
>                 pc := pc + cPICCaseSize].
>         ^false!
>
> Item was changed:
>   ----- Method: Cogit>>cPICHasForwardedClass: (in category 'in-line
> cacheing') -----
> + cPICHasForwardedClass: cPIC
> +       "The first case in a CPIC doesn't have a class reference so we
> need only step over actually usd subsequent cases."
> - cPICHasForwardedClass: cPIC
> -       <var: #cPIC type: #'CogMethod *'>
>         | pc |
> +       <var: #cPIC type: #'CogMethod *'>
> +       "start by finding the address of the topmost case, the
> cPICNumCases'th one"
> +       pc := (self addressOfEndOfCase: cPIC cPICNumCases inCPIC: cPIC)
> +                               - backEnd jumpLongConditionalByteSize.
> +       2 to: cPIC cPICNumCases do:
> +                       [:i |  | classIndex |
> +                       classIndex := literalsManager
> classRefInClosedPICAt: pc.
> +                       (objectMemory isForwardedClassIndex: classIndex)
> +                               ifTrue: [^ true].
> +                       "since we started at the top, we can just add the
> case size each time to move on to the next case"
> +                       pc := pc + cPICCaseSize].
> +       ^ false!
> -       pc := cPIC asUnsignedInteger
> -               + firstCPICCaseOffset
> -               + cPICCaseSize
> -               - backEnd jumpLongConditionalByteSize.
> -       2 to: cPIC cPICNumCases do:
> -               [:i| | classIndex |
> -               classIndex := literalsManager classRefInClosedPICAt: pc.
> -               (objectMemory isForwardedClassIndex: classIndex) ifTrue:
> -                       [^true].
> -               pc := pc + cPICCaseSize].
> -       ^false!
>
> Item was changed:
>   ----- Method: Cogit>>cPICHasFreedTargets: (in category 'in-line
> cacheing') -----
>   cPICHasFreedTargets: cPIC
> +       "scan the CPIC for target methods that have been freed. "
>         <var: #cPIC type: #'CogMethod *'>
>         | pc entryPoint targetMethod |
>         <var: #targetMethod type: #'CogMethod *'>
> +
> -       pc := cPIC asInteger + firstCPICCaseOffset.
>         1 to: cPIC cPICNumCases do:
>                 [:i|
> +               pc := self addressOfEndOfCase: i inCPIC: cPIC.
> +               entryPoint := backEnd
> jumpLongTargetBeforeFollowingAddress: pc.
> -               entryPoint := literalsManager cPICCase: i
> jumpTargetBefore: pc.
>                 "Find target from jump.  Ignore jumps to the interpret and
> MNU calls within this PIC"
>                 (cPIC containsAddress: entryPoint) ifFalse:
>                         [targetMethod := self cCoerceSimple: entryPoint -
> cmNoCheckEntryOffset to: #'CogMethod *'.
>                          self assert: (targetMethod cmType = CMMethod or:
> [targetMethod cmType = CMFree]).
>                          targetMethod cmType = CMFree ifTrue:
> +                               [^true]]].
> -                               [^true]].
> -               pc := pc + cPICCaseSize].
>         ^false!
>
> Item was changed:
>   ----- Method: Cogit>>ceCPICMiss:receiver: (in category 'in-line
> cacheing') -----
>   ceCPICMiss: cPIC receiver: receiver
>         "Code entry closed PIC miss.  A send has fallen
>          through a closed (finite) polymorphic inline cache.
>          Either extend it or patch the send site to an open PIC.
>          The stack looks like:
>                         receiver
>                         args
>           sp=>  sender return address"
>         <var: #cPIC type: #'CogMethod *'>
>         <api>
>         | outerReturn newTargetMethodOrNil errorSelectorOrNil cacheTag
> result |
>         self cCode: ''
>                 inSmalltalk:
>                         [cPIC isInteger ifTrue:
>                                 [^self ceCPICMiss: (self
> cogMethodSurrogateAt: cPIC) receiver: receiver]].
>         (objectMemory isOopForwarded: receiver) ifTrue:
>                 [^coInterpreter ceSendFromInLineCacheMiss: cPIC].
>         outerReturn := coInterpreter stackTop.
>         self deny: (backEnd inlineCacheTagAt: outerReturn) = self
> picAbortDiscriminatorValue.
> +       cPIC cPICNumCases < maxCPICCases
> -       cPIC cPICNumCases < numPICCases
>                 ifTrue:
>                         [self lookup: cPIC selector
>                                 for: receiver
>                                 methodAndErrorSelectorInto:
>                                         [:method :errsel|
>                                         newTargetMethodOrNil := method.
>                                         errorSelectorOrNil := errsel]]
>                 ifFalse: [newTargetMethodOrNil := errorSelectorOrNil :=
> nil].
>         "We assume lookupAndCog:for: will *not* reclaim the method zone"
>         self assert: outerReturn = coInterpreter stackTop.
>         cacheTag := objectRepresentation inlineCacheTagForInstance:
> receiver.
> +       (cPIC cPICNumCases >= maxCPICCases
> -       (cPIC cPICNumCases >= numPICCases
>          or: [(errorSelectorOrNil notNil and: [errorSelectorOrNil ~=
> SelectorDoesNotUnderstand])
>          or: [(objectRepresentation inlineCacheTagIsYoung: cacheTag)
>          or: [newTargetMethodOrNil isNil
>          or: [objectMemory isYoung: newTargetMethodOrNil]]]]) ifTrue:
>                 [result := self patchToOpenPICFor: cPIC selector
>                                         numArgs: cPIC cmNumArgs
>                                         receiver: receiver.
>                  self assert: result not. "If patchToOpenPICFor:.. returns
> we're out of code memory"
>                  ^coInterpreter ceSendFromInLineCacheMiss: cPIC].
>         "Now extend the PIC with the new case."
>         self cogExtendPIC: cPIC
>                 CaseNMethod: newTargetMethodOrNil
>                 tag: cacheTag
>                 isMNUCase: errorSelectorOrNil = SelectorDoesNotUnderstand.
>         "Jump back into the pic at its entry in case this is an MNU."
>         coInterpreter
>                 executeCogPIC: cPIC
>                 fromLinkedSendWithReceiver: receiver
>                 andCacheTag: (backEnd inlineCacheTagAt: outerReturn).
>         "NOTREACHED"
>         ^nil!
>
> Item was changed:
>   ----- Method: Cogit>>checkValidObjectReferencesInClosedPIC: (in category
> 'garbage collection') -----
>   checkValidObjectReferencesInClosedPIC: cPIC
>         <var: #cPIC type: #'CogMethod *'>
>         | ok pc |
>         ok := true.
>         pc := cPIC asInteger + firstCPICCaseOffset.
> +
> +       "first we check the obj ref at the beginning of the CPIC"
>         (self checkMaybeObjRefInClosedPIC: (literalsManager
> objRefInClosedPICAt: pc - backEnd jumpLongByteSize)) ifFalse:
>                 [self print: 'object leak in CPIC '; printHex: cPIC
> asInteger;
>                         print: ' @ '; printHex: pc - backEnd
> jumpLongByteSize; cr.
>                  ok := false].
> +
> +       "Next we step over each case that is in use. We find the end
> address of the cPICNumCases'th case and can then just step forward by the
> case size thereafter"
> +       pc := self addressOfEndOfCase: cPIC cPICNumCases inCPIC: cPIC.
> +
> +       "For each case we check any object reference at the end address -
> sizeof(conditional instruction) and then increment the end address by case
> size"
> -       pc := pc + cPICCaseSize.
>         2 to: cPIC cPICNumCases do:
>                 [:i|
>                 objectRepresentation inlineCacheTagsMayBeObjects ifTrue:
>                         [(self checkMaybeObjRefInClosedPIC:
> (literalsManager classRefInClosedPICAt: pc - backEnd
> jumpLongConditionalByteSize)) ifFalse:
>                                 [self print: 'object leak in CPIC ';
> printHex: cPIC asInteger;
>                                         print: ' @ '; printHex: pc -
> backEnd jumpLongConditionalByteSize - backEnd loadLiteralByteSize; cr.
>                                  ok := false]].
>                 (self checkMaybeObjRefInClosedPIC: (literalsManager
> objRefInClosedPICAt: pc - backEnd jumpLongConditionalByteSize)) ifFalse:
>                         [self print: 'object leak in CPIC '; printHex:
> cPIC asInteger;
>                                 print: ' @ '; printHex: pc - backEnd
> jumpLongConditionalByteSize; cr.
>                          ok := false].
>                 pc := pc + cPICCaseSize].
>         ^ok!
>
> Item was changed:
>   ----- Method: Cogit>>closedPICRefersToUnmarkedObject: (in category
> 'garbage collection') -----
>   closedPICRefersToUnmarkedObject: cPIC
>         "Answer if the ClosedPIC refers to any unmarked objects or
> freed/freeable target methods,
>          applying markAndTraceOrFreeCogMethod:firstVisit: to those targets
> to determine if freed/freeable."
>         <var: #cPIC type: #'CogMethod *'>
>         | pc offsetToLiteral object entryPoint targetMethod |
>         <var: #targetMethod type: #'CogMethod *'>
>         (objectMemory isImmediate: cPIC selector) ifFalse:
>                 [(objectMemory isMarked: cPIC selector) ifFalse:
>                         [^true]].
> -       pc := cPIC asInteger + firstCPICCaseOffset.
>         "First jump is unconditional; subsequent ones are conditional"
>         offsetToLiteral := backEnd jumpLongByteSize.
>         1 to: cPIC cPICNumCases do:
> +               [:i|
> +               pc := self addressOfEndOfCase: i inCPIC: cPIC.
> +               (objectRepresentation inlineCacheTagsMayBeObjects and:
> [i>1] ) "inline cache tags for the 0th case are at the send site" ifTrue:
> -               [:i|
> -               objectRepresentation inlineCacheTagsMayBeObjects ifTrue:
>                         [object := literalsManager classRefInClosedPICAt:
> pc - offsetToLiteral.
>                          ((objectRepresentation couldBeObject: object)
>                           and: [(objectMemory isMarked: object) not])
> ifTrue:
>                                 [^true]].
>                 object := literalsManager objRefInClosedPICAt: pc -
> offsetToLiteral.
>                 ((objectRepresentation couldBeObject: object)
>                  and: [(objectMemory isMarked: object) not]) ifTrue:
>                         [^true].
>                 offsetToLiteral := backEnd jumpLongConditionalByteSize.
> +               entryPoint := backEnd
> jumpLongTargetBeforeFollowingAddress: pc.
> -               entryPoint := literalsManager cPICCase: i
> jumpTargetBefore: pc.
>                 "Find target from jump.  Ignore jumps to the interpret and
> MNU calls within this PIC"
>                 self assert: (entryPoint > methodZoneBase and: [entryPoint
> < methodZone freeStart]).
>                 (cPIC containsAddress: entryPoint) ifFalse:
>                         [targetMethod := self cCoerceSimple: entryPoint -
> cmNoCheckEntryOffset to: #'CogMethod *'.
>                          self assert: (targetMethod cmType = CMMethod
>                                                 or: [targetMethod cmType =
> CMFree]).
>                          (self markAndTraceOrFreeCogMethod: targetMethod
>                                   firstVisit: targetMethod
> asUnsignedInteger > pc asUnsignedInteger) ifTrue:
>                                 [^true]].
> +               ].
> -               pc := pc + cPICCaseSize].
>         ^false!
>
> Item was changed:
>   ----- Method: Cogit>>codeRangesFor: (in category 'disassembly') -----
>   codeRangesFor: cogMethod
>         "Answer a sequence of ranges of code for the main method and all
> of the blocks in a CogMethod.
>          N.B.  These are in order of block dispatch, _not_ necessarily
> address order in the method."
>         <doNotGenerate>
>         | pc end blockEntry starts |
>         cogMethod cmType = CMClosedPIC ifTrue:
> +               [end := cogMethod asInteger + cPICEndOfCodeOffset -
> backEnd jumpLongByteSize.
> -               [end := (self addressOfEndOfCase: cogMethod cPICNumCases -
> 1 inCPIC: cogMethod) + cPICEndSize.
>                  ^{ CogCodeRange
>                                 from: cogMethod asInteger + (self sizeof:
> CogMethod)
>                                 to: end
>                                 cogMethod: cogMethod
>                                 startpc: nil }].
>         end := (self mapEndFor: cogMethod) - 1.
>         cogMethod blockEntryOffset = 0 ifTrue:
>                 [^{ CogCodeRange
>                                 from: cogMethod asInteger + (self sizeof:
> CogMethod)
>                                 to: end
>                                 cogMethod: cogMethod
>                                 startpc: (cogMethod cmType ~= CMOpenPIC
> ifTrue:
>                                                         [coInterpreter
> startPCOfMethodHeader: cogMethod methodHeader]) }].
>         pc := blockEntry := cogMethod blockEntryOffset + cogMethod
> asInteger.
>         starts := OrderedCollection with: cogMethod.
>         [pc < end] whileTrue:
>                 [| targetpc |
>                  targetpc := blockEntry.
>                  (backEnd isJumpAt: pc) ifTrue:
>                         [targetpc := backEnd jumpTargetPCAt: pc.
>                          targetpc < blockEntry ifTrue:
>                                 [starts add: (self cCoerceSimple: targetpc
> - (self sizeof: CogBlockMethod) to: #'CogBlockMethod *')]].
>                  pc := pc + (backEnd instructionSizeAt: pc)].
>         starts := starts asSortedCollection.
>         ^(1 to: starts size + 1) collect:
>                 [:i| | cogSubMethod nextpc |
>                 i <= starts size
>                         ifTrue:
>                                 [cogSubMethod := starts at: i.
>                                  nextpc := i < starts size ifTrue:
> [(starts at: i + 1) address] ifFalse: [blockEntry].
>                                  CogCodeRange
>                                         from: cogSubMethod address + (self
> sizeof: cogSubMethod)
>                                         to: nextpc - 1
>                                         cogMethod: cogSubMethod
>                                         startpc: (i = 1
>                                                                 ifTrue:
> [coInterpreter startPCOfMethodHeader: cogMethod methodHeader]
>                                                                 ifFalse:
> [cogSubMethod startpc])]
>                         ifFalse:
>                                 [CogCodeRange
>                                         from: blockEntry
>                                         to: end]]!
>
> Item was changed:
>   ----- Method: Cogit>>cogExtendPIC:CaseNMethod:tag:isMNUCase: (in
> category 'in-line cacheing') -----
>   cogExtendPIC: cPIC CaseNMethod: caseNMethod tag: caseNTag isMNUCase:
> isMNUCase
>         "Extend the cPIC with the supplied case.  If caseNMethod is cogged
> dispatch direct to
>          its unchecked entry-point.  If caseNMethod is not cogged, jump to
> the fast interpreter
>          dispatch, and if isMNUCase then dispatch to fast MNU invocation
> and mark the cPIC as
>          having the MNU case for cache flushing."
>         <var: #cPIC type: #'CogMethod *'>
> +       | operand target address |
> +
> -       | operand target address size end |
> -       "stack allocate the various collections so that they
> -        are effectively garbage collected on return."
>         coInterpreter
>                 compilationBreak: cPIC selector
>                 point: (objectMemory numBytesOf: cPIC selector)
>                 isMNUCase: isMNUCase.
> +
> -       self allocateOpcodes: 8 bytecodes: 0.
> -       methodLabel address: cPIC asUnsignedInteger; dependent: nil. "for
> pc-relative MoveCw: cPIC R: ClassReg"
>         self assert: (objectRepresentation inlineCacheTagIsYoung:
> caseNTag) not.
>         "Caller patches to open pic if caseNMethod is young."
>         self assert: (caseNMethod notNil and: [(objectMemory isYoung:
> caseNMethod) not]).
> +       (isMNUCase not and: [coInterpreter methodHasCogMethod:
> caseNMethod])
> +               ifTrue: "this isn't an mNU and we have an already cogged
> method to jump to"
> -       (isMNUCase not
> -        and: [coInterpreter methodHasCogMethod: caseNMethod])
> -               ifTrue:
>                         [operand := 0.
>                          target := (coInterpreter cogMethodOf:
> caseNMethod) asInteger + cmNoCheckEntryOffset]
> +               ifFalse:
> -               ifFalse:
>                         [operand := caseNMethod.
>                          isMNUCase
> +                               ifTrue: "this is an mNU so tag the CPIC
> header and setup a jump to the mNUAbort"
> -                               ifTrue:
>                                         [cPIC cpicHasMNUCase: true.
>                                          target := cPIC asInteger + (self
> sizeof: CogMethod)]
> +                               ifFalse: "setup a jump to the
> interpretAborth so we can cog the target method"
> -                               ifFalse:
>                                         [target := cPIC asInteger + self
> picInterpretAbortOffset]].
> +
> +       "find the end address of the new case"
> +       address := self addressOfEndOfCase: cPIC cPICNumCases +1 inCPIC:
> cPIC.
> +
> +       backEnd rewriteCPICCaseAt: address tag: caseNTag objRef: operand
> target: target.
> +
> +       "finally, rewrite the jump 3 instr  before firstCPICCaseOffset to
> jump to the beginning of this new case"
> +       self rewriteCPIC: cPIC caseJumpTo: address - cPICCaseSize.
> +
> -       self CmpCw: caseNTag R: TempReg.
> -       self MoveUniqueCw: operand R: SendNumArgsReg.
> -       self DumpJumpLongZero: target.
> -       self MoveCw: cPIC asUnsignedInteger R: ClassReg.
> -       self JumpLong: (self cPICMissTrampolineFor: cPIC cmNumArgs).
> -       self computeMaximumSizes.
> -       address := self addressOfEndOfCase: cPIC cPICNumCases - 1 inCPIC:
> cPIC.
> -       size := self generateInstructionsAt: address.
> -       end := self outputInstructionsAt: address.
>         processor flushICacheFrom: cPIC asUnsignedInteger to: cPIC
> asUnsignedInteger + closedPICSize.
> +       "update the header flag for the number of cases"
>         cPIC cPICNumCases: cPIC cPICNumCases + 1.
>         ^0!
>
> Item was changed:
>   ----- Method: Cogit>>cogMNUPICSelector:receiver:methodOperand:numArgs:
> (in category 'in-line cacheing') -----
>   cogMNUPICSelector: selector receiver: rcvr methodOperand: methodOperand
> numArgs: numArgs
>         <api>
>         "Attempt to create a one-case PIC for an MNU.
>          The tag for the case is at the send site and so doesn't need to
> be generated."
>         <returnTypeC: #'CogMethod *'>
> +       | startAddress |
> -       | startAddress size end |
>         ((objectMemory isYoung: selector)
>          or: [(objectRepresentation inlineCacheTagForInstance: rcvr) =
> self picAbortDiscriminatorValue]) ifTrue:
>                 [^0].
>         coInterpreter
>                 compilationBreak: selector
>                 point: (objectMemory numBytesOf: selector)
>                 isMNUCase: true.
>         self assert: endCPICCase0 notNil.
> +       "get memory in the code zone for the CPIC; if that fails we return
> an error code for the sender to use to work out how to blow up"
>         startAddress := methodZone allocate: closedPICSize.
>         startAddress = 0 ifTrue:
>                 [coInterpreter callForCogCompiledCodeCompaction.
>                  ^0].
> +
> +       "memcpy the prototype across to our allocated space; because
> anything else would be silly"
> +       objectMemory mem: startAddress cp: cPICPrototype y: closedPICSize.
> +
> +       self configureMNUCPIC: (self cCoerceSimple: startAddress to:
> #'CogMethod *')
> -       "stack allocate the various collections so that they
> -        are effectively garbage collected on return."
> -       self allocateOpcodes: numPICCases * 9 bytecodes: 0.
> -       methodLabel address: startAddress; dependent: nil. "for
> pc-relative MoveCw: cPIC R: ClassReg"
> -       self compileMNUCPIC: (self cCoerceSimple: startAddress to:
> #'CogMethod *')
>                 methodOperand: methodOperand
> +               numArgs: numArgs
> +               delta: startAddress - cPICPrototype.
> +
> -               numArgs: numArgs.
> -       self computeMaximumSizes.
> -       size := self generateInstructionsAt: startAddress + (self sizeof:
> CogMethod).
> -       end := self outputInstructionsAt: startAddress + (self sizeof:
> CogMethod).
> -       "The missOffset is the same as the interpretOffset. On RISCs it
> includes an additional instruction."
> -       self assert: missOffset = ((backEnd hasLinkRegister ifTrue:
> [backEnd callInstructionByteSize] ifFalse: [0])
> -                                                               +
> picInterpretAbort address + picInterpretAbort machineCodeSize -
> startAddress).
> -       self assert: startAddress + cmEntryOffset = entry address.
>         ^self
>                 fillInCPICHeader: (self cCoerceSimple: startAddress to:
> #'CogMethod *')
>                 numArgs: numArgs
>                 numCases: 1
>                 hasMNUCase: true
>                 selector: selector !
>
> Item was changed:
>   ----- Method: Cogit>>cogMethodDoesntLookKosher: (in category
> 'debugging') -----
>   cogMethodDoesntLookKosher: cogMethod
>         "Check that the header fields onf a non-free method are consistent
> with
>          the type. Answer 0 if it is ok, otherwise answer a code for the
> error."
>         <api>
>         <inline: false>
>         <var: #cogMethod type: #'CogMethod *'>
>         ((cogMethod blockSize bitAnd: objectMemory wordSize - 1) ~= 0
>          or: [cogMethod blockSize < (self sizeof: CogMethod)
>          or: [cogMethod blockSize >= 32768]]) ifTrue:
>                 [^1].
>
>         cogMethod cmType = CMFree ifTrue: [^2].
>
>         cogMethod cmType = CMMethod ifTrue:
>                 [(objectMemory isIntegerObject: cogMethod methodHeader)
> ifFalse:
>                         [^11].
>                  (objectRepresentation couldBeObject: cogMethod
> methodObject) ifFalse:
>                         [^12].
>                  (cogMethod stackCheckOffset > 0
>                  and: [cogMethod stackCheckOffset < cmNoCheckEntryOffset])
> ifTrue:
>                         [^13].
>                  ^0].
>
>         cogMethod cmType = CMOpenPIC ifTrue:
>                 [cogMethod blockSize ~= openPICSize ifTrue:
>                         [^21].
>                  cogMethod methodHeader ~= 0 ifTrue:
>                         [^22].
>
>                  "Check the nextOpenPIC link unless we're compacting"
>                  cogMethod objectHeader >= 0 ifTrue:
>                         [(cogMethod methodObject ~= 0
>                          and: [cogMethod methodObject < methodZoneBase
>                                    or: [cogMethod methodObject >
> (methodZone freeStart - openPICSize)
>                                    or: [(cogMethod methodObject bitAnd:
> objectMemory wordSize - 1) ~= 0
>                                    or: [(self cCoerceSimple: cogMethod
> methodObject
>                                                         to: #'CogMethod
> *') cmType ~= CMOpenPIC]]]]) ifTrue:
>                                 [^23]].
>                  cogMethod stackCheckOffset ~= 0 ifTrue:
>                         [^24].
>                  ^0].
>
>         cogMethod cmType = CMClosedPIC ifTrue:
>                 [cogMethod blockSize ~= closedPICSize ifTrue:
>                         [^31].
> +                (cogMethod cPICNumCases between: 1 and: maxCPICCases)
> ifFalse:
> -                (cogMethod cPICNumCases between: 1 and: numPICCases)
> ifFalse:
>                         [^32].
>                  cogMethod methodHeader ~= 0 ifTrue:
>                         [^33].
>                  cogMethod methodObject ~= 0 ifTrue:
>                         [^34].
>                  ^0].
>
>         ^9!
>
> Item was changed:
>   ----- Method:
> Cogit>>cogPICSelector:numArgs:Case0Method:Case1Method:tag:isMNUCase: (in
> category 'in-line cacheing') -----
>   cogPICSelector: selector numArgs: numArgs Case0Method: case0CogMethod
> Case1Method: case1MethodOrNil tag: case1Tag isMNUCase: isMNUCase
>         "Attempt to create a two-case PIC for case0CogMethod and
> case1Method,case1Tag.
>          The tag for case0CogMethod is at the send site and so doesn't
> need to be generated.
>          case1Method may be any of
>                 - a Cog method; link to its unchecked entry-point
>                 - a CompiledMethod; link to ceInterpretMethodFromPIC:
>                 - a CompiledMethod; link to
> ceMNUFromPICMNUMethod:receiver:"
>         <var: #case0CogMethod type: #'CogMethod *'>
>         <returnTypeC: #'CogMethod *'>
> +       | startAddress |
> -       | startAddress size end |
>         (objectMemory isYoung: selector) ifTrue:
>                 [^self cCoerceSimple: YoungSelectorInPIC to: #'CogMethod
> *'].
>         coInterpreter
>                 compilationBreak: selector
>                 point: (objectMemory numBytesOf: selector)
>                 isMNUCase: isMNUCase.
> +
> +       "get memory in the code zone for the CPIC; if that fails we return
> an error code for the sender to use to work out how to blow up"
>         startAddress := methodZone allocate: closedPICSize.
>         startAddress = 0 ifTrue:
>                 [^self cCoerceSimple: InsufficientCodeSpace to:
> #'CogMethod *'].
> +
> +       "memcpy the prototype across to our allocated space; because
> anything else would be silly"
> +       objectMemory mem: startAddress cp: cPICPrototype y: closedPICSize.
> +
> +       self configureCPIC: (self cCoerceSimple: startAddress to:
> #'CogMethod *')
> -       "stack allocate the various collections so that they
> -        are effectively garbage collected on return."
> -       self allocateOpcodes: numPICCases * 9 bytecodes: 0.
> -       methodLabel address: startAddress; dependent: nil. "for
> pc-relative MoveCw: cPIC R: ClassReg"
> -       self compileCPIC: (self cCoerceSimple: startAddress to:
> #'CogMethod *')
>                 Case0: case0CogMethod
>                 Case1Method: case1MethodOrNil
>                 tag: case1Tag
>                 isMNUCase: isMNUCase
> +               numArgs: numArgs
> +               delta: startAddress - cPICPrototype .
> +
> -               numArgs: numArgs.
> -       self computeMaximumSizes.
> -       size := self generateInstructionsAt: startAddress + (self sizeof:
> CogMethod).
> -       end := self outputInstructionsAt: startAddress + (self sizeof:
> CogMethod).
> -       "The missOffset is the same as the interpretOffset. On RISCs it
> includes an additional instruction."
> -       self assert: missOffset = ((backEnd hasLinkRegister ifTrue:
> [backEnd callInstructionByteSize] ifFalse: [0])
> -                                                               +
> picInterpretAbort address + picInterpretAbort machineCodeSize -
> startAddress).
> -       self assert: startAddress + cmEntryOffset = entry address.
> -       self assert: endCPICCase0 address = (startAddress +
> firstCPICCaseOffset).
> -       self assert: endCPICCase1 address = (startAddress +
> firstCPICCaseOffset + cPICCaseSize).
>         ^self
>                 fillInCPICHeader: (self cCoerceSimple: startAddress to:
> #'CogMethod *')
>                 numArgs: numArgs
>                 numCases: 2
>                 hasMNUCase: isMNUCase
>                 selector: selector !
>
> Item was removed:
> - ----- Method:
> Cogit>>compileCPIC:Case0:Case1Method:tag:isMNUCase:numArgs: (in category
> 'in-line cacheing') -----
> - compileCPIC: cPIC Case0: case0CogMethod Case1Method: case1Method tag:
> case1Tag isMNUCase: isMNUCase numArgs: numArgs
> -       "Compile the code for a two-case PIC for case0CogMethod and
> case1Method,case1Tag.
> -        The tag for case0CogMethod is at the send site and so doesn't
> need to be generated.
> -        case1Method may be any of
> -               - a Cog method; jump to its unchecked entry-point
> -               - a CompiledMethod; jump to the ceInterpretFromPIC
> trampoline
> -               - nil; call ceMNUFromPIC"
> -       <var: #cPIC type: #'CogMethod *'>
> -       | operand targetEntry jumpNext |
> -       <var: #case0CogMethod type: #'CogMethod *'>
> -       <var: #targetEntry type: #'void *'>
> -       <var: #jumpNext type: #'AbstractInstruction *'>
> -       self assert: case1Method notNil.
> -       self compilePICAbort: numArgs.
> -       self assert: (objectRepresentation inlineCacheTagIsYoung:
> case1Tag) not.
> -       (isMNUCase not
> -        and: [coInterpreter methodHasCogMethod: case1Method])
> -               ifTrue:
> -                       [operand := 0.
> -                        targetEntry := ((coInterpreter cogMethodOf:
> case1Method) asInteger + cmNoCheckEntryOffset) asVoidPointer]
> -               ifFalse: "We do not scavenge PICs, hence we cannot cache
> the MNU method if it is in new space."
> -                       [operand := (case1Method isNil or: [objectMemory
> isYoungObject: case1Method])
> -                                                       ifTrue: [0]
> -                                                       ifFalse:
> [case1Method].
> -                        targetEntry := case1Method isNil ifTrue:
> [picMNUAbort] ifFalse: [picInterpretAbort]].
> -
> -       jumpNext := self compileCPICEntry.
> -       self MoveUniqueCw: 0 R: SendNumArgsReg.
> -       self DumpJumpLong: case0CogMethod asInteger + cmNoCheckEntryOffset.
> -       endCPICCase0 := self CmpCw: case1Tag R: TempReg.
> -       jumpNext jmpTarget: endCPICCase0.
> -       self MoveUniqueCw: operand R: SendNumArgsReg.
> -       self DumpJumpLongZero: (isMNUCase ifTrue: [picMNUAbort] ifFalse:
> [targetEntry]) asInteger.
> -       endCPICCase1 := self MoveCw: cPIC asUnsignedInteger R: ClassReg.
> -       self JumpLong: (self cPICMissTrampolineFor: numArgs).
> -       ^0
> - !
>
> Item was changed:
>   ----- Method: Cogit>>compileClosedPICPrototype (in category 'in-line
> cacheing') -----
>   compileClosedPICPrototype
>         "Compile the abstract instructions for a full closed PIC used to
> initialize closedPICSize.
>          The loads into SendNumArgsReg are those for optional method
> objects which may be
>          used in MNU cases."
>         <inline: true>
>         | numArgs jumpNext |
>         <var: #jumpNext type: #'AbstractInstruction *'>
>         numArgs := 0.
>         self compilePICAbort: numArgs.
> +       jumpNext := self compileCPICEntry. "at the end of the entry code
> we need to jump to the first case code, which is actually the last chunk -
> for each entension we must update this jump to move back one case"
> -       jumpNext := self compileCPICEntry.
>         self MoveUniqueCw: 16r5EAF00D R: SendNumArgsReg.
> +       self JumpLong: self cPICPrototypeCaseOffset + 16rCA5E10.
> +       endCPICCase0 := self Label.
> +       1 to: maxCPICCases - 1 do:
> -       self DumpJumpLong: self cPICPrototypeCaseOffset + 16rCA5E10.
> -       jumpNext jmpTarget: (endCPICCase0 := self Label).
> -       1 to: numPICCases - 1 do:
>                 [:h|
> +               h = (maxCPICCases - 1)
> +                               ifTrue: [jumpNext jmpTarget: self Label].
> "this is where we jump to for the first case"
>                 self CmpCw: 16rBABE1F15+h R: TempReg.
>                 self MoveUniqueCw: 16rBADA550 + h R: SendNumArgsReg.
> +               self JumpLongZero: self cPICPrototypeCaseOffset +
> 16rCA5E10 + (h * 16).
> +               h =  1 ifTrue:
> -               self DumpJumpLongZero: self cPICPrototypeCaseOffset +
> 16rCA5E10 + (h * 16).
> -               h = 1 ifTrue:
>                         [endCPICCase1 := self Label]].
>         self MoveCw: methodLabel address R: ClassReg.
>         self JumpLong: (self cPICMissTrampolineFor: numArgs).
> +       cPICEndOfCodeLabel := self Label.
> +       literalsManager dumpLiterals: false.
>         ^0!
>
> Item was removed:
> - ----- Method: Cogit>>compileMNUCPIC:methodOperand:numArgs: (in category
> 'in-line cacheing') -----
> - compileMNUCPIC: cPIC methodOperand: methodOperand numArgs: numArgs
> -       "Compile the code for a one-case MNU PIC that calls ceMNUFromPIC
> for case0Tag
> -        The tag for case0 is at the send site and so doesn't need to be
> generated."
> -       <var: #cPIC type: #'CogMethod *'>
> -       | jumpNext operand |
> -       <var: #jumpNext type: #'AbstractInstruction *'>
> -       self compilePICAbort: numArgs.
> -       jumpNext := self compileCPICEntry.
> -       "We do not scavenge PICs, hence we cannot cache the MNU method if
> it is in new space."
> -       operand := (methodOperand isNil or: [objectMemory isYoungObject:
> methodOperand])
> -                                       ifTrue: [0]
> -                                       ifFalse: [methodOperand].
> -       self MoveUniqueCw: operand R: SendNumArgsReg.
> -       self DumpJumpLong: picMNUAbort asInteger.
> -       jumpNext jmpTarget: (self MoveCw: cPIC asUnsignedInteger R:
> ClassReg).
> -       self JumpLong: (self cPICMissTrampolineFor: numArgs).
> -       ^0
> - !
>
> Item was added:
> + ----- Method:
> Cogit>>configureCPIC:Case0:Case1Method:tag:isMNUCase:numArgs:delta: (in
> category 'in-line cacheing') -----
> + configureCPIC: cPIC Case0: case0CogMethod Case1Method: case1Method tag:
> case1Tag isMNUCase: isMNUCase numArgs: numArgs delta: addrDelta
> +       "Configure a copy of the prototype CPIC for a two-case PIC for
> +       case0CogMethod and
> +       case1Method
> +       case1Tag.
> +        The tag for case0CogMethod is at the send site and so doesn't
> need to be generated.
> +        case1Method may be any of
> +               - a Cog method; jump to its unchecked entry-point
> +               - a CompiledMethod; jump to the ceInterpretFromPIC
> trampoline
> +               - nil; call ceMNUFromPIC
> +       addDelta is the address change from the prototype to the new CPCI
> location, needed
> +       because the loading of the CPIC lable at the end may use a literal
> instead of a pc relative"
> +       <var: #cPIC type: #'CogMethod *'>
> +       | operand targetEntry caseEndAddress|
> +       <var: #case0CogMethod type: #'CogMethod *'>
> +       <var: #targetEntry type: #'void *'>
> +       <var: #jumpNext type: #'AbstractInstruction *'>
> +       self assert: case1Method notNil.
> +
> +       "adjust the jump at missOffset, the ceAbortXArgs"
> +       backEnd rewriteJumpLongAt: cPIC asInteger + missOffset target:
> (self picAbortTrampolineFor: numArgs).
> +
> +       self assert: (objectRepresentation inlineCacheTagIsYoung:
> case1Tag) not.
> +       (isMNUCase not
> +        and: [coInterpreter methodHasCogMethod: case1Method])
> +               ifTrue:
> +                       [operand := 0.
> +                        targetEntry := ((coInterpreter cogMethodOf:
> case1Method) asInteger + cmNoCheckEntryOffset) asVoidPointer]
> +               ifFalse: "We do not scavenge PICs, hence we cannot cache
> the MNU method if it is in new space."
> +                       [operand := (case1Method isNil or: [objectMemory
> isYoungObject: case1Method])
> +                                                       ifTrue: [0]
> +                                                       ifFalse:
> [case1Method].
> +                        targetEntry := case1Method isNil ifTrue: [cPIC
> asInteger + (self sizeof: CogMethod)] ifFalse: [cPIC asInteger + self
> picInterpretAbortOffset]].
> +
> +       "set the jump to the case0 method"
> +       backEnd rewriteJumpLongAt: cPIC asInteger + firstCPICCaseOffset
> target: case0CogMethod asInteger + cmNoCheckEntryOffset.
> +
> +       caseEndAddress := self addressOfEndOfCase: 2 inCPIC: cPIC.
> +
> +       "update the cpic case - deferred to backend because messy"
> +       backEnd rewriteCPICCaseAt: caseEndAddress tag: case1Tag objRef:
> operand target: (isMNUCase ifTrue: [cPIC asInteger + (self sizeof:
> CogMethod)] ifFalse: [targetEntry]) asInteger.
> +
> +       "update the loading of the PCIC label address"
> +       backEnd relocateMethodReferenceBeforeAddress: cPIC asInteger +
> cPICEndOfCodeOffset - backEnd jumpLongByteSize by: addrDelta.
> +
> +       "write the final desperate jump to cePICMissXArgs"
> +       backEnd rewriteJumpLongAt: cPIC asInteger + cPICEndOfCodeOffset
> target: (self cPICMissTrampolineFor: numArgs).
> +       ^0
> +       "self disassembleFrom: cPIC + (self sizeof: CogMethod) to: cPIC +
> closedPICSize - 1."!
>
> Item was added:
> + ----- Method: Cogit>>configureMNUCPIC:methodOperand:numArgs:delta: (in
> category 'in-line cacheing') -----
> + configureMNUCPIC: cPIC methodOperand: methodOperand numArgs: numArgs
> delta: addrDelta
> +       "Configure a copy of the prototype CPIC for a one-case MNU PIC
> that calls ceMNUFromPIC for case0Tag
> +        The tag for case0 is at the send site and so doesn't need to be
> generated.
> +       addDelta is the address change from the prototype to the new CPCI
> location, needed
> +       because the loading of the CPIC label at the end may use a literal
> instead of a pc relative"
> +       <var: #cPIC type: #'CogMethod *'>
> +       | operand |
> +       <var: #jumpNext type: #'AbstractInstruction *'>
> +
> +       "adjust the jump at missOffset, the ceAbortXArgs"
> +       backEnd rewriteJumpLongAt: cPIC asInteger + missOffset target:
> (self picAbortTrampolineFor: numArgs).
> +
> +       "We do not scavenge PICs, hence we cannot cache the MNU method if
> it is in new space."
> +       operand := (methodOperand isNil or: [objectMemory isYoungObject:
> methodOperand])
> +                                       ifTrue: [0]
> +                                       ifFalse: [methodOperand].
> +       "set the jump to the case0 method"
> +       backEnd rewriteJumpLongAt: cPIC asInteger + firstCPICCaseOffset
> target: cPIC asInteger + (self sizeof: CogMethod) .
> +
> +       backEnd storeLiteral: operand beforeFollowingAddress: cPIC
> asInteger + firstCPICCaseOffset - backEnd jumpLongByteSize.
> +
> +       "rewrite the final desperate jump to cePICMissXArgs"
> +       backEnd rewriteJumpLongAt: cPIC asInteger + cPICEndOfCodeOffset
> target: (self cPICMissTrampolineFor: numArgs).
> +
> +       "update the loading of the PCIC label address"
> +       backEnd relocateMethodReferenceBeforeAddress: cPIC asInteger +
> cPICEndOfCodeOffset - backEnd jumpLongByteSize by: addrDelta.
> +
> +       "finally, rewrite the jump 3 instr  before firstCPICCaseOffset to
> jump to the end of case 2, missing the actual case"
> +       self rewriteCPIC: cPIC caseJumpTo: (self addressOfEndOfCase: 2
> inCPIC: cPIC).
> +
> +
> +       ^0
> + !
>
> Item was changed:
>   ----- Method: Cogit>>disassembleMethod:on: (in category 'disassembly')
> -----
>   disassembleMethod: surrogateOrAddress on: aStream
>         <doNotGenerate>
>         | cogMethod mapEntries codeRanges |
>         cogMethod := surrogateOrAddress isInteger
>                                                                 ifTrue:
> [self cogMethodSurrogateAt: surrogateOrAddress]
>                                                                 ifFalse:
> [surrogateOrAddress].
>         cogMethod cmType = CMBlock ifTrue:
>                 [^self disassembleMethod: cogMethod cmHomeMethod on:
> aStream].
>         self printMethodHeader: cogMethod on: aStream.
>
>         (mapEntries := Dictionary new)
>                 at: cogMethod asInteger + cmEntryOffset put: 'entry'.
>
>         cogMethod cmType = CMMethod ifTrue:
>                 [mapEntries at: cogMethod asInteger + cmNoCheckEntryOffset
> put: 'noCheckEntry'].
>
>         cogMethod cmType = CMClosedPIC ifTrue:
>                 [mapEntries at: cogMethod asInteger + firstCPICCaseOffset
> put: 'ClosedPICCase0'.
> +                1 to: maxCPICCases - 1 do:
> -                1 to: numPICCases - 1 do:
>                         [:i|
>                         mapEntries
>                                 at: cogMethod asInteger +
> firstCPICCaseOffset + (i * cPICCaseSize)
>                                 put: 'ClosedPICCase', i printString]].
>
>         self mapFor: cogMethod
>                 performUntil: #collectMapEntry:address:into:
>                 arg: mapEntries.
>
>         NewspeakVM ifTrue:
>                 [objectRepresentation canPinObjects ifFalse:
>                         [mapEntries keys do:
>                                 [:a|
>                                 (mapEntries at: a) = #IsNSSendCall ifTrue:
>                                         [mapEntries
>                                                 at: a + backEnd
> jumpShortByteSize
>                                                         put: {'Class'.
> #disassembleCachedOop:. (objectMemory wordSize)};
>                                                 at: a + backEnd
> jumpShortByteSize + objectMemory bytesPerOop
>                                                         put:
> {'ImplicitReceiver'. #disassembleCachedOop:. (objectMemory wordSize)}]]]].
>
>         "This would all be far more elegant and simple if we used blocks.
>          But there are no blocks in C and the basic enumerators here need
>          to be used in the real VM.  Apologies."
>         (codeRanges := self codeRangesFor: cogMethod) do:
>                 [:range|
>                 (cogMethod cmType = CMMethod) ifTrue:
>                         [mapEntries keysAndValuesDo:
>                                 [:mcpc :label| | bcpc |
>                                 ((range includes: mcpc)
>                                  and: [(AnnotationsWithBytecodePCs
> includes: label)
>                                  and: [range cogMethod stackCheckOffset >
> 0]]) ifTrue:
>                                         [bcpc := self bytecodePCFor: mcpc
> startBcpc: range startpc in: range cogMethod.
>                                          bcpc ~= 0 ifTrue:
>                                                 [mapEntries at: mcpc put:
> label, ' bc ', bcpc printString, '/', (bcpc + 1) printString]]]].
>                 (cogMethod blockEntryOffset ~= 0
>                  and: [range first = (cogMethod blockEntryOffset +
> cogMethod asInteger)])
>                         ifTrue:
>                                 [aStream nextPutAll: 'blockEntry:'; cr.
>                                  self blockDispatchFor: cogMethod
>                                         perform: #disassemble:from:to:arg:
>                                         arg: aStream]
>                         ifFalse:
>                                 [range first > (cogMethod address +
> cmNoCheckEntryOffset) ifTrue:
>                                         [self printMethodHeader: range
> cogMethod
>                                                 on: aStream].
>                                 self disassembleFrom: range first to:
> range last labels: mapEntries on: aStream]].
>         aStream nextPutAll: 'startpc: '; print: codeRanges first startpc;
> cr.
>         (cogMethod cmType = CMMethod
>          or: [cogMethod cmType = CMOpenPIC]) ifTrue:
>                 [[self mapFor: cogMethod
>                         performUntil: #printMapEntry:mcpc:args:
>                         arg: { aStream. codeRanges. cogMethod }]
>                         on: AssertionFailure
>                         do: [:ex|
>                                 ex primitiveChangeClassTo:
> ResumableVMError basicNew. ":) :) :)"
>                                 ex resume: nil]].
>         ^cogMethod!
>
> Item was changed:
>   ----- Method: Cogit>>expectedClosedPICPrototype: (in category 'garbage
> collection') -----
>   expectedClosedPICPrototype: cPIC
>         "Answer 0 if the ClosedPIC is as expected from
> compileClosedPICPrototype,
>          otherwise answer an error code identifying the first discrepancy
> found."
>         "self disassembleFrom: methodZoneBase + (self sizeof: CogMethod)
> to: methodZoneBase + closedPICSize"
>         <var: #cPIC type: #'CogMethod *'>
>         | pc offsetToLiteral object entryPoint |
>         pc := cPIC asInteger + firstCPICCaseOffset.
>         "First jump is unconditional; subsequent ones are conditional"
>         offsetToLiteral := backEnd jumpLongByteSize.
> +       1 to: maxCPICCases do:
> -       1 to: numPICCases do:
>                 [:i|
>                 i > 1 ifTrue:
>                         [object := literalsManager classRefInClosedPICAt:
> pc - offsetToLiteral.
>                          object = (16rBABE1F15 + i - 1) ifFalse:
>                                 [^1]].
>                 object := literalsManager objRefInClosedPICAt: pc -
> offsetToLiteral.
>                 object = (i = 1
>                                         ifTrue: [16r5EAF00D]
>                                         ifFalse: [16rBADA550 + i - 1])
> ifFalse:
>                         [^2].
>                 offsetToLiteral := backEnd jumpLongConditionalByteSize.
> +               entryPoint := backEnd
> jumpLongTargetBeforeFollowingAddress: pc.
> -               entryPoint := literalsManager cPICCase: i
> jumpTargetBefore: pc.
>                 entryPoint = (self cPICPrototypeCaseOffset + 16rCA5E10 +
> (i - 1 * 16)) ifFalse:
>                                 [^3].
>                 pc := pc + cPICCaseSize].
>         pc := pc - cPICCaseSize.
> +       entryPoint := backEnd jumpLongTargetBeforeFollowingAddress: pc +
> cPICEndSize - literalsManager endSizeOffset.
> -       entryPoint := backEnd jumpLongTargetBeforeFollowingAddress: pc +
> cPICEndSize.
>         entryPoint = (self cPICMissTrampolineFor: 0) ifFalse:
>                 [^4].
>         ^0!
>
> Item was changed:
>   ----- Method: Cogit>>followMaybeObjRefInClosedPICAt: (in category
> 'garbage collection') -----
>   followMaybeObjRefInClosedPICAt: mcpc
>         "Follow a potential object reference from a closed PIC.
>          This may be a method reference or null.
> +        Answer if the followed literal is young.
> +       'mcpc' refers to the jump/branch instruction at the end of
> +       each cpic case"
> -        Answer if the followed literal is young."
>         | object subject |
>         object := literalsManager objRefInClosedPICAt: mcpc.
>         (objectRepresentation couldBeObject: object) ifFalse:
>                 [^false].
>         (objectMemory isForwarded: object) ifFalse:
>                 [^objectMemory isYoungObject: object].
>         subject := objectMemory followForwarded: object.
>         literalsManager storeObjRef: subject inClosedPICAt: mcpc.
>         codeModified := true.
>         ^objectMemory isYoungObject: subject!
>
> Item was changed:
>   ----- Method: Cogit>>followMethodReferencesInClosedPIC: (in category
> 'garbage collection') -----
>   followMethodReferencesInClosedPIC: cPIC
>         "Remap all object references in the closed PIC.  Answer if any
> references are young.
>         Set codeModified if any modifications are made."
>         <var: #cPIC type: #'CogMethod *'>
>         | pc refersToYoung |
> +       pc := self addressOfEndOfCase: 1 inCPIC: cPIC.
> +
> +       "first we check the method obj ref at the beginning of the CPIC"
> -       pc := cPIC asInteger + firstCPICCaseOffset.
>         refersToYoung := self followMaybeObjRefInClosedPICAt: pc - backEnd
> jumpLongByteSize.
> +
> +       "We find the end address of the cPICNumCases'th case and can then
> just step forward by the case size thereafter"
> +       pc := self addressOfEndOfCase:  cPIC cPICNumCases inCPIC: cPIC.
> +
> +       "For each case we check any object reference at the end address -
> sizeof(conditional instruction) and then increment the end address by case
> size"
> -       pc := pc + cPICCaseSize.
>         2 to: cPIC cPICNumCases do:
>                 [:i|
>                 (self followMaybeObjRefInClosedPICAt: pc - backEnd
> jumpLongConditionalByteSize) ifTrue:
>                         [refersToYoung := true].
>                 pc := pc + cPICCaseSize].
>         ^refersToYoung!
>
> Item was changed:
>   ----- Method: Cogit>>generateClosedPICPrototype (in category
> 'initialization') -----
>   generateClosedPICPrototype
>         "Generate the prototype ClosedPIC to determine how much space as
> full PIC takes.
>          When we first allocate a closed PIC it only has one or two cases
> and we want to grow it.
>          So we have to determine how big a full one is before hand."
> +       | cPIC endAddress |
> -       | cPIC |
>         <var: 'cPIC' type: #'CogMethod *'>
> +       maxCPICCases := 6.
> -       numPICCases := 6.
>         "stack allocate the various collections so that they
>          are effectively garbage collected on return."
> +       self allocateOpcodes: maxCPICCases * 9 bytecodes: 0.
> -       self allocateOpcodes: numPICCases * 9 bytecodes: 0.
>         methodLabel address: methodZoneBase; dependent: nil. "for
> pc-relative MoveCw: cPIC R: ClassReg"
>         self compileClosedPICPrototype.
>         self computeMaximumSizes.
>         cPIC := (self cCoerceSimple: methodZoneBase to: #'CogMethod *').
>         closedPICSize := (self sizeof: CogMethod) + (self
> generateInstructionsAt: methodZoneBase + (self sizeof: CogMethod)).
> +       endAddress := self outputInstructionsAt: methodZoneBase + (self
> sizeof: CogMethod).
> +       self assert: methodZoneBase + closedPICSize = endAddress.
> -       self outputInstructionsAt: methodZoneBase + (self sizeof:
> CogMethod).
>         firstCPICCaseOffset := endCPICCase0 address - methodZoneBase.
> +       cPICEndOfCodeOffset := cPICEndOfCodeLabel address - methodZoneBase.
>         cPICCaseSize := endCPICCase1 address - endCPICCase0 address.
> +       cPICEndSize := closedPICSize - (maxCPICCases - 1 * cPICCaseSize +
> firstCPICCaseOffset).
> -       cPICEndSize := closedPICSize - (numPICCases - 1 * cPICCaseSize +
> firstCPICCaseOffset).
>         closedPICSize := methodZone roundUpLength: closedPICSize.
>         self assert: picInterpretAbort address = (methodLabel address +
> self picInterpretAbortOffset).
> +       self assert: (self expectedClosedPICPrototype: cPIC) = 0.
> +
> +       "tpr this is a little tiresome but after any assert checking we
> need to 0 out the case0 objRef rather than leaving 16r5EAF00D lying around"
> +
> +       backEnd storeLiteral: 0 beforeFollowingAddress: endCPICCase0
> address - backEnd jumpLongByteSize.
> +
> +       "update the methodZoneBase so we keep the prototype aruond for
> later use"
> +       methodZoneBase := self alignUptoRoutineBoundary: endAddress.
> +       cPICPrototype := cPIC.
> -       self assert: (self expectedClosedPICPrototype: cPIC) = 0
>         "self cCode: ''
>                 inSmalltalk:
> +                       [self disassembleFrom: cPIC + (self sizeof:
> CogMethod) to: cPIC + closedPICSize - 1.
> -                       [self disassembleFrom: methodZoneBase + (self
> sizeof: CogMethod) to: methodZoneBase + closedPICSize - 1.
>                          self halt]"!
>
> Item was changed:
>   ----- Method: Cogit>>initializeCodeZoneFrom:upTo: (in category
> 'initialization') -----
>   initializeCodeZoneFrom: startAddress upTo: endAddress
>         <api>
>         self cCode: [self sqMakeMemoryExecutableFrom: startAddress To:
> endAddress]
>                 inSmalltalk: [self initializeProcessor].
>         codeBase := methodZoneBase := startAddress.
>         minValidCallAddress := (codeBase min: coInterpreter
> interpretAddress)
>                                                                 min:
> coInterpreter primitiveFailAddress.
>         self initializeBackend.
>         methodZone manageFrom: methodZoneBase to: endAddress.
>         self maybeGenerateCheckFeatures.
>         self maybeGenerateICacheFlush.
>         self generateVMOwnerLockFunctions.
>         ceGetSP := self cCoerceSimple: self genGetLeafCallStackPointer to:
> #'unsigned long (*)(void)'.
>         self generateStackPointerCapture.
>         self generateTrampolines.
> -       methodZone manageFrom: methodZoneBase to: endAddress.
>         self computeEntryOffsets.
>         self generateClosedPICPrototype.
> +       methodZone manageFrom: methodZoneBase to: endAddress.
>         "N.B. this is assumed to be the last thing done in initialization;
> see Cogit>>initialized"
>         self generateOpenPICPrototype!
>
> Item was changed:
>   ----- Method: Cogit>>mapObjectReferencesInClosedPIC: (in category
> 'garbage collection') -----
>   mapObjectReferencesInClosedPIC: cPIC
>         "Remap all object references in the closed PIC.  Answer if any
> references are young.
>         Set codeModified if any modifications are made."
>         <var: #cPIC type: #'CogMethod *'>
>         | pc refersToYoung |
> +       pc := self addressOfEndOfCase:1 inCPIC:cPIC.
> +
> +       "first we check the obj ref at the beginning of the CPIC"
> -       pc := cPIC asInteger + firstCPICCaseOffset.
>         refersToYoung := self updateMaybeObjRefInClosedPICAt: pc - backEnd
> jumpLongByteSize.
> +
> +       "We find the end address of the cPICNumCases'th case and can then
> just step forward by the case size thereafter"
> +       pc := self addressOfEndOfCase: cPIC cPICNumCases inCPIC: cPIC.
> +
> +       "For each case we check any object reference at the end address -
> sizeof(conditional instruction) and then increment the end address by case
> size"
> -       pc := pc + cPICCaseSize.
>         2 to: cPIC cPICNumCases do:
>                 [:i|
>                 objectRepresentation inlineCacheTagsMayBeObjects ifTrue:
>                         [(self updateMaybeClassRefInClosedPICAt: pc -
> backEnd jumpLongConditionalByteSize) ifTrue:
>                                 [refersToYoung := true]].
>                 (self updateMaybeObjRefInClosedPICAt: pc - backEnd
> jumpLongConditionalByteSize) ifTrue:
>                         [refersToYoung := true].
>                 pc := pc + cPICCaseSize].
>         ^refersToYoung!
>
> Item was changed:
>   ----- Method: Cogit>>noTargetsFreeInClosedPIC: (in category
> 'compaction') -----
>   noTargetsFreeInClosedPIC: cPIC
> +       "Answer if all targets in the PIC are in-use methods."
> -       "Answerr if all targets in the PIC are in-use methods."
>         <var: #cPIC type: #'CogMethod *'>
>         | pc entryPoint targetMethod |
>         <var: #targetMethod type: #'CogMethod *'>
> +
> -       pc := cPIC asInteger + firstCPICCaseOffset.
>         1 to: cPIC cPICNumCases do:
>                 [:i|
> +               pc := self addressOfEndOfCase: i inCPIC: cPIC.
> +               entryPoint := backEnd
> jumpLongTargetBeforeFollowingAddress: pc.
> -               entryPoint := literalsManager cPICCase: i
> jumpTargetBefore: pc.
>                 "Find target from jump.  Ignore jumps to the interpret and
> MNU calls within this PIC"
>                 (cPIC containsAddress: entryPoint) ifFalse:
>                         [targetMethod := self cCoerceSimple: entryPoint -
> cmNoCheckEntryOffset to: #'CogMethod *'.
>                          targetMethod cmType ~= CMMethod ifTrue:
> +                               [^false]]].
> -                               [^false]].
> -               i < cPIC cPICNumCases ifTrue:
> -                       [pc := pc + cPICCaseSize]].
>         ^true!
>
> Item was changed:
>   ----- Method: Cogit>>relocateCallsInClosedPIC: (in category
> 'compaction') -----
>   relocateCallsInClosedPIC: cPIC
>         <var: #cPIC type: #'CogMethod *'>
>         | delta pc entryPoint targetMethod |
>         <var: #targetMethod type: #'CogMethod *'>
>         delta := cPIC objectHeader.
>         self assert: (backEnd callTargetFromReturnAddress: cPIC asInteger
> + missOffset)
>                                         = (self picAbortTrampolineFor:
> cPIC cmNumArgs).
>         backEnd relocateCallBeforeReturnPC: cPIC asInteger + missOffset
> by: delta negated.
>
>         pc := cPIC asInteger + firstCPICCaseOffset.
>         1 to: cPIC cPICNumCases do:
>                 [:i|
> +               pc := self addressOfEndOfCase: i inCPIC: cPIC.
> +               entryPoint := backEnd
> jumpLongTargetBeforeFollowingAddress: pc.
> -               entryPoint := literalsManager cPICCase: i
> jumpTargetBefore: pc.
>                 "Find target from jump.  Ignore jumps to the interpret and
> MNU calls within this PIC"
>                 (cPIC containsAddress: entryPoint) ifFalse:
>                         [targetMethod := self cCoerceSimple: entryPoint -
> cmNoCheckEntryOffset to: #'CogMethod *'.
>                          self assert: targetMethod cmType = CMMethod.
> +                        backEnd
> +                               relocateJumpLongBeforeFollowingAddress: pc
> +                               by: (delta - targetMethod objectHeader)
> negated]].
> -                        literalsManager
> -                               cPICCase: i
> -                               relocateJumpLongBefore: pc
> -                               by: (delta - targetMethod objectHeader)
> negated].
> -               pc := pc + cPICCaseSize].
>         self assert: cPIC cPICNumCases > 0.
> +
> -       pc := pc - cPICCaseSize.
>         "Finally relocate the load of the PIC and the jump to the overflow
> routine ceCPICMiss:receiver:"
> +       backEnd relocateMethodReferenceBeforeAddress: (self
> addressOfEndOfCase: 2 inCPIC: cPIC)+ backEnd loadPICLiteralByteSize by:
> delta.
> +       backEnd relocateJumpLongBeforeFollowingAddress: cPIC asInteger +
> cPICEndOfCodeOffset by: delta negated!
> -       backEnd relocateMethodReferenceBeforeAddress: pc + backEnd
> loadPICLiteralByteSize by: delta.
> -       backEnd relocateJumpLongBeforeFollowingAddress: pc + cPICEndSize
> by: delta negated!
>
> Item was added:
> + ----- Method: Cogit>>rewriteCPIC:caseJumpTo: (in category 'in-line
> cacheing') -----
> + rewriteCPIC: cPIC caseJumpTo: target
> +       "adding a new CPIC case, or making an MNU CPIC, requires altering
> the jump that takes us to the first case to be used"
> +       <inline: true>
> +       backEnd rewriteCPICJumpAt: cPIC asInteger + firstCPICCaseOffset -
> backEnd jumpLongByteSize - backEnd loadPICLiteralByteSize target: target!
>
> Item was changed:
>   ----- Method: Cogit>>updateMaybeObjRefInClosedPICAt: (in category
> 'garbage collection') -----
>   updateMaybeObjRefInClosedPICAt: mcpc
>         "Update a potential object reference from a closed PIC.
>          This may be an object reference, an inline cache tag or null.
> +        Answer if the updated literal is young.
> +       'mcpc' refers to the jump/branch instruction at the end of
> +       each cpic case"
> -        Answer if the updated literal is young."
>         | object subject |
>         object := literalsManager objRefInClosedPICAt: mcpc.
>         (objectRepresentation couldBeObject: object) ifFalse:
>                 [^false].
>         subject := objectRepresentation remapOop: object.
>         object ~= subject ifTrue:
>                 [literalsManager storeObjRef: subject inClosedPICAt: mcpc.
>                  codeModified := true].
>         ^objectMemory isYoungObject: subject!
>
> Item was removed:
> - ----- Method: InLineLiteralsManager>>cPICCase:jumpTargetBefore: (in
> category 'closed PIC parsing') -----
> - cPICCase: caseIndex jumpTargetBefore: pc
> -       <inline: true>
> -       ^cogit backEnd jumpLongTargetBeforeFollowingAddress: pc!
>
> Item was added:
> + ----- Method: InLineLiteralsManager>>endSizeOffset (in category 'closed
> PIC parsing') -----
> + endSizeOffset
> +       "return the offset need from the cPICEndSize in order to point to
> just after the last instruction - here that means 0"
> +       ^0!
>
> Item was changed:
>   ----- Method: InLineLiteralsManager>>objRefInClosedPICAt: (in category
> 'garbage collection') -----
>   objRefInClosedPICAt: mcpc
> +       "'mcpc' refers to the jump/branch instruction at the end of
> +       each cpic case. The method objRef is the method object referenced
> by the
> +       movI $0x0bada553, %ebx
> +       or
> +       ldr    r6, [pc, #64]    ; 0x000017d4 16rBADA553
> +       type instruction preceeding this"
>         <inline: true>
>         ^cogit backEnd literalBeforeFollowingAddress: mcpc!
>
> Item was changed:
>   ----- Method: InLineLiteralsManager>>storeObjRef:inClosedPICAt: (in
> category 'garbage collection') -----
>   storeObjRef: literal inClosedPICAt: address
> +       "'mcpc' refers to the jump/branch instruction at the end of
> +       each cpic case. The objRef is the literal referenced by the
> +       movI $0x0bada553, %ebx or
> +       ldr    r6, [pc, #64]    ; 0x000017d4 16rBADA553
> +       type instruction preceeding this"
>         <var: #address type: #usqInt>
>         <inline: true>
>         cogit backEnd storeLiteral: literal beforeFollowingAddress:
> address!
>
> Item was removed:
> - ----- Method: OutOfLineLiteralsManager>>cPICCase:jumpTargetBefore: (in
> category 'closed PIC parsing') -----
> - cPICCase: caseIndex jumpTargetBefore: pc
> -       <inline: true>
> -       "With Spur the class tag is always 32-bits and the literal is
> bytesPerOop.
> -        With V3 the class and literal are both bytesPerOop."
> -       ^cogit backEnd jumpLongTargetBeforeFollowingAddress: pc -
> (caseIndex <= 1
> -
>
>  ifTrue: [objectMemory bytesPerOop]
> -
>
>  ifFalse: [objectRepresentation inlineCacheTagsMayBeObjects
> -
>
>                  ifTrue: [objectMemory bytesPerOop * 2]
> -
>
>                  ifFalse: [objectMemory bytesPerOop + 4]])!
>
> Item was changed:
>   ----- Method:
> OutOfLineLiteralsManager>>cPICCase:relocateJumpLongBefore:by: (in category
> 'closed PIC parsing') -----
>   cPICCase: caseIndex relocateJumpLongBefore: pc by: delta
>         <inline: true>
> +       cogit backEnd relocateJumpLongBeforeFollowingAddress: pc by: delta!
> -       "With Spur the class tag is always 32-bits and the literal is
> bytesPerOop.
> -        With V3 the class and literal are both bytesPerOop."
> -       cogit backEnd
> -               relocateJumpLongBeforeFollowingAddress: pc - (caseIndex <=
> 1
> -
>                                              ifTrue: [objectMemory
> bytesPerOop]
> -
>                                              ifFalse: [objectRepresentation
> inlineCacheTagsMayBeObjects
> -
>
>  ifTrue: [objectMemory bytesPerOop * 2]
> -
>
>  ifFalse: [objectMemory bytesPerOop + 4]])
> -               by: delta!
>
> Item was changed:
>   ----- Method: OutOfLineLiteralsManager>>classRefInClosedPICAt: (in
> category 'garbage collection') -----
>   classRefInClosedPICAt: address
>         <inline: true>
>         "If inline cache tags are not objects they will be 32-bit values."
> +       "Current ARM out-of-line literal CPICs use
> +       ldr ip, [pc relative address1]
> +       cmp r0, ip
> +       ldr r6, [pc relative address2
> +       beq code
> +       hence the large backwards stepping here - address is pointing at
> the beq"
>         ^objectRepresentation inlineCacheTagsMayBeObjects
> +               ifFalse: [cogit backEnd literalBeforeFollowingAddress:
> address - 8 "better to use 2 * instructionSize if we could, step back to
> the cmp so the literal is found properly" ]
> +               ifTrue: [self break. "not sure about this ? "objectMemory
> longAt: address - objectMemory bytesPerOop]!
> -               ifFalse: [objectMemory long32At: address - 4]
> -               ifTrue: [objectMemory longAt: address - objectMemory
> bytesPerOop]!
>
> Item was added:
> + ----- Method: OutOfLineLiteralsManager>>endSizeOffset (in category
> 'closed PIC parsing') -----
> + endSizeOffset
> +       "return the offset need from the cPICEndSize in order to point to
> just after the last instruction - here that means bytesPerOop * list size"
> +       ^nextLiteralIndex * objectMemory bytesPerOop!
>
> Item was changed:
>   ----- Method: OutOfLineLiteralsManager>>objRefInClosedPICAt: (in
> category 'garbage collection') -----
>   objRefInClosedPICAt: address
> +       "'mcpc' refers to the jump/branch instruction at the end of
> +       each cpic case. The objRef is the literal referenced by the
> +        ldr    r6, [pc, #88]   ; 16r5EAF00D type instruction preceeding
> this"
>         <inline: true>
> +       ^cogit backEnd literalBeforeFollowingAddress: address !
> -       ^objectMemory longAt: address!
>
> Item was changed:
>   ----- Method: OutOfLineLiteralsManager>>storeClassRef:inClosedPICAt: (in
> category 'garbage collection') -----
>   storeClassRef: classObj inClosedPICAt: address
>         <var: #address type: #usqInt>
>         <inline: true>
>         "If inline cache tags are not objects they will be 32-bit values."
> +       "Current ARM out-of-line literal CPICs use
> +       ldr ip, [pc relative address1]
> +       cmp r0, ip
> +       ldr r6, [pc relative address2
> +       beq code
> +       hence the large backwards stepping here"
>         objectRepresentation inlineCacheTagsMayBeObjects
> +               ifTrue: [self break. objectMemory long32At: address - 4
> put: classObj]
> +               ifFalse: [cogit backEnd storeLiteral: classObj
> beforeFollowingAddress:  address - 8 "better to use 2 * instructionSize if
> we could, step back to the cmp so the literal is found properly"]!
> -               ifTrue: [objectMemory long32At: address - 4 put: classObj]
> -               ifFalse: [objectMemory longAt: address - objectMemory
> bytesPerOop]!
>
> Item was changed:
>   ----- Method: OutOfLineLiteralsManager>>storeObjRef:inClosedPICAt: (in
> category 'garbage collection') -----
>   storeObjRef: literal inClosedPICAt: address
> +       "'mcpc' refers to the jump/branch instruction at the end of
> +       each cpic case. The objRef is the literal referenced by the
> +        ldr    r6, [pc, #88]   ; 16r5EAF00D type instruction preceeding
> this"
>         <var: #address type: #usqInt>
>         <inline: true>
> +       cogit backEnd storeLiteral: literal beforeFollowingAddress:
> address!
> -       objectMemory longAt: address put: literal!
>
> Item was changed:
>   ----- Method:
> SistaStackToRegisterMappingCogit>>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 *'>
> +
> -       pc := cPIC asInteger + firstCPICCaseOffset.
>         1 to: cPIC cPICNumCases do:
>                 [:i|
> +               pc := self addressOfEndOfCase: i inCPIC: cPIC.
>                 cacheTag := i = 1
>                                                 ifTrue: [firstCacheTag]
>                                                 ifFalse: [backEnd
> literalBeforeFollowingAddress: pc
>
>                                                                       -
> backEnd jumpLongConditionalByteSize
>
>                                                                       -
> backEnd loadLiteralByteSize].
>                 classOop := objectRepresentation classForInlineCacheTag:
> cacheTag.
>                 objectMemory storePointer: i * 2 - 1 ofObject: tuple
> withValue: classOop.
> +               entryPoint := backEnd
> jumpLongTargetBeforeFollowingAddress: pc.
> -               entryPoint := literalsManager cPICCase: i
> jumpTargetBefore: 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 ]!
> -               objectMemory storePointer: i * 2 ofObject: tuple
> withValue: value.
> -               pc := pc + cPICCaseSize]!
>
>


-- 
_,,,^..^,,,_
best, Eliot
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20151111/81e21836/attachment-0001.htm


More information about the Vm-dev mailing list