| 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 class Interceptors { | 5 class Interceptors { |
| 6 Compiler compiler; | 6 Compiler compiler; |
| 7 Interceptors(Compiler this.compiler); | 7 Interceptors(Compiler this.compiler); |
| 8 | 8 |
| 9 SourceString mapOperatorToMethodName(Operator op) { | 9 SourceString mapOperatorToMethodName(Operator op) { |
| 10 String name = op.source.stringValue; | 10 String name = op.source.stringValue; |
| (...skipping 819 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 830 SsaBuilder(SsaBuilderTask builder, WorkItem work) | 830 SsaBuilder(SsaBuilderTask builder, WorkItem work) |
| 831 : this.builder = builder, | 831 : this.builder = builder, |
| 832 this.work = work, | 832 this.work = work, |
| 833 interceptors = builder.interceptors, | 833 interceptors = builder.interceptors, |
| 834 methodInterceptionEnabled = true, | 834 methodInterceptionEnabled = true, |
| 835 graph = new HGraph(), | 835 graph = new HGraph(), |
| 836 stack = new List<HInstruction>(), | 836 stack = new List<HInstruction>(), |
| 837 activationVariables = new Map<Element, HLocalValue>(), | 837 activationVariables = new Map<Element, HLocalValue>(), |
| 838 jumpTargets = new Map<TargetElement, JumpHandler>(), | 838 jumpTargets = new Map<TargetElement, JumpHandler>(), |
| 839 parameters = new Map<Element, HParameterValue>(), | 839 parameters = new Map<Element, HParameterValue>(), |
| 840 inliningStack = <InliningState>[], |
| 840 super(work.resolutionTree) { | 841 super(work.resolutionTree) { |
| 841 localsHandler = new LocalsHandler(this); | 842 localsHandler = new LocalsHandler(this); |
| 842 } | 843 } |
| 843 | 844 |
| 845 static final MAX_INLINING_DEPTH = 3; |
| 846 static final MAX_INLINING_SOURCE_SIZE = 100; |
| 847 List<InliningState> inliningStack; |
| 848 Element returnElement = null; |
| 849 |
| 844 void disableMethodInterception() { | 850 void disableMethodInterception() { |
| 845 assert(methodInterceptionEnabled); | 851 assert(methodInterceptionEnabled); |
| 846 methodInterceptionEnabled = false; | 852 methodInterceptionEnabled = false; |
| 847 } | 853 } |
| 848 | 854 |
| 849 void enableMethodInterception() { | 855 void enableMethodInterception() { |
| 850 assert(!methodInterceptionEnabled); | 856 assert(!methodInterceptionEnabled); |
| 851 methodInterceptionEnabled = true; | 857 methodInterceptionEnabled = true; |
| 852 } | 858 } |
| 853 | 859 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 893 TreeElements treeElements = | 899 TreeElements treeElements = |
| 894 compiler.resolver.resolveMethodElement(constructor); | 900 compiler.resolver.resolveMethodElement(constructor); |
| 895 compiler.enqueuer.codegen.addToWorkList(bodyElement, treeElements); | 901 compiler.enqueuer.codegen.addToWorkList(bodyElement, treeElements); |
| 896 classElement.backendMembers = | 902 classElement.backendMembers = |
| 897 classElement.backendMembers.prepend(bodyElement); | 903 classElement.backendMembers.prepend(bodyElement); |
| 898 } | 904 } |
| 899 assert(bodyElement.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY); | 905 assert(bodyElement.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY); |
| 900 return bodyElement; | 906 return bodyElement; |
| 901 } | 907 } |
| 902 | 908 |
| 909 InliningState enterInlinedMethod(PartialFunctionElement function, |
| 910 Selector selector, |
| 911 Link<Node> arguments) { |
| 912 // Once we start to compile the arguments we must be sure that we don't |
| 913 // abort. |
| 914 List<HInstruction> compiledArguments = new List<HInstruction>(); |
| 915 bool succeeded = addStaticSendArgumentsToList(selector, |
| 916 arguments, |
| 917 function, |
| 918 compiledArguments); |
| 919 assert(succeeded); |
| 920 |
| 921 InliningState state = |
| 922 new InliningState(function, returnElement, elements, stack); |
| 923 inliningStack.add(state); |
| 924 stack = <HInstruction>[]; |
| 925 returnElement = new Element(const SourceString("result"), |
| 926 ElementKind.VARIABLE, |
| 927 function); |
| 928 localsHandler.updateLocal(returnElement, graph.addConstantNull()); |
| 929 elements = compiler.enqueuer.resolution.getCachedElements(function); |
| 930 FunctionSignature signature = function.computeSignature(compiler); |
| 931 int index = 0; |
| 932 signature.forEachParameter((Element parameter) { |
| 933 HInstruction argument = compiledArguments[index++]; |
| 934 localsHandler.updateLocal(parameter, argument); |
| 935 potentiallyCheckType(argument, parameter); |
| 936 }); |
| 937 return state; |
| 938 } |
| 939 |
| 940 void leaveInlinedMethod(InliningState state) { |
| 941 InliningState poppedState = inliningStack.removeLast(); |
| 942 assert(state == poppedState); |
| 943 elements = state.oldElements; |
| 944 stack.add(localsHandler.readLocal(returnElement)); |
| 945 returnElement = state.oldReturnElement; |
| 946 assert(stack.length == 1); |
| 947 state.oldStack.add(stack[0]); |
| 948 stack = state.oldStack; |
| 949 } |
| 950 |
| 951 bool tryInlineMethod(Element element, |
| 952 Selector selector, |
| 953 Link<Node> arguments) { |
| 954 if (element.kind != ElementKind.FUNCTION) return false; |
| 955 if (element is !PartialFunctionElement) return false; |
| 956 if (inliningStack.length > MAX_INLINING_DEPTH) return false; |
| 957 // Don't inline recursive calls. We use the same elements for the inlined |
| 958 // functions and would thus clobber our local variables. |
| 959 if (work.element == element) return false; |
| 960 for (int i = 0; i < inliningStack.length; i++) { |
| 961 if (inliningStack[i].function == element) return false; |
| 962 } |
| 963 // TODO(ngeoffray): Inlining currently does not work in the presence of |
| 964 // private calls. |
| 965 if (currentLibrary != element.getLibrary()) return false; |
| 966 PartialFunctionElement function = element; |
| 967 int sourceSize = |
| 968 function.endToken.charOffset - function.beginToken.charOffset; |
| 969 if (sourceSize > MAX_INLINING_SOURCE_SIZE) return false; |
| 970 if (!selector.applies(function, compiler)) return false; |
| 971 FunctionExpression functionExpression = function.parseNode(compiler); |
| 972 TreeElements newElements = |
| 973 compiler.enqueuer.resolution.getCachedElements(function); |
| 974 if (newElements === null) { |
| 975 compiler.internalError("Element not resolved: $function"); |
| 976 } |
| 977 if (!InlineWeeder.canBeInlined(functionExpression, newElements)) { |
| 978 return false; |
| 979 } |
| 980 |
| 981 InliningState state = enterInlinedMethod(function, selector, arguments); |
| 982 functionExpression.body.accept(this); |
| 983 leaveInlinedMethod(state); |
| 984 return true; |
| 985 } |
| 986 |
| 903 void inlineSuperOrRedirect(FunctionElement constructor, | 987 void inlineSuperOrRedirect(FunctionElement constructor, |
| 904 Selector selector, | 988 Selector selector, |
| 905 Link<Node> arguments, | 989 Link<Node> arguments, |
| 906 List<FunctionElement> constructors, | 990 List<FunctionElement> constructors, |
| 907 Map<Element, HInstruction> fieldValues) { | 991 Map<Element, HInstruction> fieldValues) { |
| 908 constructors.addLast(constructor); | 992 constructors.addLast(constructor); |
| 909 | 993 |
| 910 List<HInstruction> compiledArguments = new List<HInstruction>(); | 994 List<HInstruction> compiledArguments = new List<HInstruction>(); |
| 911 bool succeeded = addStaticSendArgumentsToList(selector, | 995 bool succeeded = addStaticSendArgumentsToList(selector, |
| 912 arguments, | 996 arguments, |
| (...skipping 1452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2365 } | 2449 } |
| 2366 | 2450 |
| 2367 visitStaticSend(Send node) { | 2451 visitStaticSend(Send node) { |
| 2368 Selector selector = elements.getSelector(node); | 2452 Selector selector = elements.getSelector(node); |
| 2369 Element element = elements[node]; | 2453 Element element = elements[node]; |
| 2370 if (element === compiler.assertMethod && !compiler.enableUserAssertions) { | 2454 if (element === compiler.assertMethod && !compiler.enableUserAssertions) { |
| 2371 stack.add(graph.addConstantNull()); | 2455 stack.add(graph.addConstantNull()); |
| 2372 return; | 2456 return; |
| 2373 } | 2457 } |
| 2374 compiler.ensure(element.kind !== ElementKind.GENERATIVE_CONSTRUCTOR); | 2458 compiler.ensure(element.kind !== ElementKind.GENERATIVE_CONSTRUCTOR); |
| 2459 |
| 2460 if (tryInlineMethod(element, selector, node.arguments)) return; |
| 2461 |
| 2375 HInstruction target = new HStatic(element); | 2462 HInstruction target = new HStatic(element); |
| 2376 add(target); | 2463 add(target); |
| 2377 var inputs = <HInstruction>[]; | 2464 var inputs = <HInstruction>[]; |
| 2378 inputs.add(target); | 2465 inputs.add(target); |
| 2379 if (element.kind == ElementKind.FUNCTION) { | 2466 if (element.kind == ElementKind.FUNCTION) { |
| 2380 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, | 2467 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, |
| 2381 element, inputs); | 2468 element, inputs); |
| 2382 if (!succeeded) { | 2469 if (!succeeded) { |
| 2383 // TODO(ngeoffray): Match the VM behavior and throw an | 2470 // TODO(ngeoffray): Match the VM behavior and throw an |
| 2384 // exception at runtime. | 2471 // exception at runtime. |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2638 native.handleSsaNative(this, node.expression); | 2725 native.handleSsaNative(this, node.expression); |
| 2639 return; | 2726 return; |
| 2640 } | 2727 } |
| 2641 HInstruction value; | 2728 HInstruction value; |
| 2642 if (node.expression === null) { | 2729 if (node.expression === null) { |
| 2643 value = graph.addConstantNull(); | 2730 value = graph.addConstantNull(); |
| 2644 } else { | 2731 } else { |
| 2645 visit(node.expression); | 2732 visit(node.expression); |
| 2646 value = pop(); | 2733 value = pop(); |
| 2647 } | 2734 } |
| 2648 close(attachPosition(new HReturn(value), node)).addSuccessor(graph.exit); | 2735 if (!inliningStack.isEmpty()) { |
| 2736 localsHandler.updateLocal(returnElement, value); |
| 2737 } else { |
| 2738 close(attachPosition(new HReturn(value), node)).addSuccessor(graph.exit); |
| 2739 } |
| 2649 } | 2740 } |
| 2650 | 2741 |
| 2651 visitThrow(Throw node) { | 2742 visitThrow(Throw node) { |
| 2652 if (node.expression === null) { | 2743 if (node.expression === null) { |
| 2653 HInstruction exception = rethrowableException; | 2744 HInstruction exception = rethrowableException; |
| 2654 if (exception === null) { | 2745 if (exception === null) { |
| 2655 exception = graph.addConstantNull(); | 2746 exception = graph.addConstantNull(); |
| 2656 compiler.reportError(node, | 2747 compiler.reportError(node, |
| 2657 'throw without expression outside catch block'); | 2748 'throw without expression outside catch block'); |
| 2658 } | 2749 } |
| (...skipping 783 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3442 node.visitChildren(this); | 3533 node.visitChildren(this); |
| 3443 } | 3534 } |
| 3444 | 3535 |
| 3445 HInstruction concat(HInstruction left, HInstruction right) { | 3536 HInstruction concat(HInstruction left, HInstruction right) { |
| 3446 HInstruction instruction = new HStringConcat(left, right, diagnosticNode); | 3537 HInstruction instruction = new HStringConcat(left, right, diagnosticNode); |
| 3447 builder.add(instruction); | 3538 builder.add(instruction); |
| 3448 return instruction; | 3539 return instruction; |
| 3449 } | 3540 } |
| 3450 } | 3541 } |
| 3451 | 3542 |
| 3543 /** |
| 3544 * This class visits the method that is a candidate for inlining and |
| 3545 * finds whether it is too difficult to inline. |
| 3546 */ |
| 3547 class InlineWeeder extends AbstractVisitor { |
| 3548 final TreeElements elements; |
| 3549 bool seenReturn = false; |
| 3550 bool tooDifficult = false; |
| 3551 |
| 3552 InlineWeeder(this.elements); |
| 3553 |
| 3554 static bool canBeInlined(FunctionExpression functionExpression, |
| 3555 TreeElements elements) { |
| 3556 InlineWeeder weeder = new InlineWeeder(elements); |
| 3557 weeder.visit(functionExpression.body); |
| 3558 if (weeder.tooDifficult) return false; |
| 3559 return true; |
| 3560 } |
| 3561 |
| 3562 void visit(Node node) { |
| 3563 node.accept(this); |
| 3564 } |
| 3565 |
| 3566 void visitNode(Node node) { |
| 3567 if (seenReturn) { |
| 3568 tooDifficult = true; |
| 3569 } else { |
| 3570 node.visitChildren(this); |
| 3571 } |
| 3572 } |
| 3573 |
| 3574 void visitFunctionExpression(Node node) { |
| 3575 tooDifficult = true; |
| 3576 } |
| 3577 |
| 3578 void visitFunctionDeclaration(Node node) { |
| 3579 tooDifficult = true; |
| 3580 } |
| 3581 |
| 3582 void visitSend(Node node) { |
| 3583 Element element = elements[node]; |
| 3584 // Native methods rely on the names of the arguments. If we inline they |
| 3585 // could change. |
| 3586 if (!Element.isInvalid(element) && element.kind == ElementKind.FOREIGN) { |
| 3587 tooDifficult = true; |
| 3588 } else { |
| 3589 node.visitChildren(this); |
| 3590 } |
| 3591 } |
| 3592 |
| 3593 visitLoop(Node node) { |
| 3594 node.visitChildren(this); |
| 3595 if (seenReturn) tooDifficult = true; |
| 3596 } |
| 3597 |
| 3598 void visitReturn(Node node) { |
| 3599 if (seenReturn || node.getBeginToken().stringValue === 'native') { |
| 3600 tooDifficult = true; |
| 3601 return; |
| 3602 } |
| 3603 node.visitChildren(this); |
| 3604 seenReturn = true; |
| 3605 } |
| 3606 |
| 3607 void visitTryStatement(Node node) { |
| 3608 tooDifficult = true; |
| 3609 } |
| 3610 |
| 3611 void visitThrow(Node node) { |
| 3612 tooDifficult = true; |
| 3613 } |
| 3614 } |
| 3615 |
| 3616 class InliningState { |
| 3617 final PartialFunctionElement function; |
| 3618 final Element oldReturnElement; |
| 3619 final TreeElements oldElements; |
| 3620 final List<HInstruction> oldStack; |
| 3621 |
| 3622 InliningState(this.function, |
| 3623 this.oldReturnElement, |
| 3624 this.oldElements, |
| 3625 this.oldStack); |
| 3626 } |
| 3627 |
| 3452 class SsaBranch { | 3628 class SsaBranch { |
| 3453 final SsaBranchBuilder branchBuilder; | 3629 final SsaBranchBuilder branchBuilder; |
| 3454 final HBasicBlock block; | 3630 final HBasicBlock block; |
| 3455 LocalsHandler startLocals; | 3631 LocalsHandler startLocals; |
| 3456 LocalsHandler exitLocals; | 3632 LocalsHandler exitLocals; |
| 3457 SubGraph graph; | 3633 SubGraph graph; |
| 3458 | 3634 |
| 3459 SsaBranch(this.branchBuilder) : block = new HBasicBlock(); | 3635 SsaBranch(this.branchBuilder) : block = new HBasicBlock(); |
| 3460 } | 3636 } |
| 3461 | 3637 |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3674 new HSubGraphBlockInformation(elseBranch.graph)); | 3850 new HSubGraphBlockInformation(elseBranch.graph)); |
| 3675 | 3851 |
| 3676 HBasicBlock conditionStartBlock = conditionBranch.block; | 3852 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 3677 conditionStartBlock.setBlockFlow(info, joinBlock); | 3853 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 3678 SubGraph conditionGraph = conditionBranch.graph; | 3854 SubGraph conditionGraph = conditionBranch.graph; |
| 3679 HIf branch = conditionGraph.end.last; | 3855 HIf branch = conditionGraph.end.last; |
| 3680 assert(branch is HIf); | 3856 assert(branch is HIf); |
| 3681 branch.blockInformation = conditionStartBlock.blockFlow; | 3857 branch.blockInformation = conditionStartBlock.blockFlow; |
| 3682 } | 3858 } |
| 3683 } | 3859 } |
| OLD | NEW |