Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 /** A formal parameter to a [Method]. */ | 5 /** A formal parameter to a [Method]. */ |
| 6 class Parameter { | 6 class Parameter { |
| 7 FormalNode definition; | 7 FormalNode definition; |
| 8 Member method; | 8 Member method; |
| 9 | 9 |
| 10 String name; | 10 String name; |
| (...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 414 if (declaringType.isHiddenNativeType) { | 414 if (declaringType.isHiddenNativeType) { |
| 415 // TODO: Could warn at parse time. | 415 // TODO: Could warn at parse time. |
| 416 world.error('static field of hidden native type is inaccessible', | 416 world.error('static field of hidden native type is inaccessible', |
| 417 node.span); | 417 node.span); |
| 418 } | 418 } |
| 419 return new Value(type, '${declaringType.jsname}.$jsname', node.span); | 419 return new Value(type, '${declaringType.jsname}.$jsname', node.span); |
| 420 } else { | 420 } else { |
| 421 return new Value(type, | 421 return new Value(type, |
| 422 '\$globals.${declaringType.jsname}_$jsname', node.span); | 422 '\$globals.${declaringType.jsname}_$jsname', node.span); |
| 423 } | 423 } |
| 424 } else if (target.isConst && isFinal) { | 424 } |
| 425 /*else if (target.isConst && isFinal) { | |
|
Jennifer Messerly
2012/01/09 19:06:54
remove? or is this a todo
jimhug
2012/01/09 21:34:30
Was a todo - but then I decided on something diffe
| |
| 425 // take advantage of consts and retrieve the value directly if possible | 426 // take advantage of consts and retrieve the value directly if possible |
| 426 var constTarget = target is GlobalValue ? target.dynamic.exp : target; | 427 var constTarget = target is GlobalValue ? target.dynamic.exp : target; |
| 427 if (constTarget is ConstObjectValue) { | 428 if (constTarget is ConstObjectValue) { |
| 428 return constTarget.fields[name]; | 429 return constTarget.fields[name]; |
| 429 } else if (constTarget.type == world.stringType && name == 'length') { | 430 } else if (constTarget.type == world.stringType && name == 'length') { |
| 430 return new Value(type, '${constTarget.actualValue.length}', node.span); | 431 return new Value(type, '${constTarget.actualValue.length}', node.span); |
| 431 } | 432 } |
| 432 } | 433 }*/ |
| 433 return new Value(type, '${target.code}.$jsname', node.span); | 434 return new Value(type, '${target.code}.$jsname', node.span); |
| 434 } | 435 } |
| 435 | 436 |
| 436 Value _set(MethodGenerator context, Node node, Value target, Value value, | 437 Value _set(MethodGenerator context, Node node, Value target, Value value, |
| 437 [bool isDynamic=false]) { | 438 [bool isDynamic=false]) { |
| 438 var lhs = _get(context, node, target, isDynamic); | 439 var lhs = _get(context, node, target, isDynamic); |
| 439 value = value.convertTo(context, type, isDynamic); | 440 value = value.convertTo(context, type, isDynamic); |
| 440 return new Value(type, '${lhs.code} = ${value.code}', node.span); | 441 return new Value(type, '${lhs.code} = ${value.code}', node.span); |
| 441 } | 442 } |
| 442 } | 443 } |
| (...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 931 } | 932 } |
| 932 | 933 |
| 933 int bareCount = args.bareCount; | 934 int bareCount = args.bareCount; |
| 934 for (int i = 0; i < bareCount; i++) { | 935 for (int i = 0; i < bareCount; i++) { |
| 935 var arg = args.values[i]; | 936 var arg = args.values[i]; |
| 936 if (i >= parameters.length) { | 937 if (i >= parameters.length) { |
| 937 var msg = _argCountMsg(args.length, parameters.length); | 938 var msg = _argCountMsg(args.length, parameters.length); |
| 938 return _argError(context, node, target, args, msg, i); | 939 return _argError(context, node, target, args, msg, i); |
| 939 } | 940 } |
| 940 arg = arg.convertTo(context, parameters[i].type, isDynamic); | 941 arg = arg.convertTo(context, parameters[i].type, isDynamic); |
| 941 if (isConst && arg.isConst) { | 942 argsCode.add(arg.code); |
|
Jennifer Messerly
2012/01/09 19:06:54
yay
| |
| 942 argsCode.add(arg.canonicalCode); | |
| 943 } else { | |
| 944 argsCode.add(arg.code); | |
| 945 } | |
| 946 } | 943 } |
| 947 | 944 |
| 948 int namedArgsUsed = 0; | 945 int namedArgsUsed = 0; |
| 949 if (bareCount < parameters.length) { | 946 if (bareCount < parameters.length) { |
| 950 genParameterValues(); | 947 genParameterValues(); |
| 951 | 948 |
| 952 for (int i = bareCount; i < parameters.length; i++) { | 949 for (int i = bareCount; i < parameters.length; i++) { |
| 953 var arg = args.getValue(parameters[i].name); | 950 var arg = args.getValue(parameters[i].name); |
| 954 if (arg == null) { | 951 if (arg == null) { |
| 955 arg = parameters[i].value; | 952 arg = parameters[i].value; |
| 956 } else { | 953 } else { |
| 957 arg = arg.convertTo(context, parameters[i].type, isDynamic); | 954 arg = arg.convertTo(context, parameters[i].type, isDynamic); |
| 958 namedArgsUsed++; | 955 namedArgsUsed++; |
| 959 } | 956 } |
| 960 | 957 |
| 961 if (arg == null || !parameters[i].isOptional) { | 958 if (arg == null || !parameters[i].isOptional) { |
| 962 var msg = _argCountMsg(Math.min(i, args.length), i + 1, atLeast:true); | 959 var msg = _argCountMsg(Math.min(i, args.length), i + 1, atLeast:true); |
| 963 return _argError(context, node, target, args, msg, i); | 960 return _argError(context, node, target, args, msg, i); |
| 964 } else { | 961 } else { |
| 965 argsCode.add(isConst && arg.isConst | 962 argsCode.add(arg.code); |
| 966 ? arg.canonicalCode : arg.code); | |
| 967 } | 963 } |
| 968 } | 964 } |
| 969 Arguments.removeTrailingNulls(argsCode); | 965 Arguments.removeTrailingNulls(argsCode); |
| 970 } | 966 } |
| 971 | 967 |
| 972 if (namedArgsUsed < args.nameCount) { | 968 if (namedArgsUsed < args.nameCount) { |
| 973 // Find the unused argument name | 969 // Find the unused argument name |
| 974 var seen = new Set<String>(); | 970 var seen = new Set<String>(); |
| 975 for (int i = bareCount; i < args.length; i++) { | 971 for (int i = bareCount; i < args.length; i++) { |
| 976 var name = args.getName(i); | 972 var name = args.getName(i); |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 1006 node.span); | 1002 node.span); |
| 1007 } | 1003 } |
| 1008 | 1004 |
| 1009 if (isOperator) { | 1005 if (isOperator) { |
| 1010 return _invokeBuiltin(context, node, target, args, argsCode, isDynamic); | 1006 return _invokeBuiltin(context, node, target, args, argsCode, isDynamic); |
| 1011 } | 1007 } |
| 1012 | 1008 |
| 1013 if (isFactory) { | 1009 if (isFactory) { |
| 1014 assert(target.isType); | 1010 assert(target.isType); |
| 1015 return new Value(target.type, '$generatedFactoryName($argsString)', | 1011 return new Value(target.type, '$generatedFactoryName($argsString)', |
| 1016 node.span); | 1012 node !== null ? node.span : null); |
| 1017 } | 1013 } |
| 1018 | 1014 |
| 1019 if (isStatic) { | 1015 if (isStatic) { |
| 1020 if (declaringType.isTop) { | 1016 if (declaringType.isTop) { |
| 1021 // TODO(jimhug): Explore moving libraries into their own namespaces | 1017 // TODO(jimhug): Explore moving libraries into their own namespaces |
| 1022 return new Value(inferredResult, | 1018 return new Value(inferredResult, |
| 1023 '$jsname($argsString)', node != null ? node.span : node); | 1019 '$jsname($argsString)', node !== null ? node.span : null); |
| 1024 } | 1020 } |
| 1025 return new Value(inferredResult, | 1021 return new Value(inferredResult, |
| 1026 '${declaringType.jsname}.$jsname($argsString)', node.span); | 1022 '${declaringType.jsname}.$jsname($argsString)', node.span); |
| 1027 } | 1023 } |
| 1028 | 1024 |
| 1029 var code = '${target.code}.$jsname($argsString)'; | 1025 var code = '${target.code}.$jsname($argsString)'; |
| 1030 // optimize expressions which we know statically their value. | 1026 // optimize expressions which we know statically their value. |
| 1027 // ???? | |
|
Jennifer Messerly
2012/01/09 19:06:54
is this a TODO?
jimhug
2012/01/09 21:34:30
Done.
| |
| 1028 /* | |
| 1031 if (target.isConst) { | 1029 if (target.isConst) { |
| 1032 if (target is GlobalValue) { | 1030 if (target is GlobalValue) { |
| 1033 target = target.dynamic.exp; // TODO: an inline "cast" would be nice. | 1031 target = target.dynamic.exp; // TODO: an inline "cast" would be nice. |
| 1034 } | 1032 } |
| 1035 if (name == 'get:length') { | 1033 if (name == 'get:length') { |
| 1036 if (target is ConstListValue || target is ConstMapValue) { | 1034 if (target is ConstListValue || target is ConstMapValue) { |
| 1037 code = '${target.dynamic.values.length}'; | 1035 code = '${target.dynamic.values.length}'; |
| 1038 } | 1036 } |
| 1039 } else if (name == 'isEmpty') { | 1037 } else if (name == 'isEmpty') { |
| 1040 if (target is ConstListValue || target is ConstMapValue) { | 1038 if (target is ConstListValue || target is ConstMapValue) { |
| 1041 code = '${target.dynamic.values.isEmpty()}'; | 1039 code = '${target.dynamic.values.isEmpty()}'; |
| 1042 } | 1040 } |
| 1043 } | 1041 } |
| 1044 } | 1042 } |
| 1043 */ | |
| 1045 | 1044 |
| 1046 // TODO(jmesserly): factor this better | 1045 // TODO(jmesserly): factor this better |
|
Jennifer Messerly
2012/01/09 19:06:54
Not your change, but I noticed that this block of
jimhug
2012/01/09 21:34:30
I'm not sure I understand the ramifications of rem
| |
| 1047 if (name == 'get:typeName' && declaringType.library.isDom) { | 1046 if (name == 'get:typeName' && declaringType.library.isDom) { |
| 1048 world.gen.corejs.ensureTypeNameOf(); | 1047 world.gen.corejs.ensureTypeNameOf(); |
| 1049 } | 1048 } |
| 1050 | 1049 |
| 1051 return new Value(inferredResult, code, node.span); | 1050 return new Value(inferredResult, code, node.span); |
| 1052 } | 1051 } |
| 1053 | 1052 |
| 1054 Value _invokeConstructor(MethodGenerator context, Node node, | 1053 Value _invokeConstructor(MethodGenerator context, Node node, |
| 1055 Value target, Arguments args, argsString) { | 1054 Value target, Arguments args, argsString) { |
| 1056 declaringType.markUsed(); | 1055 declaringType.markUsed(); |
| 1057 | 1056 |
| 1058 String ctor = constructorName; | 1057 String ctor = constructorName; |
| 1059 if (ctor != '') ctor = '.${ctor}\$ctor'; | 1058 if (ctor != '') ctor = '.${ctor}\$ctor'; |
| 1060 | 1059 |
| 1061 if (!target.isType) { | 1060 if (!target.isType) { |
| 1062 // initializer call to another constructor | 1061 // initializer call to another constructor |
| 1063 var code = '${declaringType.nativeName}${ctor}.call($argsString)'; | 1062 var code = '${declaringType.nativeName}${ctor}.call($argsString)'; |
| 1064 return new Value(target.type, code, node.span); | 1063 return new Value(target.type, code, node.span); |
| 1065 } else { | 1064 } else { |
| 1066 | |
| 1067 var code = 'new ${declaringType.nativeName}${ctor}($argsString)'; | 1065 var code = 'new ${declaringType.nativeName}${ctor}($argsString)'; |
| 1068 | 1066 |
| 1069 // TODO(jmesserly): using the "node" here feels really hacky | 1067 // TODO(jmesserly): using the "node" here feels really hacky |
| 1070 if (isConst && node is NewExpression && node.dynamic.isConst) { | 1068 if (isConst && node is NewExpression && node.dynamic.isConst) { |
| 1071 return _invokeConstConstructor(node, code, target, args); | 1069 return _invokeConstConstructor(node, code, target, args); |
| 1072 } else { | 1070 } else { |
| 1073 final span = node != null ? node.span : target.span; | 1071 final span = node != null ? node.span : target.span; |
| 1074 return new Value(target.type, code, span); | 1072 return new Value(target.type, code, span); |
| 1075 } | 1073 } |
| 1076 } | 1074 } |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 1088 * class B { | 1086 * class B { |
| 1089 * final int y; | 1087 * final int y; |
| 1090 * const B() : y = 0, super(1); | 1088 * const B() : y = 0, super(1); |
| 1091 * const B.a(this.y, x) : super(x); | 1089 * const B.a(this.y, x) : super(x); |
| 1092 * const B.b(v) : this.a(v, 1); | 1090 * const B.b(v) : this.a(v, 1); |
| 1093 * } | 1091 * } |
| 1094 * :] | 1092 * :] |
| 1095 */ | 1093 */ |
| 1096 Value _invokeConstConstructor( | 1094 Value _invokeConstConstructor( |
| 1097 Node node, String code, Value target, Arguments args) { | 1095 Node node, String code, Value target, Arguments args) { |
| 1096 // TODO(jimhug): This should be low-hanging fruit for abstract eval! | |
| 1097 | |
| 1098 // Statically compute the actual value for every field in the const object. | 1098 // Statically compute the actual value for every field in the const object. |
| 1099 final fields = new Map<String, EvaluatedValue>(); | 1099 final fields = new Map<String, Value>(); |
| 1100 | 1100 |
| 1101 // First deduce the value for fields initialized with the 'this.x' syntax. | 1101 // First deduce the value for fields initialized with the 'this.x' syntax. |
| 1102 for (int i = 0; i < parameters.length; i++) { | 1102 for (int i = 0; i < parameters.length; i++) { |
| 1103 var param = parameters[i]; | 1103 var param = parameters[i]; |
| 1104 if (param.isInitializer) { | 1104 if (param.isInitializer) { |
| 1105 var value = null; | 1105 var value = null; |
| 1106 if (i < args.length) { | 1106 if (i < args.length) { |
| 1107 value = args.values[i]; | 1107 value = args.values[i]; |
| 1108 } else { // named arguments | 1108 } else { // named arguments |
| 1109 value = args.getValue(param.name); | 1109 value = args.getValue(param.name); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1176 world.error('const class "${declaringType.name}" has non-final ' | 1176 world.error('const class "${declaringType.name}" has non-final ' |
| 1177 + 'field "${f.name}"', f.span); | 1177 + 'field "${f.name}"', f.span); |
| 1178 } | 1178 } |
| 1179 if (f.value != null) { | 1179 if (f.value != null) { |
| 1180 fields[f.name] = f.computeValue(); | 1180 fields[f.name] = f.computeValue(); |
| 1181 } | 1181 } |
| 1182 } | 1182 } |
| 1183 } | 1183 } |
| 1184 | 1184 |
| 1185 return world.gen.globalForConst( | 1185 return world.gen.globalForConst( |
| 1186 new ConstObjectValue(target.type, fields, code, node.span), | 1186 new ObjectValue(fields, true, target.type, code, node.span), |
| 1187 args.values); | 1187 args.values); |
| 1188 } | 1188 } |
| 1189 | 1189 |
| 1190 | 1190 |
| 1191 Value _invokeBuiltin(MethodGenerator context, Node node, Value target, | 1191 Value _invokeBuiltin(MethodGenerator context, Node node, Value target, |
| 1192 Arguments args, argsCode, bool isDynamic) { | 1192 Arguments args, argsCode, bool isDynamic) { |
| 1193 var allConst = target.isConst && args.values.every((arg) => arg.isConst); | 1193 var allConst = target.isConst && args.values.every((arg) => arg.isConst); |
| 1194 | 1194 |
| 1195 // Handle some fast paths for Number, String, List and DOM. | 1195 // Handle some fast paths for Number, String, List and DOM. |
| 1196 if (declaringType.isNum) { | 1196 if (declaringType.isNum) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1237 | 1237 |
| 1238 // Note: unfortunatelly bit operations fail on doubles in dartvm | 1238 // Note: unfortunatelly bit operations fail on doubles in dartvm |
| 1239 case ':bit_not': value = (~ival0).toDouble(); break; | 1239 case ':bit_not': value = (~ival0).toDouble(); break; |
| 1240 case ':bit_or': value = (ival0 | ival1).toDouble(); break; | 1240 case ':bit_or': value = (ival0 | ival1).toDouble(); break; |
| 1241 case ':bit_xor': value = (ival0 ^ ival1).toDouble(); break; | 1241 case ':bit_xor': value = (ival0 ^ ival1).toDouble(); break; |
| 1242 case ':bit_and': value = (ival0 & ival1).toDouble(); break; | 1242 case ':bit_and': value = (ival0 & ival1).toDouble(); break; |
| 1243 case ':shl': value = (ival0 << ival1).toDouble(); break; | 1243 case ':shl': value = (ival0 << ival1).toDouble(); break; |
| 1244 case ':sar': value = (ival0 >> ival1).toDouble(); break; | 1244 case ':sar': value = (ival0 >> ival1).toDouble(); break; |
| 1245 case ':shr': value = (ival0 >>> ival1).toDouble(); break; | 1245 case ':shr': value = (ival0 >>> ival1).toDouble(); break; |
| 1246 } | 1246 } |
| 1247 return new EvaluatedValue(inferredResult, value, "$value", node.span); | 1247 if (inferredResult.isInt) { |
| 1248 return Value.fromInt(value.toInt(), node.span); | |
| 1249 } else if (inferredResult.isDouble) { | |
| 1250 return Value.fromDouble(value.toDouble(), node.span); | |
| 1251 } else if (inferredResult.isNum) { | |
| 1252 // TODO(jimhug): Number type system is flawed here... | |
| 1253 return Value.fromDouble(value.toDouble(), node.span); | |
| 1254 } else if (inferredResult.isBool) { | |
| 1255 return Value.fromBool(value, node.span); | |
| 1256 } else { | |
| 1257 world.internalError( | |
| 1258 'unsupported const result type "${inferredResult.name}"', | |
| 1259 node.span); | |
| 1260 } | |
| 1248 } | 1261 } |
| 1249 } else if (declaringType.isString) { | 1262 } else if (declaringType.isString) { |
| 1250 if (name == ':index') { | 1263 if (name == ':index') { |
| 1251 // Note: this could technically propagate constness, but that's not | 1264 // Note: this could technically propagate constness, but that's not |
| 1252 // specified explicitly and the VM doesn't do that. | 1265 // specified explicitly and the VM doesn't do that. |
| 1253 return new Value(declaringType, '${target.code}[${argsCode[0]}]', | 1266 return new Value(declaringType, '${target.code}[${argsCode[0]}]', |
| 1254 node.span); | 1267 node.span); |
| 1255 } else if (name == ':add') { | 1268 } else if (name == ':add') { |
| 1256 if (allConst) { | 1269 if (allConst) { |
| 1257 final value = target.dynamic.actualValue + | 1270 final value = target.dynamic.actualValue + |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 1280 | 1293 |
| 1281 if (name == ':ne') { | 1294 if (name == ':ne') { |
| 1282 // Ensure == is generated. | 1295 // Ensure == is generated. |
| 1283 target.invoke(context, ':eq', node, args, isDynamic); | 1296 target.invoke(context, ':eq', node, args, isDynamic); |
| 1284 } | 1297 } |
| 1285 | 1298 |
| 1286 if (allConst) { | 1299 if (allConst) { |
| 1287 var val0 = target.dynamic.actualValue; | 1300 var val0 = target.dynamic.actualValue; |
| 1288 var val1 = args.values[0].dynamic.actualValue; | 1301 var val1 = args.values[0].dynamic.actualValue; |
| 1289 var newVal = name == ':eq' ? val0 == val1 : val0 != val1; | 1302 var newVal = name == ':eq' ? val0 == val1 : val0 != val1; |
| 1290 return new EvaluatedValue(world.nonNullBool, | 1303 return Value.fromBool(newVal, node.span); |
| 1291 newVal, "$newVal", node.span); | |
| 1292 } | 1304 } |
| 1293 // Optimize test when null is on the rhs. | 1305 // Optimize test when null is on the rhs. |
| 1294 if (argsCode[0] == 'null') { | 1306 if (argsCode[0] == 'null') { |
| 1295 return new Value(inferredResult, '${target.code} $op null', node.span); | 1307 return new Value(inferredResult, '${target.code} $op null', node.span); |
| 1296 } else if (target.type.isNum || target.type.isString) { | 1308 } else if (target.type.isNum || target.type.isString) { |
| 1297 // TODO(jimhug): Maybe check rhs. | 1309 // TODO(jimhug): Maybe check rhs. |
| 1298 return new Value(inferredResult, '${target.code} $op ${argsCode[0]}', | 1310 return new Value(inferredResult, '${target.code} $op ${argsCode[0]}', |
| 1299 node.span); | 1311 node.span); |
| 1300 } | 1312 } |
| 1301 world.gen.corejs.useOperator(name); | 1313 world.gen.corejs.useOperator(name); |
| (...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1740 } | 1752 } |
| 1741 | 1753 |
| 1742 void forEach(void f(Member member)) { | 1754 void forEach(void f(Member member)) { |
| 1743 factories.forEach((_, Map constructors) { | 1755 factories.forEach((_, Map constructors) { |
| 1744 constructors.forEach((_, Member member) { | 1756 constructors.forEach((_, Member member) { |
| 1745 f(member); | 1757 f(member); |
| 1746 }); | 1758 }); |
| 1747 }); | 1759 }); |
| 1748 } | 1760 } |
| 1749 } | 1761 } |
| OLD | NEW |