Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Side by Side Diff: pkg/compiler/lib/src/ssa/optimize.dart

Issue 2615623002: Revert "Reduce use of Element in optimize.dart" (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pkg/compiler/lib/src/ssa/locals_handler.dart ('k') | pkg/compiler/lib/src/types/type_mask.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/ssa/locals_handler.dart ('k') | pkg/compiler/lib/src/types/type_mask.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698