| 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 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 ? null | 78 ? null |
| 79 : instanceType; | 79 : instanceType; |
| 80 | 80 |
| 81 ClosedWorld get closedWorld => builder.closedWorld; | 81 ClosedWorld get closedWorld => builder.closedWorld; |
| 82 | 82 |
| 83 CommonMasks get commonMasks => closedWorld.commonMasks; | 83 CommonMasks get commonMasks => closedWorld.commonMasks; |
| 84 | 84 |
| 85 GlobalTypeInferenceResults get _globalInferenceResults => | 85 GlobalTypeInferenceResults get _globalInferenceResults => |
| 86 builder.globalInferenceResults; | 86 builder.globalInferenceResults; |
| 87 | 87 |
| 88 ClosureTask get _closureToClassMapper => builder.closureToClassMapper; | 88 ClosureClassMaps get _closureToClassMapper => builder.closureToClassMapper; |
| 89 | 89 |
| 90 /// Substituted type variables occurring in [type] into the context of | 90 /// Substituted type variables occurring in [type] into the context of |
| 91 /// [contextClass]. | 91 /// [contextClass]. |
| 92 ResolutionDartType substInContext(ResolutionDartType type) { | 92 ResolutionDartType substInContext(ResolutionDartType type) { |
| 93 if (contextClass != null) { | 93 if (contextClass != null) { |
| 94 ClassElement typeContext = Types.getClassContext(type); | 94 ClassElement typeContext = Types.getClassContext(type); |
| 95 if (typeContext != null) { | 95 if (typeContext != null) { |
| 96 type = type.substByContext(contextClass.asInstanceOf(typeContext)); | 96 type = type.substByContext(contextClass.asInstanceOf(typeContext)); |
| 97 } | 97 } |
| 98 } | 98 } |
| (...skipping 30 matching lines...) Expand all 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(ast.Node node, Element element) { | 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 ClosureScope scopeData = closureData.capturingScopes[node]; |
| 143 if (scopeData == null) return; | 143 if (scopeData == null) return; |
| 144 HInstruction box; | 144 HInstruction box; |
| 145 // The scope has captured variables. | 145 // The scope has captured variables. |
| 146 if (element != null && element.isGenerativeConstructorBody) { | 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(scopeData.boxElement, 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[scopeData.boxElement] = 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 scopeData.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 && !element.isGenerativeConstructorBody) { | 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 |
| 168 // contains the updates as the last parameter. | 168 // contains the updates as the last parameter. |
| 169 HInstruction instruction = readLocal(from); | 169 HInstruction instruction = readLocal(from); |
| 170 redirectElement(from, to); | 170 redirectElement(from, to); |
| 171 updateLocal(from, instruction); | 171 updateLocal(from, instruction); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 190 HInstruction oldValue = readLocal(boxedVariable); | 190 HInstruction oldValue = readLocal(boxedVariable); |
| 191 updateLocal(boxElement, newBox); | 191 updateLocal(boxElement, newBox); |
| 192 updateLocal(boxedVariable, oldValue); | 192 updateLocal(boxedVariable, oldValue); |
| 193 } | 193 } |
| 194 updateLocal(boxElement, newBox); | 194 updateLocal(boxElement, newBox); |
| 195 } | 195 } |
| 196 | 196 |
| 197 /// Documentation wanted -- johnniwinther | 197 /// Documentation wanted -- johnniwinther |
| 198 /// | 198 /// |
| 199 /// Invariant: [function] must be an implementation element. | 199 /// Invariant: [function] must be an implementation element. |
| 200 void startFunction(MemberElement element, ast.Node node) { | 200 void startFunction(MemberEntity element, ast.Node node, |
| 201 assert(invariant(element, element.isImplementation)); | 201 {bool isGenerativeConstructorBody}) { |
| 202 closureData = | 202 assert(invariant( |
| 203 _closureToClassMapper.getClosureToClassMapping(element.resolvedAst); | 203 element, !(element is MemberElement && !element.isImplementation))); |
| 204 closureData = _closureToClassMapper.getMemberMap(element); |
| 204 | 205 |
| 205 if (element is MethodElement) { | 206 if (element is MethodElement) { |
| 206 MethodElement functionElement = element; | 207 MethodElement functionElement = element; |
| 207 FunctionSignature params = functionElement.functionSignature; | 208 FunctionSignature params = functionElement.functionSignature; |
| 208 ClosureScope scopeData = closureData.capturingScopes[node]; | 209 ClosureScope scopeData = closureData.capturingScopes[node]; |
| 209 params.orderedForEachParameter((ParameterElement parameterElement) { | 210 params.orderedForEachParameter((ParameterElement parameterElement) { |
| 210 if (element.isGenerativeConstructorBody) { | 211 if (element.isGenerativeConstructorBody) { |
| 211 if (scopeData != null && | 212 if (scopeData != null && |
| 212 scopeData.isCapturedVariable(parameterElement)) { | 213 scopeData.isCapturedVariable(parameterElement)) { |
| 213 // The parameter will be a field in the box passed as the | 214 // The parameter will be a field in the box passed as the |
| 214 // last parameter. So no need to have it. | 215 // last parameter. So no need to have it. |
| 215 return; | 216 return; |
| 216 } | 217 } |
| 217 } | 218 } |
| 218 HInstruction parameter = builder.addParameter( | 219 HInstruction parameter = builder.addParameter( |
| 219 parameterElement, | 220 parameterElement, |
| 220 TypeMaskFactory.inferredTypeForParameter( | 221 TypeMaskFactory.inferredTypeForParameter( |
| 221 parameterElement, _globalInferenceResults)); | 222 parameterElement, _globalInferenceResults)); |
| 222 builder.parameters[parameterElement] = parameter; | 223 builder.parameters[parameterElement] = parameter; |
| 223 directLocals[parameterElement] = parameter; | 224 directLocals[parameterElement] = parameter; |
| 224 }); | 225 }); |
| 225 } | 226 } |
| 226 | 227 |
| 227 enterScope(node, element); | 228 enterScope(node, forGenerativeConstructorBody: isGenerativeConstructorBody); |
| 228 | 229 |
| 229 // If the freeVariableMapping is not empty, then this function was a | 230 // If the freeVariableMapping is not empty, then this function was a |
| 230 // nested closure that captures variables. Redirect the captured | 231 // nested closure that captures variables. Redirect the captured |
| 231 // variables to fields in the closure. | 232 // variables to fields in the closure. |
| 232 closureData.forEachFreeVariable((Local from, CapturedVariable to) { | 233 closureData.forEachFreeVariable((Local from, CapturedVariable to) { |
| 233 redirectElement(from, to); | 234 redirectElement(from, to); |
| 234 }); | 235 }); |
| 235 if (closureData.isClosure) { | 236 if (closureData.isClosure) { |
| 236 // Inside closure redirect references to itself to [:this:]. | 237 // Inside closure redirect references to itself to [:this:]. |
| 237 HThis thisInstruction = | 238 HThis thisInstruction = |
| (...skipping 13 matching lines...) Expand all Loading... |
| 251 | 252 |
| 252 // If this method is an intercepted method, add the extra | 253 // If this method is an intercepted method, add the extra |
| 253 // parameter to it, that is the actual receiver for intercepted | 254 // parameter to it, that is the actual receiver for intercepted |
| 254 // classes, or the same as [:this:] for non-intercepted classes. | 255 // classes, or the same as [:this:] for non-intercepted classes. |
| 255 ClassElement cls = element.enclosingClass; | 256 ClassElement cls = element.enclosingClass; |
| 256 | 257 |
| 257 // When the class extends a native class, the instance is pre-constructed | 258 // When the class extends a native class, the instance is pre-constructed |
| 258 // and passed to the generative constructor factory function as a parameter. | 259 // and passed to the generative constructor factory function as a parameter. |
| 259 // Instead of allocating and initializing the object, the constructor | 260 // Instead of allocating and initializing the object, the constructor |
| 260 // 'upgrades' the native subclass object by initializing the Dart fields. | 261 // 'upgrades' the native subclass object by initializing the Dart fields. |
| 261 bool isNativeUpgradeFactory = element.isGenerativeConstructor && | 262 bool isNativeUpgradeFactory = element is ConstructorEntity && |
| 263 element.isGenerativeConstructor && |
| 262 _nativeData.isNativeOrExtendsNative(cls); | 264 _nativeData.isNativeOrExtendsNative(cls); |
| 263 if (_interceptorData.isInterceptedMethod(element)) { | 265 if (_interceptorData.isInterceptedMethod(element)) { |
| 264 bool isInterceptedClass = | 266 bool isInterceptedClass = _interceptorData.isInterceptedClass(cls); |
| 265 _interceptorData.isInterceptedClass(cls.declaration); | |
| 266 String name = isInterceptedClass ? 'receiver' : '_'; | 267 String name = isInterceptedClass ? 'receiver' : '_'; |
| 267 SyntheticLocal parameter = createLocal(name); | 268 SyntheticLocal parameter = createLocal(name); |
| 268 HParameterValue value = new HParameterValue(parameter, getTypeOfThis()); | 269 HParameterValue value = new HParameterValue(parameter, getTypeOfThis()); |
| 269 builder.graph.explicitReceiverParameter = value; | 270 builder.graph.explicitReceiverParameter = value; |
| 270 builder.graph.entry.addAfter(directLocals[closureData.thisLocal], value); | 271 builder.graph.entry.addAfter(directLocals[closureData.thisLocal], value); |
| 271 if (builder.lastAddedParameter == null) { | 272 if (builder.lastAddedParameter == null) { |
| 272 // If this is the first parameter inserted, make sure it stays first. | 273 // If this is the first parameter inserted, make sure it stays first. |
| 273 builder.lastAddedParameter = value; | 274 builder.lastAddedParameter = value; |
| 274 } | 275 } |
| 275 if (isInterceptedClass) { | 276 if (isInterceptedClass) { |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 476 /// goto loop-entry; | 477 /// goto loop-entry; |
| 477 /// loop-exit: | 478 /// loop-exit: |
| 478 void startLoop(ast.Node node) { | 479 void startLoop(ast.Node node) { |
| 479 ClosureScope scopeData = closureData.capturingScopes[node]; | 480 ClosureScope scopeData = closureData.capturingScopes[node]; |
| 480 if (scopeData == null) return; | 481 if (scopeData == null) return; |
| 481 if (scopeData.hasBoxedLoopVariables()) { | 482 if (scopeData.hasBoxedLoopVariables()) { |
| 482 // If there are boxed loop variables then we set up the box and | 483 // If there are boxed loop variables then we set up the box and |
| 483 // redirections already now. This way the initializer can write its | 484 // redirections already now. This way the initializer can write its |
| 484 // values into the box. | 485 // values into the box. |
| 485 // For other loops the box will be created when entering the body. | 486 // For other loops the box will be created when entering the body. |
| 486 enterScope(node, null); | 487 enterScope(node); |
| 487 } | 488 } |
| 488 } | 489 } |
| 489 | 490 |
| 490 /// Create phis at the loop entry for local variables (ready for the values | 491 /// Create phis at the loop entry for local variables (ready for the values |
| 491 /// from the back edge). Populate the phis with the current values. | 492 /// from the back edge). Populate the phis with the current values. |
| 492 void beginLoopHeader(HBasicBlock loopEntry) { | 493 void beginLoopHeader(HBasicBlock loopEntry) { |
| 493 // Create a copy because we modify the map while iterating over it. | 494 // Create a copy because we modify the map while iterating over it. |
| 494 Map<Local, HInstruction> savedDirectLocals = | 495 Map<Local, HInstruction> savedDirectLocals = |
| 495 new Map<Local, HInstruction>.from(directLocals); | 496 new Map<Local, HInstruction>.from(directLocals); |
| 496 | 497 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 509 } | 510 } |
| 510 }); | 511 }); |
| 511 } | 512 } |
| 512 | 513 |
| 513 void enterLoopBody(ast.Node node) { | 514 void enterLoopBody(ast.Node node) { |
| 514 ClosureScope scopeData = closureData.capturingScopes[node]; | 515 ClosureScope scopeData = closureData.capturingScopes[node]; |
| 515 if (scopeData == null) return; | 516 if (scopeData == null) return; |
| 516 // If there are no declared boxed loop variables then we did not create the | 517 // If there are no declared boxed loop variables then we did not create the |
| 517 // box before the initializer and we have to create the box now. | 518 // box before the initializer and we have to create the box now. |
| 518 if (!scopeData.hasBoxedLoopVariables()) { | 519 if (!scopeData.hasBoxedLoopVariables()) { |
| 519 enterScope(node, null); | 520 enterScope(node); |
| 520 } | 521 } |
| 521 } | 522 } |
| 522 | 523 |
| 523 void enterLoopUpdates(ast.Node node) { | 524 void enterLoopUpdates(ast.Node node) { |
| 524 // If there are declared boxed loop variables then the updates might have | 525 // If there are declared boxed loop variables then the updates might have |
| 525 // access to the box and we must switch to a new box before executing the | 526 // access to the box and we must switch to a new box before executing the |
| 526 // updates. | 527 // updates. |
| 527 // In all other cases a new box will be created when entering the body of | 528 // In all other cases a new box will be created when entering the body of |
| 528 // the next iteration. | 529 // the next iteration. |
| 529 ClosureScope scopeData = closureData.capturingScopes[node]; | 530 ClosureScope scopeData = closureData.capturingScopes[node]; |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 678 final MemberEntity memberContext; | 679 final MemberEntity memberContext; |
| 679 | 680 |
| 680 // Avoid slow Object.hashCode. | 681 // Avoid slow Object.hashCode. |
| 681 final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); | 682 final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); |
| 682 static int _nextHashCode = 0; | 683 static int _nextHashCode = 0; |
| 683 | 684 |
| 684 SyntheticLocal(this.name, this.executableContext, this.memberContext); | 685 SyntheticLocal(this.name, this.executableContext, this.memberContext); |
| 685 | 686 |
| 686 toString() => 'SyntheticLocal($name)'; | 687 toString() => 'SyntheticLocal($name)'; |
| 687 } | 688 } |
| OLD | NEW |