[Vm-dev] VM Maker: VMMaker.oscog-eem.969.mcz
commits at source.squeak.org
commits at source.squeak.org
Sat Dec 6 03:04:09 UTC 2014
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.969.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.969
Author: eem
Time: 5 December 2014, 7:01:27.391 pm
UUID: cdd723c1-bec0-42d5-970f-354702984955
Ancestors: VMMaker.oscog-eem.968
Two more cases where the mnu compilation break
point needs to be checked.
Use numBytesOf: for length of selector.
Rename checkValidInlineCacheTag: to
validInlineCacheTag:. Implement it in the right place
in the obj rep hierarchy for Spur.
Add a debug lookup routine that only looks up (and follows forwarding pointers).
=============== Diff against VMMaker.oscog-eem.968 ===============
Item was added:
+ ----- Method: CogObjectRepresentation>>validInlineCacheTag: (in category 'debug support') -----
+ validInlineCacheTag: classIndexOrTagPattern
+ self subclassResponsibility!
Item was added:
+ ----- Method: CogObjectRepresentationFor32BitSpur>>validInlineCacheTag: (in category 'debug support') -----
+ validInlineCacheTag: classIndexOrTagPattern
+ "The two valid tag patterns are 0 (Character) and 1 (SmallInteger)"
+ <var: 'classIndexOrTagPattern' type: #usqInt>
+ ^classIndexOrTagPattern <= 1
+ or: [(objectMemory classAtIndex: classIndexOrTagPattern) notNil]!
Item was added:
+ ----- Method: CogObjectRepresentationFor64BitSpur>>validInlineCacheTag: (in category 'debug support') -----
+ validInlineCacheTag: classIndexOrTagPattern
+ "The three valid tag patterns are 1 (SmallInteger), 2 (Character) and 3 (SmallFloat64)."
+ ^(classIndexOrTagPattern >= 1
+ and: [classIndexOrTagPattern <= 3])
+ or: [(objectMemory classAtIndex: classIndexOrTagPattern) notNil]!
Item was removed:
- ----- Method: CogObjectRepresentationForSpur>>checkValidInlineCacheTag: (in category 'debug support') -----
- checkValidInlineCacheTag: classIndexOrTagPattern
- ^classIndexOrTagPattern <= objectMemory tagMask
- or: [(objectMemory classAtIndex: classIndexOrTagPattern) notNil]!
Item was removed:
- ----- Method: CogObjectRepresentationForSqueakV3>>checkValidInlineCacheTag: (in category 'garbage collection') -----
- checkValidInlineCacheTag: cacheTag
- ^cacheTag = ConstZero
- or: [((cacheTag bitAnd: 1 << objectMemory shiftForWord - 1) = 0
- and: [cacheTag
- between: 1 << objectMemory compactClassFieldLSB
- and: (objectMemory compactClassIndexOfHeader: -1) << objectMemory compactClassFieldLSB])
- or: [self checkValidObjectReference: cacheTag]]!
Item was added:
+ ----- Method: CogObjectRepresentationForSqueakV3>>validInlineCacheTag: (in category 'garbage collection') -----
+ validInlineCacheTag: cacheTag
+ ^cacheTag = ConstZero
+ or: [((cacheTag bitAnd: 1 << objectMemory shiftForWord - 1) = 0
+ and: [cacheTag
+ between: 1 << objectMemory compactClassFieldLSB
+ and: (objectMemory compactClassIndexOfHeader: -1) << objectMemory compactClassFieldLSB])
+ or: [self checkValidObjectReference: cacheTag]]!
Item was changed:
----- Method: Cogit>>checkIfValidOopRef:pc:cogMethod: (in category 'garbage collection') -----
checkIfValidOopRef: annotation pc: mcpc cogMethod: cogMethod
<var: #mcpc type: #'char *'>
annotation = IsObjectReference ifTrue:
[| literal |
literal := backEnd literalBeforeFollowingAddress: mcpc asInteger.
(objectRepresentation checkValidOopReference: literal) ifFalse:
[coInterpreter print: 'object ref leak in CM '; printHex: cogMethod asInteger; print: ' @ '; printHex: mcpc asInteger; cr.
^1]].
(self isSendAnnotation: annotation) ifTrue:
[| entryPoint selectorOrCacheTag offset |
entryPoint := backEnd callTargetFromReturnAddress: mcpc asInteger.
entryPoint <= methodZoneBase
ifTrue:
[offset := entryPoint]
ifFalse:
[self
offsetAndSendTableFor: entryPoint
annotation: annotation
into: [:off :table| offset := off]].
selectorOrCacheTag := backEnd inlineCacheTagAt: mcpc asInteger.
(entryPoint > methodZoneBase
and: [offset ~= cmNoCheckEntryOffset
and: [(self cCoerceSimple: entryPoint - offset to: #'CogMethod *') cmType ~= CMOpenPIC]])
ifTrue: "linked non-super send, cacheTag is a cacheTag"
+ [(objectRepresentation validInlineCacheTag: selectorOrCacheTag) ifFalse:
- [(objectRepresentation checkValidInlineCacheTag: selectorOrCacheTag) ifFalse:
[coInterpreter print: 'cache tag leak in CM '; printHex: cogMethod asInteger; print: ' @ '; printHex: mcpc asInteger; cr.
^1]]
ifFalse: "unlinked send or super send; cacheTag is a selector"
[(objectRepresentation checkValidOopReference: selectorOrCacheTag) ifFalse:
[coInterpreter print: 'selector leak in CM '; printHex: cogMethod asInteger; print: ' @ '; printHex: mcpc asInteger; cr.
^1]]].
^0 "keep scanning"!
Item was changed:
----- Method: Cogit>>checkIfValidOopRefAndTarget:pc:cogMethod: (in category 'garbage collection') -----
checkIfValidOopRefAndTarget: annotation pc: mcpc cogMethod: cogMethod
<var: #mcpc type: #'char *'>
| literal entryPoint |
annotation = IsObjectReference ifTrue:
[literal := backEnd literalBeforeFollowingAddress: mcpc asInteger.
(self asserta: (objectRepresentation checkValidOopReference: literal)) ifFalse:
[^1].
((objectRepresentation couldBeObject: literal)
and: [objectMemory isReallyYoungObject: literal]) ifTrue:
[(self asserta: (self cCoerceSimple: cogMethod to: #'CogMethod *') cmRefersToYoung) ifFalse:
[^2]]].
(self isSendAnnotation: annotation) ifTrue:
[(self asserta: (self cCoerceSimple: cogMethod to: #'CogMethod *') cmType = CMMethod) ifFalse:
[^3].
self offsetCacheTagAndCouldBeObjectAt: mcpc annotation: annotation into:
[:offset :cacheTag :tagCouldBeObject|
tagCouldBeObject
ifTrue:
[(objectRepresentation couldBeObject: cacheTag)
ifTrue:
[(self asserta: (objectRepresentation checkValidOopReference: cacheTag)) ifFalse:
[^4]]
ifFalse:
+ [(self asserta: (objectRepresentation validInlineCacheTag: cacheTag)) ifFalse:
- [(self asserta: (objectRepresentation checkValidInlineCacheTag: cacheTag)) ifFalse:
[^5]].
((objectRepresentation couldBeObject: cacheTag)
and: [objectMemory isReallyYoungObject: cacheTag]) ifTrue:
[(self asserta: (self cCoerceSimple: cogMethod to: #'CogMethod *') cmRefersToYoung) ifFalse:
[^6]]]
ifFalse:
+ [(self asserta: (objectRepresentation validInlineCacheTag: cacheTag)) ifFalse:
- [(self asserta: (objectRepresentation checkValidInlineCacheTag: cacheTag)) ifFalse:
[^7]]].
entryPoint := backEnd callTargetFromReturnAddress: mcpc asInteger.
entryPoint > methodZoneBase ifTrue:
["It's a linked send; find which kind."
self targetMethodAndSendTableFor: entryPoint into:
[:targetMethod :sendTable|
(self asserta: (targetMethod cmType = CMMethod
or: [targetMethod cmType = CMClosedPIC
or: [targetMethod cmType = CMOpenPIC]])) ifFalse:
[^8]]]].
^0 "keep scanning"!
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 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)
- point: (objectMemory lengthOf: cPIC selector)
isMNUCase: isMNUCase.
self allocateOpcodes: 5 bytecodes: 0.
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:
[operand := 0.
+ target := (coInterpreter cogMethodOf: caseNMethod) asInteger + cmNoCheckEntryOffset]
- target := (coInterpreter cogMethodOf: caseNMethod) asInteger + cmNoCheckEntryOffset]
ifFalse:
[isMNUCase ifTrue:
[cPIC cpicHasMNUCase: true].
operand := caseNMethod.
target := cPIC asInteger
+ (isMNUCase
ifTrue: [self sizeof: CogMethod]
ifFalse: [self interpretOffset - backEnd callInstructionByteSize])].
self CmpCw: caseNTag R: TempReg.
self MoveCw: operand R: SendNumArgsReg.
self JumpLongZero: target.
self MoveCw: cPIC asInteger 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: address to: cPIC asInteger + closedPICSize.
cPIC cPICNumCases: cPIC cPICNumCases + 1.
^0!
Item was changed:
----- Method: Cogit>>cogMNUPICSelector:methodOperand:numArgs: (in category 'in-line cacheing') -----
cogMNUPICSelector: selector 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 headerSize size end |
(objectMemory isYoung: selector) ifTrue:
[^0].
coInterpreter
compilationBreak: selector
+ point: (objectMemory numBytesOf: selector)
- point: (objectMemory lengthOf: selector)
isMNUCase: true.
self assert: endCPICCase0 notNil.
startAddress := methodZone allocate: closedPICSize.
startAddress = 0 ifTrue:
[coInterpreter callForCogCompiledCodeCompaction.
^0].
methodLabel
address: startAddress;
dependent: nil.
"stack allocate the various collections so that they
are effectively garbage collected on return."
self allocateOpcodes: numPICCases * 7 bytecodes: 0.
self compileMNUCPIC: (self cCoerceSimple: startAddress to: #'CogMethod *')
methodOperand: methodOperand
numArgs: numArgs.
self computeMaximumSizes.
headerSize := self sizeof: CogMethod.
size := self generateInstructionsAt: startAddress + headerSize.
end := self outputInstructionsAt: startAddress + headerSize.
"The missOffset is the same as the interpretOffset."
self assert: missOffset = (interpretCall address + interpretCall machineCodeSize - startAddress).
self assert: startAddress + cmEntryOffset = entry address.
^self
fillInCPICHeader: (self cCoerceSimple: startAddress to: #'CogMethod *')
size: closedPICSize
numArgs: numArgs
numCases: 1
hasMNUCase: true
selector: selector !
Item was changed:
----- Method: Cogit>>cogOpenPICSelector:numArgs: (in category 'in-line cacheing') -----
cogOpenPICSelector: selector numArgs: numArgs
"Create an Open PIC. Temporarily create a direct call of ceSendFromOpenPIC:.
Should become a probe of the first-level method lookup cache followed by a
call of ceSendFromOpenPIC: if the probe fails."
<returnTypeC: #'CogMethod *'>
| startAddress headerSize codeSize mapSize end |
coInterpreter
compilationBreak: selector
+ point: (objectMemory numBytesOf: selector)
- point: (objectMemory lengthOf: selector)
isMNUCase: false.
startAddress := methodZone allocate: openPICSize.
startAddress = 0 ifTrue:
[^self cCoerceSimple: InsufficientCodeSpace to: #'CogMethod *'].
methodLabel
address: startAddress;
dependent: nil.
"stack allocate the various collections so that they
are effectively garbage collected on return."
self allocateOpcodes: 100 bytecodes: 0.
self compileOpenPIC: selector numArgs: numArgs.
self computeMaximumSizes.
methodLabel concretizeAt: startAddress.
headerSize := self sizeof: CogMethod.
codeSize := self generateInstructionsAt: startAddress + headerSize.
mapSize := self generateMapAt: startAddress + openPICSize - 1 start: startAddress + cmNoCheckEntryOffset.
self assert: entry address - startAddress = cmEntryOffset.
self assert: headerSize + codeSize + mapSize <= openPICSize.
end := self outputInstructionsAt: startAddress + headerSize.
^self
fillInOPICHeader: (self cCoerceSimple: startAddress to: #'CogMethod *')
size: openPICSize
numArgs: numArgs
selector: selector !
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 headerSize size end |
(objectMemory isYoung: selector) ifTrue:
[^self cCoerceSimple: YoungSelectorInPIC to: #'CogMethod *'].
coInterpreter
compilationBreak: selector
+ point: (objectMemory numBytesOf: selector)
- point: (objectMemory lengthOf: selector)
isMNUCase: isMNUCase.
startAddress := methodZone allocate: closedPICSize.
startAddress = 0 ifTrue:
[^self cCoerceSimple: InsufficientCodeSpace to: #'CogMethod *'].
methodLabel
address: startAddress;
dependent: nil.
"stack allocate the various collections so that they
are effectively garbage collected on return."
self allocateOpcodes: numPICCases * 7 bytecodes: 0.
self compileCPIC: (self cCoerceSimple: startAddress to: #'CogMethod *')
Case0: case0CogMethod
Case1Method: case1MethodOrNil
tag: case1Tag
isMNUCase: isMNUCase
numArgs: numArgs.
self computeMaximumSizes.
headerSize := self sizeof: CogMethod.
size := self generateInstructionsAt: startAddress + headerSize.
end := self outputInstructionsAt: startAddress + headerSize.
"The missOffset is th same as the interpretOffset."
self assert: missOffset = (interpretCall address + interpretCall 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 *')
size: closedPICSize
numArgs: numArgs
numCases: 2
hasMNUCase: isMNUCase
selector: selector !
Item was changed:
----- 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.
+ coInterpreter
+ compilationBreak: cPIC selector
+ point: (objectMemory numBytesOf: cPIC selector)
+ isMNUCase: isMNUCase.
self compilePICProlog: numArgs.
self assert: (objectRepresentation inlineCacheTagIsYoung: case1Tag) not.
(isMNUCase not
and: [coInterpreter methodHasCogMethod: case1Method])
ifTrue:
[operand := 0.
targetEntry := ((coInterpreter cogMethodOf: case1Method) asInteger + cmNoCheckEntryOffset) asVoidPointer]
ifFalse:
[self assert: (case1Method isNil or: [(objectMemory isYoungObject: case1Method) not]).
operand := case1Method.
targetEntry := case1Method isNil ifTrue: [mnuCall] ifFalse: [interpretLabel]].
jumpNext := self compileCPICEntry.
self MoveCw: 0 R: SendNumArgsReg.
self JumpLong: case0CogMethod asInteger + cmNoCheckEntryOffset.
endCPICCase0 := self CmpCw: case1Tag R: TempReg.
jumpNext jmpTarget: endCPICCase0.
self MoveCw: operand R: SendNumArgsReg.
self JumpLongZero: (isMNUCase ifTrue: [mnuCall] ifFalse: [targetEntry]) asInteger.
endCPICCase1 := self MoveCw: cPIC asInteger R: ClassReg.
self JumpLong: (self cPICMissTrampolineFor: numArgs).
^0
!
Item was changed:
----- 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 |
<var: #jumpNext type: #'AbstractInstruction *'>
+ coInterpreter
+ compilationBreak: cPIC selector
+ point: (objectMemory numBytesOf: cPIC selector)
+ isMNUCase: true.
self compilePICProlog: numArgs.
jumpNext := self compileCPICEntry.
self MoveCw: methodOperand R: SendNumArgsReg.
self JumpLong: mnuCall asInteger.
jumpNext jmpTarget: (self MoveCw: cPIC asInteger R: ClassReg).
self JumpLong: (self cPICMissTrampolineFor: numArgs).
^0
!
Item was changed:
----- Method: Cogit>>setSelectorOf:to: (in category 'jit - api') -----
setSelectorOf: cogMethod to: aSelectorOop
<api>
"If a method is compiled to machine code via a block entry it won't have a selector.
A subsequent send can find the method and hence fill in the selector."
<var: #cogMethod type: #'CogMethod *'>
"self disassembleMethod: cogMethod"
coInterpreter
compilationBreak: aSelectorOop
+ point: (objectMemory numBytesOf: aSelectorOop)
- point: (objectMemory lengthOf: aSelectorOop)
isMNUCase: false.
self assert: cogMethod cmType = CMMethod.
cogMethod selector: aSelectorOop.
(objectMemory isYoung: aSelectorOop) ifTrue:
[methodZone ensureInYoungReferrers: cogMethod]!
Item was added:
+ ----- Method: StackInterpreter>>lookupSelector:inClass: (in category 'debug support') -----
+ lookupSelector: selector inClass: class
+ "Lookup selector in class. Answer the method or nil. This is a debugging routine."
+ | currentClass dictionary |
+ <api>
+
+ currentClass := class.
+ [currentClass ~= objectMemory nilObject] whileTrue:
+ [dictionary := objectMemory followObjField: MethodDictionaryIndex ofObject: currentClass.
+ dictionary = objectMemory nilObject ifTrue:
+ [^nil].
+ (self lookupMethodFor: selector InDictionary: dictionary) ifNotNil:
+ [:meth| ^meth].
+ currentClass := self superclassOf: currentClass].
+ ^nil!
Item was changed:
+ ----- Method: StackInterpreter>>mnuBreak:point:receiver: (in category 'debug support') -----
- ----- Method: StackInterpreter>>mnuBreak:point:receiver: (in category 'debugging traps') -----
mnuBreak: selectorString point: selectorLength receiver: receiverOrNil
<doNotGenerate> "C version is in platforms/Cross/vm/dispdbg.h"
"self shortPrintFrameAndCallers: localFP"
| i |
breakSelectorLength negated = selectorLength ifTrue:
[i := breakSelectorLength negated.
[i > 0] whileTrue:
[(objectMemory byteAt: selectorString + i - 1) = (breakSelector at: i) asInteger
ifTrue: [(i := i - 1) = 0 ifTrue:
[self changed: #byteCountText.
self halt: 'MNU of '
, breakSelector,
(receiverOrNil
ifNotNil: [' to ', (self shortPrint: receiverOrNil)]
ifNil: [''])]]
ifFalse: [i := 0]]]!
Item was changed:
+ ----- Method: StackInterpreter>>sendBreak:point:receiver: (in category 'debug support') -----
- ----- Method: StackInterpreter>>sendBreak:point:receiver: (in category 'debugging traps') -----
sendBreak: selectorString point: selectorLength receiver: receiverOrNil
<doNotGenerate> "C version is in platforms/Cross/vm/dispdbg.h"
"self shortPrintFrameAndCallers: localFP"
| i |
breakSelectorLength = selectorLength ifTrue:
[i := breakSelectorLength.
[i > 0] whileTrue:
[(objectMemory byteAt: selectorString + i - 1) = (breakSelector at: i) asInteger
ifTrue: [(i := i - 1) = 0 ifTrue:
[self changed: #byteCountText.
self halt: 'Send of '
, breakSelector,
(receiverOrNil
ifNotNil: [' to ', (self shortPrint: receiverOrNil)]
ifNil: [''])]]
ifFalse: [i := 0]]]!
More information about the Vm-dev
mailing list