Browse Source

More robust inliner handling common inlined blocks edge cases

Nicolas Petton 12 years ago
parent
commit
19c1fc0c0a

+ 45 - 1
js/Compiler-AST.deploy.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-AST', {});
-smalltalk.addClass('Node', smalltalk.Object, ['nodes'], 'Compiler-AST');
+smalltalk.addClass('Node', smalltalk.Object, ['nodes', 'shouldBeInlined'], 'Compiler-AST');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -55,6 +55,17 @@ return self;}
 }),
 smalltalk.Node);
 
+smalltalk.addMethod(
+"_isReturnNode",
+smalltalk.method({
+selector: "isReturnNode",
+fn: function () {
+var self=this;
+return false;
+return self;}
+}),
+smalltalk.Node);
+
 smalltalk.addMethod(
 "_isSendNode",
 smalltalk.method({
@@ -99,6 +110,28 @@ return self;}
 }),
 smalltalk.Node);
 
+smalltalk.addMethod(
+"_shouldBeInlined",
+smalltalk.method({
+selector: "shouldBeInlined",
+fn: function () {
+var self=this;
+return (($receiver = self['@shouldBeInlined']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
+return self;}
+}),
+smalltalk.Node);
+
+smalltalk.addMethod(
+"_shouldBeInlined_",
+smalltalk.method({
+selector: "shouldBeInlined:",
+fn: function (aBoolean) {
+var self=this;
+(self['@shouldBeInlined']=aBoolean);
+return self;}
+}),
+smalltalk.Node);
+
 
 
 smalltalk.addClass('AssignmentNode', smalltalk.Node, ['left', 'right'], 'Compiler-AST');
@@ -508,6 +541,17 @@ return self;}
 }),
 smalltalk.ReturnNode);
 
+smalltalk.addMethod(
+"_isReturnNode",
+smalltalk.method({
+selector: "isReturnNode",
+fn: function () {
+var self=this;
+return true;
+return self;}
+}),
+smalltalk.ReturnNode);
+
 smalltalk.addMethod(
 "_nonLocalReturn",
 smalltalk.method({

+ 65 - 1
js/Compiler-AST.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-AST', {});
-smalltalk.addClass('Node', smalltalk.Object, ['nodes'], 'Compiler-AST');
+smalltalk.addClass('Node', smalltalk.Object, ['nodes', 'shouldBeInlined'], 'Compiler-AST');
 smalltalk.Node.comment="I am the abstract root class of the abstract syntax tree."
 smalltalk.addMethod(
 "_accept_",
@@ -81,6 +81,22 @@ referencedClasses: []
 }),
 smalltalk.Node);
 
+smalltalk.addMethod(
+"_isReturnNode",
+smalltalk.method({
+selector: "isReturnNode",
+category: 'testing',
+fn: function () {
+var self=this;
+return false;
+return self;},
+args: [],
+source: "isReturnNode\x0a\x09^false",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Node);
+
 smalltalk.addMethod(
 "_isSendNode",
 smalltalk.method({
@@ -145,6 +161,38 @@ referencedClasses: []
 }),
 smalltalk.Node);
 
+smalltalk.addMethod(
+"_shouldBeInlined",
+smalltalk.method({
+selector: "shouldBeInlined",
+category: 'accessing',
+fn: function () {
+var self=this;
+return (($receiver = self['@shouldBeInlined']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
+return self;},
+args: [],
+source: "shouldBeInlined\x0a\x09^ shouldBeInlined ifNil: [ false ]",
+messageSends: ["ifNil:"],
+referencedClasses: []
+}),
+smalltalk.Node);
+
+smalltalk.addMethod(
+"_shouldBeInlined_",
+smalltalk.method({
+selector: "shouldBeInlined:",
+category: 'accessing',
+fn: function (aBoolean) {
+var self=this;
+(self['@shouldBeInlined']=aBoolean);
+return self;},
+args: ["aBoolean"],
+source: "shouldBeInlined: aBoolean\x0a\x09shouldBeInlined := aBoolean",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Node);
+
 
 
 smalltalk.addClass('AssignmentNode', smalltalk.Node, ['left', 'right'], 'Compiler-AST');
@@ -729,6 +777,22 @@ referencedClasses: []
 }),
 smalltalk.ReturnNode);
 
+smalltalk.addMethod(
+"_isReturnNode",
+smalltalk.method({
+selector: "isReturnNode",
+category: 'testing',
+fn: function () {
+var self=this;
+return true;
+return self;},
+args: [],
+source: "isReturnNode\x0a\x09^ true",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ReturnNode);
+
 smalltalk.addMethod(
 "_nonLocalReturn",
 smalltalk.method({

+ 2 - 2
js/Compiler-Exceptions.deploy.js

@@ -16,7 +16,7 @@ smalltalk.addMethod(
 "_messageText",
 smalltalk.method({
 selector: "messageText",
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(" Invalid assignment to variable: ", "__comma", [smalltalk.send(self, "_variableName", [])]);
 return self;}
@@ -52,7 +52,7 @@ smalltalk.addMethod(
 "_messageText",
 smalltalk.method({
 selector: "messageText",
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(smalltalk.send("Variable shadowing error: ", "__comma", [smalltalk.send(self, "_variableName", [])]), "__comma", [" is already defined"]);
 return self;}

+ 2 - 2
js/Compiler-Exceptions.js

@@ -19,7 +19,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "messageText",
 category: 'accessing',
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(" Invalid assignment to variable: ", "__comma", [smalltalk.send(self, "_variableName", [])]);
 return self;},
@@ -71,7 +71,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "messageText",
 category: 'accessing',
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(smalltalk.send("Variable shadowing error: ", "__comma", [smalltalk.send(self, "_variableName", [])]), "__comma", [" is already defined"]);
 return self;},

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


File diff suppressed because it is too large
+ 170 - 239
js/Compiler-IR.js


+ 339 - 22
js/Compiler-Inlining.deploy.js

@@ -24,7 +24,7 @@ smalltalk.IRInlinedAssignment);
 
 
 
-smalltalk.addClass('IRInlinedClosure', smalltalk.IRClosure, ['assignTo'], 'Compiler-Inlining');
+smalltalk.addClass('IRInlinedClosure', smalltalk.IRClosure, [], 'Compiler-Inlining');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -37,26 +37,29 @@ return self;}
 smalltalk.IRInlinedClosure);
 
 smalltalk.addMethod(
-"_assignTo",
+"_isInlined",
 smalltalk.method({
-selector: "assignTo",
+selector: "isInlined",
 fn: function () {
 var self=this;
-return self['@assignTo'];
+return true;
 return self;}
 }),
 smalltalk.IRInlinedClosure);
 
+
+
+smalltalk.addClass('IRInlinedReturn', smalltalk.IRReturn, [], 'Compiler-Inlining');
 smalltalk.addMethod(
-"_assignTo_",
+"_accept_",
 smalltalk.method({
-selector: "assignTo:",
-fn: function (aScopeVar) {
+selector: "accept:",
+fn: function (aVisitor) {
 var self=this;
-(self['@assignTo']=aScopeVar);
+return smalltalk.send(aVisitor, "_visitIRInlinedReturn_", [self]);
 return self;}
 }),
-smalltalk.IRInlinedClosure);
+smalltalk.IRInlinedReturn);
 
 smalltalk.addMethod(
 "_isInlined",
@@ -67,11 +70,11 @@ var self=this;
 return true;
 return self;}
 }),
-smalltalk.IRInlinedClosure);
+smalltalk.IRInlinedReturn);
 
 
 
-smalltalk.addClass('IRInlinedNonLocalReturn', smalltalk.IRReturn, [], 'Compiler-Inlining');
+smalltalk.addClass('IRInlinedNonLocalReturn', smalltalk.IRInlinedReturn, [], 'Compiler-Inlining');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -149,6 +152,95 @@ smalltalk.IRInlinedIfTrue);
 
 
 
+smalltalk.addClass('IRInlinedSequence', smalltalk.IRBlockSequence, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+fn: function (aVisitor) {
+var self=this;
+smalltalk.send(aVisitor, "_visitIRInlinedSequence_", [self]);
+return self;}
+}),
+smalltalk.IRInlinedSequence);
+
+smalltalk.addMethod(
+"_isInlined",
+smalltalk.method({
+selector: "isInlined",
+fn: function () {
+var self=this;
+return true;
+return self;}
+}),
+smalltalk.IRInlinedSequence);
+
+
+
+smalltalk.addClass('IRAssigningInlinedSequence', smalltalk.IRInlinedSequence, ['assignTo'], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+fn: function (aVisitor) {
+var self=this;
+return smalltalk.send(aVisitor, "_visitIRAssigningInlinedSequence_", [self]);
+return self;}
+}),
+smalltalk.IRAssigningInlinedSequence);
+
+smalltalk.addMethod(
+"_assignTo",
+smalltalk.method({
+selector: "assignTo",
+fn: function () {
+var self=this;
+return self['@assignTo'];
+return self;}
+}),
+smalltalk.IRAssigningInlinedSequence);
+
+smalltalk.addMethod(
+"_assignTo_",
+smalltalk.method({
+selector: "assignTo:",
+fn: function (anIRInstruction) {
+var self=this;
+(self['@assignTo']=anIRInstruction);
+return self;}
+}),
+smalltalk.IRAssigningInlinedSequence);
+
+
+
+smalltalk.addClass('IRReturningInlinedSequence', smalltalk.IRInlinedSequence, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+fn: function (aVisitor) {
+var self=this;
+return smalltalk.send(aVisitor, "_visitIRReturningInlinedSequence_", [self]);
+return self;}
+}),
+smalltalk.IRReturningInlinedSequence);
+
+
+
+smalltalk.addClass('IRNonLocalReturningInlinedSequence', smalltalk.IRReturningInlinedSequence, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+fn: function (aVisitor) {
+var self=this;
+return smalltalk.send(aVisitor, "_visitIRNonLocalReturningInlinedSequence_", [self]);
+return self;}
+}),
+smalltalk.IRNonLocalReturningInlinedSequence);
+
+
+
 smalltalk.addClass('IRInliner', smalltalk.IRVisitor, [], 'Compiler-Inlining');
 smalltalk.addMethod(
 "_assignmentInliner",
@@ -161,6 +253,28 @@ return self;}
 }),
 smalltalk.IRInliner);
 
+smalltalk.addMethod(
+"_nonLocalReturnInliner",
+smalltalk.method({
+selector: "nonLocalReturnInliner",
+fn: function () {
+var self=this;
+return (function($rec){smalltalk.send($rec, "_translator_", [self]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRNonLocalReturnInliner || IRNonLocalReturnInliner), "_new", []));
+return self;}
+}),
+smalltalk.IRInliner);
+
+smalltalk.addMethod(
+"_returnInliner",
+smalltalk.method({
+selector: "returnInliner",
+fn: function () {
+var self=this;
+return (function($rec){smalltalk.send($rec, "_translator_", [self]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRReturnInliner || IRReturnInliner), "_new", []));
+return self;}
+}),
+smalltalk.IRInliner);
+
 smalltalk.addMethod(
 "_sendInliner",
 smalltalk.method({
@@ -183,24 +297,50 @@ return self;}
 }),
 smalltalk.IRInliner);
 
+smalltalk.addMethod(
+"_shouldInlineReturn_",
+smalltalk.method({
+selector: "shouldInlineReturn:",
+fn: function (anIRReturn) {
+var self=this;
+return smalltalk.send(smalltalk.send(smalltalk.send(anIRReturn, "_isInlined", []), "_not", []), "_and_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(anIRReturn, "_instructions", []), "_first", []), "_isSend", []), "_and_", [(function(){return smalltalk.send(self, "_shouldInlineSend_", [smalltalk.send(smalltalk.send(anIRReturn, "_instructions", []), "_first", [])]);})]);})]);
+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 smalltalk.send(smalltalk.send(smalltalk.send(anIRSend, "_isInlined", []), "_not", []), "_and_", [(function(){return smalltalk.send((smalltalk.IRSendInliner || IRSendInliner), "_shouldInline_", [anIRSend]);})]);
 return self;}
 }),
 smalltalk.IRInliner);
 
+smalltalk.addMethod(
+"_transformNonLocalReturn_",
+smalltalk.method({
+selector: "transformNonLocalReturn:",
+fn: function (anIRNonLocalReturn) {
+var self=this;
+var $early={};
+try{var localReturn=nil;
+((($receiver = smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_canInlineNonLocalReturns", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_methodScope", []), "_removeNonLocalReturn_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);(localReturn=(function($rec){smalltalk.send($rec, "_scope_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRReturn || IRReturn), "_new", [])));smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_instructions", []), "_do_", [(function(each){return smalltalk.send(localReturn, "_add_", [each]);})]);smalltalk.send(anIRNonLocalReturn, "_replaceWith_", [localReturn]);return (function(){throw $early=[localReturn]})();})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_methodScope", []), "_removeNonLocalReturn_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);(localReturn=(function($rec){smalltalk.send($rec, "_scope_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRReturn || IRReturn), "_new", [])));smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_instructions", []), "_do_", [(function(each){return smalltalk.send(localReturn, "_add_", [each]);})]);smalltalk.send(anIRNonLocalReturn, "_replaceWith_", [localReturn]);return (function(){throw $early=[localReturn]})();})]));
+return smalltalk.send(self, "_visitIRNonLocalReturn_", [anIRNonLocalReturn], smalltalk.IRInliner.superclass || nil);
+return self;
+} catch(e) {if(e===$early)return e[0]; throw e}}
+}),
+smalltalk.IRInliner);
+
 smalltalk.addMethod(
 "_visitIRAssignment_",
 smalltalk.method({
 selector: "visitIRAssignment:",
 fn: function (anIRAssignment) {
 var self=this;
-((($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 ((($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);
@@ -211,9 +351,18 @@ smalltalk.method({
 selector: "visitIRNonLocalReturn:",
 fn: function (anIRNonLocalReturn) {
 var self=this;
-var localReturn=nil;
-((($receiver = smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_canInlineNonLocalReturns", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_methodScope", []), "_removeNonLocalReturn_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);(localReturn=(function($rec){smalltalk.send($rec, "_scope_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRInlinedNonLocalReturn || IRInlinedNonLocalReturn), "_new", [])));smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_instructions", []), "_do_", [(function(each){return smalltalk.send(localReturn, "_add_", [each]);})]);return smalltalk.send(anIRNonLocalReturn, "_replaceWith_", [localReturn]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_methodScope", []), "_removeNonLocalReturn_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);(localReturn=(function($rec){smalltalk.send($rec, "_scope_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRInlinedNonLocalReturn || IRInlinedNonLocalReturn), "_new", [])));smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_instructions", []), "_do_", [(function(each){return smalltalk.send(localReturn, "_add_", [each]);})]);return smalltalk.send(anIRNonLocalReturn, "_replaceWith_", [localReturn]);})]));
-smalltalk.send(self, "_visitIRNonLocalReturn_", [anIRNonLocalReturn], smalltalk.IRInliner.superclass || nil);
+return ((($receiver = smalltalk.send(self, "_shouldInlineReturn_", [anIRNonLocalReturn])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_nonLocalReturnInliner", []), "_inlineReturn_", [anIRNonLocalReturn]);})() : (function(){return smalltalk.send(self, "_transformNonLocalReturn_", [anIRNonLocalReturn]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_nonLocalReturnInliner", []), "_inlineReturn_", [anIRNonLocalReturn]);}), (function(){return smalltalk.send(self, "_transformNonLocalReturn_", [anIRNonLocalReturn]);})]));
+return self;}
+}),
+smalltalk.IRInliner);
+
+smalltalk.addMethod(
+"_visitIRReturn_",
+smalltalk.method({
+selector: "visitIRReturn:",
+fn: function (anIRReturn) {
+var self=this;
+return ((($receiver = smalltalk.send(self, "_shouldInlineReturn_", [anIRReturn])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_returnInliner", []), "_inlineReturn_", [anIRReturn]);})() : (function(){return smalltalk.send(self, "_visitIRReturn_", [anIRReturn], smalltalk.IRInliner.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_returnInliner", []), "_inlineReturn_", [anIRReturn]);}), (function(){return smalltalk.send(self, "_visitIRReturn_", [anIRReturn], smalltalk.IRInliner.superclass || nil);})]));
 return self;}
 }),
 smalltalk.IRInliner);
@@ -224,7 +373,7 @@ smalltalk.method({
 selector: "visitIRSend:",
 fn: function (anIRSend) {
 var self=this;
-((($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 ((($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);
@@ -232,6 +381,18 @@ smalltalk.IRInliner);
 
 
 smalltalk.addClass('IRInliningJSTranslator', smalltalk.IRJSTranslator, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_visitIRAssigningInlinedSequence_",
+smalltalk.method({
+selector: "visitIRAssigningInlinedSequence:",
+fn: function (anIRInlinedSequence) {
+var self=this;
+smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutStatementWith_", [(function(){return smalltalk.send(self, "_visit_", [each]);})]);})]);
+smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutStatementWith_", [(function(){return ((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", []), "_canBeAssigned", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){(function($rec){smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedSequence, "_assignTo", []), "_variable", []), "_alias", [])]);return smalltalk.send($rec, "_nextPutAssignment", []);})(smalltalk.send(self, "_stream", []));return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})() : (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){(function($rec){smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedSequence, "_assignTo", []), "_variable", []), "_alias", [])]);return smalltalk.send($rec, "_nextPutAssignment", []);})(smalltalk.send(self, "_stream", []));return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);}), (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})]));})]);
+return self;}
+}),
+smalltalk.IRInliningJSTranslator);
+
 smalltalk.addMethod(
 "_visitIRInlinedAssignment_",
 smalltalk.method({
@@ -249,7 +410,7 @@ smalltalk.method({
 selector: "visitIRInlinedClosure:",
 fn: function (anIRInlinedClosure) {
 var self=this;
-smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_ifNotEmpty_", [(function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_assignTo", []), "_notNil", []), "_and_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_last", []), "_canBeAssigned", []);})])).klass === smalltalk.Boolean) ? ($receiver ? (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($receiver, "_ifTrue_", [(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", []);})]));return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_last", [])]);})]);
+smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);
 return self;}
 }),
 smalltalk.IRInliningJSTranslator);
@@ -276,6 +437,64 @@ return self;}
 }),
 smalltalk.IRInliningJSTranslator);
 
+smalltalk.addMethod(
+"_visitIRInlinedNonLocalReturn_",
+smalltalk.method({
+selector: "visitIRInlinedNonLocalReturn:",
+fn: function (anIRInlinedReturn) {
+var self=this;
+smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutStatementWith_", [(function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedReturn, "_instructions", []), "_last", [])]);})]);
+smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutNonLocalReturnWith_", [(function(){return nil;})]);
+return self;}
+}),
+smalltalk.IRInliningJSTranslator);
+
+smalltalk.addMethod(
+"_visitIRInlinedReturn_",
+smalltalk.method({
+selector: "visitIRInlinedReturn:",
+fn: function (anIRInlinedReturn) {
+var self=this;
+smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedReturn, "_instructions", []), "_last", [])]);
+return self;}
+}),
+smalltalk.IRInliningJSTranslator);
+
+smalltalk.addMethod(
+"_visitIRInlinedSequence_",
+smalltalk.method({
+selector: "visitIRInlinedSequence:",
+fn: function (anIRInlinedSequence) {
+var self=this;
+smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_do_", [(function(each){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutStatementWith_", [(function(){return smalltalk.send(self, "_visit_", [each]);})]);})]);
+return self;}
+}),
+smalltalk.IRInliningJSTranslator);
+
+smalltalk.addMethod(
+"_visitIRNonLocalReturningInlinedSequence_",
+smalltalk.method({
+selector: "visitIRNonLocalReturningInlinedSequence:",
+fn: function (anIRInlinedSequence) {
+var self=this;
+smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutStatementWith_", [(function(){return smalltalk.send(self, "_visit_", [each]);})]);})]);
+smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutStatementWith_", [(function(){return ((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", []), "_canBeAssigned", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutNonLocalReturnWith_", [(function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})]);})() : (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutNonLocalReturnWith_", [(function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})]);}), (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})]));})]);
+return self;}
+}),
+smalltalk.IRInliningJSTranslator);
+
+smalltalk.addMethod(
+"_visitIRReturningInlinedSequence_",
+smalltalk.method({
+selector: "visitIRReturningInlinedSequence:",
+fn: function (anIRInlinedSequence) {
+var self=this;
+smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutStatementWith_", [(function(){return smalltalk.send(self, "_visit_", [each]);})]);})]);
+smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutStatementWith_", [(function(){return ((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", []), "_canBeAssigned", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutReturn", []);return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})() : (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutReturn", []);return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);}), (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})]));})]);
+return self;}
+}),
+smalltalk.IRInliningJSTranslator);
+
 
 
 smalltalk.addClass('IRSendInliner', smalltalk.Object, ['send', 'translator'], 'Compiler-Inlining');
@@ -324,9 +543,15 @@ selector: "inlineClosure:",
 fn: function (anIRClosure) {
 var self=this;
 var inlinedClosure=nil;
+var sequence=nil;
+var statements=nil;
 (inlinedClosure=smalltalk.send(self, "_inlinedClosure", []));
 smalltalk.send(inlinedClosure, "_scope_", [smalltalk.send(anIRClosure, "_scope", [])]);
-smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(anIRClosure, "_instructions", []), "_first", []), "_instructions", []), "_do_", [(function(each){return smalltalk.send(inlinedClosure, "_add_", [smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [each])]);})]);
+smalltalk.send(smalltalk.send(anIRClosure, "_instructions", []), "_do_", [(function(each){return ((($receiver = smalltalk.send(each, "_isSequence", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(inlinedClosure, "_add_", [each]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(inlinedClosure, "_add_", [each]);})]));})]);
+(sequence=smalltalk.send(self, "_inlinedSequence", []));
+smalltalk.send(inlinedClosure, "_add_", [sequence]);
+(statements=smalltalk.send(smalltalk.send(smalltalk.send(anIRClosure, "_instructions", []), "_last", []), "_instructions", []));
+smalltalk.send(statements, "_ifNotEmpty_", [(function(){smalltalk.send(smalltalk.send(statements, "_allButLast", []), "_do_", [(function(each){return smalltalk.send(sequence, "_add_", [smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [each])]);})]);return ((($receiver = smalltalk.send(smalltalk.send(statements, "_last", []), "_isLocalReturn", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(sequence, "_add_", [smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [smalltalk.send(smalltalk.send(smalltalk.send(statements, "_last", []), "_instructions", []), "_first", [])])]);})() : (function(){return smalltalk.send(sequence, "_add_", [smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [smalltalk.send(statements, "_last", [])])]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(sequence, "_add_", [smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [smalltalk.send(smalltalk.send(smalltalk.send(statements, "_last", []), "_instructions", []), "_first", [])])]);}), (function(){return smalltalk.send(sequence, "_add_", [smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [smalltalk.send(statements, "_last", [])])]);})]));})]);
 return inlinedClosure;
 return self;}
 }),
@@ -355,6 +580,17 @@ return self;}
 }),
 smalltalk.IRSendInliner);
 
+smalltalk.addMethod(
+"_inlinedSequence",
+smalltalk.method({
+selector: "inlinedSequence",
+fn: function () {
+var self=this;
+return smalltalk.send((smalltalk.IRInlinedSequence || IRInlinedSequence), "_new", []);
+return self;}
+}),
+smalltalk.IRSendInliner);
+
 smalltalk.addMethod(
 "_inliningError_",
 smalltalk.method({
@@ -422,6 +658,21 @@ return self;}
 }),
 smalltalk.IRSendInliner.klass);
 
+smalltalk.addMethod(
+"_shouldInline_",
+smalltalk.method({
+selector: "shouldInline:",
+fn: function (anIRInstruction) {
+var self=this;
+var $early={};
+try{((($receiver = smalltalk.send(smalltalk.send(self, "_inlinedSelectors", []), "_includes_", [smalltalk.send(anIRInstruction, "_selector", [])])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return (function(){throw $early=[false]})();})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return (function(){throw $early=[false]})();})]));
+smalltalk.send(smalltalk.send(smalltalk.send(anIRInstruction, "_instructions", []), "_allButFirst", []), "_do_", [(function(each){return ((($receiver = smalltalk.send(each, "_isClosure", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return (function(){throw $early=[false]})();})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return (function(){throw $early=[false]})();})]));})]);
+return true;
+return self;
+} catch(e) {if(e===$early)return e[0]; throw e}}
+}),
+smalltalk.IRSendInliner.klass);
+
 
 smalltalk.addClass('IRAssignmentInliner', smalltalk.IRSendInliner, ['assignment'], 'Compiler-Inlining');
 smalltalk.addMethod(
@@ -464,18 +715,84 @@ return self;}
 smalltalk.IRAssignmentInliner);
 
 smalltalk.addMethod(
-"_inlinedClosure",
+"_inlinedSequence",
 smalltalk.method({
-selector: "inlinedClosure",
+selector: "inlinedSequence",
 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 (function($rec){smalltalk.send($rec, "_assignTo_", [smalltalk.send(smalltalk.send(smalltalk.send(self, "_assignment", []), "_instructions", []), "_first", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRAssigningInlinedSequence || IRAssigningInlinedSequence), "_new", []));
 return self;}
 }),
 smalltalk.IRAssignmentInliner);
 
 
 
+smalltalk.addClass('IRReturnInliner', smalltalk.IRSendInliner, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_inlineReturn_",
+smalltalk.method({
+selector: "inlineReturn:",
+fn: function (anIRReturn) {
+var self=this;
+var return_=nil;
+(return_=smalltalk.send(self, "_inlinedReturn", []));
+smalltalk.send(smalltalk.send(anIRReturn, "_instructions", []), "_do_", [(function(each){return smalltalk.send(return_, "_add_", [each]);})]);
+smalltalk.send(anIRReturn, "_replaceWith_", [return_]);
+smalltalk.send(self, "_inlineSend_", [smalltalk.send(smalltalk.send(return_, "_instructions", []), "_last", [])]);
+return return_;
+return self;}
+}),
+smalltalk.IRReturnInliner);
+
+smalltalk.addMethod(
+"_inlinedReturn",
+smalltalk.method({
+selector: "inlinedReturn",
+fn: function () {
+var self=this;
+return smalltalk.send((smalltalk.IRInlinedReturn || IRInlinedReturn), "_new", []);
+return self;}
+}),
+smalltalk.IRReturnInliner);
+
+smalltalk.addMethod(
+"_inlinedSequence",
+smalltalk.method({
+selector: "inlinedSequence",
+fn: function () {
+var self=this;
+return smalltalk.send((smalltalk.IRReturningInlinedSequence || IRReturningInlinedSequence), "_new", []);
+return self;}
+}),
+smalltalk.IRReturnInliner);
+
+
+
+smalltalk.addClass('IRNonLocalReturnInliner', smalltalk.IRReturnInliner, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_inlinedReturn",
+smalltalk.method({
+selector: "inlinedReturn",
+fn: function () {
+var self=this;
+return smalltalk.send((smalltalk.IRInlinedNonLocalReturn || IRInlinedNonLocalReturn), "_new", []);
+return self;}
+}),
+smalltalk.IRNonLocalReturnInliner);
+
+smalltalk.addMethod(
+"_inlinedSequence",
+smalltalk.method({
+selector: "inlinedSequence",
+fn: function () {
+var self=this;
+return smalltalk.send((smalltalk.IRNonLocalReturningInlinedSequence || IRNonLocalReturningInlinedSequence), "_new", []);
+return self;}
+}),
+smalltalk.IRNonLocalReturnInliner);
+
+
+
 smalltalk.addClass('InliningCodeGenerator', smalltalk.CodeGenerator, [], 'Compiler-Inlining');
 smalltalk.addMethod(
 "_compileNode_",

+ 490 - 48
js/Compiler-Inlining.js

@@ -34,7 +34,7 @@ smalltalk.IRInlinedAssignment);
 
 
 
-smalltalk.addClass('IRInlinedClosure', smalltalk.IRClosure, ['assignTo'], 'Compiler-Inlining');
+smalltalk.addClass('IRInlinedClosure', smalltalk.IRClosure, [], 'Compiler-Inlining');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -52,36 +52,39 @@ referencedClasses: []
 smalltalk.IRInlinedClosure);
 
 smalltalk.addMethod(
-"_assignTo",
+"_isInlined",
 smalltalk.method({
-selector: "assignTo",
-category: 'accessing',
+selector: "isInlined",
+category: 'testing',
 fn: function () {
 var self=this;
-return self['@assignTo'];
+return true;
 return self;},
 args: [],
-source: "assignTo\x0a\x09^ assignTo",
+source: "isInlined\x0a\x09^ true",
 messageSends: [],
 referencedClasses: []
 }),
 smalltalk.IRInlinedClosure);
 
+
+
+smalltalk.addClass('IRInlinedReturn', smalltalk.IRReturn, [], 'Compiler-Inlining');
 smalltalk.addMethod(
-"_assignTo_",
+"_accept_",
 smalltalk.method({
-selector: "assignTo:",
-category: 'accessing',
-fn: function (aScopeVar) {
+selector: "accept:",
+category: 'visiting',
+fn: function (aVisitor) {
 var self=this;
-(self['@assignTo']=aScopeVar);
+return smalltalk.send(aVisitor, "_visitIRInlinedReturn_", [self]);
 return self;},
-args: ["aScopeVar"],
-source: "assignTo: aScopeVar\x0a\x09assignTo := aScopeVar",
-messageSends: [],
+args: ["aVisitor"],
+source: "accept: aVisitor\x0a\x09^ aVisitor visitIRInlinedReturn: self",
+messageSends: ["visitIRInlinedReturn:"],
 referencedClasses: []
 }),
-smalltalk.IRInlinedClosure);
+smalltalk.IRInlinedReturn);
 
 smalltalk.addMethod(
 "_isInlined",
@@ -97,11 +100,11 @@ source: "isInlined\x0a\x09^ true",
 messageSends: [],
 referencedClasses: []
 }),
-smalltalk.IRInlinedClosure);
+smalltalk.IRInlinedReturn);
 
 
 
-smalltalk.addClass('IRInlinedNonLocalReturn', smalltalk.IRReturn, [], 'Compiler-Inlining');
+smalltalk.addClass('IRInlinedNonLocalReturn', smalltalk.IRInlinedReturn, [], 'Compiler-Inlining');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -209,12 +212,136 @@ smalltalk.IRInlinedIfTrue);
 
 
 
+smalltalk.addClass('IRInlinedSequence', smalltalk.IRBlockSequence, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+category: 'visiting',
+fn: function (aVisitor) {
+var self=this;
+smalltalk.send(aVisitor, "_visitIRInlinedSequence_", [self]);
+return self;},
+args: ["aVisitor"],
+source: "accept: aVisitor\x0a\x09aVisitor visitIRInlinedSequence: self",
+messageSends: ["visitIRInlinedSequence:"],
+referencedClasses: []
+}),
+smalltalk.IRInlinedSequence);
+
+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.IRInlinedSequence);
+
+
+
+smalltalk.addClass('IRAssigningInlinedSequence', smalltalk.IRInlinedSequence, ['assignTo'], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+category: 'accessing',
+fn: function (aVisitor) {
+var self=this;
+return smalltalk.send(aVisitor, "_visitIRAssigningInlinedSequence_", [self]);
+return self;},
+args: ["aVisitor"],
+source: "accept: aVisitor\x0a\x09^ aVisitor visitIRAssigningInlinedSequence: self",
+messageSends: ["visitIRAssigningInlinedSequence:"],
+referencedClasses: []
+}),
+smalltalk.IRAssigningInlinedSequence);
+
+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.IRAssigningInlinedSequence);
+
+smalltalk.addMethod(
+"_assignTo_",
+smalltalk.method({
+selector: "assignTo:",
+category: 'accessing',
+fn: function (anIRInstruction) {
+var self=this;
+(self['@assignTo']=anIRInstruction);
+return self;},
+args: ["anIRInstruction"],
+source: "assignTo: anIRInstruction\x0a\x09assignTo := anIRInstruction",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.IRAssigningInlinedSequence);
+
+
+
+smalltalk.addClass('IRReturningInlinedSequence', smalltalk.IRInlinedSequence, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+category: 'visiting',
+fn: function (aVisitor) {
+var self=this;
+return smalltalk.send(aVisitor, "_visitIRReturningInlinedSequence_", [self]);
+return self;},
+args: ["aVisitor"],
+source: "accept: aVisitor\x0a\x09^ aVisitor visitIRReturningInlinedSequence: self",
+messageSends: ["visitIRReturningInlinedSequence:"],
+referencedClasses: []
+}),
+smalltalk.IRReturningInlinedSequence);
+
+
+
+smalltalk.addClass('IRNonLocalReturningInlinedSequence', smalltalk.IRReturningInlinedSequence, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+category: 'visiting',
+fn: function (aVisitor) {
+var self=this;
+return smalltalk.send(aVisitor, "_visitIRNonLocalReturningInlinedSequence_", [self]);
+return self;},
+args: ["aVisitor"],
+source: "accept: aVisitor\x0a\x09^ aVisitor visitIRNonLocalReturningInlinedSequence: self",
+messageSends: ["visitIRNonLocalReturningInlinedSequence:"],
+referencedClasses: []
+}),
+smalltalk.IRNonLocalReturningInlinedSequence);
+
+
+
 smalltalk.addClass('IRInliner', smalltalk.IRVisitor, [], 'Compiler-Inlining');
 smalltalk.addMethod(
 "_assignmentInliner",
 smalltalk.method({
 selector: "assignmentInliner",
-category: 'visiting',
+category: 'factory',
 fn: function () {
 var self=this;
 return (function($rec){smalltalk.send($rec, "_translator_", [self]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRAssignmentInliner || IRAssignmentInliner), "_new", []));
@@ -226,11 +353,43 @@ referencedClasses: ["IRAssignmentInliner"]
 }),
 smalltalk.IRInliner);
 
+smalltalk.addMethod(
+"_nonLocalReturnInliner",
+smalltalk.method({
+selector: "nonLocalReturnInliner",
+category: 'factory',
+fn: function () {
+var self=this;
+return (function($rec){smalltalk.send($rec, "_translator_", [self]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRNonLocalReturnInliner || IRNonLocalReturnInliner), "_new", []));
+return self;},
+args: [],
+source: "nonLocalReturnInliner\x0a\x09^ IRNonLocalReturnInliner new \x0a\x09\x09translator: self;\x0a\x09\x09yourself",
+messageSends: ["translator:", "yourself", "new"],
+referencedClasses: ["IRNonLocalReturnInliner"]
+}),
+smalltalk.IRInliner);
+
+smalltalk.addMethod(
+"_returnInliner",
+smalltalk.method({
+selector: "returnInliner",
+category: 'factory',
+fn: function () {
+var self=this;
+return (function($rec){smalltalk.send($rec, "_translator_", [self]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRReturnInliner || IRReturnInliner), "_new", []));
+return self;},
+args: [],
+source: "returnInliner\x0a\x09^ IRReturnInliner new \x0a\x09\x09translator: self;\x0a\x09\x09yourself",
+messageSends: ["translator:", "yourself", "new"],
+referencedClasses: ["IRReturnInliner"]
+}),
+smalltalk.IRInliner);
+
 smalltalk.addMethod(
 "_sendInliner",
 smalltalk.method({
 selector: "sendInliner",
-category: 'visiting',
+category: 'factory',
 fn: function () {
 var self=this;
 return (function($rec){smalltalk.send($rec, "_translator_", [self]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRSendInliner || IRSendInliner), "_new", []));
@@ -258,6 +417,22 @@ referencedClasses: []
 }),
 smalltalk.IRInliner);
 
+smalltalk.addMethod(
+"_shouldInlineReturn_",
+smalltalk.method({
+selector: "shouldInlineReturn:",
+category: 'testing',
+fn: function (anIRReturn) {
+var self=this;
+return smalltalk.send(smalltalk.send(smalltalk.send(anIRReturn, "_isInlined", []), "_not", []), "_and_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(anIRReturn, "_instructions", []), "_first", []), "_isSend", []), "_and_", [(function(){return smalltalk.send(self, "_shouldInlineSend_", [smalltalk.send(smalltalk.send(anIRReturn, "_instructions", []), "_first", [])]);})]);})]);
+return self;},
+args: ["anIRReturn"],
+source: "shouldInlineReturn: anIRReturn\x0a\x09^ anIRReturn isInlined not and: [ \x0a\x09\x09anIRReturn instructions first isSend and: [\x09\x0a\x09\x09\x09self shouldInlineSend: (anIRReturn instructions first) ]]",
+messageSends: ["and:", "not", "isInlined", "isSend", "first", "instructions", "shouldInlineSend:"],
+referencedClasses: []
+}),
+smalltalk.IRInliner);
+
 smalltalk.addMethod(
 "_shouldInlineSend_",
 smalltalk.method({
@@ -265,15 +440,35 @@ 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 smalltalk.send(smalltalk.send(smalltalk.send(anIRSend, "_isInlined", []), "_not", []), "_and_", [(function(){return smalltalk.send((smalltalk.IRSendInliner || IRSendInliner), "_shouldInline_", [anIRSend]);})]);
 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"],
+source: "shouldInlineSend: anIRSend\x0a\x09^ anIRSend isInlined not and: [\x0a\x09\x09IRSendInliner shouldInline: anIRSend ]",
+messageSends: ["and:", "not", "isInlined", "shouldInline:"],
 referencedClasses: ["IRSendInliner"]
 }),
 smalltalk.IRInliner);
 
+smalltalk.addMethod(
+"_transformNonLocalReturn_",
+smalltalk.method({
+selector: "transformNonLocalReturn:",
+category: 'visiting',
+fn: function (anIRNonLocalReturn) {
+var self=this;
+var $early={};
+try{var localReturn=nil;
+((($receiver = smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_canInlineNonLocalReturns", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_methodScope", []), "_removeNonLocalReturn_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);(localReturn=(function($rec){smalltalk.send($rec, "_scope_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRReturn || IRReturn), "_new", [])));smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_instructions", []), "_do_", [(function(each){return smalltalk.send(localReturn, "_add_", [each]);})]);smalltalk.send(anIRNonLocalReturn, "_replaceWith_", [localReturn]);return (function(){throw $early=[localReturn]})();})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_methodScope", []), "_removeNonLocalReturn_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);(localReturn=(function($rec){smalltalk.send($rec, "_scope_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRReturn || IRReturn), "_new", [])));smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_instructions", []), "_do_", [(function(each){return smalltalk.send(localReturn, "_add_", [each]);})]);smalltalk.send(anIRNonLocalReturn, "_replaceWith_", [localReturn]);return (function(){throw $early=[localReturn]})();})]));
+return smalltalk.send(self, "_visitIRNonLocalReturn_", [anIRNonLocalReturn], smalltalk.IRInliner.superclass || nil);
+return self;
+} catch(e) {if(e===$early)return e[0]; throw e}},
+args: ["anIRNonLocalReturn"],
+source: "transformNonLocalReturn: anIRNonLocalReturn\x0a\x09| localReturn |\x0a\x09anIRNonLocalReturn scope canInlineNonLocalReturns ifTrue: [\x0a\x09\x09anIRNonLocalReturn scope methodScope removeNonLocalReturn: anIRNonLocalReturn scope.\x0a\x09\x09localReturn := IRReturn new\x0a\x09\x09\x09scope: anIRNonLocalReturn scope;\x0a\x09\x09\x09yourself.\x0a\x09\x09anIRNonLocalReturn instructions do: [ :each |\x0a\x09\x09\x09localReturn add: each ].\x0a\x09\x09anIRNonLocalReturn replaceWith: localReturn.\x0a\x09\x09^ localReturn ].\x0a\x09^ super visitIRNonLocalReturn: anIRNonLocalReturn",
+messageSends: ["ifTrue:", "canInlineNonLocalReturns", "scope", "removeNonLocalReturn:", "methodScope", "scope:", "yourself", "new", "do:", "instructions", "add:", "replaceWith:", "visitIRNonLocalReturn:"],
+referencedClasses: ["IRReturn"]
+}),
+smalltalk.IRInliner);
+
 smalltalk.addMethod(
 "_visitIRAssignment_",
 smalltalk.method({
@@ -281,10 +476,10 @@ selector: "visitIRAssignment:",
 category: 'visiting',
 fn: function (anIRAssignment) {
 var self=this;
-((($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 ((($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 ]",
+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: []
 }),
@@ -297,14 +492,28 @@ selector: "visitIRNonLocalReturn:",
 category: 'visiting',
 fn: function (anIRNonLocalReturn) {
 var self=this;
-var localReturn=nil;
-((($receiver = smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_canInlineNonLocalReturns", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_methodScope", []), "_removeNonLocalReturn_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);(localReturn=(function($rec){smalltalk.send($rec, "_scope_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRInlinedNonLocalReturn || IRInlinedNonLocalReturn), "_new", [])));smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_instructions", []), "_do_", [(function(each){return smalltalk.send(localReturn, "_add_", [each]);})]);return smalltalk.send(anIRNonLocalReturn, "_replaceWith_", [localReturn]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_methodScope", []), "_removeNonLocalReturn_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);(localReturn=(function($rec){smalltalk.send($rec, "_scope_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRInlinedNonLocalReturn || IRInlinedNonLocalReturn), "_new", [])));smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_instructions", []), "_do_", [(function(each){return smalltalk.send(localReturn, "_add_", [each]);})]);return smalltalk.send(anIRNonLocalReturn, "_replaceWith_", [localReturn]);})]));
-smalltalk.send(self, "_visitIRNonLocalReturn_", [anIRNonLocalReturn], smalltalk.IRInliner.superclass || nil);
+return ((($receiver = smalltalk.send(self, "_shouldInlineReturn_", [anIRNonLocalReturn])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_nonLocalReturnInliner", []), "_inlineReturn_", [anIRNonLocalReturn]);})() : (function(){return smalltalk.send(self, "_transformNonLocalReturn_", [anIRNonLocalReturn]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_nonLocalReturnInliner", []), "_inlineReturn_", [anIRNonLocalReturn]);}), (function(){return smalltalk.send(self, "_transformNonLocalReturn_", [anIRNonLocalReturn]);})]));
 return self;},
 args: ["anIRNonLocalReturn"],
-source: "visitIRNonLocalReturn: anIRNonLocalReturn\x0a\x09| localReturn |\x0a\x09anIRNonLocalReturn scope canInlineNonLocalReturns ifTrue: [\x0a\x09\x09anIRNonLocalReturn scope methodScope removeNonLocalReturn: anIRNonLocalReturn scope.\x0a\x09\x09localReturn := IRInlinedNonLocalReturn new\x0a\x09\x09\x09scope: anIRNonLocalReturn scope;\x0a\x09\x09\x09yourself.\x0a\x09\x09anIRNonLocalReturn instructions do: [ :each |\x0a\x09\x09\x09localReturn add: each ].\x0a\x09\x09anIRNonLocalReturn replaceWith: localReturn ].\x0a\x09super visitIRNonLocalReturn: anIRNonLocalReturn",
-messageSends: ["ifTrue:", "canInlineNonLocalReturns", "scope", "removeNonLocalReturn:", "methodScope", "scope:", "yourself", "new", "do:", "instructions", "add:", "replaceWith:", "visitIRNonLocalReturn:"],
-referencedClasses: ["IRInlinedNonLocalReturn"]
+source: "visitIRNonLocalReturn: anIRNonLocalReturn\x0a\x09^ (self shouldInlineReturn: anIRNonLocalReturn) \x0a\x09\x09ifTrue: [ self nonLocalReturnInliner inlineReturn: anIRNonLocalReturn ]\x0a\x09\x09ifFalse: [ self transformNonLocalReturn: anIRNonLocalReturn ]",
+messageSends: ["ifTrue:ifFalse:", "shouldInlineReturn:", "inlineReturn:", "nonLocalReturnInliner", "transformNonLocalReturn:"],
+referencedClasses: []
+}),
+smalltalk.IRInliner);
+
+smalltalk.addMethod(
+"_visitIRReturn_",
+smalltalk.method({
+selector: "visitIRReturn:",
+category: 'visiting',
+fn: function (anIRReturn) {
+var self=this;
+return ((($receiver = smalltalk.send(self, "_shouldInlineReturn_", [anIRReturn])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_returnInliner", []), "_inlineReturn_", [anIRReturn]);})() : (function(){return smalltalk.send(self, "_visitIRReturn_", [anIRReturn], smalltalk.IRInliner.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_returnInliner", []), "_inlineReturn_", [anIRReturn]);}), (function(){return smalltalk.send(self, "_visitIRReturn_", [anIRReturn], smalltalk.IRInliner.superclass || nil);})]));
+return self;},
+args: ["anIRReturn"],
+source: "visitIRReturn: anIRReturn\x0a\x09^ (self shouldInlineReturn: anIRReturn) \x0a\x09\x09ifTrue: [ self returnInliner inlineReturn: anIRReturn ]\x0a\x09\x09ifFalse: [ super visitIRReturn: anIRReturn ]",
+messageSends: ["ifTrue:ifFalse:", "shouldInlineReturn:", "inlineReturn:", "returnInliner", "visitIRReturn:"],
+referencedClasses: []
 }),
 smalltalk.IRInliner);
 
@@ -315,10 +524,10 @@ selector: "visitIRSend:",
 category: 'visiting',
 fn: function (anIRSend) {
 var self=this;
-((($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 ((($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 ]",
+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: []
 }),
@@ -327,6 +536,23 @@ smalltalk.IRInliner);
 
 
 smalltalk.addClass('IRInliningJSTranslator', smalltalk.IRJSTranslator, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_visitIRAssigningInlinedSequence_",
+smalltalk.method({
+selector: "visitIRAssigningInlinedSequence:",
+category: 'visiting',
+fn: function (anIRInlinedSequence) {
+var self=this;
+smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutStatementWith_", [(function(){return smalltalk.send(self, "_visit_", [each]);})]);})]);
+smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutStatementWith_", [(function(){return ((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", []), "_canBeAssigned", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){(function($rec){smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedSequence, "_assignTo", []), "_variable", []), "_alias", [])]);return smalltalk.send($rec, "_nextPutAssignment", []);})(smalltalk.send(self, "_stream", []));return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})() : (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){(function($rec){smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedSequence, "_assignTo", []), "_variable", []), "_alias", [])]);return smalltalk.send($rec, "_nextPutAssignment", []);})(smalltalk.send(self, "_stream", []));return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);}), (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})]));})]);
+return self;},
+args: ["anIRInlinedSequence"],
+source: "visitIRAssigningInlinedSequence: anIRInlinedSequence\x0a\x0a\x09anIRInlinedSequence instructions allButLast do: [ :each | \x0a\x09\x09self stream nextPutStatementWith: [ self visit: each ]].\x0a\x0a\x09self stream nextPutStatementWith: [\x0a\x09\x09anIRInlinedSequence instructions last canBeAssigned \x0a\x09\x09\x09ifTrue: [\x0a\x09\x09\x09\x09self stream \x0a\x09\x09\x09\x09\x09nextPutAll: anIRInlinedSequence assignTo variable alias;\x0a                                \x09nextPutAssignment.\x0a\x09\x09\x09\x09self visit: anIRInlinedSequence instructions last ]\x0a\x09\x09\x09ifFalse: [ self visit: anIRInlinedSequence instructions last ]]",
+messageSends: ["do:", "allButLast", "instructions", "nextPutStatementWith:", "stream", "visit:", "ifTrue:ifFalse:", "canBeAssigned", "last", "nextPutAll:", "alias", "variable", "assignTo", "nextPutAssignment"],
+referencedClasses: []
+}),
+smalltalk.IRInliningJSTranslator);
+
 smalltalk.addMethod(
 "_visitIRInlinedAssignment_",
 smalltalk.method({
@@ -350,11 +576,11 @@ selector: "visitIRInlinedClosure:",
 category: 'visiting',
 fn: function (anIRInlinedClosure) {
 var self=this;
-smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_ifNotEmpty_", [(function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_assignTo", []), "_notNil", []), "_and_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_last", []), "_canBeAssigned", []);})])).klass === smalltalk.Boolean) ? ($receiver ? (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($receiver, "_ifTrue_", [(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", []);})]));return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_last", [])]);})]);
+smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);
 return self;},
 args: ["anIRInlinedClosure"],
-source: "visitIRInlinedClosure: anIRInlinedClosure\x0a\x09anIRInlinedClosure instructions ifNotEmpty: [\x0a\x09\x09anIRInlinedClosure instructions allButLast do: [ :each | self visit: each ].\x0a\x09\x09(anIRInlinedClosure assignTo notNil and: [\x0a\x09\x09\x09anIRInlinedClosure instructions last canBeAssigned ]) ifTrue: [\x0a\x09\x09\x09\x09self stream nextPutAll: anIRInlinedClosure assignTo variable alias.\x0a\x09\x09\x09\x09self stream nextPutAssignment ].\x0a\x09\x09self visit: anIRInlinedClosure instructions last ]",
-messageSends: ["ifNotEmpty:", "instructions", "do:", "allButLast", "visit:", "ifTrue:", "and:", "notNil", "assignTo", "canBeAssigned", "last", "nextPutAll:", "stream", "alias", "variable", "nextPutAssignment"],
+source: "visitIRInlinedClosure: anIRInlinedClosure\x0a\x09anIRInlinedClosure instructions do: [ :each |\x0a\x09\x09self visit: each ]",
+messageSends: ["do:", "instructions", "visit:"],
 referencedClasses: []
 }),
 smalltalk.IRInliningJSTranslator);
@@ -369,7 +595,7 @@ var self=this;
 smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutIf_with_", [(function(){smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAll_", ["! smalltalk.assert("]);smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedIfFalse, "_instructions", []), "_first", [])]);return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAll_", [")"]);}), (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedIfFalse, "_instructions", []), "_last", [])]);})]);
 return self;},
 args: ["anIRInlinedIfFalse"],
-source: "visitIRInlinedIfFalse: anIRInlinedIfFalse\x0a\x09self stream \x0a\x09\x09nextPutIf: [ \x0a\x09\x09\x09self stream nextPutAll: '! smalltalk.assert('.\x0a\x09\x09\x09self visit: anIRInlinedIfFalse instructions first.\x0a\x09\x09\x09self stream nextPutAll: ')' ]\x0a\x09\x09with: [ self visit: anIRInlinedIfFalse instructions last ]",
+source: "visitIRInlinedIfFalse: anIRInlinedIfFalse\x0a\x09self stream nextPutIf: [ \x0a\x09\x09self stream nextPutAll: '! smalltalk.assert('.\x0a\x09\x09self visit: anIRInlinedIfFalse instructions first.\x0a\x09\x09self stream nextPutAll: ')' ]\x0a\x09\x09with: [ self visit: anIRInlinedIfFalse instructions last ]",
 messageSends: ["nextPutIf:with:", "stream", "nextPutAll:", "visit:", "first", "instructions", "last"],
 referencedClasses: []
 }),
@@ -385,12 +611,95 @@ var self=this;
 smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutIf_with_", [(function(){smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAll_", ["smalltalk.assert("]);smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedIfTrue, "_instructions", []), "_first", [])]);return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAll_", [")"]);}), (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: [ \x0a\x09\x09\x09self stream nextPutAll: 'smalltalk.assert('. \x0a\x09\x09\x09self visit: anIRInlinedIfTrue instructions first.\x0a\x09\x09\x09self stream nextPutAll: ')' ]\x0a\x09\x09with: [ self visit: anIRInlinedIfTrue instructions last ]",
+source: "visitIRInlinedIfTrue: anIRInlinedIfTrue\x0a\x09self stream nextPutIf: [ \x0a\x09\x09self stream nextPutAll: 'smalltalk.assert('. \x0a\x09\x09self visit: anIRInlinedIfTrue instructions first.\x0a\x09\x09self stream nextPutAll: ')' ]\x0a\x09\x09with: [ self visit: anIRInlinedIfTrue instructions last ]",
 messageSends: ["nextPutIf:with:", "stream", "nextPutAll:", "visit:", "first", "instructions", "last"],
 referencedClasses: []
 }),
 smalltalk.IRInliningJSTranslator);
 
+smalltalk.addMethod(
+"_visitIRInlinedNonLocalReturn_",
+smalltalk.method({
+selector: "visitIRInlinedNonLocalReturn:",
+category: 'visiting',
+fn: function (anIRInlinedReturn) {
+var self=this;
+smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutStatementWith_", [(function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedReturn, "_instructions", []), "_last", [])]);})]);
+smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutNonLocalReturnWith_", [(function(){return nil;})]);
+return self;},
+args: ["anIRInlinedReturn"],
+source: "visitIRInlinedNonLocalReturn: anIRInlinedReturn\x0a\x09self stream nextPutStatementWith: [\x0a\x09\x09self visit: anIRInlinedReturn instructions last ].\x0a\x09self stream nextPutNonLocalReturnWith: [ ]",
+messageSends: ["nextPutStatementWith:", "stream", "visit:", "last", "instructions", "nextPutNonLocalReturnWith:"],
+referencedClasses: []
+}),
+smalltalk.IRInliningJSTranslator);
+
+smalltalk.addMethod(
+"_visitIRInlinedReturn_",
+smalltalk.method({
+selector: "visitIRInlinedReturn:",
+category: 'visiting',
+fn: function (anIRInlinedReturn) {
+var self=this;
+smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedReturn, "_instructions", []), "_last", [])]);
+return self;},
+args: ["anIRInlinedReturn"],
+source: "visitIRInlinedReturn: anIRInlinedReturn\x0a\x09self visit: anIRInlinedReturn instructions last",
+messageSends: ["visit:", "last", "instructions"],
+referencedClasses: []
+}),
+smalltalk.IRInliningJSTranslator);
+
+smalltalk.addMethod(
+"_visitIRInlinedSequence_",
+smalltalk.method({
+selector: "visitIRInlinedSequence:",
+category: 'visiting',
+fn: function (anIRInlinedSequence) {
+var self=this;
+smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_do_", [(function(each){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutStatementWith_", [(function(){return smalltalk.send(self, "_visit_", [each]);})]);})]);
+return self;},
+args: ["anIRInlinedSequence"],
+source: "visitIRInlinedSequence: anIRInlinedSequence\x0a\x09anIRInlinedSequence instructions do: [ :each | \x0a\x09\x09self stream nextPutStatementWith: [ self visit: each ]]",
+messageSends: ["do:", "instructions", "nextPutStatementWith:", "stream", "visit:"],
+referencedClasses: []
+}),
+smalltalk.IRInliningJSTranslator);
+
+smalltalk.addMethod(
+"_visitIRNonLocalReturningInlinedSequence_",
+smalltalk.method({
+selector: "visitIRNonLocalReturningInlinedSequence:",
+category: 'visiting',
+fn: function (anIRInlinedSequence) {
+var self=this;
+smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutStatementWith_", [(function(){return smalltalk.send(self, "_visit_", [each]);})]);})]);
+smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutStatementWith_", [(function(){return ((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", []), "_canBeAssigned", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutNonLocalReturnWith_", [(function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})]);})() : (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutNonLocalReturnWith_", [(function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})]);}), (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})]));})]);
+return self;},
+args: ["anIRInlinedSequence"],
+source: "visitIRNonLocalReturningInlinedSequence: anIRInlinedSequence\x0a\x0a\x09anIRInlinedSequence instructions allButLast do: [ :each | \x0a\x09\x09self stream nextPutStatementWith: [ self visit: each ]].\x0a\x0a\x09self stream nextPutStatementWith: [\x0a\x09\x09anIRInlinedSequence instructions last canBeAssigned \x0a\x09\x09\x09ifTrue: [\x0a\x09\x09\x09\x09self stream nextPutNonLocalReturnWith: [\x0a\x09\x09\x09\x09\x09self visit: anIRInlinedSequence instructions last ]]\x0a\x09\x09\x09ifFalse: [ self visit: anIRInlinedSequence instructions last ]]",
+messageSends: ["do:", "allButLast", "instructions", "nextPutStatementWith:", "stream", "visit:", "ifTrue:ifFalse:", "canBeAssigned", "last", "nextPutNonLocalReturnWith:"],
+referencedClasses: []
+}),
+smalltalk.IRInliningJSTranslator);
+
+smalltalk.addMethod(
+"_visitIRReturningInlinedSequence_",
+smalltalk.method({
+selector: "visitIRReturningInlinedSequence:",
+category: 'visiting',
+fn: function (anIRInlinedSequence) {
+var self=this;
+smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutStatementWith_", [(function(){return smalltalk.send(self, "_visit_", [each]);})]);})]);
+smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutStatementWith_", [(function(){return ((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", []), "_canBeAssigned", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutReturn", []);return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})() : (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutReturn", []);return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);}), (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedSequence, "_instructions", []), "_last", [])]);})]));})]);
+return self;},
+args: ["anIRInlinedSequence"],
+source: "visitIRReturningInlinedSequence: anIRInlinedSequence\x0a\x0a\x09anIRInlinedSequence instructions allButLast do: [ :each | \x0a\x09\x09self stream nextPutStatementWith: [ self visit: each ]].\x0a\x0a\x09self stream nextPutStatementWith: [\x0a\x09\x09anIRInlinedSequence instructions last canBeAssigned \x0a\x09\x09\x09ifTrue: [\x0a\x09\x09\x09\x09self stream nextPutReturn.\x0a\x09\x09\x09\x09self visit: anIRInlinedSequence instructions last ]\x0a\x09\x09\x09ifFalse: [ self visit: anIRInlinedSequence instructions last ]]",
+messageSends: ["do:", "allButLast", "instructions", "nextPutStatementWith:", "stream", "visit:", "ifTrue:ifFalse:", "canBeAssigned", "last", "nextPutReturn"],
+referencedClasses: []
+}),
+smalltalk.IRInliningJSTranslator);
+
 
 
 smalltalk.addClass('IRSendInliner', smalltalk.Object, ['send', 'translator'], 'Compiler-Inlining');
@@ -451,14 +760,20 @@ category: 'inlining',
 fn: function (anIRClosure) {
 var self=this;
 var inlinedClosure=nil;
+var sequence=nil;
+var statements=nil;
 (inlinedClosure=smalltalk.send(self, "_inlinedClosure", []));
 smalltalk.send(inlinedClosure, "_scope_", [smalltalk.send(anIRClosure, "_scope", [])]);
-smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(anIRClosure, "_instructions", []), "_first", []), "_instructions", []), "_do_", [(function(each){return smalltalk.send(inlinedClosure, "_add_", [smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [each])]);})]);
+smalltalk.send(smalltalk.send(anIRClosure, "_instructions", []), "_do_", [(function(each){return ((($receiver = smalltalk.send(each, "_isSequence", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(inlinedClosure, "_add_", [each]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(inlinedClosure, "_add_", [each]);})]));})]);
+(sequence=smalltalk.send(self, "_inlinedSequence", []));
+smalltalk.send(inlinedClosure, "_add_", [sequence]);
+(statements=smalltalk.send(smalltalk.send(smalltalk.send(anIRClosure, "_instructions", []), "_last", []), "_instructions", []));
+smalltalk.send(statements, "_ifNotEmpty_", [(function(){smalltalk.send(smalltalk.send(statements, "_allButLast", []), "_do_", [(function(each){return smalltalk.send(sequence, "_add_", [smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [each])]);})]);return ((($receiver = smalltalk.send(smalltalk.send(statements, "_last", []), "_isLocalReturn", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(sequence, "_add_", [smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [smalltalk.send(smalltalk.send(smalltalk.send(statements, "_last", []), "_instructions", []), "_first", [])])]);})() : (function(){return smalltalk.send(sequence, "_add_", [smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [smalltalk.send(statements, "_last", [])])]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(sequence, "_add_", [smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [smalltalk.send(smalltalk.send(smalltalk.send(statements, "_last", []), "_instructions", []), "_first", [])])]);}), (function(){return smalltalk.send(sequence, "_add_", [smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [smalltalk.send(statements, "_last", [])])]);})]));})]);
 return inlinedClosure;
 return self;},
 args: ["anIRClosure"],
-source: "inlineClosure: anIRClosure\x0a\x09| inlinedClosure |\x0a\x09inlinedClosure := self inlinedClosure.\x0a\x09inlinedClosure scope: anIRClosure scope.\x0a\x09anIRClosure instructions first instructions do: [ :each |\x0a\x09\x09inlinedClosure add: (self translator visit: each) ].\x0a\x09^ inlinedClosure",
-messageSends: ["inlinedClosure", "scope:", "scope", "do:", "instructions", "first", "add:", "visit:", "translator"],
+source: "inlineClosure: anIRClosure\x0a\x09| inlinedClosure sequence statements |\x0a\x09inlinedClosure := self inlinedClosure.\x0a\x09inlinedClosure scope: anIRClosure scope.\x0a\x0a\x09\x22Add the possible temp declarations\x22\x0a\x09anIRClosure instructions do: [ :each | \x0a\x09\x09each isSequence ifFalse: [\x0a\x09\x09\x09inlinedClosure add: each ]].\x0a\x0a\x09\x22Add a block sequence\x22\x0a\x09sequence := self inlinedSequence.\x0a\x09inlinedClosure add: sequence.\x0a\x0a\x09\x22Get all the statements\x22\x0a\x09statements := anIRClosure instructions last instructions.\x0a\x09\x0a\x09statements ifNotEmpty: [\x0a\x09\x09statements allButLast do: [ :each | sequence add: (self translator visit: each) ].\x0a\x09\x09\x22Inlined closures don't have implicit local returns\x22\x0a\x09\x09statements last isLocalReturn \x0a\x09\x09\x09ifTrue: [ sequence add: (self translator visit: statements last instructions first) ]\x0a\x09\x09\x09ifFalse: [ sequence add: (self translator visit: statements last) ]].\x0a\x0a\x09^ inlinedClosure",
+messageSends: ["inlinedClosure", "scope:", "scope", "do:", "instructions", "ifFalse:", "isSequence", "add:", "inlinedSequence", "last", "ifNotEmpty:", "allButLast", "visit:", "translator", "ifTrue:ifFalse:", "isLocalReturn", "first"],
 referencedClasses: []
 }),
 smalltalk.IRSendInliner);
@@ -484,7 +799,7 @@ smalltalk.addMethod(
 "_inlinedClosure",
 smalltalk.method({
 selector: "inlinedClosure",
-category: 'accessing',
+category: 'factory',
 fn: function () {
 var self=this;
 return smalltalk.send((smalltalk.IRInlinedClosure || IRInlinedClosure), "_new", []);
@@ -496,6 +811,22 @@ referencedClasses: ["IRInlinedClosure"]
 }),
 smalltalk.IRSendInliner);
 
+smalltalk.addMethod(
+"_inlinedSequence",
+smalltalk.method({
+selector: "inlinedSequence",
+category: 'factory',
+fn: function () {
+var self=this;
+return smalltalk.send((smalltalk.IRInlinedSequence || IRInlinedSequence), "_new", []);
+return self;},
+args: [],
+source: "inlinedSequence\x0a\x09^ IRInlinedSequence new",
+messageSends: ["new"],
+referencedClasses: ["IRInlinedSequence"]
+}),
+smalltalk.IRSendInliner);
+
 smalltalk.addMethod(
 "_inliningError_",
 smalltalk.method({
@@ -593,6 +924,26 @@ referencedClasses: []
 }),
 smalltalk.IRSendInliner.klass);
 
+smalltalk.addMethod(
+"_shouldInline_",
+smalltalk.method({
+selector: "shouldInline:",
+category: 'accessing',
+fn: function (anIRInstruction) {
+var self=this;
+var $early={};
+try{((($receiver = smalltalk.send(smalltalk.send(self, "_inlinedSelectors", []), "_includes_", [smalltalk.send(anIRInstruction, "_selector", [])])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return (function(){throw $early=[false]})();})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return (function(){throw $early=[false]})();})]));
+smalltalk.send(smalltalk.send(smalltalk.send(anIRInstruction, "_instructions", []), "_allButFirst", []), "_do_", [(function(each){return ((($receiver = smalltalk.send(each, "_isClosure", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return (function(){throw $early=[false]})();})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return (function(){throw $early=[false]})();})]));})]);
+return true;
+return self;
+} catch(e) {if(e===$early)return e[0]; throw e}},
+args: ["anIRInstruction"],
+source: "shouldInline: anIRInstruction\x0a\x09(self inlinedSelectors includes: anIRInstruction selector) ifFalse: [ ^ false ].\x0a\x09anIRInstruction instructions allButFirst do: [ :each |\x0a\x09\x09each isClosure ifFalse: [ ^ false ]].\x0a\x09^ true",
+messageSends: ["ifFalse:", "includes:", "inlinedSelectors", "selector", "do:", "allButFirst", "instructions", "isClosure"],
+referencedClasses: []
+}),
+smalltalk.IRSendInliner.klass);
+
 
 smalltalk.addClass('IRAssignmentInliner', smalltalk.IRSendInliner, ['assignment'], 'Compiler-Inlining');
 smalltalk.addMethod(
@@ -650,23 +1001,114 @@ referencedClasses: ["IRInlinedAssignment"]
 smalltalk.IRAssignmentInliner);
 
 smalltalk.addMethod(
-"_inlinedClosure",
+"_inlinedSequence",
 smalltalk.method({
-selector: "inlinedClosure",
-category: 'accessing',
+selector: "inlinedSequence",
+category: 'factory',
 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 (function($rec){smalltalk.send($rec, "_assignTo_", [smalltalk.send(smalltalk.send(smalltalk.send(self, "_assignment", []), "_instructions", []), "_first", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRAssigningInlinedSequence || IRAssigningInlinedSequence), "_new", []));
 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: []
+source: "inlinedSequence\x0a\x09^ IRAssigningInlinedSequence new\x0a\x09\x09assignTo: self assignment instructions first;\x0a\x09\x09yourself",
+messageSends: ["assignTo:", "first", "instructions", "assignment", "yourself", "new"],
+referencedClasses: ["IRAssigningInlinedSequence"]
 }),
 smalltalk.IRAssignmentInliner);
 
 
 
+smalltalk.addClass('IRReturnInliner', smalltalk.IRSendInliner, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_inlineReturn_",
+smalltalk.method({
+selector: "inlineReturn:",
+category: 'inlining',
+fn: function (anIRReturn) {
+var self=this;
+var return_=nil;
+(return_=smalltalk.send(self, "_inlinedReturn", []));
+smalltalk.send(smalltalk.send(anIRReturn, "_instructions", []), "_do_", [(function(each){return smalltalk.send(return_, "_add_", [each]);})]);
+smalltalk.send(anIRReturn, "_replaceWith_", [return_]);
+smalltalk.send(self, "_inlineSend_", [smalltalk.send(smalltalk.send(return_, "_instructions", []), "_last", [])]);
+return return_;
+return self;},
+args: ["anIRReturn"],
+source: "inlineReturn: anIRReturn\x0a\x09| return |\x0a\x09return := self inlinedReturn.\x0a\x09anIRReturn instructions do: [ :each |\x0a\x09\x09return add: each ].\x0a\x09anIRReturn replaceWith: return.\x0a\x09self inlineSend: return instructions last.\x0a\x09^ return",
+messageSends: ["inlinedReturn", "do:", "instructions", "add:", "replaceWith:", "inlineSend:", "last"],
+referencedClasses: []
+}),
+smalltalk.IRReturnInliner);
+
+smalltalk.addMethod(
+"_inlinedReturn",
+smalltalk.method({
+selector: "inlinedReturn",
+category: 'factory',
+fn: function () {
+var self=this;
+return smalltalk.send((smalltalk.IRInlinedReturn || IRInlinedReturn), "_new", []);
+return self;},
+args: [],
+source: "inlinedReturn\x0a\x09^ IRInlinedReturn new",
+messageSends: ["new"],
+referencedClasses: ["IRInlinedReturn"]
+}),
+smalltalk.IRReturnInliner);
+
+smalltalk.addMethod(
+"_inlinedSequence",
+smalltalk.method({
+selector: "inlinedSequence",
+category: 'factory',
+fn: function () {
+var self=this;
+return smalltalk.send((smalltalk.IRReturningInlinedSequence || IRReturningInlinedSequence), "_new", []);
+return self;},
+args: [],
+source: "inlinedSequence\x0a\x09^ IRReturningInlinedSequence new",
+messageSends: ["new"],
+referencedClasses: ["IRReturningInlinedSequence"]
+}),
+smalltalk.IRReturnInliner);
+
+
+
+smalltalk.addClass('IRNonLocalReturnInliner', smalltalk.IRReturnInliner, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_inlinedReturn",
+smalltalk.method({
+selector: "inlinedReturn",
+category: 'factory',
+fn: function () {
+var self=this;
+return smalltalk.send((smalltalk.IRInlinedNonLocalReturn || IRInlinedNonLocalReturn), "_new", []);
+return self;},
+args: [],
+source: "inlinedReturn\x0a\x09^ IRInlinedNonLocalReturn new",
+messageSends: ["new"],
+referencedClasses: ["IRInlinedNonLocalReturn"]
+}),
+smalltalk.IRNonLocalReturnInliner);
+
+smalltalk.addMethod(
+"_inlinedSequence",
+smalltalk.method({
+selector: "inlinedSequence",
+category: 'factory',
+fn: function () {
+var self=this;
+return smalltalk.send((smalltalk.IRNonLocalReturningInlinedSequence || IRNonLocalReturningInlinedSequence), "_new", []);
+return self;},
+args: [],
+source: "inlinedSequence\x0a\x09^ IRNonLocalReturningInlinedSequence new",
+messageSends: ["new"],
+referencedClasses: ["IRNonLocalReturningInlinedSequence"]
+}),
+smalltalk.IRNonLocalReturnInliner);
+
+
+
 smalltalk.addClass('InliningCodeGenerator', smalltalk.CodeGenerator, [], 'Compiler-Inlining');
 smalltalk.addMethod(
 "_compileNode_",

+ 4 - 3
js/Compiler-Semantic.deploy.js

@@ -947,9 +947,10 @@ smalltalk.method({
 selector: "visitSendNode:",
 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", []), "_at_ifPresent_ifAbsent_", [smalltalk.send(aNode, "_selector", []), (function(){return smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_put_", [smalltalk.send(aNode, "_selector", []), ((($receiver = smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_", [smalltalk.send(aNode, "_selector", [])])).klass === smalltalk.Number) ? $receiver +(1) : smalltalk.send($receiver, "__plus", [(1)]))]);}), (function(){return smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_put_", [smalltalk.send(aNode, "_selector", []), (1)]);})]);
-smalltalk.send(aNode, "_index_", [smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_", [smalltalk.send(aNode, "_selector", [])])]);
+((($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"]);})() : (function(){return ((($receiver = smalltalk.send(smalltalk.send((smalltalk.IRSendInliner || IRSendInliner), "_inlinedSelectors", []), "_includes_", [smalltalk.send(aNode, "_selector", [])])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(aNode, "_shouldBeInlined_", [true]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(aNode, "_shouldBeInlined_", [true]);})]));})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){smalltalk.send(aNode, "_superSend_", [true]);return smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value_", ["self"]);}), (function(){return ((($receiver = smalltalk.send(smalltalk.send((smalltalk.IRSendInliner || IRSendInliner), "_inlinedSelectors", []), "_includes_", [smalltalk.send(aNode, "_selector", [])])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(aNode, "_shouldBeInlined_", [true]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(aNode, "_shouldBeInlined_", [true]);})]));})]));
+smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_ifAbsentPut_", [smalltalk.send(aNode, "_selector", []), (function(){return smalltalk.send((smalltalk.Set || Set), "_new", []);})]);
+smalltalk.send(smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_", [smalltalk.send(aNode, "_selector", [])]), "_add_", [aNode]);
+smalltalk.send(aNode, "_index_", [smalltalk.send(smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_", [smalltalk.send(aNode, "_selector", [])]), "_size", [])]);
 smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 return self;}
 }),

+ 7 - 6
js/Compiler-Semantic.js

@@ -1354,15 +1354,16 @@ selector: "visitSendNode:",
 category: 'visiting',
 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", []), "_at_ifPresent_ifAbsent_", [smalltalk.send(aNode, "_selector", []), (function(){return smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_put_", [smalltalk.send(aNode, "_selector", []), ((($receiver = smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_", [smalltalk.send(aNode, "_selector", [])])).klass === smalltalk.Number) ? $receiver +(1) : smalltalk.send($receiver, "__plus", [(1)]))]);}), (function(){return smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_put_", [smalltalk.send(aNode, "_selector", []), (1)]);})]);
-smalltalk.send(aNode, "_index_", [smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_", [smalltalk.send(aNode, "_selector", [])])]);
+((($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"]);})() : (function(){return ((($receiver = smalltalk.send(smalltalk.send((smalltalk.IRSendInliner || IRSendInliner), "_inlinedSelectors", []), "_includes_", [smalltalk.send(aNode, "_selector", [])])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(aNode, "_shouldBeInlined_", [true]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(aNode, "_shouldBeInlined_", [true]);})]));})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){smalltalk.send(aNode, "_superSend_", [true]);return smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value_", ["self"]);}), (function(){return ((($receiver = smalltalk.send(smalltalk.send((smalltalk.IRSendInliner || IRSendInliner), "_inlinedSelectors", []), "_includes_", [smalltalk.send(aNode, "_selector", [])])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(aNode, "_shouldBeInlined_", [true]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(aNode, "_shouldBeInlined_", [true]);})]));})]));
+smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_ifAbsentPut_", [smalltalk.send(aNode, "_selector", []), (function(){return smalltalk.send((smalltalk.Set || Set), "_new", []);})]);
+smalltalk.send(smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_", [smalltalk.send(aNode, "_selector", [])]), "_add_", [aNode]);
+smalltalk.send(aNode, "_index_", [smalltalk.send(smalltalk.send(smalltalk.send(self, "_messageSends", []), "_at_", [smalltalk.send(aNode, "_selector", [])]), "_size", [])]);
 smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.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 \x0a\x09\x09at: aNode selector\x0a\x09\x09ifPresent: [ self messageSends at: aNode selector put: (self messageSends at: aNode selector) + 1 ]\x0a\x09\x09ifAbsent: [ self messageSends at: aNode selector put: 1 ].\x0a\x0a\x09aNode index: (self messageSends at: aNode selector).\x0a\x0a\x09super visitSendNode: aNode",
-messageSends: ["ifTrue:", "=", "value", "receiver", "superSend:", "value:", "at:ifPresent:ifAbsent:", "messageSends", "selector", "at:put:", "+", "at:", "index:", "visitSendNode:"],
-referencedClasses: []
+source: "visitSendNode: aNode\x0a\x0a\x09aNode receiver value = 'super' \x0a\x09\x09ifTrue: [\x0a\x09\x09\x09aNode superSend: true.\x0a\x09\x09\x09aNode receiver value: 'self' ]\x0a\x09\x09ifFalse: [ (IRSendInliner inlinedSelectors includes: aNode selector) ifTrue: [\x0a\x09\x09\x09aNode shouldBeInlined: true ]].\x0a\x0a\x09self messageSends at: aNode selector ifAbsentPut: [ Set new ].\x0a\x09(self messageSends at: aNode selector) add: aNode.\x0a\x0a\x09aNode index: (self messageSends at: aNode selector) size.\x0a\x0a\x09super visitSendNode: aNode",
+messageSends: ["ifTrue:ifFalse:", "=", "value", "receiver", "superSend:", "value:", "ifTrue:", "includes:", "inlinedSelectors", "selector", "shouldBeInlined:", "at:ifAbsentPut:", "messageSends", "new", "add:", "at:", "index:", "size", "visitSendNode:"],
+referencedClasses: ["IRSendInliner", "Set"]
 }),
 smalltalk.SemanticAnalyzer);
 

+ 17 - 1
st/Compiler-AST.st

@@ -1,6 +1,6 @@
 Smalltalk current createPackage: 'Compiler-AST' properties: #{}!
 Object subclass: #Node
-	instanceVariableNames: 'nodes'
+	instanceVariableNames: 'nodes shouldBeInlined'
 	package: 'Compiler-AST'!
 !Node commentStamp!
 I am the abstract root class of the abstract syntax tree.!
@@ -13,6 +13,14 @@ addNode: aNode
 
 nodes
 	^nodes ifNil: [nodes := Array new]
+!
+
+shouldBeInlined
+	^ shouldBeInlined ifNil: [ false ]
+!
+
+shouldBeInlined: aBoolean
+	shouldBeInlined := aBoolean
 ! !
 
 !Node methodsFor: 'building'!
@@ -35,6 +43,10 @@ isBlockSequenceNode
 	^false
 !
 
+isReturnNode
+	^false
+!
+
 isSendNode
 	^false
 !
@@ -257,6 +269,10 @@ scope: aLexicalScope
 
 !ReturnNode methodsFor: 'testing'!
 
+isReturnNode
+	^ true
+!
+
 nonLocalReturn
 	^ self scope isMethodScope not
 ! !

+ 66 - 100
st/Compiler-IR.st

@@ -63,7 +63,7 @@ alias: aNode
 		variable: (AliasVar new name: '$', self nextAlias); 
 		yourself.
 
-	self sequence add: (IRAlias new
+	self sequence add: (IRAssignment new
 		add: variable;
 		add: (self visit: aNode);
 		yourself).
@@ -74,9 +74,20 @@ alias: aNode
 !
 
 visitAssignmentNode: aNode
+	| left right assignment |
+	right := self visit: aNode right.
+	left := self visit: aNode left.
+	self sequence add: (IRAssignment new 
+		add: left;
+		add: right;
+		yourself).
+	^ left
+!
+
+visitAssignmentNode: aNode aliasing: aBoolean
 	| left right |
 	
-	aNode right isAssignmentNode 
+	aBoolean 
 		ifTrue: [ | assignment |
 			assignment := self visit: aNode right.
 			self sequence add: assignment.
@@ -108,8 +119,13 @@ visitBlockNode: aNode
 visitBlockSequenceNode: aNode
 	^ self
 		withSequence: IRBlockSequence new
-		do: [ aNode nodes do: [ :each | 
-			self sequence add: (self visit: each) ]]
+		do: [ 
+			aNode nodes ifNotEmpty: [
+				aNode nodes allButLast do: [ :each | 
+					self sequence add: (self visit: each) ].
+				aNode nodes last isReturnNode 
+					ifFalse: [ self sequence add: (IRReturn new add: (self visit: aNode nodes last); yourself) ]
+					ifTrue: [ self sequence add: (self visit: aNode nodes last) ]]]
 !
 
 visitCascadeNode: aNode
@@ -164,7 +180,8 @@ visitReturnNode: aNode
 		ifTrue: [ IRNonLocalReturn new ]
 		ifFalse: [ IRReturn new ].
 	return scope: aNode scope.
-	aNode nodes do: [ :each | return add: (self visit: each) ].
+	aNode nodes do: [ :each |
+		return add: (self visit: each) ].
 	^ return
 !
 
@@ -177,7 +194,10 @@ visitSendNode: aNode
 	aNode superSend ifTrue: [ send classSend: self theClass superclass ].
 
 	receiver := self visit: aNode receiver.
-	arguments := aNode arguments collect: [ :each | self visit: each ].
+	arguments := aNode arguments collect: [ :each | 
+		each shouldBeInlined
+			ifTrue: [ self alias: each ]
+			ifFalse: [ self visit: each ]].
 
 	send add: receiver.
 	arguments do: [ :each | send add: each ].
@@ -268,6 +288,10 @@ isInlined
 	^ false
 !
 
+isLocalReturn
+	^ false
+!
+
 isReturn
 	^ false
 !
@@ -276,6 +300,14 @@ isSend
 	^ false
 !
 
+isSequence
+	^ false
+!
+
+isTempDeclaration
+	^ false
+!
+
 isVariable
 	^ false
 ! !
@@ -304,16 +336,6 @@ accept: aVisitor
 	^ aVisitor visitIRAssignment: self
 ! !
 
-IRAssignment subclass: #IRAlias
-	instanceVariableNames: ''
-	package: 'Compiler-IR'!
-
-!IRAlias methodsFor: 'visiting'!
-
-accept: aVisitor
-	^ aVisitor visitIRAlias: self
-! !
-
 IRInstruction subclass: #IRScopedInstruction
 	instanceVariableNames: 'scope'
 	package: 'Compiler-IR'!
@@ -345,6 +367,10 @@ arguments: aCollection
 scope: aScope
 	super scope: aScope.
 	aScope instruction: self
+!
+
+sequence
+	^ self instructions last
 ! !
 
 !IRClosure methodsFor: 'testing'!
@@ -434,6 +460,14 @@ canBeAssigned
 	^ false
 !
 
+isLocalReturn
+	^ self isReturn
+!
+
+isNonLocalReturn
+	^ self isLocalReturn not
+!
+
 isReturn
 	^ true
 ! !
@@ -453,6 +487,12 @@ Non local returns are handled using a try/catch JS statement.
 
 See IRNonLocalReturnHandling class!
 
+!IRNonLocalReturn methodsFor: 'testing'!
+
+isLocalReturn
+	^ false
+! !
+
 !IRNonLocalReturn methodsFor: 'visiting'!
 
 accept: aVisitor
@@ -507,14 +547,10 @@ IRInstruction subclass: #IRSequence
 	instanceVariableNames: ''
 	package: 'Compiler-IR'!
 
-!IRSequence methodsFor: 'adding'!
+!IRSequence methodsFor: 'testing'!
 
-add: anIRInstruction
-	| statement |
-	statement := IRStatement new.
-	statement add: anIRInstruction.
-	self instructions add: statement.
-	^ anIRInstruction
+isSequence
+	^ true
 ! !
 
 !IRSequence methodsFor: 'visiting'!
@@ -533,29 +569,6 @@ accept: aVisitor
 	^ aVisitor visitIRBlockSequence: self
 ! !
 
-IRInstruction subclass: #IRStatement
-	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: 'testing'!
-
-canBeAssigned
-	^ self instructions first canBeAssigned
-!
-
-isReturn
-	^ self instructions first isReturn
-! !
-
-!IRStatement methodsFor: 'visiting'!
-
-accept: aVisitor
-	^ aVisitor visitIRStatement: self
-! !
-
 IRInstruction subclass: #IRTempDeclaration
 	instanceVariableNames: 'name'
 	package: 'Compiler-IR'!
@@ -576,6 +589,10 @@ name: aString
 
 accept: aVisitor
 	^ aVisitor visitIRTempDeclaration: self
+!
+
+isTempDeclaration
+	^ true
 ! !
 
 IRInstruction subclass: #IRValue
@@ -658,10 +675,6 @@ visit: anIRInstruction
 	^ anIRInstruction accept: self
 !
 
-visitIRAlias: anIRAlias
-	^ self visitIRAssignment: anIRAlias
-!
-
 visitIRAssignment: anIRAssignment
 	^ self visitIRInstruction: anIRAssignment
 !
@@ -674,30 +687,6 @@ visitIRClosure: anIRClosure
 	^ self visitIRInstruction: anIRClosure
 !
 
-visitIRInlinedAssignment: anIRInlinedAssignment
-	^ self visitIRAssignment: anIRInlinedAssignment
-!
-
-visitIRInlinedClosure: anIRClosure
-	^ self visitIRClosure: anIRClosure
-!
-
-visitIRInlinedIfFalse: anIRInlinedIfFalse
-	^ self visitIRInlinedSend: anIRInlinedIfFalse
-!
-
-visitIRInlinedIfTrue: anIRInlinedIfTrue
-	^ self visitIRInlinedSend: anIRInlinedIfTrue
-!
-
-visitIRInlinedNonLocalReturn: anIRNonLocalReturn
-	^ self visitIRReturn: anIRNonLocalReturn
-!
-
-visitIRInlinedSend: anIRInlinedSend
-	^ self visitIRSend: anIRInlinedSend
-!
-
 visitIRInstruction: anIRInstruction
 	anIRInstruction instructions do: [ :each | self visit: each ].
 	^ anIRInstruction
@@ -727,10 +716,6 @@ visitIRSequence: anIRSequence
 	^ self visitIRInstruction: anIRSequence
 !
 
-visitIRStatement: anIRStatement
-	^ self visitIRInstruction: anIRStatement
-!
-
 visitIRTempDeclaration: anIRTempDeclaration
 	^ self visitIRInstruction: anIRTempDeclaration
 !
@@ -780,16 +765,6 @@ visitIRAssignment: anIRAssignment
 	self visit: anIRAssignment instructions last.
 !
 
-visitIRBlockSequence: anIRBlockSequence
-	self stream nextPutSequenceWith: [
-		anIRBlockSequence instructions notEmpty ifTrue: [
-			anIRBlockSequence instructions allButLast do: [ :each | 
-				self visit: each ].
-			anIRBlockSequence instructions last isReturn ifFalse: [
-				self stream nextPutReturn ].
-			self visit: anIRBlockSequence instructions last ]]
-!
-
 visitIRClosure: anIRClosure
 	self stream 
 		nextPutClosureWith: [ super visitIRClosure: anIRClosure ] 
@@ -835,7 +810,7 @@ visitIRSend: anIRSend
 			anIRSend classSend 
 				ifNil: [ self stream nextPutAll: ',undefined' ]
 				ifNotNil: [ self stream nextPutAll: ',', anIRSend classSend asJavascript ].
-			self stream nextPutAll: ',', anIRSend index asJavascript ]
+			self stream nextPutAll: ',', anIRSend index asString ]
 		ifFalse: [
 			anIRSend classSend ifNotNil: [  
 				self stream nextPutAll: ',', anIRSend classSend asJavascript ]].
@@ -844,17 +819,8 @@ visitIRSend: anIRSend
 
 visitIRSequence: anIRSequence
 	self stream nextPutSequenceWith: [
-		"self instructions do: [ :each |
-			((IRStatement on: self builder)
-				pc: self builder nextPc;
-				with: each;
-				yourself) emitOn: aStream ]"
-		super visitIRSequence: anIRSequence ]
-!
-
-visitIRStatement: anIRStatement
-	self stream nextPutStatementWith: [
-		super visitIRStatement: anIRStatement ]
+		anIRSequence instructions do: [ :each |
+			self stream nextPutStatementWith: (self visit: each) ]]
 !
 
 visitIRTempDeclaration: anIRTempDeclaration

+ 272 - 57
st/Compiler-Inlining.st

@@ -16,32 +16,38 @@ accept: aVisitor
 ! !
 
 IRClosure subclass: #IRInlinedClosure
-	instanceVariableNames: 'assignTo'
+	instanceVariableNames: ''
 	package: 'Compiler-Inlining'!
 
-!IRInlinedClosure methodsFor: 'accessing'!
+!IRInlinedClosure methodsFor: 'testing'!
 
-assignTo
-	^ assignTo
-!
+isInlined
+	^ true
+! !
+
+!IRInlinedClosure methodsFor: 'visiting'!
 
-assignTo: aScopeVar
-	assignTo := aScopeVar
+accept: aVisitor
+	aVisitor visitIRInlinedClosure: self
 ! !
 
-!IRInlinedClosure methodsFor: 'testing'!
+IRReturn subclass: #IRInlinedReturn
+	instanceVariableNames: ''
+	package: 'Compiler-Inlining'!
+
+!IRInlinedReturn methodsFor: 'testing'!
 
 isInlined
 	^ true
 ! !
 
-!IRInlinedClosure methodsFor: 'visiting'!
+!IRInlinedReturn methodsFor: 'visiting'!
 
 accept: aVisitor
-	aVisitor visitIRInlinedClosure: self
+	^ aVisitor visitIRInlinedReturn: self
 ! !
 
-IRReturn subclass: #IRInlinedNonLocalReturn
+IRInlinedReturn subclass: #IRInlinedNonLocalReturn
 	instanceVariableNames: ''
 	package: 'Compiler-Inlining'!
 
@@ -93,24 +99,65 @@ accept: aVisitor
 	aVisitor visitIRInlinedIfTrue: self
 ! !
 
-IRVisitor subclass: #IRInliner
+IRBlockSequence subclass: #IRInlinedSequence
 	instanceVariableNames: ''
 	package: 'Compiler-Inlining'!
 
-!IRInliner methodsFor: 'testing'!
+!IRInlinedSequence methodsFor: 'testing'!
 
-shouldInlineAssignment: anIRAssignment
-	^ anIRAssignment isInlined not and: [ 
-		anIRAssignment instructions last isSend and: [	
-			self shouldInlineSend: (anIRAssignment instructions last) ]]
+isInlined
+	^ true
+! !
+
+!IRInlinedSequence methodsFor: 'visiting'!
+
+accept: aVisitor
+	aVisitor visitIRInlinedSequence: self
+! !
+
+IRInlinedSequence subclass: #IRAssigningInlinedSequence
+	instanceVariableNames: 'assignTo'
+	package: 'Compiler-Inlining'!
+
+!IRAssigningInlinedSequence methodsFor: 'accessing'!
+
+accept: aVisitor
+	^ aVisitor visitIRAssigningInlinedSequence: self
 !
 
-shouldInlineSend: anIRSend
-	^ anIRSend isInlined not and: [
-		IRSendInliner inlinedSelectors includes: anIRSend selector ]
+assignTo
+	^ assignTo
+!
+
+assignTo: anIRInstruction
+	assignTo := anIRInstruction
 ! !
 
-!IRInliner methodsFor: 'visiting'!
+IRInlinedSequence subclass: #IRReturningInlinedSequence
+	instanceVariableNames: ''
+	package: 'Compiler-Inlining'!
+
+!IRReturningInlinedSequence methodsFor: 'visiting'!
+
+accept: aVisitor
+	^ aVisitor visitIRReturningInlinedSequence: self
+! !
+
+IRReturningInlinedSequence subclass: #IRNonLocalReturningInlinedSequence
+	instanceVariableNames: ''
+	package: 'Compiler-Inlining'!
+
+!IRNonLocalReturningInlinedSequence methodsFor: 'visiting'!
+
+accept: aVisitor
+	^ aVisitor visitIRNonLocalReturningInlinedSequence: self
+! !
+
+IRVisitor subclass: #IRInliner
+	instanceVariableNames: ''
+	package: 'Compiler-Inlining'!
+
+!IRInliner methodsFor: 'factory'!
 
 assignmentInliner
 	^ IRAssignmentInliner new 
@@ -118,33 +165,79 @@ assignmentInliner
 		yourself
 !
 
+nonLocalReturnInliner
+	^ IRNonLocalReturnInliner new 
+		translator: self;
+		yourself
+!
+
+returnInliner
+	^ IRReturnInliner new 
+		translator: self;
+		yourself
+!
+
 sendInliner
 	^ IRSendInliner new 
 		translator: self;
 		yourself
+! !
+
+!IRInliner methodsFor: 'testing'!
+
+shouldInlineAssignment: anIRAssignment
+	^ anIRAssignment isInlined not and: [ 
+		anIRAssignment instructions last isSend and: [	
+			self shouldInlineSend: (anIRAssignment instructions last) ]]
 !
 
-visitIRAssignment: anIRAssignment
-	(self shouldInlineAssignment: anIRAssignment) 
-		ifTrue: [ self assignmentInliner inlineAssignment: anIRAssignment ]
-		ifFalse: [ super visitIRAssignment: anIRAssignment ]
+shouldInlineReturn: anIRReturn
+	^ anIRReturn isInlined not and: [ 
+		anIRReturn instructions first isSend and: [	
+			self shouldInlineSend: (anIRReturn instructions first) ]]
 !
 
-visitIRNonLocalReturn: anIRNonLocalReturn
+shouldInlineSend: anIRSend
+	^ anIRSend isInlined not and: [
+		IRSendInliner shouldInline: anIRSend ]
+! !
+
+!IRInliner methodsFor: 'visiting'!
+
+transformNonLocalReturn: anIRNonLocalReturn
 	| localReturn |
 	anIRNonLocalReturn scope canInlineNonLocalReturns ifTrue: [
 		anIRNonLocalReturn scope methodScope removeNonLocalReturn: anIRNonLocalReturn scope.
-		localReturn := IRInlinedNonLocalReturn new
+		localReturn := IRReturn new
 			scope: anIRNonLocalReturn scope;
 			yourself.
 		anIRNonLocalReturn instructions do: [ :each |
 			localReturn add: each ].
-		anIRNonLocalReturn replaceWith: localReturn ].
-	super visitIRNonLocalReturn: anIRNonLocalReturn
+		anIRNonLocalReturn replaceWith: localReturn.
+		^ localReturn ].
+	^ super visitIRNonLocalReturn: anIRNonLocalReturn
+!
+
+visitIRAssignment: anIRAssignment
+	^ (self shouldInlineAssignment: anIRAssignment) 
+		ifTrue: [ self assignmentInliner inlineAssignment: anIRAssignment ]
+		ifFalse: [ super visitIRAssignment: anIRAssignment ]
+!
+
+visitIRNonLocalReturn: anIRNonLocalReturn
+	^ (self shouldInlineReturn: anIRNonLocalReturn) 
+		ifTrue: [ self nonLocalReturnInliner inlineReturn: anIRNonLocalReturn ]
+		ifFalse: [ self transformNonLocalReturn: anIRNonLocalReturn ]
+!
+
+visitIRReturn: anIRReturn
+	^ (self shouldInlineReturn: anIRReturn) 
+		ifTrue: [ self returnInliner inlineReturn: anIRReturn ]
+		ifFalse: [ super visitIRReturn: anIRReturn ]
 !
 
 visitIRSend: anIRSend
-	(self shouldInlineSend: anIRSend)
+	^ (self shouldInlineSend: anIRSend)
 		ifTrue: [ self sendInliner inlineSend: anIRSend ]
 		ifFalse: [ super visitIRSend: anIRSend ]
 ! !
@@ -155,36 +248,85 @@ IRJSTranslator subclass: #IRInliningJSTranslator
 
 !IRInliningJSTranslator methodsFor: 'visiting'!
 
+visitIRAssigningInlinedSequence: anIRInlinedSequence
+
+	anIRInlinedSequence instructions allButLast do: [ :each | 
+		self stream nextPutStatementWith: [ self visit: each ]].
+
+	self stream nextPutStatementWith: [
+		anIRInlinedSequence instructions last canBeAssigned 
+			ifTrue: [
+				self stream 
+					nextPutAll: anIRInlinedSequence assignTo variable alias;
+                                	nextPutAssignment.
+				self visit: anIRInlinedSequence instructions last ]
+			ifFalse: [ self visit: anIRInlinedSequence instructions last ]]
+!
+
 visitIRInlinedAssignment: anIRInlinedAssignment
 	self visit: anIRInlinedAssignment instructions last
 !
 
 visitIRInlinedClosure: anIRInlinedClosure
-	anIRInlinedClosure instructions ifNotEmpty: [
-		anIRInlinedClosure instructions allButLast do: [ :each | self visit: each ].
-		(anIRInlinedClosure assignTo notNil and: [
-			anIRInlinedClosure instructions last canBeAssigned ]) ifTrue: [
-				self stream nextPutAll: anIRInlinedClosure assignTo variable alias.
-				self stream nextPutAssignment ].
-		self visit: anIRInlinedClosure instructions last ]
+	anIRInlinedClosure instructions do: [ :each |
+		self visit: each ]
 !
 
 visitIRInlinedIfFalse: anIRInlinedIfFalse
-	self stream 
-		nextPutIf: [ 
-			self stream nextPutAll: '!! smalltalk.assert('.
-			self visit: anIRInlinedIfFalse instructions first.
-			self stream nextPutAll: ')' ]
+	self stream nextPutIf: [ 
+		self stream nextPutAll: '!! smalltalk.assert('.
+		self visit: anIRInlinedIfFalse instructions first.
+		self stream nextPutAll: ')' ]
 		with: [ self visit: anIRInlinedIfFalse instructions last ]
 !
 
 visitIRInlinedIfTrue: anIRInlinedIfTrue
-	self stream 
-		nextPutIf: [ 
-			self stream nextPutAll: 'smalltalk.assert('. 
-			self visit: anIRInlinedIfTrue instructions first.
-			self stream nextPutAll: ')' ]
+	self stream nextPutIf: [ 
+		self stream nextPutAll: 'smalltalk.assert('. 
+		self visit: anIRInlinedIfTrue instructions first.
+		self stream nextPutAll: ')' ]
 		with: [ self visit: anIRInlinedIfTrue instructions last ]
+!
+
+visitIRInlinedNonLocalReturn: anIRInlinedReturn
+	self stream nextPutStatementWith: [
+		self visit: anIRInlinedReturn instructions last ].
+	self stream nextPutNonLocalReturnWith: [ ]
+!
+
+visitIRInlinedReturn: anIRInlinedReturn
+	self visit: anIRInlinedReturn instructions last
+!
+
+visitIRInlinedSequence: anIRInlinedSequence
+	anIRInlinedSequence instructions do: [ :each | 
+		self stream nextPutStatementWith: [ self visit: each ]]
+!
+
+visitIRNonLocalReturningInlinedSequence: anIRInlinedSequence
+
+	anIRInlinedSequence instructions allButLast do: [ :each | 
+		self stream nextPutStatementWith: [ self visit: each ]].
+
+	self stream nextPutStatementWith: [
+		anIRInlinedSequence instructions last canBeAssigned 
+			ifTrue: [
+				self stream nextPutNonLocalReturnWith: [
+					self visit: anIRInlinedSequence instructions last ]]
+			ifFalse: [ self visit: anIRInlinedSequence instructions last ]]
+!
+
+visitIRReturningInlinedSequence: anIRInlinedSequence
+
+	anIRInlinedSequence instructions allButLast do: [ :each | 
+		self stream nextPutStatementWith: [ self visit: each ]].
+
+	self stream nextPutStatementWith: [
+		anIRInlinedSequence instructions last canBeAssigned 
+			ifTrue: [
+				self stream nextPutReturn.
+				self visit: anIRInlinedSequence instructions last ]
+			ifFalse: [ self visit: anIRInlinedSequence instructions last ]]
 ! !
 
 Object subclass: #IRSendInliner
@@ -195,10 +337,6 @@ I inline some message sends and block closure arguments. I heavily rely on #perf
 
 !IRSendInliner methodsFor: 'accessing'!
 
-inlinedClosure
-	^ IRInlinedClosure new
-!
-
 send
 	^ send
 !
@@ -221,6 +359,16 @@ inliningError: aString
 	InliningError signal: aString
 ! !
 
+!IRSendInliner methodsFor: 'factory'!
+
+inlinedClosure
+	^ IRInlinedClosure new
+!
+
+inlinedSequence
+	^ IRInlinedSequence new
+! !
+
 !IRSendInliner methodsFor: 'inlining'!
 
 ifFalse: anIRInstruction
@@ -258,11 +406,29 @@ ifTrue: anIRInstruction
 !
 
 inlineClosure: anIRClosure
-	| inlinedClosure |
+	| inlinedClosure sequence statements |
 	inlinedClosure := self inlinedClosure.
 	inlinedClosure scope: anIRClosure scope.
-	anIRClosure instructions first instructions do: [ :each |
-		inlinedClosure add: (self translator visit: each) ].
+
+	"Add the possible temp declarations"
+	anIRClosure instructions do: [ :each | 
+		each isSequence ifFalse: [
+			inlinedClosure add: each ]].
+
+	"Add a block sequence"
+	sequence := self inlinedSequence.
+	inlinedClosure add: sequence.
+
+	"Get all the statements"
+	statements := anIRClosure instructions last instructions.
+	
+	statements ifNotEmpty: [
+		statements allButLast do: [ :each | sequence add: (self translator visit: each) ].
+		"Inlined closures don't have implicit local returns"
+		statements last isLocalReturn 
+			ifTrue: [ sequence add: (self translator visit: statements last instructions first) ]
+			ifFalse: [ sequence add: (self translator visit: statements last) ]].
+
 	^ inlinedClosure
 !
 
@@ -275,6 +441,13 @@ inlineSend: anIRSend
 
 inlinedSelectors
 	^ #('ifTrue:' 'ifFalse:')
+!
+
+shouldInline: anIRInstruction
+	(self inlinedSelectors includes: anIRInstruction selector) ifFalse: [ ^ false ].
+	anIRInstruction instructions allButFirst do: [ :each |
+		each isClosure ifFalse: [ ^ false ]].
+	^ true
 ! !
 
 IRSendInliner subclass: #IRAssignmentInliner
@@ -289,10 +462,12 @@ assignment
 
 assignment: aNode
 	assignment := aNode
-!
+! !
 
-inlinedClosure
-	^ super inlinedClosure
+!IRAssignmentInliner methodsFor: 'factory'!
+
+inlinedSequence
+	^ IRAssigningInlinedSequence new
 		assignTo: self assignment instructions first;
 		yourself
 ! !
@@ -310,6 +485,46 @@ inlineAssignment: anIRAssignment
 	^ inlinedAssignment
 ! !
 
+IRSendInliner subclass: #IRReturnInliner
+	instanceVariableNames: ''
+	package: 'Compiler-Inlining'!
+
+!IRReturnInliner methodsFor: 'factory'!
+
+inlinedReturn
+	^ IRInlinedReturn new
+!
+
+inlinedSequence
+	^ IRReturningInlinedSequence new
+! !
+
+!IRReturnInliner methodsFor: 'inlining'!
+
+inlineReturn: anIRReturn
+	| return |
+	return := self inlinedReturn.
+	anIRReturn instructions do: [ :each |
+		return add: each ].
+	anIRReturn replaceWith: return.
+	self inlineSend: return instructions last.
+	^ return
+! !
+
+IRReturnInliner subclass: #IRNonLocalReturnInliner
+	instanceVariableNames: ''
+	package: 'Compiler-Inlining'!
+
+!IRNonLocalReturnInliner methodsFor: 'factory'!
+
+inlinedReturn
+	^ IRInlinedNonLocalReturn new
+!
+
+inlinedSequence
+	^ IRNonLocalReturningInlinedSequence new
+! !
+
 CodeGenerator subclass: #InliningCodeGenerator
 	instanceVariableNames: ''
 	package: 'Compiler-Inlining'!

+ 9 - 8
st/Compiler-Semantic.st

@@ -514,16 +514,17 @@ visitReturnNode: aNode
 
 visitSendNode: aNode
 
-	aNode receiver value = 'super' ifTrue: [
-		aNode superSend: true.
-		aNode receiver value: 'self' ].
+	aNode receiver value = 'super' 
+		ifTrue: [
+			aNode superSend: true.
+			aNode receiver value: 'self' ]
+		ifFalse: [ (IRSendInliner inlinedSelectors includes: aNode selector) ifTrue: [
+			aNode shouldBeInlined: true ]].
 
-	self messageSends 
-		at: aNode selector
-		ifPresent: [ self messageSends at: aNode selector put: (self messageSends at: aNode selector) + 1 ]
-		ifAbsent: [ self messageSends at: aNode selector put: 1 ].
+	self messageSends at: aNode selector ifAbsentPut: [ Set new ].
+	(self messageSends at: aNode selector) add: aNode.
 
-	aNode index: (self messageSends at: aNode selector).
+	aNode index: (self messageSends at: aNode selector) size.
 
 	super visitSendNode: aNode
 !

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