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 2923 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2934 visitLiteralMapEntry(LiteralMapEntry node) { | 2934 visitLiteralMapEntry(LiteralMapEntry node) { |
2935 visit(node.value); | 2935 visit(node.value); |
2936 visit(node.key); | 2936 visit(node.key); |
2937 } | 2937 } |
2938 | 2938 |
2939 visitNamedArgument(NamedArgument node) { | 2939 visitNamedArgument(NamedArgument node) { |
2940 visit(node.expression); | 2940 visit(node.expression); |
2941 } | 2941 } |
2942 | 2942 |
2943 visitSwitchStatement(SwitchStatement node) { | 2943 visitSwitchStatement(SwitchStatement node) { |
2944 if (tryBuildConstantSwitch(node)) return; | |
2945 | |
2944 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | 2946 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
2945 HBasicBlock startBlock = openNewBlock(); | 2947 HBasicBlock startBlock = openNewBlock(); |
2946 visit(node.expression); | 2948 visit(node.expression); |
2947 HInstruction expression = pop(); | 2949 HInstruction expression = pop(); |
2948 if (node.cases.isEmpty()) { | 2950 if (node.cases.isEmpty()) { |
2949 return; | 2951 return; |
2950 } | 2952 } |
2953 | |
2951 Link<Node> cases = node.cases.nodes; | 2954 Link<Node> cases = node.cases.nodes; |
2952 | |
2953 JumpHandler jumpHandler = createJumpHandler(node); | 2955 JumpHandler jumpHandler = createJumpHandler(node); |
2954 | 2956 |
2955 buildSwitchCases(cases, expression); | 2957 buildSwitchCases(cases, expression); |
2956 | 2958 |
2957 HBasicBlock lastBlock = lastOpenedBlock; | 2959 HBasicBlock lastBlock = lastOpenedBlock; |
2958 | 2960 |
2959 // Create merge block for break targets. | 2961 // Create merge block for break targets. |
2960 HBasicBlock joinBlock = new HBasicBlock(); | 2962 HBasicBlock joinBlock = new HBasicBlock(); |
2961 List<LocalsHandler> caseLocals = <LocalsHandler>[]; | 2963 List<LocalsHandler> caseLocals = <LocalsHandler>[]; |
2962 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { | 2964 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { |
(...skipping 20 matching lines...) Expand all Loading... | |
2983 joinBlock = null; | 2985 joinBlock = null; |
2984 } | 2986 } |
2985 startBlock.setBlockFlow( | 2987 startBlock.setBlockFlow( |
2986 new HLabeledBlockInformation.implicit( | 2988 new HLabeledBlockInformation.implicit( |
2987 new HSubGraphBlockInformation(new SubGraph(startBlock, lastBlock)), | 2989 new HSubGraphBlockInformation(new SubGraph(startBlock, lastBlock)), |
2988 elements[node]), | 2990 elements[node]), |
2989 joinBlock); | 2991 joinBlock); |
2990 jumpHandler.close(); | 2992 jumpHandler.close(); |
2991 } | 2993 } |
2992 | 2994 |
2995 bool tryBuildConstantSwitch(SwitchStatement node) { | |
2996 Map<CaseMatch, Constant> constants = new Map<CaseMatch, Constant>(); | |
2997 // First check whether all case expressions are compile-time constants. | |
2998 for (SwitchCase switchCase in node.cases) { | |
2999 for (Node labelOrCase in switchCase.labelsAndCases) { | |
3000 if (labelOrCase is CaseMatch) { | |
3001 CaseMatch match = labelOrCase; | |
3002 Constant constant = | |
3003 compiler.constantHandler.tryCompileNodeWithDefinitions( | |
3004 match.expression, elements); | |
3005 if (constant === null) return false; | |
3006 constants[labelOrCase] = constant; | |
3007 } else { | |
3008 // We don't handle labels yet. | |
3009 return false; | |
3010 } | |
3011 } | |
3012 } | |
3013 // TODO(ngeoffray): Handle switch-instruction in bailout code. | |
Lasse Reichstein Nielsen
2012/06/06 09:29:31
I hope it's simple if you know how :)
| |
3014 work.allowSpeculativeOptimization = false; | |
3015 // Then build a switch structure. | |
3016 HBasicBlock expressionStart = openNewBlock(); | |
3017 visit(node.expression); | |
3018 HInstruction expression = pop(); | |
3019 if (node.cases.isEmpty()) { | |
3020 return true; | |
3021 } | |
3022 HBasicBlock expressionEnd = current; | |
3023 | |
3024 HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]); | |
3025 HBasicBlock expressionBlock = close(switchInstruction); | |
3026 JumpHandler jumpHandler = createJumpHandler(node); | |
3027 LocalsHandler savedLocals = localsHandler; | |
3028 | |
3029 List<List<Constant>> matchExpressions = <List<Constant>>[]; | |
3030 List<HStatementInformation> statements = <HStatementInformation>[]; | |
3031 bool hasDefault = false; | |
3032 for (Iterator<Node> iterator = node.cases.iterator(); iterator.hasNext();) { | |
floitsch
2012/06/06 11:50:26
I would prefer a while loop.
Lasse Reichstein Nielsen
2012/06/06 13:01:21
Done.
| |
3033 SwitchCase switchCase = iterator.next(); | |
3034 List<Constant> caseConstants = <Constant>[]; | |
3035 HBasicBlock block = graph.addNewBlock(); | |
3036 for (Node labelOrCase in switchCase.labelsAndCases) { | |
3037 if (labelOrCase is CaseMatch) { | |
floitsch
2012/06/06 11:50:26
At the moment an assert would work too here, no?
Lasse Reichstein Nielsen
2012/06/06 13:01:21
No, we still parse the labels, we just don't do an
floitsch
2012/06/06 14:32:01
But isn't there a "return false" in line 3009 for
Lasse Reichstein Nielsen
2012/06/07 12:03:05
True, there is. Let's not make the assumption in m
| |
3038 Constant constant = constants[labelOrCase]; | |
3039 caseConstants.add(constant); | |
3040 HConstant hConstant = graph.addConstant(constant); | |
3041 switchInstruction.inputs.add(hConstant); | |
3042 hConstant.usedBy.add(switchInstruction); | |
3043 expressionBlock.addSuccessor(block); | |
3044 } | |
3045 } | |
3046 matchExpressions.add(caseConstants); | |
3047 | |
3048 if (switchCase.isDefaultCase) { | |
3049 // An HSwitch has n inputs and n+1 successors, the last being the | |
3050 // default case. | |
3051 expressionBlock.addSuccessor(block); | |
3052 hasDefault = true; | |
3053 } | |
3054 open(block); | |
3055 localsHandler = new LocalsHandler.from(savedLocals); | |
3056 visit(switchCase.statements); | |
3057 if (!isAborted() && iterator.hasNext()) { | |
3058 compiler.reportWarning(node, 'Missing break at end of switch case'); | |
ngeoffray
2012/06/06 12:03:46
I don't think the codegen should emit a warning.
Lasse Reichstein Nielsen
2012/06/06 13:01:21
True. Something earlier should do that.
I'll remo
| |
3059 Element element = | |
3060 compiler.findHelper(const SourceString("getFallThroughError")); | |
ngeoffray
2012/06/06 12:03:46
Maybe move that call out of the loop?
Lasse Reichstein Nielsen
2012/06/06 13:01:21
Reasonable. Done.
| |
3061 push(new HStatic(element)); | |
3062 HInstruction error = new HInvokeStatic( | |
3063 Selector.INVOCATION_0, <HInstruction>[pop()]); | |
3064 add(error); | |
3065 close(new HThrow(error)); | |
3066 } | |
3067 statements.add( | |
3068 new HSubGraphBlockInformation(new SubGraph(block, lastOpenedBlock))); | |
3069 } | |
3070 | |
3071 // Add a join-block if necessary. | |
3072 HBasicBlock joinBlock = new HBasicBlock(); | |
3073 List<LocalsHandler> caseLocals = <LocalsHandler>[]; | |
3074 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { | |
3075 instruction.block.addSuccessor(joinBlock); | |
3076 caseLocals.add(locals); | |
3077 }); | |
3078 if (!isAborted()) { | |
ngeoffray
2012/06/06 12:03:46
Should this check be in the one line 3090? You're
Lasse Reichstein Nielsen
2012/06/06 13:01:21
If this test succeedes, it adds an element to case
| |
3079 current.close(new HGoto()); | |
3080 lastOpenedBlock.addSuccessor(joinBlock); | |
3081 caseLocals.add(localsHandler); | |
3082 } | |
3083 if (!hasDefault) { | |
ngeoffray
2012/06/06 12:03:46
ditto
Lasse Reichstein Nielsen
2012/06/06 13:01:21
And ditto.
| |
3084 // The current flow is only aborted if the switch has a default that | |
3085 // aborts (all previous cases must abort, and if there is no default, | |
3086 // it's possible to miss all the cases). | |
3087 expressionEnd.addSuccessor(joinBlock); | |
3088 caseLocals.add(savedLocals); | |
3089 } | |
3090 if (caseLocals.length != 0) { | |
3091 graph.addBlock(joinBlock); | |
3092 open(joinBlock); | |
3093 if (caseLocals.length == 1) { | |
3094 localsHandler = caseLocals[0]; | |
3095 } else { | |
3096 localsHandler = savedLocals.mergeMultiple(caseLocals, joinBlock); | |
3097 } | |
3098 } else { | |
3099 // The joinblock is not used. | |
3100 joinBlock = null; | |
3101 } | |
3102 | |
3103 HSubExpressionBlockInformation expressionInfo = | |
3104 new HSubExpressionBlockInformation(new SubExpression(expressionStart, | |
3105 expressionEnd)); | |
3106 expressionStart.setBlockFlow( | |
3107 new HSwitchBlockInformation(expressionInfo, | |
3108 matchExpressions, | |
3109 statements, | |
3110 hasDefault, | |
3111 jumpHandler.target, | |
3112 jumpHandler.labels()), | |
3113 joinBlock); | |
3114 | |
3115 jumpHandler.close(); | |
3116 return true; | |
3117 } | |
3118 | |
2993 | 3119 |
2994 // Recursively build an if/else structure to match the cases. | 3120 // Recursively build an if/else structure to match the cases. |
2995 buildSwitchCases(Link<Node> cases, HInstruction expression, | 3121 void buildSwitchCases(Link<Node> cases, HInstruction expression, |
2996 [int encounteredCaseTypes = 0]) { | 3122 [int encounteredCaseTypes = 0]) { |
2997 final int NO_TYPE = 0; | 3123 final int NO_TYPE = 0; |
2998 final int INT_TYPE = 1; | 3124 final int INT_TYPE = 1; |
2999 final int STRING_TYPE = 2; | 3125 final int STRING_TYPE = 2; |
3000 final int CONFLICT_TYPE = 3; | 3126 final int CONFLICT_TYPE = 3; |
3001 int combine(int type1, int type2) => type1 | type2; | 3127 int combine(int type1, int type2) => type1 | type2; |
3002 | 3128 |
3003 SwitchCase node = cases.head; | 3129 SwitchCase node = cases.head; |
3004 // Called for the statements on all but the last case block. | 3130 // Called for the statements on all but the last case block. |
3005 // Ensures that a user expecting a fallthrough gets an error. | 3131 // Ensures that a user expecting a fallthrough gets an error. |
3006 void visitStatementsAndAbort() { | 3132 void visitStatementsAndAbort() { |
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3413 <HInstruction>[target, input], | 3539 <HInstruction>[target, input], |
3414 HType.STRING)); | 3540 HType.STRING)); |
3415 return builder.pop(); | 3541 return builder.pop(); |
3416 } | 3542 } |
3417 | 3543 |
3418 HInstruction result(Node node) { | 3544 HInstruction result(Node node) { |
3419 flushLiterals(node); | 3545 flushLiterals(node); |
3420 return prefix; | 3546 return prefix; |
3421 } | 3547 } |
3422 } | 3548 } |
OLD | NEW |