[squeak-dev] The Trunk: Compiler-ar.107.mcz
commits at source.squeak.org
commits at source.squeak.org
Tue Dec 22 11:38:41 UTC 2009
Andreas Raab uploaded a new version of Compiler to project The Trunk:
http://source.squeak.org/trunk/Compiler-ar.107.mcz
==================== Summary ====================
Name: Compiler-ar.107
Author: ar
Time: 22 December 2009, 12:38:17 pm
UUID: 46345836-169c-a245-aa07-b546b826fdc4
Ancestors: Compiler-jcg.106
CompiledMethodTrailer phase 1: Preparations.
=============== Diff against Compiler-jcg.106 ===============
Item was changed:
----- Method: MethodNode>>rawSourceRangesAndMethodDo: (in category 'source mapping') -----
rawSourceRangesAndMethodDo: aBinaryBlock
"Evaluate aBinaryBlock with the rawSourceRanges and method generated from the receiver."
| methNode method |
methNode := encoder classEncoding parserClass new
encoderClass: encoder class;
parse: (sourceText "If no source, use decompile string as source to map from"
ifNil: [self decompileString]
ifNotNil: [sourceText])
class: self methodClass.
+ method := methNode generate. "set bytecodes to map to"
- method := methNode generate: #(0 0 0 0). "set bytecodes to map to"
^aBinaryBlock
value: methNode encoder rawSourceRanges
value: method!
Item was changed:
----- Method: ClosureCompilerTest>>testInjectIntoDecompiledDebugs (in category 'tests') -----
testInjectIntoDecompiledDebugs
"Test various debugs of the decompiled form debug correctly."
"self new testInjectIntoDecompiledDebugs"
| source |
source := (Collection sourceCodeAt: #inject:into:) asString.
{ Encoder.
EncoderForV3PlusClosures. EncoderForLongFormV3PlusClosures } do:
[:encoderClass| | method |
method := (Parser new
encoderClass: encoderClass;
parse: source
class: Collection)
+ generate.
- generate: #(0 0 0 0).
self supportTestSourceRangeAccessForDecompiledInjectInto: method source: method decompileString]!
Item was changed:
----- Method: ClosureCompilerTest>>testBlockNumberingForInjectInto (in category 'tests') -----
testBlockNumberingForInjectInto
"Test that the compiler and CompiledMethod agree on the block numbering of Collection>>inject:into:
and that temp names for inject:into: are recorded."
"self new testBlockNumberingForInjectInto"
| methodNode method tempRefs |
methodNode := Parser new
encoderClass: EncoderForV3PlusClosures;
parse: (Collection sourceCodeAt: #inject:into:)
class: Collection.
+ method := methodNode generate.
- method := methodNode generate: #(0 0 0 0).
tempRefs := methodNode encoder blockExtentsToTempsMap.
self assert: tempRefs keys asSet = method startpcsToBlockExtents values asSet.
self assert: ((tempRefs includesKey: (0 to: 6))
and: [(tempRefs at: (0 to: 6)) hasEqualElements: #(('thisValue' 1) ('binaryBlock' 2) ('nextValue' (3 1)))]).
self assert: ((tempRefs includesKey: (2 to: 4))
and: [(tempRefs at: (2 to: 4)) hasEqualElements: #(('each' 1) ('binaryBlock' 2) ('nextValue' (3 1)))])!
Item was changed:
----- Method: BytecodeAgnosticMethodNode>>schematicTempNamesString (in category 'debugger support') -----
schematicTempNamesString
"Answer the temp names for the current method node in a form that captures
temp structure. The temps at each method and block scope level occur
space-separated, with any indirect temps enclosed in parentheses. Each block
level is enclosed in square brackets. e.g.
'method level temps (indirect temp)[block args and temps (indirect)]'
This representation can be reconstituted into a blockExtentsToTempsMap
by a CompiledMethod that has been copied with the schematicTempNamesString."
encoder hasGeneratedMethod ifFalse:
["create the encoder's blockExtentsToLoals map, except if the method is quick
in which case it has no temps."
+ (self generate) isQuick ifTrue:
- (self generate: #(0 0 0 0)) isQuick ifTrue:
[^'']].
^encoder schematicTempNamesString!
Item was changed:
----- Method: BytecodeAgnosticMethodNode>>blockExtentsToTempsMap (in category 'debugger support') -----
blockExtentsToTempsMap
"Answer a Dictionary of blockExtent to temp locations for the current method.
This is used by the debugger to locate temp vars in contexts. A temp map
entry is a pair of the temp's name and its index, where an index is either an
integer for a normal temp or a pair of the index of the indirect temp vector
containing the temp and the index of the temp in its indirect temp vector."
^encoder blockExtentsToTempsMap ifNil:
[| methNode |
methNode := encoder classEncoding parserClass new
encoderClass: encoder class;
parse: (sourceText ifNil: [self decompileString])
class: self methodClass.
"As a side effect generate: creates data needed for the map."
+ methNode generate.
- methNode generate: #(0 0 0 0).
methNode encoder blockExtentsToTempsMap]!
Item was changed:
----- Method: ClosureCompilerTest>>testBlockNumbering (in category 'tests') -----
testBlockNumbering
"Test that the compiler and CompiledMethod agree on the block numbering of a substantial doit."
"self new testBlockNumbering"
| methodNode method tempRefs |
methodNode :=
Parser new
encoderClass: EncoderForV3PlusClosures;
parse: 'foo
| numCopiedValuesCounts |
numCopiedValuesCounts := Dictionary new.
0 to: 32 do: [:i| numCopiedValuesCounts at: i put: 0].
Transcript clear.
Smalltalk allClasses remove: GeniePlugin; do:
[:c|
{c. c class} do:
[:b|
Transcript nextPut: b name first; endEntry.
b selectorsAndMethodsDo:
[:s :m| | pn |
m isQuick not ifTrue:
[pn := b parserClass new
encoderClass: EncoderForV3PlusClosures;
parse: (b sourceCodeAt: s)
class: b.
+ pn generate.
- pn generate: #(0 0 0 0).
[pn accept: nil]
on: MessageNotUnderstood
do: [:ex| | msg numCopied |
msg := ex message.
(msg selector == #visitBlockNode:
and: [(msg argument instVarNamed: ''optimized'') not]) ifTrue:
[numCopied := (msg argument computeCopiedValues: pn) size.
numCopiedValuesCounts
at: numCopied
put: (numCopiedValuesCounts at: numCopied) + 1].
msg setSelector: #==.
ex resume: nil]]]]].
numCopiedValuesCounts'
class: Object.
+ method := methodNode generate.
- method := methodNode generate: #(0 0 0 0).
tempRefs := methodNode encoder blockExtentsToTempsMap.
self assert: tempRefs keys asSet = method startpcsToBlockExtents values asSet!
Item was changed:
----- Method: ClosureCompilerTest>>testMethodAndNodeTempNames (in category 'tests') -----
testMethodAndNodeTempNames
"self new testMethodAndNodeTempNames"
"Test that BytecodeAgnosticMethodNode>>blockExtentsToTempRefs answers the same
structure as CompiledMethod>>blockExtentsToTempRefs when the method has been
copied with the appropriate temps. This tests whether doit methods are debuggable
since they carry their own temps."
self closureCases do:
[:source| | mn om m mbe obe |
mn := source first isLetter
ifTrue:
[self class compilerClass new
compile: source
in: self class
notifying: nil
ifFail: [self error: 'compilation error']]
ifFalse:
[self class compilerClass new
compileNoPattern: source
in: self class
context: nil
notifying: nil
ifFail: [self error: 'compilation error']].
+ m := (om := mn generate) copyWithTempsFromMethodNode: mn.
- m := (om := mn generate: #(0 0 0 0)) copyWithTempsFromMethodNode: mn.
self assert: m holdsTempNames.
self assert: m endPC = om endPC.
mbe := m blockExtentsToTempsMap.
obe := mn blockExtentsToTempsMap.
self assert: mbe keys asSet = obe keys asSet.
(mbe keys intersection: obe keys) do:
[:interval|
self assert: (mbe at: interval) = (obe at: interval)]]!
Item was added:
+ ----- Method: BytecodeAgnosticMethodNode>>generateWithTempNames (in category 'code generation (new scheme)') -----
+ generateWithTempNames
+ "Answer a CompiledMethod with temps names encoded in trailer"
+ ^ self generate: (CompiledMethodTrailer new tempNames: self schematicTempNamesString).
+ !
Item was changed:
----- Method: ClosureCompilerTest>>testDecompiledDoitMethodTempNames (in category 'tests') -----
testDecompiledDoitMethodTempNames
"self new testDecompiledDoitMethodTempNames"
"Test that a decompiled doit that has been copied with temps decompiles to the input"
| removeComments |
removeComments := [:n| n comment: nil].
self closureCases do:
[:source| | mns m mps mnps |
"Need to compare an ungenerated tree with the generated method's methodNode
because generating code alters the tree when it introduces remote temp vectors."
mns := #(first last) collect:
[:ignored|
source first isLetter
ifTrue:
[self class compilerClass new
compile: source
in: self class
notifying: nil
ifFail: [self error: 'compilation error']]
ifFalse:
[self class compilerClass new
compileNoPattern: source
in: self class
context: nil
notifying: nil
ifFail: [self error: 'compilation error']]].
+ m := (mns last generateWithTempNames).
- m := (mns last generate: #(0 0 0 0)) copyWithTempsFromMethodNode: mns last.
removeComments value: mns first.
mns first nodesDo: removeComments.
self assert: (mnps := mns first printString) = (mps := m methodNode printString)]!
Item was changed:
----- Method: ClosureCompilerTest>>testTempNameAccessForInjectInto (in category 'tests') -----
testTempNameAccessForInjectInto
"self new testTempNameAccessForInjectInto"
| methodNode method evaluationCount block debuggerMap |
methodNode := Parser new
encoderClass: EncoderForV3PlusClosures;
parse: (Collection sourceCodeAt: #inject:into:)
class: Collection.
+ method := methodNode generate.
- method := methodNode generate: #(0 0 0 0).
debuggerMap := DebuggerMethodMap forMethod: method methodNode: methodNode.
evaluationCount := 0.
block := [:prev :each| | theContext tempNames |
evaluationCount := evaluationCount + 1.
theContext := thisContext sender.
tempNames := debuggerMap tempNamesForContext: theContext.
self assert: (tempNames hasEqualElements: tempNames).
#('thisValue' 'each' 'binaryBlock' 'nextValue')
with: { 0. each. block. prev}
do: [:tempName :value|
self assert: (debuggerMap namedTempAt: (tempNames indexOf: tempName) in: theContext) == value.
tempName ~= 'each' ifTrue:
[self assert: (debuggerMap namedTempAt: (tempNames indexOf: tempName) in: theContext home) == value]]].
(1 to: 10) withArgs: { 0. block } executeMethod: method.
self assert: evaluationCount = 10!
Item was changed:
----- Method: DecompilerTests>>checkDecompileMethod: (in category 'utilities') -----
checkDecompileMethod: oldMethod
| cls selector oldMethodNode methodNode newMethod oldCodeString newCodeString |
cls := oldMethod methodClass.
selector := oldMethod selector.
oldMethodNode := cls decompilerClass new
decompile: selector
in: cls
method: oldMethod.
[oldMethodNode properties includesKey: #warning] whileTrue:
[oldMethodNode properties removeKey: #warning].
oldCodeString := oldMethodNode decompileString.
methodNode := [cls compilerClass new
compile: oldCodeString
in: cls
notifying: nil
ifFail: []]
on: SyntaxErrorNotification
do: [:ex|
ex errorMessage = 'Cannot store into' ifTrue:
[ex return: #badStore].
ex pass].
"Ignore cannot store into block arg errors; they're not our issue."
methodNode ~~ #badStore ifTrue:
+ [newMethod := methodNode generate.
- [newMethod := methodNode generate: #(0 0 0 0).
newCodeString := (cls decompilerClass new
decompile: selector
in: cls
method: newMethod) decompileString.
"(StringHolder new textContents:
(TextDiffBuilder buildDisplayPatchFrom: oldCodeString to: newCodeString))
openLabel: 'Decompilation Differences for ', cls name,'>>',selector"
"(StringHolder new textContents:
(TextDiffBuilder buildDisplayPatchFrom: oldMethod abstractSymbolic to: newMethod abstractSymbolic))
openLabel: 'Bytecode Differences for ', cls name,'>>',selector"
self assert: oldCodeString = newCodeString
description: cls name asString, ' ', selector asString
resumable: true]!
Item was changed:
----- Method: ClosureCompilerTest>>testInjectIntoDecompilations (in category 'tests') -----
testInjectIntoDecompilations
"Test various compilations decompile to the same code for a method sufficiently
simple that this is possible and sufficiently complex that the code generated
varies between the compilations."
"self new testInjectIntoDecompilations"
| source |
source := (Collection sourceCodeAt: #inject:into:) asString.
{ Encoder.
EncoderForV3. EncoderForLongFormV3.
EncoderForV3PlusClosures. EncoderForLongFormV3PlusClosures } do:
[:encoderClass| | method |
method := (Parser new
encoderClass: encoderClass;
parse: source
class: Collection)
+ generate.
- generate: #(0 0 0 0).
self assert: (Scanner new scanTokens: method decompileString)
= #(inject: t1 into: t2
| t3 |
t3 ':=' t1 .
self do: [ ':t4' | t3 ':=' t2 value: t3 value: t4 ] .
^ t3)]!
More information about the Squeak-dev
mailing list
|