| 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 library dart2js.constant_system.dart; | 5 library dart2js.constant_system.dart; |
| 6 | 6 |
| 7 import 'compiler.dart' show | 7 import 'compiler.dart' show Compiler; |
| 8 Compiler; | |
| 9 import 'constants/constant_system.dart'; | 8 import 'constants/constant_system.dart'; |
| 10 import 'constants/values.dart'; | 9 import 'constants/values.dart'; |
| 11 import 'dart_types.dart'; | 10 import 'dart_types.dart'; |
| 12 import 'tree/tree.dart' show | 11 import 'tree/tree.dart' show DartString; |
| 13 DartString; | |
| 14 | 12 |
| 15 const DART_CONSTANT_SYSTEM = const DartConstantSystem(); | 13 const DART_CONSTANT_SYSTEM = const DartConstantSystem(); |
| 16 | 14 |
| 17 class BitNotOperation implements UnaryOperation { | 15 class BitNotOperation implements UnaryOperation { |
| 18 final String name = '~'; | 16 final String name = '~'; |
| 19 const BitNotOperation(); | 17 const BitNotOperation(); |
| 20 ConstantValue fold(ConstantValue constant) { | 18 ConstantValue fold(ConstantValue constant) { |
| 21 if (constant.isInt) { | 19 if (constant.isInt) { |
| 22 IntConstantValue intConstant = constant; | 20 IntConstantValue intConstant = constant; |
| 23 return DART_CONSTANT_SYSTEM.createInt(~intConstant.primitiveValue); | 21 return DART_CONSTANT_SYSTEM.createInt(~intConstant.primitiveValue); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 } | 68 } |
| 71 return null; | 69 return null; |
| 72 } | 70 } |
| 73 | 71 |
| 74 int foldInts(int left, int right); | 72 int foldInts(int left, int right); |
| 75 } | 73 } |
| 76 | 74 |
| 77 class BitOrOperation extends BinaryBitOperation { | 75 class BitOrOperation extends BinaryBitOperation { |
| 78 final String name = '|'; | 76 final String name = '|'; |
| 79 const BitOrOperation(); | 77 const BitOrOperation(); |
| 80 int foldInts(int left, int right) => left | right; | 78 int foldInts(int left, int right) => left | right; |
| 81 apply(left, right) => left | right; | 79 apply(left, right) => left | right; |
| 82 } | 80 } |
| 83 | 81 |
| 84 class BitAndOperation extends BinaryBitOperation { | 82 class BitAndOperation extends BinaryBitOperation { |
| 85 final String name = '&'; | 83 final String name = '&'; |
| 86 const BitAndOperation(); | 84 const BitAndOperation(); |
| 87 int foldInts(int left, int right) => left & right; | 85 int foldInts(int left, int right) => left & right; |
| 88 apply(left, right) => left & right; | 86 apply(left, right) => left & right; |
| 89 } | 87 } |
| 90 | 88 |
| 91 class BitXorOperation extends BinaryBitOperation { | 89 class BitXorOperation extends BinaryBitOperation { |
| 92 final String name = '^'; | 90 final String name = '^'; |
| 93 const BitXorOperation(); | 91 const BitXorOperation(); |
| 94 int foldInts(int left, int right) => left ^ right; | 92 int foldInts(int left, int right) => left ^ right; |
| 95 apply(left, right) => left ^ right; | 93 apply(left, right) => left ^ right; |
| 96 } | 94 } |
| 97 | 95 |
| 98 class ShiftLeftOperation extends BinaryBitOperation { | 96 class ShiftLeftOperation extends BinaryBitOperation { |
| 99 final String name = '<<'; | 97 final String name = '<<'; |
| 100 const ShiftLeftOperation(); | 98 const ShiftLeftOperation(); |
| 101 int foldInts(int left, int right) { | 99 int foldInts(int left, int right) { |
| 102 // TODO(floitsch): find a better way to guard against excessive shifts to | 100 // TODO(floitsch): find a better way to guard against excessive shifts to |
| 103 // the left. | 101 // the left. |
| 104 if (right > 100 || right < 0) return null; | 102 if (right > 100 || right < 0) return null; |
| 105 return left << right; | 103 return left << right; |
| 106 } | 104 } |
| 105 |
| 107 apply(left, right) => left << right; | 106 apply(left, right) => left << right; |
| 108 } | 107 } |
| 109 | 108 |
| 110 class ShiftRightOperation extends BinaryBitOperation { | 109 class ShiftRightOperation extends BinaryBitOperation { |
| 111 final String name = '>>'; | 110 final String name = '>>'; |
| 112 const ShiftRightOperation(); | 111 const ShiftRightOperation(); |
| 113 int foldInts(int left, int right) { | 112 int foldInts(int left, int right) { |
| 114 if (right < 0) return null; | 113 if (right < 0) return null; |
| 115 return left >> right; | 114 return left >> right; |
| 116 } | 115 } |
| 116 |
| 117 apply(left, right) => left >> right; | 117 apply(left, right) => left >> right; |
| 118 } | 118 } |
| 119 | 119 |
| 120 abstract class BinaryBoolOperation implements BinaryOperation { | 120 abstract class BinaryBoolOperation implements BinaryOperation { |
| 121 const BinaryBoolOperation(); | 121 const BinaryBoolOperation(); |
| 122 ConstantValue fold(ConstantValue left, ConstantValue right) { | 122 ConstantValue fold(ConstantValue left, ConstantValue right) { |
| 123 if (left.isBool && right.isBool) { | 123 if (left.isBool && right.isBool) { |
| 124 BoolConstantValue leftBool = left; | 124 BoolConstantValue leftBool = left; |
| 125 BoolConstantValue rightBool = right; | 125 BoolConstantValue rightBool = right; |
| 126 bool resultValue = | 126 bool resultValue = |
| (...skipping 27 matching lines...) Expand all Loading... |
| 154 NumConstantValue leftNum = left; | 154 NumConstantValue leftNum = left; |
| 155 NumConstantValue rightNum = right; | 155 NumConstantValue rightNum = right; |
| 156 num foldedValue; | 156 num foldedValue; |
| 157 if (left.isInt && right.isInt) { | 157 if (left.isInt && right.isInt) { |
| 158 foldedValue = foldInts(leftNum.primitiveValue, rightNum.primitiveValue); | 158 foldedValue = foldInts(leftNum.primitiveValue, rightNum.primitiveValue); |
| 159 } else { | 159 } else { |
| 160 foldedValue = foldNums(leftNum.primitiveValue, rightNum.primitiveValue); | 160 foldedValue = foldNums(leftNum.primitiveValue, rightNum.primitiveValue); |
| 161 } | 161 } |
| 162 // A division by 0 means that we might not have a folded value. | 162 // A division by 0 means that we might not have a folded value. |
| 163 if (foldedValue == null) return null; | 163 if (foldedValue == null) return null; |
| 164 if (left.isInt && right.isInt && !isDivide() || | 164 if (left.isInt && right.isInt && !isDivide() || isTruncatingDivide()) { |
| 165 isTruncatingDivide()) { | |
| 166 assert(foldedValue is int); | 165 assert(foldedValue is int); |
| 167 return DART_CONSTANT_SYSTEM.createInt(foldedValue); | 166 return DART_CONSTANT_SYSTEM.createInt(foldedValue); |
| 168 } else { | 167 } else { |
| 169 return DART_CONSTANT_SYSTEM.createDouble(foldedValue); | 168 return DART_CONSTANT_SYSTEM.createDouble(foldedValue); |
| 170 } | 169 } |
| 171 } | 170 } |
| 172 return null; | 171 return null; |
| 173 } | 172 } |
| 174 | 173 |
| 175 bool isDivide() => false; | 174 bool isDivide() => false; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 192 apply(left, right) => left * right; | 191 apply(left, right) => left * right; |
| 193 } | 192 } |
| 194 | 193 |
| 195 class ModuloOperation extends ArithmeticNumOperation { | 194 class ModuloOperation extends ArithmeticNumOperation { |
| 196 final String name = '%'; | 195 final String name = '%'; |
| 197 const ModuloOperation(); | 196 const ModuloOperation(); |
| 198 int foldInts(int left, int right) { | 197 int foldInts(int left, int right) { |
| 199 if (right == 0) return null; | 198 if (right == 0) return null; |
| 200 return left % right; | 199 return left % right; |
| 201 } | 200 } |
| 201 |
| 202 num foldNums(num left, num right) => left % right; | 202 num foldNums(num left, num right) => left % right; |
| 203 apply(left, right) => left % right; | 203 apply(left, right) => left % right; |
| 204 } | 204 } |
| 205 | 205 |
| 206 class TruncatingDivideOperation extends ArithmeticNumOperation { | 206 class TruncatingDivideOperation extends ArithmeticNumOperation { |
| 207 final String name = '~/'; | 207 final String name = '~/'; |
| 208 const TruncatingDivideOperation(); | 208 const TruncatingDivideOperation(); |
| 209 int foldInts(int left, int right) { | 209 int foldInts(int left, int right) { |
| 210 if (right == 0) return null; | 210 if (right == 0) return null; |
| 211 return left ~/ right; | 211 return left ~/ right; |
| 212 } | 212 } |
| 213 |
| 213 num foldNums(num left, num right) { | 214 num foldNums(num left, num right) { |
| 214 num ratio = left / right; | 215 num ratio = left / right; |
| 215 if (ratio.isNaN || ratio.isInfinite) return null; | 216 if (ratio.isNaN || ratio.isInfinite) return null; |
| 216 return ratio.truncate().toInt(); | 217 return ratio.truncate().toInt(); |
| 217 } | 218 } |
| 219 |
| 218 apply(left, right) => left ~/ right; | 220 apply(left, right) => left ~/ right; |
| 219 bool isTruncatingDivide() => true; | 221 bool isTruncatingDivide() => true; |
| 220 } | 222 } |
| 221 | 223 |
| 222 class DivideOperation extends ArithmeticNumOperation { | 224 class DivideOperation extends ArithmeticNumOperation { |
| 223 final String name = '/'; | 225 final String name = '/'; |
| 224 const DivideOperation(); | 226 const DivideOperation(); |
| 225 num foldNums(num left, num right) => left / right; | 227 num foldNums(num left, num right) => left / right; |
| 226 bool isDivide() => true; | 228 bool isDivide() => true; |
| 227 apply(left, right) => left / right; | 229 apply(left, right) => left / right; |
| 228 } | 230 } |
| 229 | 231 |
| 230 class AddOperation implements BinaryOperation { | 232 class AddOperation implements BinaryOperation { |
| 231 final String name = '+'; | 233 final String name = '+'; |
| 232 const AddOperation(); | 234 const AddOperation(); |
| 233 ConstantValue fold(ConstantValue left, ConstantValue right) { | 235 ConstantValue fold(ConstantValue left, ConstantValue right) { |
| 234 if (left.isInt && right.isInt) { | 236 if (left.isInt && right.isInt) { |
| 235 IntConstantValue leftInt = left; | 237 IntConstantValue leftInt = left; |
| 236 IntConstantValue rightInt = right; | 238 IntConstantValue rightInt = right; |
| 237 int result = leftInt.primitiveValue + rightInt.primitiveValue; | 239 int result = leftInt.primitiveValue + rightInt.primitiveValue; |
| 238 return DART_CONSTANT_SYSTEM.createInt(result); | 240 return DART_CONSTANT_SYSTEM.createInt(result); |
| 239 } else if (left.isNum && right.isNum) { | 241 } else if (left.isNum && right.isNum) { |
| 240 NumConstantValue leftNum = left; | 242 NumConstantValue leftNum = left; |
| 241 NumConstantValue rightNum = right; | 243 NumConstantValue rightNum = right; |
| 242 double result = leftNum.primitiveValue + rightNum.primitiveValue; | 244 double result = leftNum.primitiveValue + rightNum.primitiveValue; |
| 243 return DART_CONSTANT_SYSTEM.createDouble(result); | 245 return DART_CONSTANT_SYSTEM.createDouble(result); |
| 244 } else if (left.isString && right.isString) { | 246 } else if (left.isString && right.isString) { |
| 245 StringConstantValue leftString = left; | 247 StringConstantValue leftString = left; |
| 246 StringConstantValue rightString = right; | 248 StringConstantValue rightString = right; |
| 247 DartString result = new DartString.concat(leftString.primitiveValue, | 249 DartString result = new DartString.concat( |
| 248 rightString.primitiveValue); | 250 leftString.primitiveValue, rightString.primitiveValue); |
| 249 return DART_CONSTANT_SYSTEM.createString(result); | 251 return DART_CONSTANT_SYSTEM.createString(result); |
| 250 } else { | 252 } else { |
| 251 return null; | 253 return null; |
| 252 } | 254 } |
| 253 } | 255 } |
| 256 |
| 254 apply(left, right) => left + right; | 257 apply(left, right) => left + right; |
| 255 } | 258 } |
| 256 | 259 |
| 257 abstract class RelationalNumOperation implements BinaryOperation { | 260 abstract class RelationalNumOperation implements BinaryOperation { |
| 258 const RelationalNumOperation(); | 261 const RelationalNumOperation(); |
| 259 ConstantValue fold(ConstantValue left, ConstantValue right) { | 262 ConstantValue fold(ConstantValue left, ConstantValue right) { |
| 260 if (!left.isNum || !right.isNum) return null; | 263 if (!left.isNum || !right.isNum) return null; |
| 261 NumConstantValue leftNum = left; | 264 NumConstantValue leftNum = left; |
| 262 NumConstantValue rightNum = right; | 265 NumConstantValue rightNum = right; |
| 263 bool foldedValue = | 266 bool foldedValue = |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 bool result = leftNum.primitiveValue == rightNum.primitiveValue; | 312 bool result = leftNum.primitiveValue == rightNum.primitiveValue; |
| 310 return DART_CONSTANT_SYSTEM.createBool(result); | 313 return DART_CONSTANT_SYSTEM.createBool(result); |
| 311 } | 314 } |
| 312 if (left.isConstructedObject) { | 315 if (left.isConstructedObject) { |
| 313 // Unless we know that the user-defined object does not implement the | 316 // Unless we know that the user-defined object does not implement the |
| 314 // equality operator we cannot fold here. | 317 // equality operator we cannot fold here. |
| 315 return null; | 318 return null; |
| 316 } | 319 } |
| 317 return DART_CONSTANT_SYSTEM.createBool(left == right); | 320 return DART_CONSTANT_SYSTEM.createBool(left == right); |
| 318 } | 321 } |
| 322 |
| 319 apply(left, right) => left == right; | 323 apply(left, right) => left == right; |
| 320 } | 324 } |
| 321 | 325 |
| 322 class IdentityOperation implements BinaryOperation { | 326 class IdentityOperation implements BinaryOperation { |
| 323 final String name = '==='; | 327 final String name = '==='; |
| 324 const IdentityOperation(); | 328 const IdentityOperation(); |
| 325 BoolConstantValue fold(ConstantValue left, ConstantValue right) { | 329 BoolConstantValue fold(ConstantValue left, ConstantValue right) { |
| 326 // In order to preserve runtime semantics which says that NaN !== NaN don't | 330 // In order to preserve runtime semantics which says that NaN !== NaN don't |
| 327 // constant fold NaN === NaN. Otherwise the output depends on inlined | 331 // constant fold NaN === NaN. Otherwise the output depends on inlined |
| 328 // variables and other optimizations. | 332 // variables and other optimizations. |
| 329 if (left.isNaN && right.isNaN) return null; | 333 if (left.isNaN && right.isNaN) return null; |
| 330 return DART_CONSTANT_SYSTEM.createBool(left == right); | 334 return DART_CONSTANT_SYSTEM.createBool(left == right); |
| 331 } | 335 } |
| 336 |
| 332 apply(left, right) => identical(left, right); | 337 apply(left, right) => identical(left, right); |
| 333 } | 338 } |
| 334 | 339 |
| 335 class IfNullOperation implements BinaryOperation { | 340 class IfNullOperation implements BinaryOperation { |
| 336 final String name = '??'; | 341 final String name = '??'; |
| 337 const IfNullOperation(); | 342 const IfNullOperation(); |
| 338 ConstantValue fold(ConstantValue left, ConstantValue right) { | 343 ConstantValue fold(ConstantValue left, ConstantValue right) { |
| 339 if (left.isNull) return right; | 344 if (left.isNull) return right; |
| 340 return left; | 345 return left; |
| 341 } | 346 } |
| 347 |
| 342 apply(left, right) => left ?? right; | 348 apply(left, right) => left ?? right; |
| 343 } | 349 } |
| 344 | 350 |
| 345 abstract class CodeUnitAtOperation implements BinaryOperation { | 351 abstract class CodeUnitAtOperation implements BinaryOperation { |
| 346 final String name = 'charCodeAt'; | 352 final String name = 'charCodeAt'; |
| 347 const CodeUnitAtOperation(); | 353 const CodeUnitAtOperation(); |
| 348 apply(left, right) => left.codeUnitAt(right); | 354 apply(left, right) => left.codeUnitAt(right); |
| 349 } | 355 } |
| 350 | 356 |
| 351 class CodeUnitAtConstantOperation extends CodeUnitAtOperation { | 357 class CodeUnitAtConstantOperation extends CodeUnitAtOperation { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 final negate = const NegateOperation(); | 406 final negate = const NegateOperation(); |
| 401 final not = const NotOperation(); | 407 final not = const NotOperation(); |
| 402 final shiftLeft = const ShiftLeftOperation(); | 408 final shiftLeft = const ShiftLeftOperation(); |
| 403 final shiftRight = const ShiftRightOperation(); | 409 final shiftRight = const ShiftRightOperation(); |
| 404 final subtract = const SubtractOperation(); | 410 final subtract = const SubtractOperation(); |
| 405 final truncatingDivide = const TruncatingDivideOperation(); | 411 final truncatingDivide = const TruncatingDivideOperation(); |
| 406 final codeUnitAt = const CodeUnitAtConstantOperation(); | 412 final codeUnitAt = const CodeUnitAtConstantOperation(); |
| 407 | 413 |
| 408 const DartConstantSystem(); | 414 const DartConstantSystem(); |
| 409 | 415 |
| 410 | |
| 411 @override | 416 @override |
| 412 IntConstantValue createInt(int i) => new IntConstantValue(i); | 417 IntConstantValue createInt(int i) => new IntConstantValue(i); |
| 413 | 418 |
| 414 @override | 419 @override |
| 415 DoubleConstantValue createDouble(double d) => new DoubleConstantValue(d); | 420 DoubleConstantValue createDouble(double d) => new DoubleConstantValue(d); |
| 416 | 421 |
| 417 @override | 422 @override |
| 418 StringConstantValue createString(DartString string) { | 423 StringConstantValue createString(DartString string) { |
| 419 return new StringConstantValue(string); | 424 return new StringConstantValue(string); |
| 420 } | 425 } |
| 421 | 426 |
| 422 @override | 427 @override |
| 423 BoolConstantValue createBool(bool value) => new BoolConstantValue(value); | 428 BoolConstantValue createBool(bool value) => new BoolConstantValue(value); |
| 424 | 429 |
| 425 @override | 430 @override |
| 426 NullConstantValue createNull() => new NullConstantValue(); | 431 NullConstantValue createNull() => new NullConstantValue(); |
| 427 | 432 |
| 428 @override | 433 @override |
| 429 ListConstantValue createList(InterfaceType type, | 434 ListConstantValue createList(InterfaceType type, List<ConstantValue> values) { |
| 430 List<ConstantValue> values) { | |
| 431 return new ListConstantValue(type, values); | 435 return new ListConstantValue(type, values); |
| 432 } | 436 } |
| 433 | 437 |
| 434 @override | 438 @override |
| 435 MapConstantValue createMap(Compiler compiler, | 439 MapConstantValue createMap(Compiler compiler, InterfaceType type, |
| 436 InterfaceType type, | 440 List<ConstantValue> keys, List<ConstantValue> values) { |
| 437 List<ConstantValue> keys, | |
| 438 List<ConstantValue> values) { | |
| 439 return new MapConstantValue(type, keys, values); | 441 return new MapConstantValue(type, keys, values); |
| 440 } | 442 } |
| 441 | 443 |
| 442 @override | 444 @override |
| 443 ConstantValue createType(Compiler compiler, DartType type) { | 445 ConstantValue createType(Compiler compiler, DartType type) { |
| 444 // TODO(johnniwinther): Change the `Type` type to | 446 // TODO(johnniwinther): Change the `Type` type to |
| 445 // `compiler.coreTypes.typeType` and check the backend specific value in | 447 // `compiler.coreTypes.typeType` and check the backend specific value in |
| 446 // [checkConstMapKeysDontOverrideEquals] in 'members.dart'. | 448 // [checkConstMapKeysDontOverrideEquals] in 'members.dart'. |
| 447 return new TypeConstantValue(type, | 449 return new TypeConstantValue(type, |
| 448 compiler.backend.typeImplementation.computeType(compiler.resolution)); | 450 compiler.backend.typeImplementation.computeType(compiler.resolution)); |
| 449 } | 451 } |
| 450 | 452 |
| 451 bool isInt(ConstantValue constant) => constant.isInt; | 453 bool isInt(ConstantValue constant) => constant.isInt; |
| 452 bool isDouble(ConstantValue constant) => constant.isDouble; | 454 bool isDouble(ConstantValue constant) => constant.isDouble; |
| 453 bool isString(ConstantValue constant) => constant.isString; | 455 bool isString(ConstantValue constant) => constant.isString; |
| 454 bool isBool(ConstantValue constant) => constant.isBool; | 456 bool isBool(ConstantValue constant) => constant.isBool; |
| 455 bool isNull(ConstantValue constant) => constant.isNull; | 457 bool isNull(ConstantValue constant) => constant.isNull; |
| 456 | 458 |
| 457 bool isSubtype(DartTypes types, DartType s, DartType t) { | 459 bool isSubtype(DartTypes types, DartType s, DartType t) { |
| 458 return types.isSubtype(s, t); | 460 return types.isSubtype(s, t); |
| 459 } | 461 } |
| 460 } | 462 } |
| OLD | NEW |