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

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

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