Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; | 5 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
| 6 import '../common/names.dart' show Selectors; | 6 import '../common/names.dart' show Selectors; |
| 7 import '../common/tasks.dart' show CompilerTask; | 7 import '../common/tasks.dart' show CompilerTask; |
| 8 import '../compiler.dart' show Compiler; | 8 import '../compiler.dart' show Compiler; |
| 9 import '../constants/constant_system.dart'; | 9 import '../constants/constant_system.dart'; |
| 10 import '../constants/values.dart'; | 10 import '../constants/values.dart'; |
| 11 import '../core_types.dart' show CommonElements; | 11 import '../core_types.dart' show CommonElements; |
| 12 import '../elements/elements.dart' | |
| 13 show ClassElement, Entity, FieldElement, MethodElement; | |
| 14 import '../elements/entities.dart'; | |
| 12 import '../elements/resolution_types.dart'; | 15 import '../elements/resolution_types.dart'; |
| 13 import '../elements/elements.dart'; | |
| 14 import '../elements/entities.dart'; | |
| 15 import '../js/js.dart' as js; | 16 import '../js/js.dart' as js; |
| 16 import '../js_backend/backend_helpers.dart' show BackendHelpers; | 17 import '../js_backend/backend_helpers.dart' show BackendHelpers; |
| 17 import '../js_backend/js_backend.dart'; | 18 import '../js_backend/js_backend.dart'; |
| 18 import '../native/native.dart' as native; | 19 import '../native/native.dart' as native; |
| 19 import '../tree/dartstring.dart' as ast; | 20 import '../tree/dartstring.dart' as ast; |
| 20 import '../types/types.dart'; | 21 import '../types/types.dart'; |
| 21 import '../universe/selector.dart' show Selector; | 22 import '../universe/selector.dart' show Selector; |
| 22 import '../universe/side_effects.dart' show SideEffects; | 23 import '../universe/side_effects.dart' show SideEffects; |
| 23 import '../util/util.dart'; | 24 import '../util/util.dart'; |
| 24 import '../world.dart' show ClosedWorld; | 25 import '../world.dart' show ClosedWorld; |
| (...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 336 if (actualReceiver.isIndexablePrimitive(closedWorld)) { | 337 if (actualReceiver.isIndexablePrimitive(closedWorld)) { |
| 337 if (actualReceiver.isConstantString()) { | 338 if (actualReceiver.isConstantString()) { |
| 338 HConstant constantInput = actualReceiver; | 339 HConstant constantInput = actualReceiver; |
| 339 StringConstantValue constant = constantInput.constant; | 340 StringConstantValue constant = constantInput.constant; |
| 340 return graph.addConstantInt(constant.length, closedWorld); | 341 return graph.addConstantInt(constant.length, closedWorld); |
| 341 } else if (actualReceiver.isConstantList()) { | 342 } else if (actualReceiver.isConstantList()) { |
| 342 HConstant constantInput = actualReceiver; | 343 HConstant constantInput = actualReceiver; |
| 343 ListConstantValue constant = constantInput.constant; | 344 ListConstantValue constant = constantInput.constant; |
| 344 return graph.addConstantInt(constant.length, closedWorld); | 345 return graph.addConstantInt(constant.length, closedWorld); |
| 345 } | 346 } |
| 346 MemberElement element = helpers.jsIndexableLength; | 347 MemberEntity element = helpers.jsIndexableLength; |
| 347 bool isFixed = isFixedLength(actualReceiver.instructionType, closedWorld); | 348 bool isFixed = isFixedLength(actualReceiver.instructionType, closedWorld); |
| 348 TypeMask actualType = node.instructionType; | 349 TypeMask actualType = node.instructionType; |
| 349 TypeMask resultType = closedWorld.commonMasks.positiveIntType; | 350 TypeMask resultType = closedWorld.commonMasks.positiveIntType; |
| 350 // If we already have computed a more specific type, keep that type. | 351 // If we already have computed a more specific type, keep that type. |
| 351 if (HInstruction.isInstanceOf( | 352 if (HInstruction.isInstanceOf( |
| 352 actualType, helpers.jsUInt31Class, closedWorld)) { | 353 actualType, helpers.jsUInt31Class, closedWorld)) { |
| 353 resultType = closedWorld.commonMasks.uint31Type; | 354 resultType = closedWorld.commonMasks.uint31Type; |
| 354 } else if (HInstruction.isInstanceOf( | 355 } else if (HInstruction.isInstanceOf( |
| 355 actualType, helpers.jsUInt32Class, closedWorld)) { | 356 actualType, helpers.jsUInt32Class, closedWorld)) { |
| 356 resultType = closedWorld.commonMasks.uint32Type; | 357 resultType = closedWorld.commonMasks.uint32Type; |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 378 | 379 |
| 379 // Try converting the instruction to a builtin instruction. | 380 // Try converting the instruction to a builtin instruction. |
| 380 HInstruction instruction = | 381 HInstruction instruction = |
| 381 node.specializer.tryConvertToBuiltin(node, compiler, closedWorld); | 382 node.specializer.tryConvertToBuiltin(node, compiler, closedWorld); |
| 382 if (instruction != null) return instruction; | 383 if (instruction != null) return instruction; |
| 383 | 384 |
| 384 Selector selector = node.selector; | 385 Selector selector = node.selector; |
| 385 TypeMask mask = node.mask; | 386 TypeMask mask = node.mask; |
| 386 HInstruction input = node.inputs[1]; | 387 HInstruction input = node.inputs[1]; |
| 387 | 388 |
| 388 bool applies(Element element) { | 389 bool applies(MemberEntity element) { |
| 389 return selector.applies(element) && | 390 return selector.applies(element) && |
| 390 (mask == null || mask.canHit(element, selector, closedWorld)); | 391 (mask == null || mask.canHit(element, selector, closedWorld)); |
| 391 } | 392 } |
| 392 | 393 |
| 393 if (selector.isCall || selector.isOperator) { | 394 if (selector.isCall || selector.isOperator) { |
| 394 MethodElement target; | 395 FunctionEntity target; |
| 395 if (input.isExtendableArray(closedWorld)) { | 396 if (input.isExtendableArray(closedWorld)) { |
| 396 if (applies(helpers.jsArrayRemoveLast)) { | 397 if (applies(helpers.jsArrayRemoveLast)) { |
| 397 target = helpers.jsArrayRemoveLast; | 398 target = helpers.jsArrayRemoveLast; |
| 398 } else if (applies(helpers.jsArrayAdd)) { | 399 } else if (applies(helpers.jsArrayAdd)) { |
| 399 // The codegen special cases array calls, but does not | 400 // The codegen special cases array calls, but does not |
| 400 // inline argument type checks. | 401 // inline argument type checks. |
| 401 if (!compiler.options.enableTypeAssertions) { | 402 if (!compiler.options.enableTypeAssertions) { |
| 402 target = helpers.jsArrayAdd; | 403 target = helpers.jsArrayAdd; |
| 403 } | 404 } |
| 404 } | 405 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 445 } | 446 } |
| 446 | 447 |
| 447 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 448 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
| 448 propagateConstantValueToUses(node); | 449 propagateConstantValueToUses(node); |
| 449 if (node.isInterceptedCall) { | 450 if (node.isInterceptedCall) { |
| 450 HInstruction folded = handleInterceptedCall(node); | 451 HInstruction folded = handleInterceptedCall(node); |
| 451 if (folded != node) return folded; | 452 if (folded != node) return folded; |
| 452 } | 453 } |
| 453 | 454 |
| 454 TypeMask receiverType = node.getDartReceiver(closedWorld).instructionType; | 455 TypeMask receiverType = node.getDartReceiver(closedWorld).instructionType; |
| 455 Element element = | 456 MemberEntity element = |
| 456 closedWorld.locateSingleElement(node.selector, receiverType); | 457 closedWorld.locateSingleElement(node.selector, receiverType); |
| 457 // TODO(ngeoffray): Also fold if it's a getter or variable. | 458 // TODO(ngeoffray): Also fold if it's a getter or variable. |
| 458 if (element != null && | 459 if (element != null && |
| 459 element.isFunction | 460 element.isFunction |
| 460 // If we found out that the only target is an implicitly called | 461 // If we found out that the only target is an implicitly called |
| 461 // [:noSuchMethod:] we just ignore it. | 462 // [:noSuchMethod:] we just ignore it. |
| 462 && | 463 && |
| 463 node.selector.applies(element)) { | 464 node.selector.applies(element)) { |
| 464 MethodElement method = element; | 465 MethodElement method = element; |
| 465 | 466 |
| 466 if (backend.isNative(method)) { | 467 if (backend.isNative(method)) { |
| 467 HInstruction folded = tryInlineNativeMethod(node, method); | 468 HInstruction folded = tryInlineNativeMethod(node, method); |
| 468 if (folded != null) return folded; | 469 if (folded != null) return folded; |
| 469 } else { | 470 } else { |
| 470 // TODO(ngeoffray): If the method has optional parameters, | 471 // TODO(ngeoffray): If the method has optional parameters, |
| 471 // we should pass the default values. | 472 // we should pass the default values. |
| 472 FunctionSignature parameters = method.functionSignature; | 473 FunctionType type = method.type; |
| 473 if (parameters.optionalParameterCount == 0 || | 474 int optionalParameterCount = |
| 474 parameters.parameterCount == node.selector.argumentCount) { | 475 type.optionalParameterTypes.length + type.namedParameters.length; |
| 476 if (optionalParameterCount == 0 || | |
| 477 type.parameterTypes.length + optionalParameterCount == | |
| 478 node.selector.argumentCount) { | |
| 475 node.element = method; | 479 node.element = method; |
| 476 } | 480 } |
| 477 } | 481 } |
| 478 return node; | 482 return node; |
| 479 } | 483 } |
| 480 | 484 |
| 481 // Replace method calls through fields with a closure call on the value of | 485 // Replace method calls through fields with a closure call on the value of |
| 482 // the field. This usually removes the demand for the call-through stub and | 486 // the field. This usually removes the demand for the call-through stub and |
| 483 // makes the field load available to further optimization, e.g. LICM. | 487 // makes the field load available to further optimization, e.g. LICM. |
| 484 | 488 |
| 485 if (element != null && | 489 if (element != null && |
| 486 element.isField && | 490 element.isField && |
| 487 element.name == node.selector.name) { | 491 element.name == node.selector.name) { |
| 488 FieldElement field = element; | 492 FieldEntity field = element; |
| 489 if (!backend.isNative(field) && !node.isCallOnInterceptor(closedWorld)) { | 493 if (!backend.isNative(field) && !node.isCallOnInterceptor(closedWorld)) { |
| 490 HInstruction receiver = node.getDartReceiver(closedWorld); | 494 HInstruction receiver = node.getDartReceiver(closedWorld); |
| 491 TypeMask type = TypeMaskFactory.inferredTypeForElement( | 495 TypeMask type = TypeMaskFactory.inferredTypeForElement( |
| 492 field, globalInferenceResults); | 496 field as Entity, globalInferenceResults); |
|
sra1
2017/01/04 17:20:48
Why is 'as' needed? is a FieldEntity not an Entity
Johnni Winther
2017/01/05 08:54:42
It is. The Dart type system doesn't handle diamond
Siggi Cherem (dart-lang)
2017/01/05 18:14:08
mmm... this feels like it might be hiding the issu
Johnni Winther
2017/01/06 09:04:51
I like _not_ being able to write `Element` in this
| |
| 493 HInstruction load = new HFieldGet(field, receiver, type); | 497 HInstruction load = new HFieldGet(field, receiver, type); |
| 494 node.block.addBefore(node, load); | 498 node.block.addBefore(node, load); |
| 495 Selector callSelector = new Selector.callClosureFrom(node.selector); | 499 Selector callSelector = new Selector.callClosureFrom(node.selector); |
| 496 List<HInstruction> inputs = <HInstruction>[load] | 500 List<HInstruction> inputs = <HInstruction>[load] |
| 497 ..addAll(node.inputs.skip(node.isInterceptedCall ? 2 : 1)); | 501 ..addAll(node.inputs.skip(node.isInterceptedCall ? 2 : 1)); |
| 498 HInstruction closureCall = | 502 HInstruction closureCall = |
| 499 new HInvokeClosure(callSelector, inputs, node.instructionType) | 503 new HInvokeClosure(callSelector, inputs, node.instructionType) |
| 500 ..sourceInformation = node.sourceInformation; | 504 ..sourceInformation = node.sourceInformation; |
| 501 node.block.addAfter(load, closureCall); | 505 node.block.addAfter(load, closureCall); |
| 502 return closureCall; | 506 return closureCall; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 517 // TODO(ngeoffray): There are some cases where we could still inline in | 521 // TODO(ngeoffray): There are some cases where we could still inline in |
| 518 // checked mode if we know the arguments have the right type. And we could | 522 // checked mode if we know the arguments have the right type. And we could |
| 519 // do the closure conversion as well as the return type annotation check. | 523 // do the closure conversion as well as the return type annotation check. |
| 520 | 524 |
| 521 if (!node.isInterceptedCall) return null; | 525 if (!node.isInterceptedCall) return null; |
| 522 | 526 |
| 523 // TODO(sra): Check for legacy methods with bodies in the native strings. | 527 // TODO(sra): Check for legacy methods with bodies in the native strings. |
| 524 // foo() native 'return something'; | 528 // foo() native 'return something'; |
| 525 // They should not be used. | 529 // They should not be used. |
| 526 | 530 |
| 527 FunctionSignature signature = method.functionSignature; | 531 FunctionType type = method.type; |
| 528 if (signature.optionalParametersAreNamed) return null; | 532 if (type.namedParameters.isNotEmpty) return null; |
| 529 | 533 |
| 530 // Return types on native methods don't need to be checked, since the | 534 // Return types on native methods don't need to be checked, since the |
| 531 // declaration has to be truthful. | 535 // declaration has to be truthful. |
| 532 | 536 |
| 533 // The call site might omit optional arguments. The inlined code must | 537 // The call site might omit optional arguments. The inlined code must |
| 534 // preserve the number of arguments, so check only the actual arguments. | 538 // preserve the number of arguments, so check only the actual arguments. |
| 535 | 539 |
| 536 List<HInstruction> inputs = node.inputs.sublist(1); | 540 List<HInstruction> inputs = node.inputs.sublist(1); |
| 537 int inputPosition = 1; // Skip receiver. | |
| 538 bool canInline = true; | 541 bool canInline = true; |
| 539 signature.forEachParameter((ParameterElement element) { | 542 if (compiler.options.enableTypeAssertions && inputs.length > 1) { |
| 540 if (inputPosition++ < inputs.length && canInline) { | 543 // TODO(sra): Check if [input] is guaranteed to pass the parameter |
| 541 DartType type = element.type.unaliased; | 544 // type check. Consider using a strengthened type check to avoid |
| 542 if (type is FunctionType) { | 545 // passing `null` to primitive types since the native methods usually |
| 543 canInline = false; | 546 // have non-nullable primitive parameter types. |
| 544 } | 547 canInline = false; |
| 545 if (compiler.options.enableTypeAssertions) { | 548 } else { |
| 546 // TODO(sra): Check if [input] is guaranteed to pass the parameter | 549 int inputPosition = 1; // Skip receiver. |
| 547 // type check. Consider using a strengthened type check to avoid | 550 void checkParameterType(DartType type) { |
| 548 // passing `null` to primitive types since the native methods usually | 551 if (inputPosition++ < inputs.length && canInline) { |
| 549 // have non-nullable primitive parameter types. | 552 if (type.unaliased.isFunctionType) { |
| 550 canInline = false; | 553 canInline = false; |
| 554 } | |
| 551 } | 555 } |
| 552 } | 556 } |
| 553 }); | 557 |
| 558 type.parameterTypes.forEach(checkParameterType); | |
| 559 type.optionalParameterTypes.forEach(checkParameterType); | |
| 560 type.namedParameterTypes.forEach(checkParameterType); | |
| 561 } | |
| 554 | 562 |
| 555 if (!canInline) return null; | 563 if (!canInline) return null; |
| 556 | 564 |
| 557 // Strengthen instruction type from annotations to help optimize | 565 // Strengthen instruction type from annotations to help optimize |
| 558 // dependent instructions. | 566 // dependent instructions. |
| 559 native.NativeBehavior nativeBehavior = | 567 native.NativeBehavior nativeBehavior = |
| 560 backend.getNativeMethodBehavior(method); | 568 backend.getNativeMethodBehavior(method); |
| 561 TypeMask returnType = | 569 TypeMask returnType = |
| 562 TypeMaskFactory.fromNativeBehavior(nativeBehavior, closedWorld); | 570 TypeMaskFactory.fromNativeBehavior(nativeBehavior, closedWorld); |
| 563 HInvokeDynamicMethod result = | 571 HInvokeDynamicMethod result = |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 724 simplifyCondition(node.elseBlock, hoisted, true); | 732 simplifyCondition(node.elseBlock, hoisted, true); |
| 725 }); | 733 }); |
| 726 } | 734 } |
| 727 simplifyCondition(node.thenBlock, condition, !isNegated); | 735 simplifyCondition(node.thenBlock, condition, !isNegated); |
| 728 simplifyCondition(node.elseBlock, condition, isNegated); | 736 simplifyCondition(node.elseBlock, condition, isNegated); |
| 729 return node; | 737 return node; |
| 730 } | 738 } |
| 731 | 739 |
| 732 HInstruction visitIs(HIs node) { | 740 HInstruction visitIs(HIs node) { |
| 733 DartType type = node.typeExpression; | 741 DartType type = node.typeExpression; |
| 734 Element element = type.element; | |
| 735 | 742 |
| 736 if (!node.isRawCheck) { | 743 if (!node.isRawCheck) { |
| 737 return node; | 744 return node; |
| 738 } else if (type.isTypedef) { | 745 } else if (type.isTypedef) { |
| 739 return node; | 746 return node; |
| 740 } else if (element == commonElements.functionClass) { | 747 } else if (type.isFunctionType) { |
| 741 return node; | 748 return node; |
| 742 } | 749 } |
| 743 | 750 |
| 744 if (type.isObject || type.treatAsDynamic) { | 751 if (type.isObject || type.treatAsDynamic) { |
| 745 return graph.addConstantBool(true, closedWorld); | 752 return graph.addConstantBool(true, closedWorld); |
| 746 } | 753 } |
| 747 | 754 InterfaceType interfaceType = type; |
| 755 ClassEntity element = interfaceType.element; | |
| 748 HInstruction expression = node.expression; | 756 HInstruction expression = node.expression; |
| 749 if (expression.isInteger(closedWorld)) { | 757 if (expression.isInteger(closedWorld)) { |
| 750 if (element == commonElements.intClass || | 758 if (element == commonElements.intClass || |
| 751 element == commonElements.numClass || | 759 element == commonElements.numClass || |
| 752 commonElements.isNumberOrStringSupertype(element)) { | 760 commonElements.isNumberOrStringSupertype(element)) { |
| 753 return graph.addConstantBool(true, closedWorld); | 761 return graph.addConstantBool(true, closedWorld); |
| 754 } else if (element == commonElements.doubleClass) { | 762 } else if (element == commonElements.doubleClass) { |
| 755 // We let the JS semantics decide for that check. Currently | 763 // We let the JS semantics decide for that check. Currently |
| 756 // the code we emit will always return true. | 764 // the code we emit will always return true. |
| 757 return node; | 765 return node; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 840 | 848 |
| 841 HInstruction removeIfCheckAlwaysSucceeds(HCheck node, TypeMask checkedType) { | 849 HInstruction removeIfCheckAlwaysSucceeds(HCheck node, TypeMask checkedType) { |
| 842 if (checkedType.containsAll(closedWorld)) return node; | 850 if (checkedType.containsAll(closedWorld)) return node; |
| 843 HInstruction input = node.checkedInput; | 851 HInstruction input = node.checkedInput; |
| 844 TypeMask inputType = input.instructionType; | 852 TypeMask inputType = input.instructionType; |
| 845 return inputType.isInMask(checkedType, closedWorld) ? input : node; | 853 return inputType.isInMask(checkedType, closedWorld) ? input : node; |
| 846 } | 854 } |
| 847 | 855 |
| 848 HInstruction removeCheck(HCheck node) => node.checkedInput; | 856 HInstruction removeCheck(HCheck node) => node.checkedInput; |
| 849 | 857 |
| 850 FieldElement findConcreteFieldForDynamicAccess( | 858 FieldEntity findConcreteFieldForDynamicAccess( |
| 851 HInstruction receiver, Selector selector) { | 859 HInstruction receiver, Selector selector) { |
| 852 TypeMask receiverType = receiver.instructionType; | 860 TypeMask receiverType = receiver.instructionType; |
| 853 return closedWorld.locateSingleField(selector, receiverType); | 861 return closedWorld.locateSingleField(selector, receiverType); |
| 854 } | 862 } |
| 855 | 863 |
| 856 HInstruction visitFieldGet(HFieldGet node) { | 864 HInstruction visitFieldGet(HFieldGet node) { |
| 857 if (node.isNullCheck) return node; | 865 if (node.isNullCheck) return node; |
| 858 var receiver = node.receiver; | 866 var receiver = node.receiver; |
| 859 if (node.element == helpers.jsIndexableLength) { | 867 if (node.element == helpers.jsIndexableLength) { |
| 860 if (graph.allocatedFixedLists.contains(receiver)) { | 868 if (graph.allocatedFixedLists.contains(receiver)) { |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 916 return node; | 924 return node; |
| 917 } | 925 } |
| 918 | 926 |
| 919 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { | 927 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
| 920 propagateConstantValueToUses(node); | 928 propagateConstantValueToUses(node); |
| 921 if (node.isInterceptedCall) { | 929 if (node.isInterceptedCall) { |
| 922 HInstruction folded = handleInterceptedCall(node); | 930 HInstruction folded = handleInterceptedCall(node); |
| 923 if (folded != node) return folded; | 931 if (folded != node) return folded; |
| 924 } | 932 } |
| 925 HInstruction receiver = node.getDartReceiver(closedWorld); | 933 HInstruction receiver = node.getDartReceiver(closedWorld); |
| 926 FieldElement field = | 934 FieldEntity field = |
| 927 findConcreteFieldForDynamicAccess(receiver, node.selector); | 935 findConcreteFieldForDynamicAccess(receiver, node.selector); |
| 928 if (field != null) return directFieldGet(receiver, field); | 936 if (field != null) return directFieldGet(receiver, field); |
| 929 | 937 |
| 930 if (node.element == null) { | 938 if (node.element == null) { |
| 931 MemberElement element = closedWorld.locateSingleElement( | 939 MemberEntity element = closedWorld.locateSingleElement( |
| 932 node.selector, receiver.instructionType); | 940 node.selector, receiver.instructionType); |
| 933 if (element != null && element.name == node.selector.name) { | 941 if (element != null && element.name == node.selector.name) { |
| 934 node.element = element; | 942 node.element = element; |
| 935 if (element.isFunction) { | 943 if (element.isFunction) { |
| 936 // A property extraction getter, aka a tear-off. | 944 // A property extraction getter, aka a tear-off. |
| 937 node.sideEffects.clearAllDependencies(); | 945 node.sideEffects.clearAllDependencies(); |
| 938 node.sideEffects.clearAllSideEffects(); | 946 node.sideEffects.clearAllSideEffects(); |
| 939 node.setUseGvn(); // We don't care about identity of tear-offs. | 947 node.setUseGvn(); // We don't care about identity of tear-offs. |
| 940 } | 948 } |
| 941 } | 949 } |
| 942 } | 950 } |
| 943 return node; | 951 return node; |
| 944 } | 952 } |
| 945 | 953 |
| 946 HInstruction directFieldGet(HInstruction receiver, FieldElement field) { | 954 HInstruction directFieldGet(HInstruction receiver, FieldEntity field) { |
| 947 bool isAssignable = !closedWorld.fieldNeverChanges(field); | 955 bool isAssignable = !closedWorld.fieldNeverChanges(field as MemberEntity); |
| 948 | 956 |
| 949 TypeMask type; | 957 TypeMask type; |
| 950 if (backend.isNative(field.enclosingClass)) { | 958 if (backend.isNative(field.enclosingClass)) { |
| 951 type = TypeMaskFactory.fromNativeBehavior( | 959 type = TypeMaskFactory.fromNativeBehavior( |
| 952 backend.getNativeFieldLoadBehavior(field), closedWorld); | 960 backend.getNativeFieldLoadBehavior(field), closedWorld); |
| 953 } else { | 961 } else { |
| 954 type = | 962 type = TypeMaskFactory.inferredTypeForElement( |
| 955 TypeMaskFactory.inferredTypeForElement(field, globalInferenceResults); | 963 field as Entity, globalInferenceResults); |
| 956 } | 964 } |
| 957 | 965 |
| 958 return new HFieldGet(field, receiver, type, isAssignable: isAssignable); | 966 return new HFieldGet(field, receiver, type, isAssignable: isAssignable); |
| 959 } | 967 } |
| 960 | 968 |
| 961 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 969 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
| 962 if (node.isInterceptedCall) { | 970 if (node.isInterceptedCall) { |
| 963 HInstruction folded = handleInterceptedCall(node); | 971 HInstruction folded = handleInterceptedCall(node); |
| 964 if (folded != node) return folded; | 972 if (folded != node) return folded; |
| 965 } | 973 } |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 987 if (other != value) { | 995 if (other != value) { |
| 988 node.block.addBefore(node, other); | 996 node.block.addBefore(node, other); |
| 989 value = other; | 997 value = other; |
| 990 } | 998 } |
| 991 } | 999 } |
| 992 return new HFieldSet(field, receiver, value); | 1000 return new HFieldSet(field, receiver, value); |
| 993 } | 1001 } |
| 994 | 1002 |
| 995 HInstruction visitInvokeStatic(HInvokeStatic node) { | 1003 HInstruction visitInvokeStatic(HInvokeStatic node) { |
| 996 propagateConstantValueToUses(node); | 1004 propagateConstantValueToUses(node); |
| 997 MemberElement element = node.element; | 1005 MemberEntity element = node.element; |
| 998 | 1006 |
| 999 if (element == backend.helpers.checkConcurrentModificationError) { | 1007 if (element == backend.helpers.checkConcurrentModificationError) { |
| 1000 if (node.inputs.length == 2) { | 1008 if (node.inputs.length == 2) { |
| 1001 HInstruction firstArgument = node.inputs[0]; | 1009 HInstruction firstArgument = node.inputs[0]; |
| 1002 if (firstArgument is HConstant) { | 1010 if (firstArgument is HConstant) { |
| 1003 HConstant constant = firstArgument; | 1011 HConstant constant = firstArgument; |
| 1004 if (constant.constant.isTrue) return constant; | 1012 if (constant.constant.isTrue) return constant; |
| 1005 } | 1013 } |
| 1006 } | 1014 } |
| 1007 } else if (element == backend.helpers.checkInt) { | 1015 } else if (element == backend.helpers.checkInt) { |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1118 return null; | 1126 return null; |
| 1119 } | 1127 } |
| 1120 | 1128 |
| 1121 return tryConstant() ?? tryToString() ?? node; | 1129 return tryConstant() ?? tryToString() ?? node; |
| 1122 } | 1130 } |
| 1123 | 1131 |
| 1124 HInstruction visitOneShotInterceptor(HOneShotInterceptor node) { | 1132 HInstruction visitOneShotInterceptor(HOneShotInterceptor node) { |
| 1125 return handleInterceptedCall(node); | 1133 return handleInterceptedCall(node); |
| 1126 } | 1134 } |
| 1127 | 1135 |
| 1128 bool needsSubstitutionForTypeVariableAccess(ClassElement cls) { | 1136 bool needsSubstitutionForTypeVariableAccess(ClassEntity cls) { |
| 1129 if (closedWorld.isUsedAsMixin(cls)) return true; | 1137 if (closedWorld.isUsedAsMixin(cls)) return true; |
| 1130 | 1138 |
| 1131 return closedWorld.anyStrictSubclassOf(cls, (ClassElement subclass) { | 1139 return closedWorld.anyStrictSubclassOf(cls, (ClassEntity subclass) { |
| 1132 return !backend.rti.isTrivialSubstitution(subclass, cls); | 1140 return !backend.rti.isTrivialSubstitution(subclass, cls); |
| 1133 }); | 1141 }); |
| 1134 } | 1142 } |
| 1135 | 1143 |
| 1136 HInstruction visitTypeInfoExpression(HTypeInfoExpression node) { | 1144 HInstruction visitTypeInfoExpression(HTypeInfoExpression node) { |
| 1137 // Identify the case where the type info expression would be of the form: | 1145 // Identify the case where the type info expression would be of the form: |
| 1138 // | 1146 // |
| 1139 // [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)] | 1147 // [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)] |
| 1140 // | 1148 // |
| 1141 // and k is the number of type arguments of 'this'. We can simply copy the | 1149 // and k is the number of type arguments of 'this'. We can simply copy the |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1359 index = insertBoundsCheck(node, node.receiver, index); | 1367 index = insertBoundsCheck(node, node.receiver, index); |
| 1360 } | 1368 } |
| 1361 | 1369 |
| 1362 void visitIndexAssign(HIndexAssign node) { | 1370 void visitIndexAssign(HIndexAssign node) { |
| 1363 if (boundsChecked.contains(node)) return; | 1371 if (boundsChecked.contains(node)) return; |
| 1364 HInstruction index = node.index; | 1372 HInstruction index = node.index; |
| 1365 index = insertBoundsCheck(node, node.receiver, index); | 1373 index = insertBoundsCheck(node, node.receiver, index); |
| 1366 } | 1374 } |
| 1367 | 1375 |
| 1368 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 1376 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
| 1369 MemberElement element = node.element; | 1377 MemberEntity element = node.element; |
| 1370 if (node.isInterceptedCall) return; | 1378 if (node.isInterceptedCall) return; |
| 1371 if (element != helpers.jsArrayRemoveLast) return; | 1379 if (element != helpers.jsArrayRemoveLast) return; |
| 1372 if (boundsChecked.contains(node)) return; | 1380 if (boundsChecked.contains(node)) return; |
| 1373 // `0` is the index we want to check, but we want to report `-1`, as if we | 1381 // `0` is the index we want to check, but we want to report `-1`, as if we |
| 1374 // executed `a[a.length-1]` | 1382 // executed `a[a.length-1]` |
| 1375 HBoundsCheck check = insertBoundsCheck( | 1383 HBoundsCheck check = insertBoundsCheck( |
| 1376 node, node.receiver, graph.addConstantInt(0, closedWorld)); | 1384 node, node.receiver, graph.addConstantInt(0, closedWorld)); |
| 1377 HInstruction minusOne = graph.addConstantInt(-1, closedWorld); | 1385 HInstruction minusOne = graph.addConstantInt(-1, closedWorld); |
| 1378 check.inputs.add(minusOne); | 1386 check.inputs.add(minusOne); |
| 1379 minusOne.usedBy.add(check); | 1387 minusOne.usedBy.add(check); |
| (...skipping 743 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2123 | 2131 |
| 2124 HTypeKnown newInput = new HTypeKnown.pinned(convertedType, input); | 2132 HTypeKnown newInput = new HTypeKnown.pinned(convertedType, input); |
| 2125 dominator.addBefore(dominator.first, newInput); | 2133 dominator.addBefore(dominator.first, newInput); |
| 2126 dominatedUsers.forEach((HInstruction user) { | 2134 dominatedUsers.forEach((HInstruction user) { |
| 2127 user.changeUse(input, newInput); | 2135 user.changeUse(input, newInput); |
| 2128 }); | 2136 }); |
| 2129 } | 2137 } |
| 2130 | 2138 |
| 2131 void visitIs(HIs instruction) { | 2139 void visitIs(HIs instruction) { |
| 2132 DartType type = instruction.typeExpression; | 2140 DartType type = instruction.typeExpression; |
| 2133 Element element = type.element; | |
| 2134 if (!instruction.isRawCheck) { | 2141 if (!instruction.isRawCheck) { |
| 2135 return; | 2142 return; |
| 2136 } else if (element.isTypedef) { | 2143 } else if (type.isTypedef) { |
| 2137 return; | 2144 return; |
| 2138 } | 2145 } |
| 2146 InterfaceType interfaceType = type; | |
| 2147 ClassEntity cls = interfaceType.element; | |
| 2139 | 2148 |
| 2140 List<HBasicBlock> trueTargets = <HBasicBlock>[]; | 2149 List<HBasicBlock> trueTargets = <HBasicBlock>[]; |
| 2141 List<HBasicBlock> falseTargets = <HBasicBlock>[]; | 2150 List<HBasicBlock> falseTargets = <HBasicBlock>[]; |
| 2142 | 2151 |
| 2143 collectTargets(instruction, trueTargets, falseTargets); | 2152 collectTargets(instruction, trueTargets, falseTargets); |
| 2144 | 2153 |
| 2145 if (trueTargets.isEmpty && falseTargets.isEmpty) return; | 2154 if (trueTargets.isEmpty && falseTargets.isEmpty) return; |
| 2146 | 2155 |
| 2147 TypeMask convertedType = new TypeMask.nonNullSubtype(element, closedWorld); | 2156 TypeMask convertedType = new TypeMask.nonNullSubtype(cls, closedWorld); |
| 2148 HInstruction input = instruction.expression; | 2157 HInstruction input = instruction.expression; |
| 2149 | 2158 |
| 2150 for (HBasicBlock block in trueTargets) { | 2159 for (HBasicBlock block in trueTargets) { |
| 2151 insertTypePropagationForDominatedUsers(block, input, convertedType); | 2160 insertTypePropagationForDominatedUsers(block, input, convertedType); |
| 2152 } | 2161 } |
| 2153 // TODO(sra): Also strengthen uses for when the condition is known | 2162 // TODO(sra): Also strengthen uses for when the condition is known |
| 2154 // false. Avoid strengthening to `null`. | 2163 // false. Avoid strengthening to `null`. |
| 2155 } | 2164 } |
| 2156 | 2165 |
| 2157 void visitIdentity(HIdentity instruction) { | 2166 void visitIdentity(HIdentity instruction) { |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2279 HInstruction instruction = block.first; | 2288 HInstruction instruction = block.first; |
| 2280 while (instruction != null) { | 2289 while (instruction != null) { |
| 2281 HInstruction next = instruction.next; | 2290 HInstruction next = instruction.next; |
| 2282 instruction.accept(this); | 2291 instruction.accept(this); |
| 2283 instruction = next; | 2292 instruction = next; |
| 2284 } | 2293 } |
| 2285 } | 2294 } |
| 2286 | 2295 |
| 2287 void visitFieldGet(HFieldGet instruction) { | 2296 void visitFieldGet(HFieldGet instruction) { |
| 2288 if (instruction.isNullCheck) return; | 2297 if (instruction.isNullCheck) return; |
| 2289 MemberElement element = instruction.element; | 2298 MemberEntity element = instruction.element; |
| 2290 HInstruction receiver = instruction.getDartReceiver(closedWorld).nonCheck(); | 2299 HInstruction receiver = instruction.getDartReceiver(closedWorld).nonCheck(); |
| 2291 HInstruction existing = memorySet.lookupFieldValue(element, receiver); | 2300 HInstruction existing = memorySet.lookupFieldValue(element, receiver); |
| 2292 if (existing != null) { | 2301 if (existing != null) { |
| 2293 instruction.block.rewriteWithBetterUser(instruction, existing); | 2302 instruction.block.rewriteWithBetterUser(instruction, existing); |
| 2294 instruction.block.remove(instruction); | 2303 instruction.block.remove(instruction); |
| 2295 } else { | 2304 } else { |
| 2296 memorySet.registerFieldValue(element, receiver, instruction); | 2305 memorySet.registerFieldValue(element, receiver, instruction); |
| 2297 } | 2306 } |
| 2298 } | 2307 } |
| 2299 | 2308 |
| 2300 void visitFieldSet(HFieldSet instruction) { | 2309 void visitFieldSet(HFieldSet instruction) { |
| 2301 HInstruction receiver = instruction.getDartReceiver(closedWorld).nonCheck(); | 2310 HInstruction receiver = instruction.getDartReceiver(closedWorld).nonCheck(); |
| 2302 memorySet.registerFieldValueUpdate( | 2311 memorySet.registerFieldValueUpdate( |
| 2303 instruction.element, receiver, instruction.inputs.last); | 2312 instruction.element, receiver, instruction.inputs.last); |
| 2304 } | 2313 } |
| 2305 | 2314 |
| 2306 void visitCreate(HCreate instruction) { | 2315 void visitCreate(HCreate instruction) { |
| 2307 memorySet.registerAllocation(instruction); | 2316 memorySet.registerAllocation(instruction); |
| 2308 if (shouldTrackInitialValues(instruction)) { | 2317 if (shouldTrackInitialValues(instruction)) { |
| 2309 int argumentIndex = 0; | 2318 int argumentIndex = 0; |
| 2310 compiler.codegenWorld.forEachInstanceField(instruction.element, | 2319 compiler.codegenWorld.forEachInstanceField(instruction.element, |
| 2311 (_, FieldElement member) { | 2320 (_, FieldEntity member) { |
| 2312 if (compiler.elementHasCompileTimeError(member)) return; | 2321 if (compiler.elementHasCompileTimeError(member as Entity)) return; |
| 2313 memorySet.registerFieldValue( | 2322 memorySet.registerFieldValue( |
| 2314 member, instruction, instruction.inputs[argumentIndex++]); | 2323 member, instruction, instruction.inputs[argumentIndex++]); |
| 2315 }); | 2324 }); |
| 2316 } | 2325 } |
| 2317 // In case this instruction has as input non-escaping objects, we | 2326 // In case this instruction has as input non-escaping objects, we |
| 2318 // need to mark these objects as escaping. | 2327 // need to mark these objects as escaping. |
| 2319 memorySet.killAffectedBy(instruction); | 2328 memorySet.killAffectedBy(instruction); |
| 2320 } | 2329 } |
| 2321 | 2330 |
| 2322 bool shouldTrackInitialValues(HCreate instruction) { | 2331 bool shouldTrackInitialValues(HCreate instruction) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2358 } | 2367 } |
| 2359 | 2368 |
| 2360 void visitInstruction(HInstruction instruction) { | 2369 void visitInstruction(HInstruction instruction) { |
| 2361 if (instruction.isAllocation) { | 2370 if (instruction.isAllocation) { |
| 2362 memorySet.registerAllocation(instruction); | 2371 memorySet.registerAllocation(instruction); |
| 2363 } | 2372 } |
| 2364 memorySet.killAffectedBy(instruction); | 2373 memorySet.killAffectedBy(instruction); |
| 2365 } | 2374 } |
| 2366 | 2375 |
| 2367 void visitLazyStatic(HLazyStatic instruction) { | 2376 void visitLazyStatic(HLazyStatic instruction) { |
| 2368 FieldElement field = instruction.element; | 2377 FieldEntity field = instruction.element; |
| 2369 handleStaticLoad(field, instruction); | 2378 handleStaticLoad(field, instruction); |
| 2370 } | 2379 } |
| 2371 | 2380 |
| 2372 void handleStaticLoad(MemberElement element, HInstruction instruction) { | 2381 void handleStaticLoad(MemberEntity element, HInstruction instruction) { |
| 2373 HInstruction existing = memorySet.lookupFieldValue(element, null); | 2382 HInstruction existing = memorySet.lookupFieldValue(element, null); |
| 2374 if (existing != null) { | 2383 if (existing != null) { |
| 2375 instruction.block.rewriteWithBetterUser(instruction, existing); | 2384 instruction.block.rewriteWithBetterUser(instruction, existing); |
| 2376 instruction.block.remove(instruction); | 2385 instruction.block.remove(instruction); |
| 2377 } else { | 2386 } else { |
| 2378 memorySet.registerFieldValue(element, null, instruction); | 2387 memorySet.registerFieldValue(element, null, instruction); |
| 2379 } | 2388 } |
| 2380 } | 2389 } |
| 2381 | 2390 |
| 2382 void visitStatic(HStatic instruction) { | 2391 void visitStatic(HStatic instruction) { |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2437 * other checks removed to ensure that checks and type refinements do not | 2446 * other checks removed to ensure that checks and type refinements do not |
| 2438 * confuse aliasing. Values stored into a memory place keep the type | 2447 * confuse aliasing. Values stored into a memory place keep the type |
| 2439 * refinements to help further optimizations. | 2448 * refinements to help further optimizations. |
| 2440 */ | 2449 */ |
| 2441 class MemorySet { | 2450 class MemorySet { |
| 2442 final ClosedWorld closedWorld; | 2451 final ClosedWorld closedWorld; |
| 2443 | 2452 |
| 2444 /** | 2453 /** |
| 2445 * Maps a field to a map of receiver to value. | 2454 * Maps a field to a map of receiver to value. |
| 2446 */ | 2455 */ |
| 2447 final Map<Element, Map<HInstruction, HInstruction>> fieldValues = | 2456 final Map<MemberEntity, Map<HInstruction, HInstruction>> fieldValues = |
| 2448 <Element, Map<HInstruction, HInstruction>>{}; | 2457 <MemberEntity, Map<HInstruction, HInstruction>>{}; |
| 2449 | 2458 |
| 2450 /** | 2459 /** |
| 2451 * Maps a receiver to a map of keys to value. | 2460 * Maps a receiver to a map of keys to value. |
| 2452 */ | 2461 */ |
| 2453 final Map<HInstruction, Map<HInstruction, HInstruction>> keyedValues = | 2462 final Map<HInstruction, Map<HInstruction, HInstruction>> keyedValues = |
| 2454 <HInstruction, Map<HInstruction, HInstruction>>{}; | 2463 <HInstruction, Map<HInstruction, HInstruction>>{}; |
| 2455 | 2464 |
| 2456 /** | 2465 /** |
| 2457 * Set of objects that we know don't escape the current function. | 2466 * Set of objects that we know don't escape the current function. |
| 2458 */ | 2467 */ |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 2474 if (mustAlias(first, second)) return true; | 2483 if (mustAlias(first, second)) return true; |
| 2475 if (isConcrete(first) && isConcrete(second)) return false; | 2484 if (isConcrete(first) && isConcrete(second)) return false; |
| 2476 if (nonEscapingReceivers.contains(first)) return false; | 2485 if (nonEscapingReceivers.contains(first)) return false; |
| 2477 if (nonEscapingReceivers.contains(second)) return false; | 2486 if (nonEscapingReceivers.contains(second)) return false; |
| 2478 // Typed arrays of different types might have a shared buffer. | 2487 // Typed arrays of different types might have a shared buffer. |
| 2479 if (couldBeTypedArray(first) && couldBeTypedArray(second)) return true; | 2488 if (couldBeTypedArray(first) && couldBeTypedArray(second)) return true; |
| 2480 return !first.instructionType | 2489 return !first.instructionType |
| 2481 .isDisjoint(second.instructionType, closedWorld); | 2490 .isDisjoint(second.instructionType, closedWorld); |
| 2482 } | 2491 } |
| 2483 | 2492 |
| 2484 bool isFinal(Element element) { | 2493 bool isFinal(MemberEntity element) { |
| 2485 return closedWorld.fieldNeverChanges(element); | 2494 return closedWorld.fieldNeverChanges(element); |
| 2486 } | 2495 } |
| 2487 | 2496 |
| 2488 bool isConcrete(HInstruction instruction) { | 2497 bool isConcrete(HInstruction instruction) { |
| 2489 return instruction is HCreate || | 2498 return instruction is HCreate || |
| 2490 instruction is HConstant || | 2499 instruction is HConstant || |
| 2491 instruction is HLiteralList; | 2500 instruction is HLiteralList; |
| 2492 } | 2501 } |
| 2493 | 2502 |
| 2494 bool couldBeTypedArray(HInstruction receiver) { | 2503 bool couldBeTypedArray(HInstruction receiver) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 2506 void registerAllocation(HInstruction instruction) { | 2515 void registerAllocation(HInstruction instruction) { |
| 2507 assert(instruction == instruction.nonCheck()); | 2516 assert(instruction == instruction.nonCheck()); |
| 2508 nonEscapingReceivers.add(instruction); | 2517 nonEscapingReceivers.add(instruction); |
| 2509 } | 2518 } |
| 2510 | 2519 |
| 2511 /** | 2520 /** |
| 2512 * Sets `receiver.element` to contain [value]. Kills all potential places that | 2521 * Sets `receiver.element` to contain [value]. Kills all potential places that |
| 2513 * may be affected by this update. | 2522 * may be affected by this update. |
| 2514 */ | 2523 */ |
| 2515 void registerFieldValueUpdate( | 2524 void registerFieldValueUpdate( |
| 2516 MemberElement element, HInstruction receiver, HInstruction value) { | 2525 MemberEntity element, HInstruction receiver, HInstruction value) { |
| 2517 assert(receiver == null || receiver == receiver.nonCheck()); | 2526 assert(receiver == null || receiver == receiver.nonCheck()); |
| 2518 if (closedWorld.backendClasses.isNative(element)) { | 2527 if (closedWorld.backendClasses.isNativeMember(element)) { |
| 2519 return; // TODO(14955): Remove this restriction? | 2528 return; // TODO(14955): Remove this restriction? |
| 2520 } | 2529 } |
| 2521 // [value] is being set in some place in memory, we remove it from | 2530 // [value] is being set in some place in memory, we remove it from |
| 2522 // the non-escaping set. | 2531 // the non-escaping set. |
| 2523 nonEscapingReceivers.remove(value.nonCheck()); | 2532 nonEscapingReceivers.remove(value.nonCheck()); |
| 2524 Map<HInstruction, HInstruction> map = | 2533 Map<HInstruction, HInstruction> map = |
| 2525 fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{}); | 2534 fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{}); |
| 2526 map.forEach((key, value) { | 2535 map.forEach((key, value) { |
| 2527 if (mayAlias(receiver, key)) map[key] = null; | 2536 if (mayAlias(receiver, key)) map[key] = null; |
| 2528 }); | 2537 }); |
| 2529 map[receiver] = value; | 2538 map[receiver] = value; |
| 2530 } | 2539 } |
| 2531 | 2540 |
| 2532 /** | 2541 /** |
| 2533 * Registers that `receiver.element` is now [value]. | 2542 * Registers that `receiver.element` is now [value]. |
| 2534 */ | 2543 */ |
| 2535 void registerFieldValue( | 2544 void registerFieldValue( |
| 2536 MemberElement element, HInstruction receiver, HInstruction value) { | 2545 MemberEntity element, HInstruction receiver, HInstruction value) { |
| 2537 assert(receiver == null || receiver == receiver.nonCheck()); | 2546 assert(receiver == null || receiver == receiver.nonCheck()); |
| 2538 if (closedWorld.backendClasses.isNative(element)) { | 2547 if (closedWorld.backendClasses.isNativeMember(element)) { |
| 2539 return; // TODO(14955): Remove this restriction? | 2548 return; // TODO(14955): Remove this restriction? |
| 2540 } | 2549 } |
| 2541 Map<HInstruction, HInstruction> map = | 2550 Map<HInstruction, HInstruction> map = |
| 2542 fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{}); | 2551 fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{}); |
| 2543 map[receiver] = value; | 2552 map[receiver] = value; |
| 2544 } | 2553 } |
| 2545 | 2554 |
| 2546 /** | 2555 /** |
| 2547 * Returns the value stored in `receiver.element`. Returns `null` if we don't | 2556 * Returns the value stored in `receiver.element`. Returns `null` if we don't |
| 2548 * know. | 2557 * know. |
| 2549 */ | 2558 */ |
| 2550 HInstruction lookupFieldValue(Element element, HInstruction receiver) { | 2559 HInstruction lookupFieldValue(MemberEntity element, HInstruction receiver) { |
| 2551 assert(receiver == null || receiver == receiver.nonCheck()); | 2560 assert(receiver == null || receiver == receiver.nonCheck()); |
| 2552 Map<HInstruction, HInstruction> map = fieldValues[element]; | 2561 Map<HInstruction, HInstruction> map = fieldValues[element]; |
| 2553 return (map == null) ? null : map[receiver]; | 2562 return (map == null) ? null : map[receiver]; |
| 2554 } | 2563 } |
| 2555 | 2564 |
| 2556 /** | 2565 /** |
| 2557 * Kill all places that may be affected by this [instruction]. Also update the | 2566 * Kill all places that may be affected by this [instruction]. Also update the |
| 2558 * set of non-escaping objects in case [instruction] has non-escaping objects | 2567 * set of non-escaping objects in case [instruction] has non-escaping objects |
| 2559 * in its inputs. | 2568 * in its inputs. |
| 2560 */ | 2569 */ |
| 2561 void killAffectedBy(HInstruction instruction) { | 2570 void killAffectedBy(HInstruction instruction) { |
| 2562 // Even if [instruction] does not have side effects, it may use non-escaping | 2571 // Even if [instruction] does not have side effects, it may use non-escaping |
| 2563 // objects and store them in a new object, which make these objects | 2572 // objects and store them in a new object, which make these objects |
| 2564 // escaping. | 2573 // escaping. |
| 2565 instruction.inputs.forEach((input) { | 2574 instruction.inputs.forEach((input) { |
| 2566 nonEscapingReceivers.remove(input.nonCheck()); | 2575 nonEscapingReceivers.remove(input.nonCheck()); |
| 2567 }); | 2576 }); |
| 2568 | 2577 |
| 2569 if (instruction.sideEffects.changesInstanceProperty() || | 2578 if (instruction.sideEffects.changesInstanceProperty() || |
| 2570 instruction.sideEffects.changesStaticProperty()) { | 2579 instruction.sideEffects.changesStaticProperty()) { |
| 2571 fieldValues.forEach((element, map) { | 2580 fieldValues.forEach((MemberEntity element, map) { |
| 2572 if (isFinal(element)) return; | 2581 if (isFinal(element)) return; |
| 2573 map.forEach((receiver, value) { | 2582 map.forEach((receiver, value) { |
| 2574 if (escapes(receiver)) { | 2583 if (escapes(receiver)) { |
| 2575 map[receiver] = null; | 2584 map[receiver] = null; |
| 2576 } | 2585 } |
| 2577 }); | 2586 }); |
| 2578 }); | 2587 }); |
| 2579 } | 2588 } |
| 2580 | 2589 |
| 2581 if (instruction.sideEffects.changesIndex()) { | 2590 if (instruction.sideEffects.changesIndex()) { |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2744 | 2753 |
| 2745 keyedValues.forEach((receiver, values) { | 2754 keyedValues.forEach((receiver, values) { |
| 2746 result.keyedValues[receiver] = | 2755 result.keyedValues[receiver] = |
| 2747 new Map<HInstruction, HInstruction>.from(values); | 2756 new Map<HInstruction, HInstruction>.from(values); |
| 2748 }); | 2757 }); |
| 2749 | 2758 |
| 2750 result.nonEscapingReceivers.addAll(nonEscapingReceivers); | 2759 result.nonEscapingReceivers.addAll(nonEscapingReceivers); |
| 2751 return result; | 2760 return result; |
| 2752 } | 2761 } |
| 2753 } | 2762 } |
| OLD | NEW |