Eliot Miranda uploaded a new version of Compiler to project The Trunk:
http://source.squeak.org/trunk/Compiler-eem.285.mcz ==================== Summary ==================== Name: Compiler-eem.285 Author: eem Time: 5 August 2014, 7:52:00.572 pm UUID: 99d40074-99f4-4e36-875e-e3f1cd61acfa Ancestors: Compiler-eem.284 Lots more support for multiple bytecode sets. Abstract out of InstructionStream: size of closure creation bytecode scanning for inst var reads and writes Provide support for bytecode set specific callPrimitiveBytecode unusedBytecode Provide support for different special literal and special selector encodings. Ensure bytecode sizing of backward branches use negative distances. Other: Make the MessageNode transformations check for the relevant block argument count. =============== Diff against Compiler-eem.284 =============== Item was added: + ----- Method: BlockLocalTempCounter class>>tempCountForBlockStartingAt:in: (in category 'instance creation') ----- + tempCountForBlockStartingAt: startpc in: method + ^self new + tempCountForBlockAt: (method encoderClass pcOfBlockCreationBytecodeForBlockStartingAt: startpc in: method) + in: method! Item was changed: ----- Method: BytecodeEncoder class>>bytecodeSize: (in category 'instruction stream support') ----- + bytecodeSize: aByte - bytecodeSize: bytecode - "Answer the number of bytes in the (unextended) bytecode." - self subclassResponsibility! Item was added: + ----- Method: BytecodeEncoder class>>callPrimitiveCode (in category 'bytecode decoding') ----- + callPrimitiveCode + "Answer the call primitive bytecode, if it exists in the encoder's byetcode set, or nil if not." + ^nil! Item was added: + ----- Method: BytecodeEncoder class>>method:readsField: (in category 'scanning') ----- + method: method readsField: varIndex + "Answer if method loads the instance variable indexed by varIndex." + ^self subclassResponsibility! Item was added: + ----- Method: BytecodeEncoder class>>method:writesField: (in category 'scanning') ----- + method: method writesField: varIndex + "Answer if method stores into the instance variable indexed by varIndex." + ^self subclassResponsibility! Item was added: + ----- Method: BytecodeEncoder class>>pcOfBlockCreationBytecodeForBlockStartingAt:in: (in category 'bytecode decoding') ----- + pcOfBlockCreationBytecodeForBlockStartingAt: startpc in: method + "Answer the pc of the push closure bytecode whose block starts at startpc in method." + ^self subclassResponsibility! Item was added: + ----- Method: BytecodeEncoder class>>pushClosureBytecodeSize (in category 'bytecode decoding') ----- + pushClosureBytecodeSize + "Answer the size of the push closure bytecode, if there is one." + ^self subclassResponsibility! Item was added: + ----- Method: BytecodeEncoder class>>unusedBytecode (in category 'bytecode decoding') ----- + unusedBytecode + "Answer the opcode of a single-byte unused bytecode, if it exists in the encoder's bytecode set, or nil if not." + ^nil! Item was added: + ----- Method: BytecodeEncoder>>sizeCallPrimitive: (in category 'opcode sizing') ----- + sizeCallPrimitive: primitiveIndex + ^self sizeOpcodeSelector: #genCallPrimitive: withArguments: {primitiveIndex}! Item was added: + ----- Method: BytecodeEncoder>>sizeSendSpecial:numArgs: (in category 'opcode sizing') ----- + sizeSendSpecial: specialSelectorIndex numArgs: nArgs + ^self sizeOpcodeSelector: #genSendSpecial:numArgs: withArguments: {specialSelectorIndex. nArgs}! Item was changed: ----- Method: Decompiler>>decompile:in:method:using: (in category 'public access') ----- decompile: aSelector in: aClass method: aMethod using: aConstructor | block node | constructor := aConstructor. method := aMethod. self initSymbols: aClass. "create symbol tables" method isQuick ifTrue: [block := self quickMethod] ifFalse: [stack := OrderedCollection new: method frameSize. lastJumpIfPcStack := OrderedCollection new. caseExits := OrderedCollection new. statements := OrderedCollection new: 20. numLocalTemps := 0. super method: method pc: method initialPC. "skip primitive error code store if necessary" + (method primitive ~= 0 and: [self skipCallPrimitive; willStore]) ifTrue: + [pc := pc + (method encoderClass bytecodeSize: self firstByte). - (method primitive ~= 0 and: [self willStore]) ifTrue: - [pc := pc + 2. tempVars := tempVars asOrderedCollection]. block := self blockTo: method endPC + 1. stack isEmpty ifFalse: [self error: 'stack not empty']]. node := constructor codeMethod: aSelector block: block tempVars: tempVars primitive: method primitive class: aClass. method primitive > 0 ifTrue: [node removeAndRenameLastTempIfErrorCode]. ^node preen! Item was changed: ----- Method: Decompiler>>doClosureCopyCopiedValues:numArgs:blockSize: (in category 'control') ----- doClosureCopyCopiedValues: blockCopiedValues numArgs: numArgs blockSize: blockSize | startpc savedTemps savedTempVarCount savedNumLocalTemps jump blockArgs blockTemps blockTempsOffset block | savedTemps := tempVars. savedTempVarCount := tempVarCount. savedNumLocalTemps := numLocalTemps. jump := blockSize + (startpc := pc). + numLocalTemps := BlockLocalTempCounter + tempCountForBlockStartingAt: pc + in: method. - numLocalTemps := BlockLocalTempCounter tempCountForBlockAt: pc - 4 in: method. blockTempsOffset := numArgs + blockCopiedValues size. (blockStartsToTempVars notNil "implies we were intialized with temp names." and: [blockStartsToTempVars includesKey: pc]) ifTrue: [tempVars := blockStartsToTempVars at: pc] ifFalse: [blockArgs := (1 to: numArgs) collect: [:i| (constructor codeTemp: i - 1 named: 't', (tempVarCount + i) printString) beBlockArg]. blockTemps := (1 to: numLocalTemps) collect: [:i| constructor codeTemp: i + blockTempsOffset - 1 named: 't', (tempVarCount + i + numArgs) printString]. tempVars := blockArgs, blockCopiedValues, blockTemps]. numLocalTemps timesRepeat: [self interpretNextInstructionFor: self. stack removeLast]. tempVarCount := tempVarCount + numArgs + numLocalTemps. block := self blockTo: jump. stack addLast: ((constructor codeArguments: (tempVars copyFrom: 1 to: numArgs) temps: (tempVars copyFrom: blockTempsOffset + 1 to: blockTempsOffset + numLocalTemps) block: block) pc: startpc; yourself). tempVars := savedTemps. tempVarCount := savedTempVarCount. numLocalTemps := savedNumLocalTemps! Item was changed: ----- Method: Decompiler>>interpretNextInstructionFor: (in category 'private') ----- interpretNextInstructionFor: client | code varNames | "Change false here will trace all state in Transcript." + true ifTrue: [^super interpretNextInstructionFor: client]. - true ifTrue: [^ super interpretNextInstructionFor: client]. varNames := self class allInstVarNames. code := (self method at: pc) radix: 16. + Transcript cr; cr; print: pc; space; nextPutAll: '<' , code, '>'. + (varNames indexOf: 'stack') to: varNames size do: + [:i | + i <= 10 ifTrue: [Transcript cr] ifFalse: [Transcript space; space]. + Transcript nextPutAll: (varNames at: i); nextPutAll: ': '; print: (self instVarAt: i)]. + Transcript flush. + ^super interpretNextInstructionFor: client! - Transcript cr; cr; print: pc; space; - nextPutAll: '<' , code, '>'. - 8 to: varNames size do: - [:i | i <= 10 ifTrue: [Transcript cr] - ifFalse: [Transcript space; space]. - Transcript nextPutAll: (varNames at: i); - nextPutAll: ': '; print: (self instVarAt: i)]. - Transcript endEntry. - ^ super interpretNextInstructionFor: client! Item was changed: ----- Method: DecompilerConstructorForClosures>>codeMethod:block:tempVars:primitive:class: (in category 'constructor') ----- codeMethod: selector block: block tempVars: vars primitive: primitive class: class | blockNode selectorNode visibleTemps invisibleTemps arguments temporaries properties | selectorNode := self codeSelector: selector code: nil. tempVars := vars. visibleTemps := OrderedCollection new. invisibleTemps := OrderedCollection new. tempVars do: [:t| ((t isIndirectTempVector or: [t scope >= 0]) ifTrue: [visibleTemps] ifFalse: [invisibleTemps]) addLast: t]. arguments := visibleTemps copyFrom: 1 to: nArgs. temporaries := visibleTemps copyFrom: nArgs + 1 to: visibleTemps size. block arguments: arguments; temporaries: temporaries. properties := method properties copy. (properties at: #onceCache ifAbsent: []) ifNotNil: [:onceCache| properties := properties copyWithout: (Association key: #onceCache value: onceCache)]. blockNode := MethodNode new selector: selectorNode arguments: arguments precedence: selector precedence temporaries: temporaries block: block + encoder: (method encoderClass new initScopeAndLiteralTables - encoder: (EncoderForV3PlusClosures new initScopeAndLiteralTables temps: visibleTemps, invisibleTemps literals: literalValues class: class) primitive: primitive properties: properties. blockNode properties method: blockNode. ^blockNode! Item was added: + ----- Method: EncoderForV3 class>>method:readsField: (in category 'scanning') ----- + method: method readsField: varIndex + "Answer if method loads the instance variable indexed by varIndex. + N.B. Don't assume the compiler uses the most compact encoding available. + 0-15 0000iiii Push Receiver Variable #iiii + 128 10000000 jjkkkkkk Push (Receiver Variable, Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk + 132 10000100 iiijjjjj kkkkkkkk (Send, Send Super, Push Receiver Variable, Push Literal Constant, Push Literal Variable, Store Receiver Variable, Store-Pop Receiver Variable, Store Literal Variable)[iii] #kkkkkkkk jjjjj (for sends jjjjj = numArgs)" + | varIndexCode scanner | + varIndexCode := varIndex - 1. + method isReturnField ifTrue: + [^method returnField = varIndexCode]. + ^(scanner := InstructionStream on: method) scanFor: + [:b| + b < 16 + ifTrue: [b = varIndexCode] + ifFalse: + [b = 128 + ifTrue: [scanner followingByte = varIndexCode and: [varIndexCode <= 63]] + ifFalse: + [b = 132 + and: [(scanner followingByte between: 64 and: 95) + and: [scanner thirdByte = varIndexCode]]]]]! Item was added: + ----- Method: EncoderForV3 class>>method:writesField: (in category 'scanning') ----- + method: method writesField: varIndex + "Answer if method stores into the instance variable indexed by varIndex. + N.B. Don't assume the compiler uses the most compact encoding available. + 96-103 01100iii Pop and Store Receiver Variable #iii + 129 10000001 jjkkkkkk Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk + 130 10000010 jjkkkkkk Pop and Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk + 132 10000100 iiijjjjj kkkkkkkk (Send, Send Super, Push Receiver Variable, Push Literal Constant, Push Literal Variable, Store Receiver Variable, Store-Pop Receiver Variable, Store Literal Variable)[iii] #kkkkkkkk jjjjj (for sends jjjjj = numArgs)" + | varIndexCode scanner | + method isQuick ifTrue: [^false]. + varIndexCode := varIndex - 1. + ^(scanner := InstructionStream on: method) scanFor: + [:b| + b >= 96 + and: [b <= 103 + ifTrue: [b - 96 = varIndexCode] + ifFalse: + [(b = 129 or: [b = 130]) + ifTrue: [scanner followingByte = varIndexCode and: [varIndexCode <= 63]] + ifFalse: + [b = 132 + and: [(scanner followingByte between: 160 and: 223) + and: [scanner thirdByte = varIndexCode]]]]]]! Item was added: + ----- Method: EncoderForV3 class>>unusedBytecode (in category 'bytecode decoding') ----- + unusedBytecode + "Answer the opcode of a single-byte unused bytecode, if it exists in the encoder's bytecode set, or nil if not." + ^126! Item was added: + ----- Method: EncoderForV3>>genSendSpecial:numArgs: (in category 'bytecode generation') ----- + genSendSpecial: specialSelectorIndex numArgs: nArgs + "See BlueBook page 596" + self assert: (specialSelectorIndex between: 1 and: Smalltalk specialSelectorSize). + self assert: nArgs = (Smalltalk specialNargsAt: specialSelectorIndex). + "Special selector sends. + 176-191 1011iiii Send Arithmetic Message #iiii + 192-207 1100iiii Send Special Message #iiii" + stream nextPut: specialSelectorIndex + 175! Item was changed: ----- Method: EncoderForV3PlusClosures class>>bytecodeSize: (in category 'instruction stream support') ----- bytecodeSize: bytecode "Answer the number of bytes in the bytecode." bytecode <= 125 ifTrue: [^1]. bytecode >= 176 ifTrue: [^1]. bytecode >= 160 ifTrue: "long jumps" [^2]. bytecode >= 144 ifTrue: "short jumps" [^1]. "extensions" bytecode >= 128 ifTrue: [^#(2 2 2 2 3 2 2 1 1 1 2 nil 3 3 3 4) at: bytecode - 127]. ^nil! Item was added: + ----- Method: EncoderForV3PlusClosures class>>pcOfBlockCreationBytecodeForBlockStartingAt:in: (in category 'bytecode decoding') ----- + pcOfBlockCreationBytecodeForBlockStartingAt: startpc in: method + "Answer the pc of the push closure bytecode whose block starts at startpc in method. + 143 10001111 llllkkkk jjjjjjjj iiiiiiii Push Closure Num Copied llll Num Args kkkk BlockSize jjjjjjjjiiiiiiii" + ^startpc - 4! Item was added: + ----- Method: EncoderForV3PlusClosures class>>pushClosureBytecodeSize (in category 'bytecode decoding') ----- + pushClosureBytecodeSize + "Answer the size of the push closure bytecode. + 143 10001111 llllkkkk jjjjjjjj iiiiiiii Push Closure Num Copied llll Num Args kkkk BlockSize jjjjjjjjiiiiiiii" + ^4! Item was removed: - ----- Method: MessageNode>>checkBlock:as:from: (in category 'private') ----- - checkBlock: node as: nodeName from: encoder - - ^self checkBlock: node as: nodeName from: encoder maxArgs: 0! Item was changed: ----- Method: MessageNode>>sizeCodeForRepeat:value: (in category 'code generation') ----- sizeCodeForRepeat: encoder value: forValue "L1: ... Jmp(L1) nil (nil for value only);" | loopSize | + "We assume long backward branches are always maximal size branches." + loopSize := (receiver sizeCodeForEvaluatedEffect: encoder) + (encoder sizeJumpLong: -1). - loopSize := (receiver sizeCodeForEvaluatedEffect: encoder) + (encoder sizeJumpLong: 1). sizes := Array with: loopSize. ^loopSize + (forValue ifTrue: [encoder sizePushSpecialLiteral: nil] ifFalse: [0])! Item was changed: ----- Method: MessageNode>>sizeCodeForWhile:value: (in category 'code generation') ----- sizeCodeForWhile: encoder value: forValue "L1: ... Bfp(L2) ... Jmp(L1) L2: nil (nil for value only); justStmt, wholeLoop, justJump." | cond stmt stmtSize loopSize branchSize | cond := receiver. stmt := arguments at: 1. + "We assume long backward branches are always maximal size branches." + stmtSize := (stmt sizeCodeForEvaluatedEffect: encoder) + (encoder sizeJumpLong: -1). - stmtSize := (stmt sizeCodeForEvaluatedEffect: encoder) + (encoder sizeJumpLong: 1). branchSize := self sizeCode: encoder forBranchOn: selector key == #whileFalse: "Btp for whileFalse" dist: stmtSize. loopSize := (cond sizeCodeForEvaluatedValue: encoder) + branchSize + stmtSize. sizes := Array with: stmtSize with: loopSize. ^loopSize + (forValue ifTrue: [encoder sizePushSpecialLiteral: nil] ifFalse: [0])! Item was changed: ----- Method: MessageNode>>transformBoolean: (in category 'macro transformations') ----- transformBoolean: encoder ^self checkBlock: (arguments at: 1) as: 'argument' + from: encoder + maxArgs: 0! - from: encoder! Item was changed: ----- Method: MessageNode>>transformCase: (in category 'macro transformations') ----- transformCase: encoder | caseNode | caseNode := arguments first. + (caseNode isMemberOf: BraceNode) ifFalse: [^false]. + (caseNode blockAssociationCheck: encoder) ifFalse: [^false]. + (arguments size = 1 + or: [self checkBlock: arguments last as: 'otherwise arg' from: encoder maxArgs: 0]) ifFalse: + [^false]. + caseNode elements do: + [:messageNode | - (caseNode isMemberOf: BraceNode) ifFalse: [ ^false ]. - (caseNode blockAssociationCheck: encoder) ifFalse: [ ^false ]. - (arguments size = 1 or: [ - self checkBlock: arguments last as: 'otherwise arg' from: encoder ]) ifFalse: [ - ^false ]. - caseNode elements do: [ :messageNode | messageNode receiver noteOptimizedIn: self. + messageNode arguments first noteOptimizedIn: self]. + arguments size = 2 ifTrue: + [arguments last noteOptimizedIn: self]. - messageNode arguments first noteOptimizedIn: self ]. - arguments size = 2 ifTrue: [ arguments last noteOptimizedIn: self ]. ^true! Item was changed: ----- Method: MessageNode>>transformIfFalseIfTrue: (in category 'macro transformations') ----- transformIfFalseIfTrue: encoder + ^(self checkBlock: (arguments at: 1) as: 'False arg' from: encoder maxArgs: 0) + and: [(self checkBlock: (arguments at: 2) as: 'True arg' from: encoder maxArgs: 0) - ^(self checkBlock: (arguments at: 1) as: 'False arg' from: encoder) - and: [(self checkBlock: (arguments at: 2) as: 'True arg' from: encoder) and: [selector := SelectorNode new key: #ifTrue:ifFalse: code: #macro. arguments swap: 1 with: 2. arguments do: [:arg| arg noteOptimizedIn: self]. true]]! Item was changed: ----- Method: MessageNode>>transformIfTrueIfFalse: (in category 'macro transformations') ----- transformIfTrueIfFalse: encoder + ^(self checkBlock: (arguments at: 1) as: 'True arg' from: encoder maxArgs: 0) + and: [(self checkBlock: (arguments at: 2) as: 'False arg' from: encoder maxArgs: 0) - ^(self checkBlock: (arguments at: 1) as: 'True arg' from: encoder) - and: [(self checkBlock: (arguments at: 2) as: 'False arg' from: encoder) and: [arguments do: [:arg| arg noteOptimizedIn: self]. true]]! Item was changed: ----- Method: MessageNode>>transformRepeat: (in category 'macro transformations') ----- transformRepeat: encoder "answer true if this #repeat message can be optimized" + ^(self checkBlock: receiver as: 'receiver' from: encoder maxArgs: 0) - ^(self checkBlock: receiver as: 'receiver' from: encoder) and: [receiver noteOptimizedIn: self. true]! Item was changed: ----- Method: MessageNode>>transformWhile: (in category 'macro transformations') ----- transformWhile: encoder + (self checkBlock: receiver as: 'receiver' from: encoder maxArgs: 0) ifFalse: - (self checkBlock: receiver as: 'receiver' from: encoder) ifFalse: [^false]. arguments size = 0 ifTrue: "transform bodyless form to body form" [selector := SelectorNode new key: (special = 10 ifTrue: [#whileTrue:] ifFalse: [#whileFalse:]) code: #macro. arguments := Array with: ((BlockNode withJust: NodeNil) noteOptimizedIn: self). receiver noteOptimizedIn: self. ^true]. ^(self transformBoolean: encoder) and: [receiver noteOptimizedIn: self. arguments first noteOptimizedIn: self. true]! Item was added: + LiteralNode subclass: #SpecialLiteralNode + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'Compiler-ParseNodes'! Item was added: + ----- Method: SpecialLiteralNode>>emitCodeForValue:encoder: (in category 'code generation (closures)') ----- + emitCodeForValue: stack encoder: encoder + stack push: 1. + encoder genPushSpecialLiteral: key! Item was added: + ----- Method: SpecialLiteralNode>>sizeCodeForValue: (in category 'code generation (closures)') ----- + sizeCodeForValue: encoder + ^encoder sizePushSpecialLiteral: key! Item was added: + SelectorNode subclass: #SpecialSelectorNode + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'Compiler-ParseNodes'! Item was added: + ----- Method: SpecialSelectorNode>>emitCode:args:encoder:super: (in category 'code generation') ----- + emitCode: stack args: nArgs encoder: encoder super: supered + "Generate a special selector send. + A super send of a special selector must be handled like a normal send." + supered + ifTrue: + [super emitCode: stack args: nArgs encoder: encoder super: supered] + ifFalse: + [stack pop: nArgs. + encoder genSendSpecial: code numArgs: nArgs]! Item was added: + ----- Method: SpecialSelectorNode>>sizeCode:args:super: (in category 'code generation') ----- + sizeCode: encoder args: nArgs super: supered + "Size a special selector send. + A super send of a special selector must be handled like a normal send." + ^supered + ifTrue: [super sizeCode: encoder args: nArgs super: supered] + ifFalse: [encoder sizeSendSpecial: code numArgs: nArgs]! Item was changed: ----- Method: VariableNode class>>initialize (in category 'class initialization') ----- initialize "VariableNode initialize. Decompiler initialize" | encoder | encoder := Encoder new. StdVariables := Dictionary new: 16. encoder fillDict: StdVariables with: VariableNode mapping: #('self' 'thisContext' 'super' 'nil' 'false' 'true' ) to: (Array with: LdSelf with: LdThisContext with: LdSuper) , (Array with: LdNil with: LdFalse with: LdTrue). StdSelectors := Dictionary new: 64. encoder fillDict: StdSelectors + with: SpecialSelectorNode - with: SelectorNode mapping: ((1 to: Smalltalk specialSelectorSize) collect: [:i | Smalltalk specialSelectorAt: i]) + to: (1 to: Smalltalk specialSelectorSize) asArray. - to: (SendPlus to: SendPlus + 31). StdLiterals := PluggableDictionary new equalBlock: [ :x :y | x literalEqual: y ]. encoder fillDict: StdLiterals with: LiteralNode mapping: #(-1 0 1 2 ) to: (LdMinus1 to: LdMinus1 + 3). encoder initScopeAndLiteralTables. NodeNil := encoder encodeVariable: 'nil'. NodeTrue := encoder encodeVariable: 'true'. NodeFalse := encoder encodeVariable: 'false'. NodeSelf := encoder encodeVariable: 'self'. NodeThisContext := encoder encodeVariable: 'thisContext'. NodeSuper := encoder encodeVariable: 'super'! |
Free forum by Nabble | Edit this page |