[squeak-dev] The Inbox: Compiler-ul.188.mcz

commits at source.squeak.org commits at source.squeak.org
Sun Feb 13 18:42:38 UTC 2011

A new version of Compiler was added to project The Inbox:

==================== Summary ====================

Name: Compiler-ul.188
Author: ul
Time: 13 February 2011, 7:38:28.952 pm
UUID: b00de2ae-de9b-2940-bbd9-be84eb1f344b
Ancestors: Compiler-nice.187, Compiler-nice.186, Compiler-fbs.183

- merged
- changed the postscript to recompile all methods which send #repeat

=============== Diff against Compiler-nice.187 ===============

Item was changed:
  InstructionStream subclass: #Decompiler
+ 	instanceVariableNames: 'constructor method instVars tempVars constTable stack statements lastPc exit caseExits lastJumpPc lastReturnPc limit hasValue blockStackBase numLocalTemps blockStartsToTempVars tempVarCount lastJumpIfPcStack'
- 	instanceVariableNames: 'constructor method instVars tempVars constTable stack statements lastPc exit caseExits lastJumpPc lastReturnPc limit hasValue blockStackBase numLocalTemps blockStartsToTempVars tempVarCount'
  	classVariableNames: 'ArgumentFlag CascadeFlag CaseFlag IfNilFlag'
  	poolDictionaries: ''
  	category: 'Compiler-Kernel'!
+ !Decompiler commentStamp: 'nice 2/3/2011 22:54' prior: 0!
- !Decompiler commentStamp: 'nice 3/1/2010 19:56' prior: 0!
  I decompile a method in three phases:
  	Reverser: postfix byte codes -> prefix symbolic codes (nodes and atoms)
  	Parser: prefix symbolic codes -> node tree (same as the compiler)
  	Printer: node tree -> text (done by the nodes)
  instance vars:
  	constructor <DecompilerConstructor> an auxiliary knowing how to generate Abstract Syntax Tree (node tree)
  	method <CompiledMethod> the method being decompiled
  	instVars <Array of: String> the instance variables of the class implementing method
  	tempVars <String | (OrderedCollection of: String)> hold the names of temporary variables (if known)
  	constTable <Collection of: ParseNode> parse node associated with byte encoded constants (nil true false 0 1 -1 etc...)
  	stack <OrderedCollection of: (ParseNode | String | Integer) > multipurpose...
  	statements <OrderedCollection of: ParseNode> the statements of the method being decompiled 
  	lastPc <Integer>
  	exit <Integer>
  	caseExits <OrderedCollection of: Integer> - stack of exit addresses that have been seen in the branches of caseOf:'s
  	lastJumpPc <Integer>
  	lastReturnPc <Integer>
  	limit <Integer>
  	hasValue <Boolean>
  	blockStackBase <Integer>
  	numLocaltemps <Integer | Symbol> - number of temps local to a block; also a flag indicating decompiling a block
  	blockStartsToTempVars <Dictionary key: Integer value: (OrderedCollection of: String)>
+ 	tempVarCount <Integer> number of temp vars used by the method
+ 	lastJumpIfPcStack <OrderedCollection of: Integer> the value of program counter just before the last encountered conditional jumps!
- 	tempVarCount <Integer> number of temp vars used by the method!

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]
  			[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 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>>interpretNextInstructionFor: (in category 'private') -----
  interpretNextInstructionFor: client
  	| code varNames |
  "Change false here will trace all state in Transcript."
  true ifTrue: [^ super interpretNextInstructionFor: client].
  	varNames := self class allInstVarNames.
  	code := (self method at: pc) radix: 16.
  	Transcript cr; cr; print: pc; space;
+ 		nextPutAll: '<' , code, '>'.
- 		nextPutAll: '<' , (code copyFrom: 4 to: code size), '>'.
  	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: Decompiler>>jump: (in category 'instruction decoding') -----
  jump: dist
+ 	| blockBody destPc nextPC |
+ 	destPc := pc + dist.
+ 	(lastJumpIfPcStack isEmpty or: [dist < 0 and: [destPc > lastJumpIfPcStack last]])
+ 		ifTrue:
+ 			["Rule: aBackward jump not crossing a Bfp/Btp must be a repeat"
+ 			nextPC := pc.
+ 			pc := destPc.
+ 			blockBody := self statementsTo: lastPc.
+ 			blockBody size timesRepeat: [statements removeLast].
+ 			pc := nextPC.
+ 			statements addLast:
+ 				(constructor
+ 					codeMessage: (constructor codeBlock: blockBody returns: false)
+ 					selector: (constructor
+ 								codeSelector: #repeat
+ 								code: #macro)
+ 					arguments: #()).
+ 			]
+ 		ifFalse:
+ 			[exit := destPc.
+ 			lastJumpPc := lastPc]!
- 	exit := pc + dist.
- 	lastJumpPc := lastPc!

Item was changed:
  ----- Method: Decompiler>>jump:if: (in category 'instruction decoding') -----
  jump: dist if: condition
  	| savePc sign elsePc elseStart end cond ifExpr thenBlock elseBlock
  	  thenJump elseJump condHasValue isIfNil saveStack blockBody |
+ 	lastJumpIfPcStack addLast: lastPc.
+ 	stack last == CascadeFlag ifTrue: [^ [self case: dist] ensure: [lastJumpIfPcStack removeLast]].
- 	stack last == CascadeFlag ifTrue: [^ self case: dist].
  	elsePc := lastPc.
  	elseStart := pc + dist.
  	end := limit.
  	"Check for bfp-jmp to invert condition.
  	Don't be fooled by a loop with a null body."
  	sign := condition.
  	savePc := pc.
  	self interpretJump ifNotNil:
  		 (elseDist >= 0 and: [elseStart = pc]) ifTrue:
  			 [sign := sign not.  elseStart := pc + elseDist]].
  	pc := savePc.
  	ifExpr := stack removeLast.
  	(isIfNil := stack size > 0 and: [stack last == IfNilFlag]) ifTrue:
  		[stack removeLast].
  	saveStack := stack.
  	stack := OrderedCollection new.
  	thenBlock := self blockTo: elseStart.
  	condHasValue := hasValue or: [isIfNil].
  	"ensure jump is within block (in case thenExpr returns)"
  	thenJump := exit <= end ifTrue: [exit] ifFalse: [elseStart].
  	"if jump goes back, then it's a loop"
  	thenJump < elseStart
  			["Must be a while loop...
  			  thenJump will jump to the beginning of the while expr.  In the case of while's
  			  with a block in the condition, the while expr should include more than just
  			  the last expression: find all the statements needed by re-decompiling."
  			stack := saveStack.
  			pc := thenJump.
  			blockBody := self statementsTo: elsePc.
  			"discard unwanted statements from block"
  			blockBody size - 1 timesRepeat: [statements removeLast].
  			statements addLast:
  					codeMessage: (constructor codeBlock: blockBody returns: false)
  					selector: (constructor
  								codeSelector: (sign
  												ifTrue: [#whileFalse:]
  												ifFalse: [#whileTrue:])
  								code: #macro)
  					arguments: { thenBlock }).
  			pc := elseStart.
  			self convertToDoLoop]
  			["Must be a conditional..."
  			elseBlock := self blockTo: thenJump.
  			elseJump := exit.
  			"if elseJump is backwards, it is not part of the elseExpr"
  			elseJump < elsePc ifTrue:
  				[pc := lastPc].
  			cond := isIfNil
  								codeMessage: ifExpr ifNilReceiver
  								selector: (constructor
  											codeSelector: (sign ifTrue: [#ifNotNil:] ifFalse: [#ifNil:])
  											code: #macro)
  								arguments: (Array with: thenBlock)]
  								codeMessage: ifExpr
  								selector: (constructor codeSelector: #ifTrue:ifFalse: code: #macro)
  								arguments:	(sign
  												ifTrue: [{elseBlock. thenBlock}]
  												ifFalse: [{thenBlock. elseBlock}])].
  			stack := saveStack.
  				ifTrue: [stack addLast: cond]
+ 				ifFalse: [statements addLast: cond]].
+ 	lastJumpIfPcStack removeLast.!
- 				ifFalse: [statements addLast: cond]]!

Item was changed:
  ----- Method: MessageNode class>>initialize (in category 'class initialization') -----
+ initialize
+ 	"MessageNode initialize"
- initialize		"MessageNode initialize"
  	MacroSelectors := 
  		#(	ifTrue: ifFalse: ifTrue:ifFalse: ifFalse:ifTrue:
  			and: or:
  			whileFalse: whileTrue: whileFalse whileTrue
  			to:do: to:by:do:
  			caseOf: caseOf:otherwise:
+ 			ifNil: ifNotNil:  ifNil:ifNotNil: ifNotNil:ifNil:
+ 			repeat ).
- 			ifNil: ifNotNil:  ifNil:ifNotNil: ifNotNil:ifNil:).
  	MacroTransformers := 
  		#(	transformIfTrue: transformIfFalse: transformIfTrueIfFalse: transformIfFalseIfTrue:
  			transformAnd: transformOr:
  			transformWhile: transformWhile: transformWhile: transformWhile:
  			transformToDo: transformToDo:
  			transformCase: transformCase:
+ 			transformIfNil: transformIfNil:  transformIfNilIfNotNil: transformIfNotNilIfNil:
+ 			transformRepeat: ).
- 			transformIfNil: transformIfNil:  transformIfNilIfNotNil: transformIfNotNilIfNil:).
  	MacroEmitters := 
  		#(	emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:
  			emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:
  			emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:
  			emitCodeForWhile:encoder:value: emitCodeForWhile:encoder:value:
  			emitCodeForWhile:encoder:value: emitCodeForWhile:encoder:value:
  			emitCodeForToDo:encoder:value: emitCodeForToDo:encoder:value:
  			emitCodeForCase:encoder:value: emitCodeForCase:encoder:value:
  			emitCodeForIfNil:encoder:value: emitCodeForIfNil:encoder:value:
+ 			emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:
+ 			emitCodeForRepeat:encoder:value:).
- 			emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:).
  	MacroSizers := 
  		#(	sizeCodeForIf:value: sizeCodeForIf:value: sizeCodeForIf:value: sizeCodeForIf:value:
  			sizeCodeForIf:value: sizeCodeForIf:value:
  			sizeCodeForWhile:value: sizeCodeForWhile:value: sizeCodeForWhile:value: sizeCodeForWhile:value:
  			sizeCodeForToDo:value: sizeCodeForToDo:value:
  			sizeCodeForCase:value: sizeCodeForCase:value:
+ 			sizeCodeForIfNil:value: sizeCodeForIfNil:value: sizeCodeForIf:value: sizeCodeForIf:value:
+ 			sizeCodeForRepeat:value:).
- 			sizeCodeForIfNil:value: sizeCodeForIfNil:value: sizeCodeForIf:value: sizeCodeForIf:value:).
  	MacroPrinters := 
  		#(	printIfOn:indent: printIfOn:indent: printIfOn:indent: printIfOn:indent:
  			printIfOn:indent: printIfOn:indent:
  			printWhileOn:indent: printWhileOn:indent: printWhileOn:indent: printWhileOn:indent:
  			printToDoOn:indent: printToDoOn:indent:
  			printCaseOn:indent: printCaseOn:indent:
+ 			printIfNil:indent: printIfNil:indent: printIfNilNotNil:indent: printIfNilNotNil:indent:
+ 			printRepeatOn:indent:)!
- 			printIfNil:indent: printIfNil:indent: printIfNilNotNil:indent: printIfNilNotNil:indent:)!

Item was added:
+ ----- Method: MessageNode>>emitCodeForRepeat:encoder:value: (in category 'code generation') -----
+ emitCodeForRepeat: stack encoder: encoder value: forValue 
+ 	" L1: ... Jmp(L1)"
+ 	| loopSize |
+ 	loopSize := sizes at: 1.
+ 	receiver emitCodeForEvaluatedEffect: stack encoder: encoder.
+ 	self emitCodeForJump: 0 - loopSize encoder: encoder.
+ 	forValue ifTrue: [encoder genPushSpecialLiteral: nil. stack push: 1]!

Item was added:
+ ----- Method: MessageNode>>printRepeatOn:indent: (in category 'printing') -----
+ printRepeatOn: aStream indent: level
+ 	self printReceiver: receiver on: aStream indent: level.
+ 	^self printKeywords: selector key
+ 		arguments: (Array new)
+ 		on: aStream indent: level!

Item was added:
+ ----- Method: MessageNode>>sizeCodeForRepeat:value: (in category 'code generation') -----
+ sizeCodeForRepeat: encoder value: forValue 
+ 	"L1: ... Jmp(L1) nil (nil for value only);"
+ 	| loopSize |
+ 	loopSize := (receiver sizeCodeForEvaluatedEffect: encoder) + (encoder sizeJumpLong: 1).
+ 	sizes := Array with: loopSize.
+ 	^loopSize + (forValue ifTrue: [encoder sizePushSpecialLiteral: nil] ifFalse: [0])!

Item was added:
+ ----- 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)
+ 	   and: [receiver noteOptimizedIn: self.
+ 			true]!

Item was changed:
+ (PackageInfo named: 'Compiler') postscript: '"Recompile methods which send #repeat."
+ (SystemNavigation default allCallsOn: #repeat) do: [ :each |
+ 	each actualClass recompile: each selector ].
+ '!
- (PackageInfo named: 'Compiler') postscript: '"''''Fix'''' some decompiler tests."
- CompiledMethod allInstances
- 	do: [ :method |
- 		[ method decompileWithTemps ]
- 			on: AssertionFailure, Error
- 			do: [ method methodClass recompile: method selector ] ]
- 	displayingProgress: ''Recompiling...''
- 	every: 1000'!

More information about the Squeak-dev mailing list