Browse Source

Merge pull request #307 from herby/gh-296

Fixes GH-296
Nicolas Petton 12 years ago
parent
commit
b9ab20347c

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

@@ -57,6 +57,17 @@ return false;
 }),
 smalltalk.Node);
 
+smalltalk.addMethod(
+"_isImmutable",
+smalltalk.method({
+selector: "isImmutable",
+fn: function (){
+var self=this;
+return false;
+}
+}),
+smalltalk.Node);
+
 smalltalk.addMethod(
 "_isReturnNode",
 smalltalk.method({
@@ -1006,6 +1017,19 @@ return $1;
 }),
 smalltalk.ValueNode);
 
+smalltalk.addMethod(
+"_isImmutable",
+smalltalk.method({
+selector: "isImmutable",
+fn: function (){
+var self=this;
+var $1;
+$1=true;
+return $1;
+}
+}),
+smalltalk.ValueNode);
+
 smalltalk.addMethod(
 "_isValueNode",
 smalltalk.method({
@@ -1130,6 +1154,17 @@ return self}
 }),
 smalltalk.VariableNode);
 
+smalltalk.addMethod(
+"_isImmutable",
+smalltalk.method({
+selector: "isImmutable",
+fn: function (){
+var self=this;
+return false;
+}
+}),
+smalltalk.VariableNode);
+
 
 
 smalltalk.addClass('ClassReferenceNode', smalltalk.VariableNode, [], 'Compiler-AST');

+ 50 - 0
js/Compiler-AST.js

@@ -83,6 +83,22 @@ referencedClasses: []
 }),
 smalltalk.Node);
 
+smalltalk.addMethod(
+"_isImmutable",
+smalltalk.method({
+selector: "isImmutable",
+category: 'testing',
+fn: function (){
+var self=this;
+return false;
+},
+args: [],
+source: "isImmutable\x0a\x09^false",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Node);
+
 smalltalk.addMethod(
 "_isReturnNode",
 smalltalk.method({
@@ -1392,6 +1408,24 @@ referencedClasses: []
 }),
 smalltalk.ValueNode);
 
+smalltalk.addMethod(
+"_isImmutable",
+smalltalk.method({
+selector: "isImmutable",
+category: 'testing',
+fn: function (){
+var self=this;
+var $1;
+$1=true;
+return $1;
+},
+args: [],
+source: "isImmutable\x0a\x09^true",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ValueNode);
+
 smalltalk.addMethod(
 "_isValueNode",
 smalltalk.method({
@@ -1566,6 +1600,22 @@ referencedClasses: []
 }),
 smalltalk.VariableNode);
 
+smalltalk.addMethod(
+"_isImmutable",
+smalltalk.method({
+selector: "isImmutable",
+category: 'testing',
+fn: function (){
+var self=this;
+return false;
+},
+args: [],
+source: "isImmutable\x0a\x09^false",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.VariableNode);
+
 
 
 smalltalk.addClass('ClassReferenceNode', smalltalk.VariableNode, [], 'Compiler-AST');

+ 41 - 19
js/Compiler-IR.deploy.js

@@ -8,7 +8,7 @@ fn: function (aNode){
 var self=this;
 var $1,$2,$3,$4,$5,$6;
 var variable;
-$1=smalltalk.send(aNode,"_isValueNode",[]);
+$1=smalltalk.send(aNode,"_isImmutable",[]);
 if(smalltalk.assert($1)){
 $2=smalltalk.send(self,"_visit_",[aNode]);
 return $2;
@@ -114,6 +114,40 @@ return self}
 }),
 smalltalk.IRASTTranslator);
 
+smalltalk.addMethod(
+"_temporallyDependentList_",
+smalltalk.method({
+selector: "temporallyDependentList:",
+fn: function (nodes){
+var self=this;
+var $1,$3,$2;
+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",[]);
+})]);
+if(smalltalk.assert($1)){
+threshold=i;
+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]);
+} else {
+$2=smalltalk.send(self,"_visit_",[each]);
+};
+return smalltalk.send(result,"_add_",[$2]);
+})]);
+return result;
+}
+}),
+smalltalk.IRASTTranslator);
+
 smalltalk.addMethod(
 "_theClass",
 smalltalk.method({
@@ -221,7 +255,7 @@ fn: function (aNode){
 var self=this;
 var $1,$2;
 var alias;
-$1=smalltalk.send(smalltalk.send(aNode,"_receiver",[]),"_isValueNode",[]);
+$1=smalltalk.send(smalltalk.send(aNode,"_receiver",[]),"_isImmutable",[]);
 if(! smalltalk.assert($1)){
 alias=smalltalk.send(self,"_alias_",[smalltalk.send(aNode,"_receiver",[])]);
 alias;
@@ -353,8 +387,9 @@ smalltalk.method({
 selector: "visitSendNode:",
 fn: function (aNode){
 var self=this;
-var $1,$2,$3,$4;
+var $1,$2;
 var send;
+var all;
 var receiver;
 var arguments;
 send=smalltalk.send((smalltalk.IRSend || IRSend),"_new",[]);
@@ -364,22 +399,9 @@ $2=smalltalk.send(aNode,"_superSend",[]);
 if(smalltalk.assert($2)){
 smalltalk.send(send,"_classSend_",[smalltalk.send(smalltalk.send(self,"_theClass",[]),"_superclass",[])]);
 };
-$3=smalltalk.send(smalltalk.send(smalltalk.send(aNode,"_receiver",[]),"_shouldBeInlined",[]),"_or_",[(function(){
-return smalltalk.send(smalltalk.send(aNode,"_receiver",[]),"_shouldBeAliased",[]);
-})]);
-if(smalltalk.assert($3)){
-receiver=smalltalk.send(self,"_alias_",[smalltalk.send(aNode,"_receiver",[])]);
-} else {
-receiver=smalltalk.send(self,"_visit_",[smalltalk.send(aNode,"_receiver",[])]);
-};
-arguments=smalltalk.send(smalltalk.send(aNode,"_arguments",[]),"_collect_",[(function(each){
-$4=smalltalk.send(each,"_shouldBeInlined",[]);
-if(smalltalk.assert($4)){
-return smalltalk.send(self,"_alias_",[each]);
-} else {
-return smalltalk.send(self,"_visit_",[each]);
-};
-})]);
+all=smalltalk.send(self,"_temporallyDependentList_",[smalltalk.send([smalltalk.send(aNode,"_receiver",[])],"__comma",[smalltalk.send(aNode,"_arguments",[])])]);
+receiver=smalltalk.send(all,"_first",[]);
+arguments=smalltalk.send(all,"_allButFirst",[]);
 smalltalk.send(send,"_add_",[receiver]);
 smalltalk.send(arguments,"_do_",[(function(each){
 return smalltalk.send(send,"_add_",[each]);

+ 52 - 25
js/Compiler-IR.js

@@ -10,7 +10,7 @@ fn: function (aNode){
 var self=this;
 var $1,$2,$3,$4,$5,$6;
 var variable;
-$1=smalltalk.send(aNode,"_isValueNode",[]);
+$1=smalltalk.send(aNode,"_isImmutable",[]);
 if(smalltalk.assert($1)){
 $2=smalltalk.send(self,"_visit_",[aNode]);
 return $2;
@@ -28,8 +28,8 @@ smalltalk.send(smalltalk.send(smalltalk.send(self,"_method",[]),"_internalVariab
 return variable;
 },
 args: ["aNode"],
-source: "alias: aNode\x0a\x09| variable |\x0a\x0a\x09aNode isValueNode ifTrue: [ ^ self visit: aNode ].\x0a\x0a\x09variable := IRVariable new \x0a\x09\x09variable: (AliasVar new name: '$', self nextAlias); \x0a\x09\x09yourself.\x0a\x0a\x09self sequence add: (IRAssignment new\x0a\x09\x09add: variable;\x0a\x09\x09add: (self visit: aNode);\x0a\x09\x09yourself).\x0a\x0a\x09self method internalVariables add: variable.\x0a\x0a\x09^ variable",
-messageSends: ["ifTrue:", "visit:", "isValueNode", "variable:", "name:", ",", "nextAlias", "new", "yourself", "add:", "sequence", "internalVariables", "method"],
+source: "alias: aNode\x0a\x09| variable |\x0a\x0a\x09aNode isImmutable ifTrue: [ ^ self visit: aNode ].\x0a\x0a\x09variable := IRVariable new \x0a\x09\x09variable: (AliasVar new name: '$', self nextAlias); \x0a\x09\x09yourself.\x0a\x0a\x09self sequence add: (IRAssignment new\x0a\x09\x09add: variable;\x0a\x09\x09add: (self visit: aNode);\x0a\x09\x09yourself).\x0a\x0a\x09self method internalVariables add: variable.\x0a\x0a\x09^ variable",
+messageSends: ["ifTrue:", "visit:", "isImmutable", "variable:", "name:", ",", "nextAlias", "new", "yourself", "add:", "sequence", "internalVariables", "method"],
 referencedClasses: ["AliasVar", "IRVariable", "IRAssignment"]
 }),
 smalltalk.IRASTTranslator);
@@ -155,6 +155,45 @@ referencedClasses: []
 }),
 smalltalk.IRASTTranslator);
 
+smalltalk.addMethod(
+"_temporallyDependentList_",
+smalltalk.method({
+selector: "temporallyDependentList:",
+category: 'visiting',
+fn: function (nodes){
+var self=this;
+var $1,$3,$2;
+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",[]);
+})]);
+if(smalltalk.assert($1)){
+threshold=i;
+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]);
+} else {
+$2=smalltalk.send(self,"_visit_",[each]);
+};
+return smalltalk.send(result,"_add_",[$2]);
+})]);
+return result;
+},
+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:", "<="],
+referencedClasses: ["OrderedCollection"]
+}),
+smalltalk.IRASTTranslator);
+
 smalltalk.addMethod(
 "_theClass",
 smalltalk.method({
@@ -288,7 +327,7 @@ fn: function (aNode){
 var self=this;
 var $1,$2;
 var alias;
-$1=smalltalk.send(smalltalk.send(aNode,"_receiver",[]),"_isValueNode",[]);
+$1=smalltalk.send(smalltalk.send(aNode,"_receiver",[]),"_isImmutable",[]);
 if(! smalltalk.assert($1)){
 alias=smalltalk.send(self,"_alias_",[smalltalk.send(aNode,"_receiver",[])]);
 alias;
@@ -303,8 +342,8 @@ $2=smalltalk.send(self,"_alias_",[smalltalk.send(smalltalk.send(aNode,"_nodes",[
 return $2;
 },
 args: ["aNode"],
-source: "visitCascadeNode: aNode\x0a\x09| alias |\x0a\x0a\x09aNode receiver isValueNode ifFalse: [ \x0a\x09\x09alias := self alias: aNode receiver.\x0a\x09\x09aNode nodes do: [ :each |\x0a\x09\x09\x09each receiver: (VariableNode new binding: alias variable) ]].\x0a\x0a\x09aNode nodes allButLast do: [ :each |\x0a\x09\x09self sequence add: (self visit: each) ].\x0a\x0a\x09^ self alias: aNode nodes last",
-messageSends: ["ifFalse:", "alias:", "receiver", "do:", "receiver:", "binding:", "variable", "new", "nodes", "isValueNode", "add:", "visit:", "sequence", "allButLast", "last"],
+source: "visitCascadeNode: aNode\x0a\x09| alias |\x0a\x0a\x09aNode receiver isImmutable ifFalse: [ \x0a\x09\x09alias := self alias: aNode receiver.\x0a\x09\x09aNode nodes do: [ :each |\x0a\x09\x09\x09each receiver: (VariableNode new binding: alias variable) ]].\x0a\x0a\x09aNode nodes allButLast do: [ :each |\x0a\x09\x09self sequence add: (self visit: each) ].\x0a\x0a\x09^ self alias: aNode nodes last",
+messageSends: ["ifFalse:", "alias:", "receiver", "do:", "receiver:", "binding:", "variable", "new", "nodes", "isImmutable", "add:", "visit:", "sequence", "allButLast", "last"],
 referencedClasses: ["VariableNode"]
 }),
 smalltalk.IRASTTranslator);
@@ -450,8 +489,9 @@ selector: "visitSendNode:",
 category: 'visiting',
 fn: function (aNode){
 var self=this;
-var $1,$2,$3,$4;
+var $1,$2;
 var send;
+var all;
 var receiver;
 var arguments;
 send=smalltalk.send((smalltalk.IRSend || IRSend),"_new",[]);
@@ -461,22 +501,9 @@ $2=smalltalk.send(aNode,"_superSend",[]);
 if(smalltalk.assert($2)){
 smalltalk.send(send,"_classSend_",[smalltalk.send(smalltalk.send(self,"_theClass",[]),"_superclass",[])]);
 };
-$3=smalltalk.send(smalltalk.send(smalltalk.send(aNode,"_receiver",[]),"_shouldBeInlined",[]),"_or_",[(function(){
-return smalltalk.send(smalltalk.send(aNode,"_receiver",[]),"_shouldBeAliased",[]);
-})]);
-if(smalltalk.assert($3)){
-receiver=smalltalk.send(self,"_alias_",[smalltalk.send(aNode,"_receiver",[])]);
-} else {
-receiver=smalltalk.send(self,"_visit_",[smalltalk.send(aNode,"_receiver",[])]);
-};
-arguments=smalltalk.send(smalltalk.send(aNode,"_arguments",[]),"_collect_",[(function(each){
-$4=smalltalk.send(each,"_shouldBeInlined",[]);
-if(smalltalk.assert($4)){
-return smalltalk.send(self,"_alias_",[each]);
-} else {
-return smalltalk.send(self,"_visit_",[each]);
-};
-})]);
+all=smalltalk.send(self,"_temporallyDependentList_",[smalltalk.send([smalltalk.send(aNode,"_receiver",[])],"__comma",[smalltalk.send(aNode,"_arguments",[])])]);
+receiver=smalltalk.send(all,"_first",[]);
+arguments=smalltalk.send(all,"_allButFirst",[]);
 smalltalk.send(send,"_add_",[receiver]);
 smalltalk.send(arguments,"_do_",[(function(each){
 return smalltalk.send(send,"_add_",[each]);
@@ -484,8 +511,8 @@ return smalltalk.send(send,"_add_",[each]);
 return send;
 },
 args: ["aNode"],
-source: "visitSendNode: aNode\x0a\x09| send receiver arguments |\x0a\x09send := IRSend new.\x0a\x09send \x0a\x09\x09selector: aNode selector;\x0a\x09\x09index: aNode index.\x0a\x09aNode superSend ifTrue: [ send classSend: self theClass superclass ].\x0a\x0a\x09receiver := (aNode receiver shouldBeInlined or: [ aNode receiver shouldBeAliased ])\x0a\x09\x09ifTrue: [ self alias: aNode receiver ]\x0a\x09\x09ifFalse: [ self visit: aNode receiver ].\x0a\x0a\x09arguments := aNode arguments collect: [ :each | \x0a\x09\x09each shouldBeInlined\x0a\x09\x09\x09ifTrue: [ self alias: each ]\x0a\x09\x09\x09ifFalse: [ self visit: each ]].\x0a\x0a\x09send add: receiver.\x0a\x09arguments do: [ :each | send add: each ].\x0a\x0a\x09^ send",
-messageSends: ["new", "selector:", "selector", "index:", "index", "ifTrue:", "classSend:", "superclass", "theClass", "superSend", "ifTrue:ifFalse:", "alias:", "receiver", "visit:", "or:", "shouldBeAliased", "shouldBeInlined", "collect:", "arguments", "add:", "do:"],
+source: "visitSendNode: aNode\x0a\x09| send all receiver arguments |\x0a\x09send := IRSend new.\x0a\x09send \x0a\x09\x09selector: aNode selector;\x0a\x09\x09index: aNode index.\x0a\x09aNode superSend ifTrue: [ send classSend: self theClass superclass ].\x0a    \x0a    all := self temporallyDependentList: { aNode receiver }, aNode arguments.\x0a\x09receiver := all first.\x0a\x09arguments := all allButFirst.\x0a\x0a\x09send add: receiver.\x0a\x09arguments do: [ :each | send add: each ].\x0a\x0a\x09^ send\x0a",
+messageSends: ["new", "selector:", "selector", "index:", "index", "ifTrue:", "classSend:", "superclass", "theClass", "superSend", "temporallyDependentList:", ",", "arguments", "receiver", "first", "allButFirst", "add:", "do:"],
 referencedClasses: ["IRSend"]
 }),
 smalltalk.IRASTTranslator);

+ 21 - 23
js/Compiler-Semantic.deploy.js

@@ -1125,29 +1125,27 @@ smalltalk.addMethod(
 "_visitSendNode_",
 smalltalk.method({
 selector: "visitSendNode:",
-fn: function (aNode) {
-    var self = this;
-    var $1, $2, $3;
-    $1 = smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value", []), "__eq", ["super"]);
-    if (smalltalk.assert($1)) {
-        smalltalk.send(aNode, "_superSend_", [true]);
-        smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value_", ["self"]);
-    } else {
-        $2 = smalltalk.send(smalltalk.send(smalltalk.IRSendInliner || IRSendInliner, "_inlinedSelectors", []), "_includes_", [smalltalk.send(aNode, "_selector", [])]);
-        if (smalltalk.assert($2)) {
-            smalltalk.send(aNode, "_shouldBeInlined_", [true]);
-            $3 = smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_isValueNode", []);
-            if (!smalltalk.assert($3)) {
-                smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_shouldBeAliased_", [true]);
-            }
-        }
-    }
-    smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_ifAbsentPut_", [smalltalk.send(aNode, "_selector", []), function () {return smalltalk.send(smalltalk.Set || Set, "_new", []);}]);
-    smalltalk.send(smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_", [smalltalk.send(aNode, "_selector", [])]), "_add_", [aNode]);
-    smalltalk.send(aNode, "_index_", [smalltalk.send(smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_", [smalltalk.send(aNode, "_selector", [])]), "_size", [])]);
-    smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.NodeVisitor);
-    return self;
-}
+fn: function (aNode){
+var self=this;
+var $1,$2;
+$1=smalltalk.send(smalltalk.send(smalltalk.send(aNode,"_receiver",[]),"_value",[]),"__eq",["super"]);
+if(smalltalk.assert($1)){
+smalltalk.send(aNode,"_superSend_",[true]);
+smalltalk.send(smalltalk.send(aNode,"_receiver",[]),"_value_",["self"]);
+} else {
+$2=smalltalk.send(smalltalk.send((smalltalk.IRSendInliner || IRSendInliner),"_inlinedSelectors",[]),"_includes_",[smalltalk.send(aNode,"_selector",[])]);
+if(smalltalk.assert($2)){
+smalltalk.send(aNode,"_shouldBeInlined_",[true]);
+smalltalk.send(smalltalk.send(aNode,"_receiver",[]),"_shouldBeAliased_",[true]);
+};
+};
+smalltalk.send(smalltalk.send(self,"_messageSends",[]),"_at_ifAbsentPut_",[smalltalk.send(aNode,"_selector",[]),(function(){
+return smalltalk.send((smalltalk.Set || Set),"_new",[]);
+})]);
+smalltalk.send(smalltalk.send(smalltalk.send(self,"_messageSends",[]),"_at_",[smalltalk.send(aNode,"_selector",[])]),"_add_",[aNode]);
+smalltalk.send(aNode,"_index_",[smalltalk.send(smalltalk.send(smalltalk.send(self,"_messageSends",[]),"_at_",[smalltalk.send(aNode,"_selector",[])]),"_size",[])]);
+smalltalk.send(self,"_visitSendNode_",[aNode],smalltalk.NodeVisitor);
+return self}
 }),
 smalltalk.SemanticAnalyzer);
 

+ 23 - 25
js/Compiler-Semantic.js

@@ -1527,32 +1527,30 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitSendNode:",
 category: 'visiting',
-fn: function (aNode) {
-    var self = this;
-    var $1, $2, $3;
-    $1 = smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value", []), "__eq", ["super"]);
-    if (smalltalk.assert($1)) {
-        smalltalk.send(aNode, "_superSend_", [true]);
-        smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value_", ["self"]);
-    } else {
-        $2 = smalltalk.send(smalltalk.send(smalltalk.IRSendInliner || IRSendInliner, "_inlinedSelectors", []), "_includes_", [smalltalk.send(aNode, "_selector", [])]);
-        if (smalltalk.assert($2)) {
-            smalltalk.send(aNode, "_shouldBeInlined_", [true]);
-            $3 = smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_isValueNode", []);
-            if (!smalltalk.assert($3)) {
-                smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_shouldBeAliased_", [true]);
-            }
-        }
-    }
-    smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_ifAbsentPut_", [smalltalk.send(aNode, "_selector", []), function () {return smalltalk.send(smalltalk.Set || Set, "_new", []);}]);
-    smalltalk.send(smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_", [smalltalk.send(aNode, "_selector", [])]), "_add_", [aNode]);
-    smalltalk.send(aNode, "_index_", [smalltalk.send(smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_", [smalltalk.send(aNode, "_selector", [])]), "_size", [])]);
-    smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.NodeVisitor);
-    return self;
-},
+fn: function (aNode){
+var self=this;
+var $1,$2;
+$1=smalltalk.send(smalltalk.send(smalltalk.send(aNode,"_receiver",[]),"_value",[]),"__eq",["super"]);
+if(smalltalk.assert($1)){
+smalltalk.send(aNode,"_superSend_",[true]);
+smalltalk.send(smalltalk.send(aNode,"_receiver",[]),"_value_",["self"]);
+} else {
+$2=smalltalk.send(smalltalk.send((smalltalk.IRSendInliner || IRSendInliner),"_inlinedSelectors",[]),"_includes_",[smalltalk.send(aNode,"_selector",[])]);
+if(smalltalk.assert($2)){
+smalltalk.send(aNode,"_shouldBeInlined_",[true]);
+smalltalk.send(smalltalk.send(aNode,"_receiver",[]),"_shouldBeAliased_",[true]);
+};
+};
+smalltalk.send(smalltalk.send(self,"_messageSends",[]),"_at_ifAbsentPut_",[smalltalk.send(aNode,"_selector",[]),(function(){
+return smalltalk.send((smalltalk.Set || Set),"_new",[]);
+})]);
+smalltalk.send(smalltalk.send(smalltalk.send(self,"_messageSends",[]),"_at_",[smalltalk.send(aNode,"_selector",[])]),"_add_",[aNode]);
+smalltalk.send(aNode,"_index_",[smalltalk.send(smalltalk.send(smalltalk.send(self,"_messageSends",[]),"_at_",[smalltalk.send(aNode,"_selector",[])]),"_size",[])]);
+smalltalk.send(self,"_visitSendNode_",[aNode],smalltalk.NodeVisitor);
+return self},
 args: ["aNode"],
-source: "visitSendNode: aNode\x0a\x0a\x09aNode receiver value = 'super' \x0a\x09\x09ifTrue: [\x0a\x09\x09\x09aNode superSend: true.\x0a\x09\x09\x09aNode receiver value: 'self' ]\x0a\x09\x09ifFalse: [ (IRSendInliner inlinedSelectors includes: aNode selector) ifTrue: [\x0a\x09\x09\x09aNode shouldBeInlined: true.\x0a\x09\x09\x09aNode receiver isValueNode ifFalse: [ aNode receiver shouldBeAliased: true ] ] ].\x0a\x0a\x09self messageSends at: aNode selector ifAbsentPut: [ Set new ].\x0a\x09(self messageSends at: aNode selector) add: aNode.\x0a\x0a\x09aNode index: (self messageSends at: aNode selector) size.\x0a\x0a\x09super visitSendNode: aNode",
-messageSends: ["ifTrue:ifFalse:", "superSend:", "value:", "receiver", "ifTrue:", "shouldBeInlined:", "ifFalse:", "shouldBeAliased:", "isValueNode", "includes:", "selector", "inlinedSelectors", "=", "value", "at:ifAbsentPut:", "new", "messageSends", "add:", "at:", "index:", "size", "visitSendNode:"],
+source: "visitSendNode: aNode\x0a\x0a\x09aNode receiver value = 'super' \x0a\x09\x09ifTrue: [\x0a\x09\x09\x09aNode superSend: true.\x0a\x09\x09\x09aNode receiver value: 'self' ]\x0a\x09\x09ifFalse: [ (IRSendInliner inlinedSelectors includes: aNode selector) ifTrue: [\x0a\x09\x09\x09aNode shouldBeInlined: true.\x0a\x09\x09\x09aNode receiver shouldBeAliased: true ] ].\x0a\x0a\x09self messageSends at: aNode selector ifAbsentPut: [ Set new ].\x0a\x09(self messageSends at: aNode selector) add: aNode.\x0a\x0a\x09aNode index: (self messageSends at: aNode selector) size.\x0a\x0a\x09super visitSendNode: aNode",
+messageSends: ["ifTrue:ifFalse:", "superSend:", "value:", "receiver", "ifTrue:", "shouldBeInlined:", "shouldBeAliased:", "includes:", "selector", "inlinedSelectors", "=", "value", "at:ifAbsentPut:", "new", "messageSends", "add:", "at:", "index:", "size", "visitSendNode:"],
 referencedClasses: ["IRSendInliner", "Set"]
 }),
 smalltalk.SemanticAnalyzer);

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

@@ -200,6 +200,18 @@ fn: function () {
 }),
 smalltalk.CodeGeneratorTest);
 
+smalltalk.addMethod(
+"_testSendReceiverAndArgumentsOrdered",
+smalltalk.method({
+selector: "testSendReceiverAndArgumentsOrdered",
+fn: function (){
+var self=this;
+smalltalk.send(self,"_should_return_",["foo\x0a  | x |\x0a  x := 1.\x0a  ^ Array with: x with: (true ifTrue: [ x := 2 ])\x0a",[(1), (2)]]);
+smalltalk.send(self,"_should_return_",["foo\x0a  | x |\x0a  x := Array.\x0a  ^ x with: x with: (true ifTrue: [ x := 2 ])\x0a",[(smalltalk.Array || Array),(2)]]);
+return self}
+}),
+smalltalk.CodeGeneratorTest);
+
 smalltalk.addMethod(
 "_testifFalse",
 smalltalk.method({

+ 17 - 0
js/Compiler-Tests.js

@@ -270,6 +270,23 @@ referencedClasses: []
 }),
 smalltalk.CodeGeneratorTest);
 
+smalltalk.addMethod(
+"_testSendReceiverAndArgumentsOrdered",
+smalltalk.method({
+selector: "testSendReceiverAndArgumentsOrdered",
+category: 'tests',
+fn: function (){
+var self=this;
+smalltalk.send(self,"_should_return_",["foo\x0a  | x |\x0a  x := 1.\x0a  ^ Array with: x with: (true ifTrue: [ x := 2 ])\x0a",[(1), (2)]]);
+smalltalk.send(self,"_should_return_",["foo\x0a  | x |\x0a  x := Array.\x0a  ^ x with: x with: (true ifTrue: [ x := 2 ])\x0a",[(smalltalk.Array || Array),(2)]]);
+return self},
+args: [],
+source: "testSendReceiverAndArgumentsOrdered\x0a\x09self should: 'foo\x0a  | x |\x0a  x := 1.\x0a  ^ Array with: x with: (true ifTrue: [ x := 2 ])\x0a' return: #(1 2).\x0a\x0a\x09self should: 'foo\x0a  | x |\x0a  x := Array.\x0a  ^ x with: x with: (true ifTrue: [ x := 2 ])\x0a' return: {Array. 2}.\x0a",
+messageSends: ["should:return:"],
+referencedClasses: ["Array"]
+}),
+smalltalk.CodeGeneratorTest);
+
 smalltalk.addMethod(
 "_testifFalse",
 smalltalk.method({

+ 14 - 0
st/Compiler-AST.st

@@ -51,6 +51,10 @@ isBlockSequenceNode
 	^false
 !
 
+isImmutable
+	^false
+!
+
 isReturnNode
 	^false
 !
@@ -446,6 +450,10 @@ value: anObject
 
 !ValueNode methodsFor: 'testing'!
 
+isImmutable
+	^true
+!
+
 isValueNode
 	^true
 ! !
@@ -487,6 +495,12 @@ binding: aScopeVar
 	binding := aScopeVar
 ! !
 
+!VariableNode methodsFor: 'testing'!
+
+isImmutable
+	^false
+! !
+
 !VariableNode methodsFor: 'visiting'!
 
 accept: aVisitor

+ 24 - 12
st/Compiler-IR.st

@@ -60,7 +60,7 @@ withSequence: aSequence do: aBlock
 alias: aNode
 	| variable |
 
-	aNode isValueNode ifTrue: [ ^ self visit: aNode ].
+	aNode isImmutable ifTrue: [ ^ self visit: aNode ].
 
 	variable := IRVariable new 
 		variable: (AliasVar new name: '$', self nextAlias); 
@@ -76,6 +76,23 @@ alias: aNode
 	^ variable
 !
 
+temporallyDependentList: nodes
+	| threshold result |
+    threshold := 0.
+    
+    nodes withIndexDo: [ :each :i |
+        (each shouldBeInlined or: [ each shouldBeAliased ])
+		    ifTrue: [ threshold := i ]].
+
+	result := OrderedCollection new.
+	nodes withIndexDo: [ :each :i | 
+		result add: (i <= threshold
+			ifTrue: [ self alias: each ]
+			ifFalse: [ self visit: each ])].
+
+    ^result
+!
+
 visitAssignmentNode: aNode
 	| left right assignment |
 	right := self visit: aNode right.
@@ -116,7 +133,7 @@ visitBlockSequenceNode: aNode
 visitCascadeNode: aNode
 	| alias |
 
-	aNode receiver isValueNode ifFalse: [ 
+	aNode receiver isImmutable ifFalse: [ 
 		alias := self alias: aNode receiver.
 		aNode nodes do: [ :each |
 			each receiver: (VariableNode new binding: alias variable) ]].
@@ -185,21 +202,16 @@ visitReturnNode: aNode
 !
 
 visitSendNode: aNode
-	| send receiver arguments |
+	| send all receiver arguments |
 	send := IRSend new.
 	send 
 		selector: aNode selector;
 		index: aNode index.
 	aNode superSend ifTrue: [ send classSend: self theClass superclass ].
-
-	receiver := (aNode receiver shouldBeInlined or: [ aNode receiver shouldBeAliased ])
-		ifTrue: [ self alias: aNode receiver ]
-		ifFalse: [ self visit: aNode receiver ].
-
-	arguments := aNode arguments collect: [ :each | 
-		each shouldBeInlined
-			ifTrue: [ self alias: each ]
-			ifFalse: [ self visit: each ]].
+    
+    all := self temporallyDependentList: { aNode receiver }, aNode arguments.
+	receiver := all first.
+	arguments := all allButFirst.
 
 	send add: receiver.
 	arguments do: [ :each | send add: each ].

+ 1 - 1
st/Compiler-Semantic.st

@@ -521,7 +521,7 @@ visitSendNode: aNode
 			aNode receiver value: 'self' ]
 		ifFalse: [ (IRSendInliner inlinedSelectors includes: aNode selector) ifTrue: [
 			aNode shouldBeInlined: true.
-			aNode receiver isValueNode ifFalse: [ aNode receiver shouldBeAliased: true ] ] ].
+			aNode receiver shouldBeAliased: true ] ].
 
 	self messageSends at: aNode selector ifAbsentPut: [ Set new ].
 	(self messageSends at: aNode selector) add: aNode.

+ 14 - 0
st/Compiler-Tests.st

@@ -107,6 +107,20 @@ testNonLocalReturn
 	self should: 'foo [ :x | ^ x + x ] value: 4. ^ 2' return: 8
 !
 
+testSendReceiverAndArgumentsOrdered
+	self should: 'foo
+  | x |
+  x := 1.
+  ^ Array with: x with: (true ifTrue: [ x := 2 ])
+' return: #(1 2).
+
+	self should: 'foo
+  | x |
+  x := Array.
+  ^ x with: x with: (true ifTrue: [ x := 2 ])
+' return: {Array. 2}.
+!
+
 testifFalse
 	self should: 'foo true ifFalse: [ ^ 1 ]' return: receiver.
 	self should: 'foo false ifFalse: [ ^ 2 ]' return: 2.