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@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!
On 22-11-2015, at 9:57 AM, Eliot Miranda eliot.miranda@gmail.com wrote: in finishing the CPIC change use the following scripts to create a closed PIC for each platform.
It would be a teeny-tiny benefit to the Pi if we could makes the CPIC cases look like
000014e4: ldr ip, [pc, #52] ; 0x00001524 16rBABE1F1A 000014e8: cmp r0, ip 000014ec: ldreq r6, [pc, #52] ; 0x00001520 16rBADA555 000014f0: beq 0x00010a78
so that an unneeded load wasn’t done. But really teeny-tiny.
tim -- tim Rowledge; tim@rowledge.org; http://www.rowledge.org/tim Machine-independent: Does not run on any existing machine.
vm-dev@lists.squeakfoundation.org