Chromium Code Reviews| 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 |