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.variableIsUsedInTryOrSync(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.variableIsUsedInTryOrSync(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 |