David T. Lewis uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker-dtl.315.mcz
==================== Summary ====================
Name: VMMaker-dtl.315 Author: dtl Time: 6 April 2013, 11:11:30.122 am UUID: 3fbadee2-b872-46a1-9b50-b95d04f7a9a0 Ancestors: VMMaker-dtl.314
VMMaker 4.11.5
Remove PixelValuePeekPlugin from defaultUnixSpec.
New SlangTest tests for loop limit code generation.
From VMMaker.oscog-eem.279 and VMMaker.oscog-eem.282:
Fix translation of to:by:do: loops so that the limit is not re-evaluated on each iteration if it may have side-effects. As part of this change make TMethod locals a Set, and sort only when emitting locals. Alas this causes a number of methods to change.
Fix SmartSyntaxPlugin support method affected by the fixes for generating to:by:do: loops in VMMaker.oscog-eem.279.
=============== Diff against VMMaker-dtl.314 ===============
Item was changed: ----- Method: CCodeGenerator>>generateToByDo:on:indent: (in category 'C translation') ----- generateToByDo: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." + "N.B. MessageNode>>asTranslatorNodeIn: adds the limit var as a hidden fourth argument." + | blockExpr iterationVar limitExpr mayHaveSideEffects limitVar step negative | + blockExpr := msgNode args third. + blockExpr args size = 1 ifFalse: + [self error: 'wrong number of block arguments']. + iterationVar := blockExpr args first. + limitExpr := msgNode args first. - - | iterationVar step negative | - (msgNode args last args size = 1) ifFalse: [ - self error: 'wrong number of block arguments'. - ]. - iterationVar := msgNode args last args first. aStream nextPutAll: 'for (', iterationVar, ' = '. self emitCExpression: msgNode receiver on: aStream. + mayHaveSideEffects := msgNode args size = 4. "See TMethod>>prepareMethodIn:" + mayHaveSideEffects ifTrue: + [limitVar := msgNode args last. + aStream nextPutAll: ', ', limitVar name, ' = '. + self emitCExpression: limitExpr on: aStream. + limitExpr := limitVar]. aStream nextPutAll: '; ', iterationVar. negative := ((step := msgNode args at: 2) isConstant and: [step value < 0]) or: [step isSend and: [step selector == #negated and: [step receiver isConstant and: [step receiver value >= 0]]]]. aStream nextPutAll: (negative ifTrue: [' >= '] ifFalse: [' <= ']). + self emitCExpression: limitExpr on: aStream. - self emitCExpression: msgNode args first on: aStream. aStream nextPutAll: '; ', iterationVar, ' += '. self emitCExpression: step on: aStream. aStream nextPutAll: ') {'; cr. + blockExpr emitCCodeOn: aStream level: level + 1 generator: self. + aStream tab: level. + aStream nextPut: $}! - msgNode args last emitCCodeOn: aStream level: level + 1 generator: self. - level timesRepeat: [ aStream tab ]. - aStream nextPutAll: '}'.!
Item was changed: ----- Method: MessageNode>>asTranslatorNodeIn: (in category '*VMMaker-C translation') ----- asTranslatorNodeIn: aTMethod "make a CCodeGenerator equivalent of me" "selector is sometimes a Symbol, sometimes a SelectorNode!! On top of this, numArgs is needed due to the (truly grody) use of arguments as a place to store the extra expressions needed to generate code for in-line to:by:do:, etc. see below, where it is used." + | rcvrOrNil sel args | + rcvrOrNil := receiver ifNotNil: [receiver asTranslatorNodeIn: aTMethod]. + (rcvrOrNil notNil + and: [rcvrOrNil isVariable + and: [rcvrOrNil name = 'super']]) ifTrue: + [^aTMethod superExpansionNodeFor: selector key args: arguments]. + sel := selector isSymbol ifTrue: [selector] ifFalse: [selector key]. + ((sel = #cCode:inSmalltalk: "extracting here rather than in translation allows inlining in the block." + or: [sel = #cCode:]) + and: [arguments first isBlockNode]) ifTrue: + [| block | + ^(block := arguments first asTranslatorNodeIn: aTMethod) statements size = 1 + ifTrue: [block statements first] + ifFalse: [block]]. - | sel args | - sel := (selector isSymbol) ifTrue: [selector] ifFalse: [selector key]. args := (1 to: sel numArgs) collect: [:i | (arguments at: i) asTranslatorNodeIn: aTMethod]. + (sel = #to:by:do: and: [arguments size = 7 and: [(arguments at: 7) notNil]]) ifTrue: + ["Restore limit expr that got moved by transformToDo:" + args := {(arguments at: 7) value asTranslatorNodeIn: aTMethod. + args second. + args third. "add the limit var as a hidden extra argument; we may need it later" + TVariableNode new setName: arguments first key}]. + ((sel = #ifFalse: or: [sel = #or:]) + and: [arguments size = 2 and: [(arguments at: 2) notNil]]) ifTrue: + ["Restore argument block that got moved by transformOr: or transformIfFalse:" + args at: 1 put: ((arguments at: 2) asTranslatorNodeIn: aTMethod)]. + ^TSendNode new - (sel = #to:by:do: and: [arguments size = 7 and: [(arguments at: 7) notNil]]) - ifTrue: ["Restore limit expr that got moved by transformToDo:" - args at: 1 put: ((arguments at: 7) value asTranslatorNodeIn: aTMethod)]. - (sel = #or: and: [arguments size = 2 and: [(arguments at: 2) notNil]]) - ifTrue: ["Restore argument block that got moved by transformOr:" - args at: 1 put: ((arguments at: 2) asTranslatorNodeIn: aTMethod)]. - (sel = #ifFalse: and: [arguments size = 2 and: [(arguments at: 2) notNil]]) - ifTrue: ["Restore argument block that got moved by transformIfFalse:" - args at: 1 put: ((arguments at: 2) asTranslatorNodeIn: aTMethod)]. - ^ TSendNode new setSelector: sel + receiver: rcvrOrNil - receiver: (receiver ~~ nil ifTrue: [receiver asTranslatorNodeIn: aTMethod]) arguments: args!
Item was added: + ----- Method: SlangTest>>testCallMethodEmbeddedWithSendInLoopLimit (in category 'testing loop limits') ----- + testCallMethodEmbeddedWithSendInLoopLimit + "A loop embedded in a loop with two loop limit variables generated" + + "(SlangTest selector: #testCallMethodEmbeddedWithSendInLoopLimit) debug" + + | m1 sts lines | + sts := SlangTestSupportInterpreter inline: true. + m1 := (sts asCString: #callMethodEmbeddedWithSendInLoopLimit) + copyReplaceAll: 'callMethodEmbeddedWithSendInLoopLimit' + with: 'methodName'. + lines := m1 findTokens: String cr. + self should: (lines select: [:e | '*sqInt *LimiT*' match: e]) size = 2. + self should: (lines select: [:e | 'sqInt iLimiT;' = e withBlanksTrimmed]) size = 1. + self should: (lines select: [:e | 'sqInt kLimiT;' = e withBlanksTrimmed]) size = 1. + + sts := SlangTestSupportPlugin inline: true. + m1 := (sts asCString: #callMethodEmbeddedWithSendInLoopLimit) + copyReplaceAll: 'callMethodEmbeddedWithSendInLoopLimit' + with: 'methodName'. + lines := m1 findTokens: String cr. + self should: (lines select: [:e | '*sqInt *LimiT*' match: e]) size = 2. + self should: (lines select: [:e | 'sqInt iLimiT;' = e withBlanksTrimmed]) size = 1. + self should: (lines select: [:e | 'sqInt kLimiT;' = e withBlanksTrimmed]) size = 1. + + sts := SlangTestSupportSSIP inline: true. + m1 := (sts asCString: #callMethodEmbeddedWithSendInLoopLimit) + copyReplaceAll: 'callMethodEmbeddedWithSendInLoopLimit' + with: 'methodName'. + lines := m1 findTokens: String cr. + self should: (lines select: [:e | '*sqInt *LimiT*' match: e]) size = 2. + self should: (lines select: [:e | 'sqInt iLimiT;' = e withBlanksTrimmed]) size = 1. + self should: (lines select: [:e | 'sqInt kLimiT;' = e withBlanksTrimmed]) size = 1.!
Item was added: + ----- Method: SlangTest>>testCallMethodTwiceWithLoopLimitThatMightBeModified (in category 'testing loop limits') ----- + testCallMethodTwiceWithLoopLimitThatMightBeModified + "Two calls to a method with loop that might be modified generates a distinct + loop limit variable for each." + + "(SlangTest selector: #testCallMethodTwiceWithLoopLimitThatMightBeModified) debug" + + | m1 sts lines | + sts := SlangTestSupportInterpreter inline: true. + m1 := (sts asCString: #callMethodTwiceWithLoopLimitThatMightBeModified) + copyReplaceAll: 'callMethodTwiceWithLoopLimitThatMightBeModified' + with: 'methodName'. + lines := m1 findTokens: String cr. + self should: (lines select: [:e | '*sqInt *LimiT*' match: e]) size = 2. + self should: (lines select: [:e | 'sqInt iLimiT;' = e withBlanksTrimmed]) size = 1. + self should: (lines select: [:e | 'sqInt iLimiT1;' = e withBlanksTrimmed]) size = 1. + + sts := SlangTestSupportSSIP inline: true. + m1 := (sts asCString: #callMethodTwiceWithLoopLimitThatMightBeModified) + copyReplaceAll: 'callMethodTwiceWithLoopLimitThatMightBeModified' + with: 'methodName'. + lines := m1 findTokens: String cr. + self should: (lines select: [:e | '*sqInt *LimiT*' match: e]) size = 2. + self should: (lines select: [:e | 'sqInt iLimiT;' = e withBlanksTrimmed]) size = 1. + self should: (lines select: [:e | 'sqInt iLimiT1;' = e withBlanksTrimmed]) size = 1. + !
Item was added: + ----- Method: SlangTest>>testCallMethodTwiceWithSendInLoopLimit (in category 'testing loop limits') ----- + testCallMethodTwiceWithSendInLoopLimit + "Two calls to a method with loop with loop limit that is a method send can + share the same loop limit variable." + + "(SlangTest selector: #testCallMethodTwiceWithSendInLoopLimit) debug" + + | m1 sts lines | + sts := SlangTestSupportInterpreter inline: true. + m1 := (sts asCString: #callMethodTwiceWithSendInLoopLimit) + copyReplaceAll: 'callMethodTwiceWithSendInLoopLimit' + with: 'methodName'. + lines := m1 findTokens: String cr. + self should: (lines select: [:e | '*sqInt *LimiT*' match: e]) size = 1. + self should: (lines select: [:e | 'sqInt iLimiT;' = e withBlanksTrimmed]) size = 1. + + sts := SlangTestSupportPlugin inline: true. + m1 := (sts asCString: #callMethodTwiceWithSendInLoopLimit) + copyReplaceAll: 'callMethodTwiceWithSendInLoopLimit' + with: 'methodName'. + lines := m1 findTokens: String cr. + self should: (lines select: [:e | '*sqInt *LimiT*' match: e]) size = 1. + self should: (lines select: [:e | 'sqInt iLimiT;' = e withBlanksTrimmed]) size = 1. + + sts := SlangTestSupportSSIP inline: true. + m1 := (sts asCString: #callMethodTwiceWithSendInLoopLimit) + copyReplaceAll: 'callMethodTwiceWithSendInLoopLimit' + with: 'methodName'. + lines := m1 findTokens: String cr. + self should: (lines select: [:e | '*sqInt *LimiT*' match: e]) size = 1. + self should: (lines select: [:e | 'sqInt iLimiT;' = e withBlanksTrimmed]) size = 1. + !
Item was added: + ----- Method: SlangTest>>testCallMethodWithLoopLimitThatIsNotModified (in category 'testing loop limits') ----- + testCallMethodWithLoopLimitThatIsNotModified + "A call to a method with loop with a constant loop limit does not require a + loop limit variable." + + "(SlangTest selector: #testCallMethodTwiceWithSendInLoopLimit) debug" + + | m1 sts lines | + sts := SlangTestSupportInterpreter inline: true. + m1 := (sts asCString: #callMethodWithLoopLimitThatIsNotModified) + copyReplaceAll: 'callMethodWithLoopLimitThatIsNotModified' + with: 'methodName'. + lines := m1 findTokens: String cr. + self should: (lines select: [:e | '*sqInt *LimiT*' match: e]) size = 0. + self should: (lines select: [:e | 'for (i = 0; i <= 10; i += 1) {' = e withBlanksTrimmed]) size = 1. + + sts := SlangTestSupportPlugin inline: true. + m1 := (sts asCString: #callMethodWithLoopLimitThatIsNotModified) + copyReplaceAll: 'callMethodWithLoopLimitThatIsNotModified' + with: 'methodName'. + lines := m1 findTokens: String cr. + self should: (lines select: [:e | '*sqInt *LimiT*' match: e]) size = 0. + self should: (lines select: [:e | 'for (i = 0; i <= 10; i += 1) {' = e withBlanksTrimmed]) size = 1. + + sts := SlangTestSupportSSIP inline: true. + m1 := (sts asCString: #callMethodWithLoopLimitThatIsNotModified) + copyReplaceAll: 'callMethodWithLoopLimitThatIsNotModified' + with: 'methodName'. + lines := m1 findTokens: String cr. + self should: (lines select: [:e | '*sqInt *LimiT*' match: e]) size = 0. + self should: (lines select: [:e | 'for (i = 0; i <= 10; i += 1) {' = e withBlanksTrimmed]) size = 1. + !
Item was added: + ----- Method: SlangTest>>testCallMethodWithLoopLimitThatMightBeModified (in category 'testing loop limits') ----- + testCallMethodWithLoopLimitThatMightBeModified + "A call to a method with loop with a loop limit that might be modified by the loop + body requires a loop limit variable." + + "(SlangTest selector: #testCallMethodWithLoopLimitThatMightBeModified) debug" + + | m1 sts lines | + sts := SlangTestSupportInterpreter inline: true. + m1 := (sts asCString: #callMethodWithLoopLimitThatMightBeModified) + copyReplaceAll: 'callMethodWithLoopLimitThatMightBeModified' + with: 'methodName'. + lines := m1 findTokens: String cr. + self should: (lines select: [:e | '*sqInt *LimiT*' match: e]) size = 1. + self should: (lines select: [:e | 'sqInt iLimiT;' = e withBlanksTrimmed]) size = 1. + + sts := SlangTestSupportPlugin inline: true. + m1 := (sts asCString: #callMethodWithLoopLimitThatMightBeModified) + copyReplaceAll: 'callMethodWithLoopLimitThatMightBeModified' + with: 'methodName'. + lines := m1 findTokens: String cr. + self should: (lines select: [:e | '*sqInt *LimiT*' match: e]) size = 1. + self should: (lines select: [:e | 'sqInt iLimiT;' = e withBlanksTrimmed]) size = 1. + + sts := SlangTestSupportSSIP inline: true. + m1 := (sts asCString: #callMethodWithLoopLimitThatMightBeModified) + copyReplaceAll: 'callMethodWithLoopLimitThatMightBeModified' + with: 'methodName'. + lines := m1 findTokens: String cr. + self should: (lines select: [:e | '*sqInt *LimiT*' match: e]) size = 1. + self should: (lines select: [:e | 'sqInt iLimiT;' = e withBlanksTrimmed]) size = 1. + !
Item was added: + ----- Method: SlangTestSupportInterpreter>>callMethodEmbeddedWithSendInLoopLimit (in category 'loop limits') ----- + callMethodEmbeddedWithSendInLoopLimit + + <export: true> + 1 to: self methodWithIntegerResult do: [:i | + 1 to: self methodWithIntegerResult do: [:k | ]]. + !
Item was added: + ----- Method: SlangTestSupportInterpreter>>callMethodTwiceWithLoopLimitThatMightBeModified (in category 'loop limits') ----- + callMethodTwiceWithLoopLimitThatMightBeModified + + <export: true> + | aVar | + aVar := 'foo'. + self methodWithLoopLimitThatMightBeModified: aVar. + self methodWithLoopLimitThatMightBeModified: aVar. + !
Item was added: + ----- Method: SlangTestSupportInterpreter>>callMethodTwiceWithSendInLoopLimit (in category 'loop limits') ----- + callMethodTwiceWithSendInLoopLimit + + <export: true> + 1 to: self methodWithIntegerResult do: [:i | ]. + 1 to: self methodWithIntegerResult do: [:i | ]. + !
Item was added: + ----- Method: SlangTestSupportInterpreter>>callMethodWithLoopLimitThatIsNotModified (in category 'loop limits') ----- + callMethodWithLoopLimitThatIsNotModified + + <export: true> + | aVar | + aVar := 'foo'. + self methodWithLoopLimitThatIsNotModified: aVar. + !
Item was added: + ----- Method: SlangTestSupportInterpreter>>callMethodWithLoopLimitThatMightBeModified (in category 'loop limits') ----- + callMethodWithLoopLimitThatMightBeModified + + <export: true> + | aVar | + aVar := 'foo'. + self methodWithLoopLimitThatMightBeModified: aVar. + !
Item was added: + ----- Method: SlangTestSupportInterpreter>>methodWithIntegerResult (in category 'loop limits') ----- + methodWithIntegerResult + "Translates to nonsense, but use this to illustrate the point" + ^(Random new next * 100) asInteger!
Item was added: + ----- Method: SlangTestSupportInterpreter>>methodWithLoopLimitThatIsNotModified: (in category 'loop limits') ----- + methodWithLoopLimitThatIsNotModified: arrayObj + + 0 to: 10 do: [:i | self storePointerUnchecked: i ofObject: arrayObj withValue: nilObj] + !
Item was added: + ----- Method: SlangTestSupportInterpreter>>methodWithLoopLimitThatMightBeModified: (in category 'loop limits') ----- + methodWithLoopLimitThatMightBeModified: arrayObj + + 0 to: (self lengthOf: arrayObj) do: + [:i | self storePointerUnchecked: i ofObject: arrayObj withValue: nilObj] + !
Item was added: + ----- Method: SlangTestSupportPlugin>>callMethodEmbeddedWithSendInLoopLimit (in category 'loop limits') ----- + callMethodEmbeddedWithSendInLoopLimit + + <export: true> + 1 to: self methodWithIntegerResult do: [:i | + 1 to: self methodWithIntegerResult do: [:k | ]]. + !
Item was added: + ----- Method: SlangTestSupportPlugin>>callMethodTwiceWithLoopLimitThatMightBeModified (in category 'loop limits') ----- + callMethodTwiceWithLoopLimitThatMightBeModified + + <export: true> + | aVar | + aVar := 'foo'. + self methodWithLoopLimitThatMightBeModified: aVar. + self methodWithLoopLimitThatMightBeModified: aVar. + !
Item was added: + ----- Method: SlangTestSupportPlugin>>callMethodTwiceWithSendInLoopLimit (in category 'loop limits') ----- + callMethodTwiceWithSendInLoopLimit + + <export: true> + 1 to: self methodWithIntegerResult do: [:i | ]. + 1 to: self methodWithIntegerResult do: [:i | ]. + !
Item was added: + ----- Method: SlangTestSupportPlugin>>callMethodWithLoopLimitThatIsNotModified (in category 'loop limits') ----- + callMethodWithLoopLimitThatIsNotModified + + <export: true> + | aVar | + aVar := 'foo'. + self methodWithLoopLimitThatIsNotModified: aVar. + !
Item was added: + ----- Method: SlangTestSupportPlugin>>callMethodWithLoopLimitThatMightBeModified (in category 'loop limits') ----- + callMethodWithLoopLimitThatMightBeModified + + <export: true> + | aVar | + aVar := 'foo'. + self methodWithLoopLimitThatMightBeModified: aVar. + !
Item was added: + ----- Method: SlangTestSupportPlugin>>methodWithIntegerResult (in category 'loop limits') ----- + methodWithIntegerResult + "Translates to nonsense, but use this to illustrate the point" + ^(Random new next * 100) asInteger!
Item was added: + ----- Method: SlangTestSupportPlugin>>methodWithLoopLimitThatIsNotModified: (in category 'loop limits') ----- + methodWithLoopLimitThatIsNotModified: arrayObj + + 0 to: 10 do: [:i | self storePointerUnchecked: i ofObject: arrayObj withValue: nilObj] + !
Item was added: + ----- Method: SlangTestSupportPlugin>>methodWithLoopLimitThatMightBeModified: (in category 'loop limits') ----- + methodWithLoopLimitThatMightBeModified: arrayObj + + 0 to: (self lengthOf: arrayObj) do: + [:i | self storePointerUnchecked: i ofObject: arrayObj withValue: nil] + !
Item was added: + ----- Method: SlangTestSupportSSIP>>callMethodEmbeddedWithSendInLoopLimit (in category 'loop limits') ----- + callMethodEmbeddedWithSendInLoopLimit + + <export: true> + 1 to: self methodWithIntegerResult do: [:i | + 1 to: self methodWithIntegerResult do: [:k | ]]. + !
Item was added: + ----- Method: SlangTestSupportSSIP>>callMethodTwiceWithLoopLimitThatMightBeModified (in category 'loop limits') ----- + callMethodTwiceWithLoopLimitThatMightBeModified + + <export: true> + | aVar | + aVar := 'foo'. + self methodWithLoopLimitThatMightBeModified: aVar. + self methodWithLoopLimitThatMightBeModified: aVar. + !
Item was added: + ----- Method: SlangTestSupportSSIP>>callMethodTwiceWithSendInLoopLimit (in category 'loop limits') ----- + callMethodTwiceWithSendInLoopLimit + + <export: true> + 1 to: self methodWithIntegerResult do: [:i | ]. + 1 to: self methodWithIntegerResult do: [:i | ]. + !
Item was added: + ----- Method: SlangTestSupportSSIP>>callMethodWithLoopLimitThatIsNotModified (in category 'loop limits') ----- + callMethodWithLoopLimitThatIsNotModified + + <export: true> + | aVar | + aVar := 'foo'. + self methodWithLoopLimitThatIsNotModified: aVar. + !
Item was added: + ----- Method: SlangTestSupportSSIP>>callMethodWithLoopLimitThatMightBeModified (in category 'loop limits') ----- + callMethodWithLoopLimitThatMightBeModified + + <export: true> + | aVar | + aVar := 'foo'. + self methodWithLoopLimitThatMightBeModified: aVar. + !
Item was added: + ----- Method: SlangTestSupportSSIP>>methodWithIntegerResult (in category 'loop limits') ----- + methodWithIntegerResult + ^127 + 5!
Item was added: + ----- Method: SlangTestSupportSSIP>>methodWithLoopLimitThatIsNotModified: (in category 'loop limits') ----- + methodWithLoopLimitThatIsNotModified: arrayObj + + 0 to: 10 do: [:i | self storePointerUnchecked: i ofObject: arrayObj withValue: nilObj] + !
Item was added: + ----- Method: SlangTestSupportSSIP>>methodWithLoopLimitThatMightBeModified: (in category 'loop limits') ----- + methodWithLoopLimitThatMightBeModified: arrayObj + + 0 to: (self lengthOf: arrayObj) do: + [:i | self storePointerUnchecked: i ofObject: arrayObj withValue: nil] + !
Item was changed: ----- Method: TMethod>>prepareMethodIn: (in category 'transformations') ----- prepareMethodIn: aCodeGen + "Record sends of builtin operators, map sends of the special selector dispatchOn:in: + with case statement nodes, and map sends of caseOf:[otherwise:] to switch statements. + Note: Only replaces top-level sends of dispatchOn:in: et al and caseOf:[otherwise:]. + These must be top-level statements; they cannot appear in expressions. + As a hack also update the types of variables introduced to implement cascades correctly. + This has to be done at teh same time as this is done, so why not piggy back here?" + | replacements |. + cascadeVariableNumber ifNotNil: + [declarations keysAndValuesDo: + [:varName :decl| + decl isBlock ifTrue: + [self assert: ((varName beginsWith: 'cascade') and: [varName last isDigit]). + locals add: varName. + self declarationAt: varName + put: (decl value: self value: aCodeGen), ' ', varName]]]. + replacements := IdentityDictionary new. + aCodeGen + pushScope: declarations + while: + [parseTree nodesDo: + [:node| + node isSend ifTrue: + [(aCodeGen builtin: node selector) + ifTrue: + [node isBuiltinOperator: true. + "If a to:by:do:'s limit has side-effects, declare the limit variable, otherwise delete it from the args" + (node selector = #to:by:do: + and: [node args size = 4]) ifTrue: + [| limitExpr | + limitExpr := node args first. + (limitExpr anySatisfy: + [:subNode| + subNode isSend + and: [(aCodeGen builtin: subNode selector) not + and: [(subNode isStructSend: aCodeGen) not]]]) + ifTrue: [ | limitVar | + limitVar := node args last name. + "n.b. Two loops in the same method may share the same variable + for loop limit, so add the variable declaration only if not already + declared by a previous loop. Assumes that the name of the loop + limit variable (e.g. 'iLimiT') is unlikely to have been used as an actual + instance variable elsewhere." + (locals includes: limitVar) ifFalse: [locals add: limitVar]] + ifFalse: + [node arguments: node args allButLast]]] + ifFalse: + [(CaseStatements includes: node selector) ifTrue: + [replacements at: node put: (self buildCaseStmt: node)]. + (#(caseOf: #caseOf:otherwise:) includes: node selector) ifTrue: + [replacements at: node put: (self buildSwitchStmt: node)]]]. + ((node isAssignment or: [node isReturn]) + and: [node expression isSwitch]) ifTrue: + [replacements at: node put: (self transformSwitchExpression: node)]]]. + replacements isEmpty ifFalse: + [parseTree := parseTree replaceNodesIn: replacements]! - "Record sends of builtin operators and replace sends of the special selector dispatchOn:in: with case statement nodes." - "Note: Only replaces top-level sends of dispatchOn:in:. Case statements must be top-level statements; they cannot appear in expressions." - - | stmts stmt | - parseTree nodesDo: [ :node | - node isSend ifTrue: [ - "record sends of builtin operators" - (aCodeGen builtin: node selector) ifTrue: [ node isBuiltinOperator: true ]. - ]. - node isStmtList ifTrue: [ - "replace dispatchOn:in: with case statement node" - stmts := node statements. - 1 to: stmts size do: [ :i | - stmt := stmts at: i. - (stmt isSend and: [CaseStatements includes: stmt selector]) ifTrue: [ - stmts at: i put: (self buildCaseStmt: stmt). - ]. - ]. - ]. - ].!
Item was changed: ----- Method: TMethod>>preparePrimitivePrologue (in category 'primitive compilation') ----- preparePrimitivePrologue "Add a prolog and postlog to a primitive method. The prolog copies any instance variables referenced by this primitive method into local variables. The postlog copies values of assigned-to variables back into the instance. The names of the new locals are added to the local variables list.
The declarations dictionary defines the types of any non-integer variables (locals, arguments, or instance variables). In particular, it may specify the types:
int * -- an array of 32-bit values (e.g., a BitMap) short * -- an array of 16-bit values (e.g., a SoundBuffer) char * -- an array of unsigned bytes (e.g., a String) double -- a double precision floating point number (e.g., 3.14159)
Undeclared variables are taken to be integers and will be converted from Smalltalk to C ints."
"Current restrictions: o method must not contain message sends o method must not allocate objects o method must not manipulate raw oops o method cannot access class variables o method can only return an integer"
| prolog postlog instVarsUsed varsAssignedTo instVarList primArgCount varName endsWithReturn aClass | + self assert: selector ~~ #setInterpreter:. - selector == #setInterpreter: ifTrue:[self halt]. aClass := definingClass. prolog := OrderedCollection new. postlog := OrderedCollection new. instVarsUsed := self freeVariableReferences asSet. varsAssignedTo := self variablesAssignedTo asSet. instVarList := aClass allInstVarNames. primArgCount := args size.
"add receiver fetch and arg conversions to prolog" prolog addAll: self fetchRcvrExpr. 1 to: args size do: [:argIndex | varName := args at: argIndex. prolog addAll: (self argConversionExprFor: varName stackIndex: args size - argIndex)].
"add success check to postlog" postlog addAll: self checkSuccessExpr.
"add instance variable fetches to prolog and instance variable stores to postlog" 1 to: instVarList size do: [:varIndex | varName := instVarList at: varIndex. (instVarsUsed includes: varName) ifTrue: [ locals add: varName. prolog addAll: (self instVarGetExprFor: varName offset: varIndex - 1). (varsAssignedTo includes: varName) ifTrue: [ postlog addAll: (self instVarPutExprFor: varName offset: varIndex - 1)]]]. prolog addAll: self checkSuccessExpr.
+ ((locals includes: 'rcvr') or: [(locals intersection: args) notEmpty]) ifTrue: + [self error: 'local name conflicts with instance variable name']. + locals add: 'rcvr'; addAll: args. - locals addAllFirst: args. - locals addFirst: 'rcvr'. args := args class new. - locals asSet size = locals size - ifFalse: [self error: 'local name conflicts with instance variable name']. endsWithReturn := self endsWithReturn. self fixUpReturns: primArgCount postlog: postlog.
endsWithReturn ifTrue: [parseTree setStatements: prolog, parseTree statements] ifFalse: [ postlog addAll: (self popArgsExpr: primArgCount). parseTree setStatements: prolog, parseTree statements, postlog]. !
Item was added: + ----- Method: TParseNode>>anySatisfy: (in category 'enumerating') ----- + anySatisfy: aBlock + self nodesDo: [:n| (aBlock value: n) ifTrue: [^true]]. + ^false!
Item was added: + ----- Method: TParseNode>>noneSatisfy: (in category 'enumerating') ----- + noneSatisfy: aBlock + self nodesDo: [:n| (aBlock value: n) ifTrue: [^false]]. + ^true!
Item was added: + ----- Method: TSendNode>>arguments: (in category 'private') ----- + arguments: aSequence + arguments := aSequence!
Item was changed: + ----- Method: TSendNode>>printOn:level: (in category 'printing') ----- - ----- Method: TSendNode>>printOn:level: (in category 'testing') ----- printOn: aStream level: level + | possiblyParenthesize | + possiblyParenthesize := + [:node :newLevel| + (node isSend + and: [node selector precedence >= 3]) ifTrue: + [aStream nextPut: $(]. + node printOn: aStream level: newLevel. + (node isSend + and: [node selector precedence >= 3]) ifTrue: + [aStream nextPut: $)]].
+ possiblyParenthesize value: receiver value: level. + arguments size = 0 ifTrue: + [aStream space; nextPutAll: selector. + ^self]. + selector keywords with: (arguments first: selector numArgs) do: + [:keyword :arg | + aStream space; nextPutAll: keyword; space. + possiblyParenthesize value: arg value: level + 1]! - | keywords | - receiver printOn: aStream level: level. - arguments size = 0 ifTrue: [ - aStream space; nextPutAll: selector. - ^self - ]. - keywords := selector keywords. - 1 to: keywords size do: [ :i | - aStream space. - aStream nextPutAll: (keywords at: i); space. - (arguments at: i) printOn: aStream level: level + 1. - ].!
Item was changed: ----- Method: VMMaker class>>versionString (in category 'version testing') ----- versionString
"VMMaker versionString"
+ ^'4.11.5'! - ^'4.11.4'!
Item was changed: ----- Method: VMMakerTool class>>defaultUnixSpec (in category 'configurations') ----- defaultUnixSpec "Typical VMMaker spec for a unix/linux target platform"
"VMMakerTool defaultUnixSpec"
^#( #( "internal plugins" #ADPCMCodecPlugin #AsynchFilePlugin #BMPReadWriterPlugin #BalloonEnginePlugin #BitBltSimulation #CroquetPlugin #DSAPlugin #DeflatePlugin #DropPlugin #FFTPlugin #FT2Plugin #FilePlugin #FloatArrayPlugin #FloatMathPlugin #GeniePlugin #JPEGReadWriter2Plugin #JPEGReaderPlugin #JoystickTabletPlugin #KlattSynthesizerPlugin #LargeIntegersPlugin #LocalePlugin #MD5Plugin #Matrix2x3Plugin #MiscPrimitivePlugin #RandPlugin #RePlugin #SHA256Plugin #SecurityPlugin #SerialPlugin #SlangTestPlugin #SlangTestSupportPlugin #SocketPlugin #SoundCodecPlugin #SoundGenerationPlugin #SoundPlugin #StarSqueakPlugin #SurfacePlugin ) #( "external plugins" #B3DAcceleratorPlugin #B3DEnginePlugin #ClipboardExtendedPlugin #DBusPlugin #FFIPlugin #FileCopyPlugin #GStreamerPlugin #HostWindowPlugin #KedamaPlugin #KedamaPlugin2 #MIDIPlugin #Mpeg3Plugin #RomePlugin #UUIDPlugin #UnixAioPlugin #UnixOSProcessPlugin #XDisplayControlPlugin #CameraPlugin #ScratchPlugin #UnicodePlugin #WeDoPlugin #SqueakSSLPlugin - #PixelValuePeekPlugin ) true "inline flag" false "forBrowser flag" 'unix' "platform" 'src' "source directory for generated sources" 'platforms' "path to platform sources" 4 "unused, was bytesPerWord which is now a compile time definition" true "unused, was flag for source directtory pathname is relative" true "unused, was flag for platforms directory path is relative" 'Interpreter' "interpreter class name" )!
vm-dev@lists.squeakfoundation.org