| OLD | NEW | 
|---|
| 1 // Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file | 
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a | 
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. | 
| 4 | 4 | 
| 5 import '../closure.dart'; | 5 import '../closure.dart'; | 
| 6 import '../common.dart'; | 6 import '../common.dart'; | 
| 7 import '../elements/elements.dart'; | 7 import '../elements/elements.dart'; | 
| 8 import '../elements/entities.dart'; | 8 import '../elements/entities.dart'; | 
| 9 import '../elements/types.dart'; | 9 import '../elements/types.dart'; | 
| 10 import '../io/source_information.dart'; | 10 import '../io/source_information.dart'; | 
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 129   } | 129   } | 
| 130 | 130 | 
| 131   HInstruction createBox() { | 131   HInstruction createBox() { | 
| 132     HInstruction box = new HCreateBox(commonMasks.nonNullType); | 132     HInstruction box = new HCreateBox(commonMasks.nonNullType); | 
| 133     builder.add(box); | 133     builder.add(box); | 
| 134     return box; | 134     return box; | 
| 135   } | 135   } | 
| 136 | 136 | 
| 137   /// If the scope (function or loop) [node] has captured variables then this | 137   /// If the scope (function or loop) [node] has captured variables then this | 
| 138   /// method creates a box and sets up the redirections. | 138   /// method creates a box and sets up the redirections. | 
| 139   void enterScope(ClosureScope scopeData, | 139   void enterScope(ClosureAnalysisInfo closureInfo, | 
| 140       {bool forGenerativeConstructorBody: false}) { | 140       {bool forGenerativeConstructorBody: false}) { | 
| 141     // See if any variable in the top-scope of the function is captured. If yes | 141     // See if any variable in the top-scope of the function is captured. If yes | 
| 142     // we need to create a box-object. | 142     // we need to create a box-object. | 
| 143     if (scopeData == null) return; | 143     if (!closureInfo.requiresContextBox()) return; | 
| 144     HInstruction box; | 144     HInstruction box; | 
| 145     // The scope has captured variables. | 145     // The scope has captured variables. | 
| 146     if (forGenerativeConstructorBody) { | 146     if (forGenerativeConstructorBody) { | 
| 147       // The box is passed as a parameter to a generative | 147       // The box is passed as a parameter to a generative | 
| 148       // constructor body. | 148       // constructor body. | 
| 149       box = builder.addParameter(scopeData.boxElement, commonMasks.nonNullType); | 149       box = builder.addParameter(closureInfo.context, commonMasks.nonNullType); | 
| 150     } else { | 150     } else { | 
| 151       box = createBox(); | 151       box = createBox(); | 
| 152     } | 152     } | 
| 153     // Add the box to the known locals. | 153     // Add the box to the known locals. | 
| 154     directLocals[scopeData.boxElement] = box; | 154     directLocals[closureInfo.context] = box; | 
| 155     // Make sure that accesses to the boxed locals go into the box. We also | 155     // Make sure that accesses to the boxed locals go into the box. We also | 
| 156     // need to make sure that parameters are copied into the box if necessary. | 156     // need to make sure that parameters are copied into the box if necessary. | 
| 157     scopeData.forEachCapturedVariable( | 157     closureInfo.forEachCapturedVariable( | 
| 158         (LocalVariableElement from, BoxFieldElement to) { | 158         (LocalVariableElement from, BoxFieldElement to) { | 
| 159       // The [from] can only be a parameter for function-scopes and not | 159       // The [from] can only be a parameter for function-scopes and not | 
| 160       // loop scopes. | 160       // loop scopes. | 
| 161       if (from.isRegularParameter && !forGenerativeConstructorBody) { | 161       if (from.isRegularParameter && !forGenerativeConstructorBody) { | 
| 162         // Now that the redirection is set up, the update to the local will | 162         // Now that the redirection is set up, the update to the local will | 
| 163         // write the parameter value into the box. | 163         // write the parameter value into the box. | 
| 164         // Store the captured parameter in the box. Get the current value | 164         // Store the captured parameter in the box. Get the current value | 
| 165         // before we put the redirection in place. | 165         // before we put the redirection in place. | 
| 166         // We don't need to update the local for a generative | 166         // We don't need to update the local for a generative | 
| 167         // constructor body, because it receives a box that already | 167         // constructor body, because it receives a box that already | 
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 209           // The parameter will be a field in the box passed as the | 209           // The parameter will be a field in the box passed as the | 
| 210           // last parameter. So no need to have it. | 210           // last parameter. So no need to have it. | 
| 211           return; | 211           return; | 
| 212         } | 212         } | 
| 213       } | 213       } | 
| 214       HInstruction parameter = builder.addParameter(local, typeMask); | 214       HInstruction parameter = builder.addParameter(local, typeMask); | 
| 215       builder.parameters[local] = parameter; | 215       builder.parameters[local] = parameter; | 
| 216       directLocals[local] = parameter; | 216       directLocals[local] = parameter; | 
| 217     }); | 217     }); | 
| 218 | 218 | 
| 219     enterScope(scopeData, | 219     if (scopeData != null) { | 
| 220         forGenerativeConstructorBody: isGenerativeConstructorBody); | 220       // TODO(efortuna): Remove the above if wrapper (always execute this step) | 
|  | 221       // when the switch away from ClosureClassMap is complete (prior behavior | 
|  | 222       // in enterScope it was acceptable to pass in a null scopeData, but no | 
|  | 223       // longer). | 
|  | 224       enterScope(scopeData, | 
|  | 225           forGenerativeConstructorBody: isGenerativeConstructorBody); | 
|  | 226     } | 
| 221 | 227 | 
| 222     // If the freeVariableMapping is not empty, then this function was a | 228     // If the freeVariableMapping is not empty, then this function was a | 
| 223     // nested closure that captures variables. Redirect the captured | 229     // nested closure that captures variables. Redirect the captured | 
| 224     // variables to fields in the closure. | 230     // variables to fields in the closure. | 
| 225     closureData.forEachFreeVariable((Local from, FieldEntity to) { | 231     closureData.forEachFreeVariable((Local from, FieldEntity to) { | 
| 226       redirectElement(from, to); | 232       redirectElement(from, to); | 
| 227     }); | 233     }); | 
| 228     if (closureData.isClosure) { | 234     if (closureData.isClosure) { | 
| 229       // Inside closure redirect references to itself to [:this:]. | 235       // Inside closure redirect references to itself to [:this:]. | 
| 230       HThis thisInstruction = | 236       HThis thisInstruction = | 
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 466   /// We solve this by emitting the following code (only for [ast.For] loops): | 472   /// We solve this by emitting the following code (only for [ast.For] loops): | 
| 467   ///  <Create box>    <== move the first box creation outside the loop. | 473   ///  <Create box>    <== move the first box creation outside the loop. | 
| 468   ///  <initializer>; | 474   ///  <initializer>; | 
| 469   ///  loop-entry: | 475   ///  loop-entry: | 
| 470   ///    if (!<condition>) goto loop-exit; | 476   ///    if (!<condition>) goto loop-exit; | 
| 471   ///    <body> | 477   ///    <body> | 
| 472   ///    <update box>  // create a new box and copy the captured loop-variables. | 478   ///    <update box>  // create a new box and copy the captured loop-variables. | 
| 473   ///    <updates> | 479   ///    <updates> | 
| 474   ///    goto loop-entry; | 480   ///    goto loop-entry; | 
| 475   ///  loop-exit: | 481   ///  loop-exit: | 
| 476   void startLoop(ast.Node node) { | 482   void startLoop(LoopClosureRepresentationInfo loopInfo) { | 
| 477     ClosureScope scopeData = closureData.capturingScopes[node]; | 483     if (loopInfo.hasBoxedVariables) { | 
| 478     if (scopeData == null) return; |  | 
| 479     if (scopeData.hasBoxedLoopVariables()) { |  | 
| 480       // If there are boxed loop variables then we set up the box and | 484       // If there are boxed loop variables then we set up the box and | 
| 481       // redirections already now. This way the initializer can write its | 485       // redirections already now. This way the initializer can write its | 
| 482       // values into the box. | 486       // values into the box. | 
| 483       // For other loops the box will be created when entering the body. | 487       // For other loops the box will be created when entering the body. | 
| 484       enterScope(scopeData); | 488       enterScope(loopInfo); | 
| 485     } | 489     } | 
| 486   } | 490   } | 
| 487 | 491 | 
| 488   /// Create phis at the loop entry for local variables (ready for the values | 492   /// Create phis at the loop entry for local variables (ready for the values | 
| 489   /// from the back edge).  Populate the phis with the current values. | 493   /// from the back edge).  Populate the phis with the current values. | 
| 490   void beginLoopHeader(HBasicBlock loopEntry) { | 494   void beginLoopHeader(HBasicBlock loopEntry) { | 
| 491     // Create a copy because we modify the map while iterating over it. | 495     // Create a copy because we modify the map while iterating over it. | 
| 492     Map<Local, HInstruction> savedDirectLocals = | 496     Map<Local, HInstruction> savedDirectLocals = | 
| 493         new Map<Local, HInstruction>.from(directLocals); | 497         new Map<Local, HInstruction>.from(directLocals); | 
| 494 | 498 | 
| 495     // Create phis for all elements in the definitions environment. | 499     // Create phis for all elements in the definitions environment. | 
| 496     savedDirectLocals.forEach((Local local, HInstruction instruction) { | 500     savedDirectLocals.forEach((Local local, HInstruction instruction) { | 
| 497       if (isAccessedDirectly(local)) { | 501       if (isAccessedDirectly(local)) { | 
| 498         // We know 'this' cannot be modified. | 502         // We know 'this' cannot be modified. | 
| 499         if (local != closureData.thisLocal) { | 503         if (local != closureData.thisLocal) { | 
| 500           HPhi phi = | 504           HPhi phi = | 
| 501               new HPhi.singleInput(local, instruction, commonMasks.dynamicType); | 505               new HPhi.singleInput(local, instruction, commonMasks.dynamicType); | 
| 502           loopEntry.addPhi(phi); | 506           loopEntry.addPhi(phi); | 
| 503           directLocals[local] = phi; | 507           directLocals[local] = phi; | 
| 504         } else { | 508         } else { | 
| 505           directLocals[local] = instruction; | 509           directLocals[local] = instruction; | 
| 506         } | 510         } | 
| 507       } | 511       } | 
| 508     }); | 512     }); | 
| 509   } | 513   } | 
| 510 | 514 | 
| 511   void enterLoopBody(ast.Node node) { | 515   void enterLoopBody(LoopClosureRepresentationInfo loopInfo) { | 
| 512     ClosureScope scopeData = closureData.capturingScopes[node]; |  | 
| 513     if (scopeData == null) return; |  | 
| 514     // If there are no declared boxed loop variables then we did not create the | 516     // If there are no declared boxed loop variables then we did not create the | 
| 515     // box before the initializer and we have to create the box now. | 517     // box before the initializer and we have to create the box now. | 
| 516     if (!scopeData.hasBoxedLoopVariables()) { | 518     if (!loopInfo.hasBoxedVariables) { | 
| 517       enterScope(scopeData); | 519       enterScope(loopInfo); | 
| 518     } | 520     } | 
| 519   } | 521   } | 
| 520 | 522 | 
| 521   void enterLoopUpdates(ast.Node node) { | 523   void enterLoopUpdates(LoopClosureRepresentationInfo loopInfo) { | 
| 522     // If there are declared boxed loop variables then the updates might have | 524     // If there are declared boxed loop variables then the updates might have | 
| 523     // access to the box and we must switch to a new box before executing the | 525     // access to the box and we must switch to a new box before executing the | 
| 524     // updates. | 526     // updates. | 
| 525     // In all other cases a new box will be created when entering the body of | 527     // In all other cases a new box will be created when entering the body of | 
| 526     // the next iteration. | 528     // the next iteration. | 
| 527     ClosureScope scopeData = closureData.capturingScopes[node]; | 529     if (loopInfo.hasBoxedVariables) { | 
| 528     if (scopeData == null) return; | 530       updateCaptureBox(loopInfo.context, loopInfo.boxedVariables); | 
| 529     if (scopeData.hasBoxedLoopVariables()) { |  | 
| 530       updateCaptureBox(scopeData.boxElement, scopeData.boxedLoopVariables); |  | 
| 531     } | 531     } | 
| 532   } | 532   } | 
| 533 | 533 | 
| 534   /// Goes through the phis created in beginLoopHeader entry and adds the | 534   /// Goes through the phis created in beginLoopHeader entry and adds the | 
| 535   /// input from the back edge (from the current value of directLocals) to them. | 535   /// input from the back edge (from the current value of directLocals) to them. | 
| 536   void endLoop(HBasicBlock loopEntry) { | 536   void endLoop(HBasicBlock loopEntry) { | 
| 537     // If the loop has an aborting body, we don't update the loop | 537     // If the loop has an aborting body, we don't update the loop | 
| 538     // phis. | 538     // phis. | 
| 539     if (loopEntry.predecessors.length == 1) return; | 539     if (loopEntry.predecessors.length == 1) return; | 
| 540     loopEntry.forEachPhi((HPhi phi) { | 540     loopEntry.forEachPhi((HPhi phi) { | 
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 676   final MemberEntity memberContext; | 676   final MemberEntity memberContext; | 
| 677 | 677 | 
| 678   // Avoid slow Object.hashCode. | 678   // Avoid slow Object.hashCode. | 
| 679   final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); | 679   final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); | 
| 680   static int _nextHashCode = 0; | 680   static int _nextHashCode = 0; | 
| 681 | 681 | 
| 682   SyntheticLocal(this.name, this.executableContext, this.memberContext); | 682   SyntheticLocal(this.name, this.executableContext, this.memberContext); | 
| 683 | 683 | 
| 684   toString() => 'SyntheticLocal($name)'; | 684   toString() => 'SyntheticLocal($name)'; | 
| 685 } | 685 } | 
| OLD | NEW | 
|---|