Browse Source

- Inliner cleanup, removal of IRNonLocalReturnInliner
- Allow block args in inlined #ifNotNil: and co

Nicolas Petton 11 years ago
parent
commit
62c24efcba

+ 41 - 109
js/Compiler-Inlining.deploy.js

@@ -84,35 +84,6 @@ smalltalk.IRInlinedReturn);
 
 
 
-smalltalk.addClass('IRInlinedNonLocalReturn', smalltalk.IRInlinedReturn, [], 'Compiler-Inlining');
-smalltalk.addMethod(
-"_accept_",
-smalltalk.method({
-selector: "accept:",
-fn: function (aVisitor){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st(aVisitor)._visitIRInlinedNonLocalReturn_(self);
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"accept:",{aVisitor:aVisitor},smalltalk.IRInlinedNonLocalReturn)})},
-messageSends: ["visitIRInlinedNonLocalReturn:"]}),
-smalltalk.IRInlinedNonLocalReturn);
-
-smalltalk.addMethod(
-"_isInlined",
-smalltalk.method({
-selector: "isInlined",
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-return true;
-}, function($ctx1) {$ctx1.fill(self,"isInlined",{},smalltalk.IRInlinedNonLocalReturn)})},
-messageSends: []}),
-smalltalk.IRInlinedNonLocalReturn);
-
-
-
 smalltalk.addClass('IRInlinedSend', smalltalk.IRSend, [], 'Compiler-Inlining');
 smalltalk.addMethod(
 "_accept_",
@@ -246,24 +217,6 @@ return $1;
 messageSends: ["translator:", "new", "yourself"]}),
 smalltalk.IRInliner);
 
-smalltalk.addMethod(
-"_nonLocalReturnInliner",
-smalltalk.method({
-selector: "nonLocalReturnInliner",
-fn: function (){
-var self=this;
-function $IRNonLocalReturnInliner(){return smalltalk.IRNonLocalReturnInliner||(typeof IRNonLocalReturnInliner=="undefined"?nil:IRNonLocalReturnInliner)}
-return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$1;
-$2=_st($IRNonLocalReturnInliner())._new();
-_st($2)._translator_(self);
-$3=_st($2)._yourself();
-$1=$3;
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"nonLocalReturnInliner",{},smalltalk.IRInliner)})},
-messageSends: ["translator:", "new", "yourself"]}),
-smalltalk.IRInliner);
-
 smalltalk.addMethod(
 "_returnInliner",
 smalltalk.method({
@@ -416,16 +369,11 @@ selector: "visitIRNonLocalReturn:",
 fn: function (anIRNonLocalReturn){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=_st(self)._shouldInlineReturn_(anIRNonLocalReturn);
-if(smalltalk.assert($2)){
-$1=_st(_st(self)._nonLocalReturnInliner())._inlineReturn_(anIRNonLocalReturn);
-} else {
+var $1;
 $1=_st(self)._transformNonLocalReturn_(anIRNonLocalReturn);
-};
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"visitIRNonLocalReturn:",{anIRNonLocalReturn:anIRNonLocalReturn},smalltalk.IRInliner)})},
-messageSends: ["ifTrue:ifFalse:", "inlineReturn:", "nonLocalReturnInliner", "transformNonLocalReturn:", "shouldInlineReturn:"]}),
+messageSends: ["transformNonLocalReturn:"]}),
 smalltalk.IRInliner);
 
 smalltalk.addMethod(
@@ -801,8 +749,12 @@ selector: "inlineClosure:",
 fn: function (anIRClosure){
 var self=this;
 var inlinedClosure,sequence,statements;
+function $IRTempDeclaration(){return smalltalk.IRTempDeclaration||(typeof IRTempDeclaration=="undefined"?nil:IRTempDeclaration)}
+function $AliasVar(){return smalltalk.AliasVar||(typeof AliasVar=="undefined"?nil:AliasVar)}
+function $IRVariable(){return smalltalk.IRVariable||(typeof IRVariable=="undefined"?nil:IRVariable)}
+function $IRAssignment(){return smalltalk.IRAssignment||(typeof IRAssignment=="undefined"?nil:IRAssignment)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
+var $1,$2,$3,$4,$5,$6,$7,$8,$9,$10;
 inlinedClosure=_st(self)._inlinedClosure();
 _st(inlinedClosure)._scope_(_st(anIRClosure)._scope());
 _st(_st(anIRClosure)._tempDeclarations())._do_((function(each){
@@ -810,6 +762,26 @@ return smalltalk.withContext(function($ctx2) {
 return _st(inlinedClosure)._add_(each);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 sequence=_st(self)._inlinedSequence();
+_st(_st(anIRClosure)._arguments())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+$1=_st($IRTempDeclaration())._new();
+_st($1)._name_(each);
+$2=_st($1)._yourself();
+_st(inlinedClosure)._add_($2);
+$3=_st($IRAssignment())._new();
+$4=_st($AliasVar())._new();
+_st($4)._scope_(_st(inlinedClosure)._scope());
+_st($4)._name_(each);
+$5=_st($4)._yourself();
+_st($3)._add_(_st(_st($IRVariable())._new())._variable_($5));
+$6=_st($AliasVar())._new();
+_st($6)._scope_(_st(inlinedClosure)._scope());
+_st($6)._name_("$receiver");
+$7=_st($6)._yourself();
+_st($3)._add_(_st(_st($IRVariable())._new())._variable_($7));
+$8=_st($3)._yourself();
+return _st(sequence)._add_($8);
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 _st(inlinedClosure)._add_(sequence);
 statements=_st(_st(_st(anIRClosure)._instructions())._last())._instructions();
 _st(statements)._ifNotEmpty_((function(){
@@ -818,20 +790,20 @@ _st(_st(statements)._allButLast())._do_((function(each){
 return smalltalk.withContext(function($ctx3) {
 return _st(sequence)._add_(each);
 }, function($ctx3) {$ctx3.fillBlock({each:each},$ctx1)})}));
-$1=_st(_st(_st(statements)._last())._isReturn())._and_((function(){
+$9=_st(_st(_st(statements)._last())._isReturn())._and_((function(){
 return smalltalk.withContext(function($ctx3) {
 return _st(_st(statements)._last())._isBlockReturn();
 }, function($ctx3) {$ctx3.fillBlock({},$ctx1)})}));
-if(smalltalk.assert($1)){
+if(smalltalk.assert($9)){
 return _st(sequence)._add_(_st(_st(_st(statements)._last())._instructions())._first());
 } else {
 return _st(sequence)._add_(_st(statements)._last());
 };
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
-$2=inlinedClosure;
-return $2;
+$10=inlinedClosure;
+return $10;
 }, function($ctx1) {$ctx1.fill(self,"inlineClosure:",{anIRClosure:anIRClosure,inlinedClosure:inlinedClosure,sequence:sequence,statements:statements},smalltalk.IRSendInliner)})},
-messageSends: ["inlinedClosure", "scope:", "scope", "do:", "add:", "tempDeclarations", "inlinedSequence", "instructions", "last", "ifNotEmpty:", "allButLast", "ifTrue:ifFalse:", "first", "and:", "isBlockReturn", "isReturn"]}),
+messageSends: ["inlinedClosure", "scope:", "scope", "do:", "add:", "tempDeclarations", "inlinedSequence", "name:", "new", "yourself", "variable:", "arguments", "instructions", "last", "ifNotEmpty:", "allButLast", "ifTrue:ifFalse:", "first", "and:", "isBlockReturn", "isReturn"]}),
 smalltalk.IRSendInliner);
 
 smalltalk.addMethod(
@@ -900,34 +872,26 @@ fn: function (inlinedSend,anIRInstruction,anotherIRInstruction){
 var self=this;
 var inlinedClosure1,inlinedClosure2;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$3,$4,$5,$6,$7;
+var $1,$2,$3,$4,$5;
 $1=_st(anIRInstruction)._isClosure();
 if(! smalltalk.assert($1)){
 _st(self)._inliningError_("Message argument should be a block");
 };
-$2=_st(_st(_st(anIRInstruction)._arguments())._size()).__eq((0));
+$2=_st(anotherIRInstruction)._isClosure();
 if(! smalltalk.assert($2)){
-_st(self)._inliningError_("Inlined block should have zero argument");
-};
-$3=_st(anotherIRInstruction)._isClosure();
-if(! smalltalk.assert($3)){
 _st(self)._inliningError_("Message argument should be a block");
 };
-$4=_st(_st(_st(anotherIRInstruction)._arguments())._size()).__eq((0));
-if(! smalltalk.assert($4)){
-_st(self)._inliningError_("Inlined block should have zero argument");
-};
 inlinedClosure1=_st(_st(self)._translator())._visit_(_st(self)._inlineClosure_(anIRInstruction));
 inlinedClosure2=_st(_st(self)._translator())._visit_(_st(self)._inlineClosure_(anotherIRInstruction));
-$5=inlinedSend;
-_st($5)._add_(_st(_st(_st(self)._send())._instructions())._first());
-_st($5)._add_(inlinedClosure1);
-$6=_st($5)._add_(inlinedClosure2);
+$3=inlinedSend;
+_st($3)._add_(_st(_st(_st(self)._send())._instructions())._first());
+_st($3)._add_(inlinedClosure1);
+$4=_st($3)._add_(inlinedClosure2);
 _st(_st(self)._send())._replaceWith_(inlinedSend);
-$7=inlinedSend;
-return $7;
+$5=inlinedSend;
+return $5;
 }, function($ctx1) {$ctx1.fill(self,"inlinedSend:with:with:",{inlinedSend:inlinedSend,anIRInstruction:anIRInstruction,anotherIRInstruction:anotherIRInstruction,inlinedClosure1:inlinedClosure1,inlinedClosure2:inlinedClosure2},smalltalk.IRSendInliner)})},
-messageSends: ["ifFalse:", "inliningError:", "isClosure", "=", "size", "arguments", "visit:", "inlineClosure:", "translator", "add:", "first", "instructions", "send", "replaceWith:"]}),
+messageSends: ["ifFalse:", "inliningError:", "isClosure", "visit:", "inlineClosure:", "translator", "add:", "first", "instructions", "send", "replaceWith:"]}),
 smalltalk.IRSendInliner);
 
 smalltalk.addMethod(
@@ -1136,38 +1100,6 @@ smalltalk.IRAssignmentInliner);
 
 
 
-smalltalk.addClass('IRNonLocalReturnInliner', smalltalk.IRSendInliner, [], 'Compiler-Inlining');
-smalltalk.addMethod(
-"_inlineClosure_",
-smalltalk.method({
-selector: "inlineClosure:",
-fn: function (anIRClosure){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=smalltalk.IRSendInliner.fn.prototype._inlineCLosure_.apply(_st(self), [anIRClosure]);
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"inlineClosure:",{anIRClosure:anIRClosure},smalltalk.IRNonLocalReturnInliner)})},
-messageSends: ["inlineCLosure:"]}),
-smalltalk.IRNonLocalReturnInliner);
-
-smalltalk.addMethod(
-"_inlinedReturn",
-smalltalk.method({
-selector: "inlinedReturn",
-fn: function (){
-var self=this;
-function $IRInlinedNonLocalReturn(){return smalltalk.IRInlinedNonLocalReturn||(typeof IRInlinedNonLocalReturn=="undefined"?nil:IRInlinedNonLocalReturn)}
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st($IRInlinedNonLocalReturn())._new();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"inlinedReturn",{},smalltalk.IRNonLocalReturnInliner)})},
-messageSends: ["new"]}),
-smalltalk.IRNonLocalReturnInliner);
-
-
-
 smalltalk.addClass('IRReturnInliner', smalltalk.IRSendInliner, [], 'Compiler-Inlining');
 smalltalk.addMethod(
 "_inlineClosure_",

+ 45 - 139
js/Compiler-Inlining.js

@@ -117,46 +117,6 @@ smalltalk.IRInlinedReturn);
 
 
 
-smalltalk.addClass('IRInlinedNonLocalReturn', smalltalk.IRInlinedReturn, [], 'Compiler-Inlining');
-smalltalk.IRInlinedNonLocalReturn.comment="I represent an inlined non local return instruction."
-smalltalk.addMethod(
-"_accept_",
-smalltalk.method({
-selector: "accept:",
-category: 'visiting',
-fn: function (aVisitor){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st(aVisitor)._visitIRInlinedNonLocalReturn_(self);
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"accept:",{aVisitor:aVisitor},smalltalk.IRInlinedNonLocalReturn)})},
-args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09^ aVisitor visitIRInlinedNonLocalReturn: self",
-messageSends: ["visitIRInlinedNonLocalReturn:"],
-referencedClasses: []
-}),
-smalltalk.IRInlinedNonLocalReturn);
-
-smalltalk.addMethod(
-"_isInlined",
-smalltalk.method({
-selector: "isInlined",
-category: 'testing',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-return true;
-}, function($ctx1) {$ctx1.fill(self,"isInlined",{},smalltalk.IRInlinedNonLocalReturn)})},
-args: [],
-source: "isInlined\x0a\x09^ true",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.IRInlinedNonLocalReturn);
-
-
-
 smalltalk.addClass('IRInlinedSend', smalltalk.IRSend, [], 'Compiler-Inlining');
 smalltalk.IRInlinedSend.comment="I am the abstract super class of inlined message send instructions."
 smalltalk.addMethod(
@@ -338,29 +298,6 @@ referencedClasses: ["IRAssignmentInliner"]
 }),
 smalltalk.IRInliner);
 
-smalltalk.addMethod(
-"_nonLocalReturnInliner",
-smalltalk.method({
-selector: "nonLocalReturnInliner",
-category: 'factory',
-fn: function (){
-var self=this;
-function $IRNonLocalReturnInliner(){return smalltalk.IRNonLocalReturnInliner||(typeof IRNonLocalReturnInliner=="undefined"?nil:IRNonLocalReturnInliner)}
-return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$1;
-$2=_st($IRNonLocalReturnInliner())._new();
-_st($2)._translator_(self);
-$3=_st($2)._yourself();
-$1=$3;
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"nonLocalReturnInliner",{},smalltalk.IRInliner)})},
-args: [],
-source: "nonLocalReturnInliner\x0a\x09^ IRNonLocalReturnInliner new\x0a\x09\x09translator: self;\x0a\x09\x09yourself",
-messageSends: ["translator:", "new", "yourself"],
-referencedClasses: ["IRNonLocalReturnInliner"]
-}),
-smalltalk.IRInliner);
-
 smalltalk.addMethod(
 "_returnInliner",
 smalltalk.method({
@@ -549,18 +486,13 @@ category: 'visiting',
 fn: function (anIRNonLocalReturn){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=_st(self)._shouldInlineReturn_(anIRNonLocalReturn);
-if(smalltalk.assert($2)){
-$1=_st(_st(self)._nonLocalReturnInliner())._inlineReturn_(anIRNonLocalReturn);
-} else {
+var $1;
 $1=_st(self)._transformNonLocalReturn_(anIRNonLocalReturn);
-};
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"visitIRNonLocalReturn:",{anIRNonLocalReturn:anIRNonLocalReturn},smalltalk.IRInliner)})},
 args: ["anIRNonLocalReturn"],
-source: "visitIRNonLocalReturn: anIRNonLocalReturn\x0a\x09^ (self shouldInlineReturn: anIRNonLocalReturn)\x0a\x09\x09ifTrue: [ self nonLocalReturnInliner inlineReturn: anIRNonLocalReturn ]\x0a\x09\x09ifFalse: [ self transformNonLocalReturn: anIRNonLocalReturn ]",
-messageSends: ["ifTrue:ifFalse:", "inlineReturn:", "nonLocalReturnInliner", "transformNonLocalReturn:", "shouldInlineReturn:"],
+source: "visitIRNonLocalReturn: anIRNonLocalReturn\x0a\x09^ self transformNonLocalReturn: anIRNonLocalReturn",
+messageSends: ["transformNonLocalReturn:"],
 referencedClasses: []
 }),
 smalltalk.IRInliner);
@@ -1041,8 +973,12 @@ category: 'inlining',
 fn: function (anIRClosure){
 var self=this;
 var inlinedClosure,sequence,statements;
+function $IRTempDeclaration(){return smalltalk.IRTempDeclaration||(typeof IRTempDeclaration=="undefined"?nil:IRTempDeclaration)}
+function $AliasVar(){return smalltalk.AliasVar||(typeof AliasVar=="undefined"?nil:AliasVar)}
+function $IRVariable(){return smalltalk.IRVariable||(typeof IRVariable=="undefined"?nil:IRVariable)}
+function $IRAssignment(){return smalltalk.IRAssignment||(typeof IRAssignment=="undefined"?nil:IRAssignment)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
+var $1,$2,$3,$4,$5,$6,$7,$8,$9,$10;
 inlinedClosure=_st(self)._inlinedClosure();
 _st(inlinedClosure)._scope_(_st(anIRClosure)._scope());
 _st(_st(anIRClosure)._tempDeclarations())._do_((function(each){
@@ -1050,6 +986,26 @@ return smalltalk.withContext(function($ctx2) {
 return _st(inlinedClosure)._add_(each);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 sequence=_st(self)._inlinedSequence();
+_st(_st(anIRClosure)._arguments())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+$1=_st($IRTempDeclaration())._new();
+_st($1)._name_(each);
+$2=_st($1)._yourself();
+_st(inlinedClosure)._add_($2);
+$3=_st($IRAssignment())._new();
+$4=_st($AliasVar())._new();
+_st($4)._scope_(_st(inlinedClosure)._scope());
+_st($4)._name_(each);
+$5=_st($4)._yourself();
+_st($3)._add_(_st(_st($IRVariable())._new())._variable_($5));
+$6=_st($AliasVar())._new();
+_st($6)._scope_(_st(inlinedClosure)._scope());
+_st($6)._name_("$receiver");
+$7=_st($6)._yourself();
+_st($3)._add_(_st(_st($IRVariable())._new())._variable_($7));
+$8=_st($3)._yourself();
+return _st(sequence)._add_($8);
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 _st(inlinedClosure)._add_(sequence);
 statements=_st(_st(_st(anIRClosure)._instructions())._last())._instructions();
 _st(statements)._ifNotEmpty_((function(){
@@ -1058,23 +1014,23 @@ _st(_st(statements)._allButLast())._do_((function(each){
 return smalltalk.withContext(function($ctx3) {
 return _st(sequence)._add_(each);
 }, function($ctx3) {$ctx3.fillBlock({each:each},$ctx1)})}));
-$1=_st(_st(_st(statements)._last())._isReturn())._and_((function(){
+$9=_st(_st(_st(statements)._last())._isReturn())._and_((function(){
 return smalltalk.withContext(function($ctx3) {
 return _st(_st(statements)._last())._isBlockReturn();
 }, function($ctx3) {$ctx3.fillBlock({},$ctx1)})}));
-if(smalltalk.assert($1)){
+if(smalltalk.assert($9)){
 return _st(sequence)._add_(_st(_st(_st(statements)._last())._instructions())._first());
 } else {
 return _st(sequence)._add_(_st(statements)._last());
 };
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
-$2=inlinedClosure;
-return $2;
+$10=inlinedClosure;
+return $10;
 }, function($ctx1) {$ctx1.fill(self,"inlineClosure:",{anIRClosure:anIRClosure,inlinedClosure:inlinedClosure,sequence:sequence,statements:statements},smalltalk.IRSendInliner)})},
 args: ["anIRClosure"],
-source: "inlineClosure: anIRClosure\x0a\x09| inlinedClosure sequence statements |\x0a\x0a\x09inlinedClosure := self inlinedClosure.\x0a\x09inlinedClosure scope: anIRClosure scope.\x0a\x0a\x09\x22Add the possible temp declarations\x22\x0a\x09anIRClosure tempDeclarations do: [ :each |\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: each ].\x0a\x0a\x09\x09\x22Inlined closures don't have implicit local returns\x22\x0a\x09\x09(statements last isReturn and: [ statements last isBlockReturn ])\x0a\x09\x09\x09ifTrue: [ sequence add: statements last instructions first ]\x0a\x09\x09\x09ifFalse: [ sequence add: statements last ] ].\x0a\x0a\x09^ inlinedClosure",
-messageSends: ["inlinedClosure", "scope:", "scope", "do:", "add:", "tempDeclarations", "inlinedSequence", "instructions", "last", "ifNotEmpty:", "allButLast", "ifTrue:ifFalse:", "first", "and:", "isBlockReturn", "isReturn"],
-referencedClasses: []
+source: "inlineClosure: anIRClosure\x0a\x09| inlinedClosure sequence statements |\x0a\x0a\x09inlinedClosure := self inlinedClosure.\x0a\x09inlinedClosure scope: anIRClosure scope.\x0a\x0a\x09\x22Add the possible temp declarations\x22\x0a\x09anIRClosure tempDeclarations do: [ :each |\x0a\x09\x09\x09inlinedClosure add: each ].\x0a\x0a\x09\x22Add a block sequence\x22\x0a\x09sequence := self inlinedSequence.\x0a\x0a\x09\x22Map the closure arguments to the receiver of the message send\x22\x0a\x09anIRClosure arguments do: [ :each |\x0a\x09\x09inlinedClosure add: (IRTempDeclaration new name: each; yourself).\x0a\x09\x09sequence add: (IRAssignment new\x0a\x09\x09\x09add: (IRVariable new variable: (AliasVar new scope: inlinedClosure scope; name: each; yourself));\x0a\x09\x09\x09add: (IRVariable new variable: (AliasVar new scope: inlinedClosure scope; name: '$receiver'; yourself));\x0a\x09\x09\x09yourself) ].\x0a\x09\x09\x09\x0a\x09\x22To ensure the correct order of the closure instructions: first the temps then the sequence\x22\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: each ].\x0a\x0a\x09\x09\x22Inlined closures don't have implicit local returns\x22\x0a\x09\x09(statements last isReturn and: [ statements last isBlockReturn ])\x0a\x09\x09\x09ifTrue: [ sequence add: statements last instructions first ]\x0a\x09\x09\x09ifFalse: [ sequence add: statements last ] ].\x0a\x0a\x09^ inlinedClosure",
+messageSends: ["inlinedClosure", "scope:", "scope", "do:", "add:", "tempDeclarations", "inlinedSequence", "name:", "new", "yourself", "variable:", "arguments", "instructions", "last", "ifNotEmpty:", "allButLast", "ifTrue:ifFalse:", "first", "and:", "isBlockReturn", "isReturn"],
+referencedClasses: ["IRTempDeclaration", "AliasVar", "IRVariable", "IRAssignment"]
 }),
 smalltalk.IRSendInliner);
 
@@ -1160,36 +1116,28 @@ fn: function (inlinedSend,anIRInstruction,anotherIRInstruction){
 var self=this;
 var inlinedClosure1,inlinedClosure2;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$3,$4,$5,$6,$7;
+var $1,$2,$3,$4,$5;
 $1=_st(anIRInstruction)._isClosure();
 if(! smalltalk.assert($1)){
 _st(self)._inliningError_("Message argument should be a block");
 };
-$2=_st(_st(_st(anIRInstruction)._arguments())._size()).__eq((0));
+$2=_st(anotherIRInstruction)._isClosure();
 if(! smalltalk.assert($2)){
-_st(self)._inliningError_("Inlined block should have zero argument");
-};
-$3=_st(anotherIRInstruction)._isClosure();
-if(! smalltalk.assert($3)){
 _st(self)._inliningError_("Message argument should be a block");
 };
-$4=_st(_st(_st(anotherIRInstruction)._arguments())._size()).__eq((0));
-if(! smalltalk.assert($4)){
-_st(self)._inliningError_("Inlined block should have zero argument");
-};
 inlinedClosure1=_st(_st(self)._translator())._visit_(_st(self)._inlineClosure_(anIRInstruction));
 inlinedClosure2=_st(_st(self)._translator())._visit_(_st(self)._inlineClosure_(anotherIRInstruction));
-$5=inlinedSend;
-_st($5)._add_(_st(_st(_st(self)._send())._instructions())._first());
-_st($5)._add_(inlinedClosure1);
-$6=_st($5)._add_(inlinedClosure2);
+$3=inlinedSend;
+_st($3)._add_(_st(_st(_st(self)._send())._instructions())._first());
+_st($3)._add_(inlinedClosure1);
+$4=_st($3)._add_(inlinedClosure2);
 _st(_st(self)._send())._replaceWith_(inlinedSend);
-$7=inlinedSend;
-return $7;
+$5=inlinedSend;
+return $5;
 }, function($ctx1) {$ctx1.fill(self,"inlinedSend:with:with:",{inlinedSend:inlinedSend,anIRInstruction:anIRInstruction,anotherIRInstruction:anotherIRInstruction,inlinedClosure1:inlinedClosure1,inlinedClosure2:inlinedClosure2},smalltalk.IRSendInliner)})},
 args: ["inlinedSend", "anIRInstruction", "anotherIRInstruction"],
-source: "inlinedSend: inlinedSend with: anIRInstruction with: anotherIRInstruction\x0a\x09| inlinedClosure1 inlinedClosure2 |\x0a\x0a\x09anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].\x0a\x09anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].\x0a\x0a\x09anotherIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].\x0a\x09anotherIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].\x0a\x0a\x09inlinedClosure1 := self translator visit: (self inlineClosure: anIRInstruction).\x0a\x09inlinedClosure2 := self translator visit: (self inlineClosure: anotherIRInstruction).\x0a\x0a\x0a\x09inlinedSend\x0a\x09\x09add: self send instructions first;\x0a\x09\x09add: inlinedClosure1;\x0a\x09\x09add: inlinedClosure2.\x0a\x0a\x09self send replaceWith: inlinedSend.\x0a\x09^ inlinedSend",
-messageSends: ["ifFalse:", "inliningError:", "isClosure", "=", "size", "arguments", "visit:", "inlineClosure:", "translator", "add:", "first", "instructions", "send", "replaceWith:"],
+source: "inlinedSend: inlinedSend with: anIRInstruction with: anotherIRInstruction\x0a\x09| inlinedClosure1 inlinedClosure2 |\x0a\x0a\x09anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].\x0a\x09anotherIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].\x0a\x0a\x09inlinedClosure1 := self translator visit: (self inlineClosure: anIRInstruction).\x0a\x09inlinedClosure2 := self translator visit: (self inlineClosure: anotherIRInstruction).\x0a\x0a\x09inlinedSend\x0a\x09\x09add: self send instructions first;\x0a\x09\x09add: inlinedClosure1;\x0a\x09\x09add: inlinedClosure2.\x0a\x0a\x09self send replaceWith: inlinedSend.\x0a\x09^ inlinedSend",
+messageSends: ["ifFalse:", "inliningError:", "isClosure", "visit:", "inlineClosure:", "translator", "add:", "first", "instructions", "send", "replaceWith:"],
 referencedClasses: []
 }),
 smalltalk.IRSendInliner);
@@ -1461,48 +1409,6 @@ smalltalk.IRAssignmentInliner);
 
 
 
-smalltalk.addClass('IRNonLocalReturnInliner', smalltalk.IRSendInliner, [], 'Compiler-Inlining');
-smalltalk.addMethod(
-"_inlineClosure_",
-smalltalk.method({
-selector: "inlineClosure:",
-category: 'inlining',
-fn: function (anIRClosure){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=smalltalk.IRSendInliner.fn.prototype._inlineCLosure_.apply(_st(self), [anIRClosure]);
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"inlineClosure:",{anIRClosure:anIRClosure},smalltalk.IRNonLocalReturnInliner)})},
-args: ["anIRClosure"],
-source: "inlineClosure: anIRClosure\x0a\x09\x22| inlinedClosure statements |\x0a\x0a\x09inlinedClosure := super inlineClosure: anIRClosure.\x0a\x09statements := inlinedClosure instructions last instructions.\x0a\x09\x0a\x09statements ifNotEmpty: [\x0a\x09\x09statements last replaceWith: (IRNonLocalReturn new\x0a\x09\x09\x09add: statements last copy;\x0a\x09\x09\x09yourself) ].\x0a\x0a\x09^ inlinedClosure\x22\x0a\x0a\x09^ super inlineCLosure: anIRClosure",
-messageSends: ["inlineCLosure:"],
-referencedClasses: []
-}),
-smalltalk.IRNonLocalReturnInliner);
-
-smalltalk.addMethod(
-"_inlinedReturn",
-smalltalk.method({
-selector: "inlinedReturn",
-category: 'factory',
-fn: function (){
-var self=this;
-function $IRInlinedNonLocalReturn(){return smalltalk.IRInlinedNonLocalReturn||(typeof IRInlinedNonLocalReturn=="undefined"?nil:IRInlinedNonLocalReturn)}
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st($IRInlinedNonLocalReturn())._new();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"inlinedReturn",{},smalltalk.IRNonLocalReturnInliner)})},
-args: [],
-source: "inlinedReturn\x0a\x09^ IRInlinedNonLocalReturn new",
-messageSends: ["new"],
-referencedClasses: ["IRInlinedNonLocalReturn"]
-}),
-smalltalk.IRNonLocalReturnInliner);
-
-
-
 smalltalk.addClass('IRReturnInliner', smalltalk.IRSendInliner, [], 'Compiler-Inlining');
 smalltalk.IRReturnInliner.comment="I inline message sends with inlined closure together with a return instruction."
 smalltalk.addMethod(

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

@@ -730,6 +730,19 @@ return self}, function($ctx1) {$ctx1.fill(self,"testifNotNil",{},smalltalk.CodeG
 messageSends: ["should:return:"]}),
 smalltalk.CodeGeneratorTest);
 
+smalltalk.addMethod(
+"_testifNotNilWithArgument",
+smalltalk.method({
+selector: "testifNotNilWithArgument",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self)._should_return_("foo ^ 1 ifNotNil: [ :val | val + 2 ]",(3));
+_st(self)._should_return_("foo ^ nil ifNotNil: [ :val | val + 2 ]",nil);
+return self}, function($ctx1) {$ctx1.fill(self,"testifNotNilWithArgument",{},smalltalk.CodeGeneratorTest)})},
+messageSends: ["should:return:"]}),
+smalltalk.CodeGeneratorTest);
+
 smalltalk.addMethod(
 "_testifTrue",
 smalltalk.method({

+ 18 - 0
js/Compiler-Tests.js

@@ -975,6 +975,24 @@ referencedClasses: []
 }),
 smalltalk.CodeGeneratorTest);
 
+smalltalk.addMethod(
+"_testifNotNilWithArgument",
+smalltalk.method({
+selector: "testifNotNilWithArgument",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self)._should_return_("foo ^ 1 ifNotNil: [ :val | val + 2 ]",(3));
+_st(self)._should_return_("foo ^ nil ifNotNil: [ :val | val + 2 ]",nil);
+return self}, function($ctx1) {$ctx1.fill(self,"testifNotNilWithArgument",{},smalltalk.CodeGeneratorTest)})},
+args: [],
+source: "testifNotNilWithArgument\x0a\x09self should: 'foo ^ 1 ifNotNil: [ :val | val + 2 ]' return: 3.\x0a\x09self should: 'foo ^ nil ifNotNil: [ :val | val + 2 ]' return: nil",
+messageSends: ["should:return:"],
+referencedClasses: []
+}),
+smalltalk.CodeGeneratorTest);
+
 smalltalk.addMethod(
 "_testifTrue",
 smalltalk.method({

+ 4 - 4
js/Kernel-Objects.deploy.js

@@ -323,10 +323,10 @@ fn: function (aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=_st(aBlock)._value();
+$1=_st(aBlock)._value_(self);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"ifNotNil:",{aBlock:aBlock},smalltalk.Object)})},
-messageSends: ["value"]}),
+messageSends: ["value:"]}),
 smalltalk.Object);
 
 smalltalk.addMethod(
@@ -337,10 +337,10 @@ fn: function (aBlock,anotherBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=_st(aBlock)._value();
+$1=_st(aBlock)._value_(self);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"ifNotNil:ifNil:",{aBlock:aBlock,anotherBlock:anotherBlock},smalltalk.Object)})},
-messageSends: ["value"]}),
+messageSends: ["value:"]}),
 smalltalk.Object);
 
 smalltalk.addMethod(

+ 6 - 6
js/Kernel-Objects.js

@@ -435,12 +435,12 @@ fn: function (aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=_st(aBlock)._value();
+$1=_st(aBlock)._value_(self);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"ifNotNil:",{aBlock:aBlock},smalltalk.Object)})},
 args: ["aBlock"],
-source: "ifNotNil: aBlock\x0a\x09\x22inlined in the Compiler\x22\x0a\x09^aBlock value",
-messageSends: ["value"],
+source: "ifNotNil: aBlock\x0a\x09\x22inlined in the Compiler\x22\x0a\x09^aBlock value: self",
+messageSends: ["value:"],
 referencedClasses: []
 }),
 smalltalk.Object);
@@ -454,12 +454,12 @@ fn: function (aBlock,anotherBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=_st(aBlock)._value();
+$1=_st(aBlock)._value_(self);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"ifNotNil:ifNil:",{aBlock:aBlock,anotherBlock:anotherBlock},smalltalk.Object)})},
 args: ["aBlock", "anotherBlock"],
-source: "ifNotNil: aBlock ifNil: anotherBlock\x0a\x09\x22inlined in the Compiler\x22\x0a\x09^aBlock value",
-messageSends: ["value"],
+source: "ifNotNil: aBlock ifNil: anotherBlock\x0a\x09\x22inlined in the Compiler\x22\x0a\x09^aBlock value: self",
+messageSends: ["value:"],
 referencedClasses: []
 }),
 smalltalk.Object);

+ 11 - 59
st/Compiler-Inlining.st

@@ -53,24 +53,6 @@ accept: aVisitor
 	^ aVisitor visitIRInlinedReturn: self
 ! !
 
-IRInlinedReturn subclass: #IRInlinedNonLocalReturn
-	instanceVariableNames: ''
-	package: 'Compiler-Inlining'!
-!IRInlinedNonLocalReturn commentStamp!
-I represent an inlined non local return instruction.!
-
-!IRInlinedNonLocalReturn methodsFor: 'testing'!
-
-isInlined
-	^ true
-! !
-
-!IRInlinedNonLocalReturn methodsFor: 'visiting'!
-
-accept: aVisitor
-	^ aVisitor visitIRInlinedNonLocalReturn: self
-! !
-
 IRSend subclass: #IRInlinedSend
 	instanceVariableNames: ''
 	package: 'Compiler-Inlining'!
@@ -163,12 +145,6 @@ assignmentInliner
 		yourself
 !
 
-nonLocalReturnInliner
-	^ IRNonLocalReturnInliner new
-		translator: self;
-		yourself
-!
-
 returnInliner
 	^ IRReturnInliner new
 		translator: self;
@@ -225,9 +201,7 @@ visitIRAssignment: anIRAssignment
 !
 
 visitIRNonLocalReturn: anIRNonLocalReturn
-	^ (self shouldInlineReturn: anIRNonLocalReturn)
-		ifTrue: [ self nonLocalReturnInliner inlineReturn: anIRNonLocalReturn ]
-		ifFalse: [ self transformNonLocalReturn: anIRNonLocalReturn ]
+	^ self transformNonLocalReturn: anIRNonLocalReturn
 !
 
 visitIRReturn: anIRReturn
@@ -422,6 +396,16 @@ inlineClosure: anIRClosure
 
 	"Add a block sequence"
 	sequence := self inlinedSequence.
+
+	"Map the closure arguments to the receiver of the message send"
+	anIRClosure arguments do: [ :each |
+		inlinedClosure add: (IRTempDeclaration new name: each; yourself).
+		sequence add: (IRAssignment new
+			add: (IRVariable new variable: (AliasVar new scope: inlinedClosure scope; name: each; yourself));
+			add: (IRVariable new variable: (AliasVar new scope: inlinedClosure scope; name: '$receiver'; yourself));
+			yourself) ].
+			
+	"To ensure the correct order of the closure instructions: first the temps then the sequence"
 	inlinedClosure add: sequence.
 
 	"Get all the statements"
@@ -466,15 +450,11 @@ inlinedSend: inlinedSend with: anIRInstruction with: anotherIRInstruction
 	| inlinedClosure1 inlinedClosure2 |
 
 	anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].
-	anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].
-
 	anotherIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].
-	anotherIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].
 
 	inlinedClosure1 := self translator visit: (self inlineClosure: anIRInstruction).
 	inlinedClosure2 := self translator visit: (self inlineClosure: anotherIRInstruction).
 
-
 	inlinedSend
 		add: self send instructions first;
 		add: inlinedClosure1;
@@ -554,34 +534,6 @@ inlineClosure: anIRClosure
 	^ inlinedClosure
 ! !
 
-IRSendInliner subclass: #IRNonLocalReturnInliner
-	instanceVariableNames: ''
-	package: 'Compiler-Inlining'!
-
-!IRNonLocalReturnInliner methodsFor: 'factory'!
-
-inlinedReturn
-	^ IRInlinedNonLocalReturn new
-! !
-
-!IRNonLocalReturnInliner methodsFor: 'inlining'!
-
-inlineClosure: anIRClosure
-	"| inlinedClosure statements |
-
-	inlinedClosure := super inlineClosure: anIRClosure.
-	statements := inlinedClosure instructions last instructions.
-	
-	statements ifNotEmpty: [
-		statements last replaceWith: (IRNonLocalReturn new
-			add: statements last copy;
-			yourself) ].
-
-	^ inlinedClosure"
-
-	^ super inlineCLosure: anIRClosure
-! !
-
 IRSendInliner subclass: #IRReturnInliner
 	instanceVariableNames: ''
 	package: 'Compiler-Inlining'!

+ 5 - 0
st/Compiler-Tests.st

@@ -421,6 +421,11 @@ testifNotNil
 	self should: 'foo nil ifNotNil: [ ^ 2 ]' return: receiver.
 !
 
+testifNotNilWithArgument
+	self should: 'foo ^ 1 ifNotNil: [ :val | val + 2 ]' return: 3.
+	self should: 'foo ^ nil ifNotNil: [ :val | val + 2 ]' return: nil
+!
+
 testifTrue
 	self should: 'foo false ifTrue: [ ^ 1 ]' return: receiver.
 	self should: 'foo true ifTrue: [ ^ 2 ]' return: 2.

+ 2 - 2
st/Kernel-Objects.st

@@ -270,12 +270,12 @@ ifNil: aBlock ifNotNil: anotherBlock
 
 ifNotNil: aBlock
 	"inlined in the Compiler"
-	^aBlock value
+	^aBlock value: self
 !
 
 ifNotNil: aBlock ifNil: anotherBlock
 	"inlined in the Compiler"
-	^aBlock value
+	^aBlock value: self
 !
 
 isBoolean