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

Side by Side Diff: lib/compiler/implementation/ssa/builder.dart

Issue 10873025: Inlining of static functions: applying Florian's CL. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 4 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 | Annotate | Revision Log
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 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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698