| 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 |