Browse Source

Merge pull request #311 from herby/inner-alias-inline-ordering

Inner alias inline ordering problem.
Nicolas Petton 12 years ago
parent
commit
77f30df6ea

+ 21 - 0
js/Compiler-AST.deploy.js

@@ -186,6 +186,27 @@ return self}
 }),
 smalltalk.Node);
 
+smalltalk.addMethod(
+"_subtreeNeedsAliasing",
+smalltalk.method({
+selector: "subtreeNeedsAliasing",
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(smalltalk.send(smalltalk.send(self,"_shouldBeAliased",[]),"_or_",[(function(){
+return smalltalk.send(self,"_shouldBeInlined",[]);
+})]),"_or_",[(function(){
+return smalltalk.send(smalltalk.send(smalltalk.send(self,"_nodes",[]),"_detect_ifNone_",[(function(node){
+return smalltalk.send(node,"_subtreeNeedsAliasing",[]);
+}),(function(){
+return false;
+})]),"_~_eq",[false]);
+})]);
+return $1;
+}
+}),
+smalltalk.Node);
+
 
 
 smalltalk.addClass('AssignmentNode', smalltalk.Node, ['left', 'right'], 'Compiler-AST');

+ 26 - 0
js/Compiler-AST.js

@@ -262,6 +262,32 @@ referencedClasses: []
 }),
 smalltalk.Node);
 
+smalltalk.addMethod(
+"_subtreeNeedsAliasing",
+smalltalk.method({
+selector: "subtreeNeedsAliasing",
+category: 'accessing',
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(smalltalk.send(smalltalk.send(self,"_shouldBeAliased",[]),"_or_",[(function(){
+return smalltalk.send(self,"_shouldBeInlined",[]);
+})]),"_or_",[(function(){
+return smalltalk.send(smalltalk.send(smalltalk.send(self,"_nodes",[]),"_detect_ifNone_",[(function(node){
+return smalltalk.send(node,"_subtreeNeedsAliasing",[]);
+}),(function(){
+return false;
+})]),"_~_eq",[false]);
+})]);
+return $1;
+},
+args: [],
+source: "subtreeNeedsAliasing\x0a    ^(self shouldBeAliased or: [ self shouldBeInlined ]) or: [\x0a        (self nodes detect: [ :node | node subtreeNeedsAliasing ] ifNone: [ false ]) ~= false\x0a    ]",
+messageSends: ["or:", "~=", "detect:ifNone:", "subtreeNeedsAliasing", "nodes", "shouldBeInlined", "shouldBeAliased"],
+referencedClasses: []
+}),
+smalltalk.Node);
+
 
 
 smalltalk.addClass('AssignmentNode', smalltalk.Node, ['left', 'right'], 'Compiler-AST');

+ 20 - 16
js/Compiler-IR.deploy.js

@@ -120,14 +120,12 @@ smalltalk.method({
 selector: "temporallyDependentList:",
 fn: function (nodes){
 var self=this;
-var $1,$3,$2;
+var $1,$2,$4,$3,$5;
 var threshold;
 var result;
 threshold=(0);
 smalltalk.send(nodes,"_withIndexDo_",[(function(each,i){
-$1=smalltalk.send(smalltalk.send(each,"_shouldBeInlined",[]),"_or_",[(function(){
-return smalltalk.send(each,"_shouldBeAliased",[]);
-})]);
+$1=smalltalk.send(each,"_subtreeNeedsAliasing",[]);
 if(smalltalk.assert($1)){
 threshold=i;
 return threshold;
@@ -135,15 +133,17 @@ return threshold;
 })]);
 result=smalltalk.send((smalltalk.OrderedCollection || OrderedCollection),"_new",[]);
 smalltalk.send(nodes,"_withIndexDo_",[(function(each,i){
-$3=smalltalk.send(i,"__lt_eq",[threshold]);
-if(smalltalk.assert($3)){
-$2=smalltalk.send(self,"_alias_",[each]);
+$2=result;
+$4=smalltalk.send(i,"__lt_eq",[threshold]);
+if(smalltalk.assert($4)){
+$3=smalltalk.send(self,"_alias_",[each]);
 } else {
-$2=smalltalk.send(self,"_visit_",[each]);
+$3=smalltalk.send(self,"_visit_",[each]);
 };
-return smalltalk.send(result,"_add_",[$2]);
+return smalltalk.send($2,"_add_",[$3]);
 })]);
-return result;
+$5=result;
+return $5;
 }
 }),
 smalltalk.IRASTTranslator);
@@ -278,12 +278,14 @@ smalltalk.method({
 selector: "visitDynamicArrayNode:",
 fn: function (aNode){
 var self=this;
+var $1;
 var array;
 array=smalltalk.send((smalltalk.IRDynamicArray || IRDynamicArray),"_new",[]);
-smalltalk.send(smalltalk.send(aNode,"_nodes",[]),"_do_",[(function(each){
-return smalltalk.send(array,"_add_",[smalltalk.send(self,"_visit_",[each])]);
+smalltalk.send(smalltalk.send(self,"_temporallyDependentList_",[smalltalk.send(aNode,"_nodes",[])]),"_do_",[(function(each){
+return smalltalk.send(array,"_add_",[each]);
 })]);
-return array;
+$1=array;
+return $1;
 }
 }),
 smalltalk.IRASTTranslator);
@@ -294,12 +296,14 @@ smalltalk.method({
 selector: "visitDynamicDictionaryNode:",
 fn: function (aNode){
 var self=this;
+var $1;
 var dictionary;
 dictionary=smalltalk.send((smalltalk.IRDynamicDictionary || IRDynamicDictionary),"_new",[]);
-smalltalk.send(smalltalk.send(aNode,"_nodes",[]),"_do_",[(function(each){
-return smalltalk.send(dictionary,"_add_",[smalltalk.send(self,"_visit_",[each])]);
+smalltalk.send(smalltalk.send(self,"_temporallyDependentList_",[smalltalk.send(aNode,"_nodes",[])]),"_do_",[(function(each){
+return smalltalk.send(dictionary,"_add_",[each]);
 })]);
-return dictionary;
+$1=dictionary;
+return $1;
 }
 }),
 smalltalk.IRASTTranslator);

+ 26 - 22
js/Compiler-IR.js

@@ -162,14 +162,12 @@ selector: "temporallyDependentList:",
 category: 'visiting',
 fn: function (nodes){
 var self=this;
-var $1,$3,$2;
+var $1,$2,$4,$3,$5;
 var threshold;
 var result;
 threshold=(0);
 smalltalk.send(nodes,"_withIndexDo_",[(function(each,i){
-$1=smalltalk.send(smalltalk.send(each,"_shouldBeInlined",[]),"_or_",[(function(){
-return smalltalk.send(each,"_shouldBeAliased",[]);
-})]);
+$1=smalltalk.send(each,"_subtreeNeedsAliasing",[]);
 if(smalltalk.assert($1)){
 threshold=i;
 return threshold;
@@ -177,19 +175,21 @@ return threshold;
 })]);
 result=smalltalk.send((smalltalk.OrderedCollection || OrderedCollection),"_new",[]);
 smalltalk.send(nodes,"_withIndexDo_",[(function(each,i){
-$3=smalltalk.send(i,"__lt_eq",[threshold]);
-if(smalltalk.assert($3)){
-$2=smalltalk.send(self,"_alias_",[each]);
+$2=result;
+$4=smalltalk.send(i,"__lt_eq",[threshold]);
+if(smalltalk.assert($4)){
+$3=smalltalk.send(self,"_alias_",[each]);
 } else {
-$2=smalltalk.send(self,"_visit_",[each]);
+$3=smalltalk.send(self,"_visit_",[each]);
 };
-return smalltalk.send(result,"_add_",[$2]);
+return smalltalk.send($2,"_add_",[$3]);
 })]);
-return result;
+$5=result;
+return $5;
 },
 args: ["nodes"],
-source: "temporallyDependentList: nodes\x0a\x09| threshold result |\x0a    threshold := 0.\x0a    \x0a    nodes withIndexDo: [ :each :i |\x0a        (each shouldBeInlined or: [ each shouldBeAliased ])\x0a\x09\x09    ifTrue: [ threshold := i ]].\x0a\x0a\x09result := OrderedCollection new.\x0a\x09nodes withIndexDo: [ :each :i | \x0a\x09\x09result add: (i <= threshold\x0a\x09\x09\x09ifTrue: [ self alias: each ]\x0a\x09\x09\x09ifFalse: [ self visit: each ])].\x0a\x0a    ^result\x0a",
-messageSends: ["withIndexDo:", "ifTrue:", "or:", "shouldBeAliased", "shouldBeInlined", "new", "add:", "ifTrue:ifFalse:", "alias:", "visit:", "<="],
+source: "temporallyDependentList: nodes\x0a\x09| threshold result |\x0a    threshold := 0.\x0a    \x0a    nodes withIndexDo: [ :each :i |\x0a        each subtreeNeedsAliasing\x0a\x09\x09    ifTrue: [ threshold := i ]].\x0a\x0a\x09result := OrderedCollection new.\x0a\x09nodes withIndexDo: [ :each :i | \x0a\x09\x09result add: (i <= threshold\x0a\x09\x09\x09ifTrue: [ self alias: each ]\x0a\x09\x09\x09ifFalse: [ self visit: each ])].\x0a\x0a    ^result\x0a",
+messageSends: ["withIndexDo:", "ifTrue:", "subtreeNeedsAliasing", "new", "add:", "ifTrue:ifFalse:", "alias:", "visit:", "<="],
 referencedClasses: ["OrderedCollection"]
 }),
 smalltalk.IRASTTranslator);
@@ -355,16 +355,18 @@ selector: "visitDynamicArrayNode:",
 category: 'visiting',
 fn: function (aNode){
 var self=this;
+var $1;
 var array;
 array=smalltalk.send((smalltalk.IRDynamicArray || IRDynamicArray),"_new",[]);
-smalltalk.send(smalltalk.send(aNode,"_nodes",[]),"_do_",[(function(each){
-return smalltalk.send(array,"_add_",[smalltalk.send(self,"_visit_",[each])]);
+smalltalk.send(smalltalk.send(self,"_temporallyDependentList_",[smalltalk.send(aNode,"_nodes",[])]),"_do_",[(function(each){
+return smalltalk.send(array,"_add_",[each]);
 })]);
-return array;
+$1=array;
+return $1;
 },
 args: ["aNode"],
-source: "visitDynamicArrayNode: aNode\x0a\x09| array |\x0a\x09array := IRDynamicArray new.\x0a\x09aNode nodes do: [ :each | array add: (self visit: each) ].\x0a\x09^ array",
-messageSends: ["new", "do:", "add:", "visit:", "nodes"],
+source: "visitDynamicArrayNode: aNode\x0a\x09| array |\x0a\x09array := IRDynamicArray new.\x0a\x09(self temporallyDependentList: aNode nodes) do: [:each | array add: each].\x0a\x09^ array",
+messageSends: ["new", "do:", "add:", "temporallyDependentList:", "nodes"],
 referencedClasses: ["IRDynamicArray"]
 }),
 smalltalk.IRASTTranslator);
@@ -376,16 +378,18 @@ selector: "visitDynamicDictionaryNode:",
 category: 'visiting',
 fn: function (aNode){
 var self=this;
+var $1;
 var dictionary;
 dictionary=smalltalk.send((smalltalk.IRDynamicDictionary || IRDynamicDictionary),"_new",[]);
-smalltalk.send(smalltalk.send(aNode,"_nodes",[]),"_do_",[(function(each){
-return smalltalk.send(dictionary,"_add_",[smalltalk.send(self,"_visit_",[each])]);
+smalltalk.send(smalltalk.send(self,"_temporallyDependentList_",[smalltalk.send(aNode,"_nodes",[])]),"_do_",[(function(each){
+return smalltalk.send(dictionary,"_add_",[each]);
 })]);
-return dictionary;
+$1=dictionary;
+return $1;
 },
 args: ["aNode"],
-source: "visitDynamicDictionaryNode: aNode\x0a\x09| dictionary |\x0a\x09dictionary := IRDynamicDictionary new.\x0a\x09aNode nodes do: [ :each | dictionary add: (self visit: each) ].\x0a\x09^ dictionary",
-messageSends: ["new", "do:", "add:", "visit:", "nodes"],
+source: "visitDynamicDictionaryNode: aNode\x0a\x09| dictionary |\x0a\x09dictionary := IRDynamicDictionary new.\x0a    (self temporallyDependentList: aNode nodes) do: [:each | dictionary add: each].\x0a\x09^ dictionary",
+messageSends: ["new", "do:", "add:", "temporallyDependentList:", "nodes"],
 referencedClasses: ["IRDynamicDictionary"]
 }),
 smalltalk.IRASTTranslator);

+ 36 - 0
js/Compiler-Tests.deploy.js

@@ -118,6 +118,42 @@ fn: function () {
 }),
 smalltalk.CodeGeneratorTest);
 
+smalltalk.addMethod(
+"_testDynamicArrayElementsOrdered",
+smalltalk.method({
+selector: "testDynamicArrayElementsOrdered",
+fn: function (){
+var self=this;
+smalltalk.send(self,"_should_return_",["foo\x0a  | x |\x0a  x := 1.\x0a  ^ { x. true ifTrue: [ x := 2 ] }\x0a",[(1), (2)]]);
+return self}
+}),
+smalltalk.CodeGeneratorTest);
+
+smalltalk.addMethod(
+"_testDynamicDictionaryElementsOrdered",
+smalltalk.method({
+selector: "testDynamicDictionaryElementsOrdered",
+fn: function (){
+var self=this;
+smalltalk.send(self,"_should_return_",["foo\x0a  | x |\x0a  x := 'foo'->1.\x0a  ^ #{ x. (true ifTrue: [ x := 'bar'->2 ]) }\x0a",smalltalk.HashedCollection._fromPairs_([smalltalk.send("foo","__minus_gt",[(1)]),smalltalk.send("bar","__minus_gt",[(2)])])]);
+return self}
+}),
+smalltalk.CodeGeneratorTest);
+
+smalltalk.addMethod(
+"_testInnerTemporalDependentElementsOrdered",
+smalltalk.method({
+selector: "testInnerTemporalDependentElementsOrdered",
+fn: function (){
+var self=this;
+smalltalk.send(self,"_should_return_",["foo\x0a  | x |\x0a  x := Array.\x0a  ^ x with: 'foo'->x with: 'bar'->(true ifTrue: [ x := 2 ])\x0a",[smalltalk.send("foo","__minus_gt",[(smalltalk.Array || Array)]),smalltalk.send("bar","__minus_gt",[(2)])]]);
+smalltalk.send(self,"_should_return_",["foo\x0a  | x |\x0a  x := 1.\x0a  ^ Array with: 'foo'->x with: 'bar'->(true ifTrue: [ x := 2 ])\x0a",[smalltalk.send("foo","__minus_gt",[(1)]),smalltalk.send("bar","__minus_gt",[(2)])]]);
+smalltalk.send(self,"_should_return_",["foo\x0a  | x |\x0a  x := 1.\x0a  ^ { 'foo'->x. 'bar'->(true ifTrue: [ x := 2 ]) }\x0a",[smalltalk.send("foo","__minus_gt",[(1)]),smalltalk.send("bar","__minus_gt",[(2)])]]);
+smalltalk.send(self,"_should_return_",["foo\x0a  | x |\x0a  x := 1.\x0a  ^ #{ 'foo'->x. 'bar'->(true ifTrue: [ x := 2 ]) }\x0a",smalltalk.HashedCollection._fromPairs_([smalltalk.send("foo","__minus_gt",[(1)]),smalltalk.send("bar","__minus_gt",[(2)])])]);
+return self}
+}),
+smalltalk.CodeGeneratorTest);
+
 smalltalk.addMethod(
 "_testLiterals",
 smalltalk.method({

+ 51 - 0
js/Compiler-Tests.js

@@ -163,6 +163,57 @@ referencedClasses: []
 }),
 smalltalk.CodeGeneratorTest);
 
+smalltalk.addMethod(
+"_testDynamicArrayElementsOrdered",
+smalltalk.method({
+selector: "testDynamicArrayElementsOrdered",
+category: 'tests',
+fn: function (){
+var self=this;
+smalltalk.send(self,"_should_return_",["foo\x0a  | x |\x0a  x := 1.\x0a  ^ { x. true ifTrue: [ x := 2 ] }\x0a",[(1), (2)]]);
+return self},
+args: [],
+source: "testDynamicArrayElementsOrdered\x0a\x09self should: 'foo\x0a  | x |\x0a  x := 1.\x0a  ^ { x. true ifTrue: [ x := 2 ] }\x0a' return: #(1 2).\x0a",
+messageSends: ["should:return:"],
+referencedClasses: []
+}),
+smalltalk.CodeGeneratorTest);
+
+smalltalk.addMethod(
+"_testDynamicDictionaryElementsOrdered",
+smalltalk.method({
+selector: "testDynamicDictionaryElementsOrdered",
+category: 'tests',
+fn: function (){
+var self=this;
+smalltalk.send(self,"_should_return_",["foo\x0a  | x |\x0a  x := 'foo'->1.\x0a  ^ #{ x. (true ifTrue: [ x := 'bar'->2 ]) }\x0a",smalltalk.HashedCollection._fromPairs_([smalltalk.send("foo","__minus_gt",[(1)]),smalltalk.send("bar","__minus_gt",[(2)])])]);
+return self},
+args: [],
+source: "testDynamicDictionaryElementsOrdered\x0a\x09self should: 'foo\x0a  | x |\x0a  x := ''foo''->1.\x0a  ^ #{ x. (true ifTrue: [ x := ''bar''->2 ]) }\x0a' return: #{'foo'->1. 'bar'->2}.\x0a",
+messageSends: ["should:return:", "->"],
+referencedClasses: []
+}),
+smalltalk.CodeGeneratorTest);
+
+smalltalk.addMethod(
+"_testInnerTemporalDependentElementsOrdered",
+smalltalk.method({
+selector: "testInnerTemporalDependentElementsOrdered",
+category: 'tests',
+fn: function (){
+var self=this;
+smalltalk.send(self,"_should_return_",["foo\x0a  | x |\x0a  x := Array.\x0a  ^ x with: 'foo'->x with: 'bar'->(true ifTrue: [ x := 2 ])\x0a",[smalltalk.send("foo","__minus_gt",[(smalltalk.Array || Array)]),smalltalk.send("bar","__minus_gt",[(2)])]]);
+smalltalk.send(self,"_should_return_",["foo\x0a  | x |\x0a  x := 1.\x0a  ^ Array with: 'foo'->x with: 'bar'->(true ifTrue: [ x := 2 ])\x0a",[smalltalk.send("foo","__minus_gt",[(1)]),smalltalk.send("bar","__minus_gt",[(2)])]]);
+smalltalk.send(self,"_should_return_",["foo\x0a  | x |\x0a  x := 1.\x0a  ^ { 'foo'->x. 'bar'->(true ifTrue: [ x := 2 ]) }\x0a",[smalltalk.send("foo","__minus_gt",[(1)]),smalltalk.send("bar","__minus_gt",[(2)])]]);
+smalltalk.send(self,"_should_return_",["foo\x0a  | x |\x0a  x := 1.\x0a  ^ #{ 'foo'->x. 'bar'->(true ifTrue: [ x := 2 ]) }\x0a",smalltalk.HashedCollection._fromPairs_([smalltalk.send("foo","__minus_gt",[(1)]),smalltalk.send("bar","__minus_gt",[(2)])])]);
+return self},
+args: [],
+source: "testInnerTemporalDependentElementsOrdered\x0a\x09self should: 'foo\x0a  | x |\x0a  x := Array.\x0a  ^ x with: ''foo''->x with: ''bar''->(true ifTrue: [ x := 2 ])\x0a' return: {'foo'->Array. 'bar'->2}.\x0a\x09self should: 'foo\x0a  | x |\x0a  x := 1.\x0a  ^ Array with: ''foo''->x with: ''bar''->(true ifTrue: [ x := 2 ])\x0a' return: {'foo'->1. 'bar'->2}.\x0a\x09self should: 'foo\x0a  | x |\x0a  x := 1.\x0a  ^ { ''foo''->x. ''bar''->(true ifTrue: [ x := 2 ]) }\x0a' return: {'foo'->1. 'bar'->2}.\x0a\x09self should: 'foo\x0a  | x |\x0a  x := 1.\x0a  ^ #{ ''foo''->x. ''bar''->(true ifTrue: [ x := 2 ]) }\x0a' return: #{'foo'->1. 'bar'->2}.\x0a",
+messageSends: ["should:return:", "->"],
+referencedClasses: ["Array"]
+}),
+smalltalk.CodeGeneratorTest);
+
 smalltalk.addMethod(
 "_testLiterals",
 smalltalk.method({

+ 6 - 0
st/Compiler-AST.st

@@ -29,6 +29,12 @@ shouldBeInlined
 
 shouldBeInlined: aBoolean
 	shouldBeInlined := aBoolean
+!
+
+subtreeNeedsAliasing
+    ^(self shouldBeAliased or: [ self shouldBeInlined ]) or: [
+        (self nodes detect: [ :node | node subtreeNeedsAliasing ] ifNone: [ false ]) ~= false
+    ]
 ! !
 
 !Node methodsFor: 'building'!

+ 3 - 3
st/Compiler-IR.st

@@ -81,7 +81,7 @@ temporallyDependentList: nodes
     threshold := 0.
     
     nodes withIndexDo: [ :each :i |
-        (each shouldBeInlined or: [ each shouldBeAliased ])
+        each subtreeNeedsAliasing
 		    ifTrue: [ threshold := i ]].
 
 	result := OrderedCollection new.
@@ -147,14 +147,14 @@ visitCascadeNode: aNode
 visitDynamicArrayNode: aNode
 	| array |
 	array := IRDynamicArray new.
-	aNode nodes do: [ :each | array add: (self visit: each) ].
+	(self temporallyDependentList: aNode nodes) do: [:each | array add: each].
 	^ array
 !
 
 visitDynamicDictionaryNode: aNode
 	| dictionary |
 	dictionary := IRDynamicDictionary new.
-	aNode nodes do: [ :each | dictionary add: (self visit: each) ].
+    (self temporallyDependentList: aNode nodes) do: [:each | dictionary add: each].
 	^ dictionary
 !
 

+ 39 - 0
st/Compiler-Tests.st

@@ -62,6 +62,45 @@ testCascades
 	self should: 'foo ^ Array new add: 3; add: 4; yourself' return: #(3 4)
 !
 
+testDynamicArrayElementsOrdered
+	self should: 'foo
+  | x |
+  x := 1.
+  ^ { x. true ifTrue: [ x := 2 ] }
+' return: #(1 2).
+!
+
+testDynamicDictionaryElementsOrdered
+	self should: 'foo
+  | x |
+  x := ''foo''->1.
+  ^ #{ x. (true ifTrue: [ x := ''bar''->2 ]) }
+' return: #{'foo'->1. 'bar'->2}.
+!
+
+testInnerTemporalDependentElementsOrdered
+	self should: 'foo
+  | x |
+  x := Array.
+  ^ x with: ''foo''->x with: ''bar''->(true ifTrue: [ x := 2 ])
+' return: {'foo'->Array. 'bar'->2}.
+	self should: 'foo
+  | x |
+  x := 1.
+  ^ Array with: ''foo''->x with: ''bar''->(true ifTrue: [ x := 2 ])
+' return: {'foo'->1. 'bar'->2}.
+	self should: 'foo
+  | x |
+  x := 1.
+  ^ { ''foo''->x. ''bar''->(true ifTrue: [ x := 2 ]) }
+' return: {'foo'->1. 'bar'->2}.
+	self should: 'foo
+  | x |
+  x := 1.
+  ^ #{ ''foo''->x. ''bar''->(true ifTrue: [ x := 2 ]) }
+' return: #{'foo'->1. 'bar'->2}.
+!
+
 testLiterals
 	self should: 'foo ^ 1' return: 1.
 	self should: 'foo ^ ''hello''' return: 'hello'.