Skip to content

WIP - Build simple Cogit #944

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: pharo-12
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions smalltalksrc/VMMaker/PharoVMMaker.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,14 @@ PharoVMMaker >> generatePlugins: anObject [
generatePlugins := anObject
]

{ #category : 'generation' }
PharoVMMaker >> generateSimple [

self generates64Bits ifTrue: [ self generate: CoInterpreter memoryManager: Spur64BitCoMemoryManager compilerClass: SimpleStackBasedCogit ].
self generates32Bits ifTrue: [ self generate: CoInterpreter memoryManager: Spur32BitCoMemoryManager compilerClass: SimpleStackBasedCogit ].

]

{ #category : 'generation' }
PharoVMMaker >> generateStackVM [

Expand Down
184 changes: 183 additions & 1 deletion smalltalksrc/VMMaker/SimpleStackBasedCogit.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ Class {
'externalPrimJumpOffsets',
'externalSetPrimOffsets',
'introspectionDataIndex',
'introspectionData'
'introspectionData',
'counterIndex'
],
#pools : [
'VMClassIndices',
Expand Down Expand Up @@ -189,6 +190,12 @@ SimpleStackBasedCogit class >> initializeBytecodeTableForSistaV1 [
(3 254 255 unknownBytecode))
]

{ #category : 'translation' }
SimpleStackBasedCogit class >> mustBeGlobalInFile: var [

^ #( #aMethodLabel #generatorTable ) includes: var
]

{ #category : 'class initialization' }
SimpleStackBasedCogit class >> table: primArray from: specArray [
"Fill in the specified entries in the primitive table."
Expand Down Expand Up @@ -3007,6 +3014,35 @@ SimpleStackBasedCogit >> picAbortTrampolineFor: numArgs [
^cePICAbortTrampoline
]

{ #category : 'method introspection' }
SimpleStackBasedCogit >> populate: tuple withPICInfoFor: cPIC firstCacheTag: firstCacheTag [
"Populate tuple (which must be large enough) with the ClosedPIC's target method class pairs.
The first entry in tuple contains the bytecode pc for the send, so skip the tuple's first field."
<var: #cPIC type: #'CogMethod *'>
| picCaseMachineCodePC cacheTag classOop entryPoint targetMethod value |
<var: #targetMethod type: #'CogMethod *'>

1 to: cPIC cPICNumCases do: [:i|
picCaseMachineCodePC := self addressOfEndOfCase: i inCPIC: cPIC.
cacheTag := i = 1
ifTrue: [firstCacheTag]
ifFalse: [backEnd literalBeforeFollowingAddress: picCaseMachineCodePC - backEnd jumpLongConditionalByteSize].

classOop := objectRepresentation classForInlineCacheTag: cacheTag.
objectMemory storePointer: i * 2 - 1 ofObject: tuple withValue: classOop.
entryPoint := i = 1
ifTrue: [backEnd jumpLongTargetBeforeFollowingAddress: picCaseMachineCodePC]
ifFalse: [backEnd jumpLongConditionalTargetBeforeFollowingAddress: picCaseMachineCodePC].
"Find target from jump. A jump to the MNU entry-point should collect #doesNotUnderstand:"
(cPIC containsAddress: entryPoint)
ifTrue: [ value := objectMemory splObj: SelectorDoesNotUnderstand ]
ifFalse: [
targetMethod := self cCoerceSimple: entryPoint - cmNoCheckEntryOffset to: #'CogMethod *'.
self assert: targetMethod cmType = CMMethod.
value := targetMethod methodObject ].
objectMemory storePointer: i * 2 ofObject: tuple withValue: value ]
]

{ #category : 'primitive generators' }
SimpleStackBasedCogit >> primitiveDescriptor [
"If there is a generator for the current primitive then answer it;
Expand Down Expand Up @@ -3065,6 +3101,152 @@ SimpleStackBasedCogit >> primitivePropertyFlags: primIndex primitiveDescriptor:
^baseFlags
]

{ #category : 'method introspection' }
SimpleStackBasedCogit >> profilingDataFor: descriptor Annotation: isBackwardBranchAndAnnotation Mcpc: mcpc Bcpc: bcpc Method: cogMethodArg [
<var: #descriptor type: #'BytecodeDescriptor *'>
<var: #mcpc type: #'char *'>
<var: #cogMethodArg type: #'void *'>
<var: #methodClassIfSuper type: #'sqInt'>
| annotation entryPoint tuple counter |
"N.B. Counters are always 32-bits, having two 16-bit halves for the reached and taken counts."
<var: #counter type: #'unsigned int'>

descriptor ifNil:
[^0].
descriptor isBranch ifTrue:
["it's a branch; conditional?"
(descriptor isBranchTrue or: [descriptor isBranchFalse]) ifTrue: [ | counters |
counters := self
cCoerce: ((self
cCoerceSimple: cogMethodArg
to: #'CogMethod *') counters)
to: #'usqInt *'.
"If no counters are available, do not record counters"
counters = 0 ifTrue: [ ^ 0 ].

counter := counters at: counterIndex.
tuple := self profilingDataForCounter: counter at: bcpc + 1.
tuple = 0 ifTrue: [^PrimErrNoMemory].
objectMemory
storePointer: introspectionDataIndex
ofObject: introspectionData
withValue: tuple.
introspectionDataIndex := introspectionDataIndex + 1.
counterIndex := counterIndex + 1].
^0].

annotation := isBackwardBranchAndAnnotation >> 1.
((self isPureSendAnnotation: annotation)
and: [entryPoint := backEnd callTargetFromReturnAddress: mcpc asUnsignedInteger.
entryPoint > methodZoneBase]) ifFalse: "send is not linked, or is not a send"
[^0].

"It's a linked send; find which kind."
self targetMethodAndSendTableFor: entryPoint
annotation: annotation
into: [:targetCogCode :sendTable| | methodClassIfSuper association |
methodClassIfSuper := nil.
sendTable = superSendTrampolines ifTrue: [
methodClassIfSuper := coInterpreter methodClassOf: (self cCoerceSimple: cogMethodArg to: #'CogMethod *') methodObject.
].
sendTable = directedSuperSendTrampolines ifTrue: [
association := backEnd literalBeforeInlineCacheTagAt: mcpc asUnsignedInteger.
methodClassIfSuper := objectRepresentation valueOfAssociation: association ].
tuple := self profilingDataForSendTo: targetCogCode
methodClassIfSuper: methodClassIfSuper
at: mcpc
bcpc: bcpc + 1].

tuple = 0 ifTrue: [^PrimErrNoMemory].
objectMemory
storePointer: introspectionDataIndex
ofObject: introspectionData
withValue: tuple.
introspectionDataIndex := introspectionDataIndex + 1.
^0
]

{ #category : 'method introspection' }
SimpleStackBasedCogit >> profilingDataFor: cogMethod into: arrayObj [

"Collect the branch and send data for cogMethod, storing it into arrayObj."

<api>
<var: #cogMethod type: #'CogMethod *'>
| errCode |
"If the method is frameless, it has no message sends. No need to continue."
cogMethod stackCheckOffset = 0 ifTrue: [ ^ 0 ].

introspectionDataIndex := counterIndex := 0.
introspectionData := arrayObj.
errCode := self
mapFor: (self cCoerceSimple: cogMethod to: #'CogMethod *')
bcpc: (coInterpreter startPCOfMethod: cogMethod methodObject)
performUntil: #profilingDataFor:Annotation:Mcpc:Bcpc:Method:
arg: cogMethod asVoidPointer.
errCode ~= 0 ifTrue: [
self assert: errCode = PrimErrNoMemory.
^ -1 ].
^ introspectionDataIndex
]

{ #category : 'method introspection' }
SimpleStackBasedCogit >> profilingDataForCounter: counter at: bcpc [
"Undefined by now, do nothing"

^ 0
]

{ #category : 'method introspection' }
SimpleStackBasedCogit >> profilingDataForSendTo: cogCodeSendTarget methodClassIfSuper: methodClassOrNil at: sendMcpc bcpc: sendBcpc [
"Answer a tuple with the send data for a linked send to cogMethod.
If the target is a CogMethod (monomorphic send) answer
{ bytecode pc, inline cache class, target method }
If the target is an open PIC (megamorphic send) answer
{ bytecode pc, nil, send selector }
If the target is a closed PIC (polymorphic send) answer
{ bytecode pc, first class, target method, second class, second target method, ... }"
<var: #cogCodeSendTarget type: #'CogMethod *'>
<var: #sendMcpc type: #'char *'>
| tuple class |
tuple := objectMemory
eeInstantiateClassIndex: ClassArrayCompactIndex
format: objectMemory arrayFormat
numSlots: (cogCodeSendTarget cmType = CMPolymorphicIC
ifTrue: [2 * cogCodeSendTarget cPICNumCases + 1]
ifFalse: [3]).
tuple = 0 ifTrue:
[^0].

objectMemory storePointerUnchecked: 0 ofObject: tuple withValue: (objectMemory integerObjectOf: sendBcpc).

"Monomorphic - linked against a single method"
cogCodeSendTarget cmType = CMMethod ifTrue: [
"If it is not a super send, we don't have a class, let's extract it from the call site"
class := methodClassOrNil ifNil: [
objectRepresentation classForInlineCacheTag: (backEnd inlineCacheTagAt: sendMcpc asUnsignedInteger)].
objectMemory
storePointer: 1 ofObject: tuple withValue: class;
storePointer: 2 ofObject: tuple withValue: cogCodeSendTarget methodObject.
^tuple ].

cogCodeSendTarget cmType = CMPolymorphicIC ifTrue: [
self
populate: tuple
withPICInfoFor: cogCodeSendTarget
firstCacheTag: (backEnd inlineCacheTagAt: sendMcpc asUnsignedInteger).
^tuple ].

cogCodeSendTarget cmType = CMMegamorphicIC ifTrue: [
objectMemory
storePointerUnchecked: 1 ofObject: tuple withValue: objectMemory nilObject;
storePointer: 2 ofObject: tuple withValue: cogCodeSendTarget selector.
^tuple ].

self error: 'invalid method type'.
^0 "to get Slang to type this method as answering sqInt"
]

{ #category : 'bytecode generator support' }
SimpleStackBasedCogit >> putSelfInReceiverResultReg [
<inline: true>
Expand Down
Loading