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