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 |