| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; | 5 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
| 6 import '../common/names.dart' show Selectors; | 6 import '../common/names.dart' show Selectors; |
| 7 import '../common/tasks.dart' show CompilerTask; | 7 import '../common/tasks.dart' show CompilerTask; |
| 8 import '../compiler.dart' show Compiler; | 8 import '../compiler.dart' show Compiler; |
| 9 import '../constants/constant_system.dart'; | 9 import '../constants/constant_system.dart'; |
| 10 import '../constants/values.dart'; | 10 import '../constants/values.dart'; |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 325 if (actualReceiver.isIndexablePrimitive(compiler)) { | 325 if (actualReceiver.isIndexablePrimitive(compiler)) { |
| 326 if (actualReceiver.isConstantString()) { | 326 if (actualReceiver.isConstantString()) { |
| 327 HConstant constantInput = actualReceiver; | 327 HConstant constantInput = actualReceiver; |
| 328 StringConstantValue constant = constantInput.constant; | 328 StringConstantValue constant = constantInput.constant; |
| 329 return graph.addConstantInt(constant.length, compiler); | 329 return graph.addConstantInt(constant.length, compiler); |
| 330 } else if (actualReceiver.isConstantList()) { | 330 } else if (actualReceiver.isConstantList()) { |
| 331 HConstant constantInput = actualReceiver; | 331 HConstant constantInput = actualReceiver; |
| 332 ListConstantValue constant = constantInput.constant; | 332 ListConstantValue constant = constantInput.constant; |
| 333 return graph.addConstantInt(constant.length, compiler); | 333 return graph.addConstantInt(constant.length, compiler); |
| 334 } | 334 } |
| 335 Element element = helpers.jsIndexableLength; | 335 MemberElement element = helpers.jsIndexableLength; |
| 336 bool isFixed = isFixedLength(actualReceiver.instructionType, compiler); | 336 bool isFixed = isFixedLength(actualReceiver.instructionType, compiler); |
| 337 TypeMask actualType = node.instructionType; | 337 TypeMask actualType = node.instructionType; |
| 338 ClosedWorld closedWorld = compiler.closedWorld; | 338 ClosedWorld closedWorld = compiler.closedWorld; |
| 339 TypeMask resultType = backend.positiveIntType; | 339 TypeMask resultType = backend.positiveIntType; |
| 340 // If we already have computed a more specific type, keep that type. | 340 // If we already have computed a more specific type, keep that type. |
| 341 if (HInstruction.isInstanceOf( | 341 if (HInstruction.isInstanceOf( |
| 342 actualType, helpers.jsUInt31Class, closedWorld)) { | 342 actualType, helpers.jsUInt31Class, closedWorld)) { |
| 343 resultType = backend.uint31Type; | 343 resultType = backend.uint31Type; |
| 344 } else if (HInstruction.isInstanceOf( | 344 } else if (HInstruction.isInstanceOf( |
| 345 actualType, helpers.jsUInt32Class, closedWorld)) { | 345 actualType, helpers.jsUInt32Class, closedWorld)) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 376 HInstruction input = node.inputs[1]; | 376 HInstruction input = node.inputs[1]; |
| 377 | 377 |
| 378 ClosedWorld world = compiler.closedWorld; | 378 ClosedWorld world = compiler.closedWorld; |
| 379 | 379 |
| 380 bool applies(Element element) { | 380 bool applies(Element element) { |
| 381 return selector.applies(element) && | 381 return selector.applies(element) && |
| 382 (mask == null || mask.canHit(element, selector, world)); | 382 (mask == null || mask.canHit(element, selector, world)); |
| 383 } | 383 } |
| 384 | 384 |
| 385 if (selector.isCall || selector.isOperator) { | 385 if (selector.isCall || selector.isOperator) { |
| 386 Element target; | 386 MethodElement target; |
| 387 if (input.isExtendableArray(compiler)) { | 387 if (input.isExtendableArray(compiler)) { |
| 388 if (applies(helpers.jsArrayRemoveLast)) { | 388 if (applies(helpers.jsArrayRemoveLast)) { |
| 389 target = helpers.jsArrayRemoveLast; | 389 target = helpers.jsArrayRemoveLast; |
| 390 } else if (applies(helpers.jsArrayAdd)) { | 390 } else if (applies(helpers.jsArrayAdd)) { |
| 391 // The codegen special cases array calls, but does not | 391 // The codegen special cases array calls, but does not |
| 392 // inline argument type checks. | 392 // inline argument type checks. |
| 393 if (!compiler.options.enableTypeAssertions) { | 393 if (!compiler.options.enableTypeAssertions) { |
| 394 target = helpers.jsArrayAdd; | 394 target = helpers.jsArrayAdd; |
| 395 } | 395 } |
| 396 } | 396 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 446 TypeMask receiverType = node.getDartReceiver(compiler).instructionType; | 446 TypeMask receiverType = node.getDartReceiver(compiler).instructionType; |
| 447 Element element = | 447 Element element = |
| 448 compiler.closedWorld.locateSingleElement(node.selector, receiverType); | 448 compiler.closedWorld.locateSingleElement(node.selector, receiverType); |
| 449 // TODO(ngeoffray): Also fold if it's a getter or variable. | 449 // TODO(ngeoffray): Also fold if it's a getter or variable. |
| 450 if (element != null && | 450 if (element != null && |
| 451 element.isFunction | 451 element.isFunction |
| 452 // If we found out that the only target is an implicitly called | 452 // If we found out that the only target is an implicitly called |
| 453 // [:noSuchMethod:] we just ignore it. | 453 // [:noSuchMethod:] we just ignore it. |
| 454 && | 454 && |
| 455 node.selector.applies(element)) { | 455 node.selector.applies(element)) { |
| 456 FunctionElement method = element; | 456 MethodElement method = element; |
| 457 | 457 |
| 458 if (backend.isNative(method)) { | 458 if (backend.isNative(method)) { |
| 459 HInstruction folded = tryInlineNativeMethod(node, method); | 459 HInstruction folded = tryInlineNativeMethod(node, method); |
| 460 if (folded != null) return folded; | 460 if (folded != null) return folded; |
| 461 } else { | 461 } else { |
| 462 // TODO(ngeoffray): If the method has optional parameters, | 462 // TODO(ngeoffray): If the method has optional parameters, |
| 463 // we should pass the default values. | 463 // we should pass the default values. |
| 464 FunctionSignature parameters = method.functionSignature; | 464 FunctionSignature parameters = method.functionSignature; |
| 465 if (parameters.optionalParameterCount == 0 || | 465 if (parameters.optionalParameterCount == 0 || |
| 466 parameters.parameterCount == node.selector.argumentCount) { | 466 parameters.parameterCount == node.selector.argumentCount) { |
| 467 node.element = element; | 467 node.element = method; |
| 468 } | 468 } |
| 469 } | 469 } |
| 470 return node; | 470 return node; |
| 471 } | 471 } |
| 472 | 472 |
| 473 // Replace method calls through fields with a closure call on the value of | 473 // Replace method calls through fields with a closure call on the value of |
| 474 // the field. This usually removes the demand for the call-through stub and | 474 // the field. This usually removes the demand for the call-through stub and |
| 475 // makes the field load available to further optimization, e.g. LICM. | 475 // makes the field load available to further optimization, e.g. LICM. |
| 476 | 476 |
| 477 if (element != null && | 477 if (element != null && |
| 478 element.isField && | 478 element.isField && |
| 479 element.name == node.selector.name) { | 479 element.name == node.selector.name) { |
| 480 if (!backend.isNative(element) && !node.isCallOnInterceptor(compiler)) { | 480 FieldElement field = element; |
| 481 if (!backend.isNative(field) && !node.isCallOnInterceptor(compiler)) { |
| 481 HInstruction receiver = node.getDartReceiver(compiler); | 482 HInstruction receiver = node.getDartReceiver(compiler); |
| 482 TypeMask type = | 483 TypeMask type = TypeMaskFactory.inferredTypeForElement(field, compiler); |
| 483 TypeMaskFactory.inferredTypeForElement(element, compiler); | 484 HInstruction load = new HFieldGet(field, receiver, type); |
| 484 HInstruction load = new HFieldGet(element, receiver, type); | |
| 485 node.block.addBefore(node, load); | 485 node.block.addBefore(node, load); |
| 486 Selector callSelector = new Selector.callClosureFrom(node.selector); | 486 Selector callSelector = new Selector.callClosureFrom(node.selector); |
| 487 List<HInstruction> inputs = <HInstruction>[load] | 487 List<HInstruction> inputs = <HInstruction>[load] |
| 488 ..addAll(node.inputs.skip(node.isInterceptedCall ? 2 : 1)); | 488 ..addAll(node.inputs.skip(node.isInterceptedCall ? 2 : 1)); |
| 489 HInstruction closureCall = | 489 HInstruction closureCall = |
| 490 new HInvokeClosure(callSelector, inputs, node.instructionType) | 490 new HInvokeClosure(callSelector, inputs, node.instructionType) |
| 491 ..sourceInformation = node.sourceInformation; | 491 ..sourceInformation = node.sourceInformation; |
| 492 node.block.addAfter(load, closureCall); | 492 node.block.addAfter(load, closureCall); |
| 493 return closureCall; | 493 return closureCall; |
| 494 } | 494 } |
| 495 } | 495 } |
| 496 | 496 |
| 497 return node; | 497 return node; |
| 498 } | 498 } |
| 499 | 499 |
| 500 HInstruction tryInlineNativeMethod( | 500 HInstruction tryInlineNativeMethod( |
| 501 HInvokeDynamicMethod node, FunctionElement method) { | 501 HInvokeDynamicMethod node, MethodElement method) { |
| 502 // Enable direct calls to a native method only if we don't run in checked | 502 // Enable direct calls to a native method only if we don't run in checked |
| 503 // mode, where the Dart version may have type annotations on parameters and | 503 // mode, where the Dart version may have type annotations on parameters and |
| 504 // return type that it should check. | 504 // return type that it should check. |
| 505 // Also check that the parameters are not functions: it's the callee that | 505 // Also check that the parameters are not functions: it's the callee that |
| 506 // will translate them to JS functions. | 506 // will translate them to JS functions. |
| 507 // | 507 // |
| 508 // TODO(ngeoffray): There are some cases where we could still inline in | 508 // TODO(ngeoffray): There are some cases where we could still inline in |
| 509 // checked mode if we know the arguments have the right type. And we could | 509 // checked mode if we know the arguments have the right type. And we could |
| 510 // do the closure conversion as well as the return type annotation check. | 510 // do the closure conversion as well as the return type annotation check. |
| 511 | 511 |
| (...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 818 HInstruction removeIfCheckAlwaysSucceeds(HCheck node, TypeMask checkedType) { | 818 HInstruction removeIfCheckAlwaysSucceeds(HCheck node, TypeMask checkedType) { |
| 819 ClosedWorld closedWorld = compiler.closedWorld; | 819 ClosedWorld closedWorld = compiler.closedWorld; |
| 820 if (checkedType.containsAll(closedWorld)) return node; | 820 if (checkedType.containsAll(closedWorld)) return node; |
| 821 HInstruction input = node.checkedInput; | 821 HInstruction input = node.checkedInput; |
| 822 TypeMask inputType = input.instructionType; | 822 TypeMask inputType = input.instructionType; |
| 823 return inputType.isInMask(checkedType, closedWorld) ? input : node; | 823 return inputType.isInMask(checkedType, closedWorld) ? input : node; |
| 824 } | 824 } |
| 825 | 825 |
| 826 HInstruction removeCheck(HCheck node) => node.checkedInput; | 826 HInstruction removeCheck(HCheck node) => node.checkedInput; |
| 827 | 827 |
| 828 VariableElement findConcreteFieldForDynamicAccess( | 828 FieldElement findConcreteFieldForDynamicAccess( |
| 829 HInstruction receiver, Selector selector) { | 829 HInstruction receiver, Selector selector) { |
| 830 TypeMask receiverType = receiver.instructionType; | 830 TypeMask receiverType = receiver.instructionType; |
| 831 return compiler.closedWorld.locateSingleField(selector, receiverType); | 831 return compiler.closedWorld.locateSingleField(selector, receiverType); |
| 832 } | 832 } |
| 833 | 833 |
| 834 HInstruction visitFieldGet(HFieldGet node) { | 834 HInstruction visitFieldGet(HFieldGet node) { |
| 835 if (node.isNullCheck) return node; | 835 if (node.isNullCheck) return node; |
| 836 var receiver = node.receiver; | 836 var receiver = node.receiver; |
| 837 if (node.element == helpers.jsIndexableLength) { | 837 if (node.element == helpers.jsIndexableLength) { |
| 838 if (graph.allocatedFixedLists.contains(receiver)) { | 838 if (graph.allocatedFixedLists.contains(receiver)) { |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 893 return node; | 893 return node; |
| 894 } | 894 } |
| 895 | 895 |
| 896 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { | 896 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
| 897 propagateConstantValueToUses(node); | 897 propagateConstantValueToUses(node); |
| 898 if (node.isInterceptedCall) { | 898 if (node.isInterceptedCall) { |
| 899 HInstruction folded = handleInterceptedCall(node); | 899 HInstruction folded = handleInterceptedCall(node); |
| 900 if (folded != node) return folded; | 900 if (folded != node) return folded; |
| 901 } | 901 } |
| 902 HInstruction receiver = node.getDartReceiver(compiler); | 902 HInstruction receiver = node.getDartReceiver(compiler); |
| 903 Element field = findConcreteFieldForDynamicAccess(receiver, node.selector); | 903 FieldElement field = |
| 904 findConcreteFieldForDynamicAccess(receiver, node.selector); |
| 904 if (field != null) return directFieldGet(receiver, field); | 905 if (field != null) return directFieldGet(receiver, field); |
| 905 | 906 |
| 906 if (node.element == null) { | 907 if (node.element == null) { |
| 907 Element element = compiler.closedWorld | 908 MemberElement element = compiler.closedWorld |
| 908 .locateSingleElement(node.selector, receiver.instructionType); | 909 .locateSingleElement(node.selector, receiver.instructionType); |
| 909 if (element != null && element.name == node.selector.name) { | 910 if (element != null && element.name == node.selector.name) { |
| 910 node.element = element; | 911 node.element = element; |
| 911 if (element.isFunction) { | 912 if (element.isFunction) { |
| 912 // A property extraction getter, aka a tear-off. | 913 // A property extraction getter, aka a tear-off. |
| 913 node.sideEffects.clearAllDependencies(); | 914 node.sideEffects.clearAllDependencies(); |
| 914 node.sideEffects.clearAllSideEffects(); | 915 node.sideEffects.clearAllSideEffects(); |
| 915 node.setUseGvn(); // We don't care about identity of tear-offs. | 916 node.setUseGvn(); // We don't care about identity of tear-offs. |
| 916 } | 917 } |
| 917 } | 918 } |
| 918 } | 919 } |
| 919 return node; | 920 return node; |
| 920 } | 921 } |
| 921 | 922 |
| 922 HInstruction directFieldGet(HInstruction receiver, Element field) { | 923 HInstruction directFieldGet(HInstruction receiver, FieldElement field) { |
| 923 bool isAssignable = !compiler.closedWorld.fieldNeverChanges(field); | 924 bool isAssignable = !compiler.closedWorld.fieldNeverChanges(field); |
| 924 | 925 |
| 925 TypeMask type; | 926 TypeMask type; |
| 926 if (backend.isNative(field.enclosingClass)) { | 927 if (backend.isNative(field.enclosingClass)) { |
| 927 type = TypeMaskFactory.fromNativeBehavior( | 928 type = TypeMaskFactory.fromNativeBehavior( |
| 928 backend.getNativeFieldLoadBehavior(field), compiler); | 929 backend.getNativeFieldLoadBehavior(field), compiler); |
| 929 } else { | 930 } else { |
| 930 type = TypeMaskFactory.inferredTypeForElement(field, compiler); | 931 type = TypeMaskFactory.inferredTypeForElement(field, compiler); |
| 931 } | 932 } |
| 932 | 933 |
| 933 return new HFieldGet(field, receiver, type, isAssignable: isAssignable); | 934 return new HFieldGet(field, receiver, type, isAssignable: isAssignable); |
| 934 } | 935 } |
| 935 | 936 |
| 936 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 937 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
| 937 if (node.isInterceptedCall) { | 938 if (node.isInterceptedCall) { |
| 938 HInstruction folded = handleInterceptedCall(node); | 939 HInstruction folded = handleInterceptedCall(node); |
| 939 if (folded != node) return folded; | 940 if (folded != node) return folded; |
| 940 } | 941 } |
| 941 | 942 |
| 942 HInstruction receiver = node.getDartReceiver(compiler); | 943 HInstruction receiver = node.getDartReceiver(compiler); |
| 943 VariableElement field = | 944 FieldElement field = |
| 944 findConcreteFieldForDynamicAccess(receiver, node.selector); | 945 findConcreteFieldForDynamicAccess(receiver, node.selector); |
| 945 if (field == null || !field.isAssignable) return node; | 946 if (field == null || !field.isAssignable) return node; |
| 946 // Use [:node.inputs.last:] in case the call follows the | 947 // Use [:node.inputs.last:] in case the call follows the |
| 947 // interceptor calling convention, but is not a call on an | 948 // interceptor calling convention, but is not a call on an |
| 948 // interceptor. | 949 // interceptor. |
| 949 HInstruction value = node.inputs.last; | 950 HInstruction value = node.inputs.last; |
| 950 if (compiler.options.enableTypeAssertions) { | 951 if (compiler.options.enableTypeAssertions) { |
| 951 DartType type = field.type; | 952 DartType type = field.type; |
| 952 if (!type.treatAsRaw || type.isTypeVariable) { | 953 if (!type.treatAsRaw || type.isTypeVariable) { |
| 953 // We cannot generate the correct type representation here, so don't | 954 // We cannot generate the correct type representation here, so don't |
| 954 // inline this access. | 955 // inline this access. |
| 955 return node; | 956 return node; |
| 956 } | 957 } |
| 957 HInstruction other = | 958 HInstruction other = |
| 958 value.convertType(compiler, type, HTypeConversion.CHECKED_MODE_CHECK); | 959 value.convertType(compiler, type, HTypeConversion.CHECKED_MODE_CHECK); |
| 959 if (other != value) { | 960 if (other != value) { |
| 960 node.block.addBefore(node, other); | 961 node.block.addBefore(node, other); |
| 961 value = other; | 962 value = other; |
| 962 } | 963 } |
| 963 } | 964 } |
| 964 return new HFieldSet(field, receiver, value); | 965 return new HFieldSet(field, receiver, value); |
| 965 } | 966 } |
| 966 | 967 |
| 967 HInstruction visitInvokeStatic(HInvokeStatic node) { | 968 HInstruction visitInvokeStatic(HInvokeStatic node) { |
| 968 propagateConstantValueToUses(node); | 969 propagateConstantValueToUses(node); |
| 969 Element element = node.element; | 970 MemberElement element = node.element; |
| 970 | 971 |
| 971 if (element == backend.helpers.checkConcurrentModificationError) { | 972 if (element == backend.helpers.checkConcurrentModificationError) { |
| 972 if (node.inputs.length == 2) { | 973 if (node.inputs.length == 2) { |
| 973 HInstruction firstArgument = node.inputs[0]; | 974 HInstruction firstArgument = node.inputs[0]; |
| 974 if (firstArgument is HConstant) { | 975 if (firstArgument is HConstant) { |
| 975 HConstant constant = firstArgument; | 976 HConstant constant = firstArgument; |
| 976 if (constant.constant.isTrue) return constant; | 977 if (constant.constant.isTrue) return constant; |
| 977 } | 978 } |
| 978 } | 979 } |
| 979 } else if (element == backend.helpers.checkInt) { | 980 } else if (element == backend.helpers.checkInt) { |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1331 index = insertBoundsCheck(node, node.receiver, index); | 1332 index = insertBoundsCheck(node, node.receiver, index); |
| 1332 } | 1333 } |
| 1333 | 1334 |
| 1334 void visitIndexAssign(HIndexAssign node) { | 1335 void visitIndexAssign(HIndexAssign node) { |
| 1335 if (boundsChecked.contains(node)) return; | 1336 if (boundsChecked.contains(node)) return; |
| 1336 HInstruction index = node.index; | 1337 HInstruction index = node.index; |
| 1337 index = insertBoundsCheck(node, node.receiver, index); | 1338 index = insertBoundsCheck(node, node.receiver, index); |
| 1338 } | 1339 } |
| 1339 | 1340 |
| 1340 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 1341 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
| 1341 Element element = node.element; | 1342 MemberElement element = node.element; |
| 1342 if (node.isInterceptedCall) return; | 1343 if (node.isInterceptedCall) return; |
| 1343 if (element != helpers.jsArrayRemoveLast) return; | 1344 if (element != helpers.jsArrayRemoveLast) return; |
| 1344 if (boundsChecked.contains(node)) return; | 1345 if (boundsChecked.contains(node)) return; |
| 1345 // `0` is the index we want to check, but we want to report `-1`, as if we | 1346 // `0` is the index we want to check, but we want to report `-1`, as if we |
| 1346 // executed `a[a.length-1]` | 1347 // executed `a[a.length-1]` |
| 1347 HBoundsCheck check = insertBoundsCheck( | 1348 HBoundsCheck check = insertBoundsCheck( |
| 1348 node, node.receiver, graph.addConstantInt(0, backend.compiler)); | 1349 node, node.receiver, graph.addConstantInt(0, backend.compiler)); |
| 1349 HInstruction minusOne = graph.addConstantInt(-1, backend.compiler); | 1350 HInstruction minusOne = graph.addConstantInt(-1, backend.compiler); |
| 1350 check.inputs.add(minusOne); | 1351 check.inputs.add(minusOne); |
| 1351 minusOne.usedBy.add(check); | 1352 minusOne.usedBy.add(check); |
| (...skipping 803 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2155 | 2156 |
| 2156 for (HBasicBlock block in falseTargets) { | 2157 for (HBasicBlock block in falseTargets) { |
| 2157 insertTypePropagationForDominatedUsers(block, input, nonNullType); | 2158 insertTypePropagationForDominatedUsers(block, input, nonNullType); |
| 2158 } | 2159 } |
| 2159 // We don't strengthen the known-true references. It doesn't happen often | 2160 // We don't strengthen the known-true references. It doesn't happen often |
| 2160 // and we don't want "if (x==null) return x;" to convert between JavaScript | 2161 // and we don't want "if (x==null) return x;" to convert between JavaScript |
| 2161 // 'null' and 'undefined'. | 2162 // 'null' and 'undefined'. |
| 2162 } | 2163 } |
| 2163 | 2164 |
| 2164 collectTargets(HInstruction instruction, List<HBasicBlock> trueTargets, | 2165 collectTargets(HInstruction instruction, List<HBasicBlock> trueTargets, |
| 2165 List<HBasicBlock> falseTargets) { | 2166 List<HBasicBlock> falseTargets) { |
| 2166 for (HInstruction user in instruction.usedBy) { | 2167 for (HInstruction user in instruction.usedBy) { |
| 2167 if (user is HIf) { | 2168 if (user is HIf) { |
| 2168 trueTargets?.add(user.thenBlock); | 2169 trueTargets?.add(user.thenBlock); |
| 2169 falseTargets?.add(user.elseBlock); | 2170 falseTargets?.add(user.elseBlock); |
| 2170 } else if (user is HNot) { | 2171 } else if (user is HNot) { |
| 2171 collectTargets(user, falseTargets, trueTargets); | 2172 collectTargets(user, falseTargets, trueTargets); |
| 2172 } else if (user is HPhi) { | 2173 } else if (user is HPhi) { |
| 2173 List<HInstruction> inputs = user.inputs; | 2174 List<HInstruction> inputs = user.inputs; |
| 2174 if (inputs.length == 2) { | 2175 if (inputs.length == 2) { |
| 2175 assert(inputs.contains(instruction)); | 2176 assert(inputs.contains(instruction)); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2252 HInstruction instruction = block.first; | 2253 HInstruction instruction = block.first; |
| 2253 while (instruction != null) { | 2254 while (instruction != null) { |
| 2254 HInstruction next = instruction.next; | 2255 HInstruction next = instruction.next; |
| 2255 instruction.accept(this); | 2256 instruction.accept(this); |
| 2256 instruction = next; | 2257 instruction = next; |
| 2257 } | 2258 } |
| 2258 } | 2259 } |
| 2259 | 2260 |
| 2260 void visitFieldGet(HFieldGet instruction) { | 2261 void visitFieldGet(HFieldGet instruction) { |
| 2261 if (instruction.isNullCheck) return; | 2262 if (instruction.isNullCheck) return; |
| 2262 Element element = instruction.element; | 2263 MemberElement element = instruction.element; |
| 2263 HInstruction receiver = instruction.getDartReceiver(compiler).nonCheck(); | 2264 HInstruction receiver = instruction.getDartReceiver(compiler).nonCheck(); |
| 2264 HInstruction existing = memorySet.lookupFieldValue(element, receiver); | 2265 HInstruction existing = memorySet.lookupFieldValue(element, receiver); |
| 2265 if (existing != null) { | 2266 if (existing != null) { |
| 2266 instruction.block.rewriteWithBetterUser(instruction, existing); | 2267 instruction.block.rewriteWithBetterUser(instruction, existing); |
| 2267 instruction.block.remove(instruction); | 2268 instruction.block.remove(instruction); |
| 2268 } else { | 2269 } else { |
| 2269 memorySet.registerFieldValue(element, receiver, instruction); | 2270 memorySet.registerFieldValue(element, receiver, instruction); |
| 2270 } | 2271 } |
| 2271 } | 2272 } |
| 2272 | 2273 |
| 2273 void visitFieldSet(HFieldSet instruction) { | 2274 void visitFieldSet(HFieldSet instruction) { |
| 2274 HInstruction receiver = instruction.getDartReceiver(compiler).nonCheck(); | 2275 HInstruction receiver = instruction.getDartReceiver(compiler).nonCheck(); |
| 2275 memorySet.registerFieldValueUpdate( | 2276 memorySet.registerFieldValueUpdate( |
| 2276 instruction.element, receiver, instruction.inputs.last); | 2277 instruction.element, receiver, instruction.inputs.last); |
| 2277 } | 2278 } |
| 2278 | 2279 |
| 2279 void visitCreate(HCreate instruction) { | 2280 void visitCreate(HCreate instruction) { |
| 2280 memorySet.registerAllocation(instruction); | 2281 memorySet.registerAllocation(instruction); |
| 2281 if (shouldTrackInitialValues(instruction)) { | 2282 if (shouldTrackInitialValues(instruction)) { |
| 2282 int argumentIndex = 0; | 2283 int argumentIndex = 0; |
| 2283 instruction.element.forEachInstanceField((_, Element member) { | 2284 instruction.element.forEachInstanceField((_, FieldElement member) { |
| 2284 if (compiler.elementHasCompileTimeError(member)) return; | 2285 if (compiler.elementHasCompileTimeError(member)) return; |
| 2285 memorySet.registerFieldValue( | 2286 memorySet.registerFieldValue( |
| 2286 member, instruction, instruction.inputs[argumentIndex++]); | 2287 member, instruction, instruction.inputs[argumentIndex++]); |
| 2287 }, includeSuperAndInjectedMembers: true); | 2288 }, includeSuperAndInjectedMembers: true); |
| 2288 } | 2289 } |
| 2289 // In case this instruction has as input non-escaping objects, we | 2290 // In case this instruction has as input non-escaping objects, we |
| 2290 // need to mark these objects as escaping. | 2291 // need to mark these objects as escaping. |
| 2291 memorySet.killAffectedBy(instruction); | 2292 memorySet.killAffectedBy(instruction); |
| 2292 } | 2293 } |
| 2293 | 2294 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2330 } | 2331 } |
| 2331 | 2332 |
| 2332 void visitInstruction(HInstruction instruction) { | 2333 void visitInstruction(HInstruction instruction) { |
| 2333 if (instruction.isAllocation) { | 2334 if (instruction.isAllocation) { |
| 2334 memorySet.registerAllocation(instruction); | 2335 memorySet.registerAllocation(instruction); |
| 2335 } | 2336 } |
| 2336 memorySet.killAffectedBy(instruction); | 2337 memorySet.killAffectedBy(instruction); |
| 2337 } | 2338 } |
| 2338 | 2339 |
| 2339 void visitLazyStatic(HLazyStatic instruction) { | 2340 void visitLazyStatic(HLazyStatic instruction) { |
| 2340 handleStaticLoad(instruction.element, instruction); | 2341 FieldElement field = instruction.element; |
| 2342 handleStaticLoad(field, instruction); |
| 2341 } | 2343 } |
| 2342 | 2344 |
| 2343 void handleStaticLoad(Element element, HInstruction instruction) { | 2345 void handleStaticLoad(MemberElement element, HInstruction instruction) { |
| 2344 HInstruction existing = memorySet.lookupFieldValue(element, null); | 2346 HInstruction existing = memorySet.lookupFieldValue(element, null); |
| 2345 if (existing != null) { | 2347 if (existing != null) { |
| 2346 instruction.block.rewriteWithBetterUser(instruction, existing); | 2348 instruction.block.rewriteWithBetterUser(instruction, existing); |
| 2347 instruction.block.remove(instruction); | 2349 instruction.block.remove(instruction); |
| 2348 } else { | 2350 } else { |
| 2349 memorySet.registerFieldValue(element, null, instruction); | 2351 memorySet.registerFieldValue(element, null, instruction); |
| 2350 } | 2352 } |
| 2351 } | 2353 } |
| 2352 | 2354 |
| 2353 void visitStatic(HStatic instruction) { | 2355 void visitStatic(HStatic instruction) { |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2480 void registerAllocation(HInstruction instruction) { | 2482 void registerAllocation(HInstruction instruction) { |
| 2481 assert(instruction == instruction.nonCheck()); | 2483 assert(instruction == instruction.nonCheck()); |
| 2482 nonEscapingReceivers.add(instruction); | 2484 nonEscapingReceivers.add(instruction); |
| 2483 } | 2485 } |
| 2484 | 2486 |
| 2485 /** | 2487 /** |
| 2486 * Sets `receiver.element` to contain [value]. Kills all potential places that | 2488 * Sets `receiver.element` to contain [value]. Kills all potential places that |
| 2487 * may be affected by this update. | 2489 * may be affected by this update. |
| 2488 */ | 2490 */ |
| 2489 void registerFieldValueUpdate( | 2491 void registerFieldValueUpdate( |
| 2490 Element element, HInstruction receiver, HInstruction value) { | 2492 MemberElement element, HInstruction receiver, HInstruction value) { |
| 2491 assert(receiver == null || receiver == receiver.nonCheck()); | 2493 assert(receiver == null || receiver == receiver.nonCheck()); |
| 2492 if (backend.isNative(element)) { | 2494 if (backend.isNative(element)) { |
| 2493 return; // TODO(14955): Remove this restriction? | 2495 return; // TODO(14955): Remove this restriction? |
| 2494 } | 2496 } |
| 2495 // [value] is being set in some place in memory, we remove it from | 2497 // [value] is being set in some place in memory, we remove it from |
| 2496 // the non-escaping set. | 2498 // the non-escaping set. |
| 2497 nonEscapingReceivers.remove(value.nonCheck()); | 2499 nonEscapingReceivers.remove(value.nonCheck()); |
| 2498 Map<HInstruction, HInstruction> map = | 2500 Map<HInstruction, HInstruction> map = |
| 2499 fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{}); | 2501 fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{}); |
| 2500 map.forEach((key, value) { | 2502 map.forEach((key, value) { |
| 2501 if (mayAlias(receiver, key)) map[key] = null; | 2503 if (mayAlias(receiver, key)) map[key] = null; |
| 2502 }); | 2504 }); |
| 2503 map[receiver] = value; | 2505 map[receiver] = value; |
| 2504 } | 2506 } |
| 2505 | 2507 |
| 2506 /** | 2508 /** |
| 2507 * Registers that `receiver.element` is now [value]. | 2509 * Registers that `receiver.element` is now [value]. |
| 2508 */ | 2510 */ |
| 2509 void registerFieldValue( | 2511 void registerFieldValue( |
| 2510 Element element, HInstruction receiver, HInstruction value) { | 2512 MemberElement element, HInstruction receiver, HInstruction value) { |
| 2511 assert(receiver == null || receiver == receiver.nonCheck()); | 2513 assert(receiver == null || receiver == receiver.nonCheck()); |
| 2512 if (backend.isNative(element)) { | 2514 if (backend.isNative(element)) { |
| 2513 return; // TODO(14955): Remove this restriction? | 2515 return; // TODO(14955): Remove this restriction? |
| 2514 } | 2516 } |
| 2515 Map<HInstruction, HInstruction> map = | 2517 Map<HInstruction, HInstruction> map = |
| 2516 fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{}); | 2518 fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{}); |
| 2517 map[receiver] = value; | 2519 map[receiver] = value; |
| 2518 } | 2520 } |
| 2519 | 2521 |
| 2520 /** | 2522 /** |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2718 | 2720 |
| 2719 keyedValues.forEach((receiver, values) { | 2721 keyedValues.forEach((receiver, values) { |
| 2720 result.keyedValues[receiver] = | 2722 result.keyedValues[receiver] = |
| 2721 new Map<HInstruction, HInstruction>.from(values); | 2723 new Map<HInstruction, HInstruction>.from(values); |
| 2722 }); | 2724 }); |
| 2723 | 2725 |
| 2724 result.nonEscapingReceivers.addAll(nonEscapingReceivers); | 2726 result.nonEscapingReceivers.addAll(nonEscapingReceivers); |
| 2725 return result; | 2727 return result; |
| 2726 } | 2728 } |
| 2727 } | 2729 } |
| OLD | NEW |