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:compiler/src/ssa/ssa_branch_builder.dart'; | |
7 import 'package:js_runtime/shared/embedded_names.dart'; | 8 import 'package:js_runtime/shared/embedded_names.dart'; |
8 | 9 |
9 import '../closure.dart'; | 10 import '../closure.dart'; |
10 import '../common.dart'; | 11 import '../common.dart'; |
11 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; | 12 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
12 import '../common/names.dart' show Identifiers, Selectors; | 13 import '../common/names.dart' show Identifiers, Selectors; |
13 import '../common/tasks.dart' show CompilerTask; | 14 import '../common/tasks.dart' show CompilerTask; |
14 import '../compiler.dart' show Compiler; | 15 import '../compiler.dart' show Compiler; |
15 import '../constants/constant_system.dart'; | 16 import '../constants/constant_system.dart'; |
16 import '../constants/expressions.dart'; | 17 import '../constants/expressions.dart'; |
(...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
404 * account. | 405 * account. |
405 */ | 406 */ |
406 int loopNesting = 0; | 407 int loopNesting = 0; |
407 | 408 |
408 /** | 409 /** |
409 * This stack contains declaration elements of the functions being built | 410 * This stack contains declaration elements of the functions being built |
410 * or inlined by this builder. | 411 * or inlined by this builder. |
411 */ | 412 */ |
412 final List<Element> sourceElementStack = <Element>[]; | 413 final List<Element> sourceElementStack = <Element>[]; |
413 | 414 |
414 LocalsHandler localsHandler; | |
415 | |
416 HInstruction rethrowableException; | 415 HInstruction rethrowableException; |
417 | 416 |
418 Map<JumpTarget, JumpHandler> jumpTargets = <JumpTarget, JumpHandler>{}; | 417 Map<JumpTarget, JumpHandler> jumpTargets = <JumpTarget, JumpHandler>{}; |
419 | 418 |
420 /// Returns `true` if the current element is an `async` function. | 419 /// Returns `true` if the current element is an `async` function. |
421 bool get isBuildingAsyncFunction { | 420 bool get isBuildingAsyncFunction { |
422 Element element = sourceElement; | 421 Element element = sourceElement; |
423 return (element is FunctionElement && | 422 return (element is FunctionElement && |
424 element.asyncMarker == AsyncMarker.ASYNC); | 423 element.asyncMarker == AsyncMarker.ASYNC); |
425 } | 424 } |
(...skipping 1474 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1900 // TODO(kasperl): Make this goto an implicit return. | 1899 // TODO(kasperl): Make this goto an implicit return. |
1901 if (!isAborted()) closeAndGotoExit(new HGoto()); | 1900 if (!isAborted()) closeAndGotoExit(new HGoto()); |
1902 graph.finalize(); | 1901 graph.finalize(); |
1903 return graph; | 1902 return graph; |
1904 } | 1903 } |
1905 | 1904 |
1906 void pushWithPosition(HInstruction instruction, ast.Node node) { | 1905 void pushWithPosition(HInstruction instruction, ast.Node node) { |
1907 push(attachPosition(instruction, node)); | 1906 push(attachPosition(instruction, node)); |
1908 } | 1907 } |
1909 | 1908 |
1910 HInstruction popBoolified() { | 1909 @override |
1910 HBoolify popBoolified() { | |
1911 HInstruction value = pop(); | 1911 HInstruction value = pop(); |
1912 if (_checkOrTrustTypes) { | 1912 if (_checkOrTrustTypes) { |
1913 return potentiallyCheckOrTrustType(value, compiler.coreTypes.boolType, | 1913 return potentiallyCheckOrTrustType(value, compiler.coreTypes.boolType, |
1914 kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK); | 1914 kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK); |
1915 } | 1915 } |
1916 HInstruction result = new HBoolify(value, backend.boolType); | 1916 HInstruction result = new HBoolify(value, backend.boolType); |
1917 add(result); | 1917 add(result); |
1918 return result; | 1918 return result; |
1919 } | 1919 } |
1920 | 1920 |
(...skipping 609 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2530 visitThen: () => visit(node.thenPart), | 2530 visitThen: () => visit(node.thenPart), |
2531 visitElse: node.elsePart != null ? () => visit(node.elsePart) : null, | 2531 visitElse: node.elsePart != null ? () => visit(node.elsePart) : null, |
2532 sourceInformation: sourceInformationBuilder.buildIf(node)); | 2532 sourceInformation: sourceInformationBuilder.buildIf(node)); |
2533 } | 2533 } |
2534 | 2534 |
2535 void handleIf(ast.Node diagnosticNode, | 2535 void handleIf(ast.Node diagnosticNode, |
2536 {void visitCondition(), | 2536 {void visitCondition(), |
2537 void visitThen(), | 2537 void visitThen(), |
2538 void visitElse(), | 2538 void visitElse(), |
2539 SourceInformation sourceInformation}) { | 2539 SourceInformation sourceInformation}) { |
2540 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, diagnosticNode); | 2540 SsaBranchBuilder branchBuilder = |
2541 new SsaBranchBuilder(this, compiler, diagnosticNode); | |
2541 branchBuilder.handleIf(visitCondition, visitThen, visitElse, | 2542 branchBuilder.handleIf(visitCondition, visitThen, visitElse, |
2542 sourceInformation: sourceInformation); | 2543 sourceInformation: sourceInformation); |
2543 } | 2544 } |
2544 | 2545 |
2545 @override | 2546 @override |
2546 void visitIfNull(ast.Send node, ast.Node left, ast.Node right, _) { | 2547 void visitIfNull(ast.Send node, ast.Node left, ast.Node right, _) { |
2547 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 2548 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
2548 brancher.handleIfNull(() => visit(left), () => visit(right)); | 2549 brancher.handleIfNull(() => visit(left), () => visit(right)); |
2549 } | 2550 } |
2550 | 2551 |
2551 @override | 2552 @override |
2552 void visitLogicalAnd(ast.Send node, ast.Node left, ast.Node right, _) { | 2553 void visitLogicalAnd(ast.Send node, ast.Node left, ast.Node right, _) { |
2553 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); | 2554 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, compiler, node); |
2554 branchBuilder.handleLogicalAndOrWithLeftNode(left, () { | 2555 |
2555 visit(right); | 2556 // This method is similar to [SsaBranchBuilder.handleLogicalAndOr] but |
2556 }, isAnd: true); | 2557 // optimizes the case where left is a logical "and". |
2558 // | |
2559 // For example (x && y) && z is transformed into x && (y && z): | |
2560 // t0 = boolify(x); | |
2561 // if (t0) { | |
2562 // t1 = boolify(y); | |
2563 // if (t1) { | |
2564 // t2 = boolify(z); | |
2565 // } | |
2566 // t3 = phi(t2, false); | |
2567 // } | |
2568 // result = phi(t3, false); | |
2569 void handleLogicalAndWithLeftNode(ast.Node left, void visitRight()) { | |
2570 ast.Send send = left.asSend(); | |
2571 if (send != null && send.isLogicalAnd) { | |
2572 ast.Node newLeft = send.receiver; | |
2573 Link<ast.Node> link = send.argumentsNode.nodes; | |
2574 assert(link.tail.isEmpty); | |
2575 ast.Node middle = link.head; | |
2576 handleLogicalAndWithLeftNode( | |
2577 newLeft, () => handleLogicalAndWithLeftNode(middle, visitRight)); | |
2578 } else { | |
2579 branchBuilder.handleLogicalAndOr(() => visit(left), visitRight, | |
2580 isAnd: true); | |
2581 } | |
2582 } | |
2583 | |
2584 handleLogicalAndWithLeftNode(left, () => visit(right)); | |
2557 } | 2585 } |
2558 | 2586 |
2559 @override | 2587 @override |
2560 void visitLogicalOr(ast.Send node, ast.Node left, ast.Node right, _) { | 2588 void visitLogicalOr(ast.Send node, ast.Node left, ast.Node right, _) { |
2561 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); | 2589 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, compiler, node); |
2562 branchBuilder.handleLogicalAndOrWithLeftNode(left, () { | 2590 |
2563 visit(right); | 2591 // This method is similar to [SsaBranchBuilder.handleLogicalAndOr] but |
2564 }, isAnd: false); | 2592 // optimizes the case where left is a logical "or". |
2593 void handleLogicalOrWithLeftNode(ast.Node left, void visitRight()) { | |
Siggi Cherem (dart-lang)
2016/09/01 23:51:21
what if we keep the handleLogicalAndOrWithLeftNode
Harry Terkelsen
2016/09/02 17:52:27
Done.
| |
2594 ast.Send send = left.asSend(); | |
2595 if (send != null && send.isLogicalOr) { | |
2596 ast.Node newLeft = send.receiver; | |
2597 Link<ast.Node> link = send.argumentsNode.nodes; | |
2598 assert(link.tail.isEmpty); | |
2599 ast.Node middle = link.head; | |
2600 handleLogicalOrWithLeftNode( | |
2601 newLeft, () => handleLogicalOrWithLeftNode(middle, visitRight)); | |
2602 } else { | |
2603 branchBuilder.handleLogicalAndOr(() => visit(left), visitRight, | |
2604 isAnd: true); | |
Siggi Cherem (dart-lang)
2016/09/01 23:51:21
shouldn't this be "false"?
Harry Terkelsen
2016/09/02 17:52:27
oops! good catch
| |
2605 } | |
2606 } | |
2607 | |
2608 handleLogicalOrWithLeftNode(left, () => visit(right)); | |
2565 } | 2609 } |
2566 | 2610 |
2567 @override | 2611 @override |
2568 void visitNot(ast.Send node, ast.Node expression, _) { | 2612 void visitNot(ast.Send node, ast.Node expression, _) { |
2569 assert(node.argumentsNode is ast.Prefix); | 2613 assert(node.argumentsNode is ast.Prefix); |
2570 visit(expression); | 2614 visit(expression); |
2571 SourceInformation sourceInformation = | 2615 SourceInformation sourceInformation = |
2572 sourceInformationBuilder.buildGeneric(node); | 2616 sourceInformationBuilder.buildGeneric(node); |
2573 push(new HNot(popBoolified(), backend.boolType) | 2617 push(new HNot(popBoolified(), backend.boolType) |
2574 ..sourceInformation = sourceInformation); | 2618 ..sourceInformation = sourceInformation); |
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2812 @override | 2856 @override |
2813 void visitIfNotNullDynamicPropertyGet( | 2857 void visitIfNotNullDynamicPropertyGet( |
2814 ast.Send node, ast.Node receiver, Name name, _) { | 2858 ast.Send node, ast.Node receiver, Name name, _) { |
2815 // exp?.x compiled as: | 2859 // exp?.x compiled as: |
2816 // t1 = exp; | 2860 // t1 = exp; |
2817 // result = t1 == null ? t1 : t1.x; | 2861 // result = t1 == null ? t1 : t1.x; |
2818 // This is equivalent to t1 == null ? null : t1.x, but in the current form | 2862 // This is equivalent to t1 == null ? null : t1.x, but in the current form |
2819 // we will be able to later compress it as: | 2863 // we will be able to later compress it as: |
2820 // t1 || t1.x | 2864 // t1 || t1.x |
2821 HInstruction expression; | 2865 HInstruction expression; |
2822 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 2866 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
2823 brancher.handleConditional( | 2867 brancher.handleConditional( |
2824 () { | 2868 () { |
2825 expression = visitAndPop(receiver); | 2869 expression = visitAndPop(receiver); |
2826 pushCheckNull(expression); | 2870 pushCheckNull(expression); |
2827 }, | 2871 }, |
2828 () => stack.add(expression), | 2872 () => stack.add(expression), |
2829 () { | 2873 () { |
2830 generateInstanceGetterWithCompiledReceiver( | 2874 generateInstanceGetterWithCompiledReceiver( |
2831 node, | 2875 node, |
2832 elements.getSelector(node), | 2876 elements.getSelector(node), |
2833 elements.getTypeMask(node), | 2877 elements.getTypeMask(node), |
2834 expression); | 2878 expression); |
2835 }); | 2879 }); |
2836 } | 2880 } |
2837 | 2881 |
2838 /// Pushes a boolean checking [expression] against null. | 2882 @override |
2839 pushCheckNull(HInstruction expression) { | 2883 pushCheckNull(HInstruction expression) { |
2840 push(new HIdentity( | 2884 push(new HIdentity( |
2841 expression, graph.addConstantNull(compiler), null, backend.boolType)); | 2885 expression, graph.addConstantNull(compiler), null, backend.boolType)); |
2842 } | 2886 } |
2843 | 2887 |
2844 @override | 2888 @override |
2845 void visitLocalVariableGet(ast.Send node, LocalVariableElement variable, _) { | 2889 void visitLocalVariableGet(ast.Send node, LocalVariableElement variable, _) { |
2846 handleLocalGet(node, variable); | 2890 handleLocalGet(node, variable); |
2847 } | 2891 } |
2848 | 2892 |
(...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3195 visitDynamicPropertyInvoke(ast.Send node, ast.Node receiver, | 3239 visitDynamicPropertyInvoke(ast.Send node, ast.Node receiver, |
3196 ast.NodeList arguments, Selector selector, _) { | 3240 ast.NodeList arguments, Selector selector, _) { |
3197 generateDynamicSend(node); | 3241 generateDynamicSend(node); |
3198 } | 3242 } |
3199 | 3243 |
3200 @override | 3244 @override |
3201 visitIfNotNullDynamicPropertyInvoke(ast.Send node, ast.Node receiver, | 3245 visitIfNotNullDynamicPropertyInvoke(ast.Send node, ast.Node receiver, |
3202 ast.NodeList arguments, Selector selector, _) { | 3246 ast.NodeList arguments, Selector selector, _) { |
3203 /// Desugar `exp?.m()` to `(t1 = exp) == null ? t1 : t1.m()` | 3247 /// Desugar `exp?.m()` to `(t1 = exp) == null ? t1 : t1.m()` |
3204 HInstruction receiver; | 3248 HInstruction receiver; |
3205 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 3249 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
3206 brancher.handleConditional(() { | 3250 brancher.handleConditional(() { |
3207 receiver = generateInstanceSendReceiver(node); | 3251 receiver = generateInstanceSendReceiver(node); |
3208 pushCheckNull(receiver); | 3252 pushCheckNull(receiver); |
3209 }, () => stack.add(receiver), () => _generateDynamicSend(node, receiver)); | 3253 }, () => stack.add(receiver), () => _generateDynamicSend(node, receiver)); |
3210 } | 3254 } |
3211 | 3255 |
3212 @override | 3256 @override |
3213 visitThisPropertyInvoke( | 3257 visitThisPropertyInvoke( |
3214 ast.Send node, ast.NodeList arguments, Selector selector, _) { | 3258 ast.Send node, ast.NodeList arguments, Selector selector, _) { |
3215 generateDynamicSend(node); | 3259 generateDynamicSend(node); |
(...skipping 1785 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5001 if (Elements.isUnresolved(getter)) { | 5045 if (Elements.isUnresolved(getter)) { |
5002 generateSuperNoSuchMethodSend(node, getterSelector, getterInputs); | 5046 generateSuperNoSuchMethodSend(node, getterSelector, getterInputs); |
5003 getterInstruction = pop(); | 5047 getterInstruction = pop(); |
5004 } else { | 5048 } else { |
5005 getterInstruction = | 5049 getterInstruction = |
5006 buildInvokeSuper(getterSelector, getter, getterInputs); | 5050 buildInvokeSuper(getterSelector, getter, getterInputs); |
5007 add(getterInstruction); | 5051 add(getterInstruction); |
5008 } | 5052 } |
5009 | 5053 |
5010 if (node.isIfNullAssignment) { | 5054 if (node.isIfNullAssignment) { |
5011 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 5055 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
5012 brancher.handleIfNull(() => stack.add(getterInstruction), () { | 5056 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
5013 addDynamicSendArgumentsToList(node, setterInputs); | 5057 addDynamicSendArgumentsToList(node, setterInputs); |
5014 generateSuperSendSet(); | 5058 generateSuperSendSet(); |
5015 stack.add(setterInputs.last); | 5059 stack.add(setterInputs.last); |
5016 }); | 5060 }); |
5017 } else { | 5061 } else { |
5018 handleComplexOperatorSend(node, getterInstruction, arguments); | 5062 handleComplexOperatorSend(node, getterInstruction, arguments); |
5019 setterInputs.add(pop()); | 5063 setterInputs.add(pop()); |
5020 generateSuperSendSet(); | 5064 generateSuperSendSet(); |
5021 stack.add(node.isPostfix ? getterInstruction : setterInputs.last); | 5065 stack.add(node.isPostfix ? getterInstruction : setterInputs.last); |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5321 | 5365 |
5322 pushInvokeDynamic(node, elements.getGetterSelectorInComplexSendSet(node), | 5366 pushInvokeDynamic(node, elements.getGetterSelectorInComplexSendSet(node), |
5323 elements.getGetterTypeMaskInComplexSendSet(node), [receiver, index]); | 5367 elements.getGetterTypeMaskInComplexSendSet(node), [receiver, index]); |
5324 HInstruction getterInstruction = pop(); | 5368 HInstruction getterInstruction = pop(); |
5325 if (node.isIfNullAssignment) { | 5369 if (node.isIfNullAssignment) { |
5326 // Compile x[i] ??= e as: | 5370 // Compile x[i] ??= e as: |
5327 // t1 = x[i] | 5371 // t1 = x[i] |
5328 // if (t1 == null) | 5372 // if (t1 == null) |
5329 // t1 = x[i] = e; | 5373 // t1 = x[i] = e; |
5330 // result = t1 | 5374 // result = t1 |
5331 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 5375 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
5332 brancher.handleIfNull(() => stack.add(getterInstruction), () { | 5376 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
5333 visit(arguments.head); | 5377 visit(arguments.head); |
5334 HInstruction value = pop(); | 5378 HInstruction value = pop(); |
5335 pushInvokeDynamic(node, elements.getSelector(node), | 5379 pushInvokeDynamic(node, elements.getSelector(node), |
5336 elements.getTypeMask(node), [receiver, index, value]); | 5380 elements.getTypeMask(node), [receiver, index, value]); |
5337 pop(); | 5381 pop(); |
5338 stack.add(value); | 5382 stack.add(value); |
5339 }); | 5383 }); |
5340 } else { | 5384 } else { |
5341 handleComplexOperatorSend(node, getterInstruction, arguments); | 5385 handleComplexOperatorSend(node, getterInstruction, arguments); |
(...skipping 27 matching lines...) Expand all Loading... | |
5369 void visitIfNotNullDynamicPropertySet( | 5413 void visitIfNotNullDynamicPropertySet( |
5370 ast.SendSet node, ast.Node receiver, Name name, ast.Node rhs, _) { | 5414 ast.SendSet node, ast.Node receiver, Name name, ast.Node rhs, _) { |
5371 // compile e?.x = e2 to: | 5415 // compile e?.x = e2 to: |
5372 // | 5416 // |
5373 // t1 = e | 5417 // t1 = e |
5374 // if (t1 == null) | 5418 // if (t1 == null) |
5375 // result = t1 // same as result = null | 5419 // result = t1 // same as result = null |
5376 // else | 5420 // else |
5377 // result = e.x = e2 | 5421 // result = e.x = e2 |
5378 HInstruction receiverInstruction; | 5422 HInstruction receiverInstruction; |
5379 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 5423 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
5380 brancher.handleConditional( | 5424 brancher.handleConditional( |
5381 () { | 5425 () { |
5382 receiverInstruction = generateInstanceSendReceiver(node); | 5426 receiverInstruction = generateInstanceSendReceiver(node); |
5383 pushCheckNull(receiverInstruction); | 5427 pushCheckNull(receiverInstruction); |
5384 }, | 5428 }, |
5385 () => stack.add(receiverInstruction), | 5429 () => stack.add(receiverInstruction), |
5386 () { | 5430 () { |
5387 generateInstanceSetterWithCompiledReceiver( | 5431 generateInstanceSetterWithCompiledReceiver( |
5388 node, receiverInstruction, visitAndPop(rhs)); | 5432 node, receiverInstruction, visitAndPop(rhs)); |
5389 }); | 5433 }); |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5542 if (Elements.isInstanceSend(node, elements)) { | 5586 if (Elements.isInstanceSend(node, elements)) { |
5543 void generateAssignment(HInstruction receiver) { | 5587 void generateAssignment(HInstruction receiver) { |
5544 // desugars `e.x op= e2` to `e.x = e.x op e2` | 5588 // desugars `e.x op= e2` to `e.x = e.x op e2` |
5545 generateInstanceGetterWithCompiledReceiver( | 5589 generateInstanceGetterWithCompiledReceiver( |
5546 node, | 5590 node, |
5547 elements.getGetterSelectorInComplexSendSet(node), | 5591 elements.getGetterSelectorInComplexSendSet(node), |
5548 elements.getGetterTypeMaskInComplexSendSet(node), | 5592 elements.getGetterTypeMaskInComplexSendSet(node), |
5549 receiver); | 5593 receiver); |
5550 HInstruction getterInstruction = pop(); | 5594 HInstruction getterInstruction = pop(); |
5551 if (node.isIfNullAssignment) { | 5595 if (node.isIfNullAssignment) { |
5552 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 5596 SsaBranchBuilder brancher = |
5597 new SsaBranchBuilder(this, compiler, node); | |
5553 brancher.handleIfNull(() => stack.add(getterInstruction), () { | 5598 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
5554 visit(node.arguments.head); | 5599 visit(node.arguments.head); |
5555 generateInstanceSetterWithCompiledReceiver(node, receiver, pop()); | 5600 generateInstanceSetterWithCompiledReceiver(node, receiver, pop()); |
5556 }); | 5601 }); |
5557 } else { | 5602 } else { |
5558 handleComplexOperatorSend(node, getterInstruction, node.arguments); | 5603 handleComplexOperatorSend(node, getterInstruction, node.arguments); |
5559 HInstruction value = pop(); | 5604 HInstruction value = pop(); |
5560 generateInstanceSetterWithCompiledReceiver(node, receiver, value); | 5605 generateInstanceSetterWithCompiledReceiver(node, receiver, value); |
5561 } | 5606 } |
5562 if (node.isPostfix) { | 5607 if (node.isPostfix) { |
5563 pop(); | 5608 pop(); |
5564 stack.add(getterInstruction); | 5609 stack.add(getterInstruction); |
5565 } | 5610 } |
5566 } | 5611 } |
5567 | 5612 |
5568 if (node.isConditional) { | 5613 if (node.isConditional) { |
5569 // generate `e?.x op= e2` as: | 5614 // generate `e?.x op= e2` as: |
5570 // t1 = e | 5615 // t1 = e |
5571 // t1 == null ? t1 : (t1.x = t1.x op e2); | 5616 // t1 == null ? t1 : (t1.x = t1.x op e2); |
5572 HInstruction receiver; | 5617 HInstruction receiver; |
5573 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 5618 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
5574 brancher.handleConditional(() { | 5619 brancher.handleConditional(() { |
5575 receiver = generateInstanceSendReceiver(node); | 5620 receiver = generateInstanceSendReceiver(node); |
5576 pushCheckNull(receiver); | 5621 pushCheckNull(receiver); |
5577 }, () => stack.add(receiver), () => generateAssignment(receiver)); | 5622 }, () => stack.add(receiver), () => generateAssignment(receiver)); |
5578 } else { | 5623 } else { |
5579 generateAssignment(generateInstanceSendReceiver(node)); | 5624 generateAssignment(generateInstanceSendReceiver(node)); |
5580 } | 5625 } |
5581 return; | 5626 return; |
5582 } | 5627 } |
5583 | 5628 |
5584 if (getter.isMalformed) { | 5629 if (getter.isMalformed) { |
5585 generateStaticUnresolvedGet(node, getter); | 5630 generateStaticUnresolvedGet(node, getter); |
5586 } else if (getter.isField) { | 5631 } else if (getter.isField) { |
5587 generateStaticFieldGet(node, getter); | 5632 generateStaticFieldGet(node, getter); |
5588 } else if (getter.isGetter) { | 5633 } else if (getter.isGetter) { |
5589 generateStaticGetterGet(node, getter); | 5634 generateStaticGetterGet(node, getter); |
5590 } else if (getter.isFunction) { | 5635 } else if (getter.isFunction) { |
5591 generateStaticFunctionGet(node, getter); | 5636 generateStaticFunctionGet(node, getter); |
5592 } else if (getter.isLocal) { | 5637 } else if (getter.isLocal) { |
5593 handleLocalGet(node, getter); | 5638 handleLocalGet(node, getter); |
5594 } else { | 5639 } else { |
5595 internalError(node, "Unexpected getter: $getter"); | 5640 internalError(node, "Unexpected getter: $getter"); |
5596 } | 5641 } |
5597 HInstruction getterInstruction = pop(); | 5642 HInstruction getterInstruction = pop(); |
5598 if (node.isIfNullAssignment) { | 5643 if (node.isIfNullAssignment) { |
5599 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 5644 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
5600 brancher.handleIfNull(() => stack.add(getterInstruction), () { | 5645 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
5601 visit(node.arguments.head); | 5646 visit(node.arguments.head); |
5602 generateNonInstanceSetter(node, element, pop()); | 5647 generateNonInstanceSetter(node, element, pop()); |
5603 }); | 5648 }); |
5604 } else { | 5649 } else { |
5605 handleComplexOperatorSend(node, getterInstruction, node.arguments); | 5650 handleComplexOperatorSend(node, getterInstruction, node.arguments); |
5606 HInstruction value = pop(); | 5651 HInstruction value = pop(); |
5607 generateNonInstanceSetter(node, element, value); | 5652 generateNonInstanceSetter(node, element, value); |
5608 } | 5653 } |
5609 if (node.isPostfix) { | 5654 if (node.isPostfix) { |
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5999 instruction = setRtiIfNeeded(instruction, node); | 6044 instruction = setRtiIfNeeded(instruction, node); |
6000 } | 6045 } |
6001 | 6046 |
6002 TypeMask type = | 6047 TypeMask type = |
6003 TypeMaskFactory.inferredForNode(sourceElement, node, compiler); | 6048 TypeMaskFactory.inferredForNode(sourceElement, node, compiler); |
6004 if (!type.containsAll(compiler.world)) instruction.instructionType = type; | 6049 if (!type.containsAll(compiler.world)) instruction.instructionType = type; |
6005 stack.add(instruction); | 6050 stack.add(instruction); |
6006 } | 6051 } |
6007 | 6052 |
6008 visitConditional(ast.Conditional node) { | 6053 visitConditional(ast.Conditional node) { |
6009 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 6054 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
6010 brancher.handleConditional(() => visit(node.condition), | 6055 brancher.handleConditional(() => visit(node.condition), |
6011 () => visit(node.thenExpression), () => visit(node.elseExpression)); | 6056 () => visit(node.thenExpression), () => visit(node.elseExpression)); |
6012 } | 6057 } |
6013 | 6058 |
6014 visitStringInterpolation(ast.StringInterpolation node) { | 6059 visitStringInterpolation(ast.StringInterpolation node) { |
6015 StringBuilderVisitor stringBuilder = new StringBuilderVisitor(this, node); | 6060 StringBuilderVisitor stringBuilder = new StringBuilderVisitor(this, node); |
6016 stringBuilder.visit(node); | 6061 stringBuilder.visit(node); |
6017 stack.add(stringBuilder.result); | 6062 stack.add(stringBuilder.result); |
6018 } | 6063 } |
6019 | 6064 |
(...skipping 1451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7471 this.oldReturnLocal, | 7516 this.oldReturnLocal, |
7472 this.oldReturnType, | 7517 this.oldReturnType, |
7473 this.oldResolvedAst, | 7518 this.oldResolvedAst, |
7474 this.oldStack, | 7519 this.oldStack, |
7475 this.oldLocalsHandler, | 7520 this.oldLocalsHandler, |
7476 this.inTryStatement, | 7521 this.inTryStatement, |
7477 this.allFunctionsCalledOnce) | 7522 this.allFunctionsCalledOnce) |
7478 : super(function); | 7523 : super(function); |
7479 } | 7524 } |
7480 | 7525 |
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> { | 7526 class TypeBuilder implements DartTypeVisitor<dynamic, SsaBuilder> { |
7728 final ClassWorld classWorld; | 7527 final ClassWorld classWorld; |
7729 | 7528 |
7730 TypeBuilder(this.classWorld); | 7529 TypeBuilder(this.classWorld); |
7731 | 7530 |
7732 void visit(DartType type, SsaBuilder builder) => type.accept(this, builder); | 7531 void visit(DartType type, SsaBuilder builder) => type.accept(this, builder); |
7733 | 7532 |
7734 void visitVoidType(VoidType type, SsaBuilder builder) { | 7533 void visitVoidType(VoidType type, SsaBuilder builder) { |
7735 ClassElement cls = builder.backend.helpers.VoidRuntimeType; | 7534 ClassElement cls = builder.backend.helpers.VoidRuntimeType; |
7736 builder.push(new HVoidType(type, new TypeMask.exact(cls, classWorld))); | 7535 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(); | 7622 const _LoopTypeVisitor(); |
7824 int visitNode(ast.Node node) => HLoopBlockInformation.NOT_A_LOOP; | 7623 int visitNode(ast.Node node) => HLoopBlockInformation.NOT_A_LOOP; |
7825 int visitWhile(ast.While node) => HLoopBlockInformation.WHILE_LOOP; | 7624 int visitWhile(ast.While node) => HLoopBlockInformation.WHILE_LOOP; |
7826 int visitFor(ast.For node) => HLoopBlockInformation.FOR_LOOP; | 7625 int visitFor(ast.For node) => HLoopBlockInformation.FOR_LOOP; |
7827 int visitDoWhile(ast.DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP; | 7626 int visitDoWhile(ast.DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP; |
7828 int visitAsyncForIn(ast.AsyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; | 7627 int visitAsyncForIn(ast.AsyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; |
7829 int visitSyncForIn(ast.SyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; | 7628 int visitSyncForIn(ast.SyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; |
7830 int visitSwitchStatement(ast.SwitchStatement node) => | 7629 int visitSwitchStatement(ast.SwitchStatement node) => |
7831 HLoopBlockInformation.SWITCH_CONTINUE_LOOP; | 7630 HLoopBlockInformation.SWITCH_CONTINUE_LOOP; |
7832 } | 7631 } |
OLD | NEW |