[Vm-dev] VM Maker: VMMaker.oscog-eem.2050.mcz
commits at source.squeak.org
commits at source.squeak.org
Tue Dec 27 03:16:58 UTC 2016
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2050.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.2050
Author: eem
Time: 26 December 2016, 7:16:12.441075 pm
UUID: d45b0fc7-802c-400f-a433-5d4c1941fdfd
Ancestors: VMMaker.oscog-eem.2049
Slang:
Fix inlining bugs due to an overcomplex and inaccurate completion check.
Specifically:
- inlineableFunctionCall:in: & inlineableSend:in: must see if a method wants to be inlined, so that completeness can be computed properly.
- fix slips in tryToInlineMethodsIn: exiting too soon and always setting complete in a macro.
- refactor checkForCompleteness:in: to checkForCompletenessIn: and simplify, setting complete if no incomplete send is found, rather than assuming completeness and then looking for inlineability, which is wrong.
Have collectInlineList: set inline to false (rather than nil) if using asSpecified or asSpecifiedOrQuick.
Fix pruneUnreachableMethods: to not delete <api> methods.
Add cppIf:ifTrue: to statementsListsForInliningIn:'s filtering out.
Slightly more flexible generateTruncateTo:on:indent:,probably not needed due to inlining fixes, but is goodness.
Fix mis-initialization on code generation by setting the vmClass's objectmemoryClass's initializationOptions before asking it for its ancilliary classes.
Spur:
Include the compactorClass's exportAPISelectors:.
Revert some now unnecessary <inline: #always> to <inline: true>.
Declare savedFirstFieldsSpace correctly.
Declatre the compactor's default return type correctly.
General:
Add printMethodImplementorsOf: for debugging.
=============== Diff against VMMaker.oscog-eem.2049 ===============
Item was changed:
----- Method: CCodeGenerator>>collectInlineList: (in category 'inlining') -----
collectInlineList: inlineFlagOrSymbol
"Make a list of methods that should be inlined. If inlineFlagOrSymbol == #asSpecified
only inline methods marked with <inline: true>. If inlineFlagOrSymbol == #asSpecifiedOrQuick
only inline methods marked with <inline: true> or methods that are quick (^constant, ^inst var)."
"Details: The method must not include any inline C, since the
translator cannot currently map variable names in inlined C code.
Methods to be inlined must be small or called from only one place."
| selectorsOfMethodsNotToInline callsOf |
self assert: (#(true false asSpecified asSpecifiedOrQuick) includes: inlineFlagOrSymbol).
selectorsOfMethodsNotToInline := Set new: methods size.
selectorsOfMethodsNotToInline addAll: macros keys.
apiMethods ifNotNil:
[selectorsOfMethodsNotToInline addAll: apiMethods keys].
methods do:
[:m|
m isStructAccessor ifTrue:
[selectorsOfMethodsNotToInline add: m selector]].
"build dictionary to record the number of calls to each method"
callsOf := Dictionary new: methods size * 2.
methods keysAndValuesDo:
[:s :m|
(m isRealMethod
and: [self shouldGenerateMethod: m]) ifTrue:
[callsOf at: s put: 0]].
"For each method, scan its parse tree once or twice to:
1. determine if the method contains unrenamable C code or declarations or has a C builtin
2. determine how many nodes it has
3. increment the sender counts of the methods it calls"
inlineList := Set new: methods size * 2.
(methods reject: [:m| selectorsOfMethodsNotToInline includes: m selector]) do:
[:m| | inlineIt hasUnrenamableCCode nodeCount |
((breakSrcInlineSelectors includes: m selector)
and: [breakOnInline isNil]) ifTrue:
[self halt].
inlineIt := #dontCare.
(translationDict includesKey: m selector)
ifTrue: [hasUnrenamableCCode := true]
ifFalse:
[hasUnrenamableCCode := m hasUnrenamableCCode.
nodeCount := 0.
m parseTree nodesDo:
[:node|
node isSend ifTrue:
[callsOf
at: node selector
ifPresent:
[:senderCount| callsOf at: node selector put: senderCount + 1]].
nodeCount := nodeCount + 1].
inlineIt := m extractInlineDirective]. "may be true, false, #always, #never or #dontCare"
(hasUnrenamableCCode or: [inlineIt == false])
ifTrue: "don't inline if method has C code or contains negative inline directive"
[inlineIt == true ifTrue:
[logger
ensureCr;
nextPutAll: 'failed to inline ';
nextPutAll: m selector;
nextPutAll: ' as it contains unrenamable C declarations or C code';
cr; flush].
selectorsOfMethodsNotToInline add: m selector]
ifFalse:
[(inlineFlagOrSymbol caseOf: {
[#asSpecified] -> [inlineIt == true].
[#asSpecifiedOrQuick] -> [inlineIt == true or: [m compiledMethod isQuick]].
[true] -> [nodeCount < 40 or: [inlineIt == true]].
[false] -> [false]})
ifTrue: "inline if method has no C code and is either small or contains inline directive"
[inlineList add: m selector]
ifFalse:
[(#(asSpecified asSpecifiedOrQuick) includes: inlineFlagOrSymbol) ifTrue:
[selectorsOfMethodsNotToInline add: m selector]]]].
+ (#(asSpecified asSpecifiedOrQuick) includes: inlineFlagOrSymbol)
+ ifTrue:
+ [methods do: [:m| m inline ifNil: [m inline: (inlineList includes: m selector)]]]
+ ifFalse:
+ [callsOf associationsDo:
+ [:assoc|
+ (assoc value = 1
+ and: [(selectorsOfMethodsNotToInline includes: assoc key) not]) ifTrue:
+ [inlineList add: assoc key]]]!
- (#(asSpecified asSpecifiedOrQuick) includes: inlineFlagOrSymbol) ifFalse:
- [callsOf associationsDo:
- [:assoc|
- (assoc value = 1
- and: [(selectorsOfMethodsNotToInline includes: assoc key) not]) ifTrue:
- [inlineList add: assoc key]]]!
Item was changed:
----- Method: CCodeGenerator>>generateTruncateTo:on:indent: (in category 'C translation') -----
generateTruncateTo: msgNode on: aStream indent: level
"Generate the C code for this message onto the given stream."
+ | arg |
+ (self isConstantNode: msgNode args first valueInto: [:a| arg := a]) ifFalse:
+ [self error: 'can''t find method for inlining truncateTo:'].
+ self assert: (arg isInteger and: [arg isPowerOfTwo]).
- self assert: msgNode args first isConstant.
- self assert: msgNode args first value isInteger.
- self assert: msgNode args first value isPowerOfTwo.
aStream nextPut: $(.
self emitCExpression: msgNode receiver on: aStream.
+ aStream nextPutAll: ' & ~'; print: arg - 1; nextPut: $)!
- aStream nextPutAll: ' & ~'; print: msgNode args first value - 1; nextPut: $)!
Item was added:
+ ----- Method: CCodeGenerator>>maybeBreakForTestOfInliningOf: (in category 'inlining') -----
+ maybeBreakForTestOfInliningOf: aNodeOrSelector
+ "convenient for debugging..."
+ | selector |
+ selector := aNodeOrSelector isSymbol
+ ifTrue: [aNodeOrSelector]
+ ifFalse:
+ [aNodeOrSelector isSend
+ ifTrue: [aNodeOrSelector selector]
+ ifFalse: [^self]].
+ ((breakSrcInlineSelectors includes: selector)
+ and: [breakDestInlineSelectors isEmpty
+ and: [breakOnInline == true]]) ifTrue:
+ [self halt: selector]!
Item was changed:
----- Method: CCodeGenerator>>pruneUnreachableMethods (in category 'inlining') -----
pruneUnreachableMethods
"Remove any methods that are not reachable. Retain methods needed by the translated classes - see implementors of requiredMethodNames"
| neededSelectors newMethods previousSize visited |
"add all the exported methods and all the called methods to the requiredSelectors"
"keep all the fake methods (macros and struct accessors; these are needed
to ensure correct code generation."
neededSelectors := Set withAll: requiredSelectors.
methods do: [ :m |
m export ifTrue:
[neededSelectors add: m selector].
+ m isAPIMethod ifTrue:
+ [neededSelectors add: m selector].
m isRealMethod ifFalse:
[neededSelectors add: m selector]].
"Now compute the transitive closure..."
previousSize := neededSelectors size.
visited := IdentitySet new: methods size.
[neededSelectors do:
[:s|
(methods at: s ifAbsent: []) ifNotNil:
[:m|
(visited includes: m) ifFalse:
[visited add: m.
(m isRealMethod
and: [self shouldGenerateMethod: m]) ifTrue:
[neededSelectors addAll: m allCalls]]]].
neededSelectors size > previousSize]
whileTrue:
[previousSize := neededSelectors size].
"build a new dictionary of methods from the collection of all the ones to keep"
newMethods := Dictionary new: neededSelectors size.
neededSelectors do:
[:sel|
methods at: sel ifPresent: [:meth| newMethods at: sel put: meth]].
methods := newMethods!
Item was added:
+ ----- Method: ObjectMemory>>printMethodImplementorsOf: (in category 'debug printing') -----
+ printMethodImplementorsOf: anOop
+ "Scan the heap printing the oops of any and all methods that implement anOop"
+ <api>
+ | obj |
+ obj := self firstAccessibleObject.
+ [obj = nil] whileFalse:
+ [((self isCompiledMethod: obj)
+ and: [(self maybeSelectorOfMethod: obj) = anOop]) ifTrue:
+ [self printHex: obj; space; printOopShort: obj; cr]]!
Item was changed:
----- Method: Spur32BitCoMemoryManager class>>exportAPISelectors: (in category 'translation') -----
exportAPISelectors: options
^(Set withAll: (self exportAPISelectorsFor: self))
addAll: (SpurGenerationScavenger exportAPISelectors: options);
+ addAll: (self compactorClass exportAPISelectors: options);
yourself!
Item was changed:
----- Method: Spur64BitCoMemoryManager class>>exportAPISelectors: (in category 'translation') -----
exportAPISelectors: options
^(Set withAll: (self exportAPISelectorsFor: self))
addAll: (SpurGenerationScavenger exportAPISelectors: options);
+ addAll: (self compactorClass exportAPISelectors: options);
yourself!
Item was added:
+ ----- Method: SpurMemoryManager>>printMethodImplementorsOf: (in category 'debug printing') -----
+ printMethodImplementorsOf: anOop
+ "Scan the heap printing the oops of any and all methods that implement anOop"
+ <api>
+ self allObjectsDo:
+ [:obj|
+ ((self isCompiledMethod: obj)
+ and: [(coInterpreter maybeSelectorOfMethod: obj) = anOop]) ifTrue:
+ [coInterpreter printHex: obj; space; printOopShort: obj; cr]]!
Item was changed:
----- Method: SpurMemoryManager>>slidingCompactionShouldRemapObj: (in category 'gc - scavenge/compact') -----
slidingCompactionShouldRemapObj: objOop
+ <inline: true>
- <inline: #always>
"Answer if the obj should be scavenged, or simply followed. Sent via the compactor
from shouldRemapObj:. We test for being already scavenged because mapStackPages
via mapInterpreterOops may be applied twice in the context of a global GC where a
scavenge, followed by a scan-mark-free, and final compaction passes may result in
scavenged fields being visited twice."
^(self isForwarded: objOop)
or: [gcPhaseInProgress > 0 "Hence either scavengeInProgress or slidingCompactionInProgress"
and: [self scavengeInProgress
ifTrue: [(self isReallyYoungObject: objOop)
and: [(self isInFutureSpace: objOop) not]]
ifFalse: [compactor isMobile: objOop]]]!
Item was changed:
----- Method: SpurMemoryManager>>vanillaShouldRemapObj: (in category 'gc - scavenge/compact') -----
vanillaShouldRemapObj: objOop
+ <inline: true>
- <inline: #always>
"Answer if the obj should be scavenged, or simply followed. Sent via the compactor
from shouldRemapObj:. We test for being already scavenged because mapStackPages
via mapInterpreterOops may be applied twice in the context of a global GC where a
scavenge, followed by a scan-mark-free, and final compaction passes may result in
scavenged fields being visited twice."
^(self isForwarded: objOop)
or: [(self isReallyYoungObject: objOop)
and: [(self isInFutureSpace: objOop) not]]!
Item was added:
+ ----- Method: SpurPigCompactor class>>implicitReturnTypeFor: (in category 'translation') -----
+ implicitReturnTypeFor: aSelector
+ "Answer the return type for methods that don't have an explicit return."
+ ^#void!
Item was added:
+ ----- Method: SpurPlanningCompactor class>>declareCVarsIn: (in category 'translation') -----
+ declareCVarsIn: aCCodeGenerator
+ aCCodeGenerator var: 'savedFirstFieldsSpace' type: #SpurContiguousObjStack!
Item was added:
+ ----- Method: SpurPlanningCompactor class>>implicitReturnTypeFor: (in category 'translation') -----
+ implicitReturnTypeFor: aSelector
+ "Answer the return type for methods that don't have an explicit return."
+ ^#void!
Item was changed:
----- Method: SpurPlanningCompactor>>copyAndUnmarkObject:to:firstField: (in category 'compaction') -----
copyAndUnmarkObject: o to: toFinger firstField: firstField
"Copy the object to toFinger, clearing its mark bit and restoring its firstField, which was overwritten with a forwarding pointer.
Answer the number of bytes in the object, including overflow header."
+ <inline: true>
- <inline: #always>
| bytes numSlots destObj start |
numSlots := manager rawNumSlotsOf: o.
destObj := (manager objectWithRawSlotsHasOverflowHeader: numSlots)
ifTrue: [toFinger + manager baseHeaderSize]
ifFalse: [toFinger].
bytes := manager bytesInObject: o given: numSlots.
start := manager startOfObject: o given: numSlots.
manager
mem: toFinger asVoidPointer cp: start asVoidPointer y: bytes;
setIsMarkedOf: destObj to: false;
storePointerUnchecked: 0 ofObject: destObj withValue: firstField.
^bytes!
Item was changed:
----- Method: SpurPlanningCompactor>>isMobile: (in category 'private') -----
isMobile: obj
+ <inline: true>
- <inline: #always>
^(self oop: obj isGreaterThanOrEqualTo: firstMobileObject andLessThanOrEqualTo: lastMobileObject)
and: [(manager isPinned: obj) not]!
Item was changed:
----- Method: SpurPlanningCompactor>>shouldRemapObj: (in category 'gc - scavenge/compact') -----
shouldRemapObj: objOop
- <api>
"Answer if the obj should be scavenged, or simply followed. Sent via the compactor
from shouldRemapObj:. We test for being already scavenged because mapStackPages
via mapInterpreterOops may be applied twice in the context of a global GC where a
scavenge, followed by a scan-mark-free, and final compaction passes may result in
scavenged fields being visited twice."
+ <api>
+ <inline: false>
^manager slidingCompactionShouldRemapObj: objOop!
Item was changed:
----- Method: SpurPlanningCompactor>>updatePointersFrom:to:in: (in category 'compaction') -----
updatePointersFrom: start to: finish in: obj
+ <inline: true>
- <inline: #always>
start to: finish do:
[:i| | oop fwd |
oop := manager fetchPointer: i ofObject: obj.
((manager isNonImmediate: oop) and: [self isMobile: oop]) ifTrue:
[self assert: (manager isMarked: oop).
fwd := manager fetchPointer: 0 ofObject: oop.
self assert: (self isPostMobile: fwd).
manager storePointerUnchecked: i ofObject: obj withValue: fwd]]!
Item was removed:
- ----- Method: TMethod>>checkForCompleteness:in: (in category 'inlining') -----
- checkForCompleteness: stmtLists in: aCodeGen
- "Set the complete flag if none of the given statement list nodes contains further candidates for inlining."
-
- complete := true.
- stmtLists do:
- [:stmtList|
- stmtList statements do:
- [:node|
- [(self inlineableSend: node in: aCodeGen) ifTrue:
- [complete := false. "more inlining to do"
- ^self]]]].
-
- parseTree
- nodesDo:
- [:node|
- (self inlineableFunctionCall: node in: aCodeGen) ifTrue:
- [complete := false. "more inlining to do"
- ^self]]
- unless:
- [:node|
- node isSend
- and: [node selector == #cCode:inSmalltalk:
- or: [aCodeGen isAssertSelector: node selector]]]!
Item was added:
+ ----- Method: TMethod>>checkForCompletenessIn: (in category 'inlining support') -----
+ checkForCompletenessIn: aCodeGen
+ "Set the complete flag if the parse tree contains no further candidates for inlining."
+ | foundIncompleteSend incompleteSends |
+ aCodeGen maybeBreakForTestOfInliningOf: selector.
+
+ foundIncompleteSend := false.
+ incompleteSends := IdentitySet new.
+
+ parseTree
+ nodesDo:
+ [:node|
+ node isSend ifTrue:
+ [(self methodIsEffectivelyComplete: node selector in: aCodeGen)
+ ifTrue:
+ [(self inlineableFunctionCall: node in: aCodeGen) ifTrue:
+ [complete := false. "more inlining to do"
+ ^self]]
+ ifFalse:
+ [foundIncompleteSend := true.
+ incompleteSends add: node]]]
+ unless:
+ [:node|
+ node isSend
+ and: [node selector == #cCode:inSmalltalk:
+ or: [aCodeGen isAssertSelector: node selector]]].
+
+ foundIncompleteSend ifFalse:
+ [complete := true]!
Item was added:
+ ----- Method: TMethod>>incompleteSendsIn: (in category 'inlining support') -----
+ incompleteSendsIn: aCodeGen
+ "Debugging support; answer the incomplete and inlineable sends in the receiver."
+ | incompleteSends inlineableSends |
+ aCodeGen maybeBreakForTestOfInliningOf: selector.
+
+ incompleteSends := IdentitySet new.
+ inlineableSends := IdentitySet new.
+
+ parseTree
+ nodesDo:
+ [:node|
+ node isSend ifTrue:
+ [(self methodIsEffectivelyComplete: node selector in: aCodeGen)
+ ifTrue:
+ [(self inlineableFunctionCall: node in: aCodeGen) ifTrue:
+ [inlineableSends add: node]]
+ ifFalse:
+ [incompleteSends add: node]]]
+ unless:
+ [:node|
+ node isSend
+ and: [node selector == #cCode:inSmalltalk:
+ or: [aCodeGen isAssertSelector: node selector]]].
+
+ ^{incompleteSends. inlineableSends}!
Item was added:
+ ----- Method: TMethod>>inline: (in category 'accessing') -----
+ inline: aBoolean
+ inline := aBoolean!
Item was changed:
----- Method: TMethod>>inlineableFunctionCall:in: (in category 'inlining') -----
inlineableFunctionCall: aNode in: aCodeGen
"Answer if the given send node is a call to a 'functional' method--a method whose body is a single return statement of some expression and whose actual parameters can all be directly substituted."
aCodeGen maybeBreakForTestToInline: aNode in: self.
aNode isSend ifFalse:
[^false].
^(aCodeGen methodNamed: aNode selector)
ifNil:
[aNode asTransformedConstantPerform
ifNil: [self isInlineableConditional: aNode in: aCodeGen]
ifNotNil: [:n| self inlineableFunctionCall: n in: aCodeGen]]
ifNotNil:
[:m|
(m ~~ self
+ and: [(m isFunctionalIn: aCodeGen)
+ and: [m mayBeInlined
- and: [(m isFunctionalIn: aCodeGen)
and: [(aCodeGen mayInline: m selector)
+ and: [aNode args allSatisfy: [:a| self isSubstitutableNode: a intoMethod: m in: aCodeGen]]]]])
- and: [aNode args allSatisfy: [:a| self isSubstitutableNode: a intoMethod: m in: aCodeGen]]]])
or: [m checkForRequiredInlinability]]!
Item was changed:
----- Method: TMethod>>inlineableSend:in: (in category 'inlining') -----
inlineableSend: aNode in: aCodeGen
"Answer if the given send node is a call to a method that can be inlined."
| m |
aCodeGen maybeBreakForTestToInline: aNode in: self.
aNode isSend ifFalse: [^false].
m := aCodeGen methodNamed: aNode selector. "nil if builtin or external function"
^m ~= nil
and: [m ~~ self
+ and: [m mayBeInlined
and: [(m isComplete and: [aCodeGen mayInline: m selector])
+ or: [m checkForRequiredInlinability]]]]!
- or: [m checkForRequiredInlinability]]]!
Item was added:
+ ----- Method: TMethod>>mayBeInlined (in category 'accessing') -----
+ mayBeInlined
+ ^inline == true or: [inline == nil or: [inline == #always]]!
Item was added:
+ ----- Method: TMethod>>methodIsEffectivelyComplete:in: (in category 'inlining support') -----
+ methodIsEffectivelyComplete: selector in: aCodeGen
+ "Answer if selector is effectively not inlineable in the receiver.
+ This is tricky because block inlining requires that certain methods must be inlined, which
+ can be at odds wuth the opportunistic strategy the inliner takes. Since the inliner only
+ inlines complete methods and certain methods may never be marked as complete (e.g.
+ recursive methods) we have to short-cut certain kinds of send. In particular, short-cut
+ sends that turn into jumps in the interpret routine (sharedCase and sharedLabel below)."
+ ^(aCodeGen methodNamed: selector)
+ ifNil: [true] "builtins or externals are not inlineable"
+ ifNotNil:
+ [:m|
+ m isComplete
+ "unlinable methods can't be inlined"
+ or: [m mayBeInlined not
+ "Methods which are inlined as jumps don't need inlining"
+ or: [m sharedCase notNil or: [m sharedLabel notNil]]]]!
Item was changed:
----- Method: TMethod>>statementsListsForInliningIn: (in category 'inlining') -----
statementsListsForInliningIn: aCodeGen
"Answer a collection of statement list nodes that are candidates for inlining.
Currently, we cannot inline into the argument blocks of and: and or: messages.
We do not want to inline code strings within cCode:inSmalltalk: blocks (those with a
proper block for the cCode: argument are inlined in MessageNode>>asTranslatorNodeIn:).
We do not want to inline code within assert: sends (because we want the assert to read nicely)."
| stmtLists |
stmtLists := OrderedCollection new: 10.
parseTree
nodesDo:
[:node|
node isStmtList ifTrue: [stmtLists add: node]]
unless:
[:node|
node isSend
and: [node selector == #cCode:inSmalltalk:
or: [aCodeGen isAssertSelector: node selector]]].
parseTree nodesDo:
[:node|
node isSend ifTrue:
[node selector = #cCode:inSmalltalk: ifTrue:
[node nodesDo:
[:ccisNode| stmtLists remove: ccisNode ifAbsent: []]].
+ (node selector = #cppIf:ifTrue:ifFalse: or: [node selector = #cppIf:ifTrue:]) ifTrue:
- node selector = #cppIf:ifTrue:ifFalse: ifTrue:
[node args first nodesDo:
[:inCondNode| stmtLists remove: inCondNode ifAbsent: []]].
((node selector = #and:) or: [node selector = #or:]) ifTrue:
"Note: the PP 2.3 compiler produces two arg nodes for these selectors"
[stmtLists remove: node args first ifAbsent: [].
stmtLists remove: node args last ifAbsent: []].
(#( #ifTrue: #ifFalse: #ifTrue:ifFalse: #ifFalse:ifTrue:
#ifNil: #ifNotNil: #ifNil:ifNotNil: #ifNotNil:ifNil: ) includes: node selector) ifTrue:
[stmtLists remove: node receiver ifAbsent: []].
(#(whileTrue whileTrue: whilefalse whileFalse:) includes: node selector) ifTrue:
"Allow inlining if it is a [...] whileTrue/whileFalse.
This is identified by having more than one statement in the
receiver block in which case the C code wouldn't work anyways"
[node receiver statements size = 1 ifTrue:
[stmtLists remove: node receiver ifAbsent: []]].
(node selector = #to:do:) ifTrue:
[stmtLists remove: node receiver ifAbsent: [].
stmtLists remove: node args first ifAbsent: []].
(node selector = #to:by:do:) ifTrue:
[stmtLists remove: node receiver ifAbsent: [].
stmtLists remove: node args first ifAbsent: [].
stmtLists remove: node args second ifAbsent: []]].
node isCaseStmt ifTrue: "don't inline cases"
[node cases do: [:case| stmtLists remove: case ifAbsent: []]]].
^stmtLists!
Item was changed:
----- Method: TMethod>>tryToInlineMethodsIn: (in category 'inlining') -----
tryToInlineMethodsIn: aCodeGen
"Expand any (complete) inline methods sent by this method.
Set the complete flag when all inlining has been done.
Answer if something was inlined."
| didSomething statementLists |
+ "complete ifTrue:
+ [^false]."
+
self definedAsMacro ifTrue:
+ [complete ifTrue:
+ [^false].
+ ^complete := true].
+
- [complete := true.
- ^false].
didSomething := self tryToInlineMethodStatementsIn: aCodeGen statementListsInto: [:stmtLists| statementLists := stmtLists].
didSomething := (self tryToInlineMethodExpressionsIn: aCodeGen) or: [didSomething].
didSomething ifTrue:
+ [writtenToGlobalVarsCache := nil].
- [writtenToGlobalVarsCache := nil.
- ^didSomething].
complete ifFalse:
+ [self checkForCompletenessIn: aCodeGen.
- [self checkForCompleteness: statementLists in: aCodeGen.
complete ifTrue: [didSomething := true]]. "marking a method complete is progress"
^didSomething!
Item was changed:
----- Method: VMMaker>>buildCodeGeneratorForInterpreter:includeAPIMethods:initializeClasses: (in category 'generate sources') -----
buildCodeGeneratorForInterpreter: interpreterClass includeAPIMethods: getAPIMethods initializeClasses: initializeClasses
"Answer the code generator for translating the interpreter."
| cg interpreterClasses |
initializeClasses ifTrue:
[interpreterClass initializeWithOptions: optionsDictionary.
interpreterClass hasCogit ifTrue:
+ [interpreterClass cogitClass initializeWithOptions: optionsDictionary].
+ interpreterClass objectMemoryClass initializationOptions: optionsDictionary].
- [interpreterClass cogitClass initializeWithOptions: optionsDictionary]].
(cg := self createCodeGenerator) vmClass: interpreterClass.
"Construct interpreterClasses as all classes from interpreterClass &
objectMemoryClass up to VMClass in superclass to subclass order."
interpreterClasses := OrderedCollection new.
{interpreterClass. interpreterClass objectMemoryClass} do:
[:vmClass| | theClass |
theClass := vmClass.
[theClass ~~ VMClass] whileTrue:
+ [theClass initializationOptions: optionsDictionary.
+ interpreterClasses addFirst: theClass.
- [interpreterClasses addFirst: theClass.
theClass := theClass superclass]].
interpreterClasses
addFirst: VMClass;
addAllLast: (cg nonStructClassesForTranslationClasses: interpreterClasses).
initializeClasses ifTrue:
[interpreterClasses do:
[:ic|
(ic respondsTo: #initializeWithOptions:)
ifTrue: [ic initializeWithOptions: optionsDictionary]
ifFalse: [ic initialize]].
(cg structClassesForTranslationClasses: interpreterClasses) do:
[:structClass| structClass initialize]].
cg addStructClasses: (cg structClassesForTranslationClasses: interpreterClasses).
interpreterClasses do: [:ic| cg addClass: ic].
getAPIMethods ifTrue:
[interpreterClass cogitClass ifNotNil:
[:cogitClass|
cg includeAPIFrom: (self
buildCodeGeneratorForCogit: cogitClass
includeAPIMethods: false
initializeClasses: false)]].
^cg!
More information about the Vm-dev
mailing list