Browse Source

Working inliner. Not yet inlining non local returns

Nicolas Petton 12 years ago
parent
commit
5eb1fd77c1

+ 64 - 20
js/Compiler-AST.deploy.js

@@ -1,12 +1,12 @@
 smalltalk.addPackage('Compiler-AST', {});
-smalltalk.addClass('Node', smalltalk.Object, ['nodes', 'used', 'alias', 'canBeInlined'], 'Compiler-AST');
+smalltalk.addClass('Node', smalltalk.Object, ['nodes', 'used', 'assignedTo', 'alias', 'canBeInlined'], 'Compiler-AST');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
 selector: "accept:",
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitNode_", [self]);
+return smalltalk.send(aVisitor, "_visitNode_", [self]);
 return self;}
 }),
 smalltalk.Node);
@@ -44,6 +44,28 @@ return self;}
 }),
 smalltalk.Node);
 
+smalltalk.addMethod(
+"_assignedTo",
+smalltalk.method({
+selector: "assignedTo",
+fn: function () {
+var self=this;
+return self['@assignedTo'];
+return self;}
+}),
+smalltalk.Node);
+
+smalltalk.addMethod(
+"_assignedTo_",
+smalltalk.method({
+selector: "assignedTo:",
+fn: function (aScopeVar) {
+var self=this;
+(self['@assignedTo']=aScopeVar);
+return self;}
+}),
+smalltalk.Node);
+
 smalltalk.addMethod(
 "_beUsed",
 smalltalk.method({
@@ -70,7 +92,7 @@ smalltalk.addMethod(
 "_canBeInlined",
 smalltalk.method({
 selector: "canBeInlined",
-fn: function (){
+fn: function () {
 var self=this;
 return (($receiver = self['@canBeInlined']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
 return self;}
@@ -81,7 +103,7 @@ smalltalk.addMethod(
 "_canBeInlined_",
 smalltalk.method({
 selector: "canBeInlined:",
-fn: function (aBoolean){
+fn: function (aBoolean) {
 var self=this;
 (self['@canBeInlined']=aBoolean);
 return self;}
@@ -99,6 +121,17 @@ return self;}
 }),
 smalltalk.Node);
 
+smalltalk.addMethod(
+"_isAssignmentNode",
+smalltalk.method({
+selector: "isAssignmentNode",
+fn: function () {
+var self=this;
+return false;
+return self;}
+}),
+smalltalk.Node);
+
 smalltalk.addMethod(
 "_isBlockNode",
 smalltalk.method({
@@ -218,7 +251,18 @@ smalltalk.method({
 selector: "accept:",
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitAssignmentNode_", [self]);
+return smalltalk.send(aVisitor, "_visitAssignmentNode_", [self]);
+return self;}
+}),
+smalltalk.AssignmentNode);
+
+smalltalk.addMethod(
+"_isAssignmentNode",
+smalltalk.method({
+selector: "isAssignmentNode",
+fn: function () {
+var self=this;
+return true;
 return self;}
 }),
 smalltalk.AssignmentNode);
@@ -288,7 +332,7 @@ smalltalk.method({
 selector: "accept:",
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitBlockNode_", [self]);
+return smalltalk.send(aVisitor, "_visitBlockNode_", [self]);
 return self;}
 }),
 smalltalk.BlockNode);
@@ -297,7 +341,7 @@ smalltalk.addMethod(
 "_canInlineNonLocalReturns",
 smalltalk.method({
 selector: "canInlineNonLocalReturns",
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(smalltalk.send(self, "_canBeInlined", []), "_and_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(self, "_scope", []), "_outerScope", []), "_node", []), "_canInlineNonLocalReturns", []);})]);
 return self;}
@@ -368,7 +412,7 @@ smalltalk.method({
 selector: "accept:",
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitCascadeNode_", [self]);
+return smalltalk.send(aVisitor, "_visitCascadeNode_", [self]);
 return self;}
 }),
 smalltalk.CascadeNode);
@@ -426,7 +470,7 @@ smalltalk.method({
 selector: "accept:",
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitDynamicArrayNode_", [self]);
+return smalltalk.send(aVisitor, "_visitDynamicArrayNode_", [self]);
 return self;}
 }),
 smalltalk.DynamicArrayNode);
@@ -440,7 +484,7 @@ smalltalk.method({
 selector: "accept:",
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitDynamicDictionaryNode_", [self]);
+return smalltalk.send(aVisitor, "_visitDynamicDictionaryNode_", [self]);
 return self;}
 }),
 smalltalk.DynamicDictionaryNode);
@@ -454,7 +498,7 @@ smalltalk.method({
 selector: "accept:",
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitJSStatementNode_", [self]);
+return smalltalk.send(aVisitor, "_visitJSStatementNode_", [self]);
 return self;}
 }),
 smalltalk.JSStatementNode);
@@ -490,7 +534,7 @@ smalltalk.method({
 selector: "accept:",
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitMethodNode_", [self]);
+return smalltalk.send(aVisitor, "_visitMethodNode_", [self]);
 return self;}
 }),
 smalltalk.MethodNode);
@@ -532,7 +576,7 @@ smalltalk.addMethod(
 "_canInlineNonLocalReturns",
 smalltalk.method({
 selector: "canInlineNonLocalReturns",
-fn: function (){
+fn: function () {
 var self=this;
 return true;
 return self;}
@@ -680,7 +724,7 @@ smalltalk.method({
 selector: "accept:",
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitReturnNode_", [self]);
+return smalltalk.send(aVisitor, "_visitReturnNode_", [self]);
 return self;}
 }),
 smalltalk.ReturnNode);
@@ -727,7 +771,7 @@ smalltalk.method({
 selector: "accept:",
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitSendNode_", [self]);
+return smalltalk.send(aVisitor, "_visitSendNode_", [self]);
 return self;}
 }),
 smalltalk.SendNode);
@@ -875,7 +919,7 @@ smalltalk.method({
 selector: "accept:",
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitSequenceNode_", [self]);
+return smalltalk.send(aVisitor, "_visitSequenceNode_", [self]);
 return self;}
 }),
 smalltalk.SequenceNode);
@@ -955,7 +999,7 @@ smalltalk.method({
 selector: "accept:",
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitBlockSequenceNode_", [self]);
+return smalltalk.send(aVisitor, "_visitBlockSequenceNode_", [self]);
 return self;}
 }),
 smalltalk.BlockSequenceNode);
@@ -980,7 +1024,7 @@ smalltalk.method({
 selector: "accept:",
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitValueNode_", [self]);
+return smalltalk.send(aVisitor, "_visitValueNode_", [self]);
 return self;}
 }),
 smalltalk.ValueNode);
@@ -1038,7 +1082,7 @@ smalltalk.method({
 selector: "accept:",
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitVariableNode_", [self]);
+return smalltalk.send(aVisitor, "_visitVariableNode_", [self]);
 return self;}
 }),
 smalltalk.VariableNode);
@@ -1119,7 +1163,7 @@ smalltalk.method({
 selector: "accept:",
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitClassReferenceNode_", [self]);
+return smalltalk.send(aVisitor, "_visitClassReferenceNode_", [self]);
 return self;}
 }),
 smalltalk.ClassReferenceNode);

+ 99 - 35
js/Compiler-AST.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-AST', {});
-smalltalk.addClass('Node', smalltalk.Object, ['nodes', 'used', 'alias', 'canBeInlined'], 'Compiler-AST');
+smalltalk.addClass('Node', smalltalk.Object, ['nodes', 'used', 'assignedTo', 'alias', 'canBeInlined'], 'Compiler-AST');
 smalltalk.Node.comment="I am the abstract root class of the abstract syntax tree."
 smalltalk.addMethod(
 "_accept_",
@@ -8,10 +8,10 @@ selector: "accept:",
 category: 'visiting',
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitNode_", [self]);
+return smalltalk.send(aVisitor, "_visitNode_", [self]);
 return self;},
 args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitNode: self",
+source: "accept: aVisitor\x0a\x09^ aVisitor visitNode: self",
 messageSends: ["visitNode:"],
 referencedClasses: []
 }),
@@ -65,6 +65,38 @@ referencedClasses: []
 }),
 smalltalk.Node);
 
+smalltalk.addMethod(
+"_assignedTo",
+smalltalk.method({
+selector: "assignedTo",
+category: 'accessing',
+fn: function () {
+var self=this;
+return self['@assignedTo'];
+return self;},
+args: [],
+source: "assignedTo\x0a\x09^ assignedTo",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Node);
+
+smalltalk.addMethod(
+"_assignedTo_",
+smalltalk.method({
+selector: "assignedTo:",
+category: 'accessing',
+fn: function (aScopeVar) {
+var self=this;
+(self['@assignedTo']=aScopeVar);
+return self;},
+args: ["aScopeVar"],
+source: "assignedTo: aScopeVar\x0a\x09assignedTo := aScopeVar",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Node);
+
 smalltalk.addMethod(
 "_beUsed",
 smalltalk.method({
@@ -102,7 +134,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "canBeInlined",
 category: 'accessing',
-fn: function (){
+fn: function () {
 var self=this;
 return (($receiver = self['@canBeInlined']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
 return self;},
@@ -118,7 +150,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "canBeInlined:",
 category: 'accessing',
-fn: function (aBoolean){
+fn: function (aBoolean) {
 var self=this;
 (self['@canBeInlined']=aBoolean);
 return self;},
@@ -145,6 +177,22 @@ referencedClasses: []
 }),
 smalltalk.Node);
 
+smalltalk.addMethod(
+"_isAssignmentNode",
+smalltalk.method({
+selector: "isAssignmentNode",
+category: 'testing',
+fn: function () {
+var self=this;
+return false;
+return self;},
+args: [],
+source: "isAssignmentNode\x0a\x09^ false",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Node);
+
 smalltalk.addMethod(
 "_isBlockNode",
 smalltalk.method({
@@ -315,15 +363,31 @@ selector: "accept:",
 category: 'visiting',
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitAssignmentNode_", [self]);
+return smalltalk.send(aVisitor, "_visitAssignmentNode_", [self]);
 return self;},
 args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitAssignmentNode: self",
+source: "accept: aVisitor\x0a\x09^ aVisitor visitAssignmentNode: self",
 messageSends: ["visitAssignmentNode:"],
 referencedClasses: []
 }),
 smalltalk.AssignmentNode);
 
+smalltalk.addMethod(
+"_isAssignmentNode",
+smalltalk.method({
+selector: "isAssignmentNode",
+category: 'testing',
+fn: function () {
+var self=this;
+return true;
+return self;},
+args: [],
+source: "isAssignmentNode\x0a\x09^ true",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.AssignmentNode);
+
 smalltalk.addMethod(
 "_left",
 smalltalk.method({
@@ -415,10 +479,10 @@ selector: "accept:",
 category: 'visiting',
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitBlockNode_", [self]);
+return smalltalk.send(aVisitor, "_visitBlockNode_", [self]);
 return self;},
 args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitBlockNode: self",
+source: "accept: aVisitor\x0a\x09^ aVisitor visitBlockNode: self",
 messageSends: ["visitBlockNode:"],
 referencedClasses: []
 }),
@@ -429,7 +493,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "canInlineNonLocalReturns",
 category: 'testing',
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(smalltalk.send(self, "_canBeInlined", []), "_and_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(self, "_scope", []), "_outerScope", []), "_node", []), "_canInlineNonLocalReturns", []);})]);
 return self;},
@@ -530,10 +594,10 @@ selector: "accept:",
 category: 'visiting',
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitCascadeNode_", [self]);
+return smalltalk.send(aVisitor, "_visitCascadeNode_", [self]);
 return self;},
 args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitCascadeNode: self",
+source: "accept: aVisitor\x0a\x09^ aVisitor visitCascadeNode: self",
 messageSends: ["visitCascadeNode:"],
 referencedClasses: []
 }),
@@ -613,10 +677,10 @@ selector: "accept:",
 category: 'visiting',
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitDynamicArrayNode_", [self]);
+return smalltalk.send(aVisitor, "_visitDynamicArrayNode_", [self]);
 return self;},
 args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitDynamicArrayNode: self",
+source: "accept: aVisitor\x0a\x09^ aVisitor visitDynamicArrayNode: self",
 messageSends: ["visitDynamicArrayNode:"],
 referencedClasses: []
 }),
@@ -632,10 +696,10 @@ selector: "accept:",
 category: 'visiting',
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitDynamicDictionaryNode_", [self]);
+return smalltalk.send(aVisitor, "_visitDynamicDictionaryNode_", [self]);
 return self;},
 args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitDynamicDictionaryNode: self",
+source: "accept: aVisitor\x0a\x09^ aVisitor visitDynamicDictionaryNode: self",
 messageSends: ["visitDynamicDictionaryNode:"],
 referencedClasses: []
 }),
@@ -651,10 +715,10 @@ selector: "accept:",
 category: 'visiting',
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitJSStatementNode_", [self]);
+return smalltalk.send(aVisitor, "_visitJSStatementNode_", [self]);
 return self;},
 args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitJSStatementNode: self",
+source: "accept: aVisitor\x0a\x09^ aVisitor visitJSStatementNode: self",
 messageSends: ["visitJSStatementNode:"],
 referencedClasses: []
 }),
@@ -702,10 +766,10 @@ selector: "accept:",
 category: 'visiting',
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitMethodNode_", [self]);
+return smalltalk.send(aVisitor, "_visitMethodNode_", [self]);
 return self;},
 args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitMethodNode: self",
+source: "accept: aVisitor\x0a\x09^ aVisitor visitMethodNode: self",
 messageSends: ["visitMethodNode:"],
 referencedClasses: []
 }),
@@ -764,7 +828,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "canInlineNonLocalReturns",
 category: 'testing',
-fn: function (){
+fn: function () {
 var self=this;
 return true;
 return self;},
@@ -977,10 +1041,10 @@ selector: "accept:",
 category: 'visiting',
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitReturnNode_", [self]);
+return smalltalk.send(aVisitor, "_visitReturnNode_", [self]);
 return self;},
 args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitReturnNode: self",
+source: "accept: aVisitor\x0a\x09^ aVisitor visitReturnNode: self",
 messageSends: ["visitReturnNode:"],
 referencedClasses: []
 }),
@@ -1044,10 +1108,10 @@ selector: "accept:",
 category: 'visiting',
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitSendNode_", [self]);
+return smalltalk.send(aVisitor, "_visitSendNode_", [self]);
 return self;},
 args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitSendNode: self",
+source: "accept: aVisitor\x0a\x09^ aVisitor visitSendNode: self",
 messageSends: ["visitSendNode:"],
 referencedClasses: []
 }),
@@ -1257,10 +1321,10 @@ selector: "accept:",
 category: 'visiting',
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitSequenceNode_", [self]);
+return smalltalk.send(aVisitor, "_visitSequenceNode_", [self]);
 return self;},
 args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitSequenceNode: self",
+source: "accept: aVisitor\x0a\x09^ aVisitor visitSequenceNode: self",
 messageSends: ["visitSequenceNode:"],
 referencedClasses: []
 }),
@@ -1372,10 +1436,10 @@ selector: "accept:",
 category: 'visiting',
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitBlockSequenceNode_", [self]);
+return smalltalk.send(aVisitor, "_visitBlockSequenceNode_", [self]);
 return self;},
 args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitBlockSequenceNode: self",
+source: "accept: aVisitor\x0a\x09^ aVisitor visitBlockSequenceNode: self",
 messageSends: ["visitBlockSequenceNode:"],
 referencedClasses: []
 }),
@@ -1407,10 +1471,10 @@ selector: "accept:",
 category: 'visiting',
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitValueNode_", [self]);
+return smalltalk.send(aVisitor, "_visitValueNode_", [self]);
 return self;},
 args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitValueNode: self",
+source: "accept: aVisitor\x0a\x09^ aVisitor visitValueNode: self",
 messageSends: ["visitValueNode:"],
 referencedClasses: []
 }),
@@ -1490,10 +1554,10 @@ selector: "accept:",
 category: 'visiting',
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitVariableNode_", [self]);
+return smalltalk.send(aVisitor, "_visitVariableNode_", [self]);
 return self;},
 args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitVariableNode: self",
+source: "accept: aVisitor\x0a\x09^ aVisitor visitVariableNode: self",
 messageSends: ["visitVariableNode:"],
 referencedClasses: []
 }),
@@ -1606,10 +1670,10 @@ selector: "accept:",
 category: 'visiting',
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitClassReferenceNode_", [self]);
+return smalltalk.send(aVisitor, "_visitClassReferenceNode_", [self]);
 return self;},
 args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitClassReferenceNode: self",
+source: "accept: aVisitor\x0a\x09^ aVisitor visitClassReferenceNode: self",
 messageSends: ["visitClassReferenceNode:"],
 referencedClasses: []
 }),

+ 23 - 23
js/Compiler-Core.deploy.js

@@ -165,7 +165,7 @@ smalltalk.addMethod(
 "_recompile_",
 smalltalk.method({
 selector: "recompile:",
-fn: function (aClass){
+fn: function (aClass) {
 var self=this;
 smalltalk.send(smalltalk.send(aClass, "_methodDictionary", []), "_do_", [(function(each){smalltalk.send((typeof console == 'undefined' ? nil : console), "_log_", [smalltalk.send(smalltalk.send(smalltalk.send(aClass, "_name", []), "__comma", [" >> "]), "__comma", [smalltalk.send(each, "_selector", [])])]);return smalltalk.send(self, "_install_forClass_category_", [smalltalk.send(each, "_source", []), aClass, smalltalk.send(each, "_category", [])]);})]);
 smalltalk.send(self, "_setupClass_", [aClass]);
@@ -274,7 +274,7 @@ smalltalk.method({
 selector: "visit:",
 fn: function (aNode) {
 var self=this;
-smalltalk.send(aNode, "_accept_", [self]);
+return smalltalk.send(aNode, "_accept_", [self]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -285,7 +285,7 @@ smalltalk.method({
 selector: "visitAll:",
 fn: function (aCollection) {
 var self=this;
-smalltalk.send(aCollection, "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);
+return smalltalk.send(aCollection, "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -296,7 +296,7 @@ smalltalk.method({
 selector: "visitAssignmentNode:",
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -307,7 +307,7 @@ smalltalk.method({
 selector: "visitBlockNode:",
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -318,7 +318,7 @@ smalltalk.method({
 selector: "visitBlockSequenceNode:",
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitSequenceNode_", [aNode]);
+return smalltalk.send(self, "_visitSequenceNode_", [aNode]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -329,7 +329,7 @@ smalltalk.method({
 selector: "visitCascadeNode:",
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -338,9 +338,9 @@ smalltalk.addMethod(
 "_visitClassReferenceNode_",
 smalltalk.method({
 selector: "visitClassReferenceNode:",
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitVariableNode_", [aNode]);
+return smalltalk.send(self, "_visitVariableNode_", [aNode]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -351,7 +351,7 @@ smalltalk.method({
 selector: "visitDynamicArrayNode:",
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -362,7 +362,7 @@ smalltalk.method({
 selector: "visitDynamicDictionaryNode:",
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -373,7 +373,7 @@ smalltalk.method({
 selector: "visitJSStatementNode:",
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -384,7 +384,7 @@ smalltalk.method({
 selector: "visitMethodNode:",
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -395,7 +395,7 @@ smalltalk.method({
 selector: "visitNode:",
 fn: function (aNode) {
 var self=this;
-smalltalk.send(smalltalk.send(aNode, "_nodes", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);
+return smalltalk.send(self, "_visitAll_", [smalltalk.send(aNode, "_nodes", [])]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -406,7 +406,7 @@ smalltalk.method({
 selector: "visitReturnNode:",
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -417,7 +417,7 @@ smalltalk.method({
 selector: "visitSendNode:",
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -428,7 +428,7 @@ smalltalk.method({
 selector: "visitSequenceNode:",
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -439,7 +439,7 @@ smalltalk.method({
 selector: "visitValueNode:",
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -450,7 +450,7 @@ smalltalk.method({
 selector: "visitVariableNode:",
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;}
 }),
 smalltalk.NodeVisitor);
@@ -558,8 +558,8 @@ var self=this;
 var ir=nil;
 var stream=nil;
 smalltalk.send(smalltalk.send(self, "_semanticAnalyzer", []), "_visit_", [aNode]);
-(ir=(function($rec){smalltalk.send($rec, "_visit_", [aNode]);return smalltalk.send($rec, "_builder", []);})(smalltalk.send(self, "_translator", [])));
-return (function($rec){smalltalk.send($rec, "_visit_", [smalltalk.send(ir, "_method", [])]);return smalltalk.send($rec, "_contents", []);})(smalltalk.send(self, "_irTranslator", []));
+(ir=smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [aNode]));
+return (function($rec){smalltalk.send($rec, "_visit_", [ir]);return smalltalk.send($rec, "_contents", []);})(smalltalk.send(self, "_irTranslator", []));
 return self;}
 }),
 smalltalk.CodeGenerator);
@@ -590,9 +590,9 @@ smalltalk.addMethod(
 "_translator",
 smalltalk.method({
 selector: "translator",
-fn: function (){
+fn: function () {
 var self=this;
-return (function($rec){smalltalk.send($rec, "_source_", [smalltalk.send(self, "_source", [])]);smalltalk.send($rec, "_theClass_", [smalltalk.send(self, "_currentClass", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRASTResolver || IRASTResolver), "_new", []));
+return (function($rec){smalltalk.send($rec, "_source_", [smalltalk.send(self, "_source", [])]);smalltalk.send($rec, "_theClass_", [smalltalk.send(self, "_currentClass", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRASTTranslator || IRASTTranslator), "_new", []));
 return self;}
 }),
 smalltalk.CodeGenerator);

+ 45 - 45
js/Compiler-Core.js

@@ -231,7 +231,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "recompile:",
 category: 'compiling',
-fn: function (aClass){
+fn: function (aClass) {
 var self=this;
 smalltalk.send(smalltalk.send(aClass, "_methodDictionary", []), "_do_", [(function(each){smalltalk.send((typeof console == 'undefined' ? nil : console), "_log_", [smalltalk.send(smalltalk.send(smalltalk.send(aClass, "_name", []), "__comma", [" >> "]), "__comma", [smalltalk.send(each, "_selector", [])])]);return smalltalk.send(self, "_install_forClass_category_", [smalltalk.send(each, "_source", []), aClass, smalltalk.send(each, "_category", [])]);})]);
 smalltalk.send(self, "_setupClass_", [aClass]);
@@ -385,10 +385,10 @@ selector: "visit:",
 category: 'visiting',
 fn: function (aNode) {
 var self=this;
-smalltalk.send(aNode, "_accept_", [self]);
+return smalltalk.send(aNode, "_accept_", [self]);
 return self;},
 args: ["aNode"],
-source: "visit: aNode\x0a\x09aNode accept: self",
+source: "visit: aNode\x0a\x09^ aNode accept: self",
 messageSends: ["accept:"],
 referencedClasses: []
 }),
@@ -401,10 +401,10 @@ selector: "visitAll:",
 category: 'visiting',
 fn: function (aCollection) {
 var self=this;
-smalltalk.send(aCollection, "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);
+return smalltalk.send(aCollection, "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);
 return self;},
 args: ["aCollection"],
-source: "visitAll: aCollection\x0a\x09aCollection do: [ :each | self visit: each ]",
+source: "visitAll: aCollection\x0a\x09^ aCollection do: [ :each | self visit: each ]",
 messageSends: ["do:", "visit:"],
 referencedClasses: []
 }),
@@ -417,10 +417,10 @@ selector: "visitAssignmentNode:",
 category: 'visiting',
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;},
 args: ["aNode"],
-source: "visitAssignmentNode: aNode\x0a\x09self visitNode: aNode",
+source: "visitAssignmentNode: aNode\x0a\x09^ self visitNode: aNode",
 messageSends: ["visitNode:"],
 referencedClasses: []
 }),
@@ -433,10 +433,10 @@ selector: "visitBlockNode:",
 category: 'visiting',
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;},
 args: ["aNode"],
-source: "visitBlockNode: aNode\x0a\x09self visitNode: aNode",
+source: "visitBlockNode: aNode\x0a\x09^ self visitNode: aNode",
 messageSends: ["visitNode:"],
 referencedClasses: []
 }),
@@ -449,10 +449,10 @@ selector: "visitBlockSequenceNode:",
 category: 'visiting',
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitSequenceNode_", [aNode]);
+return smalltalk.send(self, "_visitSequenceNode_", [aNode]);
 return self;},
 args: ["aNode"],
-source: "visitBlockSequenceNode: aNode\x0a\x09self visitSequenceNode: aNode",
+source: "visitBlockSequenceNode: aNode\x0a\x09^ self visitSequenceNode: aNode",
 messageSends: ["visitSequenceNode:"],
 referencedClasses: []
 }),
@@ -465,10 +465,10 @@ selector: "visitCascadeNode:",
 category: 'visiting',
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;},
 args: ["aNode"],
-source: "visitCascadeNode: aNode\x0a\x09self visitNode: aNode",
+source: "visitCascadeNode: aNode\x0a\x09^ self visitNode: aNode",
 messageSends: ["visitNode:"],
 referencedClasses: []
 }),
@@ -479,12 +479,12 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitClassReferenceNode:",
 category: 'visiting',
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitVariableNode_", [aNode]);
+return smalltalk.send(self, "_visitVariableNode_", [aNode]);
 return self;},
 args: ["aNode"],
-source: "visitClassReferenceNode: aNode\x0a\x09self visitVariableNode: aNode",
+source: "visitClassReferenceNode: aNode\x0a\x09^ self visitVariableNode: aNode",
 messageSends: ["visitVariableNode:"],
 referencedClasses: []
 }),
@@ -497,10 +497,10 @@ selector: "visitDynamicArrayNode:",
 category: 'visiting',
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;},
 args: ["aNode"],
-source: "visitDynamicArrayNode: aNode\x0a\x09self visitNode: aNode",
+source: "visitDynamicArrayNode: aNode\x0a\x09^ self visitNode: aNode",
 messageSends: ["visitNode:"],
 referencedClasses: []
 }),
@@ -513,10 +513,10 @@ selector: "visitDynamicDictionaryNode:",
 category: 'visiting',
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;},
 args: ["aNode"],
-source: "visitDynamicDictionaryNode: aNode\x0a\x09self visitNode: aNode",
+source: "visitDynamicDictionaryNode: aNode\x0a\x09^ self visitNode: aNode",
 messageSends: ["visitNode:"],
 referencedClasses: []
 }),
@@ -529,10 +529,10 @@ selector: "visitJSStatementNode:",
 category: 'visiting',
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;},
 args: ["aNode"],
-source: "visitJSStatementNode: aNode\x0a\x09self visitNode: aNode",
+source: "visitJSStatementNode: aNode\x0a\x09^ self visitNode: aNode",
 messageSends: ["visitNode:"],
 referencedClasses: []
 }),
@@ -545,10 +545,10 @@ selector: "visitMethodNode:",
 category: 'visiting',
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;},
 args: ["aNode"],
-source: "visitMethodNode: aNode\x0a\x09self visitNode: aNode",
+source: "visitMethodNode: aNode\x0a\x09^ self visitNode: aNode",
 messageSends: ["visitNode:"],
 referencedClasses: []
 }),
@@ -561,11 +561,11 @@ selector: "visitNode:",
 category: 'visiting',
 fn: function (aNode) {
 var self=this;
-smalltalk.send(smalltalk.send(aNode, "_nodes", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);
+return smalltalk.send(self, "_visitAll_", [smalltalk.send(aNode, "_nodes", [])]);
 return self;},
 args: ["aNode"],
-source: "visitNode: aNode\x0a\x09aNode nodes do: [ :each | self visit: each ]",
-messageSends: ["do:", "nodes", "visit:"],
+source: "visitNode: aNode\x0a\x09^ self visitAll: aNode nodes",
+messageSends: ["visitAll:", "nodes"],
 referencedClasses: []
 }),
 smalltalk.NodeVisitor);
@@ -577,10 +577,10 @@ selector: "visitReturnNode:",
 category: 'visiting',
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;},
 args: ["aNode"],
-source: "visitReturnNode: aNode\x0a\x09self visitNode: aNode",
+source: "visitReturnNode: aNode\x0a\x09^ self visitNode: aNode",
 messageSends: ["visitNode:"],
 referencedClasses: []
 }),
@@ -593,10 +593,10 @@ selector: "visitSendNode:",
 category: 'visiting',
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;},
 args: ["aNode"],
-source: "visitSendNode: aNode\x0a\x09self visitNode: aNode",
+source: "visitSendNode: aNode\x0a\x09^ self visitNode: aNode",
 messageSends: ["visitNode:"],
 referencedClasses: []
 }),
@@ -609,10 +609,10 @@ selector: "visitSequenceNode:",
 category: 'visiting',
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;},
 args: ["aNode"],
-source: "visitSequenceNode: aNode\x0a\x09self visitNode: aNode",
+source: "visitSequenceNode: aNode\x0a\x09^ self visitNode: aNode",
 messageSends: ["visitNode:"],
 referencedClasses: []
 }),
@@ -625,10 +625,10 @@ selector: "visitValueNode:",
 category: 'visiting',
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;},
 args: ["aNode"],
-source: "visitValueNode: aNode\x0a\x09self visitNode: aNode",
+source: "visitValueNode: aNode\x0a\x09^ self visitNode: aNode",
 messageSends: ["visitNode:"],
 referencedClasses: []
 }),
@@ -641,10 +641,10 @@ selector: "visitVariableNode:",
 category: 'visiting',
 fn: function (aNode) {
 var self=this;
-smalltalk.send(self, "_visitNode_", [aNode]);
+return smalltalk.send(self, "_visitNode_", [aNode]);
 return self;},
 args: ["aNode"],
-source: "visitVariableNode: aNode\x0a\x09self visitNode: aNode",
+source: "visitVariableNode: aNode\x0a\x09^ self visitNode: aNode",
 messageSends: ["visitNode:"],
 referencedClasses: []
 }),
@@ -794,12 +794,12 @@ var self=this;
 var ir=nil;
 var stream=nil;
 smalltalk.send(smalltalk.send(self, "_semanticAnalyzer", []), "_visit_", [aNode]);
-(ir=(function($rec){smalltalk.send($rec, "_visit_", [aNode]);return smalltalk.send($rec, "_builder", []);})(smalltalk.send(self, "_translator", [])));
-return (function($rec){smalltalk.send($rec, "_visit_", [smalltalk.send(ir, "_method", [])]);return smalltalk.send($rec, "_contents", []);})(smalltalk.send(self, "_irTranslator", []));
+(ir=smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [aNode]));
+return (function($rec){smalltalk.send($rec, "_visit_", [ir]);return smalltalk.send($rec, "_contents", []);})(smalltalk.send(self, "_irTranslator", []));
 return self;},
 args: ["aNode"],
-source: "compileNode: aNode\x0a\x09| ir stream |\x0a\x09self semanticAnalyzer visit: aNode.\x0a\x09ir := self translator visit: aNode; builder.\x0a\x09^ self irTranslator\x0a\x09\x09visit: ir method;\x0a\x09\x09contents",
-messageSends: ["visit:", "semanticAnalyzer", "builder", "translator", "method", "contents", "irTranslator"],
+source: "compileNode: aNode\x0a\x09| ir stream |\x0a\x09self semanticAnalyzer visit: aNode.\x0a\x09ir := self translator visit: aNode.\x0a\x09^ self irTranslator\x0a\x09\x09visit: ir;\x0a\x09\x09contents",
+messageSends: ["visit:", "semanticAnalyzer", "translator", "contents", "irTranslator"],
 referencedClasses: []
 }),
 smalltalk.CodeGenerator);
@@ -841,14 +841,14 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "translator",
 category: 'compiling',
-fn: function (){
+fn: function () {
 var self=this;
-return (function($rec){smalltalk.send($rec, "_source_", [smalltalk.send(self, "_source", [])]);smalltalk.send($rec, "_theClass_", [smalltalk.send(self, "_currentClass", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRASTResolver || IRASTResolver), "_new", []));
+return (function($rec){smalltalk.send($rec, "_source_", [smalltalk.send(self, "_source", [])]);smalltalk.send($rec, "_theClass_", [smalltalk.send(self, "_currentClass", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRASTTranslator || IRASTTranslator), "_new", []));
 return self;},
 args: [],
-source: "translator\x0a\x09^ IRASTResolver new\x0a\x09\x09source: self source;\x0a\x09\x09theClass: self currentClass;\x0a\x09\x09yourself",
+source: "translator\x0a\x09^ IRASTTranslator new\x0a\x09\x09source: self source;\x0a\x09\x09theClass: self currentClass;\x0a\x09\x09yourself",
 messageSends: ["source:", "source", "theClass:", "currentClass", "yourself", "new"],
-referencedClasses: ["IRASTResolver"]
+referencedClasses: ["IRASTTranslator"]
 }),
 smalltalk.CodeGenerator);
 

File diff suppressed because it is too large
+ 222 - 461
js/Compiler-IR.deploy.js


File diff suppressed because it is too large
+ 205 - 610
js/Compiler-IR.js


+ 461 - 0
js/Compiler-Inlining.deploy.js

@@ -0,0 +1,461 @@
+smalltalk.addPackage('Compiler-Inlining', {});
+smalltalk.addClass('IRInlinedAssignment', smalltalk.IRAssignment, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+fn: function (aVisitor){
+var self=this;
+return smalltalk.send(aVisitor, "_visitIRInlinedAssignment_", [self]);
+return self;}
+}),
+smalltalk.IRInlinedAssignment);
+
+smalltalk.addMethod(
+"_isInlined",
+smalltalk.method({
+selector: "isInlined",
+fn: function (){
+var self=this;
+return true;
+return self;}
+}),
+smalltalk.IRInlinedAssignment);
+
+
+
+smalltalk.addClass('IRInlinedClosure', smalltalk.IRClosure, ['assignTo'], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+fn: function (aVisitor) {
+var self=this;
+smalltalk.send(aVisitor, "_visitIRInlinedClosure_", [self]);
+return self;}
+}),
+smalltalk.IRInlinedClosure);
+
+smalltalk.addMethod(
+"_assignTo",
+smalltalk.method({
+selector: "assignTo",
+fn: function () {
+var self=this;
+return self['@assignTo'];
+return self;}
+}),
+smalltalk.IRInlinedClosure);
+
+smalltalk.addMethod(
+"_assignTo_",
+smalltalk.method({
+selector: "assignTo:",
+fn: function (aScopeVar){
+var self=this;
+(self['@assignTo']=aScopeVar);
+return self;}
+}),
+smalltalk.IRInlinedClosure);
+
+smalltalk.addMethod(
+"_isInlined",
+smalltalk.method({
+selector: "isInlined",
+fn: function (){
+var self=this;
+return true;
+return self;}
+}),
+smalltalk.IRInlinedClosure);
+
+
+
+smalltalk.addClass('IRInlinedNonLocalReturn', smalltalk.IRNonLocalReturn, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+fn: function (aVisitor){
+var self=this;
+return smalltalk.send(aVisitor, "_visitIRInlinedNonLocalReturn_", [self]);
+return self;}
+}),
+smalltalk.IRInlinedNonLocalReturn);
+
+smalltalk.addMethod(
+"_isInlined",
+smalltalk.method({
+selector: "isInlined",
+fn: function (){
+var self=this;
+return true;
+return self;}
+}),
+smalltalk.IRInlinedNonLocalReturn);
+
+
+
+smalltalk.addClass('IRInlinedSend', smalltalk.IRSend, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+fn: function (aVisitor) {
+var self=this;
+smalltalk.send(aVisitor, "_visitInlinedSend_", [self]);
+return self;}
+}),
+smalltalk.IRInlinedSend);
+
+smalltalk.addMethod(
+"_isInlined",
+smalltalk.method({
+selector: "isInlined",
+fn: function (){
+var self=this;
+return true;
+return self;}
+}),
+smalltalk.IRInlinedSend);
+
+
+
+smalltalk.addClass('IRInlinedIfTrue', smalltalk.IRInlinedSend, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+fn: function (aVisitor) {
+var self=this;
+smalltalk.send(aVisitor, "_visitIRInlinedIfTrue_", [self]);
+return self;}
+}),
+smalltalk.IRInlinedIfTrue);
+
+
+
+smalltalk.addClass('IRInliner', smalltalk.IRVisitor, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_assignmentInliner",
+smalltalk.method({
+selector: "assignmentInliner",
+fn: function () {
+var self=this;
+return (function($rec){smalltalk.send($rec, "_translator_", [self]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRAssignmentInliner || IRAssignmentInliner), "_new", []));
+return self;}
+}),
+smalltalk.IRInliner);
+
+smalltalk.addMethod(
+"_sendInliner",
+smalltalk.method({
+selector: "sendInliner",
+fn: function () {
+var self=this;
+return (function($rec){smalltalk.send($rec, "_translator_", [self]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRSendInliner || IRSendInliner), "_new", []));
+return self;}
+}),
+smalltalk.IRInliner);
+
+smalltalk.addMethod(
+"_shouldInlineAssignment_",
+smalltalk.method({
+selector: "shouldInlineAssignment:",
+fn: function (anIRAssignment){
+var self=this;
+return smalltalk.send(smalltalk.send(smalltalk.send(anIRAssignment, "_isInlined", []), "_not", []), "_and_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(anIRAssignment, "_instructions", []), "_last", []), "_isSend", []), "_and_", [(function(){return smalltalk.send(self, "_shouldInlineSend_", [smalltalk.send(smalltalk.send(anIRAssignment, "_instructions", []), "_last", [])]);})]);})]);
+return self;}
+}),
+smalltalk.IRInliner);
+
+smalltalk.addMethod(
+"_shouldInlineSend_",
+smalltalk.method({
+selector: "shouldInlineSend:",
+fn: function (anIRSend){
+var self=this;
+return smalltalk.send(smalltalk.send(smalltalk.send(anIRSend, "_isInlined", []), "_not", []), "_and_", [(function(){return smalltalk.send(smalltalk.send((smalltalk.IRSendInliner || IRSendInliner), "_inlinedSelectors", []), "_includes_", [smalltalk.send(anIRSend, "_selector", [])]);})]);
+return self;}
+}),
+smalltalk.IRInliner);
+
+smalltalk.addMethod(
+"_visitIRAssignment_",
+smalltalk.method({
+selector: "visitIRAssignment:",
+fn: function (anIRAssignment){
+var self=this;
+return ((($receiver = smalltalk.send(self, "_shouldInlineAssignment_", [anIRAssignment])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_assignmentInliner", []), "_inlineAssignment_", [anIRAssignment]);})() : (function(){return smalltalk.send(self, "_visitIRAssignment_", [anIRAssignment], smalltalk.IRInliner.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_assignmentInliner", []), "_inlineAssignment_", [anIRAssignment]);}), (function(){return smalltalk.send(self, "_visitIRAssignment_", [anIRAssignment], smalltalk.IRInliner.superclass || nil);})]));
+return self;}
+}),
+smalltalk.IRInliner);
+
+smalltalk.addMethod(
+"_visitIRSend_",
+smalltalk.method({
+selector: "visitIRSend:",
+fn: function (anIRSend){
+var self=this;
+return ((($receiver = smalltalk.send(self, "_shouldInlineSend_", [anIRSend])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [anIRSend]);})() : (function(){return smalltalk.send(self, "_visitIRSend_", [anIRSend], smalltalk.IRInliner.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [anIRSend]);}), (function(){return smalltalk.send(self, "_visitIRSend_", [anIRSend], smalltalk.IRInliner.superclass || nil);})]));
+return self;}
+}),
+smalltalk.IRInliner);
+
+smalltalk.addMethod(
+"_visitSendNode_",
+smalltalk.method({
+selector: "visitSendNode:",
+fn: function (aNode) {
+var self=this;
+((($receiver = smalltalk.send(aNode, "_canBeInlined", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [aNode]);})() : (function(){return smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.IRInliningASTResolver.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [aNode]);}), (function(){return smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.IRInliningASTResolver.superclass || nil);})]));
+return self;}
+}),
+smalltalk.IRInliner);
+
+
+
+smalltalk.addClass('IRInliningJSTranslator', smalltalk.IRJSTranslator, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_visitIRInlinedAssignment_",
+smalltalk.method({
+selector: "visitIRInlinedAssignment:",
+fn: function (anIRInlinedAssignment){
+var self=this;
+smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedAssignment, "_instructions", []), "_last", [])]);
+return self;}
+}),
+smalltalk.IRInliningJSTranslator);
+
+smalltalk.addMethod(
+"_visitIRInlinedClosure_",
+smalltalk.method({
+selector: "visitIRInlinedClosure:",
+fn: function (anIRInlinedClosure){
+var self=this;
+smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);
+(($receiver = smalltalk.send(anIRInlinedClosure, "_assignTo", [])) != nil && $receiver != undefined) ? (function(){smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_assignTo", []), "_variable", []), "_alias", [])]);return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAssignment", []);})() : nil;
+smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_last", [])]);
+return self;}
+}),
+smalltalk.IRInliningJSTranslator);
+
+smalltalk.addMethod(
+"_visitIRInlinedIfTrue_",
+smalltalk.method({
+selector: "visitIRInlinedIfTrue:",
+fn: function (anIRInlinedIfTrue) {
+var self=this;
+smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutIf_with_", [(function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedIfTrue, "_instructions", []), "_first", [])]);}), (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedIfTrue, "_instructions", []), "_last", [])]);})]);
+return self;}
+}),
+smalltalk.IRInliningJSTranslator);
+
+
+
+smalltalk.addClass('IRSendInliner', smalltalk.Object, ['send', 'translator'], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_ifTrue_",
+smalltalk.method({
+selector: "ifTrue:",
+fn: function (anIRInstruction){
+var self=this;
+var inlinedSend=nil;
+var inlinedClosure=nil;
+((($receiver = smalltalk.send(anIRInstruction, "_isClosure", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(self, "_inliningError_", ["Message argument should be a block"]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(self, "_inliningError_", ["Message argument should be a block"]);})]));
+((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRInstruction, "_arguments", []), "_size", []), "__eq", [(0)])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(self, "_inliningError_", ["Inlined block should have zero argument"]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(self, "_inliningError_", ["Inlined block should have zero argument"]);})]));
+(inlinedClosure=smalltalk.send(self, "_inlinedClosure", []));
+smalltalk.send(smalltalk.send(anIRInstruction, "_instructions", []), "_do_", [(function(each){(instruction=smalltalk.send(smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [each]), "_first", []));return smalltalk.send(inlinedClosure, "_add_", [(typeof instruction == 'undefined' ? nil : instruction)]);})]);
+(inlinedSend=smalltalk.send((smalltalk.IRInlinedIfTrue || IRInlinedIfTrue), "_new", []));
+(function($rec){smalltalk.send($rec, "_add_", [smalltalk.send(smalltalk.send(smalltalk.send(self, "_send", []), "_instructions", []), "_first", [])]);return smalltalk.send($rec, "_add_", [inlinedClosure]);})(inlinedSend);
+smalltalk.send(smalltalk.send(self, "_send", []), "_replaceWith_", [inlinedSend]);
+return inlinedSend;
+return self;}
+}),
+smalltalk.IRSendInliner);
+
+smalltalk.addMethod(
+"_inlineSend_",
+smalltalk.method({
+selector: "inlineSend:",
+fn: function (anIRSend){
+var self=this;
+smalltalk.send(self, "_send_", [anIRSend]);
+smalltalk.send(self, "_perform_withArguments_", [smalltalk.send(smalltalk.send(self, "_send", []), "_selector", []), smalltalk.send(smalltalk.send(smalltalk.send(self, "_send", []), "_instructions", []), "_allButFirst", [])]);
+return self;}
+}),
+smalltalk.IRSendInliner);
+
+smalltalk.addMethod(
+"_inlinedClosure",
+smalltalk.method({
+selector: "inlinedClosure",
+fn: function (){
+var self=this;
+return smalltalk.send((smalltalk.IRInlinedClosure || IRInlinedClosure), "_new", []);
+return self;}
+}),
+smalltalk.IRSendInliner);
+
+smalltalk.addMethod(
+"_inliningError_",
+smalltalk.method({
+selector: "inliningError:",
+fn: function (aString) {
+var self=this;
+smalltalk.send((smalltalk.InliningError || InliningError), "_signal_", [aString]);
+return self;}
+}),
+smalltalk.IRSendInliner);
+
+smalltalk.addMethod(
+"_send",
+smalltalk.method({
+selector: "send",
+fn: function () {
+var self=this;
+return self['@send'];
+return self;}
+}),
+smalltalk.IRSendInliner);
+
+smalltalk.addMethod(
+"_send_",
+smalltalk.method({
+selector: "send:",
+fn: function (anIRSend) {
+var self=this;
+(self['@send']=anIRSend);
+return self;}
+}),
+smalltalk.IRSendInliner);
+
+smalltalk.addMethod(
+"_translator",
+smalltalk.method({
+selector: "translator",
+fn: function () {
+var self=this;
+return self['@translator'];
+return self;}
+}),
+smalltalk.IRSendInliner);
+
+smalltalk.addMethod(
+"_translator_",
+smalltalk.method({
+selector: "translator:",
+fn: function (anASTTranslator) {
+var self=this;
+(self['@translator']=anASTTranslator);
+return self;}
+}),
+smalltalk.IRSendInliner);
+
+
+smalltalk.addMethod(
+"_inlinedSelectors",
+smalltalk.method({
+selector: "inlinedSelectors",
+fn: function () {
+var self=this;
+return ["ifTrue:"];
+return self;}
+}),
+smalltalk.IRSendInliner.klass);
+
+
+smalltalk.addClass('IRAssignmentInliner', smalltalk.IRSendInliner, ['assignment'], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_assignment",
+smalltalk.method({
+selector: "assignment",
+fn: function () {
+var self=this;
+return self['@assignment'];
+return self;}
+}),
+smalltalk.IRAssignmentInliner);
+
+smalltalk.addMethod(
+"_assignment_",
+smalltalk.method({
+selector: "assignment:",
+fn: function (aNode) {
+var self=this;
+(self['@assignment']=aNode);
+return self;}
+}),
+smalltalk.IRAssignmentInliner);
+
+smalltalk.addMethod(
+"_inlineAssignment_",
+smalltalk.method({
+selector: "inlineAssignment:",
+fn: function (anIRAssignment){
+var self=this;
+var inlinedAssignment=nil;
+smalltalk.send(self, "_assignment_", [anIRAssignment]);
+(inlinedAssignment=smalltalk.send((smalltalk.IRInlinedAssignment || IRInlinedAssignment), "_new", []));
+smalltalk.send(smalltalk.send(anIRAssignment, "_instructions", []), "_do_", [(function(each){return smalltalk.send(inlinedAssignment, "_add_", [each]);})]);
+smalltalk.send(anIRAssignment, "_replaceWith_", [inlinedAssignment]);
+smalltalk.send(self, "_inlineSend_", [smalltalk.send(smalltalk.send(inlinedAssignment, "_instructions", []), "_last", [])]);
+return inlinedAssignment;
+return self;}
+}),
+smalltalk.IRAssignmentInliner);
+
+smalltalk.addMethod(
+"_inlinedClosure",
+smalltalk.method({
+selector: "inlinedClosure",
+fn: function (){
+var self=this;
+return (function($rec){smalltalk.send($rec, "_assignTo_", [smalltalk.send(smalltalk.send(smalltalk.send(self, "_assignment", []), "_instructions", []), "_first", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send(self, "_inlinedClosure", [], smalltalk.IRAssignmentInliner.superclass || nil));
+return self;}
+}),
+smalltalk.IRAssignmentInliner);
+
+
+
+smalltalk.addClass('InliningCodeGenerator', smalltalk.CodeGenerator, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_compileNode_",
+smalltalk.method({
+selector: "compileNode:",
+fn: function (aNode){
+var self=this;
+var ir=nil;
+var stream=nil;
+smalltalk.send(smalltalk.send(self, "_semanticAnalyzer", []), "_visit_", [aNode]);
+(ir=smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [aNode]));
+smalltalk.send(smalltalk.send(self, "_inliner", []), "_visit_", [ir]);
+return (function($rec){smalltalk.send($rec, "_visit_", [ir]);return smalltalk.send($rec, "_contents", []);})(smalltalk.send(self, "_irTranslator", []));
+return self;}
+}),
+smalltalk.InliningCodeGenerator);
+
+smalltalk.addMethod(
+"_inliner",
+smalltalk.method({
+selector: "inliner",
+fn: function (){
+var self=this;
+return smalltalk.send((smalltalk.IRInliner || IRInliner), "_new", []);
+return self;}
+}),
+smalltalk.InliningCodeGenerator);
+
+smalltalk.addMethod(
+"_irTranslator",
+smalltalk.method({
+selector: "irTranslator",
+fn: function () {
+var self=this;
+return smalltalk.send((smalltalk.IRInliningJSTranslator || IRInliningJSTranslator), "_new", []);
+return self;}
+}),
+smalltalk.InliningCodeGenerator);
+
+
+

+ 647 - 0
js/Compiler-Inlining.js

@@ -0,0 +1,647 @@
+smalltalk.addPackage('Compiler-Inlining', {});
+smalltalk.addClass('IRInlinedAssignment', smalltalk.IRAssignment, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+category: 'visiting',
+fn: function (aVisitor){
+var self=this;
+return smalltalk.send(aVisitor, "_visitIRInlinedAssignment_", [self]);
+return self;},
+args: ["aVisitor"],
+source: "accept: aVisitor\x0a\x09^ aVisitor visitIRInlinedAssignment: self",
+messageSends: ["visitIRInlinedAssignment:"],
+referencedClasses: []
+}),
+smalltalk.IRInlinedAssignment);
+
+smalltalk.addMethod(
+"_isInlined",
+smalltalk.method({
+selector: "isInlined",
+category: 'testing',
+fn: function (){
+var self=this;
+return true;
+return self;},
+args: [],
+source: "isInlined\x0a\x09^ true",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.IRInlinedAssignment);
+
+
+
+smalltalk.addClass('IRInlinedClosure', smalltalk.IRClosure, ['assignTo'], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+category: 'visiting',
+fn: function (aVisitor) {
+var self=this;
+smalltalk.send(aVisitor, "_visitIRInlinedClosure_", [self]);
+return self;},
+args: ["aVisitor"],
+source: "accept: aVisitor\x0a\x09aVisitor visitIRInlinedClosure: self",
+messageSends: ["visitIRInlinedClosure:"],
+referencedClasses: []
+}),
+smalltalk.IRInlinedClosure);
+
+smalltalk.addMethod(
+"_assignTo",
+smalltalk.method({
+selector: "assignTo",
+category: 'accessing',
+fn: function () {
+var self=this;
+return self['@assignTo'];
+return self;},
+args: [],
+source: "assignTo\x0a\x09^ assignTo",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.IRInlinedClosure);
+
+smalltalk.addMethod(
+"_assignTo_",
+smalltalk.method({
+selector: "assignTo:",
+category: 'accessing',
+fn: function (aScopeVar){
+var self=this;
+(self['@assignTo']=aScopeVar);
+return self;},
+args: ["aScopeVar"],
+source: "assignTo: aScopeVar\x0a\x09assignTo := aScopeVar",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.IRInlinedClosure);
+
+smalltalk.addMethod(
+"_isInlined",
+smalltalk.method({
+selector: "isInlined",
+category: 'testing',
+fn: function (){
+var self=this;
+return true;
+return self;},
+args: [],
+source: "isInlined\x0a\x09^ true",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.IRInlinedClosure);
+
+
+
+smalltalk.addClass('IRInlinedNonLocalReturn', smalltalk.IRNonLocalReturn, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+category: 'visiting',
+fn: function (aVisitor){
+var self=this;
+return smalltalk.send(aVisitor, "_visitIRInlinedNonLocalReturn_", [self]);
+return self;},
+args: ["aVisitor"],
+source: "accept: aVisitor\x0a\x09^ aVisitor visitIRInlinedNonLocalReturn: self",
+messageSends: ["visitIRInlinedNonLocalReturn:"],
+referencedClasses: []
+}),
+smalltalk.IRInlinedNonLocalReturn);
+
+smalltalk.addMethod(
+"_isInlined",
+smalltalk.method({
+selector: "isInlined",
+category: 'testing',
+fn: function (){
+var self=this;
+return true;
+return self;},
+args: [],
+source: "isInlined\x0a\x09^ true",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.IRInlinedNonLocalReturn);
+
+
+
+smalltalk.addClass('IRInlinedSend', smalltalk.IRSend, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+category: 'visiting',
+fn: function (aVisitor) {
+var self=this;
+smalltalk.send(aVisitor, "_visitInlinedSend_", [self]);
+return self;},
+args: ["aVisitor"],
+source: "accept: aVisitor\x0a\x09aVisitor visitInlinedSend: self",
+messageSends: ["visitInlinedSend:"],
+referencedClasses: []
+}),
+smalltalk.IRInlinedSend);
+
+smalltalk.addMethod(
+"_isInlined",
+smalltalk.method({
+selector: "isInlined",
+category: 'testing',
+fn: function (){
+var self=this;
+return true;
+return self;},
+args: [],
+source: "isInlined\x0a\x09^ true",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.IRInlinedSend);
+
+
+
+smalltalk.addClass('IRInlinedIfTrue', smalltalk.IRInlinedSend, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+category: 'visiting',
+fn: function (aVisitor) {
+var self=this;
+smalltalk.send(aVisitor, "_visitIRInlinedIfTrue_", [self]);
+return self;},
+args: ["aVisitor"],
+source: "accept: aVisitor\x0a\x09aVisitor visitIRInlinedIfTrue: self",
+messageSends: ["visitIRInlinedIfTrue:"],
+referencedClasses: []
+}),
+smalltalk.IRInlinedIfTrue);
+
+
+
+smalltalk.addClass('IRInliner', smalltalk.IRVisitor, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_assignmentInliner",
+smalltalk.method({
+selector: "assignmentInliner",
+category: 'visiting',
+fn: function () {
+var self=this;
+return (function($rec){smalltalk.send($rec, "_translator_", [self]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRAssignmentInliner || IRAssignmentInliner), "_new", []));
+return self;},
+args: [],
+source: "assignmentInliner\x0a\x09^ IRAssignmentInliner new \x0a\x09\x09translator: self;\x0a\x09\x09yourself",
+messageSends: ["translator:", "yourself", "new"],
+referencedClasses: ["IRAssignmentInliner"]
+}),
+smalltalk.IRInliner);
+
+smalltalk.addMethod(
+"_sendInliner",
+smalltalk.method({
+selector: "sendInliner",
+category: 'visiting',
+fn: function () {
+var self=this;
+return (function($rec){smalltalk.send($rec, "_translator_", [self]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRSendInliner || IRSendInliner), "_new", []));
+return self;},
+args: [],
+source: "sendInliner\x0a\x09^ IRSendInliner new \x0a\x09\x09translator: self;\x0a\x09\x09yourself",
+messageSends: ["translator:", "yourself", "new"],
+referencedClasses: ["IRSendInliner"]
+}),
+smalltalk.IRInliner);
+
+smalltalk.addMethod(
+"_shouldInlineAssignment_",
+smalltalk.method({
+selector: "shouldInlineAssignment:",
+category: 'testing',
+fn: function (anIRAssignment){
+var self=this;
+return smalltalk.send(smalltalk.send(smalltalk.send(anIRAssignment, "_isInlined", []), "_not", []), "_and_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(anIRAssignment, "_instructions", []), "_last", []), "_isSend", []), "_and_", [(function(){return smalltalk.send(self, "_shouldInlineSend_", [smalltalk.send(smalltalk.send(anIRAssignment, "_instructions", []), "_last", [])]);})]);})]);
+return self;},
+args: ["anIRAssignment"],
+source: "shouldInlineAssignment: anIRAssignment\x0a\x09^ anIRAssignment isInlined not and: [ \x0a\x09\x09anIRAssignment instructions last isSend and: [\x09\x0a\x09\x09\x09self shouldInlineSend: (anIRAssignment instructions last) ]]",
+messageSends: ["and:", "not", "isInlined", "isSend", "last", "instructions", "shouldInlineSend:"],
+referencedClasses: []
+}),
+smalltalk.IRInliner);
+
+smalltalk.addMethod(
+"_shouldInlineSend_",
+smalltalk.method({
+selector: "shouldInlineSend:",
+category: 'testing',
+fn: function (anIRSend){
+var self=this;
+return smalltalk.send(smalltalk.send(smalltalk.send(anIRSend, "_isInlined", []), "_not", []), "_and_", [(function(){return smalltalk.send(smalltalk.send((smalltalk.IRSendInliner || IRSendInliner), "_inlinedSelectors", []), "_includes_", [smalltalk.send(anIRSend, "_selector", [])]);})]);
+return self;},
+args: ["anIRSend"],
+source: "shouldInlineSend: anIRSend\x0a\x09^ anIRSend isInlined not and: [\x0a\x09\x09IRSendInliner inlinedSelectors includes: anIRSend selector ]",
+messageSends: ["and:", "not", "isInlined", "includes:", "inlinedSelectors", "selector"],
+referencedClasses: ["IRSendInliner"]
+}),
+smalltalk.IRInliner);
+
+smalltalk.addMethod(
+"_visitIRAssignment_",
+smalltalk.method({
+selector: "visitIRAssignment:",
+category: 'visiting',
+fn: function (anIRAssignment){
+var self=this;
+return ((($receiver = smalltalk.send(self, "_shouldInlineAssignment_", [anIRAssignment])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_assignmentInliner", []), "_inlineAssignment_", [anIRAssignment]);})() : (function(){return smalltalk.send(self, "_visitIRAssignment_", [anIRAssignment], smalltalk.IRInliner.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_assignmentInliner", []), "_inlineAssignment_", [anIRAssignment]);}), (function(){return smalltalk.send(self, "_visitIRAssignment_", [anIRAssignment], smalltalk.IRInliner.superclass || nil);})]));
+return self;},
+args: ["anIRAssignment"],
+source: "visitIRAssignment: anIRAssignment\x0a\x09^ (self shouldInlineAssignment: anIRAssignment) \x0a\x09\x09ifTrue: [ self assignmentInliner inlineAssignment: anIRAssignment ]\x0a\x09\x09ifFalse: [ super visitIRAssignment: anIRAssignment ]",
+messageSends: ["ifTrue:ifFalse:", "shouldInlineAssignment:", "inlineAssignment:", "assignmentInliner", "visitIRAssignment:"],
+referencedClasses: []
+}),
+smalltalk.IRInliner);
+
+smalltalk.addMethod(
+"_visitIRSend_",
+smalltalk.method({
+selector: "visitIRSend:",
+category: 'visiting',
+fn: function (anIRSend){
+var self=this;
+return ((($receiver = smalltalk.send(self, "_shouldInlineSend_", [anIRSend])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [anIRSend]);})() : (function(){return smalltalk.send(self, "_visitIRSend_", [anIRSend], smalltalk.IRInliner.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [anIRSend]);}), (function(){return smalltalk.send(self, "_visitIRSend_", [anIRSend], smalltalk.IRInliner.superclass || nil);})]));
+return self;},
+args: ["anIRSend"],
+source: "visitIRSend: anIRSend\x0a\x09^ (self shouldInlineSend: anIRSend)\x0a\x09\x09ifTrue: [ self sendInliner inlineSend: anIRSend ]\x0a\x09\x09ifFalse: [ super visitIRSend: anIRSend ]",
+messageSends: ["ifTrue:ifFalse:", "shouldInlineSend:", "inlineSend:", "sendInliner", "visitIRSend:"],
+referencedClasses: []
+}),
+smalltalk.IRInliner);
+
+smalltalk.addMethod(
+"_visitSendNode_",
+smalltalk.method({
+selector: "visitSendNode:",
+category: 'visiting',
+fn: function (aNode) {
+var self=this;
+((($receiver = smalltalk.send(aNode, "_canBeInlined", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [aNode]);})() : (function(){return smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.IRInliningASTResolver.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [aNode]);}), (function(){return smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.IRInliningASTResolver.superclass || nil);})]));
+return self;},
+args: ["aNode"],
+source: "visitSendNode: aNode\x0a\x09aNode canBeInlined\x0a\x09\x09ifTrue: [ self sendInliner inlineSend: aNode ]\x0a\x09\x09ifFalse: [ super visitSendNode: aNode ]",
+messageSends: ["ifTrue:ifFalse:", "canBeInlined", "inlineSend:", "sendInliner", "visitSendNode:"],
+referencedClasses: []
+}),
+smalltalk.IRInliner);
+
+
+
+smalltalk.addClass('IRInliningJSTranslator', smalltalk.IRJSTranslator, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_visitIRInlinedAssignment_",
+smalltalk.method({
+selector: "visitIRInlinedAssignment:",
+category: 'visiting',
+fn: function (anIRInlinedAssignment){
+var self=this;
+smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedAssignment, "_instructions", []), "_last", [])]);
+return self;},
+args: ["anIRInlinedAssignment"],
+source: "visitIRInlinedAssignment: anIRInlinedAssignment\x0a\x09self visit: anIRInlinedAssignment instructions last",
+messageSends: ["visit:", "last", "instructions"],
+referencedClasses: []
+}),
+smalltalk.IRInliningJSTranslator);
+
+smalltalk.addMethod(
+"_visitIRInlinedClosure_",
+smalltalk.method({
+selector: "visitIRInlinedClosure:",
+category: 'visiting',
+fn: function (anIRInlinedClosure){
+var self=this;
+smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);
+(($receiver = smalltalk.send(anIRInlinedClosure, "_assignTo", [])) != nil && $receiver != undefined) ? (function(){smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_assignTo", []), "_variable", []), "_alias", [])]);return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAssignment", []);})() : nil;
+smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_last", [])]);
+return self;},
+args: ["anIRInlinedClosure"],
+source: "visitIRInlinedClosure: anIRInlinedClosure\x0a\x09anIRInlinedClosure instructions allButLast do: [ :each | self visit: each ].\x0a\x09anIRInlinedClosure assignTo ifNotNil: [\x0a\x09\x09self stream nextPutAll: anIRInlinedClosure assignTo variable alias.\x0a\x09\x09self stream nextPutAssignment ].\x0a\x09self visit: anIRInlinedClosure instructions last",
+messageSends: ["do:", "allButLast", "instructions", "visit:", "ifNotNil:", "assignTo", "nextPutAll:", "stream", "alias", "variable", "nextPutAssignment", "last"],
+referencedClasses: []
+}),
+smalltalk.IRInliningJSTranslator);
+
+smalltalk.addMethod(
+"_visitIRInlinedIfTrue_",
+smalltalk.method({
+selector: "visitIRInlinedIfTrue:",
+category: 'visiting',
+fn: function (anIRInlinedIfTrue) {
+var self=this;
+smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutIf_with_", [(function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedIfTrue, "_instructions", []), "_first", [])]);}), (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedIfTrue, "_instructions", []), "_last", [])]);})]);
+return self;},
+args: ["anIRInlinedIfTrue"],
+source: "visitIRInlinedIfTrue: anIRInlinedIfTrue\x0a\x09self stream \x0a\x09\x09nextPutIf: [ self visit: anIRInlinedIfTrue instructions first ]\x0a\x09\x09with: [ self visit: anIRInlinedIfTrue instructions last ]",
+messageSends: ["nextPutIf:with:", "stream", "visit:", "first", "instructions", "last"],
+referencedClasses: []
+}),
+smalltalk.IRInliningJSTranslator);
+
+
+
+smalltalk.addClass('IRSendInliner', smalltalk.Object, ['send', 'translator'], 'Compiler-Inlining');
+smalltalk.IRSendInliner.comment="I inline some message sends and block closure arguments. I heavily rely on #perform: to dispatch inlining methods."
+smalltalk.addMethod(
+"_ifTrue_",
+smalltalk.method({
+selector: "ifTrue:",
+category: 'inlining',
+fn: function (anIRInstruction){
+var self=this;
+var inlinedSend=nil;
+var inlinedClosure=nil;
+((($receiver = smalltalk.send(anIRInstruction, "_isClosure", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(self, "_inliningError_", ["Message argument should be a block"]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(self, "_inliningError_", ["Message argument should be a block"]);})]));
+((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRInstruction, "_arguments", []), "_size", []), "__eq", [(0)])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(self, "_inliningError_", ["Inlined block should have zero argument"]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(self, "_inliningError_", ["Inlined block should have zero argument"]);})]));
+(inlinedClosure=smalltalk.send(self, "_inlinedClosure", []));
+smalltalk.send(smalltalk.send(anIRInstruction, "_instructions", []), "_do_", [(function(each){(instruction=smalltalk.send(smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [each]), "_first", []));return smalltalk.send(inlinedClosure, "_add_", [(typeof instruction == 'undefined' ? nil : instruction)]);})]);
+(inlinedSend=smalltalk.send((smalltalk.IRInlinedIfTrue || IRInlinedIfTrue), "_new", []));
+(function($rec){smalltalk.send($rec, "_add_", [smalltalk.send(smalltalk.send(smalltalk.send(self, "_send", []), "_instructions", []), "_first", [])]);return smalltalk.send($rec, "_add_", [inlinedClosure]);})(inlinedSend);
+smalltalk.send(smalltalk.send(self, "_send", []), "_replaceWith_", [inlinedSend]);
+return inlinedSend;
+return self;},
+args: ["anIRInstruction"],
+source: "ifTrue: anIRInstruction\x0a\x09| inlinedSend inlinedClosure |\x0a\x0a\x09anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].\x0a\x09anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].\x0a\x0a\x09inlinedClosure := self inlinedClosure.\x0a\x09anIRInstruction instructions do: [ :each |\x0a\x09\x09instruction := (self translator visit: each) first.\x0a\x09\x09inlinedClosure add: instruction ].\x0a\x0a\x09inlinedSend := IRInlinedIfTrue new.\x0a\x09inlinedSend\x0a\x09\x09add: self send instructions first;\x0a\x09\x09add: inlinedClosure.\x0a\x0a\x09self send replaceWith: inlinedSend.\x0a\x09^ inlinedSend",
+messageSends: ["ifFalse:", "isClosure", "inliningError:", "=", "size", "arguments", "inlinedClosure", "do:", "instructions", "first", "visit:", "translator", "add:", "new", "send", "replaceWith:"],
+referencedClasses: ["IRInlinedIfTrue"]
+}),
+smalltalk.IRSendInliner);
+
+smalltalk.addMethod(
+"_inlineSend_",
+smalltalk.method({
+selector: "inlineSend:",
+category: 'inlining',
+fn: function (anIRSend){
+var self=this;
+smalltalk.send(self, "_send_", [anIRSend]);
+smalltalk.send(self, "_perform_withArguments_", [smalltalk.send(smalltalk.send(self, "_send", []), "_selector", []), smalltalk.send(smalltalk.send(smalltalk.send(self, "_send", []), "_instructions", []), "_allButFirst", [])]);
+return self;},
+args: ["anIRSend"],
+source: "inlineSend: anIRSend\x0a\x09self send: anIRSend.\x0a\x09self perform: self send selector withArguments: self send instructions allButFirst",
+messageSends: ["send:", "perform:withArguments:", "selector", "send", "allButFirst", "instructions"],
+referencedClasses: []
+}),
+smalltalk.IRSendInliner);
+
+smalltalk.addMethod(
+"_inlinedClosure",
+smalltalk.method({
+selector: "inlinedClosure",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.send((smalltalk.IRInlinedClosure || IRInlinedClosure), "_new", []);
+return self;},
+args: [],
+source: "inlinedClosure\x0a\x09^ IRInlinedClosure new",
+messageSends: ["new"],
+referencedClasses: ["IRInlinedClosure"]
+}),
+smalltalk.IRSendInliner);
+
+smalltalk.addMethod(
+"_inliningError_",
+smalltalk.method({
+selector: "inliningError:",
+category: 'error handling',
+fn: function (aString) {
+var self=this;
+smalltalk.send((smalltalk.InliningError || InliningError), "_signal_", [aString]);
+return self;},
+args: ["aString"],
+source: "inliningError: aString\x0a\x09InliningError signal: aString",
+messageSends: ["signal:"],
+referencedClasses: ["InliningError"]
+}),
+smalltalk.IRSendInliner);
+
+smalltalk.addMethod(
+"_send",
+smalltalk.method({
+selector: "send",
+category: 'accessing',
+fn: function () {
+var self=this;
+return self['@send'];
+return self;},
+args: [],
+source: "send\x0a\x09^ send",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.IRSendInliner);
+
+smalltalk.addMethod(
+"_send_",
+smalltalk.method({
+selector: "send:",
+category: 'accessing',
+fn: function (anIRSend) {
+var self=this;
+(self['@send']=anIRSend);
+return self;},
+args: ["anIRSend"],
+source: "send: anIRSend\x0a\x09send := anIRSend",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.IRSendInliner);
+
+smalltalk.addMethod(
+"_translator",
+smalltalk.method({
+selector: "translator",
+category: 'accessing',
+fn: function () {
+var self=this;
+return self['@translator'];
+return self;},
+args: [],
+source: "translator\x0a\x09^ translator",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.IRSendInliner);
+
+smalltalk.addMethod(
+"_translator_",
+smalltalk.method({
+selector: "translator:",
+category: 'accessing',
+fn: function (anASTTranslator) {
+var self=this;
+(self['@translator']=anASTTranslator);
+return self;},
+args: ["anASTTranslator"],
+source: "translator: anASTTranslator\x0a\x09translator := anASTTranslator",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.IRSendInliner);
+
+
+smalltalk.addMethod(
+"_inlinedSelectors",
+smalltalk.method({
+selector: "inlinedSelectors",
+category: 'accessing',
+fn: function () {
+var self=this;
+return ["ifTrue:"];
+return self;},
+args: [],
+source: "inlinedSelectors\x0a\x09^ #('ifTrue:')",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.IRSendInliner.klass);
+
+
+smalltalk.addClass('IRAssignmentInliner', smalltalk.IRSendInliner, ['assignment'], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_assignment",
+smalltalk.method({
+selector: "assignment",
+category: 'accessing',
+fn: function () {
+var self=this;
+return self['@assignment'];
+return self;},
+args: [],
+source: "assignment\x0a\x09^ assignment",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.IRAssignmentInliner);
+
+smalltalk.addMethod(
+"_assignment_",
+smalltalk.method({
+selector: "assignment:",
+category: 'accessing',
+fn: function (aNode) {
+var self=this;
+(self['@assignment']=aNode);
+return self;},
+args: ["aNode"],
+source: "assignment: aNode\x0a\x09assignment := aNode",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.IRAssignmentInliner);
+
+smalltalk.addMethod(
+"_inlineAssignment_",
+smalltalk.method({
+selector: "inlineAssignment:",
+category: 'inlining',
+fn: function (anIRAssignment){
+var self=this;
+var inlinedAssignment=nil;
+smalltalk.send(self, "_assignment_", [anIRAssignment]);
+(inlinedAssignment=smalltalk.send((smalltalk.IRInlinedAssignment || IRInlinedAssignment), "_new", []));
+smalltalk.send(smalltalk.send(anIRAssignment, "_instructions", []), "_do_", [(function(each){return smalltalk.send(inlinedAssignment, "_add_", [each]);})]);
+smalltalk.send(anIRAssignment, "_replaceWith_", [inlinedAssignment]);
+smalltalk.send(self, "_inlineSend_", [smalltalk.send(smalltalk.send(inlinedAssignment, "_instructions", []), "_last", [])]);
+return inlinedAssignment;
+return self;},
+args: ["anIRAssignment"],
+source: "inlineAssignment: anIRAssignment\x0a\x09| inlinedAssignment |\x0a\x09self assignment: anIRAssignment.\x0a\x09inlinedAssignment := IRInlinedAssignment new.\x0a\x09anIRAssignment instructions do: [ :each |\x0a\x09\x09inlinedAssignment add: each ].\x0a\x09anIRAssignment replaceWith: inlinedAssignment.\x0a\x09self inlineSend: inlinedAssignment instructions last.\x0a\x09^ inlinedAssignment",
+messageSends: ["assignment:", "new", "do:", "instructions", "add:", "replaceWith:", "inlineSend:", "last"],
+referencedClasses: ["IRInlinedAssignment"]
+}),
+smalltalk.IRAssignmentInliner);
+
+smalltalk.addMethod(
+"_inlinedClosure",
+smalltalk.method({
+selector: "inlinedClosure",
+category: 'accessing',
+fn: function (){
+var self=this;
+return (function($rec){smalltalk.send($rec, "_assignTo_", [smalltalk.send(smalltalk.send(smalltalk.send(self, "_assignment", []), "_instructions", []), "_first", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send(self, "_inlinedClosure", [], smalltalk.IRAssignmentInliner.superclass || nil));
+return self;},
+args: [],
+source: "inlinedClosure\x0a\x09^ super inlinedClosure\x0a\x09\x09assignTo: self assignment instructions first;\x0a\x09\x09yourself",
+messageSends: ["assignTo:", "first", "instructions", "assignment", "yourself", "inlinedClosure"],
+referencedClasses: []
+}),
+smalltalk.IRAssignmentInliner);
+
+
+
+smalltalk.addClass('InliningCodeGenerator', smalltalk.CodeGenerator, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_compileNode_",
+smalltalk.method({
+selector: "compileNode:",
+category: 'compiling',
+fn: function (aNode){
+var self=this;
+var ir=nil;
+var stream=nil;
+smalltalk.send(smalltalk.send(self, "_semanticAnalyzer", []), "_visit_", [aNode]);
+(ir=smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [aNode]));
+smalltalk.send(smalltalk.send(self, "_inliner", []), "_visit_", [ir]);
+return (function($rec){smalltalk.send($rec, "_visit_", [ir]);return smalltalk.send($rec, "_contents", []);})(smalltalk.send(self, "_irTranslator", []));
+return self;},
+args: ["aNode"],
+source: "compileNode: aNode\x0a\x09| ir stream |\x0a\x09self semanticAnalyzer visit: aNode.\x0a\x09ir := self translator visit: aNode.\x0a\x09self inliner visit: ir.\x0a\x09^ self irTranslator\x0a\x09\x09visit: ir;\x0a\x09\x09contents",
+messageSends: ["visit:", "semanticAnalyzer", "translator", "inliner", "contents", "irTranslator"],
+referencedClasses: []
+}),
+smalltalk.InliningCodeGenerator);
+
+smalltalk.addMethod(
+"_inliner",
+smalltalk.method({
+selector: "inliner",
+category: 'compiling',
+fn: function (){
+var self=this;
+return smalltalk.send((smalltalk.IRInliner || IRInliner), "_new", []);
+return self;},
+args: [],
+source: "inliner\x0a\x09^ IRInliner new",
+messageSends: ["new"],
+referencedClasses: ["IRInliner"]
+}),
+smalltalk.InliningCodeGenerator);
+
+smalltalk.addMethod(
+"_irTranslator",
+smalltalk.method({
+selector: "irTranslator",
+category: 'compiling',
+fn: function () {
+var self=this;
+return smalltalk.send((smalltalk.IRInliningJSTranslator || IRInliningJSTranslator), "_new", []);
+return self;},
+args: [],
+source: "irTranslator\x0a\x09^ IRInliningJSTranslator new",
+messageSends: ["new"],
+referencedClasses: ["IRInliningJSTranslator"]
+}),
+smalltalk.InliningCodeGenerator);
+
+
+

+ 18 - 19
js/Compiler-Semantic.deploy.js

@@ -61,7 +61,7 @@ smalltalk.addMethod(
 "_instruction",
 smalltalk.method({
 selector: "instruction",
-fn: function (){
+fn: function () {
 var self=this;
 return self['@instruction'];
 return self;}
@@ -72,7 +72,7 @@ smalltalk.addMethod(
 "_instruction_",
 smalltalk.method({
 selector: "instruction:",
-fn: function (anIRInstruction){
+fn: function (anIRInstruction) {
 var self=this;
 (self['@instruction']=anIRInstruction);
 return self;}
@@ -199,7 +199,7 @@ smalltalk.addMethod(
 "_addIVar_",
 smalltalk.method({
 selector: "addIVar:",
-fn: function (aString){
+fn: function (aString) {
 var self=this;
 smalltalk.send(smalltalk.send(self, "_iVars", []), "_at_put_", [aString, smalltalk.send((smalltalk.InstanceVar || InstanceVar), "_on_", [aString])]);
 smalltalk.send(smalltalk.send(smalltalk.send(self, "_iVars", []), "_at_", [aString]), "_scope_", [self]);
@@ -211,7 +211,7 @@ smalltalk.addMethod(
 "_addNonLocalReturn_",
 smalltalk.method({
 selector: "addNonLocalReturn:",
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_add_", [aNode]);
 return self;}
@@ -255,7 +255,7 @@ smalltalk.addMethod(
 "_hasNonLocalReturn",
 smalltalk.method({
 selector: "hasNonLocalReturn",
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_notEmpty", []);
 return self;}
@@ -343,7 +343,7 @@ smalltalk.addMethod(
 "_nonLocalReturns",
 smalltalk.method({
 selector: "nonLocalReturns",
-fn: function (){
+fn: function () {
 var self=this;
 return (($receiver = self['@nonLocalReturns']) == nil || $receiver == undefined) ? (function(){return (self['@nonLocalReturns']=smalltalk.send((smalltalk.OrderedCollection || OrderedCollection), "_new", []));})() : $receiver;
 return self;}
@@ -366,7 +366,7 @@ smalltalk.addMethod(
 "_removeNonLocalReturn_",
 smalltalk.method({
 selector: "removeNonLocalReturn:",
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_remove_ifAbsent_", [aNode, (function(){return nil;})]);
 return self;}
@@ -413,7 +413,7 @@ smalltalk.addMethod(
 "_isClassRefVar",
 smalltalk.method({
 selector: "isClassRefVar",
-fn: function (){
+fn: function () {
 var self=this;
 return false;
 return self;}
@@ -576,7 +576,7 @@ smalltalk.addMethod(
 "_alias",
 smalltalk.method({
 selector: "alias",
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send("(smalltalk.", "__comma", [smalltalk.send(self, "_name", [])]), "__comma", [" || "]), "__comma", [smalltalk.send(self, "_name", [])]), "__comma", [")"]);
 return self;}
@@ -587,7 +587,7 @@ smalltalk.addMethod(
 "_isClassRefVar",
 smalltalk.method({
 selector: "isClassRefVar",
-fn: function (){
+fn: function () {
 var self=this;
 return true;
 return self;}
@@ -601,7 +601,7 @@ smalltalk.addMethod(
 "_alias",
 smalltalk.method({
 selector: "alias",
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(smalltalk.send("self[\x22@", "__comma", [smalltalk.send(self, "_name", [])]), "__comma", ["\x22]"]);
 return self;}
@@ -838,7 +838,7 @@ fn: function (aNode) {
 var self=this;
 smalltalk.send(self, "_visitAssignmentNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 smalltalk.send(smalltalk.send(aNode, "_left", []), "_beAssigned", []);
-smalltalk.send(smalltalk.send(aNode, "_right", []), "_beUsed", []);
+smalltalk.send(smalltalk.send(aNode, "_right", []), "_assignedTo_", [smalltalk.send(smalltalk.send(aNode, "_left", []), "_binding", [])]);
 return self;}
 }),
 smalltalk.SemanticAnalyzer);
@@ -847,7 +847,7 @@ smalltalk.addMethod(
 "_visitBlockNode_",
 smalltalk.method({
 selector: "visitBlockNode:",
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 smalltalk.send(self, "_pushScope_", [smalltalk.send(self, "_newBlockScope", [])]);
 smalltalk.send(aNode, "_scope_", [self['@currentScope']]);
@@ -863,7 +863,7 @@ smalltalk.addMethod(
 "_visitCascadeNode_",
 smalltalk.method({
 selector: "visitCascadeNode:",
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 var $1,$2,$3,$4,$5,$6,$7,$8,$9;
 $1=(function(each){
@@ -884,7 +884,7 @@ $7=smalltalk.send(aNode,"_nodes",[]);
 $8=smalltalk.send($7,"_first",[]);
 $9=smalltalk.send($8,"_superSend",[]);
 smalltalk.send($9,"_ifTrue_",[$4]);
-return self}
+return self;}
 }),
 smalltalk.SemanticAnalyzer);
 
@@ -904,7 +904,7 @@ smalltalk.addMethod(
 "_visitMethodNode_",
 smalltalk.method({
 selector: "visitMethodNode:",
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 smalltalk.send(self, "_pushScope_", [smalltalk.send(self, "_newMethodScope", [])]);
 smalltalk.send(aNode, "_scope_", [self['@currentScope']]);
@@ -922,10 +922,9 @@ smalltalk.addMethod(
 "_visitReturnNode_",
 smalltalk.method({
 selector: "visitReturnNode:",
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 ((($receiver = smalltalk.send(self['@currentScope'], "_isMethodScope", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(self['@currentScope'], "_localReturn_", [true]);})() : (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_addNonLocalReturn_", [aNode]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(self['@currentScope'], "_localReturn_", [true]);}), (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_addNonLocalReturn_", [aNode]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})]));
-smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_nodes", []), "_first", []), "_beUsed", []);
 smalltalk.send(self, "_visitReturnNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 return self;}
 }),
@@ -935,7 +934,7 @@ smalltalk.addMethod(
 "_visitSendNode_",
 smalltalk.method({
 selector: "visitSendNode:",
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 ((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value", []), "__eq", ["super"])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(aNode, "_superSend_", [true]);return smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value_", ["self"]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){smalltalk.send(aNode, "_superSend_", [true]);return smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value_", ["self"]);})]));
 smalltalk.send(smalltalk.send(self, "_messageSends", []), "_add_", [smalltalk.send(aNode, "_selector", [])]);

+ 23 - 24
js/Compiler-Semantic.js

@@ -88,7 +88,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "instruction",
 category: 'accessing',
-fn: function (){
+fn: function () {
 var self=this;
 return self['@instruction'];
 return self;},
@@ -104,7 +104,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "instruction:",
 category: 'accessing',
-fn: function (anIRInstruction){
+fn: function (anIRInstruction) {
 var self=this;
 (self['@instruction']=anIRInstruction);
 return self;},
@@ -287,7 +287,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "addIVar:",
 category: 'adding',
-fn: function (aString){
+fn: function (aString) {
 var self=this;
 smalltalk.send(smalltalk.send(self, "_iVars", []), "_at_put_", [aString, smalltalk.send((smalltalk.InstanceVar || InstanceVar), "_on_", [aString])]);
 smalltalk.send(smalltalk.send(smalltalk.send(self, "_iVars", []), "_at_", [aString]), "_scope_", [self]);
@@ -304,7 +304,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "addNonLocalReturn:",
 category: 'adding',
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_add_", [aNode]);
 return self;},
@@ -368,7 +368,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "hasNonLocalReturn",
 category: 'testing',
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_notEmpty", []);
 return self;},
@@ -496,7 +496,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "nonLocalReturns",
 category: 'accessing',
-fn: function (){
+fn: function () {
 var self=this;
 return (($receiver = self['@nonLocalReturns']) == nil || $receiver == undefined) ? (function(){return (self['@nonLocalReturns']=smalltalk.send((smalltalk.OrderedCollection || OrderedCollection), "_new", []));})() : $receiver;
 return self;},
@@ -529,7 +529,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "removeNonLocalReturn:",
 category: 'adding',
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_remove_ifAbsent_", [aNode, (function(){return nil;})]);
 return self;},
@@ -597,7 +597,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "isClassRefVar",
 category: 'testing',
-fn: function (){
+fn: function () {
 var self=this;
 return false;
 return self;},
@@ -833,7 +833,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "alias",
 category: 'accessing',
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send("(smalltalk.", "__comma", [smalltalk.send(self, "_name", [])]), "__comma", [" || "]), "__comma", [smalltalk.send(self, "_name", [])]), "__comma", [")"]);
 return self;},
@@ -849,7 +849,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "isClassRefVar",
 category: 'testing',
-fn: function (){
+fn: function () {
 var self=this;
 return true;
 return self;},
@@ -869,7 +869,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "alias",
 category: 'testing',
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(smalltalk.send("self[\x22@", "__comma", [smalltalk.send(self, "_name", [])]), "__comma", ["\x22]"]);
 return self;},
@@ -1210,11 +1210,11 @@ fn: function (aNode) {
 var self=this;
 smalltalk.send(self, "_visitAssignmentNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 smalltalk.send(smalltalk.send(aNode, "_left", []), "_beAssigned", []);
-smalltalk.send(smalltalk.send(aNode, "_right", []), "_beUsed", []);
+smalltalk.send(smalltalk.send(aNode, "_right", []), "_assignedTo_", [smalltalk.send(smalltalk.send(aNode, "_left", []), "_binding", [])]);
 return self;},
 args: ["aNode"],
-source: "visitAssignmentNode: aNode\x0a\x09super visitAssignmentNode: aNode.\x0a\x09aNode left beAssigned.\x0a\x09aNode right beUsed",
-messageSends: ["visitAssignmentNode:", "beAssigned", "left", "beUsed", "right"],
+source: "visitAssignmentNode: aNode\x0a\x09super visitAssignmentNode: aNode.\x0a\x09aNode left beAssigned.\x0a\x09aNode right assignedTo: aNode left binding",
+messageSends: ["visitAssignmentNode:", "beAssigned", "left", "assignedTo:", "right", "binding"],
 referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);
@@ -1224,7 +1224,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitBlockNode:",
 category: 'visiting',
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 smalltalk.send(self, "_pushScope_", [smalltalk.send(self, "_newBlockScope", [])]);
 smalltalk.send(aNode, "_scope_", [self['@currentScope']]);
@@ -1245,7 +1245,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitCascadeNode:",
 category: 'visiting',
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 var $1,$2,$3,$4,$5,$6,$7,$8,$9;
 $1=(function(each){
@@ -1266,7 +1266,7 @@ $7=smalltalk.send(aNode,"_nodes",[]);
 $8=smalltalk.send($7,"_first",[]);
 $9=smalltalk.send($8,"_superSend",[]);
 smalltalk.send($9,"_ifTrue_",[$4]);
-return self},
+return self;},
 args: ["aNode"],
 source: "visitCascadeNode: aNode\x0a\x09\x22Populate the receiver into all children\x22\x0a\x09aNode nodes do: [ :each | \x0a\x09\x09each receiver: aNode receiver ].\x0a\x09super visitCascadeNode: aNode.\x0a\x09aNode nodes first superSend ifTrue: [\x0a\x09\x09aNode nodes do: [ :each | each superSend: true ]]",
 messageSends: ["do:", "receiver:", "receiver", "nodes", "visitCascadeNode:", "ifTrue:", "superSend:", "superSend", "first"],
@@ -1296,7 +1296,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitMethodNode:",
 category: 'visiting',
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 smalltalk.send(self, "_pushScope_", [smalltalk.send(self, "_newMethodScope", [])]);
 smalltalk.send(aNode, "_scope_", [self['@currentScope']]);
@@ -1319,15 +1319,14 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitReturnNode:",
 category: 'visiting',
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 ((($receiver = smalltalk.send(self['@currentScope'], "_isMethodScope", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(self['@currentScope'], "_localReturn_", [true]);})() : (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_addNonLocalReturn_", [aNode]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(self['@currentScope'], "_localReturn_", [true]);}), (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_addNonLocalReturn_", [aNode]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})]));
-smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_nodes", []), "_first", []), "_beUsed", []);
 smalltalk.send(self, "_visitReturnNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 return self;},
 args: ["aNode"],
-source: "visitReturnNode: aNode\x0a\x09currentScope isMethodScope \x0a\x09\x09ifTrue: [ currentScope localReturn: true ]\x0a\x09\x09ifFalse: [\x0a\x09\x09\x09currentScope methodScope addNonLocalReturn: aNode.\x0a\x09\x09\x09aNode nonLocalReturn: true ].\x0a\x09aNode nodes first beUsed.\x0a\x09super visitReturnNode: aNode",
-messageSends: ["ifTrue:ifFalse:", "isMethodScope", "localReturn:", "addNonLocalReturn:", "methodScope", "nonLocalReturn:", "beUsed", "first", "nodes", "visitReturnNode:"],
+source: "visitReturnNode: aNode\x0a\x09currentScope isMethodScope \x0a\x09\x09ifTrue: [ currentScope localReturn: true ]\x0a\x09\x09ifFalse: [\x0a\x09\x09\x09currentScope methodScope addNonLocalReturn: aNode.\x0a\x09\x09\x09aNode nonLocalReturn: true ].\x0a\x09super visitReturnNode: aNode",
+messageSends: ["ifTrue:ifFalse:", "isMethodScope", "localReturn:", "addNonLocalReturn:", "methodScope", "nonLocalReturn:", "visitReturnNode:"],
 referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);
@@ -1337,7 +1336,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitSendNode:",
 category: 'visiting',
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 ((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value", []), "__eq", ["super"])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(aNode, "_superSend_", [true]);return smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value_", ["self"]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){smalltalk.send(aNode, "_superSend_", [true]);return smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value_", ["self"]);})]));
 smalltalk.send(smalltalk.send(self, "_messageSends", []), "_add_", [smalltalk.send(aNode, "_selector", [])]);
@@ -1346,7 +1345,7 @@ smalltalk.send(smalltalk.send(aNode, "_arguments", []), "_do_", [(function(each)
 smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 return self;},
 args: ["aNode"],
-source: "visitSendNode: aNode\x0a\x0a\x09aNode receiver value = 'super' ifTrue: [\x0a\x09\x09aNode superSend: true.\x0a\x09\x09aNode receiver value: 'self'].\x0a\x0a\x09self messageSends add: aNode selector.\x0a\x09aNode receiver ifNotNil: [\x0a\x09\x09aNode receiver beUsed ].\x0a\x09aNode arguments do: [ :each |\x0a\x09\x09each isSendNode ifTrue: [ each beUsed ]].\x0a\x09super visitSendNode: aNode",
+source: "visitSendNode: aNode\x0a\x0a\x09aNode receiver value = 'super' ifTrue: [\x0a\x09\x09aNode superSend: true.\x0a\x09\x09aNode receiver value: 'self'].\x0a\x0a\x09self messageSends add: aNode selector.\x0a\x09aNode receiver ifNotNil: [\x0a\x09\x09aNode receiver beUsed ].\x0a\x09aNode arguments do: [ :each |\x0a\x09\x09each isSendNode ifTrue: [ each beUsed ]].\x0a\x0a\x09super visitSendNode: aNode",
 messageSends: ["ifTrue:", "=", "value", "receiver", "superSend:", "value:", "add:", "messageSends", "selector", "ifNotNil:", "beUsed", "do:", "arguments", "isSendNode", "visitSendNode:"],
 referencedClasses: []
 }),

+ 34 - 16
st/Compiler-AST.st

@@ -1,6 +1,6 @@
 Smalltalk current createPackage: 'Compiler-AST' properties: #{}!
 Object subclass: #Node
-	instanceVariableNames: 'nodes used alias canBeInlined'
+	instanceVariableNames: 'nodes used assignedTo alias canBeInlined'
 	package: 'Compiler-AST'!
 !Node commentStamp!
 I am the abstract root class of the abstract syntax tree.!
@@ -19,6 +19,14 @@ alias: aString
 	alias := aString
 !
 
+assignedTo
+	^ assignedTo
+!
+
+assignedTo: aScopeVar
+	assignedTo := aScopeVar
+!
+
 beUsed
 	used := true
 !
@@ -59,6 +67,10 @@ isAliased
 	^ self alias notNil
 !
 
+isAssignmentNode
+	^ false
+!
+
 isBlockNode
 	^false
 !
@@ -86,7 +98,7 @@ shouldBeAliased
 !Node methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitNode: self
+	^ aVisitor visitNode: self
 ! !
 
 Node subclass: #AssignmentNode
@@ -116,10 +128,16 @@ right: aNode
 	right := aNode
 ! !
 
+!AssignmentNode methodsFor: 'testing'!
+
+isAssignmentNode
+	^ true
+! !
+
 !AssignmentNode methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitAssignmentNode: self
+	^ aVisitor visitAssignmentNode: self
 ! !
 
 Node subclass: #BlockNode
@@ -158,7 +176,7 @@ isBlockNode
 !BlockNode methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitBlockNode: self
+	^ aVisitor visitBlockNode: self
 ! !
 
 Node subclass: #CascadeNode
@@ -186,7 +204,7 @@ receiver: aNode
 !CascadeNode methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitCascadeNode: self
+	^ aVisitor visitCascadeNode: self
 ! !
 
 Node subclass: #DynamicArrayNode
@@ -196,7 +214,7 @@ Node subclass: #DynamicArrayNode
 !DynamicArrayNode methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitDynamicArrayNode: self
+	^ aVisitor visitDynamicArrayNode: self
 ! !
 
 Node subclass: #DynamicDictionaryNode
@@ -206,7 +224,7 @@ Node subclass: #DynamicDictionaryNode
 !DynamicDictionaryNode methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitDynamicDictionaryNode: self
+	^ aVisitor visitDynamicDictionaryNode: self
 ! !
 
 Node subclass: #JSStatementNode
@@ -226,7 +244,7 @@ source: aString
 !JSStatementNode methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitJSStatementNode: self
+	^ aVisitor visitJSStatementNode: self
 ! !
 
 Node subclass: #MethodNode
@@ -308,7 +326,7 @@ hasNonLocalReturn
 !MethodNode methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitMethodNode: self
+	^ aVisitor visitMethodNode: self
 ! !
 
 Node subclass: #ReturnNode
@@ -334,7 +352,7 @@ shouldBeAliased
 !ReturnNode methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitReturnNode: self
+	^ aVisitor visitReturnNode: self
 ! !
 
 Node subclass: #SendNode
@@ -412,7 +430,7 @@ isSendNode
 !SendNode methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitSendNode: self
+	^ aVisitor visitSendNode: self
 ! !
 
 Node subclass: #SequenceNode
@@ -453,7 +471,7 @@ canAliasChildren
 !SequenceNode methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitSequenceNode: self
+	^ aVisitor visitSequenceNode: self
 ! !
 
 SequenceNode subclass: #BlockSequenceNode
@@ -469,7 +487,7 @@ isBlockSequenceNode
 !BlockSequenceNode methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitBlockSequenceNode: self
+	^ aVisitor visitBlockSequenceNode: self
 ! !
 
 Node subclass: #ValueNode
@@ -499,7 +517,7 @@ shouldBeAliased
 !ValueNode methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitValueNode: self
+	^ aVisitor visitValueNode: self
 ! !
 
 ValueNode subclass: #VariableNode
@@ -536,7 +554,7 @@ binding: aScopeVar
 !VariableNode methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitVariableNode: self
+	^ aVisitor visitVariableNode: self
 ! !
 
 VariableNode subclass: #ClassReferenceNode
@@ -546,6 +564,6 @@ VariableNode subclass: #ClassReferenceNode
 !ClassReferenceNode methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitClassReferenceNode: self
+	^ aVisitor visitClassReferenceNode: self
 ! !
 

+ 20 - 20
st/Compiler-Core.st

@@ -135,71 +135,71 @@ Object subclass: #NodeVisitor
 !NodeVisitor methodsFor: 'visiting'!
 
 visit: aNode
-	aNode accept: self
+	^ aNode accept: self
 !
 
 visitAll: aCollection
-	aCollection do: [ :each | self visit: each ]
+	^ aCollection do: [ :each | self visit: each ]
 !
 
 visitAssignmentNode: aNode
-	self visitNode: aNode
+	^ self visitNode: aNode
 !
 
 visitBlockNode: aNode
-	self visitNode: aNode
+	^ self visitNode: aNode
 !
 
 visitBlockSequenceNode: aNode
-	self visitSequenceNode: aNode
+	^ self visitSequenceNode: aNode
 !
 
 visitCascadeNode: aNode
-	self visitNode: aNode
+	^ self visitNode: aNode
 !
 
 visitClassReferenceNode: aNode
-	self visitVariableNode: aNode
+	^ self visitVariableNode: aNode
 !
 
 visitDynamicArrayNode: aNode
-	self visitNode: aNode
+	^ self visitNode: aNode
 !
 
 visitDynamicDictionaryNode: aNode
-	self visitNode: aNode
+	^ self visitNode: aNode
 !
 
 visitJSStatementNode: aNode
-	self visitNode: aNode
+	^ self visitNode: aNode
 !
 
 visitMethodNode: aNode
-	self visitNode: aNode
+	^ self visitNode: aNode
 !
 
 visitNode: aNode
-	aNode nodes do: [ :each | self visit: each ]
+	^ self visitAll: aNode nodes
 !
 
 visitReturnNode: aNode
-	self visitNode: aNode
+	^ self visitNode: aNode
 !
 
 visitSendNode: aNode
-	self visitNode: aNode
+	^ self visitNode: aNode
 !
 
 visitSequenceNode: aNode
-	self visitNode: aNode
+	^ self visitNode: aNode
 !
 
 visitValueNode: aNode
-	self visitNode: aNode
+	^ self visitNode: aNode
 !
 
 visitVariableNode: aNode
-	self visitNode: aNode
+	^ self visitNode: aNode
 ! !
 
 NodeVisitor subclass: #AbstractCodeGenerator
@@ -258,9 +258,9 @@ AbstractCodeGenerator subclass: #CodeGenerator
 compileNode: aNode
 	| ir stream |
 	self semanticAnalyzer visit: aNode.
-	ir := self translator visit: aNode; builder.
+	ir := self translator visit: aNode.
 	^ self irTranslator
-		visit: ir method;
+		visit: ir;
 		contents
 !
 
@@ -273,7 +273,7 @@ semanticAnalyzer
 !
 
 translator
-	^ IRASTResolver new
+	^ IRASTTranslator new
 		source: self source;
 		theClass: self currentClass;
 		yourself

+ 229 - 303
st/Compiler-IR.st

@@ -1,6 +1,6 @@
 Smalltalk current createPackage: 'Compiler-IR' properties: #{}!
 NodeVisitor subclass: #IRASTTranslator
-	instanceVariableNames: 'builder source theClass'
+	instanceVariableNames: 'source theClass method sequence nextAlias'
 	package: 'Compiler-IR'!
 !IRASTTranslator commentStamp!
 I am the AST (abstract syntax tree) visitor responsible for building the intermediate representation graph.
@@ -8,12 +8,26 @@ I rely on a builder object, instance of IRBuilder.!
 
 !IRASTTranslator methodsFor: 'accessing'!
 
-builder
-	^ builder ifNil: [ builder := IRBuilder new ]
+method
+	^ method
 !
 
-builder: aBuilder
-	builder := aBuilder
+method: anIRMethod
+	method := anIRMethod
+!
+
+nextAlias
+	nextAlias ifNil: [ nextAlias := 0 ].
+	nextAlias := nextAlias + 1.
+	^ nextAlias asString
+!
+
+sequence
+	^ sequence
+!
+
+sequence: anIRSequence
+	sequence := anIRSequence
 !
 
 source
@@ -34,267 +48,159 @@ theClass: aClass
 
 !IRASTTranslator methodsFor: 'visiting'!
 
+alias: aNode
+	| variable |
+	variable := IRVariable new 
+		variable: (AliasVar new name: '$', self nextAlias); 
+		yourself.
+
+	self sequence add: (IRAlias new
+		add: variable;
+		add: (self visit: aNode);
+		yourself).
+
+	self method internalVariables add: variable.
+
+	^ variable
+!
+
 visitAssignmentNode: aNode
-	self builder assignment 
-		with: [ self visit: aNode left ];
-		with: [ self visit: aNode right ]
+	| left right |
+	
+	aNode right isAssignmentNode 
+		ifTrue: [ | assignment |
+			assignment := self visit: aNode right.
+			self sequence add: assignment.
+			right :=  assignment instructions first ]
+		ifFalse: [ right := self visit: aNode right ].
+
+	left := self visit: aNode left.
+	
+	^ IRAssignment new 
+		add: left;
+		add: right;
+		yourself
 !
 
 visitBlockNode: aNode
-	self builder closure 
-		with: [ 
-			aNode scope temps do: [ :each |
-				self builder tempDeclaration name: each name ].
-			super visitBlockNode: aNode ];
-		arguments: aNode parameters
+	| closure |
+	closure := IRClosure new
+		arguments: aNode parameters;
+		yourself.
+	aNode scope temps do: [ :each |
+		closure add: (IRTempDeclaration new 
+			name: each name;
+			yourself) ].
+	aNode nodes do: [ :each | closure add: (self visit: each) ].
+	^ closure
 !
 
 visitBlockSequenceNode: aNode
-	self builder blockSequence with: [
-		aNode nodes do: [ :each | self visit: each ]]
+	| seq |
+	seq := IRBlockSequence new.
+	self sequence: seq.
+	aNode nodes do: [ :each | 
+		self sequence add: (self visit: each) ].
+	^ seq
+!
+
+visitCascadeNode: aNode
+	| alias |
+
+	aNode receiver isValueNode ifFalse: [ 
+		alias := self sequence add: (self alias: aNode receiver).
+		aNode nodes do: [ :each |
+			each receiver: (VariableNode new binding: alias variable) ]].
+
+	aNode nodes allButLast do: [ :each |
+		self sequence add: (self visit: each) ].
+
+	^ self alias: aNode nodes last
 !
 
 visitJSStatementNode: aNode
-	self builder verbatim: aNode source
+	^ IRVerbatim new
+		source: aNode source;
+		yourself
 !
 
 visitMethodNode: aNode
-	self builder method 
+
+	self method: (IRMethod new
 		source: self source;
 		arguments: aNode arguments;
 		selector: aNode selector;
 		messageSends: aNode messageSends;
-		classReferences: aNode classReferences.
+		classReferences: aNode classReferences;
+		yourself).
 
 	aNode scope temps do: [ :each |
-		self builder tempDeclaration name: each name ].
+		self method add: (IRTempDeclaration new
+			name: each name;
+			yourself) ].
+
 	aNode hasNonLocalReturn 
-		ifTrue: [ self builder nonLocalReturnHandling with: [
-			super visitMethodNode: aNode ]]
-		ifFalse: [ super visitMethodNode: aNode ].
+		ifTrue: [ | handling |
+			handling := IRNonLocalReturnHandling new.
+			aNode nodes do: [ :each | handling add: (self visit: each) ].
+			self method add: handling ]
+		ifFalse: [ aNode nodes do: [ :each | self method add: (self visit: each) ]].
 
 	aNode hasLocalReturn ifFalse: [
-		self builder return with: [
-			self builder variable: (aNode scope pseudoVars at: 'self') ]]
+		(self method add: IRReturn new) add: (IRVariable new
+			variable: (aNode scope pseudoVars at: 'self');
+			yourself) ].
+
+	^ self method
 !
 
 visitReturnNode: aNode
-	(aNode nonLocalReturn 
-		ifTrue: [ self builder nonLocalReturn ]
-		ifFalse: [ self builder return ]) with: [ super visitReturnNode: aNode ]
+	| return |
+	return := aNode nonLocalReturn 
+		ifTrue: [ IRNonLocalReturn new ]
+		ifFalse: [ IRReturn new ].
+	aNode nodes do: [ :each | return add: (self visit: each) ].
+	^ return
 !
 
 visitSendNode: aNode
-	| send |
-	send := self builder send.
+	| send receiver arguments |
+	send := IRSend new.
 	send selector: aNode selector.
 	aNode superSend ifTrue: [ send classSend: self theClass superclass ].
-	send with: [
-		self visit: aNode receiver.
-		(aNode arguments do: [ :each | self visit: each ]) ]
-!
-
-visitSequenceNode: aNode
-	self builder sequence with: [
-		super visitSequenceNode: aNode ]
-!
-
-visitValueNode: aNode
-	self builder value: aNode value
-!
 
-visitVariableNode: aNode
-	self builder variable: aNode binding
-! !
+	receiver := self visit: aNode receiver.
+	arguments := aNode arguments collect: [ :each | self visit: each ].
 
-IRASTTranslator subclass: #IRASTResolver
-	instanceVariableNames: 'nextAlias'
-	package: 'Compiler-IR'!
-!IRASTResolver commentStamp!
-I resolve nodes by creating an alias variable when appropriate, to flatten the AST.
-Nodes referenced in other nodes are aliased, except for some specific nodes such as variable or value nodes.!
+	send add: receiver.
+	arguments do: [ :each | send add: each ].
 
-!IRASTResolver methodsFor: 'accessing'!
-
-nextAlias
-	"Message sends are assigned, or 'aliased', to internal variables.
-	Internal variable names are unique, and attached to the annotated send node"
-
-	nextAlias ifNil: [ nextAlias := 0 ].
-	nextAlias := nextAlias + 1.
-	^ '$', nextAlias asString
-! !
-
-!IRASTResolver methodsFor: 'visiting'!
-
-resolve: aNode
-	aNode isBlockSequenceNode ifFalse: [
-		aNode nodes do: [ :each | self resolve: each ]].
-	aNode shouldBeAliased ifTrue: [
-			| alias |
-			alias := self nextAlias.
-			self builder method internalVariables add: alias.
-			self builder alias
-				with: [ self builder variable: (AliasVar new 
-					name: alias;
-					node: aNode;
-					yourself) ];
-				with: [ self visit: aNode resolving: false ].
-				aNode alias: alias ]
-!
-
-visit: aNode
-	self visit: aNode resolving: aNode canAliasChildren
-!
-
-visit: aNode resolving: aBoolean
-	aBoolean ifTrue: [ self resolve: aNode ].
-	aNode isAliased 
-		ifTrue: [ self visitAliased: aNode ]
-		ifFalse: [ super visit: aNode ]
-!
-
-visitAliased: aNode
-	^ self builder variable: (AliasVar new 
-		name: aNode alias;
-		node: aNode;
-		yourself)
-!
-
-visitCascadeNode: aNode
-	"Special care must be taken for cascade nodes.
-	Only the last node should be aliased if any"
-
-	aNode nodes allButLast do: [ :each |
-		self visit: each resolving: false ].
-	self visit: aNode nodes last
-! !
-
-Object subclass: #IRBuilder
-	instanceVariableNames: 'method root nextPc'
-	package: 'Compiler-IR'!
-!IRBuilder commentStamp!
-I am responsible for building the IR (Intermatiate Representation) graph, composed of IRInstruction objects.!
-
-!IRBuilder methodsFor: 'accessing'!
-
-method
-	^ method
-!
-
-nextPc
-	nextPc ifNil: [ nextPc := 0 ].
-	nextPc := nextPc + 1.
-	^ nextPc
-!
-
-root
-	^ root
+	^ send
 !
 
-root: anIRInstruction
-	root := anIRInstruction
-! !
-
-!IRBuilder methodsFor: 'building'!
-
-add: aClass
-	^ self root append: (aClass on: self)
-!
-
-alias
-	^ self add: IRAlias
-!
-
-append: anObject
-	^root append: anObject
-!
-
-assignment
-	^ self add: IRAssignment
-!
-
-blockSequence
-	^ self add: IRBlockSequence
-!
-
-closure
-	^ self add: IRClosure
-!
-
-nonLocalReturn
-	^ self add: IRNonLocalReturn
-!
-
-nonLocalReturnHandling
-	^ self add: IRNonLocalReturnHandling
-!
-
-return
-	^ self add: IRReturn
-!
-
-send
-	^ self add: IRSend
-!
-
-sequence
-	^ self add: IRSequence
-!
-
-statement
-	^ self add: IRStatement
-!
-
-tempDeclaration
-	^ self add: IRTempDeclaration
-!
-
-value
-	^ self add: IRValue
-!
-
-value: aString
-	^ self value
-		value: aString;
-		yourself
-!
-
-variable
-	^ self add: IRVariable
+visitSequenceNode: aNode
+	| seq |
+	seq := IRSequence new.
+	self sequence: seq.
+	aNode nodes do: [ :each | 
+		self sequence add: (self visit: each) ].
+	^ seq
 !
 
-variable: aScopeVariable
-	^ self variable
-		variable: aScopeVariable;
+visitValueNode: aNode
+	^ IRValue new 
+		value: aNode value; 
 		yourself
 !
 
-verbatim: aString
-	^(self add: IRVerbatim)
-		source: aString;
+visitVariableNode: aNode
+	^ IRVariable new 
+		variable: aNode binding; 
 		yourself
-!
-
-with: anObject
-	self root with: anObject
-! !
-
-!IRBuilder methodsFor: 'emiting'!
-
-emitOn: aStream
-	method emitOn: aStream
-! !
-
-!IRBuilder methodsFor: 'initialization'!
-
-initialize
-	super initialize.
-	root := method := IRMethod on: self
 ! !
 
 Object subclass: #IRInstruction
-	instanceVariableNames: 'builder instructions'
+	instanceVariableNames: 'parent instructions'
 	package: 'Compiler-IR'!
 !IRInstruction commentStamp!
 I am the abstract root class of the IR (intermediate representation) instructions class hierarchy.
@@ -302,47 +208,42 @@ The IR graph is used to emit JavaScript code using a JSStream.!
 
 !IRInstruction methodsFor: 'accessing'!
 
-builder
-	^ builder
+instructions
+	^ instructions ifNil: [ instructions := OrderedCollection new ]
 !
 
-builder: aBuilder
-	builder := aBuilder
+parent
+	^ parent
 !
 
-instructions
-	^ instructions ifNil: [ instructions := OrderedCollection new ]
+parent: anIRInstruction
+	parent := anIRInstruction
 ! !
 
 !IRInstruction methodsFor: 'building'!
 
-append: anObject
-	anObject appendToInstruction: self.
-	^ anObject
+add: anObject
+	anObject parent: self.
+	^ self instructions add: anObject
 !
 
-appendBlock: aBlock
-	| root |
-	root := self builder root.
-	self builder root: self.
-	aBlock value.
-	self builder root: root
+remove
+	self parent remove: self
 !
 
-appendInstruction: anIRInstruction
-	self instructions add: anIRInstruction
+remove: anIRInstruction
+	self instructions remove: anIRInstruction
 !
 
-appendString: aString
-	self append: (self builder value: aString)
-!
-
-appendToInstruction: anIRInstruction
-	anIRInstruction appendInstruction: self
+replace: anIRInstruction with: anotherIRInstruction
+	anotherIRInstruction parent: self.
+	self instructions 
+		at: (self instructions indexOf: anIRInstruction)
+		put: anotherIRInstruction
 !
 
-with: anObject
-	anObject appendToInstruction: self
+replaceWith: anIRInstruction
+	self parent replace: self with: anIRInstruction
 ! !
 
 !IRInstruction methodsFor: 'testing'!
@@ -351,14 +252,26 @@ isClosure
 	^ false
 !
 
+isInlined
+	^ false
+!
+
 isReturn
 	^ false
+!
+
+isSend
+	^ false
+!
+
+isVariable
+	^ false
 ! !
 
 !IRInstruction methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRInstruction: self
+	^ aVisitor visitIRInstruction: self
 ! !
 
 !IRInstruction class methodsFor: 'instance creation'!
@@ -376,7 +289,7 @@ IRInstruction subclass: #IRAssignment
 !IRAssignment methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRAssignment: self
+	^ aVisitor visitIRAssignment: self
 ! !
 
 IRAssignment subclass: #IRAlias
@@ -386,7 +299,7 @@ IRAssignment subclass: #IRAlias
 !IRAlias methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRAlias: self
+	^ aVisitor visitIRAlias: self
 ! !
 
 IRInstruction subclass: #IRClosure
@@ -412,7 +325,7 @@ isClosure
 !IRClosure methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRClosure: self
+	^ aVisitor visitIRClosure: self
 ! !
 
 IRInstruction subclass: #IRMethod
@@ -470,7 +383,7 @@ source: aString
 !IRMethod methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRMethod: self
+	^ aVisitor visitIRMethod: self
 ! !
 
 IRInstruction subclass: #IRNonLocalReturnHandling
@@ -483,7 +396,7 @@ Non local returns are handled with a try/catch statement!
 !IRNonLocalReturnHandling methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRNonLocalReturnHandling: self
+	^ aVisitor visitIRNonLocalReturnHandling: self
 ! !
 
 IRInstruction subclass: #IRReturn
@@ -501,7 +414,7 @@ isReturn
 !IRReturn methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRReturn: self
+	^ aVisitor visitIRReturn: self
 ! !
 
 IRReturn subclass: #IRNonLocalReturn
@@ -516,7 +429,7 @@ See IRNonLocalReturnHandling class!
 !IRNonLocalReturn methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRNonLocalReturn: self
+	^ aVisitor visitIRNonLocalReturn: self
 ! !
 
 IRInstruction subclass: #IRSend
@@ -543,10 +456,16 @@ selector: aString
 	selector := aString
 ! !
 
+!IRSend methodsFor: 'testing'!
+
+isSend
+	^ true
+! !
+
 !IRSend methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRSend: self
+	^ aVisitor visitIRSend: self
 ! !
 
 IRInstruction subclass: #IRSequence
@@ -555,14 +474,18 @@ IRInstruction subclass: #IRSequence
 
 !IRSequence methodsFor: 'adding'!
 
-appendInstruction: anIRInstruction
-	self instructions add: ((IRStatement on: self builder) with: anIRInstruction)
+add: anIRInstruction
+	| statement |
+	statement := IRStatement new.
+	statement add: anIRInstruction.
+	self instructions add: statement.
+	^ anIRInstruction
 ! !
 
 !IRSequence methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRSequence: self
+	^ aVisitor visitIRSequence: self
 ! !
 
 IRSequence subclass: #IRBlockSequence
@@ -572,22 +495,16 @@ IRSequence subclass: #IRBlockSequence
 !IRBlockSequence methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRBlockSequence: self
+	^ aVisitor visitIRBlockSequence: self
 ! !
 
 IRInstruction subclass: #IRStatement
-	instanceVariableNames: 'pc'
+	instanceVariableNames: ''
 	package: 'Compiler-IR'!
 !IRStatement commentStamp!
 I am a statement instruction. 
 Statements can be used to control the PC count, among other things.!
 
-!IRStatement methodsFor: 'accessing'!
-
-pc
-	^ pc ifNil: [pc := self builder nextPc]
-! !
-
 !IRStatement methodsFor: 'testing'!
 
 isReturn
@@ -597,7 +514,7 @@ isReturn
 !IRStatement methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRStatement: self
+	^ aVisitor visitIRStatement: self
 ! !
 
 IRInstruction subclass: #IRTempDeclaration
@@ -619,7 +536,7 @@ name: aString
 !IRTempDeclaration methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRTempDeclaration: self
+	^ aVisitor visitIRTempDeclaration: self
 ! !
 
 IRInstruction subclass: #IRValue
@@ -641,7 +558,7 @@ value: aString
 !IRValue methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRValue: self
+	^ aVisitor visitIRValue: self
 ! !
 
 IRInstruction subclass: #IRVariable
@@ -660,10 +577,16 @@ variable: aScopeVariable
 	variable := aScopeVariable
 ! !
 
+!IRVariable methodsFor: 'testing'!
+
+isVariable
+	^ true
+! !
+
 !IRVariable methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRVariable: self
+	^ aVisitor visitIRVariable: self
 ! !
 
 IRInstruction subclass: #IRVerbatim
@@ -683,7 +606,7 @@ source: aString
 !IRVerbatim methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRVerbatim: self
+	^ aVisitor visitIRVerbatim: self
 ! !
 
 Object subclass: #IRVisitor
@@ -693,83 +616,91 @@ Object subclass: #IRVisitor
 !IRVisitor methodsFor: 'visiting'!
 
 visit: anIRInstruction
-	anIRInstruction accept: self
+	^ anIRInstruction accept: self
 !
 
 visitIRAlias: anIRAlias
-	self visitIRAssignment: anIRAlias
+	^ self visitIRAssignment: anIRAlias
 !
 
 visitIRAssignment: anIRAssignment
-	self visitIRInstruction: anIRAssignment
+	^ self visitIRInstruction: anIRAssignment
 !
 
 visitIRBlockSequence: anIRBlockSequence
-	self visitIRSequence: anIRBlockSequence
+	^ self visitIRSequence: anIRBlockSequence
 !
 
 visitIRClosure: anIRClosure
-	self visitIRInstruction: anIRClosure
+	^ self visitIRInstruction: anIRClosure
+!
+
+visitIRInlinedAssignment: anIRInlinedAssignment
+	^ self visitIRAssignment: anIRInlinedAssignment
 !
 
 visitIRInlinedClosure: anIRClosure
-	self visitIRClosure: anIRClosure
+	^ self visitIRClosure: anIRClosure
 !
 
 visitIRInlinedIfTrue: anIRInlinedIfTrue
-	self visitIRInlinedSend: anIRInlinedIfTrue
+	^ self visitIRInlinedSend: anIRInlinedIfTrue
+!
+
+visitIRInlinedNonLocalReturn: anIRNonLocalReturn
+	^ self visitIRNonLocalReturn: anIRNonLocalReturn anIRNonLocalReturn
 !
 
 visitIRInlinedSend: anIRInlinedSend
-	self visitIRSend: anIRInlinedSend
+	^ self visitIRSend: anIRInlinedSend
 !
 
 visitIRInstruction: anIRInstruction
-	anIRInstruction instructions do: [ :each | self visit: each ]
+	^ anIRInstruction instructions do: [ :each | self visit: each ]
 !
 
 visitIRMethod: anIRMethod
-	self visitIRInstruction: anIRMethod
+	^ self visitIRInstruction: anIRMethod
 !
 
 visitIRNonLocalReturn: anIRNonLocalReturn
-	self visitIRInstruction: anIRNonLocalReturn
+	^ self visitIRInstruction: anIRNonLocalReturn
 !
 
 visitIRNonLocalReturnHandling: anIRNonLocalReturnHandling
-	self visitIRInstruction: anIRNonLocalReturnHandling
+	^ self visitIRInstruction: anIRNonLocalReturnHandling
 !
 
 visitIRReturn: anIRReturn
-	self visitIRInstruction: anIRReturn
+	^ self visitIRInstruction: anIRReturn
 !
 
 visitIRSend: anIRSend
-	self visitIRInstruction: anIRSend
+	^ self visitIRInstruction: anIRSend
 !
 
 visitIRSequence: anIRSequence
-	self visitIRInstruction: anIRSequence
+	^ self visitIRInstruction: anIRSequence
 !
 
 visitIRStatement: anIRStatement
-	self visitIRInstruction: anIRStatement
+	^ self visitIRInstruction: anIRStatement
 !
 
 visitIRTempDeclaration: anIRTempDeclaration
-	self visitIRInstruction: anIRTempDeclaration
+	^ self visitIRInstruction: anIRTempDeclaration
 !
 
 visitIRValue: anIRValue
-	self visitIRInstruction: anIRValue
+	^ self visitIRInstruction: anIRValue
 !
 
 visitIRVariable: anIRVariable
-	self visitIRInstruction: anIRVariable
+	^ self visitIRInstruction: anIRVariable
 !
 
 visitIRVerbatim: anIRVerbatim
-	self visitIRInstruction: anIRVerbatim
+	^ self visitIRInstruction: anIRVerbatim
 ! !
 
 IRVisitor subclass: #IRJSTranslator
@@ -827,7 +758,8 @@ visitIRMethod: anIRMethod
 		with: [ self stream 
 			nextPutFunctionWith: [ 
 				anIRMethod internalVariables notEmpty ifTrue: [
-					self stream nextPutVars: anIRMethod internalVariables ].
+					self stream nextPutVars: (anIRMethod internalVariables asArray collect: [ :each |
+						each variable alias ]) ].
 				super visitIRMethod: anIRMethod ]
 			arguments: anIRMethod arguments ]
 !
@@ -871,8 +803,10 @@ visitIRSequence: anIRSequence
 !
 
 visitIRStatement: anIRStatement
-	self stream nextPutStatementWith: [
-		super visitIRStatement: anIRStatement ]
+	(anIRStatement instructions size = 1 and: [
+		anIRStatement instructions first isVariable ]) ifFalse: [
+			self stream nextPutStatementWith: [
+				super visitIRStatement: anIRStatement ]]
 !
 
 visitIRTempDeclaration: anIRTempDeclaration
@@ -1049,17 +983,9 @@ appendToInstruction: anIRInstruction
 
 !String methodsFor: '*Compiler-IR'!
 
-appendToInstruction: anInstruction
-	anInstruction appendString: self
-!
-
 asVariableName
 	^ (Smalltalk current reservedWords includes: self)
 		ifTrue: [ self, '_' ]
 		ifFalse: [ self ]
-!
-
-emitOn: aStream
-	aStream nextPutAll: self
 ! !
 

+ 282 - 0
st/Compiler-Inlining.st

@@ -0,0 +1,282 @@
+Smalltalk current createPackage: 'Compiler-Inlining' properties: #{}!
+IRAssignment subclass: #IRInlinedAssignment
+	instanceVariableNames: ''
+	package: 'Compiler-Inlining'!
+
+!IRInlinedAssignment methodsFor: 'testing'!
+
+isInlined
+	^ true
+! !
+
+!IRInlinedAssignment methodsFor: 'visiting'!
+
+accept: aVisitor
+	^ aVisitor visitIRInlinedAssignment: self
+! !
+
+IRClosure subclass: #IRInlinedClosure
+	instanceVariableNames: 'assignTo'
+	package: 'Compiler-Inlining'!
+
+!IRInlinedClosure methodsFor: 'accessing'!
+
+assignTo
+	^ assignTo
+!
+
+assignTo: aScopeVar
+	assignTo := aScopeVar
+! !
+
+!IRInlinedClosure methodsFor: 'testing'!
+
+isInlined
+	^ true
+! !
+
+!IRInlinedClosure methodsFor: 'visiting'!
+
+accept: aVisitor
+	aVisitor visitIRInlinedClosure: self
+! !
+
+IRNonLocalReturn subclass: #IRInlinedNonLocalReturn
+	instanceVariableNames: ''
+	package: 'Compiler-Inlining'!
+
+!IRInlinedNonLocalReturn methodsFor: 'testing'!
+
+isInlined
+	^ true
+! !
+
+!IRInlinedNonLocalReturn methodsFor: 'visiting'!
+
+accept: aVisitor
+	^ aVisitor visitIRInlinedNonLocalReturn: self
+! !
+
+IRSend subclass: #IRInlinedSend
+	instanceVariableNames: ''
+	package: 'Compiler-Inlining'!
+
+!IRInlinedSend methodsFor: 'testing'!
+
+isInlined
+	^ true
+! !
+
+!IRInlinedSend methodsFor: 'visiting'!
+
+accept: aVisitor
+	aVisitor visitInlinedSend: self
+! !
+
+IRInlinedSend subclass: #IRInlinedIfTrue
+	instanceVariableNames: ''
+	package: 'Compiler-Inlining'!
+
+!IRInlinedIfTrue methodsFor: 'visiting'!
+
+accept: aVisitor
+	aVisitor visitIRInlinedIfTrue: self
+! !
+
+IRVisitor subclass: #IRInliner
+	instanceVariableNames: ''
+	package: 'Compiler-Inlining'!
+
+!IRInliner methodsFor: 'testing'!
+
+shouldInlineAssignment: anIRAssignment
+	^ anIRAssignment isInlined not and: [ 
+		anIRAssignment instructions last isSend and: [	
+			self shouldInlineSend: (anIRAssignment instructions last) ]]
+!
+
+shouldInlineSend: anIRSend
+	^ anIRSend isInlined not and: [
+		IRSendInliner inlinedSelectors includes: anIRSend selector ]
+! !
+
+!IRInliner methodsFor: 'visiting'!
+
+assignmentInliner
+	^ IRAssignmentInliner new 
+		translator: self;
+		yourself
+!
+
+sendInliner
+	^ IRSendInliner new 
+		translator: self;
+		yourself
+!
+
+visitIRAssignment: anIRAssignment
+	^ (self shouldInlineAssignment: anIRAssignment) 
+		ifTrue: [ self assignmentInliner inlineAssignment: anIRAssignment ]
+		ifFalse: [ super visitIRAssignment: anIRAssignment ]
+!
+
+visitIRSend: anIRSend
+	^ (self shouldInlineSend: anIRSend)
+		ifTrue: [ self sendInliner inlineSend: anIRSend ]
+		ifFalse: [ super visitIRSend: anIRSend ]
+!
+
+visitSendNode: aNode
+	aNode canBeInlined
+		ifTrue: [ self sendInliner inlineSend: aNode ]
+		ifFalse: [ super visitSendNode: aNode ]
+! !
+
+IRJSTranslator subclass: #IRInliningJSTranslator
+	instanceVariableNames: ''
+	package: 'Compiler-Inlining'!
+
+!IRInliningJSTranslator methodsFor: 'visiting'!
+
+visitIRInlinedAssignment: anIRInlinedAssignment
+	self visit: anIRInlinedAssignment instructions last
+!
+
+visitIRInlinedClosure: anIRInlinedClosure
+	anIRInlinedClosure instructions allButLast do: [ :each | self visit: each ].
+	anIRInlinedClosure assignTo ifNotNil: [
+		self stream nextPutAll: anIRInlinedClosure assignTo variable alias.
+		self stream nextPutAssignment ].
+	self visit: anIRInlinedClosure instructions last
+!
+
+visitIRInlinedIfTrue: anIRInlinedIfTrue
+	self stream 
+		nextPutIf: [ self visit: anIRInlinedIfTrue instructions first ]
+		with: [ self visit: anIRInlinedIfTrue instructions last ]
+! !
+
+Object subclass: #IRSendInliner
+	instanceVariableNames: 'send translator'
+	package: 'Compiler-Inlining'!
+!IRSendInliner commentStamp!
+I inline some message sends and block closure arguments. I heavily rely on #perform: to dispatch inlining methods.!
+
+!IRSendInliner methodsFor: 'accessing'!
+
+inlinedClosure
+	^ IRInlinedClosure new
+!
+
+send
+	^ send
+!
+
+send: anIRSend
+	send := anIRSend
+!
+
+translator
+	^ translator
+!
+
+translator: anASTTranslator
+	translator := anASTTranslator
+! !
+
+!IRSendInliner methodsFor: 'error handling'!
+
+inliningError: aString
+	InliningError signal: aString
+! !
+
+!IRSendInliner methodsFor: 'inlining'!
+
+ifTrue: anIRInstruction
+	| inlinedSend inlinedClosure |
+
+	anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].
+	anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].
+
+	inlinedClosure := self inlinedClosure.
+	anIRInstruction instructions do: [ :each |
+		instruction := (self translator visit: each) first.
+		inlinedClosure add: instruction ].
+
+	inlinedSend := IRInlinedIfTrue new.
+	inlinedSend
+		add: self send instructions first;
+		add: inlinedClosure.
+
+	self send replaceWith: inlinedSend.
+	^ inlinedSend
+!
+
+inlineSend: anIRSend
+	self send: anIRSend.
+	self perform: self send selector withArguments: self send instructions allButFirst
+! !
+
+!IRSendInliner class methodsFor: 'accessing'!
+
+inlinedSelectors
+	^ #('ifTrue:')
+! !
+
+IRSendInliner subclass: #IRAssignmentInliner
+	instanceVariableNames: 'assignment'
+	package: 'Compiler-Inlining'!
+
+!IRAssignmentInliner methodsFor: 'accessing'!
+
+assignment
+	^ assignment
+!
+
+assignment: aNode
+	assignment := aNode
+!
+
+inlinedClosure
+	^ super inlinedClosure
+		assignTo: self assignment instructions first;
+		yourself
+! !
+
+!IRAssignmentInliner methodsFor: 'inlining'!
+
+inlineAssignment: anIRAssignment
+	| inlinedAssignment |
+	self assignment: anIRAssignment.
+	inlinedAssignment := IRInlinedAssignment new.
+	anIRAssignment instructions do: [ :each |
+		inlinedAssignment add: each ].
+	anIRAssignment replaceWith: inlinedAssignment.
+	self inlineSend: inlinedAssignment instructions last.
+	^ inlinedAssignment
+! !
+
+CodeGenerator subclass: #InliningCodeGenerator
+	instanceVariableNames: ''
+	package: 'Compiler-Inlining'!
+
+!InliningCodeGenerator methodsFor: 'compiling'!
+
+compileNode: aNode
+	| ir stream |
+	self semanticAnalyzer visit: aNode.
+	ir := self translator visit: aNode.
+	self inliner visit: ir.
+	^ self irTranslator
+		visit: ir;
+		contents
+!
+
+inliner
+	^ IRInliner new
+!
+
+irTranslator
+	^ IRInliningJSTranslator new
+! !
+

+ 2 - 2
st/Compiler-Semantic.st

@@ -452,7 +452,7 @@ allowUnknownVariables
 visitAssignmentNode: aNode
 	super visitAssignmentNode: aNode.
 	aNode left beAssigned.
-	aNode right beUsed
+	aNode right assignedTo: aNode left binding
 !
 
 visitBlockNode: aNode
@@ -507,7 +507,6 @@ visitReturnNode: aNode
 		ifFalse: [
 			currentScope methodScope addNonLocalReturn: aNode.
 			aNode nonLocalReturn: true ].
-	aNode nodes first beUsed.
 	super visitReturnNode: aNode
 !
 
@@ -522,6 +521,7 @@ visitSendNode: aNode
 		aNode receiver beUsed ].
 	aNode arguments do: [ :each |
 		each isSendNode ifTrue: [ each beUsed ]].
+
 	super visitSendNode: aNode
 !
 

Some files were not shown because too many files changed in this diff