| 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 |