Chromium Code Reviews| 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 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 77 ? null | 77 ? null |
| 78 : instanceType; | 78 : instanceType; |
| 79 | 79 |
| 80 ClosedWorld get closedWorld => builder.closedWorld; | 80 ClosedWorld get closedWorld => builder.closedWorld; |
| 81 | 81 |
| 82 CommonMasks get commonMasks => closedWorld.commonMasks; | 82 CommonMasks get commonMasks => closedWorld.commonMasks; |
| 83 | 83 |
| 84 GlobalTypeInferenceResults get _globalInferenceResults => | 84 GlobalTypeInferenceResults get _globalInferenceResults => |
| 85 builder.globalInferenceResults; | 85 builder.globalInferenceResults; |
| 86 | 86 |
| 87 ClosureClassMaps get _closureToClassMapper => builder.closureToClassMapper; | |
| 88 | |
| 89 /// Substituted type variables occurring in [type] into the context of | 87 /// Substituted type variables occurring in [type] into the context of |
| 90 /// [contextClass]. | 88 /// [contextClass]. |
| 91 DartType substInContext(DartType type) { | 89 DartType substInContext(DartType type) { |
| 92 if (contextClass != null) { | 90 if (contextClass != null) { |
| 93 ClassElement typeContext = DartTypes.getClassContext(type); | 91 ClassElement typeContext = DartTypes.getClassContext(type); |
| 94 if (typeContext != null) { | 92 if (typeContext != null) { |
| 95 type = builder.types.substByContext( | 93 type = builder.types.substByContext( |
| 96 type, | 94 type, |
| 97 builder.types.asInstanceOf( | 95 builder.types.asInstanceOf( |
| 98 builder.types.getThisType(contextClass), typeContext)); | 96 builder.types.getThisType(contextClass), typeContext)); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 131 } | 129 } |
| 132 | 130 |
| 133 HInstruction createBox() { | 131 HInstruction createBox() { |
| 134 HInstruction box = new HCreateBox(commonMasks.nonNullType); | 132 HInstruction box = new HCreateBox(commonMasks.nonNullType); |
| 135 builder.add(box); | 133 builder.add(box); |
| 136 return box; | 134 return box; |
| 137 } | 135 } |
| 138 | 136 |
| 139 /// 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 |
| 140 /// method creates a box and sets up the redirections. | 138 /// method creates a box and sets up the redirections. |
| 141 void enterScope(ast.Node node, {bool forGenerativeConstructorBody: false}) { | 139 void enterScope(ClosureScope scopeData, |
| 140 {bool forGenerativeConstructorBody: false}) { | |
| 142 // 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 |
| 143 // we need to create a box-object. | 142 // we need to create a box-object. |
| 144 ClosureScope scopeData = closureData.capturingScopes[node]; | |
| 145 if (scopeData == null) return; | 143 if (scopeData == null) return; |
| 146 HInstruction box; | 144 HInstruction box; |
| 147 // The scope has captured variables. | 145 // The scope has captured variables. |
| 148 if (forGenerativeConstructorBody) { | 146 if (forGenerativeConstructorBody) { |
| 149 // The box is passed as a parameter to a generative | 147 // The box is passed as a parameter to a generative |
| 150 // constructor body. | 148 // constructor body. |
| 151 box = builder.addParameter(scopeData.boxElement, commonMasks.nonNullType); | 149 box = builder.addParameter(scopeData.boxElement, commonMasks.nonNullType); |
| 152 } else { | 150 } else { |
| 153 box = createBox(); | 151 box = createBox(); |
| 154 } | 152 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 191 HInstruction oldValue = readLocal(boxedVariable); | 189 HInstruction oldValue = readLocal(boxedVariable); |
| 192 updateLocal(boxElement, newBox); | 190 updateLocal(boxElement, newBox); |
| 193 updateLocal(boxedVariable, oldValue); | 191 updateLocal(boxedVariable, oldValue); |
| 194 } | 192 } |
| 195 updateLocal(boxElement, newBox); | 193 updateLocal(boxElement, newBox); |
| 196 } | 194 } |
| 197 | 195 |
| 198 /// Documentation wanted -- johnniwinther | 196 /// Documentation wanted -- johnniwinther |
| 199 /// | 197 /// |
| 200 /// Invariant: [function] must be an implementation element. | 198 /// Invariant: [function] must be an implementation element. |
| 201 void startFunction(MemberEntity element, ast.Node node, | 199 void startFunction(MemberEntity element, ClosureClassMap closureData, |
| 200 ClosureScope scopeData, Map<Local, TypeMask> parameters, | |
| 202 {bool isGenerativeConstructorBody}) { | 201 {bool isGenerativeConstructorBody}) { |
| 203 assert(!(element is MemberElement && !element.isImplementation), | 202 assert(!(element is MemberElement && !element.isImplementation), |
| 204 failedAt(element)); | 203 failedAt(element)); |
| 205 closureData = _closureToClassMapper.getMemberMap(element); | 204 this.closureData = closureData; |
| 206 | 205 |
| 207 if (element is MethodElement) { | 206 parameters.forEach((Local local, TypeMask typeMask) { |
|
Emily Fortuna
2017/06/07 18:16:42
perhaps I'm missing something here -- why do we wa
Johnni Winther
2017/06/07 18:34:45
If we move this (and other pieces) out of the loca
Emily Fortuna
2017/06/07 19:21:40
Got it! Thanks for the clarification!
| |
| 208 MethodElement functionElement = element; | 207 if (isGenerativeConstructorBody) { |
| 209 FunctionSignature params = functionElement.functionSignature; | 208 if (scopeData != null && scopeData.isCapturedVariable(local)) { |
| 210 ClosureScope scopeData = closureData.capturingScopes[node]; | 209 // The parameter will be a field in the box passed as the |
| 211 params.orderedForEachParameter((ParameterElement parameterElement) { | 210 // last parameter. So no need to have it. |
| 212 if (element.isGenerativeConstructorBody) { | 211 return; |
| 213 if (scopeData != null && | |
| 214 scopeData.isCapturedVariable(parameterElement)) { | |
| 215 // The parameter will be a field in the box passed as the | |
| 216 // last parameter. So no need to have it. | |
| 217 return; | |
| 218 } | |
| 219 } | 212 } |
| 220 HInstruction parameter = builder.addParameter( | 213 } |
| 221 parameterElement, | 214 HInstruction parameter = builder.addParameter(local, typeMask); |
| 222 TypeMaskFactory.inferredTypeForParameter( | 215 builder.parameters[local] = parameter; |
| 223 parameterElement, _globalInferenceResults)); | 216 directLocals[local] = parameter; |
| 224 builder.parameters[parameterElement] = parameter; | 217 }); |
| 225 directLocals[parameterElement] = parameter; | |
| 226 }); | |
| 227 } | |
| 228 | 218 |
| 229 enterScope(node, forGenerativeConstructorBody: isGenerativeConstructorBody); | 219 enterScope(scopeData, |
| 220 forGenerativeConstructorBody: isGenerativeConstructorBody); | |
| 230 | 221 |
| 231 // If the freeVariableMapping is not empty, then this function was a | 222 // If the freeVariableMapping is not empty, then this function was a |
| 232 // nested closure that captures variables. Redirect the captured | 223 // nested closure that captures variables. Redirect the captured |
| 233 // variables to fields in the closure. | 224 // variables to fields in the closure. |
| 234 closureData.forEachFreeVariable((Local from, FieldEntity to) { | 225 closureData.forEachFreeVariable((Local from, FieldEntity to) { |
| 235 redirectElement(from, to); | 226 redirectElement(from, to); |
| 236 }); | 227 }); |
| 237 if (closureData.isClosure) { | 228 if (closureData.isClosure) { |
| 238 // Inside closure redirect references to itself to [:this:]. | 229 // Inside closure redirect references to itself to [:this:]. |
| 239 HThis thisInstruction = | 230 HThis thisInstruction = |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 318 bool isUsedInTryOrGenerator(Local local) { | 309 bool isUsedInTryOrGenerator(Local local) { |
| 319 return closureData.variablesUsedInTryOrGenerator.contains(local); | 310 return closureData.variablesUsedInTryOrGenerator.contains(local); |
| 320 } | 311 } |
| 321 | 312 |
| 322 /// Returns an [HInstruction] for the given element. If the element is | 313 /// Returns an [HInstruction] for the given element. If the element is |
| 323 /// boxed or stored in a closure then the method generates code to retrieve | 314 /// boxed or stored in a closure then the method generates code to retrieve |
| 324 /// the value. | 315 /// the value. |
| 325 HInstruction readLocal(Local local, {SourceInformation sourceInformation}) { | 316 HInstruction readLocal(Local local, {SourceInformation sourceInformation}) { |
| 326 if (isAccessedDirectly(local)) { | 317 if (isAccessedDirectly(local)) { |
| 327 if (directLocals[local] == null) { | 318 if (directLocals[local] == null) { |
| 328 if (local is TypeVariableElement) { | 319 if (local is TypeVariableLocal) { |
| 329 throw new SpannableAssertionFailure(CURRENT_ELEMENT_SPANNABLE, | 320 throw new SpannableAssertionFailure( |
| 330 "Runtime type information not available for $local."); | 321 CURRENT_ELEMENT_SPANNABLE, |
| 322 "Runtime type information not available for $local " | |
| 323 "in $executableContext."); | |
| 331 } else { | 324 } else { |
| 332 throw new SpannableAssertionFailure( | 325 throw new SpannableAssertionFailure( |
| 333 local, "Cannot find value $local in ${directLocals.keys}."); | 326 local, |
| 327 "Cannot find value $local in ${directLocals.keys} for " | |
| 328 "$executableContext."); | |
| 334 } | 329 } |
| 335 } | 330 } |
| 336 HInstruction value = directLocals[local]; | 331 HInstruction value = directLocals[local]; |
| 337 if (sourceInformation != null) { | 332 if (sourceInformation != null) { |
| 338 value = new HRef(value, sourceInformation); | 333 value = new HRef(value, sourceInformation); |
| 339 builder.add(value); | 334 builder.add(value); |
| 340 } | 335 } |
| 341 return value; | 336 return value; |
| 342 } else if (isStoredInClosureField(local)) { | 337 } else if (isStoredInClosureField(local)) { |
| 343 ClosureFieldElement redirect = redirectionMapping[local]; | 338 ClosureFieldElement redirect = redirectionMapping[local]; |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 479 /// goto loop-entry; | 474 /// goto loop-entry; |
| 480 /// loop-exit: | 475 /// loop-exit: |
| 481 void startLoop(ast.Node node) { | 476 void startLoop(ast.Node node) { |
| 482 ClosureScope scopeData = closureData.capturingScopes[node]; | 477 ClosureScope scopeData = closureData.capturingScopes[node]; |
| 483 if (scopeData == null) return; | 478 if (scopeData == null) return; |
| 484 if (scopeData.hasBoxedLoopVariables()) { | 479 if (scopeData.hasBoxedLoopVariables()) { |
| 485 // If there are boxed loop variables then we set up the box and | 480 // If there are boxed loop variables then we set up the box and |
| 486 // redirections already now. This way the initializer can write its | 481 // redirections already now. This way the initializer can write its |
| 487 // values into the box. | 482 // values into the box. |
| 488 // For other loops the box will be created when entering the body. | 483 // For other loops the box will be created when entering the body. |
| 489 enterScope(node); | 484 enterScope(scopeData); |
| 490 } | 485 } |
| 491 } | 486 } |
| 492 | 487 |
| 493 /// Create phis at the loop entry for local variables (ready for the values | 488 /// Create phis at the loop entry for local variables (ready for the values |
| 494 /// from the back edge). Populate the phis with the current values. | 489 /// from the back edge). Populate the phis with the current values. |
| 495 void beginLoopHeader(HBasicBlock loopEntry) { | 490 void beginLoopHeader(HBasicBlock loopEntry) { |
| 496 // Create a copy because we modify the map while iterating over it. | 491 // Create a copy because we modify the map while iterating over it. |
| 497 Map<Local, HInstruction> savedDirectLocals = | 492 Map<Local, HInstruction> savedDirectLocals = |
| 498 new Map<Local, HInstruction>.from(directLocals); | 493 new Map<Local, HInstruction>.from(directLocals); |
| 499 | 494 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 512 } | 507 } |
| 513 }); | 508 }); |
| 514 } | 509 } |
| 515 | 510 |
| 516 void enterLoopBody(ast.Node node) { | 511 void enterLoopBody(ast.Node node) { |
| 517 ClosureScope scopeData = closureData.capturingScopes[node]; | 512 ClosureScope scopeData = closureData.capturingScopes[node]; |
| 518 if (scopeData == null) return; | 513 if (scopeData == null) return; |
| 519 // If there are no declared boxed loop variables then we did not create the | 514 // If there are no declared boxed loop variables then we did not create the |
| 520 // box before the initializer and we have to create the box now. | 515 // box before the initializer and we have to create the box now. |
| 521 if (!scopeData.hasBoxedLoopVariables()) { | 516 if (!scopeData.hasBoxedLoopVariables()) { |
| 522 enterScope(node); | 517 enterScope(scopeData); |
| 523 } | 518 } |
| 524 } | 519 } |
| 525 | 520 |
| 526 void enterLoopUpdates(ast.Node node) { | 521 void enterLoopUpdates(ast.Node node) { |
| 527 // If there are declared boxed loop variables then the updates might have | 522 // If there are declared boxed loop variables then the updates might have |
| 528 // access to the box and we must switch to a new box before executing the | 523 // access to the box and we must switch to a new box before executing the |
| 529 // updates. | 524 // updates. |
| 530 // In all other cases a new box will be created when entering the body of | 525 // In all other cases a new box will be created when entering the body of |
| 531 // the next iteration. | 526 // the next iteration. |
| 532 ClosureScope scopeData = closureData.capturingScopes[node]; | 527 ClosureScope scopeData = closureData.capturingScopes[node]; |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 681 final MemberEntity memberContext; | 676 final MemberEntity memberContext; |
| 682 | 677 |
| 683 // Avoid slow Object.hashCode. | 678 // Avoid slow Object.hashCode. |
| 684 final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); | 679 final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); |
| 685 static int _nextHashCode = 0; | 680 static int _nextHashCode = 0; |
| 686 | 681 |
| 687 SyntheticLocal(this.name, this.executableContext, this.memberContext); | 682 SyntheticLocal(this.name, this.executableContext, this.memberContext); |
| 688 | 683 |
| 689 toString() => 'SyntheticLocal($name)'; | 684 toString() => 'SyntheticLocal($name)'; |
| 690 } | 685 } |
| OLD | NEW |