| 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/resolution_types.dart'; | 7 import '../elements/resolution_types.dart'; |
| 8 import '../elements/elements.dart'; | 8 import '../elements/elements.dart'; |
| 9 import '../elements/entities.dart'; | 9 import '../elements/entities.dart'; |
| 10 import '../io/source_information.dart'; | 10 import '../io/source_information.dart'; |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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(ast.Node node, {bool forGenerativeConstructorBody: false}) { | 139 void enterScope(ast.Node node, {bool forGenerativeConstructorBody: false}) { |
| 140 // See if any variable in the top-scope of the function is captured. If yes | 140 // See if any variable in the top-scope of the function is captured. If yes |
| 141 // we need to create a box-object. | 141 // we need to create a box-object. |
| 142 ClosureScope scopeData = closureData.capturingScopes[node]; | 142 CapturedVariableInfo scopeData = |
| 143 if (scopeData == null) return; | 143 _closureToClassMapper.getCapturedVariableInfo(node); |
| 144 if (!scopeData.hasCapturedVariables()) return; |
| 145 Local localExecutableContext = |
| 146 _closureToClassMapper.getExecutableContext(node); |
| 147 |
| 144 HInstruction box; | 148 HInstruction box; |
| 145 // The scope has captured variables. | 149 // The scope has captured variables. |
| 146 if (forGenerativeConstructorBody) { | 150 if (forGenerativeConstructorBody) { |
| 147 // The box is passed as a parameter to a generative | 151 // The box is passed as a parameter to a generative |
| 148 // constructor body. | 152 // constructor body. |
| 149 box = builder.addParameter(scopeData.boxElement, commonMasks.nonNullType); | 153 box = |
| 154 builder.addParameter(localExecutableContext, commonMasks.nonNullType); |
| 150 } else { | 155 } else { |
| 151 box = createBox(); | 156 box = createBox(); |
| 152 } | 157 } |
| 153 // Add the box to the known locals. | 158 // Add the box to the known locals. |
| 154 directLocals[scopeData.boxElement] = box; | 159 directLocals[localExecutableContext] = box; |
| 155 // Make sure that accesses to the boxed locals go into the box. We also | 160 // 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. | 161 // need to make sure that parameters are copied into the box if necessary. |
| 157 scopeData.forEachCapturedVariable( | 162 scopeData.forEachCapturedVariable( |
| 158 (LocalVariableElement from, BoxFieldElement to) { | 163 (LocalVariableElement from, BoxFieldElement to) { |
| 159 // The [from] can only be a parameter for function-scopes and not | 164 // The [from] can only be a parameter for function-scopes and not |
| 160 // loop scopes. | 165 // loop scopes. |
| 161 if (from.isRegularParameter && !forGenerativeConstructorBody) { | 166 if (from.isRegularParameter && !forGenerativeConstructorBody) { |
| 162 // Now that the redirection is set up, the update to the local will | 167 // Now that the redirection is set up, the update to the local will |
| 163 // write the parameter value into the box. | 168 // write the parameter value into the box. |
| 164 // Store the captured parameter in the box. Get the current value | 169 // Store the captured parameter in the box. Get the current value |
| 165 // before we put the redirection in place. | 170 // before we put the redirection in place. |
| 166 // We don't need to update the local for a generative | 171 // We don't need to update the local for a generative |
| 167 // constructor body, because it receives a box that already | 172 // constructor body, because it receives a box that already |
| 168 // contains the updates as the last parameter. | 173 // contains the updates as the last parameter. |
| 169 HInstruction instruction = readLocal(from); | 174 HInstruction instruction = readLocal(from); |
| 170 redirectElement(from, to); | 175 redirectElement(from, to); |
| 171 updateLocal(from, instruction); | 176 updateLocal(from, instruction); |
| 172 } else { | 177 } else { |
| 173 redirectElement(from, to); | 178 redirectElement(from, to); |
| 174 } | 179 } |
| 175 }); | 180 }); |
| 176 } | 181 } |
| 177 | 182 |
| 178 /// Replaces the current box with a new box and copies over the given list | 183 /// Replaces the current box with a new box and copies over the given list |
| 179 /// of elements from the old box into the new box. | 184 /// of elements from the old box into the new box. |
| 180 void updateCaptureBox( | 185 void updateCaptureBox( |
| 181 BoxLocal boxElement, List<LocalVariableElement> toBeCopiedElements) { | 186 Local boxElement, List<LocalVariableElement> toBeCopiedElements) { |
| 182 // Create a new box and copy over the values from the old box into the | 187 // Create a new box and copy over the values from the old box into the |
| 183 // new one. | 188 // new one. |
| 184 HInstruction oldBox = readLocal(boxElement); | 189 HInstruction oldBox = readLocal(boxElement); |
| 185 HInstruction newBox = createBox(); | 190 HInstruction newBox = createBox(); |
| 186 for (LocalVariableElement boxedVariable in toBeCopiedElements) { | 191 for (LocalVariableElement boxedVariable in toBeCopiedElements) { |
| 187 // [readLocal] uses the [boxElement] to find its box. By replacing it | 192 // [readLocal] uses the [boxElement] to find its box. By replacing it |
| 188 // behind its back we can still get to the old values. | 193 // behind its back we can still get to the old values. |
| 189 updateLocal(boxElement, oldBox); | 194 updateLocal(boxElement, oldBox); |
| 190 HInstruction oldValue = readLocal(boxedVariable); | 195 HInstruction oldValue = readLocal(boxedVariable); |
| 191 updateLocal(boxElement, newBox); | 196 updateLocal(boxElement, newBox); |
| 192 updateLocal(boxedVariable, oldValue); | 197 updateLocal(boxedVariable, oldValue); |
| 193 } | 198 } |
| 194 updateLocal(boxElement, newBox); | 199 updateLocal(boxElement, newBox); |
| 195 } | 200 } |
| 196 | 201 |
| 197 /// Documentation wanted -- johnniwinther | 202 /// Documentation wanted -- johnniwinther |
| 198 /// | 203 /// |
| 199 /// Invariant: [function] must be an implementation element. | 204 /// Invariant: [function] must be an implementation element. |
| 200 void startFunction(MemberEntity element, ast.Node node, | 205 void startFunction(MemberEntity element, ast.Node node, |
| 201 {bool isGenerativeConstructorBody}) { | 206 {bool isGenerativeConstructorBody}) { |
| 202 assert(invariant( | 207 assert(invariant( |
| 203 element, !(element is MemberElement && !element.isImplementation))); | 208 element, !(element is MemberElement && !element.isImplementation))); |
| 204 closureData = _closureToClassMapper.getMemberMap(element); | 209 closureData = _closureToClassMapper.getMemberMap(element); |
| 205 | 210 |
| 206 if (element is MethodElement) { | 211 if (element is MethodElement) { |
| 207 MethodElement functionElement = element; | 212 MethodElement functionElement = element; |
| 208 FunctionSignature params = functionElement.functionSignature; | 213 FunctionSignature params = functionElement.functionSignature; |
| 209 ClosureScope scopeData = closureData.capturingScopes[node]; | |
| 210 params.orderedForEachParameter((ParameterElement parameterElement) { | 214 params.orderedForEachParameter((ParameterElement parameterElement) { |
| 211 if (element.isGenerativeConstructorBody) { | 215 if (element.isGenerativeConstructorBody) { |
| 212 if (scopeData != null && | 216 if (_closureToClassMapper |
| 213 scopeData.isCapturedVariable(parameterElement)) { | 217 .getCapturedVariableInfo(node) |
| 218 .isCaptured(parameterElement)) { |
| 214 // The parameter will be a field in the box passed as the | 219 // The parameter will be a field in the box passed as the |
| 215 // last parameter. So no need to have it. | 220 // last parameter. So no need to have it. |
| 216 return; | 221 return; |
| 217 } | 222 } |
| 218 } | 223 } |
| 219 HInstruction parameter = builder.addParameter( | 224 HInstruction parameter = builder.addParameter( |
| 220 parameterElement, | 225 parameterElement, |
| 221 TypeMaskFactory.inferredTypeForParameter( | 226 TypeMaskFactory.inferredTypeForParameter( |
| 222 parameterElement, _globalInferenceResults)); | 227 parameterElement, _globalInferenceResults)); |
| 223 builder.parameters[parameterElement] = parameter; | 228 builder.parameters[parameterElement] = parameter; |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 470 /// <Create box> <== move the first box creation outside the loop. | 475 /// <Create box> <== move the first box creation outside the loop. |
| 471 /// <initializer>; | 476 /// <initializer>; |
| 472 /// loop-entry: | 477 /// loop-entry: |
| 473 /// if (!<condition>) goto loop-exit; | 478 /// if (!<condition>) goto loop-exit; |
| 474 /// <body> | 479 /// <body> |
| 475 /// <update box> // create a new box and copy the captured loop-variables. | 480 /// <update box> // create a new box and copy the captured loop-variables. |
| 476 /// <updates> | 481 /// <updates> |
| 477 /// goto loop-entry; | 482 /// goto loop-entry; |
| 478 /// loop-exit: | 483 /// loop-exit: |
| 479 void startLoop(ast.Node node) { | 484 void startLoop(ast.Node node) { |
| 480 ClosureScope scopeData = closureData.capturingScopes[node]; | 485 CapturedVariableInfo scopeData = |
| 481 if (scopeData == null) return; | 486 _closureToClassMapper.getCapturedVariableInfo(node); |
| 482 if (scopeData.hasBoxedLoopVariables()) { | 487 if (scopeData.hasBoxedLoopVariables()) { |
| 483 // If there are boxed loop variables then we set up the box and | 488 // If there are boxed loop variables then we set up the box and |
| 484 // redirections already now. This way the initializer can write its | 489 // redirections already now. This way the initializer can write its |
| 485 // values into the box. | 490 // values into the box. |
| 486 // For other loops the box will be created when entering the body. | 491 // For other loops the box will be created when entering the body. |
| 487 enterScope(node); | 492 enterScope(node); |
| 488 } | 493 } |
| 489 } | 494 } |
| 490 | 495 |
| 491 /// Create phis at the loop entry for local variables (ready for the values | 496 /// Create phis at the loop entry for local variables (ready for the values |
| (...skipping 13 matching lines...) Expand all Loading... |
| 505 loopEntry.addPhi(phi); | 510 loopEntry.addPhi(phi); |
| 506 directLocals[local] = phi; | 511 directLocals[local] = phi; |
| 507 } else { | 512 } else { |
| 508 directLocals[local] = instruction; | 513 directLocals[local] = instruction; |
| 509 } | 514 } |
| 510 } | 515 } |
| 511 }); | 516 }); |
| 512 } | 517 } |
| 513 | 518 |
| 514 void enterLoopBody(ast.Node node) { | 519 void enterLoopBody(ast.Node node) { |
| 515 ClosureScope scopeData = closureData.capturingScopes[node]; | 520 CapturedVariableInfo scopeData = |
| 516 if (scopeData == null) return; | 521 _closureToClassMapper.getCapturedVariableInfo(node); |
| 517 // If there are no declared boxed loop variables then we did not create the | 522 // If there are no declared boxed loop variables then we did not create the |
| 518 // box before the initializer and we have to create the box now. | 523 // box before the initializer and we have to create the box now. |
| 519 if (!scopeData.hasBoxedLoopVariables()) { | 524 if (!scopeData.hasBoxedLoopVariables()) { |
| 520 enterScope(node); | 525 enterScope(node); |
| 521 } | 526 } |
| 522 } | 527 } |
| 523 | 528 |
| 524 void enterLoopUpdates(ast.Node node) { | 529 void enterLoopUpdates(ast.Node node) { |
| 525 // If there are declared boxed loop variables then the updates might have | 530 // If there are declared boxed loop variables then the updates might have |
| 526 // access to the box and we must switch to a new box before executing the | 531 // access to the box and we must switch to a new box before executing the |
| 527 // updates. | 532 // updates. |
| 528 // In all other cases a new box will be created when entering the body of | 533 // In all other cases a new box will be created when entering the body of |
| 529 // the next iteration. | 534 // the next iteration. |
| 530 ClosureScope scopeData = closureData.capturingScopes[node]; | 535 CapturedVariableInfo scopeData = |
| 531 if (scopeData == null) return; | 536 _closureToClassMapper.getCapturedVariableInfo(node); |
| 532 if (scopeData.hasBoxedLoopVariables()) { | 537 if (scopeData.hasBoxedLoopVariables()) { |
| 533 updateCaptureBox(scopeData.boxElement, scopeData.boxedLoopVariables); | 538 updateCaptureBox(_closureToClassMapper.getExecutableContext(node), |
| 539 scopeData.boxedLoopVariables); |
| 534 } | 540 } |
| 535 } | 541 } |
| 536 | 542 |
| 537 /// Goes through the phis created in beginLoopHeader entry and adds the | 543 /// Goes through the phis created in beginLoopHeader entry and adds the |
| 538 /// input from the back edge (from the current value of directLocals) to them. | 544 /// input from the back edge (from the current value of directLocals) to them. |
| 539 void endLoop(HBasicBlock loopEntry) { | 545 void endLoop(HBasicBlock loopEntry) { |
| 540 // If the loop has an aborting body, we don't update the loop | 546 // If the loop has an aborting body, we don't update the loop |
| 541 // phis. | 547 // phis. |
| 542 if (loopEntry.predecessors.length == 1) return; | 548 if (loopEntry.predecessors.length == 1) return; |
| 543 loopEntry.forEachPhi((HPhi phi) { | 549 loopEntry.forEachPhi((HPhi phi) { |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 679 final MemberEntity memberContext; | 685 final MemberEntity memberContext; |
| 680 | 686 |
| 681 // Avoid slow Object.hashCode. | 687 // Avoid slow Object.hashCode. |
| 682 final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); | 688 final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); |
| 683 static int _nextHashCode = 0; | 689 static int _nextHashCode = 0; |
| 684 | 690 |
| 685 SyntheticLocal(this.name, this.executableContext, this.memberContext); | 691 SyntheticLocal(this.name, this.executableContext, this.memberContext); |
| 686 | 692 |
| 687 toString() => 'SyntheticLocal($name)'; | 693 toString() => 'SyntheticLocal($name)'; |
| 688 } | 694 } |
| OLD | NEW |