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 'dart:collection'; | 5 import 'dart:collection'; |
6 | 6 |
7 import 'package:js_runtime/shared/embedded_names.dart'; | 7 import 'package:js_runtime/shared/embedded_names.dart'; |
8 | 8 |
9 import '../closure.dart'; | 9 import '../closure.dart'; |
10 import '../common.dart'; | 10 import '../common.dart'; |
(...skipping 20 matching lines...) Expand all Loading... |
31 import '../resolution/semantic_visitor.dart'; | 31 import '../resolution/semantic_visitor.dart'; |
32 import '../resolution/tree_elements.dart' show TreeElements; | 32 import '../resolution/tree_elements.dart' show TreeElements; |
33 import '../tree/tree.dart' as ast; | 33 import '../tree/tree.dart' as ast; |
34 import '../types/types.dart'; | 34 import '../types/types.dart'; |
35 import '../universe/call_structure.dart' show CallStructure; | 35 import '../universe/call_structure.dart' show CallStructure; |
36 import '../universe/selector.dart' show Selector; | 36 import '../universe/selector.dart' show Selector; |
37 import '../universe/side_effects.dart' show SideEffects; | 37 import '../universe/side_effects.dart' show SideEffects; |
38 import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse; | 38 import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse; |
39 import '../util/util.dart'; | 39 import '../util/util.dart'; |
40 import '../world.dart' show ClassWorld; | 40 import '../world.dart' show ClassWorld; |
| 41 |
41 import 'graph_builder.dart'; | 42 import 'graph_builder.dart'; |
42 import 'locals_handler.dart'; | 43 import 'locals_handler.dart'; |
43 import 'nodes.dart'; | 44 import 'nodes.dart'; |
44 import 'optimize.dart'; | 45 import 'optimize.dart'; |
| 46 import 'ssa_branch_builder.dart'; |
45 import 'types.dart'; | 47 import 'types.dart'; |
46 | 48 |
47 /// A synthetic local variable only used with the SSA graph. | 49 /// A synthetic local variable only used with the SSA graph. |
48 /// | 50 /// |
49 /// For instance used for holding return value of function or the exception of a | 51 /// For instance used for holding return value of function or the exception of a |
50 /// try-catch statement. | 52 /// try-catch statement. |
51 class SyntheticLocal extends Local { | 53 class SyntheticLocal extends Local { |
52 final String name; | 54 final String name; |
53 final ExecutableElement executableContext; | 55 final ExecutableElement executableContext; |
54 | 56 |
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
404 * account. | 406 * account. |
405 */ | 407 */ |
406 int loopNesting = 0; | 408 int loopNesting = 0; |
407 | 409 |
408 /** | 410 /** |
409 * This stack contains declaration elements of the functions being built | 411 * This stack contains declaration elements of the functions being built |
410 * or inlined by this builder. | 412 * or inlined by this builder. |
411 */ | 413 */ |
412 final List<Element> sourceElementStack = <Element>[]; | 414 final List<Element> sourceElementStack = <Element>[]; |
413 | 415 |
414 LocalsHandler localsHandler; | |
415 | |
416 HInstruction rethrowableException; | 416 HInstruction rethrowableException; |
417 | 417 |
418 Map<JumpTarget, JumpHandler> jumpTargets = <JumpTarget, JumpHandler>{}; | 418 Map<JumpTarget, JumpHandler> jumpTargets = <JumpTarget, JumpHandler>{}; |
419 | 419 |
420 /// Returns `true` if the current element is an `async` function. | 420 /// Returns `true` if the current element is an `async` function. |
421 bool get isBuildingAsyncFunction { | 421 bool get isBuildingAsyncFunction { |
422 Element element = sourceElement; | 422 Element element = sourceElement; |
423 return (element is FunctionElement && | 423 return (element is FunctionElement && |
424 element.asyncMarker == AsyncMarker.ASYNC); | 424 element.asyncMarker == AsyncMarker.ASYNC); |
425 } | 425 } |
(...skipping 1474 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1900 // TODO(kasperl): Make this goto an implicit return. | 1900 // TODO(kasperl): Make this goto an implicit return. |
1901 if (!isAborted()) closeAndGotoExit(new HGoto()); | 1901 if (!isAborted()) closeAndGotoExit(new HGoto()); |
1902 graph.finalize(); | 1902 graph.finalize(); |
1903 return graph; | 1903 return graph; |
1904 } | 1904 } |
1905 | 1905 |
1906 void pushWithPosition(HInstruction instruction, ast.Node node) { | 1906 void pushWithPosition(HInstruction instruction, ast.Node node) { |
1907 push(attachPosition(instruction, node)); | 1907 push(attachPosition(instruction, node)); |
1908 } | 1908 } |
1909 | 1909 |
| 1910 @override |
1910 HInstruction popBoolified() { | 1911 HInstruction popBoolified() { |
1911 HInstruction value = pop(); | 1912 HInstruction value = pop(); |
1912 if (_checkOrTrustTypes) { | 1913 if (_checkOrTrustTypes) { |
1913 return potentiallyCheckOrTrustType(value, compiler.coreTypes.boolType, | 1914 return potentiallyCheckOrTrustType(value, compiler.coreTypes.boolType, |
1914 kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK); | 1915 kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK); |
1915 } | 1916 } |
1916 HInstruction result = new HBoolify(value, backend.boolType); | 1917 HInstruction result = new HBoolify(value, backend.boolType); |
1917 add(result); | 1918 add(result); |
1918 return result; | 1919 return result; |
1919 } | 1920 } |
(...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2530 visitThen: () => visit(node.thenPart), | 2531 visitThen: () => visit(node.thenPart), |
2531 visitElse: node.elsePart != null ? () => visit(node.elsePart) : null, | 2532 visitElse: node.elsePart != null ? () => visit(node.elsePart) : null, |
2532 sourceInformation: sourceInformationBuilder.buildIf(node)); | 2533 sourceInformation: sourceInformationBuilder.buildIf(node)); |
2533 } | 2534 } |
2534 | 2535 |
2535 void handleIf(ast.Node diagnosticNode, | 2536 void handleIf(ast.Node diagnosticNode, |
2536 {void visitCondition(), | 2537 {void visitCondition(), |
2537 void visitThen(), | 2538 void visitThen(), |
2538 void visitElse(), | 2539 void visitElse(), |
2539 SourceInformation sourceInformation}) { | 2540 SourceInformation sourceInformation}) { |
2540 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, diagnosticNode); | 2541 SsaBranchBuilder branchBuilder = |
| 2542 new SsaBranchBuilder(this, compiler, diagnosticNode); |
2541 branchBuilder.handleIf(visitCondition, visitThen, visitElse, | 2543 branchBuilder.handleIf(visitCondition, visitThen, visitElse, |
2542 sourceInformation: sourceInformation); | 2544 sourceInformation: sourceInformation); |
2543 } | 2545 } |
2544 | 2546 |
2545 @override | 2547 @override |
2546 void visitIfNull(ast.Send node, ast.Node left, ast.Node right, _) { | 2548 void visitIfNull(ast.Send node, ast.Node left, ast.Node right, _) { |
2547 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 2549 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
2548 brancher.handleIfNull(() => visit(left), () => visit(right)); | 2550 brancher.handleIfNull(() => visit(left), () => visit(right)); |
2549 } | 2551 } |
2550 | 2552 |
| 2553 /// Optimizes logical binary where the left is also a logical binary. |
| 2554 /// |
| 2555 /// This method transforms the operator by optimizing the case where [left] is |
| 2556 /// a logical "and" or logical "or". Then it uses [branchBuilder] to build the |
| 2557 /// graph for the optimized expression. |
| 2558 /// |
| 2559 /// For example, `(x && y) && z` is transformed into `x && (y && z)`: |
| 2560 /// |
| 2561 /// t0 = boolify(x); |
| 2562 /// if (t0) { |
| 2563 /// t1 = boolify(y); |
| 2564 /// if (t1) { |
| 2565 /// t2 = boolify(z); |
| 2566 /// } |
| 2567 /// t3 = phi(t2, false); |
| 2568 /// } |
| 2569 /// result = phi(t3, false); |
| 2570 void handleLogicalBinaryWithLeftNode( |
| 2571 ast.Node left, void visitRight(), SsaBranchBuilder branchBuilder, |
| 2572 {bool isAnd}) { |
| 2573 ast.Send send = left.asSend(); |
| 2574 if (send != null && (isAnd ? send.isLogicalAnd : send.isLogicalOr)) { |
| 2575 ast.Node newLeft = send.receiver; |
| 2576 Link<ast.Node> link = send.argumentsNode.nodes; |
| 2577 assert(link.tail.isEmpty); |
| 2578 ast.Node middle = link.head; |
| 2579 handleLogicalBinaryWithLeftNode( |
| 2580 newLeft, |
| 2581 () => handleLogicalBinaryWithLeftNode( |
| 2582 middle, visitRight, branchBuilder, |
| 2583 isAnd: isAnd), |
| 2584 branchBuilder, |
| 2585 isAnd: isAnd); |
| 2586 } else { |
| 2587 branchBuilder.handleLogicalBinary(() => visit(left), visitRight, |
| 2588 isAnd: isAnd); |
| 2589 } |
| 2590 } |
| 2591 |
2551 @override | 2592 @override |
2552 void visitLogicalAnd(ast.Send node, ast.Node left, ast.Node right, _) { | 2593 void visitLogicalAnd(ast.Send node, ast.Node left, ast.Node right, _) { |
2553 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); | 2594 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, compiler, node); |
2554 branchBuilder.handleLogicalAndOrWithLeftNode(left, () { | 2595 handleLogicalBinaryWithLeftNode(left, () => visit(right), branchBuilder, |
2555 visit(right); | 2596 isAnd: true); |
2556 }, isAnd: true); | |
2557 } | 2597 } |
2558 | 2598 |
2559 @override | 2599 @override |
2560 void visitLogicalOr(ast.Send node, ast.Node left, ast.Node right, _) { | 2600 void visitLogicalOr(ast.Send node, ast.Node left, ast.Node right, _) { |
2561 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); | 2601 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, compiler, node); |
2562 branchBuilder.handleLogicalAndOrWithLeftNode(left, () { | 2602 handleLogicalBinaryWithLeftNode(left, () => visit(right), branchBuilder, |
2563 visit(right); | 2603 isAnd: false); |
2564 }, isAnd: false); | |
2565 } | 2604 } |
2566 | 2605 |
2567 @override | 2606 @override |
2568 void visitNot(ast.Send node, ast.Node expression, _) { | 2607 void visitNot(ast.Send node, ast.Node expression, _) { |
2569 assert(node.argumentsNode is ast.Prefix); | 2608 assert(node.argumentsNode is ast.Prefix); |
2570 visit(expression); | 2609 visit(expression); |
2571 SourceInformation sourceInformation = | 2610 SourceInformation sourceInformation = |
2572 sourceInformationBuilder.buildGeneric(node); | 2611 sourceInformationBuilder.buildGeneric(node); |
2573 push(new HNot(popBoolified(), backend.boolType) | 2612 push(new HNot(popBoolified(), backend.boolType) |
2574 ..sourceInformation = sourceInformation); | 2613 ..sourceInformation = sourceInformation); |
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2812 @override | 2851 @override |
2813 void visitIfNotNullDynamicPropertyGet( | 2852 void visitIfNotNullDynamicPropertyGet( |
2814 ast.Send node, ast.Node receiver, Name name, _) { | 2853 ast.Send node, ast.Node receiver, Name name, _) { |
2815 // exp?.x compiled as: | 2854 // exp?.x compiled as: |
2816 // t1 = exp; | 2855 // t1 = exp; |
2817 // result = t1 == null ? t1 : t1.x; | 2856 // result = t1 == null ? t1 : t1.x; |
2818 // This is equivalent to t1 == null ? null : t1.x, but in the current form | 2857 // This is equivalent to t1 == null ? null : t1.x, but in the current form |
2819 // we will be able to later compress it as: | 2858 // we will be able to later compress it as: |
2820 // t1 || t1.x | 2859 // t1 || t1.x |
2821 HInstruction expression; | 2860 HInstruction expression; |
2822 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 2861 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
2823 brancher.handleConditional( | 2862 brancher.handleConditional( |
2824 () { | 2863 () { |
2825 expression = visitAndPop(receiver); | 2864 expression = visitAndPop(receiver); |
2826 pushCheckNull(expression); | 2865 pushCheckNull(expression); |
2827 }, | 2866 }, |
2828 () => stack.add(expression), | 2867 () => stack.add(expression), |
2829 () { | 2868 () { |
2830 generateInstanceGetterWithCompiledReceiver( | 2869 generateInstanceGetterWithCompiledReceiver( |
2831 node, | 2870 node, |
2832 elements.getSelector(node), | 2871 elements.getSelector(node), |
2833 elements.getTypeMask(node), | 2872 elements.getTypeMask(node), |
2834 expression); | 2873 expression); |
2835 }); | 2874 }); |
2836 } | 2875 } |
2837 | 2876 |
2838 /// Pushes a boolean checking [expression] against null. | 2877 @override |
2839 pushCheckNull(HInstruction expression) { | 2878 pushCheckNull(HInstruction expression) { |
2840 push(new HIdentity( | 2879 push(new HIdentity( |
2841 expression, graph.addConstantNull(compiler), null, backend.boolType)); | 2880 expression, graph.addConstantNull(compiler), null, backend.boolType)); |
2842 } | 2881 } |
2843 | 2882 |
2844 @override | 2883 @override |
2845 void visitLocalVariableGet(ast.Send node, LocalVariableElement variable, _) { | 2884 void visitLocalVariableGet(ast.Send node, LocalVariableElement variable, _) { |
2846 handleLocalGet(node, variable); | 2885 handleLocalGet(node, variable); |
2847 } | 2886 } |
2848 | 2887 |
(...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3195 visitDynamicPropertyInvoke(ast.Send node, ast.Node receiver, | 3234 visitDynamicPropertyInvoke(ast.Send node, ast.Node receiver, |
3196 ast.NodeList arguments, Selector selector, _) { | 3235 ast.NodeList arguments, Selector selector, _) { |
3197 generateDynamicSend(node); | 3236 generateDynamicSend(node); |
3198 } | 3237 } |
3199 | 3238 |
3200 @override | 3239 @override |
3201 visitIfNotNullDynamicPropertyInvoke(ast.Send node, ast.Node receiver, | 3240 visitIfNotNullDynamicPropertyInvoke(ast.Send node, ast.Node receiver, |
3202 ast.NodeList arguments, Selector selector, _) { | 3241 ast.NodeList arguments, Selector selector, _) { |
3203 /// Desugar `exp?.m()` to `(t1 = exp) == null ? t1 : t1.m()` | 3242 /// Desugar `exp?.m()` to `(t1 = exp) == null ? t1 : t1.m()` |
3204 HInstruction receiver; | 3243 HInstruction receiver; |
3205 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 3244 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
3206 brancher.handleConditional(() { | 3245 brancher.handleConditional(() { |
3207 receiver = generateInstanceSendReceiver(node); | 3246 receiver = generateInstanceSendReceiver(node); |
3208 pushCheckNull(receiver); | 3247 pushCheckNull(receiver); |
3209 }, () => stack.add(receiver), () => _generateDynamicSend(node, receiver)); | 3248 }, () => stack.add(receiver), () => _generateDynamicSend(node, receiver)); |
3210 } | 3249 } |
3211 | 3250 |
3212 @override | 3251 @override |
3213 visitThisPropertyInvoke( | 3252 visitThisPropertyInvoke( |
3214 ast.Send node, ast.NodeList arguments, Selector selector, _) { | 3253 ast.Send node, ast.NodeList arguments, Selector selector, _) { |
3215 generateDynamicSend(node); | 3254 generateDynamicSend(node); |
(...skipping 1785 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5001 if (Elements.isUnresolved(getter)) { | 5040 if (Elements.isUnresolved(getter)) { |
5002 generateSuperNoSuchMethodSend(node, getterSelector, getterInputs); | 5041 generateSuperNoSuchMethodSend(node, getterSelector, getterInputs); |
5003 getterInstruction = pop(); | 5042 getterInstruction = pop(); |
5004 } else { | 5043 } else { |
5005 getterInstruction = | 5044 getterInstruction = |
5006 buildInvokeSuper(getterSelector, getter, getterInputs); | 5045 buildInvokeSuper(getterSelector, getter, getterInputs); |
5007 add(getterInstruction); | 5046 add(getterInstruction); |
5008 } | 5047 } |
5009 | 5048 |
5010 if (node.isIfNullAssignment) { | 5049 if (node.isIfNullAssignment) { |
5011 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 5050 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
5012 brancher.handleIfNull(() => stack.add(getterInstruction), () { | 5051 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
5013 addDynamicSendArgumentsToList(node, setterInputs); | 5052 addDynamicSendArgumentsToList(node, setterInputs); |
5014 generateSuperSendSet(); | 5053 generateSuperSendSet(); |
5015 stack.add(setterInputs.last); | 5054 stack.add(setterInputs.last); |
5016 }); | 5055 }); |
5017 } else { | 5056 } else { |
5018 handleComplexOperatorSend(node, getterInstruction, arguments); | 5057 handleComplexOperatorSend(node, getterInstruction, arguments); |
5019 setterInputs.add(pop()); | 5058 setterInputs.add(pop()); |
5020 generateSuperSendSet(); | 5059 generateSuperSendSet(); |
5021 stack.add(node.isPostfix ? getterInstruction : setterInputs.last); | 5060 stack.add(node.isPostfix ? getterInstruction : setterInputs.last); |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5321 | 5360 |
5322 pushInvokeDynamic(node, elements.getGetterSelectorInComplexSendSet(node), | 5361 pushInvokeDynamic(node, elements.getGetterSelectorInComplexSendSet(node), |
5323 elements.getGetterTypeMaskInComplexSendSet(node), [receiver, index]); | 5362 elements.getGetterTypeMaskInComplexSendSet(node), [receiver, index]); |
5324 HInstruction getterInstruction = pop(); | 5363 HInstruction getterInstruction = pop(); |
5325 if (node.isIfNullAssignment) { | 5364 if (node.isIfNullAssignment) { |
5326 // Compile x[i] ??= e as: | 5365 // Compile x[i] ??= e as: |
5327 // t1 = x[i] | 5366 // t1 = x[i] |
5328 // if (t1 == null) | 5367 // if (t1 == null) |
5329 // t1 = x[i] = e; | 5368 // t1 = x[i] = e; |
5330 // result = t1 | 5369 // result = t1 |
5331 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 5370 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
5332 brancher.handleIfNull(() => stack.add(getterInstruction), () { | 5371 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
5333 visit(arguments.head); | 5372 visit(arguments.head); |
5334 HInstruction value = pop(); | 5373 HInstruction value = pop(); |
5335 pushInvokeDynamic(node, elements.getSelector(node), | 5374 pushInvokeDynamic(node, elements.getSelector(node), |
5336 elements.getTypeMask(node), [receiver, index, value]); | 5375 elements.getTypeMask(node), [receiver, index, value]); |
5337 pop(); | 5376 pop(); |
5338 stack.add(value); | 5377 stack.add(value); |
5339 }); | 5378 }); |
5340 } else { | 5379 } else { |
5341 handleComplexOperatorSend(node, getterInstruction, arguments); | 5380 handleComplexOperatorSend(node, getterInstruction, arguments); |
(...skipping 27 matching lines...) Expand all Loading... |
5369 void visitIfNotNullDynamicPropertySet( | 5408 void visitIfNotNullDynamicPropertySet( |
5370 ast.SendSet node, ast.Node receiver, Name name, ast.Node rhs, _) { | 5409 ast.SendSet node, ast.Node receiver, Name name, ast.Node rhs, _) { |
5371 // compile e?.x = e2 to: | 5410 // compile e?.x = e2 to: |
5372 // | 5411 // |
5373 // t1 = e | 5412 // t1 = e |
5374 // if (t1 == null) | 5413 // if (t1 == null) |
5375 // result = t1 // same as result = null | 5414 // result = t1 // same as result = null |
5376 // else | 5415 // else |
5377 // result = e.x = e2 | 5416 // result = e.x = e2 |
5378 HInstruction receiverInstruction; | 5417 HInstruction receiverInstruction; |
5379 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 5418 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
5380 brancher.handleConditional( | 5419 brancher.handleConditional( |
5381 () { | 5420 () { |
5382 receiverInstruction = generateInstanceSendReceiver(node); | 5421 receiverInstruction = generateInstanceSendReceiver(node); |
5383 pushCheckNull(receiverInstruction); | 5422 pushCheckNull(receiverInstruction); |
5384 }, | 5423 }, |
5385 () => stack.add(receiverInstruction), | 5424 () => stack.add(receiverInstruction), |
5386 () { | 5425 () { |
5387 generateInstanceSetterWithCompiledReceiver( | 5426 generateInstanceSetterWithCompiledReceiver( |
5388 node, receiverInstruction, visitAndPop(rhs)); | 5427 node, receiverInstruction, visitAndPop(rhs)); |
5389 }); | 5428 }); |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5542 if (Elements.isInstanceSend(node, elements)) { | 5581 if (Elements.isInstanceSend(node, elements)) { |
5543 void generateAssignment(HInstruction receiver) { | 5582 void generateAssignment(HInstruction receiver) { |
5544 // desugars `e.x op= e2` to `e.x = e.x op e2` | 5583 // desugars `e.x op= e2` to `e.x = e.x op e2` |
5545 generateInstanceGetterWithCompiledReceiver( | 5584 generateInstanceGetterWithCompiledReceiver( |
5546 node, | 5585 node, |
5547 elements.getGetterSelectorInComplexSendSet(node), | 5586 elements.getGetterSelectorInComplexSendSet(node), |
5548 elements.getGetterTypeMaskInComplexSendSet(node), | 5587 elements.getGetterTypeMaskInComplexSendSet(node), |
5549 receiver); | 5588 receiver); |
5550 HInstruction getterInstruction = pop(); | 5589 HInstruction getterInstruction = pop(); |
5551 if (node.isIfNullAssignment) { | 5590 if (node.isIfNullAssignment) { |
5552 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 5591 SsaBranchBuilder brancher = |
| 5592 new SsaBranchBuilder(this, compiler, node); |
5553 brancher.handleIfNull(() => stack.add(getterInstruction), () { | 5593 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
5554 visit(node.arguments.head); | 5594 visit(node.arguments.head); |
5555 generateInstanceSetterWithCompiledReceiver(node, receiver, pop()); | 5595 generateInstanceSetterWithCompiledReceiver(node, receiver, pop()); |
5556 }); | 5596 }); |
5557 } else { | 5597 } else { |
5558 handleComplexOperatorSend(node, getterInstruction, node.arguments); | 5598 handleComplexOperatorSend(node, getterInstruction, node.arguments); |
5559 HInstruction value = pop(); | 5599 HInstruction value = pop(); |
5560 generateInstanceSetterWithCompiledReceiver(node, receiver, value); | 5600 generateInstanceSetterWithCompiledReceiver(node, receiver, value); |
5561 } | 5601 } |
5562 if (node.isPostfix) { | 5602 if (node.isPostfix) { |
5563 pop(); | 5603 pop(); |
5564 stack.add(getterInstruction); | 5604 stack.add(getterInstruction); |
5565 } | 5605 } |
5566 } | 5606 } |
5567 | 5607 |
5568 if (node.isConditional) { | 5608 if (node.isConditional) { |
5569 // generate `e?.x op= e2` as: | 5609 // generate `e?.x op= e2` as: |
5570 // t1 = e | 5610 // t1 = e |
5571 // t1 == null ? t1 : (t1.x = t1.x op e2); | 5611 // t1 == null ? t1 : (t1.x = t1.x op e2); |
5572 HInstruction receiver; | 5612 HInstruction receiver; |
5573 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 5613 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
5574 brancher.handleConditional(() { | 5614 brancher.handleConditional(() { |
5575 receiver = generateInstanceSendReceiver(node); | 5615 receiver = generateInstanceSendReceiver(node); |
5576 pushCheckNull(receiver); | 5616 pushCheckNull(receiver); |
5577 }, () => stack.add(receiver), () => generateAssignment(receiver)); | 5617 }, () => stack.add(receiver), () => generateAssignment(receiver)); |
5578 } else { | 5618 } else { |
5579 generateAssignment(generateInstanceSendReceiver(node)); | 5619 generateAssignment(generateInstanceSendReceiver(node)); |
5580 } | 5620 } |
5581 return; | 5621 return; |
5582 } | 5622 } |
5583 | 5623 |
5584 if (getter.isMalformed) { | 5624 if (getter.isMalformed) { |
5585 generateStaticUnresolvedGet(node, getter); | 5625 generateStaticUnresolvedGet(node, getter); |
5586 } else if (getter.isField) { | 5626 } else if (getter.isField) { |
5587 generateStaticFieldGet(node, getter); | 5627 generateStaticFieldGet(node, getter); |
5588 } else if (getter.isGetter) { | 5628 } else if (getter.isGetter) { |
5589 generateStaticGetterGet(node, getter); | 5629 generateStaticGetterGet(node, getter); |
5590 } else if (getter.isFunction) { | 5630 } else if (getter.isFunction) { |
5591 generateStaticFunctionGet(node, getter); | 5631 generateStaticFunctionGet(node, getter); |
5592 } else if (getter.isLocal) { | 5632 } else if (getter.isLocal) { |
5593 handleLocalGet(node, getter); | 5633 handleLocalGet(node, getter); |
5594 } else { | 5634 } else { |
5595 internalError(node, "Unexpected getter: $getter"); | 5635 internalError(node, "Unexpected getter: $getter"); |
5596 } | 5636 } |
5597 HInstruction getterInstruction = pop(); | 5637 HInstruction getterInstruction = pop(); |
5598 if (node.isIfNullAssignment) { | 5638 if (node.isIfNullAssignment) { |
5599 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 5639 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
5600 brancher.handleIfNull(() => stack.add(getterInstruction), () { | 5640 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
5601 visit(node.arguments.head); | 5641 visit(node.arguments.head); |
5602 generateNonInstanceSetter(node, element, pop()); | 5642 generateNonInstanceSetter(node, element, pop()); |
5603 }); | 5643 }); |
5604 } else { | 5644 } else { |
5605 handleComplexOperatorSend(node, getterInstruction, node.arguments); | 5645 handleComplexOperatorSend(node, getterInstruction, node.arguments); |
5606 HInstruction value = pop(); | 5646 HInstruction value = pop(); |
5607 generateNonInstanceSetter(node, element, value); | 5647 generateNonInstanceSetter(node, element, value); |
5608 } | 5648 } |
5609 if (node.isPostfix) { | 5649 if (node.isPostfix) { |
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5999 instruction = setRtiIfNeeded(instruction, node); | 6039 instruction = setRtiIfNeeded(instruction, node); |
6000 } | 6040 } |
6001 | 6041 |
6002 TypeMask type = | 6042 TypeMask type = |
6003 TypeMaskFactory.inferredForNode(sourceElement, node, compiler); | 6043 TypeMaskFactory.inferredForNode(sourceElement, node, compiler); |
6004 if (!type.containsAll(compiler.world)) instruction.instructionType = type; | 6044 if (!type.containsAll(compiler.world)) instruction.instructionType = type; |
6005 stack.add(instruction); | 6045 stack.add(instruction); |
6006 } | 6046 } |
6007 | 6047 |
6008 visitConditional(ast.Conditional node) { | 6048 visitConditional(ast.Conditional node) { |
6009 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 6049 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
6010 brancher.handleConditional(() => visit(node.condition), | 6050 brancher.handleConditional(() => visit(node.condition), |
6011 () => visit(node.thenExpression), () => visit(node.elseExpression)); | 6051 () => visit(node.thenExpression), () => visit(node.elseExpression)); |
6012 } | 6052 } |
6013 | 6053 |
6014 visitStringInterpolation(ast.StringInterpolation node) { | 6054 visitStringInterpolation(ast.StringInterpolation node) { |
6015 StringBuilderVisitor stringBuilder = new StringBuilderVisitor(this, node); | 6055 StringBuilderVisitor stringBuilder = new StringBuilderVisitor(this, node); |
6016 stringBuilder.visit(node); | 6056 stringBuilder.visit(node); |
6017 stack.add(stringBuilder.result); | 6057 stack.add(stringBuilder.result); |
6018 } | 6058 } |
6019 | 6059 |
(...skipping 1451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7471 this.oldReturnLocal, | 7511 this.oldReturnLocal, |
7472 this.oldReturnType, | 7512 this.oldReturnType, |
7473 this.oldResolvedAst, | 7513 this.oldResolvedAst, |
7474 this.oldStack, | 7514 this.oldStack, |
7475 this.oldLocalsHandler, | 7515 this.oldLocalsHandler, |
7476 this.inTryStatement, | 7516 this.inTryStatement, |
7477 this.allFunctionsCalledOnce) | 7517 this.allFunctionsCalledOnce) |
7478 : super(function); | 7518 : super(function); |
7479 } | 7519 } |
7480 | 7520 |
7481 class SsaBranch { | |
7482 final SsaBranchBuilder branchBuilder; | |
7483 final HBasicBlock block; | |
7484 LocalsHandler startLocals; | |
7485 LocalsHandler exitLocals; | |
7486 SubGraph graph; | |
7487 | |
7488 SsaBranch(this.branchBuilder) : block = new HBasicBlock(); | |
7489 } | |
7490 | |
7491 class SsaBranchBuilder { | |
7492 final SsaBuilder builder; | |
7493 final ast.Node diagnosticNode; | |
7494 | |
7495 SsaBranchBuilder(this.builder, [this.diagnosticNode]); | |
7496 | |
7497 Compiler get compiler => builder.compiler; | |
7498 | |
7499 void checkNotAborted() { | |
7500 if (builder.isAborted()) { | |
7501 compiler.unimplemented(diagnosticNode, "aborted control flow"); | |
7502 } | |
7503 } | |
7504 | |
7505 void buildCondition( | |
7506 void visitCondition(), | |
7507 SsaBranch conditionBranch, | |
7508 SsaBranch thenBranch, | |
7509 SsaBranch elseBranch, | |
7510 SourceInformation sourceInformation) { | |
7511 startBranch(conditionBranch); | |
7512 visitCondition(); | |
7513 checkNotAborted(); | |
7514 assert(identical(builder.current, builder.lastOpenedBlock)); | |
7515 HInstruction conditionValue = builder.popBoolified(); | |
7516 HIf branch = new HIf(conditionValue)..sourceInformation = sourceInformation; | |
7517 HBasicBlock conditionExitBlock = builder.current; | |
7518 builder.close(branch); | |
7519 conditionBranch.exitLocals = builder.localsHandler; | |
7520 conditionExitBlock.addSuccessor(thenBranch.block); | |
7521 conditionExitBlock.addSuccessor(elseBranch.block); | |
7522 bool conditionBranchLocalsCanBeReused = | |
7523 mergeLocals(conditionBranch, thenBranch, mayReuseFromLocals: true); | |
7524 mergeLocals(conditionBranch, elseBranch, | |
7525 mayReuseFromLocals: conditionBranchLocalsCanBeReused); | |
7526 | |
7527 conditionBranch.graph = | |
7528 new SubExpression(conditionBranch.block, conditionExitBlock); | |
7529 } | |
7530 | |
7531 /** | |
7532 * Returns true if the locals of the [fromBranch] may be reused. A [:true:] | |
7533 * return value implies that [mayReuseFromLocals] was set to [:true:]. | |
7534 */ | |
7535 bool mergeLocals(SsaBranch fromBranch, SsaBranch toBranch, | |
7536 {bool mayReuseFromLocals}) { | |
7537 LocalsHandler fromLocals = fromBranch.exitLocals; | |
7538 if (toBranch.startLocals == null) { | |
7539 if (mayReuseFromLocals) { | |
7540 toBranch.startLocals = fromLocals; | |
7541 return false; | |
7542 } else { | |
7543 toBranch.startLocals = new LocalsHandler.from(fromLocals); | |
7544 return true; | |
7545 } | |
7546 } else { | |
7547 toBranch.startLocals.mergeWith(fromLocals, toBranch.block); | |
7548 return true; | |
7549 } | |
7550 } | |
7551 | |
7552 void startBranch(SsaBranch branch) { | |
7553 builder.graph.addBlock(branch.block); | |
7554 builder.localsHandler = branch.startLocals; | |
7555 builder.open(branch.block); | |
7556 } | |
7557 | |
7558 HInstruction buildBranch(SsaBranch branch, void visitBranch(), | |
7559 SsaBranch joinBranch, bool isExpression) { | |
7560 startBranch(branch); | |
7561 visitBranch(); | |
7562 branch.graph = new SubGraph(branch.block, builder.lastOpenedBlock); | |
7563 branch.exitLocals = builder.localsHandler; | |
7564 if (!builder.isAborted()) { | |
7565 builder.goto(builder.current, joinBranch.block); | |
7566 mergeLocals(branch, joinBranch, mayReuseFromLocals: true); | |
7567 } | |
7568 if (isExpression) { | |
7569 checkNotAborted(); | |
7570 return builder.pop(); | |
7571 } | |
7572 return null; | |
7573 } | |
7574 | |
7575 handleIf(void visitCondition(), void visitThen(), void visitElse(), | |
7576 {SourceInformation sourceInformation}) { | |
7577 if (visitElse == null) { | |
7578 // Make sure to have an else part to avoid a critical edge. A | |
7579 // critical edge is an edge that connects a block with multiple | |
7580 // successors to a block with multiple predecessors. We avoid | |
7581 // such edges because they prevent inserting copies during code | |
7582 // generation of phi instructions. | |
7583 visitElse = () {}; | |
7584 } | |
7585 | |
7586 _handleDiamondBranch(visitCondition, visitThen, visitElse, | |
7587 isExpression: false, sourceInformation: sourceInformation); | |
7588 } | |
7589 | |
7590 handleConditional(void visitCondition(), void visitThen(), void visitElse()) { | |
7591 assert(visitElse != null); | |
7592 _handleDiamondBranch(visitCondition, visitThen, visitElse, | |
7593 isExpression: true); | |
7594 } | |
7595 | |
7596 handleIfNull(void left(), void right()) { | |
7597 // x ?? y is transformed into: x == null ? y : x | |
7598 HInstruction leftExpression; | |
7599 handleConditional(() { | |
7600 left(); | |
7601 leftExpression = builder.pop(); | |
7602 builder.pushCheckNull(leftExpression); | |
7603 }, right, () => builder.stack.add(leftExpression)); | |
7604 } | |
7605 | |
7606 void handleLogicalAndOr(void left(), void right(), {bool isAnd}) { | |
7607 // x && y is transformed into: | |
7608 // t0 = boolify(x); | |
7609 // if (t0) { | |
7610 // t1 = boolify(y); | |
7611 // } | |
7612 // result = phi(t1, false); | |
7613 // | |
7614 // x || y is transformed into: | |
7615 // t0 = boolify(x); | |
7616 // if (not(t0)) { | |
7617 // t1 = boolify(y); | |
7618 // } | |
7619 // result = phi(t1, true); | |
7620 HInstruction boolifiedLeft; | |
7621 HInstruction boolifiedRight; | |
7622 | |
7623 void visitCondition() { | |
7624 left(); | |
7625 boolifiedLeft = builder.popBoolified(); | |
7626 builder.stack.add(boolifiedLeft); | |
7627 if (!isAnd) { | |
7628 builder.push(new HNot(builder.pop(), builder.backend.boolType)); | |
7629 } | |
7630 } | |
7631 | |
7632 void visitThen() { | |
7633 right(); | |
7634 boolifiedRight = builder.popBoolified(); | |
7635 } | |
7636 | |
7637 handleIf(visitCondition, visitThen, null); | |
7638 HConstant notIsAnd = | |
7639 builder.graph.addConstantBool(!isAnd, builder.compiler); | |
7640 JavaScriptBackend backend = builder.backend; | |
7641 HPhi result = new HPhi.manyInputs( | |
7642 null, <HInstruction>[boolifiedRight, notIsAnd], backend.dynamicType); | |
7643 builder.current.addPhi(result); | |
7644 builder.stack.add(result); | |
7645 } | |
7646 | |
7647 void handleLogicalAndOrWithLeftNode(ast.Node left, void visitRight(), | |
7648 {bool isAnd}) { | |
7649 // This method is similar to [handleLogicalAndOr] but optimizes the case | |
7650 // where left is a logical "and" or logical "or". | |
7651 // | |
7652 // For example (x && y) && z is transformed into x && (y && z): | |
7653 // t0 = boolify(x); | |
7654 // if (t0) { | |
7655 // t1 = boolify(y); | |
7656 // if (t1) { | |
7657 // t2 = boolify(z); | |
7658 // } | |
7659 // t3 = phi(t2, false); | |
7660 // } | |
7661 // result = phi(t3, false); | |
7662 | |
7663 ast.Send send = left.asSend(); | |
7664 if (send != null && (isAnd ? send.isLogicalAnd : send.isLogicalOr)) { | |
7665 ast.Node newLeft = send.receiver; | |
7666 Link<ast.Node> link = send.argumentsNode.nodes; | |
7667 assert(link.tail.isEmpty); | |
7668 ast.Node middle = link.head; | |
7669 handleLogicalAndOrWithLeftNode( | |
7670 newLeft, | |
7671 () => | |
7672 handleLogicalAndOrWithLeftNode(middle, visitRight, isAnd: isAnd), | |
7673 isAnd: isAnd); | |
7674 } else { | |
7675 handleLogicalAndOr(() => builder.visit(left), visitRight, isAnd: isAnd); | |
7676 } | |
7677 } | |
7678 | |
7679 void _handleDiamondBranch( | |
7680 void visitCondition(), void visitThen(), void visitElse(), | |
7681 {bool isExpression, SourceInformation sourceInformation}) { | |
7682 SsaBranch conditionBranch = new SsaBranch(this); | |
7683 SsaBranch thenBranch = new SsaBranch(this); | |
7684 SsaBranch elseBranch = new SsaBranch(this); | |
7685 SsaBranch joinBranch = new SsaBranch(this); | |
7686 | |
7687 conditionBranch.startLocals = builder.localsHandler; | |
7688 builder.goto(builder.current, conditionBranch.block); | |
7689 | |
7690 buildCondition(visitCondition, conditionBranch, thenBranch, elseBranch, | |
7691 sourceInformation); | |
7692 HInstruction thenValue = | |
7693 buildBranch(thenBranch, visitThen, joinBranch, isExpression); | |
7694 HInstruction elseValue = | |
7695 buildBranch(elseBranch, visitElse, joinBranch, isExpression); | |
7696 | |
7697 if (isExpression) { | |
7698 assert(thenValue != null && elseValue != null); | |
7699 JavaScriptBackend backend = builder.backend; | |
7700 HPhi phi = new HPhi.manyInputs( | |
7701 null, <HInstruction>[thenValue, elseValue], backend.dynamicType); | |
7702 joinBranch.block.addPhi(phi); | |
7703 builder.stack.add(phi); | |
7704 } | |
7705 | |
7706 HBasicBlock joinBlock; | |
7707 // If at least one branch did not abort, open the joinBranch. | |
7708 if (!joinBranch.block.predecessors.isEmpty) { | |
7709 startBranch(joinBranch); | |
7710 joinBlock = joinBranch.block; | |
7711 } | |
7712 | |
7713 HIfBlockInformation info = new HIfBlockInformation( | |
7714 new HSubExpressionBlockInformation(conditionBranch.graph), | |
7715 new HSubGraphBlockInformation(thenBranch.graph), | |
7716 new HSubGraphBlockInformation(elseBranch.graph)); | |
7717 | |
7718 HBasicBlock conditionStartBlock = conditionBranch.block; | |
7719 conditionStartBlock.setBlockFlow(info, joinBlock); | |
7720 SubGraph conditionGraph = conditionBranch.graph; | |
7721 HIf branch = conditionGraph.end.last; | |
7722 assert(branch is HIf); | |
7723 branch.blockInformation = conditionStartBlock.blockFlow; | |
7724 } | |
7725 } | |
7726 | |
7727 class TypeBuilder implements DartTypeVisitor<dynamic, SsaBuilder> { | 7521 class TypeBuilder implements DartTypeVisitor<dynamic, SsaBuilder> { |
7728 final ClassWorld classWorld; | 7522 final ClassWorld classWorld; |
7729 | 7523 |
7730 TypeBuilder(this.classWorld); | 7524 TypeBuilder(this.classWorld); |
7731 | 7525 |
7732 void visit(DartType type, SsaBuilder builder) => type.accept(this, builder); | 7526 void visit(DartType type, SsaBuilder builder) => type.accept(this, builder); |
7733 | 7527 |
7734 void visitVoidType(VoidType type, SsaBuilder builder) { | 7528 void visitVoidType(VoidType type, SsaBuilder builder) { |
7735 ClassElement cls = builder.backend.helpers.VoidRuntimeType; | 7529 ClassElement cls = builder.backend.helpers.VoidRuntimeType; |
7736 builder.push(new HVoidType(type, new TypeMask.exact(cls, classWorld))); | 7530 builder.push(new HVoidType(type, new TypeMask.exact(cls, classWorld))); |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7823 const _LoopTypeVisitor(); | 7617 const _LoopTypeVisitor(); |
7824 int visitNode(ast.Node node) => HLoopBlockInformation.NOT_A_LOOP; | 7618 int visitNode(ast.Node node) => HLoopBlockInformation.NOT_A_LOOP; |
7825 int visitWhile(ast.While node) => HLoopBlockInformation.WHILE_LOOP; | 7619 int visitWhile(ast.While node) => HLoopBlockInformation.WHILE_LOOP; |
7826 int visitFor(ast.For node) => HLoopBlockInformation.FOR_LOOP; | 7620 int visitFor(ast.For node) => HLoopBlockInformation.FOR_LOOP; |
7827 int visitDoWhile(ast.DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP; | 7621 int visitDoWhile(ast.DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP; |
7828 int visitAsyncForIn(ast.AsyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; | 7622 int visitAsyncForIn(ast.AsyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; |
7829 int visitSyncForIn(ast.SyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; | 7623 int visitSyncForIn(ast.SyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; |
7830 int visitSwitchStatement(ast.SwitchStatement node) => | 7624 int visitSwitchStatement(ast.SwitchStatement node) => |
7831 HLoopBlockInformation.SWITCH_CONTINUE_LOOP; | 7625 HLoopBlockInformation.SWITCH_CONTINUE_LOOP; |
7832 } | 7626 } |
OLD | NEW |