author | Jan Vrany <jan.vrany@fit.cvut.cz> |
Mon, 15 Feb 2010 17:55:26 +0000 | |
changeset 28 | 2eab5fdb9467 |
parent 27 | 45902cde2ab1 |
child 29 | 2f154b67e1e8 |
IRBuilderTest.st | file | annotate | diff | comparison | revisions | |
IRDecompiler.st | file | annotate | diff | comparison | revisions | |
IRFunction.st | file | annotate | diff | comparison | revisions | |
cvut_stx_goodies_newcompiler.st | file | annotate | diff | comparison | revisions | |
extensions.st | file | annotate | diff | comparison | revisions |
--- a/IRBuilderTest.st Mon Dec 28 16:20:44 2009 +0000 +++ b/IRBuilderTest.st Mon Feb 15 17:55:26 2010 +0000 @@ -186,10 +186,10 @@ !IRBuilderTest methodsFor:'testing'! -halt +error "Redefinition for testing the #send:toSuperOf:" - "Created: / 11-06-2008 / 16:08:52 / Jan Vrany <vranyj1@fel.cvut.cz>" + "Created: / 15-02-2010 / 16:20:57 / Jan Vrany <jan.vrany@fit.cvut.cz>" ! isThisEverCalled @@ -668,7 +668,7 @@ numRargs:1; addTemps:#( #self ); pushReceiver; - send:#halt toSuperOf:IRBuilderTest; + send:#error toSuperOf:IRBuilderTest; returnTop; ir. aCompiledMethod := iRMethod compiledCode. @@ -680,6 +680,7 @@ raise:Error. "Modified: / 11-06-2008 / 16:09:12 / Jan Vrany <vranyj1@fel.cvut.cz>" + "Modified: / 15-02-2010 / 16:20:44 / Jan Vrany <jan.vrany@fit.cvut.cz>" ! testStorIntoVariable
--- a/IRDecompiler.st Mon Dec 28 16:20:44 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1305 +0,0 @@ -"{ Package: 'cvut:stx/goodies/newcompiler' }" - -IRInterpreter subclass:#IRDecompiler - instanceVariableNames:'stack sp scope currentInstr valueLabelMap mapEmptyStatement' - classVariableNames:'' - poolDictionaries:'' - category:'NewCompiler-IR' -! - -IRDecompiler comment:'I interpret IRMethod instructions and generate a Smalltalk abstract syntax tree rooted at a RBMethodNode. -This is implemented like a shift-reduce parser. Each instruction either causes a node to be pushed on the stack (shift), or causes one or more nodes to be popped and combined into a single node which is push back on the stack (reduce). Most reduction is done at the "label: labelNum" instruction where it tries to reduce jump structures into control messages like #ifTrue:, whileFalse:, etc. -Several pseudo nodes (RBPseudoNode and subclasses) are used to represent basic instructions that have not been reduced to real AST nodes yet. -' -! - - -!IRDecompiler class methodsFor:'as yet unclassified'! - -dummySelector: numArgs - "Answer a dummy selector with number of args" - - | sel | - sel _ 'unknown'. - 1 to: numArgs do: [:i | - sel _ sel, 'with:']. - ^ sel asSymbol -! ! - -!IRDecompiler methodsFor:'accessing'! - -scope - - ^scope -! ! - -!IRDecompiler methodsFor:'init'! - -addTempToScope: ir - - "Temp may be created only if they are not used in the method" - 0 to: ir numRargs - 1 do: [:i | (scope - rawVarAt: i - ifNone: [ - scope capturedVars do: [:each | - each index = i ifTrue:[ - scope tempVarAt: scope capturedVars size + scope tempVars size. - ^self]]. - scope tempVarAt: i]) markArg] -! - -decompileIR: ir - | sequenceNode temps args goto seq value method | - scope isBlockScope - ifTrue:[(scope addTemp: 'parent env') markArg] - ifFalse:[(scope addTemp: 'self') markArg]. - ir tempKeys do: [:temp | scope tempVarAt: temp]. - 0 to: ir numRargs - 1 do: [:i | (scope tempVarAt: i) markArg]. - self interpret: ir. - - self addTempToScope: ir. - self label: #return. - self Label: #return. - (self endCase: #lastReturn) ifFalse:[self Label: #return.]. - goto := self Goto. - value := self ValueOrNone. - seq := self Sequence. - self removeClosureCreation: seq. - sp = 1 ifFalse: [stack explore. self error: 'error']. - value ifNotNil: [seq addNode: value]. - sequenceNode := (self newBlock: seq return: goto) body. - temps := scope compactIndexTemps asArray. - ir tempKeys: temps. - args := (temps first: ir numRargs) allButFirst. - args := args collect: [:var | self newVar: var]. - temps := temps allButFirst: ir numRargs. - sequenceNode temporaries: (temps collect: [:var | self newVar: var]), - ((scope capturedVars select:[:var | var name ~= 'self' and: [var sourceTemp == nil]]) - collect:[:var | self newVar: var]). - method := (RBMethodNode new) - selectorParts: (self - newSelectorParts: (self class dummySelector: args size)); - arguments: args; - body: sequenceNode; - primitiveNode: ir primitiveNode; - scope: scope. - sequenceNode parent: method. - Preferences compileBlocksAsClosures - ifFalse: [ASTFixDecompileBlockScope new visitNode: method]. - ^ method -! - -removeClosureCreation: seq - (Preferences compileBlocksAsClosures - and: [seq statements size > 0] - and: [seq statements first isClosureEnvironmentCreation]) ifTrue: [ - seq statements removeFirst. - (seq statements size > 0 - and: [seq statements first isClosureEnvironmentRegistration]) - ifTrue: [seq statements removeFirst]]. - - [Preferences compileBlocksAsClosures - and: [seq statements size > 0] - and: [seq statements first isClosureRegistrationAndCreation - or: [seq statements first isSelfClosureRegistration] - or: [seq statements first isTempClosureRegistration]]] - whileTrue: [seq statements removeFirst] -! - -scope: aLexicalScope - - scope := aLexicalScope -! ! - -!IRDecompiler methodsFor:'instructions'! - -goto: seqNum - - self stackPush: (RBPseudoGotoNode new destination: seqNum). -! - -if: bool goto: seqNum1 otherwise: seqNum2 - - self stackPush: (RBPseudoIfNode new - boolean: bool; - destination: seqNum1; - otherwise: seqNum2) -! - -label: seqNum - - stack isEmpty ifTrue: [ "start" - ^ stack addLast: (RBPseudoLabelNode new destination: seqNum)]. - - self captureEmptyStatement. - "Reduce jump structures to one of the following if possible" - [ (self endBlock: seqNum) or: [ - (self endAndOr: seqNum) or: [ - (self endAndOr2: seqNum) or: [ - (self endIfThen: seqNum) or: [ - (self endIfThen2: seqNum) or:[ - (self endIfThenElse: seqNum) or: [ - (self endCase: seqNum) or: [ - (self endToDo: seqNum) or: [ - (self endWhile: seqNum) or: [ - (self endWhile2: seqNum) or: [ - (self endIfNil: seqNum)]]]]]]]]]] - ] whileTrue. - - stack addLast: (RBPseudoLabelNode new destination: seqNum). -! - -popTop - - | value | - stack last ifNil: [^ stack removeLast]. "pop no-op from #simplifyTempAssign:" - [stack last isLabel - and: [(stack atLast:2) isGoto] - and: [stack last destination = (stack atLast: 2) destination]] - whileTrue: [ - stack removeLast. - stack removeLast]. - stack last isValue ifTrue: [ - (stack atLast: 2) isSequence ifTrue: [ - value := stack removeLast. - ^ stack last addNode: value. - ] ifFalse: [(stack atLast: 2) isPseudo ifTrue: [ - value := stack removeLast. - ^ stack addLast: (RBSequenceNode statements: {value}). - ]]. - ]. - stack addLast: RBPseudoPopNode new -! - -pushBlock: irMethod - - self block: irMethod env: nil -! - -pushBlockMethod: irMethod - - "block will recognized when send: #createBlock:" - self pushLiteral: irMethod -! - -pushDup - - stack addLast: RBPseudoDupNode new -! - -pushInstVar: index - - self stackPush: (self newVar: (scope instanceScope instVar: index)) -! - -pushLiteral: object - - self stackPush: (self newLiteral: object). -! - -pushLiteralVariable: object - - | var | - var := scope lookupVar: object key asString. - self stackPush: (self newVar: var) -! - -pushTemp: tempIndex - - | var | - var := scope basicTempVarAt: tempIndex. - var isTemp ifTrue: [var cantBeCapture]. - self stackPush: (self newVar: var). -! - -remoteReturn - - stack removeLast. "pop home context free var" - self goto: #return. -! - -returnTop - - self goto: #return. -! - -send: selector numArgs: numArgs - - | args rcvr | - selector = #caseError ifTrue:[^self stackPush: (RBPseudoSendNode new selector: selector)]. - args := OrderedCollection new. - [ selector numArgs timesRepeat: [args addFirst: self Value]. - rcvr := self Value. - ] on: Abort do: [ - [self stackPush: (RBPseudoSendNode new selector: selector). - ^self cascade] on: Abort do:[^false] - ]. - - Preferences compileBlocksAsClosures - ifTrue: [ (rcvr isLiteral and: [selector = #createBlock:]) ifTrue: [ - ^ self block: rcvr value env: args first]] - ifFalse: [ (selector = #blockCopy:) ifTrue: [ - ^ self stackPush: (RBPseudoSendNode new selector: selector; arguments: args)]]. - - self stackPush: (self simplify: (RBMessageNode new - receiver: rcvr - selectorParts: (self newSelectorParts: selector) - arguments: args)). - - "Created: / 01-12-2008 / 19:40:52 / Jan Vrany <vranyj1@fel.cvut.cz>" -! - -send: selector numArgs: numArgs toSuperOf: behavior - - | args rcvr | - args := OrderedCollection new. - selector numArgs timesRepeat: [args addFirst: self Value]. - rcvr := self Value. - (rcvr isVariable and: [rcvr name = 'self']) ifFalse: [self patternError]. - - rcvr identifierToken: (SqueakToken value: 'super' start: 0). - self stackPush: (RBMessageNode new - receiver: rcvr - selectorParts: (self newSelectorParts: selector) - arguments: args). - - "Created: / 01-12-2008 / 19:45:52 / Jan Vrany <vranyj1@fel.cvut.cz>" -! - -storeIntoLiteralVariable: association - - | var | - var := scope lookupVar: association key asString. - self stackPush: (self simplifyTempAssign: - (RBAssignmentNode variable: (self newVar: (var markWrite)) value: self Value)) -! - -storeTemp: tempIndex - - | var | - var := scope basicTempVarAt: tempIndex. - var isCaptured ifFalse: [var cantBeCapture]. - var isTemp ifTrue:[ - var isArg: false]. - self stackPush: (self simplifyTempAssign: - (RBAssignmentNode variable: (self newVar: (var markWrite)) value: self Value)). -! ! - -!IRDecompiler methodsFor:'interpret'! - -interpretInstruction: irInstruction - - currentInstr := irInstruction. - super interpretInstruction: irInstruction. -! - -interpretSequence: instructionSequence - - super interpretSequence: instructionSequence. - "currentInstr := nil." -! ! - -!IRDecompiler methodsFor:'old blocks'! - -blockReturnTop - - self goto: #return. -! - -endBlock: seqNum - - | blockSeq block goto startBlock | - [ - goto := self GotoOrReturn: seqNum. - (goto isRet - or:[goto mapInstr notNil - and: [goto mapInstr isBlockReturnTop]]) ifFalse: [self abort]. - sp = 0 ifTrue: [self abort]. - blockSeq := self Sequence2. - startBlock := self Label. - block := self Block. - (goto isRet not - and:[goto mapInstr notNil] - and: [goto mapInstr isBlockReturnTop] - and: [block successor ~= seqNum]) ifTrue:[ - self stackPush: block. - self stackPush: startBlock. - self stackPush: blockSeq. - self stackPush: goto. - self abort]. - self Send. - ] on: Abort do: [^ false]. - - self stackPush: (self newBlock: blockSeq return: goto). - stack last arguments: block arguments. - "No extra scope is need if we don't use any temporaries and arguments. - so we remove them" - (stack last arguments isEmpty and: [stack last body temporaries isEmpty]) - ifTrue:[ASTReplaceVariableScope replace: stack last scope: scope outerScope ]. - scope := scope outerScope. - currentInstr := nil. - self goto: block successor. - ^ true -! - -jumpOverBlock: seqNum1 to: seqNum2 - | numArgs args oldscope pseudoBlock | - - oldscope := scope. - self scope: (scope newBlockScope). - oldscope tempVarAt: 0. - (scope addObjectTemp: (oldscope tempVarAt: 0)). - numArgs := stack last arguments first value. - self stackPush: (pseudoBlock := RBPseudoBlockNode new). - - args := OrderedCollection new. - numArgs timesRepeat: [ | var instr | - instr := currentInstr blockSequence removeFirst. - var := oldscope tempVarAt: instr number. - args add: (self newVar: var). - var isUnused ifTrue: [oldscope removeTempFromOldBlock: var]. - scope addObjectTemp: var. - currentInstr blockSequence first isPop - ifFalse: [ - currentInstr blockSequence sequence addFirst: (IRInstruction pushTemp: var index)] - ifTrue:[currentInstr blockSequence removeFirst]. - - ]. - args := args reverse. - pseudoBlock - block: seqNum1; - successor: seqNum2; - arguments: args - -! - -storeInstVar: number - - | var | - var := scope instanceScope instVar: number. - self stackPush: (RBAssignmentNode variable: (self newVar: var) value: self Value) -! ! - -!IRDecompiler methodsFor:'priv instructions'! - -addReturn: statements from: goto - - | ret | - statements last isReturn ifTrue:[^self]. - ret := RBReturnNode value: statements last. - Preferences compileBlocksAsClosures ifTrue:[ - scope isHome ifFalse: [ret homeBinding: scope outerEnvScope thisEnvVar]]. - goto mapInstr sourceNode: ret. - statements atLast: 1 put: ret. -! - -block: method env: envRefNode - - self stackPush: (IRDecompiler new - scope: (scope newBlockScope "capturedVars: vars"); - decompileIR: method ir) - asBlock -! - -cascade - - | messages selector args rcvr | - messages := OrderedCollection new. - "last message" - selector _ self Send selector. - args := OrderedCollection new. - selector numArgs timesRepeat: [args addFirst: self Value]. - messages addFirst: selector -> args. - - "rest of messages" - [(rcvr := self ValueOrNone) isNil] whileTrue: [ - self Pop. - selector := self Send selector. - args := OrderedCollection new. - selector numArgs timesRepeat: [args addFirst: self Value]. - self Dup. - messages addFirst: selector -> args. - ]. - - messages := messages collect: [:assoc | - RBMessageNode - receiver: rcvr - selector: assoc key - arguments: assoc value]. - self stackPush: (RBCascadeNode messages: messages). -! - -endAndOr2: seqNum - - | goto seq p if2 test else o if1 seqValue elseTest otherwise | - [ - goto _ self Goto. - seqValue _ self ValueOrNone. - seq _ self Sequence. - p _ self Label destination. - if2 _ self IfGoto: seqNum otherwise: p. - elseTest _ self Value. - else _ self SequenceBackTo: goto destination. - o _ self Label destination. - o = goto destination ifTrue: [self abort]. - if1 _ self IfGoto: seqNum otherwise: o. - test _ self Value. - ] on: Abort do: [^ false]. - - if1 boolean = if2 boolean - ifFalse: [ - otherwise := RBSequenceNode statements: #(). - otherwise addNode: (self newLiteral: if2 boolean). - self stackPush: (RBMessageNode - receiver: test - selector: (if2 boolean ifTrue: [#ifTrue:ifFalse:] ifFalse: [#ifFalse:ifTrue:]) - arguments: {self newBlock: (else addNode: elseTest). - self newBlock: otherwise}).] - ifTrue:[self stackPush: (RBMessageNode - receiver: test - selector: (if2 boolean ifTrue: [#or:] ifFalse: [#and:]) - arguments: {self newBlock: (else addNode: elseTest)})]. - stack addLast: if2. - self label: p. - stack addLast: seq. - seqValue ifNotNil: [stack addLast: seqValue]. - stack addLast: goto. - ^ true -! - -endAndOr: seqNum - - | o test branches if body block sel1 sel2 if2 | - branches := OrderedCollection new. - [ - (if2 := self If) otherwise = seqNum ifFalse: [self abort]. - [ test := self Value. - body := self Sequence. - branches add: {body. test}. - o := self Label destination. - (if := self If) otherwise = o ifFalse: [self abort]. - if destination = seqNum - ] whileFalse: [ - if boolean = if2 boolean ifFalse: [self abort]. - if destination = if2 destination ifFalse: [self abort]. - ]. - if boolean = if2 boolean ifTrue: [self abort]. - test := self Value. - ] on: Abort do: [^ false]. - - if boolean - ifTrue: [sel1 := #or:. sel2 := #and:] - ifFalse: [sel1 := #and:. sel2 := #or:]. - block := self newBlock: (branches first first addNode: branches first second). - branches allButFirstDo: [:pair | - block := self newBlock: (pair first addNode: (RBMessageNode - receiver: pair second - selector: sel2 - arguments: {block})). - ]. - self stackPush: (RBMessageNode - receiver: test - selector: sel1 - arguments: {block}). - stack addLast: if2. - ^ true -! - -endCase: seqNum - - | otherwiseGoto goto node otherwiseValue otherwiseSeq n branchValue branchSeq f caseValue caseSeq rcvr branches message seqEnd afterOterwise seq afterOterwiseValue | - branches := OrderedCollection new. - [ "otherwise" - otherwiseGoto := self Goto. - node := self stackDown. - node isSequence ifTrue: [(node statements size = 1 - and:[node statements first isSend] - and: [ - node := node statements first. - node selector == #caseError]) ifFalse: [ - otherwiseSeq := node] ]. - (node isPop or: [node isSend and: [node selector == #caseError]]) ifTrue: [ - node isPop ifTrue: [node := self Send]. - node selector == #caseError ifFalse: [self abort]. - ] ifFalse: [ - sp := sp + 1. "stackUp" - - seqNum == #lastReturn - ifFalse: [ - otherwiseValue := self ValueOrNone. - otherwiseSeq := self Sequence] - ifTrue: [ - afterOterwiseValue := self ValueOrNone. - otherwiseSeq := RBSequenceNode statements: #(). - afterOterwise := self SequenceOtherwise]. - ]. - n := self Label destination. - "last case branch" - seqNum == #lastReturn - ifFalse: [goto := self GotoOrReturn: seqNum] - ifTrue: [ - seqEnd := n. - goto := self GotoOrReturn: n. - otherwiseGoto := goto]. - branchValue := self ValueOrNone. - branchSeq := self Sequence. - (stack at: sp) isPop ifTrue: [self stackDown]. - f := self Label destination. - - "last case" - self IfGoto: n otherwise: f. - self Send selector == #= ifFalse: [self abort]. - caseValue := self Value. - caseSeq := self Sequence. - otherwiseSeq ifNil: [self Dup]. - branches addFirst: ({caseSeq. caseValue} -> {branchSeq. branchValue. goto}). - - [(rcvr := self ValueOrNone) isNil] whileTrue: [ - "case branch" - n := self Label destination. - seqNum == #lastReturn - ifFalse: [goto := self GotoOrReturn: seqNum] - ifTrue: [goto := self GotoOrReturn: seqEnd]. - branchValue := self ValueOrNone. - branchSeq := self Sequence. - self Pop. - f := self Label destination. - "case" - self IfGoto: n otherwise: f. - self Send selector == #= ifFalse: [self abort]. - caseValue := self Value. - caseSeq := self Sequence. - self Dup. - branches addFirst: ({caseSeq. caseValue} -> {branchSeq. branchValue. goto}). - ]. - ] on: Abort do: [^ false]. - - branches := branches collect: [:assoc | - assoc key second - ifNotNil: [assoc key first addNode: assoc key second]. - assoc value second - ifNotNil: [assoc value first addNode: assoc value second]. - RBMessageNode - receiver: (self newBlock: assoc key first return: nil) - selector: #-> - arguments: - {self newBlock: assoc value first return: assoc value third} - ]. - message := otherwiseSeq - ifNil: [ - RBMessageNode - receiver: rcvr - selector: #caseOf: - arguments: {RBArrayNode statements: branches}] - ifNotNil: [ - otherwiseValue - ifNotNil: [otherwiseSeq addNode: otherwiseValue]. - RBMessageNode - receiver: rcvr - selector: #caseOf:otherwise: - arguments: - {RBArrayNode statements: branches. - self newBlock: otherwiseSeq return: otherwiseGoto}. - ]. - self stackPush: message. - seqNum == #lastReturn ifTrue: [ - self popTop. - seq := self Sequence. - afterOterwise ifNotNil:[seq statements addAllLast: afterOterwise statements]. - self stackPush: seq. - afterOterwiseValue ifNotNil:[self stackPush: afterOterwiseValue]. - branchValue := 1]. - branchValue ifNil: [self popTop]. - self stackPush: otherwiseGoto. - ^ true -! - -endIfNil: seqNum - - | goto branch o if rcvr value | - [ - goto := self Goto. - value := self Value. - branch := self Sequence. - self Pop. - o := self Label destination. - if := self IfGoto: seqNum otherwise: o. - self Send selector == #== ifFalse: [self abort]. - (self Value isLiteral: [:v | v isNil]) ifFalse: [self abort]. - self Dup. - rcvr := self Value. - ] on: Abort do: [^ false]. - - branch addNode: value. - self stackPush: (RBMessageNode - receiver: rcvr - selector: (if boolean ifTrue: [#ifNotNil:] ifFalse: [#ifNil:]) - arguments: {self newBlock: branch return: goto}). - self goto: seqNum. - ^ true -! - -endIfThen2: seqNum - - | goto branch o if test value gotoNum branch2 | - [ - goto := self Goto. - (goto mapInstr ~= nil - and: [goto mapInstr isJump] - and: [goto mapInstr destination size = 1] - and: [goto mapInstr destination last isJump]) - ifTrue: [gotoNum := goto - mapInstr destination last destination orderNumber] - ifFalse:[self abort]. - (currentInstr ~= nil - and: [currentInstr isJump] - and: [currentInstr destination orderNumber = goto destination]) - ifFalse: [self abort]. - value := self Value. - branch := self Sequence. - o := self Label destination. - seqNum = gotoNum - ifFalse:[if := self IfGoto: gotoNum otherwise: o] - ifTrue:[self abort]. - test := self Value. - ] on: Abort do: [^ false]. - - value ifNotNil: [branch addNode: value]. - branch2 := RBSequenceNode statements: #(). - branch2 addNode: (self newLiteral: if boolean). - self stackPush: (self simplify: (RBMessageNode - receiver: test - selector: (if boolean ifTrue: [#ifFalse:ifTrue:] ifFalse: [#ifTrue:ifFalse:]) - arguments: {self newBlock: branch return: goto. - self newBlock: branch2})). - self goto: goto destination. - ^true -! - -endIfThen3: seqNum - - | goto branch o if test value | - [ - goto := self Goto. - (goto destination == seqNum or: [self isExplicitReturn: goto]) - ifFalse: [self abort]. - goto isRet ifTrue: [value := self Value]. - branch := self Sequence. - o := self Label destination. - if := self If. - ((if destination = seqNum - or: [if destination = (mapEmptyStatement at: seqNum ifAbsent:[seqNum])]) - and: [if otherwise = o]) - ifFalse:[self abort]. - test := self Value. - ] on: Abort do: [^ false]. - - - value ifNotNil: [branch addNode: value]. - self stackPush: (self simplify: (RBMessageNode - receiver: test - selector: (if boolean ifTrue: [#ifFalse:] ifFalse: [#ifTrue:]) - arguments: {self newBlock: branch return: goto})). - self popTop. - self goto: seqNum. - ^ true -! - -endIfThen: seqNum - - | goto branch o if test value | - [ - goto := self Goto. - (goto destination == seqNum or: [self isExplicitReturn: goto]) - ifFalse: [self abort]. - goto isRet ifTrue: [value := self Value]. - branch := self Sequence. - o := self Label destination. - if := self IfGoto: seqNum otherwise: o. - test := self Value. - ] on: Abort do: [^ false]. - - - value ifNotNil: [branch addNode: value]. - self stackPush: (self simplify: (RBMessageNode - receiver: test - selector: (if boolean ifTrue: [#ifFalse:] ifFalse: [#ifTrue:]) - arguments: {self newBlock: branch return: goto})). - self popTop. - self goto: seqNum. - ^ true -! - -endIfThenElse: seqNum - - | goto2 else d goto1 then o if test value2 value1 | - [ - goto2 := self Goto. - value2 := self ValueOrNone. - else := self Sequence. - d := self Label destination. - goto1 := self Goto. - ((self isExplicitReturn: goto2) or: [goto2 destination == goto1 destination]) ifFalse: [self abort]. - value1 := self ValueOrNone. - then := self Sequence. - o := self Label destination. - if := self IfGoto: d otherwise: o. - test := self Value. - ] on: Abort do: [^ false]. - - value2 ifNotNil: [else addNode: value2]. - value1 ifNotNil: [then addNode: value1]. - (self isExplicitReturn: goto1) ifTrue:[self addReturn: then statements from: goto1]. - (self isExplicitReturn: goto2) ifTrue:[self addReturn: else statements from: goto2]. - self stackPush: (self simplify: (else isEmpty - ifTrue: [RBMessageNode - receiver: test - selector: (if boolean ifTrue: [#ifFalse:] ifFalse: [#ifTrue:]) - arguments: {self newBlock: then return: goto1}] - ifFalse: [RBMessageNode - receiver: test - selector: (if boolean - ifTrue: [#ifFalse:ifTrue:] - ifFalse: [#ifTrue:ifFalse:]) - arguments: { - self newBlock: then return: goto1. - self newBlock: else return: goto2}])). - value1 ifNil: [self popTop]. - currentInstr := goto1 mapInstr. - self stackPush: goto1. - (else statements isEmpty and: - [stack anySatisfy: [:n | n isIf and: [n destination = d]]] - ) ifTrue: [ - self label: d. - currentInstr := goto2 mapInstr. - self stackPush: goto2. - ]. - ^ true -! - -endToDo: seqNum - - | start limit incr iter step loopBlock o if test limitExpr init | - [ - start := self Goto destination. - limit := self Value. - incr := self Assignment. - iter := incr variable. - (incr value isMessage and: - [incr value selector == #+ and: - [incr value receiver isVariable and: - [incr value receiver binding == iter binding]]] - ) ifFalse: [self abort]. - step := incr value arguments first. - loopBlock := self Sequence. - o := self Label destination. - if := self IfGoto: seqNum otherwise: o. - test := self Value. - (test isMessage and: - [(test selector == #<= or: [test selector == #>=]) and: - [(valueLabelMap at: test arguments first ifAbsent: [self abort]) destination = start]] - ) ifFalse: [self abort]. - limitExpr := test arguments first. - limitExpr isAssignment ifTrue: [ - (limitExpr variable binding index == limit binding index - and:[limitExpr variable binding scope == limit binding scope]) ifFalse: [self abort]. - limitExpr := limitExpr value. - ]. - init := test receiver. - (init isAssignment and: [init variable binding == iter binding]) - ifFalse: [self abort]. - ] on: Abort do: [^ false]. - limit isVariable - ifTrue:[scope - removeTemp: limit binding - ifAbsent:[Preferences compileBlocksAsClosures - ifFalse:[scope removeTempFromOldBlock: limit]]]. - loopBlock := self newBlock: loopBlock. - loopBlock arguments: {iter}. - self stackPush: ((step isLiteral: [:c | c = 1]) - ifTrue: [RBMessageNode - receiver: init value - selector: #to:do: - arguments: {limitExpr. loopBlock}] - ifFalse: [RBMessageNode - receiver: init value - selector: #to:by:do: - arguments: {limitExpr. step. loopBlock}]). - self popTop. - self goto: seqNum. - ^ true -! - -endWhile2: seqNum - - | start loopBlock if test sequence o goto previousStack | - [ - stack := (previousStack := stack) copy. - start := (goto := self Goto) destination. - self stackPush: goto. - [self endIfThen3: start] whileTrue. - start := self Goto destination. - loopBlock _ self Sequence. - o _ self Label destination. - if _ self IfGoto: seqNum otherwise: o. - test _ self Value. - sequence _ self SequenceBackTo: start. - self Label: start. - sp _ sp + 1. "stackUp" - ] on: Abort do: [stack := previousStack. ^ false]. - loopBlock isEmpty - ifTrue:[self stackPush: (self simplify: (RBMessageNode - receiver: (self newBlock: (sequence addNode: test)) - selector: (if boolean ifTrue: [#whileFalse] ifFalse: [#whileTrue]) - arguments: #()))] - ifFalse:[self stackPush: (self simplify: (RBMessageNode - receiver: (self newBlock: (sequence addNode: test)) - selector: (if boolean ifTrue: [#whileFalse:] ifFalse: [#whileTrue:]) - arguments: {self newBlock: loopBlock}))]. - self popTop. - self goto: seqNum. - ^ true -! - -endWhile: seqNum - - | start loopBlock if test sequence o | - [ - start _ self Goto destination. - loopBlock _ self Sequence. - o _ self Label destination. - if _ self IfGoto: seqNum otherwise: o. - test _ self Value. - sequence _ self SequenceBackTo: start. - self Label: start. - sp _ sp + 1. "stackUp" - ] on: Abort do: [^ false]. - loopBlock isEmpty - ifTrue:[self stackPush: (self simplify: (RBMessageNode - receiver: (self newBlock: (sequence addNode: test)) - selector: (if boolean ifTrue: [#whileFalse] ifFalse: [#whileTrue]) - arguments: #()))] - ifFalse:[self stackPush: (self simplify: (RBMessageNode - receiver: (self newBlock: (sequence addNode: test)) - selector: (if boolean ifTrue: [#whileFalse:] ifFalse: [#whileTrue:]) - arguments: {self newBlock: loopBlock}))]. - self popTop. - self goto: seqNum. - ^ true -! ! - -!IRDecompiler methodsFor:'private'! - -captureEmptyStatement - | by replace node | - - [by := self Goto destination. - replace := self Label destination. - replace = 0 ifTrue: [self abort]] - on: Abort - do: [^ false]. - mapEmptyStatement at: by put: replace. - sp := nil. - ^ true -! - -fixInnerFreeVar: aRcvrTemp - - | scopeInnerFreeVar | - scopeInnerFreeVar := scope outerScope. - [aRcvrTemp scope = scopeInnerFreeVar] whileFalse:[ - scopeInnerFreeVar hasInnerFreeVars: true. - scopeInnerFreeVar := scopeInnerFreeVar outerScope]. - aRcvrTemp scope hasInnerFreeVars: true -! - -initialize - - stack := OrderedCollection new. - scope := nil parseScope newMethodScope. "in case never set" - valueLabelMap := IdentityDictionary new. - mapEmptyStatement := IdentityDictionary new -! - -isExplicitReturn: goto - - Preferences compileBlocksAsClosures - ifTrue:[^ goto isRet - and: [goto mapInstr notNil] - and: [goto mapInstr isRemote or: [scope isBlockScope not]]] - ifFalse: [^goto isRet and: [goto mapInstr isBlockReturnTop not]] -! - -mapNode: node - - currentInstr ifNil: [^ self]. - node isPseudo - ifTrue: [node mapInstr: currentInstr] - ifFalse: [currentInstr sourceNode: node] -! - -newBlock: sequence - - ^ self newBlock: sequence return: nil -! - -newBlock: sequence return: goto - - | statements block | - statements := sequence statements. - (goto notNil and: [self isExplicitReturn: goto]) ifTrue: [ - self addReturn: statements from: goto - ]. - sequence statements: statements. - block := RBBlockNode body: sequence. - sequence parent: block. - Preferences compileBlocksAsClosures ifFalse: [block scope: scope]. - ^block -! - -newLiteral: literal - - ^ RBLiteralNode value: literal -! - -newSelectorParts: selector - - ^ selector keywords collect: [:word | - RBLiteralToken value: word] -! - -newVar: semVar - - ^ RBVariableNode new - identifierToken: (RBIdentifierToken value: semVar name start: 0); - binding: semVar -! - -simplify: mess - "mess is a messageNode. If it is a message created by the compiler convert it back to its normal form" - - | rcvr var | -" (mess selector == #value and: [mess receiver isLiteral]) ifTrue: [ - ^ self newVar: (GlobalVar new assoc: mess receiver value; scope: scope) - ]." - - (mess selector = #privSetInHolder: and: [mess arguments first isLiteral]) ifTrue: [ - ^ RBAssignmentNode - variable: (self newVar: (GlobalVar new assoc: mess arguments first value; scope: scope) markWrite) - value: mess receiver - ]. - - (mess selector = #privGetInstVar: and: - [mess arguments first isLiteral and: - [mess receiver isVariable]]) ifTrue: [ - rcvr := mess receiver binding. - rcvr == scope receiverVar ifTrue: [ - ^ self newVar: (scope receiverVarAt: mess arguments first value)]. - (rcvr isContextVar and: [mess arguments first value == 5]) ifTrue: [ - var := scope tempVarAt: -1. - ^self newVar: var]. - (rcvr isCaptured and:[rcvr sourceTemp = rcvr scope receiverVar]) - ifTrue:[ - self fixInnerFreeVar: rcvr. - ^self newVar: (rcvr scope receiverVarAt: mess arguments first value)]. - rcvr isEnv ifTrue: [^self newVar: (rcvr scope captureVarAt: mess arguments first value)]]. - - (mess selector = #privStoreIn:instVar: and: - [mess arguments last isLiteral and: - [mess arguments first isVariable]]) ifTrue: [ - rcvr := mess arguments first binding. - (mess receiver name = 'self' and: [rcvr isEnv]) - ifTrue:[scope captureSelf: mess arguments last value. - ^mess]. - rcvr == scope receiverVar ifTrue: [^ RBAssignmentNode - variable: (self newVar: (scope receiverVarForAssignmentAt: mess arguments last value) markWrite) - value: mess receiver]. - (rcvr isCaptured and:[rcvr sourceTemp = rcvr scope receiverVar]) - ifTrue:[ - self fixInnerFreeVar: rcvr. - ^RBAssignmentNode - variable: (self newVar: (rcvr scope receiverVarForAssignmentAt: mess arguments last value) markWrite) - value: mess receiver]. - mess isClosureEnvironmentRegistration - ifTrue: [ - scope captureSelf: mess arguments last value. - ^mess]. - rcvr isEnv ifTrue:[ - mess receiver isTemp - ifTrue:[var := (scope - captureVarAt: mess arguments last value - sourceTemp: mess receiver binding) markWrite.] - ifFalse:[var := (scope - captureVarAt: mess arguments last value sourceTemp: ((TempVar new) - name: (scope captureVarName: mess arguments last value); - index: mess arguments last value; - scope: self; - cantBeCapture)) markWrite - ]. - ^ RBAssignmentNode - variable: (self newVar: var) - value: mess receiver]]. - ^mess -! - -simplifyTempAssign: assignment - "If it is a assignment created by the compiler convert it back to its normal form" - - | mess | - ((mess := assignment value) isMessage and: - [mess selector = #wrapInTempHolder and: - [mess receiver isLiteral: [:v | v isNil]]] - ) ifTrue: [ - ^ nil "no-op" - ]. - - ^ assignment -! ! - -!IRDecompiler methodsFor:'stack'! - -Assignment - - | node | - (node := self stackDown) isAssignment ifTrue: [^ node]. - self abort -! - -Block - - | node | - (node := self stackDown) isBlock ifTrue: [^ node]. - self abort -! - -Dup - - | node | - (node := self stackDown) isDup ifTrue: [^ node]. - self abort -! - -Goto - - | node | - (node := self stackDown) isGoto ifTrue: [^ node]. - self abort -! - -Goto: seqNum - - | goto | - (goto := self Goto) destination = seqNum ifTrue: [^ goto]. - self abort -! - -GotoOrReturn: seqNum - - | goto | - goto := self Goto. - (goto destination = seqNum or: [goto isRet]) ifTrue: [^ goto]. - self abort -! - -If - - | node | - (node := self stackDown) isIf ifTrue: [^ node]. - self abort -! - -IfGoto: seqNum otherwise: seqNum2 - - | if | - ((if := self If) destination = seqNum and: [if otherwise = seqNum2]) - ifTrue: [^ if]. - self abort -! - -Label - - | node | - (node := self stackDown) isLabel ifTrue: [^ node]. - self abort -! - -Label: seqNum - - | label | - (label := self Label) destination = seqNum ifTrue: [^ label]. - self abort -! - -Pop - - | node | - (node := self stackDown) isPop ifTrue: [^ node]. - self abort -! - -Send - - | node | - (node := self stackDown) isPseudoSend ifTrue: [^ node]. - self abort -! - -Sequence - | node seq i goto | - seq := RBSequenceNode statements: #(). - i := self spIndex. - [node := stack at: i. - node isSequence - ifTrue: - [seq addNodesFirst: node statements. - node := stack at: (i := i - 1)]. - (node isLabel and: [i > 1]) - ifFalse: - [sp := i. - ^ seq]. - goto := stack at: (i := i - 1). - goto isGoto and: [goto destination = node destination]] - whileTrue: [i := i - 1]. - sp := i + 1. - ^ seq -! - -Sequence2 - | node seq i block temps label | - seq := RBSequenceNode statements: #(). - i := self spIndex. - node := stack at: i. - [(node isLabel and: [(stack at: i - 1) isGoto] and:[node destination = (stack at: i - 1) destination]) - ifTrue:[ - i := i - 2. - node := stack at: i]. - (node isLabel not and: [i > 1])] whileTrue: - [ - node isSequence - ifTrue: [seq addNodesFirst: node statements] - ifFalse: [seq addNodeFirst: node]. - i := i - 1. - node := stack at: i]. - sp := i. - label := self Label. - block := self Block. - self stackPush: block. - self stackPush: label. - "Add the temporaries find" - temps := scope tempVars asArray allButFirst. - temps := temps select: [:each | ((block arguments - collect: [:var | var binding]) includes: each) not]. - seq temporaries: (temps collect: [:var | self newVar: var]). - ^ seq -! - -SequenceBackTo: labelNum - | node seq i goto | - seq := RBSequenceNode statements: #(). - i := self spIndex. - [node := stack at: i. - node isSequence - ifTrue: - [seq addNodesFirst: node statements. - node := stack at: (i := i - 1)]. - (node isLabel and: [i > 1]) - ifFalse: - [sp := i. - ^ seq]. - node destination = labelNum - ifTrue: - [sp := i. - ^ seq]. - goto := stack at: (i := i - 1). - goto isGoto and: [goto destination = node destination]] - whileTrue: [i := i - 1]. - sp := i + 1. - ^ seq -! - -SequenceOtherwise - | node seq i | - seq := RBSequenceNode statements: #(). - i := self spIndex. - node := stack at: i. - node isSequence ifTrue: [ - seq addNodesFirst: node statements. - self stackDown] - ifFalse:[node isLabel ifFalse:[self abort]]. - ^ seq -! - -Value - - | node | - node := self ValueOrNone. - node ifNil: [self abort]. - ^ node -! - -ValueOrNone - | node i label | - i := self spIndex. - [node := stack at: i. - node isValue - ifTrue: - [label ifNotNil: [valueLabelMap at: node put: label]. - sp := i - 1. - ^ node]. - (node isLabel and: [i > 1]) ifFalse: [^ nil]. - label := node. - node := stack at: (i := i - 1). - node isGoto and: [node destination = label destination]] - whileTrue: [i := i - 1]. - ^ nil -! - -abort - - | spWas | - spWas := sp. - sp := nil. - Abort signal -! - -fixStack - - sp ifNotNil: [stack removeLast: (stack size - sp)]. - sp := nil. -! - -spIndex - ^ sp ifNil: [sp := stack size] -! - -stackDown - - | node | - sp ifNil: [sp _ stack size]. - sp = 0 ifTrue: [self abort]. - node _ stack at: sp. - sp _ sp - 1. - ^ node -! - -stackPush: node - - self fixStack. - stack addLast: node. - node ifNil: [^ self]. "no op" - self mapNode: node. -! ! - -!IRDecompiler class methodsFor:'documentation'! - -version - ^ '$Header: /cvs/stx/cvut/stx/goodies/newcompiler/IRDecompiler.st,v 1.3 2009/10/08 12:04:20 fm Exp $' -! - -version_CVS - ^ '$Header: /cvs/stx/cvut/stx/goodies/newcompiler/IRDecompiler.st,v 1.3 2009/10/08 12:04:20 fm Exp $' -! - -version_SVN - ^ '$Id$' -! !
--- a/IRFunction.st Mon Dec 28 16:20:44 2009 +0000 +++ b/IRFunction.st Mon Feb 15 17:55:26 2010 +0000 @@ -174,11 +174,12 @@ inspector2TabIRCode ^Tools::Inspector2Tab new - label: 'IR Code'; - priority: 75; - view: ((ScrollableView for:TextView) contents: self longPrintString; yourself) + label: 'IR Code'; + priority: 75; + text: self longPrintString. "Created: / 11-06-2008 / 01:05:16 / Jan Vrany <vranyj1@fel.cvut.cz>" + "Modified: / 15-02-2010 / 13:04:55 / Jan Vrany <jan.vrany@fit.cvut.cz>" ! ! !IRFunction methodsFor:'decompiling'!