| 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 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 /// might not be in scope or from the current instance. | 199 /// might not be in scope or from the current instance. |
| 200 /// | 200 /// |
| 201 final InterfaceType instanceType; | 201 final InterfaceType instanceType; |
| 202 | 202 |
| 203 SourceInformationBuilder get sourceInformationBuilder { | 203 SourceInformationBuilder get sourceInformationBuilder { |
| 204 return builder.sourceInformationBuilder; | 204 return builder.sourceInformationBuilder; |
| 205 } | 205 } |
| 206 | 206 |
| 207 LocalsHandler( | 207 LocalsHandler( |
| 208 this.builder, this.executableContext, InterfaceType instanceType) | 208 this.builder, this.executableContext, InterfaceType instanceType) |
| 209 : this.instanceType = instanceType == null || | 209 : this.instanceType = |
| 210 instanceType.containsTypeVariables ? null : instanceType; | 210 instanceType == null || instanceType.containsTypeVariables |
| 211 ? null |
| 212 : instanceType; |
| 211 | 213 |
| 212 /// Substituted type variables occurring in [type] into the context of | 214 /// Substituted type variables occurring in [type] into the context of |
| 213 /// [contextClass]. | 215 /// [contextClass]. |
| 214 DartType substInContext(DartType type) { | 216 DartType substInContext(DartType type) { |
| 215 if (contextClass != null) { | 217 if (contextClass != null) { |
| 216 ClassElement typeContext = Types.getClassContext(type); | 218 ClassElement typeContext = Types.getClassContext(type); |
| 217 if (typeContext != null) { | 219 if (typeContext != null) { |
| 218 type = type.substByContext(contextClass.asInstanceOf(typeContext)); | 220 type = type.substByContext(contextClass.asInstanceOf(typeContext)); |
| 219 } | 221 } |
| 220 } | 222 } |
| (...skipping 2532 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2753 return; | 2755 return; |
| 2754 } | 2756 } |
| 2755 // Assert has message. Generate: | 2757 // Assert has message. Generate: |
| 2756 // | 2758 // |
| 2757 // if (assertTest(condition)) assertThrow(message); | 2759 // if (assertTest(condition)) assertThrow(message); |
| 2758 // | 2760 // |
| 2759 void buildCondition() { | 2761 void buildCondition() { |
| 2760 visit(node.condition); | 2762 visit(node.condition); |
| 2761 pushInvokeStatic(node, helpers.assertTest, [pop()]); | 2763 pushInvokeStatic(node, helpers.assertTest, [pop()]); |
| 2762 } | 2764 } |
| 2765 |
| 2763 void fail() { | 2766 void fail() { |
| 2764 visit(node.message); | 2767 visit(node.message); |
| 2765 pushInvokeStatic(node, helpers.assertThrow, [pop()]); | 2768 pushInvokeStatic(node, helpers.assertThrow, [pop()]); |
| 2766 pop(); | 2769 pop(); |
| 2767 } | 2770 } |
| 2771 |
| 2768 handleIf(node, visitCondition: buildCondition, visitThen: fail); | 2772 handleIf(node, visitCondition: buildCondition, visitThen: fail); |
| 2769 } | 2773 } |
| 2770 | 2774 |
| 2771 visitBlock(ast.Block node) { | 2775 visitBlock(ast.Block node) { |
| 2772 assert(!isAborted()); | 2776 assert(!isAborted()); |
| 2773 if (!isReachable) return; // This can only happen when inlining. | 2777 if (!isReachable) return; // This can only happen when inlining. |
| 2774 for (Link<ast.Node> link = node.statements.nodes; | 2778 for (Link<ast.Node> link = node.statements.nodes; |
| 2775 !link.isEmpty; | 2779 !link.isEmpty; |
| 2776 link = link.tail) { | 2780 link = link.tail) { |
| 2777 visit(link.head); | 2781 visit(link.head); |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3091 assert(isReachable); | 3095 assert(isReachable); |
| 3092 assert(node.body != null); | 3096 assert(node.body != null); |
| 3093 void buildInitializer() { | 3097 void buildInitializer() { |
| 3094 ast.Node initializer = node.initializer; | 3098 ast.Node initializer = node.initializer; |
| 3095 if (initializer == null) return; | 3099 if (initializer == null) return; |
| 3096 visit(initializer); | 3100 visit(initializer); |
| 3097 if (initializer.asExpression() != null) { | 3101 if (initializer.asExpression() != null) { |
| 3098 pop(); | 3102 pop(); |
| 3099 } | 3103 } |
| 3100 } | 3104 } |
| 3105 |
| 3101 HInstruction buildCondition() { | 3106 HInstruction buildCondition() { |
| 3102 if (node.condition == null) { | 3107 if (node.condition == null) { |
| 3103 return graph.addConstantBool(true, compiler); | 3108 return graph.addConstantBool(true, compiler); |
| 3104 } | 3109 } |
| 3105 visit(node.condition); | 3110 visit(node.condition); |
| 3106 return popBoolified(); | 3111 return popBoolified(); |
| 3107 } | 3112 } |
| 3113 |
| 3108 void buildUpdate() { | 3114 void buildUpdate() { |
| 3109 for (ast.Expression expression in node.update) { | 3115 for (ast.Expression expression in node.update) { |
| 3110 visit(expression); | 3116 visit(expression); |
| 3111 assert(!isAborted()); | 3117 assert(!isAborted()); |
| 3112 // The result of the update instruction isn't used, and can just | 3118 // The result of the update instruction isn't used, and can just |
| 3113 // be dropped. | 3119 // be dropped. |
| 3114 pop(); | 3120 pop(); |
| 3115 } | 3121 } |
| 3116 } | 3122 } |
| 3123 |
| 3117 void buildBody() { | 3124 void buildBody() { |
| 3118 visit(node.body); | 3125 visit(node.body); |
| 3119 } | 3126 } |
| 3127 |
| 3120 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); | 3128 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); |
| 3121 } | 3129 } |
| 3122 | 3130 |
| 3123 visitWhile(ast.While node) { | 3131 visitWhile(ast.While node) { |
| 3124 assert(isReachable); | 3132 assert(isReachable); |
| 3125 HInstruction buildCondition() { | 3133 HInstruction buildCondition() { |
| 3126 visit(node.condition); | 3134 visit(node.condition); |
| 3127 return popBoolified(); | 3135 return popBoolified(); |
| 3128 } | 3136 } |
| 3137 |
| 3129 handleLoop(node, () {}, buildCondition, () {}, () { | 3138 handleLoop(node, () {}, buildCondition, () {}, () { |
| 3130 visit(node.body); | 3139 visit(node.body); |
| 3131 }); | 3140 }); |
| 3132 } | 3141 } |
| 3133 | 3142 |
| 3134 visitDoWhile(ast.DoWhile node) { | 3143 visitDoWhile(ast.DoWhile node) { |
| 3135 assert(isReachable); | 3144 assert(isReachable); |
| 3136 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | 3145 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
| 3137 localsHandler.startLoop(node); | 3146 localsHandler.startLoop(node); |
| 3138 loopNesting++; | 3147 loopNesting++; |
| (...skipping 2520 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5659 | 5668 |
| 5660 var nativeBehavior = new native.NativeBehavior() | 5669 var nativeBehavior = new native.NativeBehavior() |
| 5661 ..sideEffects.setAllSideEffects(); | 5670 ..sideEffects.setAllSideEffects(); |
| 5662 | 5671 |
| 5663 DartType type = element.isConstructor | 5672 DartType type = element.isConstructor |
| 5664 ? element.enclosingClass.thisType | 5673 ? element.enclosingClass.thisType |
| 5665 : element.type.returnType; | 5674 : element.type.returnType; |
| 5666 // Native behavior effects here are similar to native/behavior.dart. | 5675 // Native behavior effects here are similar to native/behavior.dart. |
| 5667 // The return type is dynamic if we don't trust js-interop type | 5676 // The return type is dynamic if we don't trust js-interop type |
| 5668 // declarations. | 5677 // declarations. |
| 5669 nativeBehavior.typesReturned.add(compiler | 5678 nativeBehavior.typesReturned.add( |
| 5670 .options.trustJSInteropTypeAnnotations ? type : const DynamicType()); | 5679 compiler.options.trustJSInteropTypeAnnotations |
| 5680 ? type |
| 5681 : const DynamicType()); |
| 5671 | 5682 |
| 5672 // The allocation effects include the declared type if it is native (which | 5683 // The allocation effects include the declared type if it is native (which |
| 5673 // includes js interop types). | 5684 // includes js interop types). |
| 5674 if (type.element != null && backend.isNative(type.element)) { | 5685 if (type.element != null && backend.isNative(type.element)) { |
| 5675 nativeBehavior.typesInstantiated.add(type); | 5686 nativeBehavior.typesInstantiated.add(type); |
| 5676 } | 5687 } |
| 5677 | 5688 |
| 5678 // It also includes any other JS interop type if we don't trust the | 5689 // It also includes any other JS interop type if we don't trust the |
| 5679 // annotation or if is declared too broad. | 5690 // annotation or if is declared too broad. |
| 5680 if (!compiler.options.trustJSInteropTypeAnnotations || | 5691 if (!compiler.options.trustJSInteropTypeAnnotations || |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5794 void generateSuperSendSet() { | 5805 void generateSuperSendSet() { |
| 5795 Selector setterSelector = elements.getSelector(node); | 5806 Selector setterSelector = elements.getSelector(node); |
| 5796 if (Elements.isUnresolved(element) || | 5807 if (Elements.isUnresolved(element) || |
| 5797 !setterSelector.applies(element, compiler.world)) { | 5808 !setterSelector.applies(element, compiler.world)) { |
| 5798 generateSuperNoSuchMethodSend(node, setterSelector, setterInputs); | 5809 generateSuperNoSuchMethodSend(node, setterSelector, setterInputs); |
| 5799 pop(); | 5810 pop(); |
| 5800 } else { | 5811 } else { |
| 5801 add(buildInvokeSuper(setterSelector, element, setterInputs)); | 5812 add(buildInvokeSuper(setterSelector, element, setterInputs)); |
| 5802 } | 5813 } |
| 5803 } | 5814 } |
| 5815 |
| 5804 if (identical(node.assignmentOperator.source, '=')) { | 5816 if (identical(node.assignmentOperator.source, '=')) { |
| 5805 addDynamicSendArgumentsToList(node, setterInputs); | 5817 addDynamicSendArgumentsToList(node, setterInputs); |
| 5806 generateSuperSendSet(); | 5818 generateSuperSendSet(); |
| 5807 stack.add(setterInputs.last); | 5819 stack.add(setterInputs.last); |
| 5808 } else { | 5820 } else { |
| 5809 Element getter = elements[node.selector]; | 5821 Element getter = elements[node.selector]; |
| 5810 List<HInstruction> getterInputs = <HInstruction>[]; | 5822 List<HInstruction> getterInputs = <HInstruction>[]; |
| 5811 Link<ast.Node> arguments = node.arguments; | 5823 Link<ast.Node> arguments = node.arguments; |
| 5812 if (node.isIndex) { | 5824 if (node.isIndex) { |
| 5813 // If node is of the form [:super.foo[0] += 2:], the send has | 5825 // If node is of the form [:super.foo[0] += 2:], the send has |
| (...skipping 568 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6382 } else { | 6394 } else { |
| 6383 handleComplexOperatorSend(node, getterInstruction, node.arguments); | 6395 handleComplexOperatorSend(node, getterInstruction, node.arguments); |
| 6384 HInstruction value = pop(); | 6396 HInstruction value = pop(); |
| 6385 generateInstanceSetterWithCompiledReceiver(node, receiver, value); | 6397 generateInstanceSetterWithCompiledReceiver(node, receiver, value); |
| 6386 } | 6398 } |
| 6387 if (node.isPostfix) { | 6399 if (node.isPostfix) { |
| 6388 pop(); | 6400 pop(); |
| 6389 stack.add(getterInstruction); | 6401 stack.add(getterInstruction); |
| 6390 } | 6402 } |
| 6391 } | 6403 } |
| 6404 |
| 6392 if (node.isConditional) { | 6405 if (node.isConditional) { |
| 6393 // generate `e?.x op= e2` as: | 6406 // generate `e?.x op= e2` as: |
| 6394 // t1 = e | 6407 // t1 = e |
| 6395 // t1 == null ? t1 : (t1.x = t1.x op e2); | 6408 // t1 == null ? t1 : (t1.x = t1.x op e2); |
| 6396 HInstruction receiver; | 6409 HInstruction receiver; |
| 6397 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 6410 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| 6398 brancher.handleConditional(() { | 6411 brancher.handleConditional(() { |
| 6399 receiver = generateInstanceSendReceiver(node); | 6412 receiver = generateInstanceSendReceiver(node); |
| 6400 pushCheckNull(receiver); | 6413 pushCheckNull(receiver); |
| 6401 }, () => stack.add(receiver), () => generateAssignment(receiver)); | 6414 }, () => stack.add(receiver), () => generateAssignment(receiver)); |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6632 redirectingSignature.orderedOptionalParameters; | 6645 redirectingSignature.orderedOptionalParameters; |
| 6633 | 6646 |
| 6634 // TODO(25579): This code can do the wrong thing redirecting constructor and | 6647 // TODO(25579): This code can do the wrong thing redirecting constructor and |
| 6635 // the target do not correspond. It is correct if there is no | 6648 // the target do not correspond. It is correct if there is no |
| 6636 // warning. Ideally the redirecting constructor and the target would be the | 6649 // warning. Ideally the redirecting constructor and the target would be the |
| 6637 // same function. | 6650 // same function. |
| 6638 | 6651 |
| 6639 void loadLocal(ParameterElement parameter) { | 6652 void loadLocal(ParameterElement parameter) { |
| 6640 inputs.add(localsHandler.readLocal(parameter)); | 6653 inputs.add(localsHandler.readLocal(parameter)); |
| 6641 } | 6654 } |
| 6655 |
| 6642 void loadPosition(int position, ParameterElement optionalParameter) { | 6656 void loadPosition(int position, ParameterElement optionalParameter) { |
| 6643 if (position < redirectingRequireds.length) { | 6657 if (position < redirectingRequireds.length) { |
| 6644 loadLocal(redirectingRequireds[position]); | 6658 loadLocal(redirectingRequireds[position]); |
| 6645 } else if (position < redirectingSignature.parameterCount && | 6659 } else if (position < redirectingSignature.parameterCount && |
| 6646 !redirectingSignature.optionalParametersAreNamed) { | 6660 !redirectingSignature.optionalParametersAreNamed) { |
| 6647 loadLocal(redirectingOptionals[position - redirectingRequireds.length]); | 6661 loadLocal(redirectingOptionals[position - redirectingRequireds.length]); |
| 6648 } else if (optionalParameter != null) { | 6662 } else if (optionalParameter != null) { |
| 6649 inputs.add(handleConstantForOptionalParameter(optionalParameter)); | 6663 inputs.add(handleConstantForOptionalParameter(optionalParameter)); |
| 6650 } else { | 6664 } else { |
| 6651 // Wrong. | 6665 // Wrong. |
| (...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6920 | 6934 |
| 6921 HInstruction buildCondition() { | 6935 HInstruction buildCondition() { |
| 6922 Selector selector = Selectors.moveNext; | 6936 Selector selector = Selectors.moveNext; |
| 6923 TypeMask mask = elements.getMoveNextTypeMask(node); | 6937 TypeMask mask = elements.getMoveNextTypeMask(node); |
| 6924 pushInvokeDynamic(node, selector, mask, [streamIterator]); | 6938 pushInvokeDynamic(node, selector, mask, [streamIterator]); |
| 6925 HInstruction future = pop(); | 6939 HInstruction future = pop(); |
| 6926 push(new HAwait(future, | 6940 push(new HAwait(future, |
| 6927 new TypeMask.subclass(coreClasses.objectClass, compiler.world))); | 6941 new TypeMask.subclass(coreClasses.objectClass, compiler.world))); |
| 6928 return popBoolified(); | 6942 return popBoolified(); |
| 6929 } | 6943 } |
| 6944 |
| 6930 void buildBody() { | 6945 void buildBody() { |
| 6931 Selector call = Selectors.current; | 6946 Selector call = Selectors.current; |
| 6932 TypeMask callMask = elements.getCurrentTypeMask(node); | 6947 TypeMask callMask = elements.getCurrentTypeMask(node); |
| 6933 pushInvokeDynamic(node, call, callMask, [streamIterator]); | 6948 pushInvokeDynamic(node, call, callMask, [streamIterator]); |
| 6934 | 6949 |
| 6935 ast.Node identifier = node.declaredIdentifier; | 6950 ast.Node identifier = node.declaredIdentifier; |
| 6936 Element variable = elements.getForInVariable(node); | 6951 Element variable = elements.getForInVariable(node); |
| 6937 Selector selector = elements.getSelector(identifier); | 6952 Selector selector = elements.getSelector(identifier); |
| 6938 TypeMask mask = elements.getTypeMask(identifier); | 6953 TypeMask mask = elements.getTypeMask(identifier); |
| 6939 | 6954 |
| (...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7334 * Builds a simple switch statement which does not handle uses of continue | 7349 * Builds a simple switch statement which does not handle uses of continue |
| 7335 * statements to labeled switch cases. | 7350 * statements to labeled switch cases. |
| 7336 */ | 7351 */ |
| 7337 void buildSimpleSwitchStatement( | 7352 void buildSimpleSwitchStatement( |
| 7338 ast.SwitchStatement node, Map<ast.CaseMatch, ConstantValue> constants) { | 7353 ast.SwitchStatement node, Map<ast.CaseMatch, ConstantValue> constants) { |
| 7339 JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: false); | 7354 JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: false); |
| 7340 HInstruction buildExpression() { | 7355 HInstruction buildExpression() { |
| 7341 visit(node.expression); | 7356 visit(node.expression); |
| 7342 return pop(); | 7357 return pop(); |
| 7343 } | 7358 } |
| 7359 |
| 7344 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) { | 7360 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) { |
| 7345 List<ConstantValue> constantList = <ConstantValue>[]; | 7361 List<ConstantValue> constantList = <ConstantValue>[]; |
| 7346 for (ast.Node labelOrCase in switchCase.labelsAndCases) { | 7362 for (ast.Node labelOrCase in switchCase.labelsAndCases) { |
| 7347 if (labelOrCase is ast.CaseMatch) { | 7363 if (labelOrCase is ast.CaseMatch) { |
| 7348 constantList.add(constants[labelOrCase]); | 7364 constantList.add(constants[labelOrCase]); |
| 7349 } | 7365 } |
| 7350 } | 7366 } |
| 7351 return constantList; | 7367 return constantList; |
| 7352 } | 7368 } |
| 7369 |
| 7353 bool isDefaultCase(ast.SwitchCase switchCase) { | 7370 bool isDefaultCase(ast.SwitchCase switchCase) { |
| 7354 return switchCase.isDefaultCase; | 7371 return switchCase.isDefaultCase; |
| 7355 } | 7372 } |
| 7373 |
| 7356 void buildSwitchCase(ast.SwitchCase node) { | 7374 void buildSwitchCase(ast.SwitchCase node) { |
| 7357 visit(node.statements); | 7375 visit(node.statements); |
| 7358 } | 7376 } |
| 7377 |
| 7359 handleSwitch(node, jumpHandler, buildExpression, node.cases, getConstants, | 7378 handleSwitch(node, jumpHandler, buildExpression, node.cases, getConstants, |
| 7360 isDefaultCase, buildSwitchCase); | 7379 isDefaultCase, buildSwitchCase); |
| 7361 jumpHandler.close(); | 7380 jumpHandler.close(); |
| 7362 } | 7381 } |
| 7363 | 7382 |
| 7364 /** | 7383 /** |
| 7365 * Builds a switch statement that can handle arbitrary uses of continue | 7384 * Builds a switch statement that can handle arbitrary uses of continue |
| 7366 * statements to labeled switch cases. | 7385 * statements to labeled switch cases. |
| 7367 */ | 7386 */ |
| 7368 void buildComplexSwitchStatement( | 7387 void buildComplexSwitchStatement( |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7407 if (!hasDefault) { | 7426 if (!hasDefault) { |
| 7408 // Use [:null:] as the marker for a synthetic default clause. | 7427 // Use [:null:] as the marker for a synthetic default clause. |
| 7409 // The synthetic default is added because otherwise, there would be no | 7428 // The synthetic default is added because otherwise, there would be no |
| 7410 // good place to give a default value to the local. | 7429 // good place to give a default value to the local. |
| 7411 switchCases = node.cases.nodes.toList()..add(null); | 7430 switchCases = node.cases.nodes.toList()..add(null); |
| 7412 } | 7431 } |
| 7413 HInstruction buildExpression() { | 7432 HInstruction buildExpression() { |
| 7414 visit(node.expression); | 7433 visit(node.expression); |
| 7415 return pop(); | 7434 return pop(); |
| 7416 } | 7435 } |
| 7436 |
| 7417 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) { | 7437 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) { |
| 7418 List<ConstantValue> constantList = <ConstantValue>[]; | 7438 List<ConstantValue> constantList = <ConstantValue>[]; |
| 7419 if (switchCase != null) { | 7439 if (switchCase != null) { |
| 7420 for (ast.Node labelOrCase in switchCase.labelsAndCases) { | 7440 for (ast.Node labelOrCase in switchCase.labelsAndCases) { |
| 7421 if (labelOrCase is ast.CaseMatch) { | 7441 if (labelOrCase is ast.CaseMatch) { |
| 7422 constantList.add(constants[labelOrCase]); | 7442 constantList.add(constants[labelOrCase]); |
| 7423 } | 7443 } |
| 7424 } | 7444 } |
| 7425 } | 7445 } |
| 7426 return constantList; | 7446 return constantList; |
| 7427 } | 7447 } |
| 7448 |
| 7428 bool isDefaultCase(ast.SwitchCase switchCase) { | 7449 bool isDefaultCase(ast.SwitchCase switchCase) { |
| 7429 return switchCase == null || switchCase.isDefaultCase; | 7450 return switchCase == null || switchCase.isDefaultCase; |
| 7430 } | 7451 } |
| 7452 |
| 7431 void buildSwitchCase(ast.SwitchCase switchCase) { | 7453 void buildSwitchCase(ast.SwitchCase switchCase) { |
| 7432 if (switchCase != null) { | 7454 if (switchCase != null) { |
| 7433 // Generate 'target = i; break;' for switch case i. | 7455 // Generate 'target = i; break;' for switch case i. |
| 7434 int index = caseIndex[switchCase]; | 7456 int index = caseIndex[switchCase]; |
| 7435 HInstruction value = graph.addConstantInt(index, compiler); | 7457 HInstruction value = graph.addConstantInt(index, compiler); |
| 7436 localsHandler.updateLocal(switchTarget, value); | 7458 localsHandler.updateLocal(switchTarget, value); |
| 7437 } else { | 7459 } else { |
| 7438 // Generate synthetic default case 'target = null; break;'. | 7460 // Generate synthetic default case 'target = null; break;'. |
| 7439 HInstruction value = graph.addConstantNull(compiler); | 7461 HInstruction value = graph.addConstantNull(compiler); |
| 7440 localsHandler.updateLocal(switchTarget, value); | 7462 localsHandler.updateLocal(switchTarget, value); |
| 7441 } | 7463 } |
| 7442 jumpTargets[switchTarget].generateBreak(); | 7464 jumpTargets[switchTarget].generateBreak(); |
| 7443 } | 7465 } |
| 7466 |
| 7444 handleSwitch(node, jumpHandler, buildExpression, switchCases, getConstants, | 7467 handleSwitch(node, jumpHandler, buildExpression, switchCases, getConstants, |
| 7445 isDefaultCase, buildSwitchCase); | 7468 isDefaultCase, buildSwitchCase); |
| 7446 jumpHandler.close(); | 7469 jumpHandler.close(); |
| 7447 | 7470 |
| 7448 HInstruction buildCondition() => graph.addConstantBool(true, compiler); | 7471 HInstruction buildCondition() => graph.addConstantBool(true, compiler); |
| 7449 | 7472 |
| 7450 void buildSwitch() { | 7473 void buildSwitch() { |
| 7451 HInstruction buildExpression() { | 7474 HInstruction buildExpression() { |
| 7452 return localsHandler.readLocal(switchTarget); | 7475 return localsHandler.readLocal(switchTarget); |
| 7453 } | 7476 } |
| 7477 |
| 7454 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) { | 7478 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) { |
| 7455 return <ConstantValue>[constantSystem.createInt(caseIndex[switchCase])]; | 7479 return <ConstantValue>[constantSystem.createInt(caseIndex[switchCase])]; |
| 7456 } | 7480 } |
| 7481 |
| 7457 void buildSwitchCase(ast.SwitchCase switchCase) { | 7482 void buildSwitchCase(ast.SwitchCase switchCase) { |
| 7458 visit(switchCase.statements); | 7483 visit(switchCase.statements); |
| 7459 if (!isAborted()) { | 7484 if (!isAborted()) { |
| 7460 // Ensure that we break the loop if the case falls through. (This | 7485 // Ensure that we break the loop if the case falls through. (This |
| 7461 // is only possible for the last case.) | 7486 // is only possible for the last case.) |
| 7462 jumpTargets[switchTarget].generateBreak(); | 7487 jumpTargets[switchTarget].generateBreak(); |
| 7463 } | 7488 } |
| 7464 } | 7489 } |
| 7490 |
| 7465 // Pass a [NullJumpHandler] because the target for the contained break | 7491 // Pass a [NullJumpHandler] because the target for the contained break |
| 7466 // is not the generated switch statement but instead the loop generated | 7492 // is not the generated switch statement but instead the loop generated |
| 7467 // in the call to [handleLoop] below. | 7493 // in the call to [handleLoop] below. |
| 7468 handleSwitch( | 7494 handleSwitch( |
| 7469 node, | 7495 node, |
| 7470 new NullJumpHandler(reporter), | 7496 new NullJumpHandler(reporter), |
| 7471 buildExpression, | 7497 buildExpression, |
| 7472 node.cases, | 7498 node.cases, |
| 7473 getConstants, | 7499 getConstants, |
| 7474 (_) => false, // No case is default. | 7500 (_) => false, // No case is default. |
| 7475 buildSwitchCase); | 7501 buildSwitchCase); |
| 7476 } | 7502 } |
| 7477 | 7503 |
| 7478 void buildLoop() { | 7504 void buildLoop() { |
| 7479 handleLoop(node, () {}, buildCondition, () {}, buildSwitch); | 7505 handleLoop(node, () {}, buildCondition, () {}, buildSwitch); |
| 7480 } | 7506 } |
| 7481 | 7507 |
| 7482 if (hasDefault) { | 7508 if (hasDefault) { |
| 7483 buildLoop(); | 7509 buildLoop(); |
| 7484 } else { | 7510 } else { |
| 7485 // If the switch statement has no default case, surround the loop with | 7511 // If the switch statement has no default case, surround the loop with |
| 7486 // a test of the target. | 7512 // a test of the target. |
| 7487 void buildCondition() { | 7513 void buildCondition() { |
| 7488 js.Template code = js.js.parseForeignJS('#'); | 7514 js.Template code = js.js.parseForeignJS('#'); |
| 7489 push(new HForeignCode( | 7515 push(new HForeignCode( |
| 7490 code, backend.boolType, [localsHandler.readLocal(switchTarget)], | 7516 code, backend.boolType, [localsHandler.readLocal(switchTarget)], |
| 7491 nativeBehavior: native.NativeBehavior.PURE)); | 7517 nativeBehavior: native.NativeBehavior.PURE)); |
| 7492 } | 7518 } |
| 7519 |
| 7493 handleIf(node, | 7520 handleIf(node, |
| 7494 visitCondition: buildCondition, | 7521 visitCondition: buildCondition, |
| 7495 visitThen: buildLoop, | 7522 visitThen: buildLoop, |
| 7496 visitElse: () => {}); | 7523 visitElse: () => {}); |
| 7497 } | 7524 } |
| 7498 } | 7525 } |
| 7499 | 7526 |
| 7500 /** | 7527 /** |
| 7501 * Creates a switch statement. | 7528 * Creates a switch statement. |
| 7502 * | 7529 * |
| (...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7858 if (!isAborted()) endFinallyBlock = close(new HGoto()); | 7885 if (!isAborted()) endFinallyBlock = close(new HGoto()); |
| 7859 tryInstruction.finallyBlock = startFinallyBlock; | 7886 tryInstruction.finallyBlock = startFinallyBlock; |
| 7860 finallyGraph = new SubGraph(startFinallyBlock, lastOpenedBlock); | 7887 finallyGraph = new SubGraph(startFinallyBlock, lastOpenedBlock); |
| 7861 } | 7888 } |
| 7862 | 7889 |
| 7863 HBasicBlock exitBlock = graph.addNewBlock(); | 7890 HBasicBlock exitBlock = graph.addNewBlock(); |
| 7864 | 7891 |
| 7865 addOptionalSuccessor(b1, b2) { | 7892 addOptionalSuccessor(b1, b2) { |
| 7866 if (b2 != null) b1.addSuccessor(b2); | 7893 if (b2 != null) b1.addSuccessor(b2); |
| 7867 } | 7894 } |
| 7895 |
| 7868 addExitTrySuccessor(successor) { | 7896 addExitTrySuccessor(successor) { |
| 7869 if (successor == null) return; | 7897 if (successor == null) return; |
| 7870 // Iterate over all blocks created inside this try/catch, and | 7898 // Iterate over all blocks created inside this try/catch, and |
| 7871 // attach successor information to blocks that end with | 7899 // attach successor information to blocks that end with |
| 7872 // [HExitTry]. | 7900 // [HExitTry]. |
| 7873 for (int i = startTryBlock.id; i < successor.id; i++) { | 7901 for (int i = startTryBlock.id; i < successor.id; i++) { |
| 7874 HBasicBlock block = graph.blocks[i]; | 7902 HBasicBlock block = graph.blocks[i]; |
| 7875 var last = block.last; | 7903 var last = block.last; |
| 7876 if (last is HExitTry) { | 7904 if (last is HExitTry) { |
| 7877 block.addSuccessor(successor); | 7905 block.addSuccessor(successor); |
| (...skipping 753 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8631 const _LoopTypeVisitor(); | 8659 const _LoopTypeVisitor(); |
| 8632 int visitNode(ast.Node node) => HLoopBlockInformation.NOT_A_LOOP; | 8660 int visitNode(ast.Node node) => HLoopBlockInformation.NOT_A_LOOP; |
| 8633 int visitWhile(ast.While node) => HLoopBlockInformation.WHILE_LOOP; | 8661 int visitWhile(ast.While node) => HLoopBlockInformation.WHILE_LOOP; |
| 8634 int visitFor(ast.For node) => HLoopBlockInformation.FOR_LOOP; | 8662 int visitFor(ast.For node) => HLoopBlockInformation.FOR_LOOP; |
| 8635 int visitDoWhile(ast.DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP; | 8663 int visitDoWhile(ast.DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP; |
| 8636 int visitAsyncForIn(ast.AsyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; | 8664 int visitAsyncForIn(ast.AsyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; |
| 8637 int visitSyncForIn(ast.SyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; | 8665 int visitSyncForIn(ast.SyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; |
| 8638 int visitSwitchStatement(ast.SwitchStatement node) => | 8666 int visitSwitchStatement(ast.SwitchStatement node) => |
| 8639 HLoopBlockInformation.SWITCH_CONTINUE_LOOP; | 8667 HLoopBlockInformation.SWITCH_CONTINUE_LOOP; |
| 8640 } | 8668 } |
| OLD | NEW |