| 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 14 matching lines...) Expand all Loading... |
| 25 /// The values of locals that can be directly accessed (without redirections | 25 /// The values of locals that can be directly accessed (without redirections |
| 26 /// to boxes or closure-fields). | 26 /// to boxes or closure-fields). |
| 27 /// | 27 /// |
| 28 /// [directLocals] is iterated, so it is "insertion ordered" to make the | 28 /// [directLocals] is iterated, so it is "insertion ordered" to make the |
| 29 /// iteration order a function only of insertions and not a function of | 29 /// iteration order a function only of insertions and not a function of |
| 30 /// e.g. Element hash codes. I'd prefer to use a SortedMap but some elements | 30 /// e.g. Element hash codes. I'd prefer to use a SortedMap but some elements |
| 31 /// don't have source locations for [Elements.compareByPosition]. | 31 /// don't have source locations for [Elements.compareByPosition]. |
| 32 Map<Local, HInstruction> directLocals = new Map<Local, HInstruction>(); | 32 Map<Local, HInstruction> directLocals = new Map<Local, HInstruction>(); |
| 33 Map<Local, FieldEntity> redirectionMapping = new Map<Local, FieldEntity>(); | 33 Map<Local, FieldEntity> redirectionMapping = new Map<Local, FieldEntity>(); |
| 34 final GraphBuilder builder; | 34 final GraphBuilder builder; |
| 35 ClosureRepresentationInfo closureData; | 35 ScopeInfo scopeInfo; |
| 36 Map<TypeVariableType, TypeVariableLocal> typeVariableLocals = | 36 Map<TypeVariableType, TypeVariableLocal> typeVariableLocals = |
| 37 new Map<TypeVariableType, TypeVariableLocal>(); | 37 new Map<TypeVariableType, TypeVariableLocal>(); |
| 38 final Entity executableContext; | 38 final Entity executableContext; |
| 39 final MemberEntity memberContext; | 39 final MemberEntity memberContext; |
| 40 | 40 |
| 41 /// The class that defines the current type environment or null if no type | 41 /// The class that defines the current type environment or null if no type |
| 42 /// variables are in scope. | 42 /// variables are in scope. |
| 43 final ClassEntity contextClass; | 43 final ClassEntity contextClass; |
| 44 | 44 |
| 45 /// The type of the current instance, if concrete. | 45 /// The type of the current instance, if concrete. |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 /// copy the [directLocals], since the other fields can be shared | 106 /// copy the [directLocals], since the other fields can be shared |
| 107 /// throughout the AST visit. | 107 /// throughout the AST visit. |
| 108 LocalsHandler.from(LocalsHandler other) | 108 LocalsHandler.from(LocalsHandler other) |
| 109 : directLocals = new Map<Local, HInstruction>.from(other.directLocals), | 109 : directLocals = new Map<Local, HInstruction>.from(other.directLocals), |
| 110 redirectionMapping = other.redirectionMapping, | 110 redirectionMapping = other.redirectionMapping, |
| 111 executableContext = other.executableContext, | 111 executableContext = other.executableContext, |
| 112 memberContext = other.memberContext, | 112 memberContext = other.memberContext, |
| 113 contextClass = other.contextClass, | 113 contextClass = other.contextClass, |
| 114 instanceType = other.instanceType, | 114 instanceType = other.instanceType, |
| 115 builder = other.builder, | 115 builder = other.builder, |
| 116 closureData = other.closureData, | 116 scopeInfo = other.scopeInfo, |
| 117 _nativeData = other._nativeData, | 117 _nativeData = other._nativeData, |
| 118 _interceptorData = other._interceptorData, | 118 _interceptorData = other._interceptorData, |
| 119 activationVariables = other.activationVariables, | 119 activationVariables = other.activationVariables, |
| 120 cachedTypeOfThis = other.cachedTypeOfThis, | 120 cachedTypeOfThis = other.cachedTypeOfThis, |
| 121 cachedTypesOfCapturedVariables = other.cachedTypesOfCapturedVariables; | 121 cachedTypesOfCapturedVariables = other.cachedTypesOfCapturedVariables; |
| 122 | 122 |
| 123 /// Redirects accesses from element [from] to element [to]. The [to] element | 123 /// Redirects accesses from element [from] to element [to]. The [to] element |
| 124 /// must be a boxed variable or a variable that is stored in a closure-field. | 124 /// must be a boxed variable or a variable that is stored in a closure-field. |
| 125 void redirectElement(Local from, FieldEntity to) { | 125 void redirectElement(Local from, FieldEntity to) { |
| 126 assert(redirectionMapping[from] == null); | 126 assert(redirectionMapping[from] == null); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after 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( | 200 void startFunction(MemberEntity element, ScopeInfo scopeInfo, |
| 201 MemberEntity element, | 201 ClosureAnalysisInfo scopeData, Map<Local, TypeMask> parameters, |
| 202 ClosureRepresentationInfo closureData, | |
| 203 ClosureAnalysisInfo scopeData, | |
| 204 Map<Local, TypeMask> parameters, | |
| 205 {bool isGenerativeConstructorBody}) { | 202 {bool isGenerativeConstructorBody}) { |
| 206 assert(!(element is MemberElement && !element.isImplementation), | 203 assert(!(element is MemberElement && !element.isImplementation), |
| 207 failedAt(element)); | 204 failedAt(element)); |
| 208 this.closureData = closureData; | 205 this.scopeInfo = scopeInfo; |
| 209 | 206 |
| 210 parameters.forEach((Local local, TypeMask typeMask) { | 207 parameters.forEach((Local local, TypeMask typeMask) { |
| 211 if (isGenerativeConstructorBody) { | 208 if (isGenerativeConstructorBody) { |
| 212 if (scopeData.isCaptured(local)) { | 209 if (scopeData.isCaptured(local)) { |
| 213 // The parameter will be a field in the box passed as the | 210 // The parameter will be a field in the box passed as the |
| 214 // last parameter. So no need to have it. | 211 // last parameter. So no need to have it. |
| 215 return; | 212 return; |
| 216 } | 213 } |
| 217 } | 214 } |
| 218 HInstruction parameter = builder.addParameter(local, typeMask); | 215 HInstruction parameter = builder.addParameter(local, typeMask); |
| 219 builder.parameters[local] = parameter; | 216 builder.parameters[local] = parameter; |
| 220 directLocals[local] = parameter; | 217 directLocals[local] = parameter; |
| 221 }); | 218 }); |
| 222 | 219 |
| 223 enterScope(scopeData, | 220 enterScope(scopeData, |
| 224 forGenerativeConstructorBody: isGenerativeConstructorBody); | 221 forGenerativeConstructorBody: isGenerativeConstructorBody); |
| 225 | 222 |
| 226 if (closureData.isClosure) { | 223 // When we remove the element model, we can just use the first check |
| 224 // (because the underlying elements won't all be *both* ScopeInfos and |
| 225 // ClosureRepresentationInfos). |
| 226 if (scopeInfo is ClosureRepresentationInfo && scopeInfo.isClosure) { |
| 227 ClosureRepresentationInfo closureData = scopeInfo; |
| 227 // If the freeVariableMapping is not empty, then this function was a | 228 // If the freeVariableMapping is not empty, then this function was a |
| 228 // nested closure that captures variables. Redirect the captured | 229 // nested closure that captures variables. Redirect the captured |
| 229 // variables to fields in the closure. | 230 // variables to fields in the closure. |
| 230 closureData.forEachFreeVariable((Local from, FieldEntity to) { | 231 closureData.forEachFreeVariable((Local from, FieldEntity to) { |
| 231 redirectElement(from, to); | 232 redirectElement(from, to); |
| 232 }); | 233 }); |
| 233 // Inside closure redirect references to itself to [:this:]. | 234 // Inside closure redirect references to itself to [:this:]. |
| 234 HThis thisInstruction = | 235 HThis thisInstruction = |
| 235 new HThis(closureData.thisLocal, commonMasks.nonNullType); | 236 new HThis(closureData.thisLocal, commonMasks.nonNullType); |
| 236 builder.graph.thisInstruction = thisInstruction; | 237 builder.graph.thisInstruction = thisInstruction; |
| 237 builder.graph.entry.addAtEntry(thisInstruction); | 238 builder.graph.entry.addAtEntry(thisInstruction); |
| 238 updateLocal(closureData.closureEntity, thisInstruction); | 239 updateLocal(closureData.closureEntity, thisInstruction); |
| 239 } else if (element.isInstanceMember) { | 240 } else if (element.isInstanceMember) { |
| 240 // Once closures have been mapped to classes their instance members might | 241 // Once closures have been mapped to classes their instance members might |
| 241 // not have any thisElement if the closure was created inside a static | 242 // not have any thisElement if the closure was created inside a static |
| 242 // context. | 243 // context. |
| 243 HThis thisInstruction = new HThis(closureData.thisLocal, getTypeOfThis()); | 244 HThis thisInstruction = new HThis(scopeInfo.thisLocal, getTypeOfThis()); |
| 244 builder.graph.thisInstruction = thisInstruction; | 245 builder.graph.thisInstruction = thisInstruction; |
| 245 builder.graph.entry.addAtEntry(thisInstruction); | 246 builder.graph.entry.addAtEntry(thisInstruction); |
| 246 directLocals[closureData.thisLocal] = thisInstruction; | 247 directLocals[scopeInfo.thisLocal] = thisInstruction; |
| 247 } | 248 } |
| 248 | 249 |
| 249 // If this method is an intercepted method, add the extra | 250 // If this method is an intercepted method, add the extra |
| 250 // parameter to it, that is the actual receiver for intercepted | 251 // parameter to it, that is the actual receiver for intercepted |
| 251 // classes, or the same as [:this:] for non-intercepted classes. | 252 // classes, or the same as [:this:] for non-intercepted classes. |
| 252 ClassEntity cls = element.enclosingClass; | 253 ClassEntity cls = element.enclosingClass; |
| 253 | 254 |
| 254 // When the class extends a native class, the instance is pre-constructed | 255 // When the class extends a native class, the instance is pre-constructed |
| 255 // and passed to the generative constructor factory function as a parameter. | 256 // and passed to the generative constructor factory function as a parameter. |
| 256 // Instead of allocating and initializing the object, the constructor | 257 // Instead of allocating and initializing the object, the constructor |
| 257 // 'upgrades' the native subclass object by initializing the Dart fields. | 258 // 'upgrades' the native subclass object by initializing the Dart fields. |
| 258 bool isNativeUpgradeFactory = element is ConstructorEntity && | 259 bool isNativeUpgradeFactory = element is ConstructorEntity && |
| 259 element.isGenerativeConstructor && | 260 element.isGenerativeConstructor && |
| 260 _nativeData.isNativeOrExtendsNative(cls); | 261 _nativeData.isNativeOrExtendsNative(cls); |
| 261 if (_interceptorData.isInterceptedMethod(element)) { | 262 if (_interceptorData.isInterceptedMethod(element)) { |
| 262 bool isInterceptedClass = _interceptorData.isInterceptedClass(cls); | 263 bool isInterceptedClass = _interceptorData.isInterceptedClass(cls); |
| 263 String name = isInterceptedClass ? 'receiver' : '_'; | 264 String name = isInterceptedClass ? 'receiver' : '_'; |
| 264 SyntheticLocal parameter = createLocal(name); | 265 SyntheticLocal parameter = createLocal(name); |
| 265 HParameterValue value = new HParameterValue(parameter, getTypeOfThis()); | 266 HParameterValue value = new HParameterValue(parameter, getTypeOfThis()); |
| 266 builder.graph.explicitReceiverParameter = value; | 267 builder.graph.explicitReceiverParameter = value; |
| 267 builder.graph.entry.addAfter(directLocals[closureData.thisLocal], value); | 268 builder.graph.entry.addAfter(directLocals[scopeInfo.thisLocal], value); |
| 268 if (builder.lastAddedParameter == null) { | 269 if (builder.lastAddedParameter == null) { |
| 269 // If this is the first parameter inserted, make sure it stays first. | 270 // If this is the first parameter inserted, make sure it stays first. |
| 270 builder.lastAddedParameter = value; | 271 builder.lastAddedParameter = value; |
| 271 } | 272 } |
| 272 if (isInterceptedClass) { | 273 if (isInterceptedClass) { |
| 273 // Only use the extra parameter in intercepted classes. | 274 // Only use the extra parameter in intercepted classes. |
| 274 directLocals[closureData.thisLocal] = value; | 275 directLocals[scopeInfo.thisLocal] = value; |
| 275 } | 276 } |
| 276 } else if (isNativeUpgradeFactory) { | 277 } else if (isNativeUpgradeFactory) { |
| 277 SyntheticLocal parameter = createLocal('receiver'); | 278 SyntheticLocal parameter = createLocal('receiver'); |
| 278 // Unlike `this`, receiver is nullable since direct calls to generative | 279 // Unlike `this`, receiver is nullable since direct calls to generative |
| 279 // constructor call the constructor with `null`. | 280 // constructor call the constructor with `null`. |
| 280 HParameterValue value = | 281 HParameterValue value = |
| 281 new HParameterValue(parameter, new TypeMask.exact(cls, closedWorld)); | 282 new HParameterValue(parameter, new TypeMask.exact(cls, closedWorld)); |
| 282 builder.graph.explicitReceiverParameter = value; | 283 builder.graph.explicitReceiverParameter = value; |
| 283 builder.graph.entry.addAtEntry(value); | 284 builder.graph.entry.addAtEntry(value); |
| 284 if (builder.lastAddedParameter == null) { | 285 if (builder.lastAddedParameter == null) { |
| 285 // If this is the first parameter inserted, make sure it stays first. | 286 // If this is the first parameter inserted, make sure it stays first. |
| 286 builder.lastAddedParameter = value; | 287 builder.lastAddedParameter = value; |
| 287 } | 288 } |
| 288 } | 289 } |
| 289 } | 290 } |
| 290 | 291 |
| 291 /// Returns true if the local can be accessed directly. Boxed variables or | 292 /// Returns true if the local can be accessed directly. Boxed variables or |
| 292 /// captured variables that are stored in the closure-field return [:false:]. | 293 /// captured variables that are stored in the closure-field return [:false:]. |
| 293 bool isAccessedDirectly(Local local) { | 294 bool isAccessedDirectly(Local local) { |
| 294 assert(local != null); | 295 assert(local != null); |
| 295 return !redirectionMapping.containsKey(local) && | 296 return !redirectionMapping.containsKey(local) && |
| 296 !closureData.variableIsUsedInTryOrSync(local); | 297 !scopeInfo.variablesUsedInTryOrSync.contains(local); |
| 297 } | 298 } |
| 298 | 299 |
| 299 bool isStoredInClosureField(Local local) { | 300 bool isStoredInClosureField(Local local) { |
| 300 assert(local != null); | 301 assert(local != null); |
| 301 if (isAccessedDirectly(local)) return false; | 302 if (isAccessedDirectly(local)) return false; |
| 303 if (scopeInfo is! ClosureRepresentationInfo) return false; |
| 302 FieldEntity redirectTarget = redirectionMapping[local]; | 304 FieldEntity redirectTarget = redirectionMapping[local]; |
| 303 if (redirectTarget == null) return false; | 305 if (redirectTarget == null) return false; |
| 304 return redirectTarget is ClosureFieldElement; | 306 return redirectTarget is ClosureFieldElement; |
| 305 } | 307 } |
| 306 | 308 |
| 307 bool isBoxed(Local local) { | 309 bool isBoxed(Local local) { |
| 308 if (isAccessedDirectly(local)) return false; | 310 if (isAccessedDirectly(local)) return false; |
| 309 if (isStoredInClosureField(local)) return false; | 311 if (isStoredInClosureField(local)) return false; |
| 310 return redirectionMapping.containsKey(local); | 312 return redirectionMapping.containsKey(local); |
| 311 } | 313 } |
| 312 | 314 |
| 313 bool _isUsedInTryOrGenerator(Local local) { | 315 bool _isUsedInTryOrGenerator(Local local) { |
| 314 return closureData.variableIsUsedInTryOrSync(local); | 316 return scopeInfo.variablesUsedInTryOrSync.contains(local); |
| 315 } | 317 } |
| 316 | 318 |
| 317 /// Returns an [HInstruction] for the given element. If the element is | 319 /// Returns an [HInstruction] for the given element. If the element is |
| 318 /// boxed or stored in a closure then the method generates code to retrieve | 320 /// boxed or stored in a closure then the method generates code to retrieve |
| 319 /// the value. | 321 /// the value. |
| 320 HInstruction readLocal(Local local, {SourceInformation sourceInformation}) { | 322 HInstruction readLocal(Local local, {SourceInformation sourceInformation}) { |
| 321 if (isAccessedDirectly(local)) { | 323 if (isAccessedDirectly(local)) { |
| 322 if (directLocals[local] == null) { | 324 if (directLocals[local] == null) { |
| 323 if (local is TypeVariableLocal) { | 325 if (local is TypeVariableLocal) { |
| 324 throw new SpannableAssertionFailure( | 326 throw new SpannableAssertionFailure( |
| 325 CURRENT_ELEMENT_SPANNABLE, | 327 CURRENT_ELEMENT_SPANNABLE, |
| 326 "Runtime type information not available for $local " | 328 "Runtime type information not available for $local " |
| 327 "in $executableContext."); | 329 "in $executableContext."); |
| 328 } else { | 330 } else { |
| 329 throw new SpannableAssertionFailure( | 331 throw new SpannableAssertionFailure( |
| 330 local, | 332 local, |
| 331 "Cannot find value $local in ${directLocals.keys} for " | 333 "Cannot find value $local in ${directLocals.keys} for " |
| 332 "$executableContext."); | 334 "$executableContext."); |
| 333 } | 335 } |
| 334 } | 336 } |
| 335 HInstruction value = directLocals[local]; | 337 HInstruction value = directLocals[local]; |
| 336 if (sourceInformation != null) { | 338 if (sourceInformation != null) { |
| 337 value = new HRef(value, sourceInformation); | 339 value = new HRef(value, sourceInformation); |
| 338 builder.add(value); | 340 builder.add(value); |
| 339 } | 341 } |
| 340 return value; | 342 return value; |
| 341 } else if (isStoredInClosureField(local)) { | 343 } else if (isStoredInClosureField(local)) { |
| 344 ClosureRepresentationInfo closureData = scopeInfo; |
| 342 ClosureFieldElement redirect = redirectionMapping[local]; | 345 ClosureFieldElement redirect = redirectionMapping[local]; |
| 343 HInstruction receiver = readLocal(closureData.closureEntity); | 346 HInstruction receiver = readLocal(closureData.closureEntity); |
| 344 TypeMask type = local is BoxLocal | 347 TypeMask type = local is BoxLocal |
| 345 ? commonMasks.nonNullType | 348 ? commonMasks.nonNullType |
| 346 : getTypeOfCapturedVariable(redirect); | 349 : getTypeOfCapturedVariable(redirect); |
| 347 HInstruction fieldGet = new HFieldGet(redirect, receiver, type); | 350 HInstruction fieldGet = new HFieldGet(redirect, receiver, type); |
| 348 builder.add(fieldGet); | 351 builder.add(fieldGet); |
| 349 return fieldGet..sourceInformation = sourceInformation; | 352 return fieldGet..sourceInformation = sourceInformation; |
| 350 } else if (isBoxed(local)) { | 353 } else if (isBoxed(local)) { |
| 351 BoxFieldElement redirect = redirectionMapping[local]; | 354 BoxFieldElement redirect = redirectionMapping[local]; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 363 assert(_isUsedInTryOrGenerator(local)); | 366 assert(_isUsedInTryOrGenerator(local)); |
| 364 HLocalValue localValue = getLocal(local); | 367 HLocalValue localValue = getLocal(local); |
| 365 HInstruction instruction = new HLocalGet( | 368 HInstruction instruction = new HLocalGet( |
| 366 local, localValue, commonMasks.dynamicType, sourceInformation); | 369 local, localValue, commonMasks.dynamicType, sourceInformation); |
| 367 builder.add(instruction); | 370 builder.add(instruction); |
| 368 return instruction; | 371 return instruction; |
| 369 } | 372 } |
| 370 } | 373 } |
| 371 | 374 |
| 372 HInstruction readThis() { | 375 HInstruction readThis() { |
| 373 HInstruction res = readLocal(closureData.thisLocal); | 376 HInstruction res = readLocal(scopeInfo.thisLocal); |
| 374 if (res.instructionType == null) { | 377 if (res.instructionType == null) { |
| 375 res.instructionType = getTypeOfThis(); | 378 res.instructionType = getTypeOfThis(); |
| 376 } | 379 } |
| 377 return res; | 380 return res; |
| 378 } | 381 } |
| 379 | 382 |
| 380 HLocalValue getLocal(Local local, {SourceInformation sourceInformation}) { | 383 HLocalValue getLocal(Local local, {SourceInformation sourceInformation}) { |
| 381 // If the element is a parameter, we already have a | 384 // If the element is a parameter, we already have a |
| 382 // HParameterValue for it. We cannot create another one because | 385 // HParameterValue for it. We cannot create another one because |
| 383 // it could then have another name than the real parameter. And | 386 // it could then have another name than the real parameter. And |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 487 /// from the back edge). Populate the phis with the current values. | 490 /// from the back edge). Populate the phis with the current values. |
| 488 void beginLoopHeader(HBasicBlock loopEntry) { | 491 void beginLoopHeader(HBasicBlock loopEntry) { |
| 489 // Create a copy because we modify the map while iterating over it. | 492 // Create a copy because we modify the map while iterating over it. |
| 490 Map<Local, HInstruction> savedDirectLocals = | 493 Map<Local, HInstruction> savedDirectLocals = |
| 491 new Map<Local, HInstruction>.from(directLocals); | 494 new Map<Local, HInstruction>.from(directLocals); |
| 492 | 495 |
| 493 // Create phis for all elements in the definitions environment. | 496 // Create phis for all elements in the definitions environment. |
| 494 savedDirectLocals.forEach((Local local, HInstruction instruction) { | 497 savedDirectLocals.forEach((Local local, HInstruction instruction) { |
| 495 if (isAccessedDirectly(local)) { | 498 if (isAccessedDirectly(local)) { |
| 496 // We know 'this' cannot be modified. | 499 // We know 'this' cannot be modified. |
| 497 if (local != closureData.thisLocal) { | 500 if (local != scopeInfo.thisLocal) { |
| 498 HPhi phi = | 501 HPhi phi = |
| 499 new HPhi.singleInput(local, instruction, commonMasks.dynamicType); | 502 new HPhi.singleInput(local, instruction, commonMasks.dynamicType); |
| 500 loopEntry.addPhi(phi); | 503 loopEntry.addPhi(phi); |
| 501 directLocals[local] = phi; | 504 directLocals[local] = phi; |
| 502 } else { | 505 } else { |
| 503 directLocals[local] = instruction; | 506 directLocals[local] = instruction; |
| 504 } | 507 } |
| 505 } | 508 } |
| 506 }); | 509 }); |
| 507 } | 510 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 544 /// first input, and the otherLocals instruction as the second. | 547 /// first input, and the otherLocals instruction as the second. |
| 545 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { | 548 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { |
| 546 // If an element is in one map but not the other we can safely | 549 // If an element is in one map but not the other we can safely |
| 547 // ignore it. It means that a variable was declared in the | 550 // ignore it. It means that a variable was declared in the |
| 548 // block. Since variable declarations are scoped the declared | 551 // block. Since variable declarations are scoped the declared |
| 549 // variable cannot be alive outside the block. Note: this is only | 552 // variable cannot be alive outside the block. Note: this is only |
| 550 // true for nodes where we do joins. | 553 // true for nodes where we do joins. |
| 551 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); | 554 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); |
| 552 otherLocals.directLocals.forEach((Local local, HInstruction instruction) { | 555 otherLocals.directLocals.forEach((Local local, HInstruction instruction) { |
| 553 // We know 'this' cannot be modified. | 556 // We know 'this' cannot be modified. |
| 554 if (local == closureData.thisLocal) { | 557 if (local == scopeInfo.thisLocal) { |
| 555 assert(directLocals[local] == instruction); | 558 assert(directLocals[local] == instruction); |
| 556 joinedLocals[local] = instruction; | 559 joinedLocals[local] = instruction; |
| 557 } else { | 560 } else { |
| 558 HInstruction mine = directLocals[local]; | 561 HInstruction mine = directLocals[local]; |
| 559 if (mine == null) return; | 562 if (mine == null) return; |
| 560 if (identical(instruction, mine)) { | 563 if (identical(instruction, mine)) { |
| 561 joinedLocals[local] = instruction; | 564 joinedLocals[local] = instruction; |
| 562 } else { | 565 } else { |
| 563 HInstruction phi = new HPhi.manyInputs(local, | 566 HInstruction phi = new HPhi.manyInputs(local, |
| 564 <HInstruction>[mine, instruction], commonMasks.dynamicType); | 567 <HInstruction>[mine, instruction], commonMasks.dynamicType); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 575 /// returned. Unless it is also in the list, the current localsHandler is not | 578 /// returned. Unless it is also in the list, the current localsHandler is not |
| 576 /// used for its values, only for its declared variables. This is a way to | 579 /// used for its values, only for its declared variables. This is a way to |
| 577 /// exclude local values from the result when they are no longer in scope. | 580 /// exclude local values from the result when they are no longer in scope. |
| 578 LocalsHandler mergeMultiple( | 581 LocalsHandler mergeMultiple( |
| 579 List<LocalsHandler> localsHandlers, HBasicBlock joinBlock) { | 582 List<LocalsHandler> localsHandlers, HBasicBlock joinBlock) { |
| 580 assert(localsHandlers.length > 0); | 583 assert(localsHandlers.length > 0); |
| 581 if (localsHandlers.length == 1) return localsHandlers.single; | 584 if (localsHandlers.length == 1) return localsHandlers.single; |
| 582 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); | 585 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); |
| 583 HInstruction thisValue = null; | 586 HInstruction thisValue = null; |
| 584 directLocals.forEach((Local local, HInstruction instruction) { | 587 directLocals.forEach((Local local, HInstruction instruction) { |
| 585 if (local != closureData.thisLocal) { | 588 if (local != scopeInfo.thisLocal) { |
| 586 HPhi phi = new HPhi.noInputs(local, commonMasks.dynamicType); | 589 HPhi phi = new HPhi.noInputs(local, commonMasks.dynamicType); |
| 587 joinedLocals[local] = phi; | 590 joinedLocals[local] = phi; |
| 588 joinBlock.addPhi(phi); | 591 joinBlock.addPhi(phi); |
| 589 } else { | 592 } else { |
| 590 // We know that "this" never changes, if it's there. | 593 // We know that "this" never changes, if it's there. |
| 591 // Save it for later. While merging, there is no phi for "this", | 594 // Save it for later. While merging, there is no phi for "this", |
| 592 // so we don't have to special case it in the merge loop. | 595 // so we don't have to special case it in the merge loop. |
| 593 thisValue = instruction; | 596 thisValue = instruction; |
| 594 } | 597 } |
| 595 }); | 598 }); |
| 596 for (LocalsHandler handler in localsHandlers) { | 599 for (LocalsHandler handler in localsHandlers) { |
| 597 handler.directLocals.forEach((Local local, HInstruction instruction) { | 600 handler.directLocals.forEach((Local local, HInstruction instruction) { |
| 598 HPhi phi = joinedLocals[local]; | 601 HPhi phi = joinedLocals[local]; |
| 599 if (phi != null) { | 602 if (phi != null) { |
| 600 phi.addInput(instruction); | 603 phi.addInput(instruction); |
| 601 } | 604 } |
| 602 }); | 605 }); |
| 603 } | 606 } |
| 604 if (thisValue != null) { | 607 if (thisValue != null) { |
| 605 // If there was a "this" for the scope, add it to the new locals. | 608 // If there was a "this" for the scope, add it to the new locals. |
| 606 joinedLocals[closureData.thisLocal] = thisValue; | 609 joinedLocals[scopeInfo.thisLocal] = thisValue; |
| 607 } | 610 } |
| 608 | 611 |
| 609 // Remove locals that are not in all handlers. | 612 // Remove locals that are not in all handlers. |
| 610 directLocals = new Map<Local, HInstruction>(); | 613 directLocals = new Map<Local, HInstruction>(); |
| 611 joinedLocals.forEach((Local local, HInstruction instruction) { | 614 joinedLocals.forEach((Local local, HInstruction instruction) { |
| 612 if (local != closureData.thisLocal && | 615 if (local != scopeInfo.thisLocal && |
| 613 instruction.inputs.length != localsHandlers.length) { | 616 instruction.inputs.length != localsHandlers.length) { |
| 614 joinBlock.removePhi(instruction); | 617 joinBlock.removePhi(instruction); |
| 615 } else { | 618 } else { |
| 616 directLocals[local] = instruction; | 619 directLocals[local] = instruction; |
| 617 } | 620 } |
| 618 }); | 621 }); |
| 619 return this; | 622 return this; |
| 620 } | 623 } |
| 621 | 624 |
| 622 TypeMask cachedTypeOfThis; | 625 TypeMask cachedTypeOfThis; |
| 623 | 626 |
| 624 TypeMask getTypeOfThis() { | 627 TypeMask getTypeOfThis() { |
| 625 TypeMask result = cachedTypeOfThis; | 628 TypeMask result = cachedTypeOfThis; |
| 626 if (result == null) { | 629 if (result == null) { |
| 627 ThisLocal local = closureData.thisLocal; | 630 ThisLocal local = scopeInfo.thisLocal; |
| 628 ClassEntity cls = local.enclosingClass; | 631 ClassEntity cls = local.enclosingClass; |
| 629 if (closedWorld.isUsedAsMixin(cls)) { | 632 if (closedWorld.isUsedAsMixin(cls)) { |
| 630 // If the enclosing class is used as a mixin, [:this:] can be | 633 // If the enclosing class is used as a mixin, [:this:] can be |
| 631 // of the class that mixins the enclosing class. These two | 634 // of the class that mixins the enclosing class. These two |
| 632 // classes do not have a subclass relationship, so, for | 635 // classes do not have a subclass relationship, so, for |
| 633 // simplicity, we mark the type as an interface type. | 636 // simplicity, we mark the type as an interface type. |
| 634 result = new TypeMask.nonNullSubtype(cls, closedWorld); | 637 result = new TypeMask.nonNullSubtype(cls, closedWorld); |
| 635 } else { | 638 } else { |
| 636 result = new TypeMask.nonNullSubclass(cls, closedWorld); | 639 result = new TypeMask.nonNullSubclass(cls, closedWorld); |
| 637 } | 640 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 670 final MemberEntity memberContext; | 673 final MemberEntity memberContext; |
| 671 | 674 |
| 672 // Avoid slow Object.hashCode. | 675 // Avoid slow Object.hashCode. |
| 673 final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); | 676 final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); |
| 674 static int _nextHashCode = 0; | 677 static int _nextHashCode = 0; |
| 675 | 678 |
| 676 SyntheticLocal(this.name, this.executableContext, this.memberContext); | 679 SyntheticLocal(this.name, this.executableContext, this.memberContext); |
| 677 | 680 |
| 678 toString() => 'SyntheticLocal($name)'; | 681 toString() => 'SyntheticLocal($name)'; |
| 679 } | 682 } |
| OLD | NEW |