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 class Interceptors { | 5 class Interceptors { |
6 Compiler compiler; | 6 Compiler compiler; |
7 Interceptors(Compiler this.compiler); | 7 Interceptors(Compiler this.compiler); |
8 | 8 |
9 SourceString mapOperatorToMethodName(Operator op) { | 9 SourceString mapOperatorToMethodName(Operator op) { |
10 String name = op.source.stringValue; | 10 String name = op.source.stringValue; |
(...skipping 2903 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2914 visitLiteralMapEntry(LiteralMapEntry node) { | 2914 visitLiteralMapEntry(LiteralMapEntry node) { |
2915 visit(node.value); | 2915 visit(node.value); |
2916 visit(node.key); | 2916 visit(node.key); |
2917 } | 2917 } |
2918 | 2918 |
2919 visitNamedArgument(NamedArgument node) { | 2919 visitNamedArgument(NamedArgument node) { |
2920 visit(node.expression); | 2920 visit(node.expression); |
2921 } | 2921 } |
2922 | 2922 |
2923 visitSwitchStatement(SwitchStatement node) { | 2923 visitSwitchStatement(SwitchStatement node) { |
| 2924 if (tryBuildConstantSwitch(node)) return; |
| 2925 |
2924 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | 2926 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
2925 HBasicBlock startBlock = openNewBlock(); | 2927 HBasicBlock startBlock = openNewBlock(); |
2926 visit(node.expression); | 2928 visit(node.expression); |
2927 HInstruction expression = pop(); | 2929 HInstruction expression = pop(); |
2928 if (node.cases.isEmpty()) { | 2930 if (node.cases.isEmpty()) { |
2929 return; | 2931 return; |
2930 } | 2932 } |
| 2933 |
2931 Link<Node> cases = node.cases.nodes; | 2934 Link<Node> cases = node.cases.nodes; |
2932 | |
2933 JumpHandler jumpHandler = createJumpHandler(node); | 2935 JumpHandler jumpHandler = createJumpHandler(node); |
2934 | 2936 |
2935 buildSwitchCases(cases, expression); | 2937 buildSwitchCases(cases, expression); |
2936 | 2938 |
2937 HBasicBlock lastBlock = lastOpenedBlock; | 2939 HBasicBlock lastBlock = lastOpenedBlock; |
2938 | 2940 |
2939 // Create merge block for break targets. | 2941 // Create merge block for break targets. |
2940 HBasicBlock joinBlock = new HBasicBlock(); | 2942 HBasicBlock joinBlock = new HBasicBlock(); |
2941 List<LocalsHandler> caseLocals = <LocalsHandler>[]; | 2943 List<LocalsHandler> caseLocals = <LocalsHandler>[]; |
2942 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { | 2944 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { |
(...skipping 20 matching lines...) Expand all Loading... |
2963 joinBlock = null; | 2965 joinBlock = null; |
2964 } | 2966 } |
2965 startBlock.setBlockFlow( | 2967 startBlock.setBlockFlow( |
2966 new HLabeledBlockInformation.implicit( | 2968 new HLabeledBlockInformation.implicit( |
2967 new HSubGraphBlockInformation(new SubGraph(startBlock, lastBlock)), | 2969 new HSubGraphBlockInformation(new SubGraph(startBlock, lastBlock)), |
2968 elements[node]), | 2970 elements[node]), |
2969 joinBlock); | 2971 joinBlock); |
2970 jumpHandler.close(); | 2972 jumpHandler.close(); |
2971 } | 2973 } |
2972 | 2974 |
| 2975 bool tryBuildConstantSwitch(SwitchStatement node) { |
| 2976 Map<CaseMatch, Constant> constants = new Map<CaseMatch, Constant>(); |
| 2977 // First check whether all case expressions are compile-time constants. |
| 2978 for (SwitchCase switchCase in node.cases) { |
| 2979 for (Node labelOrCase in switchCase.labelsAndCases) { |
| 2980 if (labelOrCase is CaseMatch) { |
| 2981 CaseMatch match = labelOrCase; |
| 2982 Constant constant = |
| 2983 compiler.constantHandler.tryCompileNodeWithDefinitions( |
| 2984 match.expression, elements); |
| 2985 if (constant === null) return false; |
| 2986 constants[labelOrCase] = constant; |
| 2987 } else { |
| 2988 // We don't handle labels yet. |
| 2989 return false; |
| 2990 } |
| 2991 } |
| 2992 } |
| 2993 // TODO(ngeoffray): Handle switch-instruction in bailout code. |
| 2994 work.allowSpeculativeOptimization = false; |
| 2995 // Then build a switch structure. |
| 2996 HBasicBlock expressionStart = openNewBlock(); |
| 2997 visit(node.expression); |
| 2998 HInstruction expression = pop(); |
| 2999 if (node.cases.isEmpty()) { |
| 3000 return true; |
| 3001 } |
| 3002 HBasicBlock expressionEnd = current; |
| 3003 |
| 3004 HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]); |
| 3005 HBasicBlock expressionBlock = close(switchInstruction); |
| 3006 JumpHandler jumpHandler = createJumpHandler(node); |
| 3007 LocalsHandler savedLocals = localsHandler; |
| 3008 |
| 3009 List<List<Constant>> matchExpressions = <List<Constant>>[]; |
| 3010 List<HStatementInformation> statements = <HStatementInformation>[]; |
| 3011 bool hasDefault = false; |
| 3012 Element getFallThroughErrorElement = |
| 3013 compiler.findHelper(const SourceString("getFallThroughError")); |
| 3014 Iterator<Node> caseIterator = node.cases.iterator(); |
| 3015 while (caseIterator.hasNext()) { |
| 3016 SwitchCase switchCase = caseIterator.next(); |
| 3017 List<Constant> caseConstants = <Constant>[]; |
| 3018 HBasicBlock block = graph.addNewBlock(); |
| 3019 for (Node labelOrCase in switchCase.labelsAndCases) { |
| 3020 if (labelOrCase is CaseMatch) { |
| 3021 Constant constant = constants[labelOrCase]; |
| 3022 caseConstants.add(constant); |
| 3023 HConstant hConstant = graph.addConstant(constant); |
| 3024 switchInstruction.inputs.add(hConstant); |
| 3025 hConstant.usedBy.add(switchInstruction); |
| 3026 expressionBlock.addSuccessor(block); |
| 3027 } |
| 3028 } |
| 3029 matchExpressions.add(caseConstants); |
| 3030 |
| 3031 if (switchCase.isDefaultCase) { |
| 3032 // An HSwitch has n inputs and n+1 successors, the last being the |
| 3033 // default case. |
| 3034 expressionBlock.addSuccessor(block); |
| 3035 hasDefault = true; |
| 3036 } |
| 3037 open(block); |
| 3038 localsHandler = new LocalsHandler.from(savedLocals); |
| 3039 visit(switchCase.statements); |
| 3040 if (!isAborted() && caseIterator.hasNext()) { |
| 3041 push(new HStatic(getFallThroughErrorElement)); |
| 3042 HInstruction error = new HInvokeStatic( |
| 3043 Selector.INVOCATION_0, <HInstruction>[pop()]); |
| 3044 add(error); |
| 3045 close(new HThrow(error)); |
| 3046 } |
| 3047 statements.add( |
| 3048 new HSubGraphBlockInformation(new SubGraph(block, lastOpenedBlock))); |
| 3049 } |
| 3050 |
| 3051 // Add a join-block if necessary. |
| 3052 // We create [joinBlock] early, and then go through the cases that might |
| 3053 // want to jump to it. In each case, if we add [joinBlock] as a successor |
| 3054 // of another block, we also add an element to [caseLocals] that is used |
| 3055 // to create the phis in [joinBlock]. |
| 3056 // If we never jump to the join block, [caseLocals] will stay empty, and |
| 3057 // the join block is never added to the graph. |
| 3058 HBasicBlock joinBlock = new HBasicBlock(); |
| 3059 List<LocalsHandler> caseLocals = <LocalsHandler>[]; |
| 3060 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { |
| 3061 instruction.block.addSuccessor(joinBlock); |
| 3062 caseLocals.add(locals); |
| 3063 }); |
| 3064 if (!isAborted()) { |
| 3065 current.close(new HGoto()); |
| 3066 lastOpenedBlock.addSuccessor(joinBlock); |
| 3067 caseLocals.add(localsHandler); |
| 3068 } |
| 3069 if (!hasDefault) { |
| 3070 // The current flow is only aborted if the switch has a default that |
| 3071 // aborts (all previous cases must abort, and if there is no default, |
| 3072 // it's possible to miss all the cases). |
| 3073 expressionEnd.addSuccessor(joinBlock); |
| 3074 caseLocals.add(savedLocals); |
| 3075 } |
| 3076 assert(caseLocals.length == joinBlock.predecessors.length); |
| 3077 if (caseLocals.length != 0) { |
| 3078 graph.addBlock(joinBlock); |
| 3079 open(joinBlock); |
| 3080 if (caseLocals.length == 1) { |
| 3081 localsHandler = caseLocals[0]; |
| 3082 } else { |
| 3083 localsHandler = savedLocals.mergeMultiple(caseLocals, joinBlock); |
| 3084 } |
| 3085 } else { |
| 3086 // The joinblock is not used. |
| 3087 joinBlock = null; |
| 3088 } |
| 3089 |
| 3090 HSubExpressionBlockInformation expressionInfo = |
| 3091 new HSubExpressionBlockInformation(new SubExpression(expressionStart, |
| 3092 expressionEnd)); |
| 3093 expressionStart.setBlockFlow( |
| 3094 new HSwitchBlockInformation(expressionInfo, |
| 3095 matchExpressions, |
| 3096 statements, |
| 3097 hasDefault, |
| 3098 jumpHandler.target, |
| 3099 jumpHandler.labels()), |
| 3100 joinBlock); |
| 3101 |
| 3102 jumpHandler.close(); |
| 3103 return true; |
| 3104 } |
| 3105 |
2973 | 3106 |
2974 // Recursively build an if/else structure to match the cases. | 3107 // Recursively build an if/else structure to match the cases. |
2975 buildSwitchCases(Link<Node> cases, HInstruction expression, | 3108 void buildSwitchCases(Link<Node> cases, HInstruction expression, |
2976 [int encounteredCaseTypes = 0]) { | 3109 [int encounteredCaseTypes = 0]) { |
2977 final int NO_TYPE = 0; | 3110 final int NO_TYPE = 0; |
2978 final int INT_TYPE = 1; | 3111 final int INT_TYPE = 1; |
2979 final int STRING_TYPE = 2; | 3112 final int STRING_TYPE = 2; |
2980 final int CONFLICT_TYPE = 3; | 3113 final int CONFLICT_TYPE = 3; |
2981 int combine(int type1, int type2) => type1 | type2; | 3114 int combine(int type1, int type2) => type1 | type2; |
2982 | 3115 |
2983 SwitchCase node = cases.head; | 3116 SwitchCase node = cases.head; |
2984 // Called for the statements on all but the last case block. | 3117 // Called for the statements on all but the last case block. |
2985 // Ensures that a user expecting a fallthrough gets an error. | 3118 // Ensures that a user expecting a fallthrough gets an error. |
2986 void visitStatementsAndAbort() { | 3119 void visitStatementsAndAbort() { |
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3393 <HInstruction>[target, input], | 3526 <HInstruction>[target, input], |
3394 HType.STRING)); | 3527 HType.STRING)); |
3395 return builder.pop(); | 3528 return builder.pop(); |
3396 } | 3529 } |
3397 | 3530 |
3398 HInstruction result(Node node) { | 3531 HInstruction result(Node node) { |
3399 flushLiterals(node); | 3532 flushLiterals(node); |
3400 return prefix; | 3533 return prefix; |
3401 } | 3534 } |
3402 } | 3535 } |
OLD | NEW |