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'; |
11 import '../js_backend/native_data.dart'; | 11 import '../js_backend/native_data.dart'; |
12 import '../js_backend/interceptor_data.dart'; | 12 import '../js_backend/interceptor_data.dart'; |
| 13 import '../js_model/closure.dart' show JClosureField, JRecord; |
13 import '../tree/tree.dart' as ast; | 14 import '../tree/tree.dart' as ast; |
14 import '../types/types.dart'; | 15 import '../types/types.dart'; |
15 import '../world.dart' show ClosedWorld; | 16 import '../world.dart' show ClosedWorld; |
16 | 17 |
17 import 'graph_builder.dart'; | 18 import 'graph_builder.dart'; |
18 import 'nodes.dart'; | 19 import 'nodes.dart'; |
19 import 'types.dart'; | 20 import 'types.dart'; |
20 | 21 |
21 /// Keeps track of locals (including parameters and phis) when building. The | 22 /// Keeps track of locals (including parameters and phis) when building. The |
22 /// 'this' reference is treated as parameter and hence handled by this class, | 23 /// 'this' reference is treated as parameter and hence handled by this class, |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 // The box is passed as a parameter to a generative | 148 // The box is passed as a parameter to a generative |
148 // constructor body. | 149 // constructor body. |
149 box = builder.addParameter(closureInfo.context, commonMasks.nonNullType); | 150 box = builder.addParameter(closureInfo.context, commonMasks.nonNullType); |
150 } else { | 151 } else { |
151 box = createBox(); | 152 box = createBox(); |
152 } | 153 } |
153 // Add the box to the known locals. | 154 // Add the box to the known locals. |
154 directLocals[closureInfo.context] = box; | 155 directLocals[closureInfo.context] = box; |
155 // Make sure that accesses to the boxed locals go into the box. We also | 156 // Make sure that accesses to the boxed locals go into the box. We also |
156 // need to make sure that parameters are copied into the box if necessary. | 157 // need to make sure that parameters are copied into the box if necessary. |
157 closureInfo.forEachBoxedVariable((_from, _to) { | 158 closureInfo.forEachBoxedVariable((Local from, FieldEntity boxTo) { |
158 LocalVariableElement from = _from; | |
159 BoxFieldElement to = _to; | |
160 // The [from] can only be a parameter for function-scopes and not | 159 // The [from] can only be a parameter for function-scopes and not |
161 // loop scopes. | 160 // loop scopes. |
162 if (from.isRegularParameter && !forGenerativeConstructorBody) { | 161 if (from.isRegularParameter && !forGenerativeConstructorBody) { |
163 // Now that the redirection is set up, the update to the local will | 162 // Now that the redirection is set up, the update to the local will |
164 // write the parameter value into the box. | 163 // write the parameter value into the box. |
165 // Store the captured parameter in the box. Get the current value | 164 // Store the captured parameter in the box. Get the current value |
166 // before we put the redirection in place. | 165 // before we put the redirection in place. |
167 // We don't need to update the local for a generative | 166 // We don't need to update the local for a generative |
168 // constructor body, because it receives a box that already | 167 // constructor body, because it receives a box that already |
169 // contains the updates as the last parameter. | 168 // contains the updates as the last parameter. |
170 HInstruction instruction = readLocal(from); | 169 HInstruction instruction = readLocal(from); |
171 redirectElement(from, to); | 170 redirectElement(from, boxTo); |
172 updateLocal(from, instruction); | 171 updateLocal(from, instruction); |
173 } else { | 172 } else { |
174 redirectElement(from, to); | 173 redirectElement(from, boxTo); |
175 } | 174 } |
176 }); | 175 }); |
177 } | 176 } |
178 | 177 |
179 /// Replaces the current box with a new box and copies over the given list | 178 /// Replaces the current box with a new box and copies over the given list |
180 /// of elements from the old box into the new box. | 179 /// of elements from the old box into the new box. |
181 void updateCaptureBox(Local currentBox, List<Local> toBeCopiedElements) { | 180 void updateCaptureBox(Local currentBox, List<Local> toBeCopiedElements) { |
182 // Create a new box and copy over the values from the old box into the | 181 // Create a new box and copy over the values from the old box into the |
183 // new one. | 182 // new one. |
184 HInstruction oldBox = readLocal(currentBox); | 183 HInstruction oldBox = readLocal(currentBox); |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 assert(local != null); | 294 assert(local != null); |
296 return !redirectionMapping.containsKey(local) && | 295 return !redirectionMapping.containsKey(local) && |
297 !scopeInfo.localIsUsedInTryOrSync(local); | 296 !scopeInfo.localIsUsedInTryOrSync(local); |
298 } | 297 } |
299 | 298 |
300 bool isStoredInClosureField(Local local) { | 299 bool isStoredInClosureField(Local local) { |
301 assert(local != null); | 300 assert(local != null); |
302 if (isAccessedDirectly(local)) return false; | 301 if (isAccessedDirectly(local)) return false; |
303 if (scopeInfo is! ClosureRepresentationInfo) return false; | 302 if (scopeInfo is! ClosureRepresentationInfo) return false; |
304 FieldEntity redirectTarget = redirectionMapping[local]; | 303 FieldEntity redirectTarget = redirectionMapping[local]; |
| 304 print( |
| 305 'is stored in closure field $local ${isAccessedDirectly(local)} ${scopeI
nfo.runtimeType} ${redirectTarget.runtimeType}'); |
305 if (redirectTarget == null) return false; | 306 if (redirectTarget == null) return false; |
306 return redirectTarget is ClosureFieldElement; | 307 return redirectTarget is ClosureFieldElement || |
| 308 redirectTarget is JClosureField; |
307 } | 309 } |
308 | 310 |
309 bool isBoxed(Local local) { | 311 bool isBoxed(Local local) { |
310 if (isAccessedDirectly(local)) return false; | 312 if (isAccessedDirectly(local)) return false; |
311 if (isStoredInClosureField(local)) return false; | 313 if (isStoredInClosureField(local)) return false; |
312 return redirectionMapping.containsKey(local); | 314 return redirectionMapping.containsKey(local); |
313 } | 315 } |
314 | 316 |
315 bool _isUsedInTryOrGenerator(Local local) { | 317 bool _isUsedInTryOrGenerator(Local local) { |
316 return scopeInfo.localIsUsedInTryOrSync(local); | 318 return scopeInfo.localIsUsedInTryOrSync(local); |
(...skipping 17 matching lines...) Expand all Loading... |
334 "$executableContext."); | 336 "$executableContext."); |
335 } | 337 } |
336 } | 338 } |
337 HInstruction value = directLocals[local]; | 339 HInstruction value = directLocals[local]; |
338 if (sourceInformation != null) { | 340 if (sourceInformation != null) { |
339 value = new HRef(value, sourceInformation); | 341 value = new HRef(value, sourceInformation); |
340 builder.add(value); | 342 builder.add(value); |
341 } | 343 } |
342 return value; | 344 return value; |
343 } else if (isStoredInClosureField(local)) { | 345 } else if (isStoredInClosureField(local)) { |
| 346 print('bbbbbbb $local'); |
344 ClosureRepresentationInfo closureData = scopeInfo; | 347 ClosureRepresentationInfo closureData = scopeInfo; |
345 ClosureFieldElement redirect = redirectionMapping[local]; | 348 FieldEntity redirect = redirectionMapping[local]; |
346 HInstruction receiver = readLocal(closureData.closureEntity); | 349 HInstruction receiver = readLocal(closureData.closureEntity); |
347 TypeMask type = local is BoxLocal | 350 TypeMask type = local is BoxLocal |
348 ? commonMasks.nonNullType | 351 ? commonMasks.nonNullType |
349 : getTypeOfCapturedVariable(redirect); | 352 : getTypeOfCapturedVariable(redirect); |
350 HInstruction fieldGet = new HFieldGet(redirect, receiver, type); | 353 HInstruction fieldGet = new HFieldGet(redirect, receiver, type); |
351 builder.add(fieldGet); | 354 builder.add(fieldGet); |
352 return fieldGet..sourceInformation = sourceInformation; | 355 return fieldGet..sourceInformation = sourceInformation; |
353 } else if (isBoxed(local)) { | 356 } else if (isBoxed(local)) { |
354 BoxFieldElement redirect = redirectionMapping[local]; | 357 FieldEntity redirect = redirectionMapping[local]; |
| 358 BoxLocal localBox; |
355 // In the function that declares the captured variable the box is | 359 // In the function that declares the captured variable the box is |
356 // accessed as direct local. Inside the nested closure the box is | 360 // accessed as direct local. Inside the nested closure the box is |
357 // accessed through a closure-field. | 361 // accessed through a closure-field. |
358 // Calling [readLocal] makes sure we generate the correct code to get | 362 // Calling [readLocal] makes sure we generate the correct code to get |
359 // the box. | 363 // the box. |
| 364 print("AAAAAAAAAAAAAA $local $redirect ${redirect.runtimeType}"); |
| 365 if (redirect is BoxFieldElement) { |
| 366 localBox = redirect.box; |
| 367 } else if (redirect is JRecord) { |
| 368 localBox = redirect.box; |
| 369 } |
| 370 assert(localBox != null); |
| 371 |
360 HInstruction box = readLocal(redirect.box); | 372 HInstruction box = readLocal(redirect.box); |
361 HInstruction lookup = | 373 HInstruction lookup = |
362 new HFieldGet(redirect, box, getTypeOfCapturedVariable(redirect)); | 374 new HFieldGet(redirect, box, getTypeOfCapturedVariable(redirect)); |
363 builder.add(lookup); | 375 builder.add(lookup); |
364 return lookup..sourceInformation = sourceInformation; | 376 return lookup..sourceInformation = sourceInformation; |
365 } else { | 377 } else { |
366 assert(_isUsedInTryOrGenerator(local)); | 378 assert(_isUsedInTryOrGenerator(local)); |
367 HLocalValue localValue = getLocal(local); | 379 HLocalValue localValue = getLocal(local); |
368 HInstruction instruction = new HLocalGet( | 380 HInstruction instruction = new HLocalGet( |
369 local, localValue, commonMasks.dynamicType, sourceInformation); | 381 local, localValue, commonMasks.dynamicType, sourceInformation); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
409 void updateLocal(Local local, HInstruction value, | 421 void updateLocal(Local local, HInstruction value, |
410 {SourceInformation sourceInformation}) { | 422 {SourceInformation sourceInformation}) { |
411 if (value is HRef) { | 423 if (value is HRef) { |
412 HRef ref = value; | 424 HRef ref = value; |
413 value = ref.value; | 425 value = ref.value; |
414 } | 426 } |
415 assert(!isStoredInClosureField(local)); | 427 assert(!isStoredInClosureField(local)); |
416 if (isAccessedDirectly(local)) { | 428 if (isAccessedDirectly(local)) { |
417 directLocals[local] = value; | 429 directLocals[local] = value; |
418 } else if (isBoxed(local)) { | 430 } else if (isBoxed(local)) { |
419 BoxFieldElement redirect = redirectionMapping[local]; | 431 FieldEntity redirect = redirectionMapping[local]; |
| 432 assert(redirect != null); |
| 433 BoxLocal localBox; |
| 434 if (redirect is BoxFieldElement) { |
| 435 localBox = redirect.box; |
| 436 } else if (redirect is JRecord) { |
| 437 localBox = redirect.box; |
| 438 } |
| 439 assert(localBox != null); |
| 440 |
420 // The box itself could be captured, or be local. A local variable that | 441 // The box itself could be captured, or be local. A local variable that |
421 // is captured will be boxed, but the box itself will be a local. | 442 // is captured will be boxed, but the box itself will be a local. |
422 // Inside the closure the box is stored in a closure-field and cannot | 443 // Inside the closure the box is stored in a closure-field and cannot |
423 // be accessed directly. | 444 // be accessed directly. |
424 HInstruction box = readLocal(redirect.box); | 445 HInstruction box = readLocal(localBox); |
425 builder.add(new HFieldSet(redirect, box, value) | 446 builder.add(new HFieldSet(redirect, box, value) |
426 ..sourceInformation = sourceInformation); | 447 ..sourceInformation = sourceInformation); |
427 } else { | 448 } else { |
428 assert(_isUsedInTryOrGenerator(local)); | 449 assert(_isUsedInTryOrGenerator(local)); |
429 HLocalValue localValue = getLocal(local); | 450 HLocalValue localValue = getLocal(local); |
430 builder.add(new HLocalSet(local, localValue, value) | 451 builder.add(new HLocalSet(local, localValue, value) |
431 ..sourceInformation = sourceInformation); | 452 ..sourceInformation = sourceInformation); |
432 } | 453 } |
433 } | 454 } |
434 | 455 |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
636 // simplicity, we mark the type as an interface type. | 657 // simplicity, we mark the type as an interface type. |
637 result = new TypeMask.nonNullSubtype(cls, closedWorld); | 658 result = new TypeMask.nonNullSubtype(cls, closedWorld); |
638 } else { | 659 } else { |
639 result = new TypeMask.nonNullSubclass(cls, closedWorld); | 660 result = new TypeMask.nonNullSubclass(cls, closedWorld); |
640 } | 661 } |
641 cachedTypeOfThis = result; | 662 cachedTypeOfThis = result; |
642 } | 663 } |
643 return result; | 664 return result; |
644 } | 665 } |
645 | 666 |
646 Map<Element, TypeMask> cachedTypesOfCapturedVariables = | 667 Map<FieldEntity, TypeMask> cachedTypesOfCapturedVariables = |
647 new Map<Element, TypeMask>(); | 668 new Map<FieldEntity, TypeMask>(); |
648 | 669 |
649 TypeMask getTypeOfCapturedVariable(FieldElement element) { | 670 TypeMask getTypeOfCapturedVariable(FieldEntity element) { |
650 return cachedTypesOfCapturedVariables.putIfAbsent(element, () { | 671 return cachedTypesOfCapturedVariables.putIfAbsent(element, () { |
651 return TypeMaskFactory.inferredTypeForMember( | 672 return TypeMaskFactory.inferredTypeForMember( |
652 element, _globalInferenceResults); | 673 element, _globalInferenceResults); |
653 }); | 674 }); |
654 } | 675 } |
655 | 676 |
656 /// Variables stored in the current activation. These variables are | 677 /// Variables stored in the current activation. These variables are |
657 /// being updated in try/catch blocks, and should be | 678 /// being updated in try/catch blocks, and should be |
658 /// accessed indirectly through [HLocalGet] and [HLocalSet]. | 679 /// accessed indirectly through [HLocalGet] and [HLocalSet]. |
659 Map<Local, HLocalValue> activationVariables = <Local, HLocalValue>{}; | 680 Map<Local, HLocalValue> activationVariables = <Local, HLocalValue>{}; |
(...skipping 13 matching lines...) Expand all Loading... |
673 final MemberEntity memberContext; | 694 final MemberEntity memberContext; |
674 | 695 |
675 // Avoid slow Object.hashCode. | 696 // Avoid slow Object.hashCode. |
676 final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); | 697 final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); |
677 static int _nextHashCode = 0; | 698 static int _nextHashCode = 0; |
678 | 699 |
679 SyntheticLocal(this.name, this.executableContext, this.memberContext); | 700 SyntheticLocal(this.name, this.executableContext, this.memberContext); |
680 | 701 |
681 toString() => 'SyntheticLocal($name)'; | 702 toString() => 'SyntheticLocal($name)'; |
682 } | 703 } |
OLD | NEW |