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 3120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3131 } | 3131 } |
| 3132 startBlock.setBlockFlow( | 3132 startBlock.setBlockFlow( |
| 3133 new HLabeledBlockInformation.implicit( | 3133 new HLabeledBlockInformation.implicit( |
| 3134 new HSubGraphBlockInformation(new SubGraph(startBlock, lastBlock)), | 3134 new HSubGraphBlockInformation(new SubGraph(startBlock, lastBlock)), |
| 3135 elements[node]), | 3135 elements[node]), |
| 3136 joinBlock); | 3136 joinBlock); |
| 3137 jumpHandler.close(); | 3137 jumpHandler.close(); |
| 3138 } | 3138 } |
| 3139 | 3139 |
| 3140 bool tryBuildConstantSwitch(SwitchStatement node) { | 3140 bool tryBuildConstantSwitch(SwitchStatement node) { |
| 3141 // TODO(lrn): Move the constant resolution to the resolver, so | |
| 3142 // we can report an error before reaching the backend. | |
| 3141 Map<CaseMatch, Constant> constants = new Map<CaseMatch, Constant>(); | 3143 Map<CaseMatch, Constant> constants = new Map<CaseMatch, Constant>(); |
| 3142 // First check whether all case expressions are compile-time constants. | 3144 // First check whether all case expressions are compile-time constants, |
| 3145 // and all have the same type that doesn't override operator==. | |
| 3146 Constant firstConstant = null; | |
| 3147 bool failure = false; | |
| 3143 for (SwitchCase switchCase in node.cases) { | 3148 for (SwitchCase switchCase in node.cases) { |
| 3144 for (Node labelOrCase in switchCase.labelsAndCases) { | 3149 for (Node labelOrCase in switchCase.labelsAndCases) { |
| 3145 if (labelOrCase is CaseMatch) { | 3150 if (labelOrCase is CaseMatch) { |
| 3146 CaseMatch match = labelOrCase; | 3151 CaseMatch match = labelOrCase; |
| 3147 Constant constant = | 3152 Constant constant = |
| 3148 compiler.constantHandler.tryCompileNodeWithDefinitions( | 3153 compiler.constantHandler.tryCompileNodeWithDefinitions( |
| 3149 match.expression, elements); | 3154 match.expression, elements); |
| 3150 if (constant === null) return false; | 3155 if (constant === null) { |
| 3156 compiler.reportWarning(match.expression, | |
| 3157 MessageKind.NOT_A_COMPILE_TIME_CONSTANT.error()); | |
| 3158 failure = true; | |
| 3159 continue; | |
| 3160 } | |
| 3161 if (firstConstant == null) { | |
| 3162 firstConstant = constant; | |
| 3163 if (nonPrimitiveTypeOverridesEquals(constant)) { | |
| 3164 compiler.reportWarning(match.expression, | |
| 3165 MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS.error()); | |
| 3166 failure = true; | |
| 3167 } | |
| 3168 } else { | |
| 3169 if (!constant.isSameType(firstConstant)) { | |
| 3170 compiler.reportWarning(match.expression, | |
| 3171 MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL.error()); | |
| 3172 failure = true; | |
| 3173 } | |
| 3174 } | |
| 3151 constants[labelOrCase] = constant; | 3175 constants[labelOrCase] = constant; |
| 3152 } else { | 3176 } else { |
| 3153 // We don't handle labels yet. | 3177 compiler.reportWarning(node, "Unsupported: Labels on cases"); |
| 3154 return false; | 3178 failure = true; |
| 3155 } | 3179 } |
| 3156 } | 3180 } |
| 3157 } | 3181 } |
| 3182 if (failure) { | |
| 3183 return false; | |
| 3184 } | |
| 3185 | |
| 3158 // TODO(ngeoffray): Handle switch-instruction in bailout code. | 3186 // TODO(ngeoffray): Handle switch-instruction in bailout code. |
| 3159 work.allowSpeculativeOptimization = false; | 3187 work.allowSpeculativeOptimization = false; |
| 3160 // Then build a switch structure. | 3188 // Then build a switch structure. |
| 3161 HBasicBlock expressionStart = openNewBlock(); | 3189 HBasicBlock expressionStart = openNewBlock(); |
| 3162 visit(node.expression); | 3190 visit(node.expression); |
| 3163 HInstruction expression = pop(); | 3191 HInstruction expression = pop(); |
| 3164 if (node.cases.isEmpty()) { | 3192 if (node.cases.isEmpty()) { |
| 3165 return true; | 3193 return true; |
| 3166 } | 3194 } |
| 3167 HBasicBlock expressionEnd = current; | 3195 HBasicBlock expressionEnd = current; |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3259 statements, | 3287 statements, |
| 3260 hasDefault, | 3288 hasDefault, |
| 3261 jumpHandler.target, | 3289 jumpHandler.target, |
| 3262 jumpHandler.labels()), | 3290 jumpHandler.labels()), |
| 3263 joinBlock); | 3291 joinBlock); |
| 3264 | 3292 |
| 3265 jumpHandler.close(); | 3293 jumpHandler.close(); |
| 3266 return true; | 3294 return true; |
| 3267 } | 3295 } |
| 3268 | 3296 |
| 3297 bool nonPrimitiveTypeOverridesEquals(Constant constant) { | |
| 3298 // If constant is primitive, just return false. We know | |
| 3299 // about the equals methods of num/String classes. | |
| 3300 // [Map] and [List] does not override equals. | |
|
floitsch
2012/08/30 14:08:18
do not
Lasse Reichstein Nielsen
2012/09/03 09:12:56
Done.
| |
| 3301 if (!constant.isConstructedObject()) return false; | |
| 3302 | |
| 3303 ConstructedConstant constructedConstant = constant; | |
| 3304 Type type = constructedConstant.type; | |
| 3305 assert(type !== null); | |
| 3306 Element element = type.element; | |
|
ngeoffray
2012/08/30 07:29:13
The code below probably deserves to be in a helper
Lasse Reichstein Nielsen
2012/08/30 10:54:25
Any wish for the abstraction level?
isOverridingEq
ngeoffray
2012/08/30 11:07:13
I like the three of them :) The first two are easy
Lasse Reichstein Nielsen
2012/09/03 09:12:56
I went with
typeOverridesObjectEquals
and
lookup
| |
| 3307 // If the type is not a class, we'll just assume it overrides | |
| 3308 // operator==. Typedefs do, since [Function] does. | |
| 3309 if (!element.isClass()) return true; | |
| 3310 ClassElement classElement = element; | |
| 3311 SourceString dartMethodName = Elements.constructOperatorName( | |
| 3312 const SourceString('operator'), | |
| 3313 const SourceString('==')); | |
| 3314 Element operatorEq = classElement.lookupMember(dartMethodName); | |
| 3315 if (operatorEq == null) return false; | |
| 3316 // If the operator== declaration is in Object, it's not overridden. | |
| 3317 return (operatorEq.getEnclosingClass() != compiler.objectClass); | |
| 3318 } | |
| 3319 | |
| 3269 | 3320 |
| 3270 // Recursively build an if/else structure to match the cases. | 3321 // Recursively build an if/else structure to match the cases. |
| 3271 void buildSwitchCases(Link<Node> cases, HInstruction expression, | 3322 void buildSwitchCases(Link<Node> cases, HInstruction expression, |
| 3272 [int encounteredCaseTypes = 0]) { | 3323 [int encounteredCaseTypes = 0]) { |
| 3273 final int NO_TYPE = 0; | 3324 final int NO_TYPE = 0; |
| 3274 final int INT_TYPE = 1; | 3325 final int INT_TYPE = 1; |
| 3275 final int STRING_TYPE = 2; | 3326 final int STRING_TYPE = 2; |
| 3276 final int CONFLICT_TYPE = 3; | 3327 final int CONFLICT_TYPE = 3; |
| 3277 int combine(int type1, int type2) => type1 | type2; | 3328 int combine(int type1, int type2) => type1 | type2; |
| 3278 | 3329 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3319 Element equalsHelper = interceptors.getEqualsInterceptor(); | 3370 Element equalsHelper = interceptors.getEqualsInterceptor(); |
| 3320 HInstruction target = new HStatic(equalsHelper); | 3371 HInstruction target = new HStatic(equalsHelper); |
| 3321 add(target); | 3372 add(target); |
| 3322 CaseMatch match = remainingCases.head; | 3373 CaseMatch match = remainingCases.head; |
| 3323 // TODO(lrn): Move the constant resolution to the resolver, so | 3374 // TODO(lrn): Move the constant resolution to the resolver, so |
| 3324 // we can report an error before reaching the backend. | 3375 // we can report an error before reaching the backend. |
| 3325 Constant constant = | 3376 Constant constant = |
| 3326 compiler.constantHandler.tryCompileNodeWithDefinitions( | 3377 compiler.constantHandler.tryCompileNodeWithDefinitions( |
| 3327 match.expression, elements); | 3378 match.expression, elements); |
| 3328 if (constant !== null) { | 3379 if (constant !== null) { |
| 3329 if (constant.isInt()) { | |
| 3330 // Report the first mixed-string/int type error only. | |
| 3331 if (encounteredCaseTypes == STRING_TYPE) { | |
| 3332 compiler.reportWarning( | |
| 3333 match, MessageKind.INVALID_CASE_EXPRESSION_TYPE); | |
| 3334 } | |
| 3335 encounteredCaseTypes = combine(encounteredCaseTypes, INT_TYPE); | |
| 3336 } else if (constant.isString()) { | |
| 3337 if (encounteredCaseTypes == INT_TYPE) { | |
| 3338 compiler.reportWarning( | |
| 3339 match, MessageKind.INVALID_CASE_EXPRESSION_TYPE); | |
| 3340 } | |
| 3341 encounteredCaseTypes = combine(encounteredCaseTypes, STRING_TYPE); | |
| 3342 } else { | |
| 3343 compiler.reportWarning(match, | |
| 3344 MessageKind.INVALID_CASE_EXPRESSION); | |
| 3345 encounteredCaseTypes = CONFLICT_TYPE; | |
| 3346 } | |
| 3347 stack.add(graph.addConstant(constant)); | 3380 stack.add(graph.addConstant(constant)); |
| 3348 } else { | 3381 } else { |
| 3349 // TODO(lrn): Remove this else branch, and make the constant | |
| 3350 // evaluation mandatory when we are ready to break existing code using | |
| 3351 // non constant-int-or-string expressions. | |
| 3352 compiler.reportWarning(match, | |
| 3353 'case expressions not compile-time constant int or string.'); | |
| 3354 visit(match.expression); | 3382 visit(match.expression); |
| 3355 encounteredCaseTypes = CONFLICT_TYPE; | |
| 3356 } | 3383 } |
| 3357 push(new HEquals(target, pop(), expression)); | 3384 push(new HEquals(target, pop(), expression)); |
| 3358 } | 3385 } |
| 3359 | 3386 |
| 3360 // If this is the last expression, just return it. | 3387 // If this is the last expression, just return it. |
| 3361 Link<Node> tail = skipLabels(remainingCases.tail); | 3388 Link<Node> tail = skipLabels(remainingCases.tail); |
| 3362 if (tail.isEmpty()) { | 3389 if (tail.isEmpty()) { |
| 3363 left(); | 3390 left(); |
| 3364 return; | 3391 return; |
| 3365 } | 3392 } |
| (...skipping 573 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3939 new HSubGraphBlockInformation(elseBranch.graph)); | 3966 new HSubGraphBlockInformation(elseBranch.graph)); |
| 3940 | 3967 |
| 3941 HBasicBlock conditionStartBlock = conditionBranch.block; | 3968 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 3942 conditionStartBlock.setBlockFlow(info, joinBlock); | 3969 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 3943 SubGraph conditionGraph = conditionBranch.graph; | 3970 SubGraph conditionGraph = conditionBranch.graph; |
| 3944 HIf branch = conditionGraph.end.last; | 3971 HIf branch = conditionGraph.end.last; |
| 3945 assert(branch is HIf); | 3972 assert(branch is HIf); |
| 3946 branch.blockInformation = conditionStartBlock.blockFlow; | 3973 branch.blockInformation = conditionStartBlock.blockFlow; |
| 3947 } | 3974 } |
| 3948 } | 3975 } |
| OLD | NEW |