Browse Source

Merge branch 'master' into dag

# Conflicts:
#	src/Compiler-IR.js
#	src/Compiler-Inlining.js
#	src/Compiler-Inlining.st
Herbert Vojčík 7 years ago
parent
commit
857a7b941a
5 changed files with 162 additions and 429 deletions
  1. 1 0
      API-CHANGES.txt
  2. 33 206
      src/Compiler-IR.js
  3. 5 45
      src/Compiler-IR.st
  4. 96 149
      src/Compiler-Inlining.js
  5. 27 29
      src/Compiler-Inlining.st

+ 1 - 0
API-CHANGES.txt

@@ -1,6 +1,7 @@
 0.18.0:
 
 * Remove class RethrowErrorHandler (hack for cli before 0.12.3).
+* Some internal API changes in Compiler-*.
 
 - Object >>
   - throw:

+ 33 - 206
src/Compiler-IR.js

@@ -1121,24 +1121,6 @@ messageSends: ["parent:", "add:", "dagChildren"]
 }),
 $globals.IRInstruction);
 
-$core.addMethod(
-$core.method({
-selector: "canBeAssigned",
-protocol: 'testing',
-fn: function (){
-var self=this;
-return true;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "canBeAssigned\x0a\x09^ true",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.IRInstruction);
-
 $core.addMethod(
 $core.method({
 selector: "isClosure",
@@ -1175,24 +1157,6 @@ messageSends: []
 }),
 $globals.IRInstruction);
 
-$core.addMethod(
-$core.method({
-selector: "isLocalReturn",
-protocol: 'testing',
-fn: function (){
-var self=this;
-return false;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isLocalReturn\x0a\x09^ false",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.IRInstruction);
-
 $core.addMethod(
 $core.method({
 selector: "isMethod",
@@ -1211,24 +1175,6 @@ messageSends: []
 }),
 $globals.IRInstruction);
 
-$core.addMethod(
-$core.method({
-selector: "isReturn",
-protocol: 'testing',
-fn: function (){
-var self=this;
-return false;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isReturn\x0a\x09^ false",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.IRInstruction);
-
 $core.addMethod(
 $core.method({
 selector: "isSend",
@@ -1379,30 +1325,6 @@ messageSends: []
 }),
 $globals.IRInstruction);
 
-$core.addMethod(
-$core.method({
-selector: "remove",
-protocol: 'building',
-fn: function (){
-var self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-$recv(self._parent())._remove_(self);
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"remove",{},$globals.IRInstruction)});
-//>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "remove\x0a\x09self parent remove: self",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: ["remove:", "parent"]
-}),
-$globals.IRInstruction);
-
 $core.addMethod(
 $core.method({
 selector: "remove:",
@@ -1512,6 +1434,24 @@ messageSends: ["ifNotNil:", "parent", "scope"]
 }),
 $globals.IRInstruction);
 
+$core.addMethod(
+$core.method({
+selector: "yieldsValue",
+protocol: 'testing',
+fn: function (){
+var self=this;
+return true;
+
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "yieldsValue\x0a\x09^ true",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: []
+}),
+$globals.IRInstruction);
+
 
 $core.addMethod(
 $core.method({
@@ -2297,24 +2237,6 @@ messageSends: ["visitIRReturn:"]
 }),
 $globals.IRReturn);
 
-$core.addMethod(
-$core.method({
-selector: "canBeAssigned",
-protocol: 'testing',
-fn: function (){
-var self=this;
-return false;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "canBeAssigned\x0a\x09^ false",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.IRReturn);
-
 $core.addMethod(
 $core.method({
 selector: "expression",
@@ -2340,110 +2262,51 @@ $globals.IRReturn);
 
 $core.addMethod(
 $core.method({
-selector: "isBlockReturn",
-protocol: 'testing',
-fn: function (){
-var self=this;
-return false;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isBlockReturn\x0a\x09^ false",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.IRReturn);
-
-$core.addMethod(
-$core.method({
-selector: "isLocalReturn",
-protocol: 'testing',
-fn: function (){
-var self=this;
-return true;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isLocalReturn\x0a\x09^ true",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.IRReturn);
-
-$core.addMethod(
-$core.method({
-selector: "isNonLocalReturn",
-protocol: 'testing',
+selector: "scope",
+protocol: 'accessing',
 fn: function (){
 var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return $recv(self._isLocalReturn())._not();
+var $1,$receiver;
+$1=self["@scope"];
+if(($receiver = $1) == null || $receiver.isNil){
+return $recv(self._parent())._scope();
+} else {
+return $1;
+};
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"isNonLocalReturn",{},$globals.IRReturn)});
+}, function($ctx1) {$ctx1.fill(self,"scope",{},$globals.IRReturn)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "isNonLocalReturn\x0a\x09^ self isLocalReturn not",
+source: "scope\x0a\x09^ scope ifNil: [ self parent scope ]",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: ["not", "isLocalReturn"]
+messageSends: ["ifNil:", "scope", "parent"]
 }),
 $globals.IRReturn);
 
 $core.addMethod(
 $core.method({
-selector: "isReturn",
+selector: "yieldsValue",
 protocol: 'testing',
 fn: function (){
 var self=this;
-return true;
+return false;
 
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "isReturn\x0a\x09^ true",
+source: "yieldsValue\x0a\x09^ false",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: []
 }),
 $globals.IRReturn);
 
-$core.addMethod(
-$core.method({
-selector: "scope",
-protocol: 'accessing',
-fn: function (){
-var self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-var $1,$receiver;
-$1=self["@scope"];
-if(($receiver = $1) == null || $receiver.isNil){
-return $recv(self._parent())._scope();
-} else {
-return $1;
-};
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"scope",{},$globals.IRReturn)});
-//>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "scope\x0a\x09^ scope ifNil: [ self parent scope ]",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: ["ifNil:", "scope", "parent"]
-}),
-$globals.IRReturn);
-
 
 
 $core.addClass('IRBlockReturn', $globals.IRReturn, [], 'Compiler-IR');
@@ -2473,24 +2336,6 @@ messageSends: ["visitIRBlockReturn:"]
 }),
 $globals.IRBlockReturn);
 
-$core.addMethod(
-$core.method({
-selector: "isBlockReturn",
-protocol: 'testing',
-fn: function (){
-var self=this;
-return true;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isBlockReturn\x0a\x09^ true",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.IRBlockReturn);
-
 
 
 $core.addClass('IRNonLocalReturn', $globals.IRReturn, [], 'Compiler-IR');
@@ -2520,24 +2365,6 @@ messageSends: ["visitIRNonLocalReturn:"]
 }),
 $globals.IRNonLocalReturn);
 
-$core.addMethod(
-$core.method({
-selector: "isLocalReturn",
-protocol: 'testing',
-fn: function (){
-var self=this;
-return false;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isLocalReturn\x0a\x09^ false",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.IRNonLocalReturn);
-
 
 
 $core.addClass('IRTempDeclaration', $globals.IRScopedInstruction, ['name'], 'Compiler-IR');

+ 5 - 45
src/Compiler-IR.st

@@ -288,10 +288,6 @@ add: anObject
 	^ self dagChildren add: anObject
 !
 
-remove
-	self parent remove: self
-!
-
 remove: anIRInstruction
 	self dagChildren remove: anIRInstruction
 !
@@ -309,10 +305,6 @@ replaceWith: anIRInstruction
 
 !IRInstruction methodsFor: 'testing'!
 
-canBeAssigned
-	^ true
-!
-
 isClosure
 	^ false
 !
@@ -321,18 +313,10 @@ isInlined
 	^ false
 !
 
-isLocalReturn
-	^ false
-!
-
 isMethod
 	^ false
 !
 
-isReturn
-	^ false
-!
-
 isSend
 	^ false
 !
@@ -351,6 +335,10 @@ isVariable
 
 needsBoxingAsReceiver
 	^ true
+!
+
+yieldsValue
+	^ true
 ! !
 
 !IRInstruction class methodsFor: 'instance creation'!
@@ -565,24 +553,8 @@ scope
 
 !IRReturn methodsFor: 'testing'!
 
-canBeAssigned
-	^ false
-!
-
-isBlockReturn
+yieldsValue
 	^ false
-!
-
-isLocalReturn
-	^ true
-!
-
-isNonLocalReturn
-	^ self isLocalReturn not
-!
-
-isReturn
-	^ true
 ! !
 
 !IRReturn methodsFor: 'visiting'!
@@ -597,12 +569,6 @@ IRReturn subclass: #IRBlockReturn
 !IRBlockReturn commentStamp!
 Smalltalk blocks return their last statement. I am a implicit block return instruction.!
 
-!IRBlockReturn methodsFor: 'testing'!
-
-isBlockReturn
-	^ true
-! !
-
 !IRBlockReturn methodsFor: 'visiting'!
 
 acceptDagVisitor: aVisitor
@@ -618,12 +584,6 @@ Non local returns are handled using a try/catch JavaScript statement.
 
 See `IRNonLocalReturnHandling` class.!
 
-!IRNonLocalReturn methodsFor: 'testing'!
-
-isLocalReturn
-	^ false
-! !
-
 !IRNonLocalReturn methodsFor: 'visiting'!
 
 acceptDagVisitor: aVisitor

+ 96 - 149
src/Compiler-Inlining.js

@@ -665,7 +665,43 @@ $globals.IRInliner);
 
 $core.addMethod(
 $core.method({
-selector: "transformNonLocalReturn:",
+selector: "visitIRAssignment:",
+protocol: 'visiting',
+fn: function (anIRAssignment){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1;
+$1=self._shouldInlineAssignment_(anIRAssignment);
+if($core.assert($1)){
+return $recv(self._assignmentInliner())._inlineAssignment_(anIRAssignment);
+} else {
+return (
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.supercall = true,
+//>>excludeEnd("ctx");
+($globals.IRInliner.superclass||$boot.nilAsClass).fn.prototype._visitIRAssignment_.apply($recv(self), [anIRAssignment]));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.supercall = false;
+//>>excludeEnd("ctx");;
+};
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"visitIRAssignment:",{anIRAssignment:anIRAssignment},$globals.IRInliner)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["anIRAssignment"],
+source: "visitIRAssignment: anIRAssignment\x0a\x09^ (self shouldInlineAssignment: anIRAssignment)\x0a\x09\x09ifTrue: [ self assignmentInliner inlineAssignment: anIRAssignment ]\x0a\x09\x09ifFalse: [ super visitIRAssignment: anIRAssignment ]",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["ifTrue:ifFalse:", "shouldInlineAssignment:", "inlineAssignment:", "assignmentInliner", "visitIRAssignment:"]
+}),
+$globals.IRInliner);
+
+$core.addMethod(
+$core.method({
+selector: "visitIRNonLocalReturn:",
 protocol: 'visiting',
 fn: function (anIRNonLocalReturn){
 var self=this;
@@ -716,77 +752,18 @@ $ctx1.supercall = false;
 //>>excludeEnd("ctx");;
 return $7;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"transformNonLocalReturn:",{anIRNonLocalReturn:anIRNonLocalReturn,localReturn:localReturn},$globals.IRInliner)});
+}, function($ctx1) {$ctx1.fill(self,"visitIRNonLocalReturn:",{anIRNonLocalReturn:anIRNonLocalReturn,localReturn:localReturn},$globals.IRInliner)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anIRNonLocalReturn"],
-source: "transformNonLocalReturn: anIRNonLocalReturn\x0a\x09\x22Replace a non local return into a local return\x22\x0a\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 dagChildren do: [ :each |\x0a\x09\x09\x09localReturn add: each ].\x0a\x09\x09anIRNonLocalReturn replaceWith: localReturn.\x0a\x09\x09^ localReturn ].\x0a\x09^ super visitIRNonLocalReturn: anIRNonLocalReturn",
+source: "visitIRNonLocalReturn: 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 dagChildren do: [ :each |\x0a\x09\x09\x09localReturn add: each ].\x0a\x09\x09anIRNonLocalReturn replaceWith: localReturn.\x0a\x09\x09^ localReturn ].\x0a\x09^ super visitIRNonLocalReturn: anIRNonLocalReturn",
 referencedClasses: ["IRReturn"],
 //>>excludeEnd("ide");
 messageSends: ["ifTrue:", "canInlineNonLocalReturns", "scope", "removeNonLocalReturn:", "methodScope", "scope:", "new", "yourself", "do:", "dagChildren", "add:", "replaceWith:", "visitIRNonLocalReturn:"]
 }),
 $globals.IRInliner);
 
-$core.addMethod(
-$core.method({
-selector: "visitIRAssignment:",
-protocol: 'visiting',
-fn: function (anIRAssignment){
-var self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-var $1;
-$1=self._shouldInlineAssignment_(anIRAssignment);
-if($core.assert($1)){
-return $recv(self._assignmentInliner())._inlineAssignment_(anIRAssignment);
-} else {
-return (
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = true,
-//>>excludeEnd("ctx");
-($globals.IRInliner.superclass||$boot.nilAsClass).fn.prototype._visitIRAssignment_.apply($recv(self), [anIRAssignment]));
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
-};
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"visitIRAssignment:",{anIRAssignment:anIRAssignment},$globals.IRInliner)});
-//>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["anIRAssignment"],
-source: "visitIRAssignment: anIRAssignment\x0a\x09^ (self shouldInlineAssignment: anIRAssignment)\x0a\x09\x09ifTrue: [ self assignmentInliner inlineAssignment: anIRAssignment ]\x0a\x09\x09ifFalse: [ super visitIRAssignment: anIRAssignment ]",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: ["ifTrue:ifFalse:", "shouldInlineAssignment:", "inlineAssignment:", "assignmentInliner", "visitIRAssignment:"]
-}),
-$globals.IRInliner);
-
-$core.addMethod(
-$core.method({
-selector: "visitIRNonLocalReturn:",
-protocol: 'visiting',
-fn: function (anIRNonLocalReturn){
-var self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-return self._transformNonLocalReturn_(anIRNonLocalReturn);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"visitIRNonLocalReturn:",{anIRNonLocalReturn:anIRNonLocalReturn},$globals.IRInliner)});
-//>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["anIRNonLocalReturn"],
-source: "visitIRNonLocalReturn: anIRNonLocalReturn\x0a\x09^ self transformNonLocalReturn: anIRNonLocalReturn",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: ["transformNonLocalReturn:"]
-}),
-$globals.IRInliner);
-
 $core.addMethod(
 $core.method({
 selector: "visitIRReturn:",
@@ -1218,46 +1195,6 @@ messageSends: ["nextPutIf:then:else:", "stream", "nextPutAll:", "visit:", "first
 }),
 $globals.IRInliningJSTranslator);
 
-$core.addMethod(
-$core.method({
-selector: "visitIRInlinedNonLocalReturn:",
-protocol: 'visiting',
-fn: function (anIRInlinedReturn){
-var self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-var $1;
-$1=self._stream();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["stream"]=1;
-//>>excludeEnd("ctx");
-$recv($1)._nextPutStatementWith_((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return self._visit_($recv(anIRInlinedReturn)._expression());
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
-$recv(self._stream())._nextPutNonLocalReturnWith_((function(){
-
-}));
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"visitIRInlinedNonLocalReturn:",{anIRInlinedReturn:anIRInlinedReturn},$globals.IRInliningJSTranslator)});
-//>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["anIRInlinedReturn"],
-source: "visitIRInlinedNonLocalReturn: anIRInlinedReturn\x0a\x09self stream nextPutStatementWith: [\x0a\x09\x09self visit: anIRInlinedReturn expression ].\x0a\x09self stream nextPutNonLocalReturnWith: [ ]",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: ["nextPutStatementWith:", "stream", "visit:", "expression", "nextPutNonLocalReturnWith:"]
-}),
-$globals.IRInliningJSTranslator);
-
 $core.addMethod(
 $core.method({
 selector: "visitIRInlinedReturn:",
@@ -1566,7 +1503,7 @@ var inlinedClosure,sequence,statements;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2,$3,$5,$6,$4,$7,$9,$11,$13,$14,$15,$12,$10,$17,$19,$20,$18,$16,$8,$23,$22,$24,$21,$25,$27,$26;
+var $1,$2,$3,$5,$6,$4,$7,$9,$11,$13,$14,$15,$12,$10,$17,$19,$20,$18,$16,$8;
 inlinedClosure=self._inlinedClosure();
 $1=inlinedClosure;
 $2=$recv(anIRClosure)._scope();
@@ -1704,38 +1641,7 @@ $ctx3.sendIdx["add:"]=7;
 }, function($ctx3) {$ctx3.fillBlock({each:each},$ctx2,4)});
 //>>excludeEnd("ctx");
 }));
-$23=$recv(statements)._last();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["last"]=1;
-//>>excludeEnd("ctx");
-$22=$recv($23)._isReturn();
-$21=$recv($22)._and_((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx3) {
-//>>excludeEnd("ctx");
-$24=$recv(statements)._last();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx3.sendIdx["last"]=2;
-//>>excludeEnd("ctx");
-return $recv($24)._isBlockReturn();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,5)});
-//>>excludeEnd("ctx");
-}));
-if($core.assert($21)){
-$25=sequence;
-$27=$recv(statements)._last();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["last"]=3;
-//>>excludeEnd("ctx");
-$26=$recv($27)._expression();
-return $recv($25)._add_($26);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["add:"]=8;
-//>>excludeEnd("ctx");
-} else {
-return $recv(sequence)._add_($recv(statements)._last());
-};
+return $recv(sequence)._add_($recv($recv(statements)._last())._asInlinedBlockResult());
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)});
 //>>excludeEnd("ctx");
@@ -1747,10 +1653,10 @@ return inlinedClosure;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anIRClosure"],
-source: "inlineClosure: anIRClosure\x0a\x09| inlinedClosure sequence statements |\x0a\x0a\x09inlinedClosure := self inlinedClosure.\x0a\x09inlinedClosure \x0a\x09\x09scope: anIRClosure scope;\x0a\x09\x09parent: anIRClosure parent.\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 sequence dagChildren.\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 expression ]\x0a\x09\x09\x09ifFalse: [ sequence add: statements last ] ].\x0a\x0a\x09^ inlinedClosure",
+source: "inlineClosure: anIRClosure\x0a\x09| inlinedClosure sequence statements |\x0a\x0a\x09inlinedClosure := self inlinedClosure.\x0a\x09inlinedClosure \x0a\x09\x09scope: anIRClosure scope;\x0a\x09\x09parent: anIRClosure parent.\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 sequence dagChildren.\x0a\x09\x0a\x09statements ifNotEmpty: [\x0a\x09\x09statements allButLast do: [ :each | sequence add: each ].\x0a\x0a\x09\x09\x22Inlined closures change local returns into result value itself\x22\x0a\x09\x09sequence add: statements last asInlinedBlockResult ].\x0a\x0a\x09^ inlinedClosure",
 referencedClasses: ["IRTempDeclaration", "IRAssignment", "IRVariable", "AliasVar"],
 //>>excludeEnd("ide");
-messageSends: ["inlinedClosure", "scope:", "scope", "parent:", "parent", "do:", "tempDeclarations", "add:", "inlinedSequence", "arguments", "name:", "new", "yourself", "variable:", "dagChildren", "sequence", "ifNotEmpty:", "allButLast", "ifTrue:ifFalse:", "and:", "isReturn", "last", "isBlockReturn", "expression"]
+messageSends: ["inlinedClosure", "scope:", "scope", "parent:", "parent", "do:", "tempDeclarations", "add:", "inlinedSequence", "arguments", "name:", "new", "yourself", "variable:", "dagChildren", "sequence", "ifNotEmpty:", "allButLast", "asInlinedBlockResult", "last"]
 }),
 $globals.IRSendInliner);
 
@@ -2193,12 +2099,12 @@ selector: "inlineClosure:",
 protocol: 'inlining',
 fn: function (anIRClosure){
 var self=this;
-var inlinedClosure,statements;
+var closure,statements;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 var $2,$1,$3,$5,$4;
-inlinedClosure=(
+closure=(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
 //>>excludeEnd("ctx");
@@ -2206,7 +2112,7 @@ $ctx1.supercall = true,
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = false;
 //>>excludeEnd("ctx");;
-statements=$recv($recv(inlinedClosure)._sequence())._dagChildren();
+statements=$recv($recv(closure)._sequence())._dagChildren();
 $recv(statements)._ifNotEmpty_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
@@ -2215,7 +2121,7 @@ $2=$recv(statements)._last();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx2.sendIdx["last"]=1;
 //>>excludeEnd("ctx");
-$1=$recv($2)._canBeAssigned();
+$1=$recv($2)._yieldsValue();
 if($core.assert($1)){
 $3=$recv(statements)._last();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -2234,17 +2140,17 @@ return $recv($3)._replaceWith_($4);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
 }));
-return inlinedClosure;
+return closure;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"inlineClosure:",{anIRClosure:anIRClosure,inlinedClosure:inlinedClosure,statements:statements},$globals.IRAssignmentInliner)});
+}, function($ctx1) {$ctx1.fill(self,"inlineClosure:",{anIRClosure:anIRClosure,closure:closure,statements:statements},$globals.IRAssignmentInliner)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anIRClosure"],
-source: "inlineClosure: anIRClosure\x0a\x09| inlinedClosure statements |\x0a\x0a\x09inlinedClosure := super inlineClosure: anIRClosure.\x0a\x09statements := inlinedClosure sequence dagChildren.\x0a\x09\x0a\x09statements ifNotEmpty: [\x0a\x09\x09statements last canBeAssigned ifTrue: [\x0a\x09\x09\x09statements last replaceWith: (IRAssignment new\x0a\x09\x09\x09\x09add: self assignment left;\x0a\x09\x09\x09\x09add: statements last copy;\x0a\x09\x09\x09\x09yourself) ] ].\x0a\x0a\x09^ inlinedClosure",
+source: "inlineClosure: anIRClosure\x0a\x09| closure statements |\x0a\x0a\x09closure := super inlineClosure: anIRClosure.\x0a\x09statements := closure sequence dagChildren.\x0a\x09\x0a\x09statements ifNotEmpty: [\x0a\x09\x09statements last yieldsValue ifTrue: [\x0a\x09\x09\x09statements last replaceWith: (IRAssignment new\x0a\x09\x09\x09\x09add: self assignment left;\x0a\x09\x09\x09\x09add: statements last copy;\x0a\x09\x09\x09\x09yourself) ] ].\x0a\x0a\x09^ closure",
 referencedClasses: ["IRAssignment"],
 //>>excludeEnd("ide");
-messageSends: ["inlineClosure:", "dagChildren", "sequence", "ifNotEmpty:", "ifTrue:", "canBeAssigned", "last", "replaceWith:", "add:", "new", "left", "assignment", "copy", "yourself"]
+messageSends: ["inlineClosure:", "dagChildren", "sequence", "ifNotEmpty:", "ifTrue:", "yieldsValue", "last", "replaceWith:", "add:", "new", "left", "assignment", "copy", "yourself"]
 }),
 $globals.IRAssignmentInliner);
 
@@ -2282,8 +2188,8 @@ $2=$recv(statements)._last();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx2.sendIdx["last"]=1;
 //>>excludeEnd("ctx");
-$1=$recv($2)._isReturn();
-if(!$core.assert($1)){
+$1=$recv($2)._yieldsValue();
+if($core.assert($1)){
 $3=$recv(statements)._last();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx2.sendIdx["last"]=2;
@@ -2304,10 +2210,10 @@ return closure;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anIRClosure"],
-source: "inlineClosure: anIRClosure\x0a\x09| closure statements |\x0a\x0a\x09closure := super inlineClosure: anIRClosure.\x0a\x09statements := closure sequence dagChildren.\x0a\x09\x0a\x09statements ifNotEmpty: [\x0a\x09\x09statements last isReturn\x0a\x09\x09\x09ifFalse: [ statements last replaceWith: (IRReturn new\x0a\x09\x09\x09\x09add: statements last copy;\x0a\x09\x09\x09\x09yourself)] ].\x0a\x0a\x09^ closure",
+source: "inlineClosure: anIRClosure\x0a\x09| closure statements |\x0a\x0a\x09closure := super inlineClosure: anIRClosure.\x0a\x09statements := closure sequence dagChildren.\x0a\x09\x0a\x09statements ifNotEmpty: [\x0a\x09\x09statements last yieldsValue ifTrue: [\x0a\x09\x09\x09statements last replaceWith: (IRReturn new\x0a\x09\x09\x09\x09add: statements last copy;\x0a\x09\x09\x09\x09yourself)] ].\x0a\x0a\x09^ closure",
 referencedClasses: ["IRReturn"],
 //>>excludeEnd("ide");
-messageSends: ["inlineClosure:", "dagChildren", "sequence", "ifNotEmpty:", "ifFalse:", "isReturn", "last", "replaceWith:", "add:", "new", "copy", "yourself"]
+messageSends: ["inlineClosure:", "dagChildren", "sequence", "ifNotEmpty:", "ifTrue:", "yieldsValue", "last", "replaceWith:", "add:", "new", "copy", "yourself"]
 }),
 $globals.IRReturnInliner);
 
@@ -2469,4 +2375,45 @@ $core.addClass('InliningError', $globals.SemanticError, [], 'Compiler-Inlining')
 $globals.InliningError.comment="Instances of InliningError are signaled when using an `InliningCodeGenerator`in a `Compiler`.";
 //>>excludeEnd("ide");
 
+$core.addMethod(
+$core.method({
+selector: "asInlinedBlockResult",
+protocol: '*Compiler-Inlining',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return self._expression();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"asInlinedBlockResult",{},$globals.IRBlockReturn)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "asInlinedBlockResult\x0a\x09^ self expression",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["expression"]
+}),
+$globals.IRBlockReturn);
+
+$core.addMethod(
+$core.method({
+selector: "asInlinedBlockResult",
+protocol: '*Compiler-Inlining',
+fn: function (){
+var self=this;
+return self;
+
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "asInlinedBlockResult\x0a\x09^ self",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: []
+}),
+$globals.IRInstruction);
+
 });

+ 27 - 29
src/Compiler-Inlining.st

@@ -211,9 +211,13 @@ shouldInlineSend: anIRSend
 
 !IRInliner methodsFor: 'visiting'!
 
-transformNonLocalReturn: anIRNonLocalReturn
-	"Replace a non local return into a local return"
+visitIRAssignment: anIRAssignment
+	^ (self shouldInlineAssignment: anIRAssignment)
+		ifTrue: [ self assignmentInliner inlineAssignment: anIRAssignment ]
+		ifFalse: [ super visitIRAssignment: anIRAssignment ]
+!
 
+visitIRNonLocalReturn: anIRNonLocalReturn
 	| localReturn |
 	anIRNonLocalReturn scope canInlineNonLocalReturns ifTrue: [
 		anIRNonLocalReturn scope methodScope removeNonLocalReturn: anIRNonLocalReturn scope.
@@ -227,16 +231,6 @@ transformNonLocalReturn: anIRNonLocalReturn
 	^ super visitIRNonLocalReturn: anIRNonLocalReturn
 !
 
-visitIRAssignment: anIRAssignment
-	^ (self shouldInlineAssignment: anIRAssignment)
-		ifTrue: [ self assignmentInliner inlineAssignment: anIRAssignment ]
-		ifFalse: [ super visitIRAssignment: anIRAssignment ]
-!
-
-visitIRNonLocalReturn: anIRNonLocalReturn
-	^ self transformNonLocalReturn: anIRNonLocalReturn
-!
-
 visitIRReturn: anIRReturn
 	^ (self shouldInlineReturn: anIRReturn)
 		ifTrue: [ self returnInliner inlineReturn: anIRReturn ]
@@ -305,12 +299,6 @@ visitIRInlinedIfTrueIfFalse: anIRInlinedIfTrueIfFalse
 		else: [ self visit: anIRInlinedIfTrueIfFalse dagChildren third ]
 !
 
-visitIRInlinedNonLocalReturn: anIRInlinedReturn
-	self stream nextPutStatementWith: [
-		self visit: anIRInlinedReturn expression ].
-	self stream nextPutNonLocalReturnWith: [ ]
-!
-
 visitIRInlinedReturn: anIRInlinedReturn
 	self visit: anIRInlinedReturn expression
 !
@@ -442,10 +430,8 @@ inlineClosure: anIRClosure
 	statements ifNotEmpty: [
 		statements allButLast do: [ :each | sequence add: each ].
 
-		"Inlined closures don't have implicit local returns"
-		(statements last isReturn and: [ statements last isBlockReturn ])
-			ifTrue: [ sequence add: statements last expression ]
-			ifFalse: [ sequence add: statements last ] ].
+		"Inlined closures change local returns into result value itself"
+		sequence add: statements last asInlinedBlockResult ].
 
 	^ inlinedClosure
 !
@@ -550,19 +536,19 @@ inlineAssignment: anIRAssignment
 !
 
 inlineClosure: anIRClosure
-	| inlinedClosure statements |
+	| closure statements |
 
-	inlinedClosure := super inlineClosure: anIRClosure.
-	statements := inlinedClosure sequence dagChildren.
+	closure := super inlineClosure: anIRClosure.
+	statements := closure sequence dagChildren.
 	
 	statements ifNotEmpty: [
-		statements last canBeAssigned ifTrue: [
+		statements last yieldsValue ifTrue: [
 			statements last replaceWith: (IRAssignment new
 				add: self assignment left;
 				add: statements last copy;
 				yourself) ] ].
 
-	^ inlinedClosure
+	^ closure
 ! !
 
 IRSendInliner subclass: #IRReturnInliner
@@ -586,8 +572,8 @@ inlineClosure: anIRClosure
 	statements := closure sequence dagChildren.
 	
 	statements ifNotEmpty: [
-		statements last isReturn
-			ifFalse: [ statements last replaceWith: (IRReturn new
+		statements last yieldsValue ifTrue: [
+			statements last replaceWith: (IRReturn new
 				add: statements last copy;
 				yourself)] ].
 
@@ -639,3 +625,15 @@ SemanticError subclass: #InliningError
 !InliningError commentStamp!
 Instances of InliningError are signaled when using an `InliningCodeGenerator`in a `Compiler`.!
 
+!IRBlockReturn methodsFor: '*Compiler-Inlining'!
+
+asInlinedBlockResult
+	^ self expression
+! !
+
+!IRInstruction methodsFor: '*Compiler-Inlining'!
+
+asInlinedBlockResult
+	^ self
+! !
+