[Vm-dev] VM Maker: VMMaker.oscog-eem.1528.mcz
Eliot Miranda
eliot.miranda at gmail.com
Sun Nov 22 17:57:13 UTC 2015
Hi Ryan, Tim,
in finishing the CPIC change use the following scripts to create a
closed PIC for each platform.
StackToRegisterMappingCogit genAndDisPICoptions: #(ISA IA32
CogCompilerClass CogIA32Compiler ObjectMemory NewCoObjectMemory).
StackToRegisterMappingCogit genAndDisPICoptions: #(ISA IA32
CogCompilerClass CogIA32Compiler ObjectMemory Spur32BitCoMemoryManager).
StackToRegisterMappingCogit genAndDisPICoptions: #(ISA ARMv5
CogCompilerClass CogOutOfLineLiteralsARMCompiler ObjectMemory
Spur32BitCoMemoryManager).
StackToRegisterMappingCogit genAndDisPICoptions: #(ISA ARMv5
CogCompilerClass CogInLineLiteralsARMCompiler ObjectMemory
Spur32BitCoMemoryManager).
StackToRegisterMappingCogit genAndDisPICoptions: #(ISA MIPSEL
CogCompilerClass CogMIPSELCompiler ObjectMemory Spur32BitCoMemoryManager).
StackToRegisterMappingCogit genAndDisPICoptions: #(ISA X64 CogCompilerClass
CogInLineLiteralsX64Compiler ObjectMemory Spur64BitCoMemoryManager).
StackToRegisterMappingCogit genAndDisPICoptions: #(ISA X64 CogCompilerClass
CogOutOfLineLiteralsX64Compiler ObjectMemory Spur64BitCoMemoryManager).
Only the first four (both x86 and both ARMv5) work. Don't worry about x64;
I'm fixing that.
I hope to fix expectedClosedPICPrototype to include asserts to
test rewriteCPIC:caseJumpTo: et al, but have dad duties so may not get to
this until Monday/Tuesday.
On Sun, Nov 22, 2015 at 9:33 AM, <commits at source.squeak.org> wrote:
>
> Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
> http://source.squeak.org/VMMaker/VMMaker.oscog-eem.1528.mcz
>
> ==================== Summary ====================
>
> Name: VMMaker.oscog-eem.1528
> Author: eem
> Time: 22 November 2015, 9:33:01.294 am
> UUID: 3ed0e2f1-7f11-4ab0-be68-96373bf4612f
> Ancestors: VMMaker.oscog-eem.1527
>
> Reorder CPIC instructions to suit MIPSEL, i.e. put the load before the
> compare and jump. Simplify and eliminate duplication, especially in thge
> literals managers, nuking almost all of their PIC support code. It isn't
> needed since the code ends up being the same in each manager.
>
> There is still work to do:
> - the rewriteCPICFoo methods should all be implemented in Cogit and should
> use the same accessors as expectedClosedPICPrototype demonstrates.
> - those methods should be tested via extra asserts in
> expectedClosedPICPrototype
>
> Extend MIPS' noteFollowingConditionalBranch: to include long conditional
> jumps.
>
> =============== Diff against VMMaker.oscog-eem.1527 ===============
>
> Item was added:
> + ----- Method: CogARMCompiler>>instructionIsCMP: (in category 'testing')
> -----
> + instructionIsCMP: instr
> + "is this an CMP instruction?"
> + ^(instr >> 21 bitAnd: 16r7F) = CmpOpcode!
>
> Item was added:
> + ----- Method: CogARMCompiler>>instructionIsLDR: (in category 'testing')
> -----
> + instructionIsLDR: instr
> + "is this any kind of LDR instruction? c.f.
> memMxr:reg:base:u:b:l:imm:"
> + ^instr >> 28 ~= 16rF "the NEVER condition is used to encode
> non-load instructions"
> + and: [(instr >> 20 bitAnd: 16rC5) = 16r41] "ldr r1, [r2,
> #+/-imm] or ldr r1, [r2, r3]"!
>
> Item was changed:
> ----- Method: CogARMCompiler>>instructionIsOR: (in category 'testing')
> -----
> instructionIsOR: instr
> "is this an ORR instruction?"
> + ^(instr >> 21 bitAnd: 16r7F) = (16r10 bitOr: OrOpcode)!
> - ^(instr >> 21 bitAnd: 16rF) = 16rC!
>
> Item was removed:
> - ----- Method: CogARMCompiler>>literalBeforeFollowingAddress: (in
> category 'inline cacheing') -----
> - literalBeforeFollowingAddress: followingAddress
> - "Answer the constant loaded by the instruction sequence just
> before this address:"
> - ^self subclassResponsibility!
>
> Item was added:
> + ----- Method: CogAbstractInstruction>>cmpC32RTempByteSize (in category
> 'accessing') -----
> + cmpC32RTempByteSize
> + self subclassResponsibility!
>
> Item was added:
> + ----- Method: CogAbstractInstruction>>literal32BeforeFollowingAddress:
> (in category 'inline cacheing') -----
> + literal32BeforeFollowingAddress: followingAddress
> + "Answer the constant loaded by the instruction sequence just
> before this address:"
> + <inline: true>
> + ^objectMemory wordSize = 8
> + ifTrue: [self subclassResponsibility]
> + ifFalse: [self literalBeforeFollowingAddress:
> followingAddress]!
>
> Item was added:
> + ----- Method: CogAbstractInstruction>>literalBeforeFollowingAddress: (in
> category 'inline cacheing') -----
> + literalBeforeFollowingAddress: followingAddress
> + "Answer the constant loaded by the instruction sequence just
> before this address:"
> + ^self subclassResponsibility!
>
> Item was changed:
> ----- 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
> initialize & extend CPICs."
> - "rewrite the three values involved in a CPIC case. Used by the
> create & extend cpcic methods"
> self subclassResponsibility
> !
>
> Item was added:
> + ----- Method: CogIA32Compiler>>cmpC32RTempByteSize (in category
> 'accessing') -----
> + cmpC32RTempByteSize
> + ^5!
>
> Item was changed:
> ----- 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
> initialize & extend CPICs."
> - "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)"
> +
> - 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: CogInLineLiteralsARMCompiler>>cmpC32RTempByteSize (in
> category 'accessing') -----
> + cmpC32RTempByteSize
> + ^20!
>
> Item was added:
> + ----- Method:
> CogInLineLiteralsARMCompiler>>literal32BeforeFollowingAddress: (in category
> 'inline cacheing') -----
> + literal32BeforeFollowingAddress: followingAddress
> + "Answer the 32-bit constant loaded by a MOV/ORR/ORR/ORR
> + or MOV/ORR/ORR/ORR/PUSH, or MOV/ORR/ORR/ORR/CMP sequence, just
> before this address:"
> + ^(self instructionIsOR: (self instructionBeforeAddress:
> followingAddress))
> + ifTrue: [self
> extract32BitOperandFrom4InstructionsPreceding: followingAddress]
> + ifFalse: [self
> extract32BitOperandFrom4InstructionsPreceding: followingAddress - 4]!
>
> Item was added:
> + ----- Method:
> CogInLineLiteralsX64Compiler>>literal32BeforeFollowingAddress: (in category
> 'inline cacheing') -----
> + literal32BeforeFollowingAddress: followingAddress
> + "Answer the 32-bit literal embedded in the instruction immediately
> preceding followingAddress."
> + ^ ((objectMemory byteAt: followingAddress - 1) << 24)
> + + ((objectMemory byteAt: followingAddress - 2) << 16)
> + + ((objectMemory byteAt: followingAddress - 3) << 8)
> + + (objectMemory byteAt: followingAddress - 4)!
>
> Item was added:
> + ----- Method: CogMIPSELCompiler>>cmpC32RTempByteSize (in category
> 'accessing') -----
> + cmpC32RTempByteSize
> + self flag: #todo. "value - reg or reg - value?"
> + self flag: #inefficient. "Cog RTL assumes we can do any kind of
> conditional branch after a Cmp."
> + ^28!
>
> Item was changed:
> ----- Method: CogMIPSELCompiler>>noteFollowingConditionalBranch: (in
> category 'abstract instructions') -----
> noteFollowingConditionalBranch: branch
> "Support for processors without condition codes, such as the MIPS.
> Answer the branch opcode. Modify the receiver and the branch to
> implement a suitable conditional branch that doesn't depend on
> condition codes being set by the receiver."
> <var: #branch type: #'AbstractInstruction *'>
> branch opcode caseOf: {
> [JumpOverflow] -> [opcode := opcode caseOf: {
>
> [AddCqR] -> [AddCheckOverflowCqR].
>
> [AddRR] -> [AddCheckOverflowRR].
>
> [MulRR] -> [MulCheckOverflowRR].
>
> [SubCqR] -> [SubCheckOverflowCqR].
>
> [SubRR] -> [SubCheckOverflowRR].
>
> }].
> [JumpNoOverflow] -> [opcode := opcode caseOf: {
>
> [AddCqR] -> [AddCheckOverflowCqR].
>
> [AddRR] -> [AddCheckOverflowRR].
>
> [MulRR] -> [MulCheckOverflowRR].
>
> [SubCqR] -> [SubCheckOverflowCqR].
>
> [SubRR] -> [SubCheckOverflowRR].
>
> }].
> "Ryan, I'm imagining that all the other cases go in here,
> such as collapsing CmpRR; JumpZero to Label; BrEqRR.
> This is obviously not nearly complete."
> [JumpZero] -> [opcode caseOf: {
>
> [CmpRR] -> [branch setOpcode: BrEqRR andOperandsFrom: self.
> +
> branch operands at: 3 put: (operands at: 1).
>
> opcode := Label].
> }].
> [JumpNonZero] -> [opcode caseOf: {
>
> [CmpRR] -> [branch setOpcode: BrNeRR andOperandsFrom: self.
> +
> branch operands at: 3 put: (operands at: 1).
>
> opcode := Label].
> }].
> + [JumpLongZero] -> [opcode caseOf: {
> +
> [CmpRR] -> [branch setOpcode: BrNeRR andOperandsFrom: self.
> +
> "skip the following long branch"
> +
> branch operands at: 3 put: self
> jumpLongByteSize.
> +
> opcode := JumpLong].
> + }].
> + [JumpLongNonZero] -> [opcode caseOf: {
> +
> [CmpRR] -> [branch setOpcode: BrEqRR andOperandsFrom: self.
> +
> "skip the following long branch"
> +
> branch operands at: 3 put: self
> jumpLongByteSize.
> +
> opcode := JumpLong].
> + }].
> }
> "No otherwise for now to catch all cases"
> "otherwise: []".
> ^branch!
>
> Item was added:
> + ----- Method:
> CogObjectRepresentationFor32BitSpur>>markAndTraceCacheTagLiteral:in:atpc:
> (in category 'garbage collection') -----
> + markAndTraceCacheTagLiteral: literal in: cogMethodOrNil atpc: address
> + "Mark and trace a literal in an inline cache preceding address in
> cogMethodOrNil.
> + Answer if code was modified."
> + <var: #cogMethodOrNil type: #'CogMethod *'>
> + <var: #address type: #usqInt>
> + | objOop |
> + (self couldBeObject: literal) ifFalse:
> + [^false].
> + self assert: (objectMemory addressCouldBeObj: literal).
> + (objectMemory isForwarded: literal) ifFalse:
> + [objectMemory markAndTrace: literal.
> + ^false].
> + objOop := objectMemory followForwarded: literal.
> + cogit backEnd rewriteInlineCacheTag: objOop at: address.
> + self markAndTraceUpdatedLiteral: objOop in: cogMethodOrNil.
> + ^true!
>
> Item was added:
> + ----- Method:
> CogObjectRepresentationFor64BitSpur>>markAndTraceCacheTagLiteral:in:atpc:
> (in category 'garbage collection') -----
> + markAndTraceCacheTagLiteral: literal in: cogMethodOrNil atpc: address
> + "Mark and trace a literal in an inline cache preceding address in
> cogMethodOrNil.
> + Answer if code was modified. In 64-bit Spur, cache tags are
> either selector
> + indices or class indices and so this is a noop."
> + <var: #cogMethodOrNil type: #'CogMethod *'>
> + <var: #address type: #usqInt>
> + <inline: true>
> + ^false!
>
> Item was removed:
> - ----- Method:
> CogObjectRepresentationForSpur>>markAndTraceCacheTagLiteral:in:atpc: (in
> category 'garbage collection') -----
> - markAndTraceCacheTagLiteral: literal in: cogMethodOrNil atpc: address
> - "Mark and trace a literal in an inline cache preceding address in
> cogMethodOrNil.
> - Answer if code was modified."
> - <var: #cogMethodOrNil type: #'CogMethod *'>
> - <var: #address type: #usqInt>
> - | objOop |
> - (self couldBeObject: literal) ifFalse:
> - [^false].
> - self assert: (objectMemory addressCouldBeObj: literal).
> - (objectMemory isForwarded: literal) ifFalse:
> - [objectMemory markAndTrace: literal.
> - ^false].
> - objOop := objectMemory followForwarded: literal.
> - cogit backEnd rewriteInlineCacheTag: objOop at: address.
> - self markAndTraceUpdatedLiteral: objOop in: cogMethodOrNil.
> - ^true!
>
> Item was removed:
> - ----- Method: CogObjectRepresentationForSqueakV3>>remapCacheTag: (in
> category 'garbage collection') -----
> - remapCacheTag: cacheTag
> - ^(self couldBeObject: cacheTag)
> - ifTrue: [objectMemory remap: cacheTag]
> - ifFalse: [cacheTag]!
>
> Item was added:
> + ----- Method: CogOutOfLineLiteralsARMCompiler>>cmpC32RTempByteSize (in
> category 'accessing') -----
> + cmpC32RTempByteSize
> + ^8!
>
> Item was changed:
> ----- Method:
> CogOutOfLineLiteralsARMCompiler>>literalBeforeFollowingAddress: (in
> category 'inline cacheing') -----
> literalBeforeFollowingAddress: followingAddress
> "Return the literal referenced by the instruction immediately
> preceding followingAddress."
> + ^objectMemory longAt: (self pcRelativeAddressAt:
> + ((self instructionIsLDR: (self instructionBeforeAddress:
> followingAddress))
> + ifTrue: [self instructionAddressBefore:
> followingAddress]
> + ifFalse: [self instructionAddressBefore:
> followingAddress - 4]))!
> - ^objectMemory longAt: (self pcRelativeAddressAt: (self
> instructionAddressBefore: followingAddress))!
>
> 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 instructionIsLDR: (self
> instructionBeforeAddress: followingAddress))
> + ifTrue: [self
> instructionAddressBefore: followingAddress]
> + ifFalse: [self
> instructionAddressBefore: followingAddress - 4]))
> + put: literal!
> - objectMemory longAt: (self pcRelativeAddressAt: (self
> instructionAddressBefore: followingAddress )) put: literal!
>
> Item was added:
> + ----- Method: CogX64Compiler>>cmpC32RTempByteSize (in category
> 'accessing') -----
> + cmpC32RTempByteSize
> + ^6!
>
> 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."
> | 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 backEnd
> literal32BeforeFollowingAddress: pc.
> - 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!
>
> 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: (backEnd
> literalBeforeFollowingAddress: pc - backEnd jumpLongByteSize)) ifFalse:
> - (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"
> 2 to: cPIC cPICNumCases do:
> [:i|
> objectRepresentation inlineCacheTagsMayBeObjects ifTrue:
> + [(self checkMaybeObjRefInClosedPIC:
> (literalsManager backEnd literal32BeforeFollowingAddress: pc - backEnd
> jumpLongConditionalByteSize)) ifFalse:
> - [(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: (backEnd
> literalBeforeFollowingAddress: pc - backEnd jumpLongConditionalByteSize -
> backEnd cmpC32RTempByteSize)) ifFalse:
> - (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 object |
> + ((objectMemory isImmediate: cPIC selector)
> + or: [objectMemory isMarked: cPIC selector]) ifFalse:
> + [^true].
> +
> - | pc offsetToLiteral object entryPoint targetMethod |
> - <var: #targetMethod type: #'CogMethod *'>
> - (objectMemory isImmediate: cPIC selector) ifFalse:
> - [(objectMemory isMarked: cPIC selector) ifFalse:
> - [^true]].
> "First jump is unconditional; subsequent ones are conditional."
> + "Check the potential method oop for the first case only.
> + Inline cache tags for the 1st case are at the send site."
> + pc := self addressOfEndOfCase: 1 inCPIC: cPIC.
> + (objectRepresentation couldBeObject: (object := backEnd
> literalBeforeFollowingAddress: pc - backEnd jumpLongByteSize)) ifTrue:
> + [(objectMemory isMarked: object) ifFalse:
> + [^true]].
> +
> + "Check the first target"
> + (self markAndTraceOrFreePICTarget: (backEnd
> jumpLongTargetBeforeFollowingAddress: pc) in: cPIC) ifTrue:
> + [^true].
> +
> + 2 to: cPIC cPICNumCases do:
> - offsetToLiteral := backEnd jumpLongByteSize.
> - 1 to: cPIC cPICNumCases do:
> [:i|
> pc := self addressOfEndOfCase: i inCPIC: cPIC.
> + (objectRepresentation inlineCacheTagsMayBeObjects
> + and: [objectRepresentation couldBeObject: (object :=
> literalsManager backEnd literal32BeforeFollowingAddress: pc - backEnd
> jumpLongConditionalByteSize)]) ifTrue:
> + [(objectMemory isMarked: object) ifFalse:
> - (objectRepresentation inlineCacheTagsMayBeObjects and:
> [i>1] ) "inline cache tags for the 0th case are at the send site" ifTrue:
> - [object := literalsManager classRefInClosedPICAt:
> pc - offsetToLiteral.
> - ((objectRepresentation couldBeObject: object)
> - and: [(objectMemory isMarked: object) not])
> ifTrue:
> [^true]].
> + "Check the potential method oop for subsequent cases."
> + (objectRepresentation couldBeObject: (object := backEnd
> literalBeforeFollowingAddress: pc - backEnd jumpLongConditionalByteSize -
> backEnd cmpC32RTempByteSize)) ifTrue:
> + [(objectMemory isMarked: object) ifFalse:
> + [^true]].
> + "Check subsequent targets"
> + (self markAndTraceOrFreePICTarget: (backEnd
> jumpLongConditionalTargetBeforeFollowingAddress: pc) in: cPIC) ifTrue:
> + [^true]].
> +
> - object := literalsManager objRefInClosedPICAt: pc -
> offsetToLiteral.
> - ((objectRepresentation couldBeObject: object)
> - and: [(objectMemory isMarked: object) not]) ifTrue:
> - [^true].
> - offsetToLiteral := backEnd jumpLongConditionalByteSize.
> - entryPoint := i = 1
> - ifTrue: [backEnd
> jumpLongTargetBeforeFollowingAddress: pc]
> - ifFalse: [backEnd
> jumpLongConditionalTargetBeforeFollowingAddress: 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]]].
> ^false!
>
> Item was changed:
> ----- Method: Cogit>>compileClosedPICPrototype (in category 'in-line
> cacheing') -----
> compileClosedPICPrototype
> "Compile the abstract instructions for a full closed PIC, used to
> generate the chunk of code
> which is copied to form each closed PIC. A Closed Polymorphic
> Inline Cache is a small jump
> table used to optimize sends with a limited degree of
> polymorphism (currently up to 6 cases).
> We call it closed because it deals only with a finite number of
> cases, as opposed to an Open PIC.
> When a monomorphic linked send (a send with a single case,
> linking direct to the checked entry
> point of a CogMethod) fails a class check, the Cogit attempts to
> create a two-entry PIC that will
> handle jumping to the original target for the original class and
> the relevant target for the new
> class. This jump table will be extended on subsequent failures
> up to a limit (6).
>
> We avoid extending CPICs to Open PICs by linking the send site to
> an Open PIC if one already
> exists with the send's selector, a good policy since measurements
> show that sends of mega-
> morphic selectors usually become megamorphic at all send sites.
> Hence the Open PIC list.
>
> A CPIC also optimizes MNUs and interpret-only methods. Each case
> can load SendNumArgs with
> the oop of a method, or will load SendNumArgs with 0 if not.
> MNUs are optimized by jumping to
> the mnuAbort in the CPIC, which calls code that creates the
> Message, thereby avoiding looking up
> the original message which will not be found, and either looks up
> doesNotUnderstand: or directly
> activates the method loaded into SendNumArgs, hence avoiding
> looking up doesNotUnderstand:.
> Interpret-only methods are handled by jumping to the
> picInterpretAbort, which enters the
> interpreter activating the method loaded in SendNumArgs.
>
> CPICs look like the following, where rClass is set at the
> original send site for the 1st case, and #Foo
> is some constant, either an oop, a class tag or an instruction
> address.
>
> rTemp := (rRecever bitAnd: TagMask) = 0 ifTrue: [rReceiver
> class] ifFalse: [rRecever bitAnd: TagMask].
> rTemp = rClass ifFalse:
> [self goto: #Label].
> rSendNumArgs := #MethodForCase1Or0.
> self goto: #TargetForCase1.
> #Label
> rTemp = #ClassTagForCase6 ifTrue:
> [rSendNumArgs := #MethodForCase6Or0.
> self goto: #TargetForCase6].
> ...cases 5, 4 & 3
> rTemp = #ClassTagForCase2 ifTrue:
> [rSendNumArgs := #MethodForCase2Or0.
> self goto: #TargetForCase2].
> self goto: #CPICMissTrampoline
> literals (if out-of-line literals)
>
> where we short-cut as many cases as needed by making the self
> goto: #Label skip as many cases
> as needed."
> <inline: true>
> | numArgs jumpNext |
> <var: #jumpNext type: #'AbstractInstruction *'>
> self compilePICAbort: (numArgs := 0). "Will get rewritten to
> appropriate arity when configuring."
> 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.
> On each entension we must update this jump to move back one case."
> "16r5EAF00D is the method oop, or 0, for the 1st case."
> self MoveUniqueCw: 16r5EAF00D R: SendNumArgsReg.
> self JumpLong: self cPICPrototypeCaseOffset + 16rCA5E10.
> endCPICCase0 := self Label.
> 1 to: maxCPICCases - 1 do:
> [:h|
> h = (maxCPICCases - 1) ifTrue:
> [jumpNext jmpTarget: self Label]. "this is where
> we jump to for the first case"
> - "16rBABE1F15+h is the class tag for the Nth case"
> - self CmpC32: 16rBABE1F15+h R: TempReg.
> "16rBADA550+h is the method oop, or 0, for the Nth case."
> self MoveUniqueCw: 16rBADA550 + h R: SendNumArgsReg.
> + "16rBABE1F15+h is the class tag for the Nth case"
> + self CmpC32: 16rBABE1F15+h R: TempReg.
> self JumpLongZero: self cPICPrototypeCaseOffset +
> 16rCA5E10 + (h * 16).
> h = 1 ifTrue:
> [endCPICCase1 := self Label]].
> self MoveCw: methodLabel address R: ClassReg.
> self JumpLong: (self cPICMissTrampolineFor: numArgs). "Will get
> rewritten to appropriate arity when configuring."
> cPICEndOfCodeLabel := self Label.
> literalsManager dumpLiterals: false.
> ^0!
>
> Item was changed:
> ----- Method: Cogit>>expectedClosedPICPrototype: (in category 'in-line
> cacheing') -----
> 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 object entryPoint |
> + pc := cPIC asUnsignedInteger + firstCPICCaseOffset.
> - | pc offsetToLiteral object entryPoint |
> - pc := cPIC asInteger + firstCPICCaseOffset.
> "First jump is unconditional; subsequent ones are conditional"
> + object := backEnd literalBeforeFollowingAddress: pc - backEnd
> jumpLongByteSize.
> + self assert: object = 16r5EAF00D.
> - offsetToLiteral := backEnd jumpLongByteSize.
> -
> - object := literalsManager objRefInClosedPICAt: pc -
> offsetToLiteral.
> - self assert: (object = 16r5EAF00D).
>
> entryPoint := backEnd jumpLongTargetBeforeFollowingAddress: pc.
> + self assert: entryPoint = (self cPICPrototypeCaseOffset +
> 16rCA5E10).
> - self assert: (entryPoint = (self cPICPrototypeCaseOffset +
> 16rCA5E10)).
>
> 1 to: maxCPICCases - 1 do:
> + [:i | | methodObjPC classTagPC |
> - [:i |
> pc := pc + cPICCaseSize.
> - offsetToLiteral := backEnd jumpLongConditionalByteSize.
>
> + methodObjPC := pc - backEnd jumpLongConditionalByteSize -
> backEnd cmpC32RTempByteSize.
> + object := backEnd literalBeforeFollowingAddress:
> methodObjPC.
> - object := literalsManager classRefInClosedPICAt: pc -
> offsetToLiteral.
> - self assert: object = (16rBABE1F15 + i).
> - literalsManager storeClassRef: (object bitXor:
> 16r5A5A5A5A) inClosedPICAt: pc - offsetToLiteral.
> - object := literalsManager classRefInClosedPICAt: pc -
> offsetToLiteral.
> - self assert: object = ((16rBABE1F15 + i bitXor:
> 16r5A5A5A5A)).
> - literalsManager storeClassRef: (object bitXor:
> 16r5A5A5A5A) inClosedPICAt: pc - offsetToLiteral.
> -
> - object := literalsManager objRefInClosedPICAt: pc -
> offsetToLiteral.
> self assert: object = (16rBADA550 + i).
> + backEnd storeLiteral: (object bitXor: 16rA5A5A5A5)
> beforeFollowingAddress: methodObjPC.
> + object := backEnd literalBeforeFollowingAddress:
> methodObjPC.
> + self assert: object = (16rBADA550 + i bitXor: 16rA5A5A5A5).
> + backEnd storeLiteral: (object bitXor: 16rA5A5A5A5)
> beforeFollowingAddress: methodObjPC.
> - literalsManager storeObjRef: (object bitXor: 16rA5A5A5A5)
> inClosedPICAt: pc - offsetToLiteral.
> - object := literalsManager objRefInClosedPICAt: pc -
> offsetToLiteral.
> - self assert: object = ((16rBADA550 + i) bitXor:
> 16rA5A5A5A5).
> - literalsManager storeObjRef: (object bitXor: 16rA5A5A5A5)
> inClosedPICAt: pc - offsetToLiteral.
>
> + classTagPC := pc - backEnd jumpLongConditionalByteSize.
> + object := backEnd literal32BeforeFollowingAddress:
> classTagPC.
> + self assert: object = (16rBABE1F15 + i).
> + backEnd storeLiteral: (object bitXor: 16r5A5A5A5A)
> beforeFollowingAddress: classTagPC.
> + object := backEnd literal32BeforeFollowingAddress:
> classTagPC.
> + self assert: object = (16rBABE1F15 + i bitXor:
> 16r5A5A5A5A).
> + backEnd storeLiteral: (object bitXor: 16r5A5A5A5A)
> beforeFollowingAddress: classTagPC.
> +
> entryPoint := backEnd
> jumpLongConditionalTargetBeforeFollowingAddress: pc.
> self assert: entryPoint = (self cPICPrototypeCaseOffset +
> 16rCA5E10 + (i * 16))].
>
> entryPoint := backEnd jumpLongTargetBeforeFollowingAddress: pc +
> cPICEndSize - literalsManager endSizeOffset.
> + self assert: entryPoint = (self cPICMissTrampolineFor: 0).
> - self assert: (entryPoint = (self cPICMissTrampolineFor: 0)).
>
> ^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"
> | object subject |
> + object := backEnd literalBeforeFollowingAddress: mcpc.
> - object := literalsManager objRefInClosedPICAt: mcpc.
> (objectRepresentation couldBeObject: object) ifFalse:
> [^false].
> (objectMemory isForwarded: object) ifFalse:
> [^objectMemory isYoungObject: object].
> subject := objectMemory followForwarded: object.
> + backEnd storeLiteral: subject beforeFollowingAddress: mcpc.
> - 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 potential method oop load at the beginning of
> the CPIC"
> - "first we check the method obj ref at the beginning of the CPIC"
> 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.
>
> + "Next we check the potential potential method oop load for each
> case."
> - "For each case we check any object reference at the end address -
> sizeof(conditional instruction) and then increment the end address by case
> size"
> 2 to: cPIC cPICNumCases do:
> [:i|
> + (self followMaybeObjRefInClosedPICAt: pc - backEnd
> jumpLongConditionalByteSize - backEnd cmpC32RTempByteSize) ifTrue:
> - (self followMaybeObjRefInClosedPICAt: pc - backEnd
> jumpLongConditionalByteSize) ifTrue:
> [refersToYoung := true].
> pc := pc + cPICCaseSize].
> ^refersToYoung!
>
> 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 potential method oop load at the beginning of
> the CPIC"
> + refersToYoung := self remapMaybeObjRefInClosedPICAt: pc - backEnd
> jumpLongByteSize.
> - "first we check the obj ref at the beginning of the CPIC"
> - 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.
>
> + "Next we check the potential class ref in the compare instruction,
> and the potential method oop load for each case."
> - "For each case we check any object reference at the end address -
> sizeof(conditional instruction) and then increment the end address by case
> size"
> 2 to: cPIC cPICNumCases do:
> [:i|
> objectRepresentation inlineCacheTagsMayBeObjects ifTrue:
> + [(self remapMaybeObjRefInClosedPICAt: pc - backEnd
> jumpLongConditionalByteSize) ifTrue:
> - [(self updateMaybeClassRefInClosedPICAt: pc -
> backEnd jumpLongConditionalByteSize) ifTrue:
> [refersToYoung := true]].
> + (self remapMaybeObjRefInClosedPICAt: pc - backEnd
> jumpLongConditionalByteSize - backEnd cmpC32RTempByteSize) ifTrue:
> - (self updateMaybeObjRefInClosedPICAt: pc - backEnd
> jumpLongConditionalByteSize) ifTrue:
> [refersToYoung := true].
> pc := pc + cPICCaseSize].
> ^refersToYoung!
>
> Item was added:
> + ----- Method: Cogit>>markAndTraceOrFreePICTarget:in: (in category
> 'garbage collection') -----
> + markAndTraceOrFreePICTarget: entryPoint in: cPIC
> + "If entryPoint is that of some method, then mark and trace objects
> in it and free if it is appropriate.
> + Answer if the method has been freed."
> + <var: #cPIC type: #'CogMethod *'>
> + | targetMethod |
> + <var: #targetMethod type: #'CogMethod *'>
> + self assert: (entryPoint > methodZoneBase and: [entryPoint <
> methodZone freeStart]).
> + (cPIC containsAddress: entryPoint) ifTrue:
> + [^false].
> + targetMethod := self cCoerceSimple: entryPoint -
> cmNoCheckEntryOffset to: #'CogMethod *'.
> + self assert: (targetMethod cmType = CMMethod or: [targetMethod
> cmType = CMFree]).
> + ^self markAndTraceOrFreeCogMethod: targetMethod
> + firstVisit: targetMethod asUnsignedInteger > cPIC
> asUnsignedInteger!
>
> Item was added:
> + ----- Method: Cogit>>remapMaybeObjRefInClosedPICAt: (in category
> 'garbage collection') -----
> + remapMaybeObjRefInClosedPICAt: mcpc
> + "Remap 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 is the address of the next instruction following either
> + the load of the method literal or the compare of the class tag."
> + | object subject |
> + object := backEnd literalBeforeFollowingAddress: mcpc.
> + (objectRepresentation couldBeObject: object) ifFalse:
> + [^false].
> + subject := objectRepresentation remapOop: object.
> + object ~= subject ifTrue:
> + [backEnd storeLiteral: subject beforeFollowingAddress:
> mcpc.
> + codeModified := true].
> + ^objectMemory isYoungObject: subject!
>
> Item was added:
> + ----- Method: Cogit>>storeClassRef:inClosedPICAt: (in category 'in-line
> cacheing') -----
> + storeClassRef: classObj inClosedPICAt: address
> + <var: #address type: #usqInt>
> + <inline: true>
> + "If inline cache tags are not objects they will be 32-bit values."
> + objectRepresentation inlineCacheTagsMayBeObjects
> + ifTrue: [backEnd storeLiteral: classObj
> beforeFollowingAddress: address]
> + ifFalse: [backEnd storeLiteral32: classObj
> beforeFollowingAddress: address]!
>
> Item was removed:
> - ----- Method: Cogit>>updateMaybeClassRefInClosedPICAt: (in category
> 'garbage collection') -----
> - updateMaybeClassRefInClosedPICAt: 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."
> - | object subject |
> - object := literalsManager classRefInClosedPICAt: mcpc.
> - (objectRepresentation couldBeObject: object) ifFalse:
> - [^false].
> - subject := objectRepresentation remapOop: object.
> - object ~= subject ifTrue:
> - [literalsManager storeClassRef: subject inClosedPICAt:
> mcpc.
> - codeModified := true].
> - ^objectMemory isYoungObject: subject!
>
> Item was removed:
> - ----- 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"
> - | 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 changed:
> VMClass subclass: #InLineLiteralsManager
> + instanceVariableNames: 'cogit objectMemory objectRepresentation'
> - instanceVariableNames: 'cogit'
> classVariableNames: ''
> poolDictionaries: ''
> category: 'VMMaker-JIT'!
>
> !InLineLiteralsManager commentStamp: 'eem 6/7/2015 12:07' prior: 0!
> An InLineLiteralsManager is a dummy class that understands the
> OutOfLineLiteralsManager API but does nothing. It is used to allow the
> Cogits to work with back-ends that generate either in-line or out-of-line
> literals.!
>
> Item was removed:
> - ----- Method: InLineLiteralsManager>>cPICCase:relocateJumpLongBefore:by:
> (in category 'closed PIC parsing') -----
> - cPICCase: caseIndex relocateJumpLongBefore: pc by: delta
> - <inline: true>
> - cogit backEnd
> - relocateJumpLongBeforeFollowingAddress: pc
> - by: delta!
>
> Item was removed:
> - ----- Method: InLineLiteralsManager>>classRefInClosedPICAt: (in category
> 'garbage collection') -----
> - classRefInClosedPICAt: mcpc
> - <inline: true>
> - ^cogit backEnd literalBeforeFollowingAddress: mcpc - cogit backEnd
> loadLiteralByteSize!
>
> Item was changed:
> ----- Method: InLineLiteralsManager>>cogit: (in category
> 'initialization') -----
> cogit: aCogit
> <doNotGenerate>
> + cogit := aCogit.
> + objectMemory := aCogit objectMemory.
> + objectRepresentation := aCogit objectRepresentation.!
> - cogit := aCogit!
>
> Item was removed:
> - ----- 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 removed:
> - ----- Method: InLineLiteralsManager>>storeClassRef:inClosedPICAt: (in
> category 'garbage collection') -----
> - storeClassRef: classObj inClosedPICAt: address
> - <var: #address type: #usqInt>
> - <inline: true>
> - cogit backEnd storeLiteral: classObj beforeFollowingAddress:
> address - cogit backEnd loadLiteralByteSize!
>
> Item was removed:
> - ----- 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:relocateJumpLongBefore:by: (in category
> 'closed PIC parsing') -----
> - cPICCase: caseIndex relocateJumpLongBefore: pc by: delta
> - <inline: true>
> - cogit backEnd relocateJumpLongBeforeFollowingAddress: pc by: delta!
>
> Item was removed:
> - ----- 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]!
>
> Item was removed:
> - ----- 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 !
>
> Item was removed:
> - ----- 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"]!
>
> Item was removed:
> - ----- 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!
>
>
--
_,,,^..^,,,_
best, Eliot
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20151122/af52b22b/attachment-0001.htm
More information about the Vm-dev
mailing list