| 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 '../compiler.dart' show Compiler; | 7 import '../compiler.dart' show Compiler; |
| 8 import '../dart_types.dart'; | 8 import '../dart_types.dart'; |
| 9 import '../elements/elements.dart'; | 9 import '../elements/elements.dart'; |
| 10 import '../io/source_information.dart'; | 10 import '../io/source_information.dart'; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 /// } | 54 /// } |
| 55 /// main() { | 55 /// main() { |
| 56 /// new Foo<String>('foo'); | 56 /// new Foo<String>('foo'); |
| 57 /// } | 57 /// } |
| 58 /// | 58 /// |
| 59 /// [instanceType] is not used if it contains type variables, since these | 59 /// [instanceType] is not used if it contains type variables, since these |
| 60 /// might not be in scope or from the current instance. | 60 /// might not be in scope or from the current instance. |
| 61 /// | 61 /// |
| 62 final InterfaceType instanceType; | 62 final InterfaceType instanceType; |
| 63 | 63 |
| 64 final Compiler compiler; | 64 final Compiler _compiler; |
| 65 | 65 |
| 66 LocalsHandler(this.builder, this.executableContext, | 66 LocalsHandler(this.builder, this.executableContext, |
| 67 InterfaceType instanceType, this.compiler) | 67 InterfaceType instanceType, this._compiler) |
| 68 : this.instanceType = | 68 : this.instanceType = |
| 69 instanceType == null || instanceType.containsTypeVariables | 69 instanceType == null || instanceType.containsTypeVariables |
| 70 ? null | 70 ? null |
| 71 : instanceType; | 71 : instanceType; |
| 72 | 72 |
| 73 /// Substituted type variables occurring in [type] into the context of | 73 /// Substituted type variables occurring in [type] into the context of |
| 74 /// [contextClass]. | 74 /// [contextClass]. |
| 75 DartType substInContext(DartType type) { | 75 DartType substInContext(DartType type) { |
| 76 if (contextClass != null) { | 76 if (contextClass != null) { |
| 77 ClassElement typeContext = Types.getClassContext(type); | 77 ClassElement typeContext = Types.getClassContext(type); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 88 /// Creates a new [LocalsHandler] based on [other]. We only need to | 88 /// Creates a new [LocalsHandler] based on [other]. We only need to |
| 89 /// copy the [directLocals], since the other fields can be shared | 89 /// copy the [directLocals], since the other fields can be shared |
| 90 /// throughout the AST visit. | 90 /// throughout the AST visit. |
| 91 LocalsHandler.from(LocalsHandler other) | 91 LocalsHandler.from(LocalsHandler other) |
| 92 : directLocals = new Map<Local, HInstruction>.from(other.directLocals), | 92 : directLocals = new Map<Local, HInstruction>.from(other.directLocals), |
| 93 redirectionMapping = other.redirectionMapping, | 93 redirectionMapping = other.redirectionMapping, |
| 94 executableContext = other.executableContext, | 94 executableContext = other.executableContext, |
| 95 instanceType = other.instanceType, | 95 instanceType = other.instanceType, |
| 96 builder = other.builder, | 96 builder = other.builder, |
| 97 closureData = other.closureData, | 97 closureData = other.closureData, |
| 98 compiler = other.compiler, | 98 _compiler = other._compiler, |
| 99 activationVariables = other.activationVariables, | 99 activationVariables = other.activationVariables, |
| 100 cachedTypeOfThis = other.cachedTypeOfThis, | 100 cachedTypeOfThis = other.cachedTypeOfThis, |
| 101 cachedTypesOfCapturedVariables = other.cachedTypesOfCapturedVariables; | 101 cachedTypesOfCapturedVariables = other.cachedTypesOfCapturedVariables; |
| 102 | 102 |
| 103 /// Redirects accesses from element [from] to element [to]. The [to] element | 103 /// Redirects accesses from element [from] to element [to]. The [to] element |
| 104 /// must be a boxed variable or a variable that is stored in a closure-field. | 104 /// must be a boxed variable or a variable that is stored in a closure-field. |
| 105 void redirectElement(Local from, CapturedVariable to) { | 105 void redirectElement(Local from, CapturedVariable to) { |
| 106 assert(redirectionMapping[from] == null); | 106 assert(redirectionMapping[from] == null); |
| 107 redirectionMapping[from] = to; | 107 redirectionMapping[from] = to; |
| 108 assert(isStoredInClosureField(from) || isBoxed(from)); | 108 assert(isStoredInClosureField(from) || isBoxed(from)); |
| 109 } | 109 } |
| 110 | 110 |
| 111 HInstruction createBox() { | 111 HInstruction createBox() { |
| 112 // TODO(floitsch): Clean up this hack. Should we create a box-object by | 112 // TODO(floitsch): Clean up this hack. Should we create a box-object by |
| 113 // just creating an empty object literal? | 113 // just creating an empty object literal? |
| 114 JavaScriptBackend backend = compiler.backend; | 114 JavaScriptBackend backend = _compiler.backend; |
| 115 HInstruction box = new HForeignCode( | 115 HInstruction box = new HForeignCode( |
| 116 js.js.parseForeignJS('{}'), backend.nonNullType, <HInstruction>[], | 116 js.js.parseForeignJS('{}'), backend.nonNullType, <HInstruction>[], |
| 117 nativeBehavior: native.NativeBehavior.PURE_ALLOCATION); | 117 nativeBehavior: native.NativeBehavior.PURE_ALLOCATION); |
| 118 builder.add(box); | 118 builder.add(box); |
| 119 return box; | 119 return box; |
| 120 } | 120 } |
| 121 | 121 |
| 122 /// If the scope (function or loop) [node] has captured variables then this | 122 /// If the scope (function or loop) [node] has captured variables then this |
| 123 /// method creates a box and sets up the redirections. | 123 /// method creates a box and sets up the redirections. |
| 124 void enterScope(ast.Node node, Element element) { | 124 void enterScope(ast.Node node, Element element) { |
| 125 // See if any variable in the top-scope of the function is captured. If yes | 125 // See if any variable in the top-scope of the function is captured. If yes |
| 126 // we need to create a box-object. | 126 // we need to create a box-object. |
| 127 ClosureScope scopeData = closureData.capturingScopes[node]; | 127 ClosureScope scopeData = closureData.capturingScopes[node]; |
| 128 if (scopeData == null) return; | 128 if (scopeData == null) return; |
| 129 HInstruction box; | 129 HInstruction box; |
| 130 // The scope has captured variables. | 130 // The scope has captured variables. |
| 131 if (element != null && element.isGenerativeConstructorBody) { | 131 if (element != null && element.isGenerativeConstructorBody) { |
| 132 // The box is passed as a parameter to a generative | 132 // The box is passed as a parameter to a generative |
| 133 // constructor body. | 133 // constructor body. |
| 134 JavaScriptBackend backend = compiler.backend; | 134 JavaScriptBackend backend = _compiler.backend; |
| 135 box = builder.addParameter(scopeData.boxElement, backend.nonNullType); | 135 box = builder.addParameter(scopeData.boxElement, backend.nonNullType); |
| 136 } else { | 136 } else { |
| 137 box = createBox(); | 137 box = createBox(); |
| 138 } | 138 } |
| 139 // Add the box to the known locals. | 139 // Add the box to the known locals. |
| 140 directLocals[scopeData.boxElement] = box; | 140 directLocals[scopeData.boxElement] = box; |
| 141 // Make sure that accesses to the boxed locals go into the box. We also | 141 // Make sure that accesses to the boxed locals go into the box. We also |
| 142 // need to make sure that parameters are copied into the box if necessary. | 142 // need to make sure that parameters are copied into the box if necessary. |
| 143 scopeData.forEachCapturedVariable( | 143 scopeData.forEachCapturedVariable( |
| 144 (LocalVariableElement from, BoxFieldElement to) { | 144 (LocalVariableElement from, BoxFieldElement to) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 178 updateLocal(boxedVariable, oldValue); | 178 updateLocal(boxedVariable, oldValue); |
| 179 } | 179 } |
| 180 updateLocal(boxElement, newBox); | 180 updateLocal(boxElement, newBox); |
| 181 } | 181 } |
| 182 | 182 |
| 183 /// Documentation wanted -- johnniwinther | 183 /// Documentation wanted -- johnniwinther |
| 184 /// | 184 /// |
| 185 /// Invariant: [function] must be an implementation element. | 185 /// Invariant: [function] must be an implementation element. |
| 186 void startFunction(AstElement element, ast.Node node) { | 186 void startFunction(AstElement element, ast.Node node) { |
| 187 assert(invariant(element, element.isImplementation)); | 187 assert(invariant(element, element.isImplementation)); |
| 188 closureData = compiler.closureToClassMapper | 188 closureData = _compiler.closureToClassMapper |
| 189 .computeClosureToClassMapping(element.resolvedAst); | 189 .computeClosureToClassMapping(element.resolvedAst); |
| 190 | 190 |
| 191 if (element is FunctionElement) { | 191 if (element is FunctionElement) { |
| 192 FunctionElement functionElement = element; | 192 FunctionElement functionElement = element; |
| 193 FunctionSignature params = functionElement.functionSignature; | 193 FunctionSignature params = functionElement.functionSignature; |
| 194 ClosureScope scopeData = closureData.capturingScopes[node]; | 194 ClosureScope scopeData = closureData.capturingScopes[node]; |
| 195 params.orderedForEachParameter((ParameterElement parameterElement) { | 195 params.orderedForEachParameter((ParameterElement parameterElement) { |
| 196 if (element.isGenerativeConstructorBody) { | 196 if (element.isGenerativeConstructorBody) { |
| 197 if (scopeData != null && | 197 if (scopeData != null && |
| 198 scopeData.isCapturedVariable(parameterElement)) { | 198 scopeData.isCapturedVariable(parameterElement)) { |
| 199 // The parameter will be a field in the box passed as the | 199 // The parameter will be a field in the box passed as the |
| 200 // last parameter. So no need to have it. | 200 // last parameter. So no need to have it. |
| 201 return; | 201 return; |
| 202 } | 202 } |
| 203 } | 203 } |
| 204 HInstruction parameter = builder.addParameter(parameterElement, | 204 HInstruction parameter = builder.addParameter( |
| 205 TypeMaskFactory.inferredTypeForElement(parameterElement, compiler)); | 205 parameterElement, |
| 206 TypeMaskFactory.inferredTypeForElement( |
| 207 parameterElement, _compiler)); |
| 206 builder.parameters[parameterElement] = parameter; | 208 builder.parameters[parameterElement] = parameter; |
| 207 directLocals[parameterElement] = parameter; | 209 directLocals[parameterElement] = parameter; |
| 208 }); | 210 }); |
| 209 } | 211 } |
| 210 | 212 |
| 211 enterScope(node, element); | 213 enterScope(node, element); |
| 212 | 214 |
| 213 // If the freeVariableMapping is not empty, then this function was a | 215 // If the freeVariableMapping is not empty, then this function was a |
| 214 // nested closure that captures variables. Redirect the captured | 216 // nested closure that captures variables. Redirect the captured |
| 215 // variables to fields in the closure. | 217 // variables to fields in the closure. |
| 216 closureData.forEachFreeVariable((Local from, CapturedVariable to) { | 218 closureData.forEachFreeVariable((Local from, CapturedVariable to) { |
| 217 redirectElement(from, to); | 219 redirectElement(from, to); |
| 218 }); | 220 }); |
| 219 JavaScriptBackend backend = compiler.backend; | 221 JavaScriptBackend backend = _compiler.backend; |
| 220 if (closureData.isClosure) { | 222 if (closureData.isClosure) { |
| 221 // Inside closure redirect references to itself to [:this:]. | 223 // Inside closure redirect references to itself to [:this:]. |
| 222 HThis thisInstruction = | 224 HThis thisInstruction = |
| 223 new HThis(closureData.thisLocal, backend.nonNullType); | 225 new HThis(closureData.thisLocal, backend.nonNullType); |
| 224 builder.graph.thisInstruction = thisInstruction; | 226 builder.graph.thisInstruction = thisInstruction; |
| 225 builder.graph.entry.addAtEntry(thisInstruction); | 227 builder.graph.entry.addAtEntry(thisInstruction); |
| 226 updateLocal(closureData.closureElement, thisInstruction); | 228 updateLocal(closureData.closureElement, thisInstruction); |
| 227 } else if (element.isInstanceMember) { | 229 } else if (element.isInstanceMember) { |
| 228 // Once closures have been mapped to classes their instance members might | 230 // Once closures have been mapped to classes their instance members might |
| 229 // not have any thisElement if the closure was created inside a static | 231 // not have any thisElement if the closure was created inside a static |
| (...skipping 28 matching lines...) Expand all Loading... |
| 258 } | 260 } |
| 259 if (isInterceptorClass) { | 261 if (isInterceptorClass) { |
| 260 // Only use the extra parameter in intercepted classes. | 262 // Only use the extra parameter in intercepted classes. |
| 261 directLocals[closureData.thisLocal] = value; | 263 directLocals[closureData.thisLocal] = value; |
| 262 } | 264 } |
| 263 } else if (isNativeUpgradeFactory) { | 265 } else if (isNativeUpgradeFactory) { |
| 264 SyntheticLocal parameter = | 266 SyntheticLocal parameter = |
| 265 new SyntheticLocal('receiver', executableContext); | 267 new SyntheticLocal('receiver', executableContext); |
| 266 // Unlike `this`, receiver is nullable since direct calls to generative | 268 // Unlike `this`, receiver is nullable since direct calls to generative |
| 267 // constructor call the constructor with `null`. | 269 // constructor call the constructor with `null`. |
| 268 ClassWorld classWorld = compiler.world; | 270 ClassWorld classWorld = _compiler.world; |
| 269 HParameterValue value = | 271 HParameterValue value = |
| 270 new HParameterValue(parameter, new TypeMask.exact(cls, classWorld)); | 272 new HParameterValue(parameter, new TypeMask.exact(cls, classWorld)); |
| 271 builder.graph.explicitReceiverParameter = value; | 273 builder.graph.explicitReceiverParameter = value; |
| 272 builder.graph.entry.addAtEntry(value); | 274 builder.graph.entry.addAtEntry(value); |
| 273 } | 275 } |
| 274 } | 276 } |
| 275 | 277 |
| 276 /// Returns true if the local can be accessed directly. Boxed variables or | 278 /// Returns true if the local can be accessed directly. Boxed variables or |
| 277 /// captured variables that are stored in the closure-field return [:false:]. | 279 /// captured variables that are stored in the closure-field return [:false:]. |
| 278 bool isAccessedDirectly(Local local) { | 280 bool isAccessedDirectly(Local local) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 299 return closureData.variablesUsedInTryOrGenerator.contains(local); | 301 return closureData.variablesUsedInTryOrGenerator.contains(local); |
| 300 } | 302 } |
| 301 | 303 |
| 302 /// Returns an [HInstruction] for the given element. If the element is | 304 /// Returns an [HInstruction] for the given element. If the element is |
| 303 /// boxed or stored in a closure then the method generates code to retrieve | 305 /// boxed or stored in a closure then the method generates code to retrieve |
| 304 /// the value. | 306 /// the value. |
| 305 HInstruction readLocal(Local local, {SourceInformation sourceInformation}) { | 307 HInstruction readLocal(Local local, {SourceInformation sourceInformation}) { |
| 306 if (isAccessedDirectly(local)) { | 308 if (isAccessedDirectly(local)) { |
| 307 if (directLocals[local] == null) { | 309 if (directLocals[local] == null) { |
| 308 if (local is TypeVariableElement) { | 310 if (local is TypeVariableElement) { |
| 309 compiler.reporter.internalError(compiler.currentElement, | 311 _compiler.reporter.internalError(_compiler.currentElement, |
| 310 "Runtime type information not available for $local."); | 312 "Runtime type information not available for $local."); |
| 311 } else { | 313 } else { |
| 312 compiler.reporter.internalError( | 314 _compiler.reporter.internalError( |
| 313 local, "Cannot find value $local in ${directLocals.keys}."); | 315 local, "Cannot find value $local in ${directLocals.keys}."); |
| 314 } | 316 } |
| 315 } | 317 } |
| 316 HInstruction value = directLocals[local]; | 318 HInstruction value = directLocals[local]; |
| 317 if (sourceInformation != null) { | 319 if (sourceInformation != null) { |
| 318 value = new HRef(value, sourceInformation); | 320 value = new HRef(value, sourceInformation); |
| 319 builder.add(value); | 321 builder.add(value); |
| 320 } | 322 } |
| 321 return value; | 323 return value; |
| 322 } else if (isStoredInClosureField(local)) { | 324 } else if (isStoredInClosureField(local)) { |
| 323 ClosureFieldElement redirect = redirectionMapping[local]; | 325 ClosureFieldElement redirect = redirectionMapping[local]; |
| 324 HInstruction receiver = readLocal(closureData.closureElement); | 326 HInstruction receiver = readLocal(closureData.closureElement); |
| 325 TypeMask type = local is BoxLocal | 327 TypeMask type = local is BoxLocal |
| 326 ? (compiler.backend as JavaScriptBackend).nonNullType | 328 ? (_compiler.backend as JavaScriptBackend).nonNullType |
| 327 : getTypeOfCapturedVariable(redirect); | 329 : getTypeOfCapturedVariable(redirect); |
| 328 HInstruction fieldGet = new HFieldGet(redirect, receiver, type); | 330 HInstruction fieldGet = new HFieldGet(redirect, receiver, type); |
| 329 builder.add(fieldGet); | 331 builder.add(fieldGet); |
| 330 return fieldGet..sourceInformation = sourceInformation; | 332 return fieldGet..sourceInformation = sourceInformation; |
| 331 } else if (isBoxed(local)) { | 333 } else if (isBoxed(local)) { |
| 332 BoxFieldElement redirect = redirectionMapping[local]; | 334 BoxFieldElement redirect = redirectionMapping[local]; |
| 333 // In the function that declares the captured variable the box is | 335 // In the function that declares the captured variable the box is |
| 334 // accessed as direct local. Inside the nested closure the box is | 336 // accessed as direct local. Inside the nested closure the box is |
| 335 // accessed through a closure-field. | 337 // accessed through a closure-field. |
| 336 // Calling [readLocal] makes sure we generate the correct code to get | 338 // Calling [readLocal] makes sure we generate the correct code to get |
| 337 // the box. | 339 // the box. |
| 338 HInstruction box = readLocal(redirect.box); | 340 HInstruction box = readLocal(redirect.box); |
| 339 HInstruction lookup = | 341 HInstruction lookup = |
| 340 new HFieldGet(redirect, box, getTypeOfCapturedVariable(redirect)); | 342 new HFieldGet(redirect, box, getTypeOfCapturedVariable(redirect)); |
| 341 builder.add(lookup); | 343 builder.add(lookup); |
| 342 return lookup..sourceInformation = sourceInformation; | 344 return lookup..sourceInformation = sourceInformation; |
| 343 } else { | 345 } else { |
| 344 assert(isUsedInTryOrGenerator(local)); | 346 assert(isUsedInTryOrGenerator(local)); |
| 345 HLocalValue localValue = getLocal(local); | 347 HLocalValue localValue = getLocal(local); |
| 346 HInstruction instruction = new HLocalGet( | 348 HInstruction instruction = new HLocalGet( |
| 347 local, | 349 local, |
| 348 localValue, | 350 localValue, |
| 349 (compiler.backend as JavaScriptBackend).dynamicType, | 351 (_compiler.backend as JavaScriptBackend).dynamicType, |
| 350 sourceInformation); | 352 sourceInformation); |
| 351 builder.add(instruction); | 353 builder.add(instruction); |
| 352 return instruction; | 354 return instruction; |
| 353 } | 355 } |
| 354 } | 356 } |
| 355 | 357 |
| 356 HInstruction readThis() { | 358 HInstruction readThis() { |
| 357 HInstruction res = readLocal(closureData.thisLocal); | 359 HInstruction res = readLocal(closureData.thisLocal); |
| 358 if (res.instructionType == null) { | 360 if (res.instructionType == null) { |
| 359 res.instructionType = getTypeOfThis(); | 361 res.instructionType = getTypeOfThis(); |
| 360 } | 362 } |
| 361 return res; | 363 return res; |
| 362 } | 364 } |
| 363 | 365 |
| 364 HLocalValue getLocal(Local local, {SourceInformation sourceInformation}) { | 366 HLocalValue getLocal(Local local, {SourceInformation sourceInformation}) { |
| 365 // If the element is a parameter, we already have a | 367 // If the element is a parameter, we already have a |
| 366 // HParameterValue for it. We cannot create another one because | 368 // HParameterValue for it. We cannot create another one because |
| 367 // it could then have another name than the real parameter. And | 369 // it could then have another name than the real parameter. And |
| 368 // the other one would not know it is just a copy of the real | 370 // the other one would not know it is just a copy of the real |
| 369 // parameter. | 371 // parameter. |
| 370 if (local is ParameterElement) { | 372 if (local is ParameterElement) { |
| 371 assert(invariant(local, builder.parameters.containsKey(local), | 373 assert(invariant(local, builder.parameters.containsKey(local), |
| 372 message: "No local value for parameter $local in " | 374 message: "No local value for parameter $local in " |
| 373 "${builder.parameters}.")); | 375 "${builder.parameters}.")); |
| 374 return builder.parameters[local]; | 376 return builder.parameters[local]; |
| 375 } | 377 } |
| 376 | 378 |
| 377 return activationVariables.putIfAbsent(local, () { | 379 return activationVariables.putIfAbsent(local, () { |
| 378 JavaScriptBackend backend = compiler.backend; | 380 JavaScriptBackend backend = _compiler.backend; |
| 379 HLocalValue localValue = new HLocalValue(local, backend.nonNullType) | 381 HLocalValue localValue = new HLocalValue(local, backend.nonNullType) |
| 380 ..sourceInformation = sourceInformation; | 382 ..sourceInformation = sourceInformation; |
| 381 builder.graph.entry.addAtExit(localValue); | 383 builder.graph.entry.addAtExit(localValue); |
| 382 return localValue; | 384 return localValue; |
| 383 }); | 385 }); |
| 384 } | 386 } |
| 385 | 387 |
| 386 Local getTypeVariableAsLocal(TypeVariableType type) { | 388 Local getTypeVariableAsLocal(TypeVariableType type) { |
| 387 return typeVariableLocals.putIfAbsent(type, () { | 389 return typeVariableLocals.putIfAbsent(type, () { |
| 388 return new TypeVariableLocal(type, executableContext); | 390 return new TypeVariableLocal(type, executableContext); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 } | 475 } |
| 474 } | 476 } |
| 475 | 477 |
| 476 /// Create phis at the loop entry for local variables (ready for the values | 478 /// Create phis at the loop entry for local variables (ready for the values |
| 477 /// from the back edge). Populate the phis with the current values. | 479 /// from the back edge). Populate the phis with the current values. |
| 478 void beginLoopHeader(HBasicBlock loopEntry) { | 480 void beginLoopHeader(HBasicBlock loopEntry) { |
| 479 // Create a copy because we modify the map while iterating over it. | 481 // Create a copy because we modify the map while iterating over it. |
| 480 Map<Local, HInstruction> savedDirectLocals = | 482 Map<Local, HInstruction> savedDirectLocals = |
| 481 new Map<Local, HInstruction>.from(directLocals); | 483 new Map<Local, HInstruction>.from(directLocals); |
| 482 | 484 |
| 483 JavaScriptBackend backend = compiler.backend; | 485 JavaScriptBackend backend = _compiler.backend; |
| 484 // Create phis for all elements in the definitions environment. | 486 // Create phis for all elements in the definitions environment. |
| 485 savedDirectLocals.forEach((Local local, HInstruction instruction) { | 487 savedDirectLocals.forEach((Local local, HInstruction instruction) { |
| 486 if (isAccessedDirectly(local)) { | 488 if (isAccessedDirectly(local)) { |
| 487 // We know 'this' cannot be modified. | 489 // We know 'this' cannot be modified. |
| 488 if (local != closureData.thisLocal) { | 490 if (local != closureData.thisLocal) { |
| 489 HPhi phi = | 491 HPhi phi = |
| 490 new HPhi.singleInput(local, instruction, backend.dynamicType); | 492 new HPhi.singleInput(local, instruction, backend.dynamicType); |
| 491 loopEntry.addPhi(phi); | 493 loopEntry.addPhi(phi); |
| 492 directLocals[local] = phi; | 494 directLocals[local] = phi; |
| 493 } else { | 495 } else { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 537 /// there is a conflict. | 539 /// there is a conflict. |
| 538 /// If a phi node is necessary, it will use this handler's instruction as the | 540 /// If a phi node is necessary, it will use this handler's instruction as the |
| 539 /// first input, and the otherLocals instruction as the second. | 541 /// first input, and the otherLocals instruction as the second. |
| 540 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { | 542 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { |
| 541 // If an element is in one map but not the other we can safely | 543 // If an element is in one map but not the other we can safely |
| 542 // ignore it. It means that a variable was declared in the | 544 // ignore it. It means that a variable was declared in the |
| 543 // block. Since variable declarations are scoped the declared | 545 // block. Since variable declarations are scoped the declared |
| 544 // variable cannot be alive outside the block. Note: this is only | 546 // variable cannot be alive outside the block. Note: this is only |
| 545 // true for nodes where we do joins. | 547 // true for nodes where we do joins. |
| 546 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); | 548 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); |
| 547 JavaScriptBackend backend = compiler.backend; | 549 JavaScriptBackend backend = _compiler.backend; |
| 548 otherLocals.directLocals.forEach((Local local, HInstruction instruction) { | 550 otherLocals.directLocals.forEach((Local local, HInstruction instruction) { |
| 549 // We know 'this' cannot be modified. | 551 // We know 'this' cannot be modified. |
| 550 if (local == closureData.thisLocal) { | 552 if (local == closureData.thisLocal) { |
| 551 assert(directLocals[local] == instruction); | 553 assert(directLocals[local] == instruction); |
| 552 joinedLocals[local] = instruction; | 554 joinedLocals[local] = instruction; |
| 553 } else { | 555 } else { |
| 554 HInstruction mine = directLocals[local]; | 556 HInstruction mine = directLocals[local]; |
| 555 if (mine == null) return; | 557 if (mine == null) return; |
| 556 if (identical(instruction, mine)) { | 558 if (identical(instruction, mine)) { |
| 557 joinedLocals[local] = instruction; | 559 joinedLocals[local] = instruction; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 570 /// localsHandlers into a new one using phis. The new localsHandler is | 572 /// localsHandlers into a new one using phis. The new localsHandler is |
| 571 /// returned. Unless it is also in the list, the current localsHandler is not | 573 /// returned. Unless it is also in the list, the current localsHandler is not |
| 572 /// used for its values, only for its declared variables. This is a way to | 574 /// used for its values, only for its declared variables. This is a way to |
| 573 /// exclude local values from the result when they are no longer in scope. | 575 /// exclude local values from the result when they are no longer in scope. |
| 574 LocalsHandler mergeMultiple( | 576 LocalsHandler mergeMultiple( |
| 575 List<LocalsHandler> localsHandlers, HBasicBlock joinBlock) { | 577 List<LocalsHandler> localsHandlers, HBasicBlock joinBlock) { |
| 576 assert(localsHandlers.length > 0); | 578 assert(localsHandlers.length > 0); |
| 577 if (localsHandlers.length == 1) return localsHandlers[0]; | 579 if (localsHandlers.length == 1) return localsHandlers[0]; |
| 578 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); | 580 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); |
| 579 HInstruction thisValue = null; | 581 HInstruction thisValue = null; |
| 580 JavaScriptBackend backend = compiler.backend; | 582 JavaScriptBackend backend = _compiler.backend; |
| 581 directLocals.forEach((Local local, HInstruction instruction) { | 583 directLocals.forEach((Local local, HInstruction instruction) { |
| 582 if (local != closureData.thisLocal) { | 584 if (local != closureData.thisLocal) { |
| 583 HPhi phi = new HPhi.noInputs(local, backend.dynamicType); | 585 HPhi phi = new HPhi.noInputs(local, backend.dynamicType); |
| 584 joinedLocals[local] = phi; | 586 joinedLocals[local] = phi; |
| 585 joinBlock.addPhi(phi); | 587 joinBlock.addPhi(phi); |
| 586 } else { | 588 } else { |
| 587 // We know that "this" never changes, if it's there. | 589 // We know that "this" never changes, if it's there. |
| 588 // Save it for later. While merging, there is no phi for "this", | 590 // Save it for later. While merging, there is no phi for "this", |
| 589 // so we don't have to special case it in the merge loop. | 591 // so we don't have to special case it in the merge loop. |
| 590 thisValue = instruction; | 592 thisValue = instruction; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 616 return this; | 618 return this; |
| 617 } | 619 } |
| 618 | 620 |
| 619 TypeMask cachedTypeOfThis; | 621 TypeMask cachedTypeOfThis; |
| 620 | 622 |
| 621 TypeMask getTypeOfThis() { | 623 TypeMask getTypeOfThis() { |
| 622 TypeMask result = cachedTypeOfThis; | 624 TypeMask result = cachedTypeOfThis; |
| 623 if (result == null) { | 625 if (result == null) { |
| 624 ThisLocal local = closureData.thisLocal; | 626 ThisLocal local = closureData.thisLocal; |
| 625 ClassElement cls = local.enclosingClass; | 627 ClassElement cls = local.enclosingClass; |
| 626 ClassWorld classWorld = compiler.world; | 628 ClassWorld classWorld = _compiler.world; |
| 627 if (classWorld.isUsedAsMixin(cls)) { | 629 if (classWorld.isUsedAsMixin(cls)) { |
| 628 // If the enclosing class is used as a mixin, [:this:] can be | 630 // If the enclosing class is used as a mixin, [:this:] can be |
| 629 // of the class that mixins the enclosing class. These two | 631 // of the class that mixins the enclosing class. These two |
| 630 // classes do not have a subclass relationship, so, for | 632 // classes do not have a subclass relationship, so, for |
| 631 // simplicity, we mark the type as an interface type. | 633 // simplicity, we mark the type as an interface type. |
| 632 result = new TypeMask.nonNullSubtype(cls.declaration, compiler.world); | 634 result = new TypeMask.nonNullSubtype(cls.declaration, _compiler.world); |
| 633 } else { | 635 } else { |
| 634 result = new TypeMask.nonNullSubclass(cls.declaration, compiler.world); | 636 result = new TypeMask.nonNullSubclass(cls.declaration, _compiler.world); |
| 635 } | 637 } |
| 636 cachedTypeOfThis = result; | 638 cachedTypeOfThis = result; |
| 637 } | 639 } |
| 638 return result; | 640 return result; |
| 639 } | 641 } |
| 640 | 642 |
| 641 Map<Element, TypeMask> cachedTypesOfCapturedVariables = | 643 Map<Element, TypeMask> cachedTypesOfCapturedVariables = |
| 642 new Map<Element, TypeMask>(); | 644 new Map<Element, TypeMask>(); |
| 643 | 645 |
| 644 TypeMask getTypeOfCapturedVariable(Element element) { | 646 TypeMask getTypeOfCapturedVariable(Element element) { |
| 645 assert(element.isField); | 647 assert(element.isField); |
| 646 return cachedTypesOfCapturedVariables.putIfAbsent(element, () { | 648 return cachedTypesOfCapturedVariables.putIfAbsent(element, () { |
| 647 return TypeMaskFactory.inferredTypeForElement(element, compiler); | 649 return TypeMaskFactory.inferredTypeForElement(element, _compiler); |
| 648 }); | 650 }); |
| 649 } | 651 } |
| 650 | 652 |
| 651 /// Variables stored in the current activation. These variables are | 653 /// Variables stored in the current activation. These variables are |
| 652 /// being updated in try/catch blocks, and should be | 654 /// being updated in try/catch blocks, and should be |
| 653 /// accessed indirectly through [HLocalGet] and [HLocalSet]. | 655 /// accessed indirectly through [HLocalGet] and [HLocalSet]. |
| 654 Map<Local, HLocalValue> activationVariables = <Local, HLocalValue>{}; | 656 Map<Local, HLocalValue> activationVariables = <Local, HLocalValue>{}; |
| 655 } | 657 } |
| OLD | NEW |