Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(810)

Side by Side Diff: pkg/compiler/lib/src/cps_ir/type_propagation.dart

Issue 1761903002: dart2js cps: Keep interceptors in a separate field. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Rebase Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 library dart2js.cps_ir.type_propagation; 4 library dart2js.cps_ir.type_propagation;
5 5
6 import 'optimizers.dart'; 6 import 'optimizers.dart';
7 7
8 import '../closure.dart' show 8 import '../closure.dart' show
9 ClosureClassElement; 9 ClosureClassElement;
10 import '../common.dart'; 10 import '../common.dart';
(...skipping 1142 matching lines...) Expand 10 before | Expand all | Expand 10 after
1153 return compiler.world.allFunctions.filter(selector, receiverType); 1153 return compiler.world.allFunctions.filter(selector, receiverType);
1154 } 1154 }
1155 1155
1156 /************************* CALL EXPRESSIONS *************************/ 1156 /************************* CALL EXPRESSIONS *************************/
1157 1157
1158 /// Replaces [node] with a more specialized instruction, if possible. 1158 /// Replaces [node] with a more specialized instruction, if possible.
1159 /// 1159 ///
1160 /// Returns `true` if the node was replaced. 1160 /// Returns `true` if the node was replaced.
1161 specializeOperatorCall(InvokeMethod node) { 1161 specializeOperatorCall(InvokeMethod node) {
1162 if (!backend.isInterceptedSelector(node.selector)) return null; 1162 if (!backend.isInterceptedSelector(node.selector)) return null;
1163 if (node.dartArgumentsLength > 1) return null; 1163 if (node.argumentRefs.length > 1) return null;
1164 if (node.callingConvention == CallingConvention.OneShotIntercepted) { 1164 if (node.callingConvention == CallingConvention.OneShotIntercepted) {
1165 return null; 1165 return null;
1166 } 1166 }
1167 1167
1168 bool trustPrimitives = compiler.trustPrimitives; 1168 bool trustPrimitives = compiler.trustPrimitives;
1169 1169
1170 /// Check that the receiver and argument satisfy the given type checks, and 1170 /// Check that the receiver and argument satisfy the given type checks, and
1171 /// throw a [NoSuchMethodError] or [ArgumentError] if the check fails. 1171 /// throw a [NoSuchMethodError] or [ArgumentError] if the check fails.
1172 CpsFragment makeGuard(TypeCheckOperator receiverGuard, 1172 CpsFragment makeGuard(TypeCheckOperator receiverGuard,
1173 [TypeCheckOperator argumentGuard]) { 1173 [TypeCheckOperator argumentGuard]) {
1174 CpsFragment cps = new CpsFragment(node.sourceInformation); 1174 CpsFragment cps = new CpsFragment(node.sourceInformation);
1175 1175
1176 // Make no guards if trusting primitives. 1176 // Make no guards if trusting primitives.
1177 if (trustPrimitives) return cps; 1177 if (trustPrimitives) return cps;
1178 1178
1179 // Determine which guards are needed. 1179 // Determine which guards are needed.
1180 ChecksNeeded receiverChecks = 1180 ChecksNeeded receiverChecks =
1181 receiverGuard.getChecksNeeded(node.dartReceiver, classWorld); 1181 receiverGuard.getChecksNeeded(node.receiver, classWorld);
1182 bool needReceiverGuard = receiverChecks != ChecksNeeded.None; 1182 bool needReceiverGuard = receiverChecks != ChecksNeeded.None;
1183 bool needArgumentGuard = 1183 bool needArgumentGuard =
1184 argumentGuard != null && 1184 argumentGuard != null &&
1185 argumentGuard.needsCheck(node.dartArgument(0), classWorld); 1185 argumentGuard.needsCheck(node.argument(0), classWorld);
1186 1186
1187 if (!needReceiverGuard && !needArgumentGuard) return cps; 1187 if (!needReceiverGuard && !needArgumentGuard) return cps;
1188 1188
1189 // If we only need the receiver check, emit the specialized receiver 1189 // If we only need the receiver check, emit the specialized receiver
1190 // check instruction. Examples: 1190 // check instruction. Examples:
1191 // 1191 //
1192 // if (typeof receiver !== "number") return receiver.$lt; 1192 // if (typeof receiver !== "number") return receiver.$lt;
1193 // if (typeof receiver !== "number") return receiver.$lt(); 1193 // if (typeof receiver !== "number") return receiver.$lt();
1194 // 1194 //
1195 if (!needArgumentGuard) { 1195 if (!needArgumentGuard) {
1196 Primitive condition = receiverGuard.makeCheck(cps, node.dartReceiver); 1196 Primitive condition = receiverGuard.makeCheck(cps, node.receiver);
1197 cps.letPrim(new ReceiverCheck( 1197 cps.letPrim(new ReceiverCheck(
1198 node.dartReceiver, 1198 node.receiver,
1199 node.selector, 1199 node.selector,
1200 node.sourceInformation, 1200 node.sourceInformation,
1201 condition: condition, 1201 condition: condition,
1202 useSelector: true, 1202 useSelector: true,
1203 isNullCheck: receiverChecks == ChecksNeeded.Null 1203 isNullCheck: receiverChecks == ChecksNeeded.Null
1204 )); 1204 ));
1205 return cps; 1205 return cps;
1206 } 1206 }
1207 1207
1208 // TODO(asgerf): We should consider specialized instructions for 1208 // TODO(asgerf): We should consider specialized instructions for
1209 // argument checks and receiver+argument checks, to avoid breaking up 1209 // argument checks and receiver+argument checks, to avoid breaking up
1210 // basic blocks. 1210 // basic blocks.
1211 1211
1212 // Emit as `H.iae(x)` if only the argument check may fail. For example: 1212 // Emit as `H.iae(x)` if only the argument check may fail. For example:
1213 // 1213 //
1214 // if (typeof argument !== "number") return H.iae(argument); 1214 // if (typeof argument !== "number") return H.iae(argument);
1215 // 1215 //
1216 if (!needReceiverGuard) { 1216 if (!needReceiverGuard) {
1217 cps.ifTruthy(argumentGuard.makeCheck(cps, node.dartArgument(0))) 1217 cps.ifTruthy(argumentGuard.makeCheck(cps, node.argument(0)))
1218 .invokeStaticThrower(helpers.throwIllegalArgumentException, 1218 .invokeStaticThrower(helpers.throwIllegalArgumentException,
1219 [node.dartArgument(0)]); 1219 [node.argument(0)]);
1220 return cps; 1220 return cps;
1221 } 1221 }
1222 1222
1223 // Both receiver and argument check is needed. Emit as a combined check 1223 // Both receiver and argument check is needed. Emit as a combined check
1224 // using a one-shot interceptor to produce the exact error message in 1224 // using a one-shot interceptor to produce the exact error message in
1225 // the error case. For example: 1225 // the error case. For example:
1226 // 1226 //
1227 // if (typeof receiver !== "number" || typeof argument !== "number") 1227 // if (typeof receiver !== "number" || typeof argument !== "number")
1228 // return J.$lt(receiver, argument); 1228 // return J.$lt(receiver, argument);
1229 // 1229 //
1230 Continuation fail = cps.letCont(); 1230 Continuation fail = cps.letCont();
1231 cps.ifTruthy(receiverGuard.makeCheck(cps, node.dartReceiver)) 1231 cps.ifTruthy(receiverGuard.makeCheck(cps, node.receiver))
1232 .invokeContinuation(fail); 1232 .invokeContinuation(fail);
1233 cps.ifTruthy(argumentGuard.makeCheck(cps, node.dartArgument(0))) 1233 cps.ifTruthy(argumentGuard.makeCheck(cps, node.argument(0)))
1234 .invokeContinuation(fail); 1234 .invokeContinuation(fail);
1235 1235
1236 cps.insideContinuation(fail) 1236 cps.insideContinuation(fail)
1237 ..invokeMethod(node.dartReceiver, node.selector, node.mask, 1237 ..invokeMethod(node.receiver, node.selector, node.mask,
1238 [node.dartArgument(0)], CallingConvention.OneShotIntercepted) 1238 [node.argument(0)],
1239 callingConvention: CallingConvention.OneShotIntercepted)
1239 ..put(new Unreachable()); 1240 ..put(new Unreachable());
1240 1241
1241 return cps; 1242 return cps;
1242 } 1243 }
1243 1244
1244 /// Replaces the call with [operator], using the receiver and first argument 1245 /// Replaces the call with [operator], using the receiver and first argument
1245 /// as operands (in that order). 1246 /// as operands (in that order).
1246 /// 1247 ///
1247 /// If [guard] is given, the receiver and argument are both checked using 1248 /// If [guard] is given, the receiver and argument are both checked using
1248 /// that operator. 1249 /// that operator.
1249 CpsFragment makeBinary(BuiltinOperator operator, 1250 CpsFragment makeBinary(BuiltinOperator operator,
1250 {TypeCheckOperator guard: TypeCheckOperator.none}) { 1251 {TypeCheckOperator guard: TypeCheckOperator.none}) {
1251 CpsFragment cps = makeGuard(guard, guard); 1252 CpsFragment cps = makeGuard(guard, guard);
1252 Primitive left = guard.makeRefinement(cps, node.dartReceiver, classWorld); 1253 Primitive left = guard.makeRefinement(cps, node.receiver, classWorld);
1253 Primitive right = 1254 Primitive right =
1254 guard.makeRefinement(cps, node.dartArgument(0), classWorld); 1255 guard.makeRefinement(cps, node.argument(0), classWorld);
1255 Primitive result = cps.applyBuiltin(operator, [left, right]); 1256 Primitive result = cps.applyBuiltin(operator, [left, right]);
1256 result.hint = node.hint; 1257 result.hint = node.hint;
1257 node.replaceUsesWith(result); 1258 node.replaceUsesWith(result);
1258 return cps; 1259 return cps;
1259 } 1260 }
1260 1261
1261 /// Like [makeBinary] but for unary operators with the receiver as the 1262 /// Like [makeBinary] but for unary operators with the receiver as the
1262 /// argument. 1263 /// argument.
1263 CpsFragment makeUnary(BuiltinOperator operator, 1264 CpsFragment makeUnary(BuiltinOperator operator,
1264 {TypeCheckOperator guard: TypeCheckOperator.none}) { 1265 {TypeCheckOperator guard: TypeCheckOperator.none}) {
1265 CpsFragment cps = makeGuard(guard); 1266 CpsFragment cps = makeGuard(guard);
1266 Primitive argument = 1267 Primitive argument =
1267 guard.makeRefinement(cps, node.dartReceiver, classWorld); 1268 guard.makeRefinement(cps, node.receiver, classWorld);
1268 Primitive result = cps.applyBuiltin(operator, [argument]); 1269 Primitive result = cps.applyBuiltin(operator, [argument]);
1269 result.hint = node.hint; 1270 result.hint = node.hint;
1270 node.replaceUsesWith(result); 1271 node.replaceUsesWith(result);
1271 return cps; 1272 return cps;
1272 } 1273 }
1273 1274
1274 Selector renameToOptimizedSelector(String name) { 1275 Selector renameToOptimizedSelector(String name) {
1275 return new Selector.call( 1276 return new Selector.call(
1276 new Name(name, backend.helpers.interceptorsLibrary), 1277 new Name(name, backend.helpers.interceptorsLibrary),
1277 node.selector.callStructure); 1278 node.selector.callStructure);
1278 } 1279 }
1279 1280
1280 /// Replaces the call with a call to [name] with the same inputs. 1281 /// Replaces the call with a call to [name] with the same inputs.
1281 InvokeMethod makeRenamedInvoke(String name) { 1282 InvokeMethod makeRenamedInvoke(String name) {
1282 return new InvokeMethod(node.receiver, 1283 return new InvokeMethod(node.receiver,
1283 renameToOptimizedSelector(name), 1284 renameToOptimizedSelector(name),
1284 node.mask, 1285 node.mask,
1285 node.arguments.toList(), 1286 node.arguments.toList(),
1286 sourceInformation: node.sourceInformation, 1287 sourceInformation: node.sourceInformation,
1287 callingConvention: node.callingConvention); 1288 callingConvention: node.callingConvention,
1289 interceptor: node.interceptor);
1288 } 1290 }
1289 1291
1290 TypeMask successType = 1292 TypeMask successType =
1291 typeSystem.receiverTypeFor(node.selector, node.dartReceiver.type); 1293 typeSystem.receiverTypeFor(node.selector, node.receiver.type);
1292 1294
1293 if (node.selector.isOperator && node.dartArgumentsLength == 1) { 1295 if (node.selector.isOperator && node.argumentRefs.length == 1) {
1294 Primitive leftArg = node.dartReceiver; 1296 Primitive leftArg = node.receiver;
1295 Primitive rightArg = node.dartArgument(0); 1297 Primitive rightArg = node.argument(0);
1296 AbstractConstantValue left = getValue(leftArg); 1298 AbstractConstantValue left = getValue(leftArg);
1297 AbstractConstantValue right = getValue(rightArg); 1299 AbstractConstantValue right = getValue(rightArg);
1298 1300
1299 String opname = node.selector.name; 1301 String opname = node.selector.name;
1300 if (opname == '==') { 1302 if (opname == '==') {
1301 // Equality is special due to its treatment of null values and the 1303 // Equality is special due to its treatment of null values and the
1302 // fact that Dart-null corresponds to both JS-null and JS-undefined. 1304 // fact that Dart-null corresponds to both JS-null and JS-undefined.
1303 // Please see documentation for IsFalsy, StrictEq, and LooseEq. 1305 // Please see documentation for IsFalsy, StrictEq, and LooseEq.
1304 if (left.isNullConstant || right.isNullConstant) { 1306 if (left.isNullConstant || right.isNullConstant) {
1305 return makeBinary(BuiltinOperator.Identical); 1307 return makeBinary(BuiltinOperator.Identical);
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1376 } 1378 }
1377 } 1379 }
1378 if (lattice.isDefinitelyString(left, allowNull: trustPrimitives) && 1380 if (lattice.isDefinitelyString(left, allowNull: trustPrimitives) &&
1379 lattice.isDefinitelyString(right, allowNull: trustPrimitives) && 1381 lattice.isDefinitelyString(right, allowNull: trustPrimitives) &&
1380 opname == '+') { 1382 opname == '+') {
1381 // TODO(asgerf): Add IsString builtin so we can use a guard here. 1383 // TODO(asgerf): Add IsString builtin so we can use a guard here.
1382 return makeBinary(BuiltinOperator.StringConcatenate); 1384 return makeBinary(BuiltinOperator.StringConcatenate);
1383 } 1385 }
1384 } 1386 }
1385 } 1387 }
1386 if (node.selector.isOperator && node.dartArgumentsLength == 0) { 1388 if (node.selector.isOperator && node.argumentRefs.length == 0) {
1387 if (typeSystem.isDefinitelyNum(successType)) { 1389 if (typeSystem.isDefinitelyNum(successType)) {
1388 String opname = node.selector.name; 1390 String opname = node.selector.name;
1389 if (opname == '~') { 1391 if (opname == '~') {
1390 return makeUnary(BuiltinOperator.NumBitNot, guard: checkIsNumber); 1392 return makeUnary(BuiltinOperator.NumBitNot, guard: checkIsNumber);
1391 } 1393 }
1392 if (opname == 'unary-') { 1394 if (opname == 'unary-') {
1393 return makeUnary(BuiltinOperator.NumNegate, guard: checkIsNumber); 1395 return makeUnary(BuiltinOperator.NumNegate, guard: checkIsNumber);
1394 } 1396 }
1395 } 1397 }
1396 } 1398 }
1397 if (node.selector.isCall) { 1399 if (node.selector.isCall) {
1398 String name = node.selector.name; 1400 String name = node.selector.name;
1399 Primitive receiver = node.dartReceiver; 1401 Primitive receiver = node.receiver;
1400 AbstractConstantValue receiverValue = getValue(receiver); 1402 AbstractConstantValue receiverValue = getValue(receiver);
1401 if (name == 'remainder') { 1403 if (name == 'remainder') {
1402 if (node.dartArgumentsLength == 1) { 1404 if (node.argumentRefs.length == 1) {
1403 Primitive arg = node.dartArgument(0); 1405 Primitive arg = node.argument(0);
1404 AbstractConstantValue argValue = getValue(arg); 1406 AbstractConstantValue argValue = getValue(arg);
1405 if (lattice.isDefinitelyInt(receiverValue, allowNull: true) && 1407 if (lattice.isDefinitelyInt(receiverValue, allowNull: true) &&
1406 lattice.isDefinitelyInt(argValue) && 1408 lattice.isDefinitelyInt(argValue) &&
1407 isIntNotZero(argValue)) { 1409 isIntNotZero(argValue)) {
1408 return makeBinary(BuiltinOperator.NumRemainder, 1410 return makeBinary(BuiltinOperator.NumRemainder,
1409 guard: checkIsNumber); 1411 guard: checkIsNumber);
1410 } 1412 }
1411 } 1413 }
1412 } else if (name == 'codeUnitAt') { 1414 } else if (name == 'codeUnitAt') {
1413 if (node.dartArgumentsLength == 1) { 1415 if (node.argumentRefs.length == 1) {
1414 Primitive index = node.dartArgument(0); 1416 Primitive index = node.argument(0);
1415 if (lattice.isDefinitelyString(receiverValue) && 1417 if (lattice.isDefinitelyString(receiverValue) &&
1416 lattice.isDefinitelyInt(getValue(index))) { 1418 lattice.isDefinitelyInt(getValue(index))) {
1417 CpsFragment cps = new CpsFragment(node.sourceInformation); 1419 CpsFragment cps = new CpsFragment(node.sourceInformation);
1418 receiver = makeBoundsCheck(cps, receiver, index); 1420 receiver = makeBoundsCheck(cps, receiver, index);
1419 ApplyBuiltinOperator get = 1421 ApplyBuiltinOperator get =
1420 cps.applyBuiltin(BuiltinOperator.CharCodeAt, 1422 cps.applyBuiltin(BuiltinOperator.CharCodeAt,
1421 <Primitive>[receiver, index]); 1423 <Primitive>[receiver, index]);
1422 node.replaceUsesWith(get); 1424 node.replaceUsesWith(get);
1423 get.hint = node.hint; 1425 get.hint = node.hint;
1424 return cps; 1426 return cps;
(...skipping 13 matching lines...) Expand all
1438 bool isInterceptedSelector(Selector selector) { 1440 bool isInterceptedSelector(Selector selector) {
1439 return backend.isInterceptedSelector(selector); 1441 return backend.isInterceptedSelector(selector);
1440 } 1442 }
1441 1443
1442 /// If [node] is a getter or setter invocation, tries to replace the 1444 /// If [node] is a getter or setter invocation, tries to replace the
1443 /// invocation with a direct access to a field. 1445 /// invocation with a direct access to a field.
1444 /// 1446 ///
1445 /// Returns `true` if the node was replaced. 1447 /// Returns `true` if the node was replaced.
1446 Primitive specializeFieldAccess(InvokeMethod node) { 1448 Primitive specializeFieldAccess(InvokeMethod node) {
1447 if (!node.selector.isGetter && !node.selector.isSetter) return null; 1449 if (!node.selector.isGetter && !node.selector.isSetter) return null;
1448 AbstractConstantValue receiver = getValue(node.dartReceiver); 1450 AbstractConstantValue receiver = getValue(node.receiver);
1449 Element target = 1451 Element target =
1450 typeSystem.locateSingleElement(receiver.type, node.selector); 1452 typeSystem.locateSingleElement(receiver.type, node.selector);
1451 if (target is! FieldElement) return null; 1453 if (target is! FieldElement) return null;
1452 // TODO(asgerf): Inlining native fields will make some tests pass for the 1454 // TODO(asgerf): Inlining native fields will make some tests pass for the
1453 // wrong reason, so for testing reasons avoid inlining them. 1455 // wrong reason, so for testing reasons avoid inlining them.
1454 if (backend.isNative(target) || backend.isJsInterop(target)) { 1456 if (backend.isNative(target) || backend.isJsInterop(target)) {
1455 return null; 1457 return null;
1456 } 1458 }
1457 if (node.selector.isGetter) { 1459 if (node.selector.isGetter) {
1458 return new GetField(node.dartReceiver, target); 1460 return new GetField(node.receiver, target);
1459 } else { 1461 } else {
1460 if (target.isFinal) return null; 1462 if (target.isFinal) return null;
1461 assert(node.hasNoUses); 1463 assert(node.hasNoUses);
1462 return new SetField(node.dartReceiver, 1464 return new SetField(node.receiver,
1463 target, 1465 target,
1464 node.dartArgument(0)); 1466 node.argument(0));
1465 } 1467 }
1466 } 1468 }
1467 1469
1468 /// Create a check that throws if [index] is not a valid index on [list]. 1470 /// Create a check that throws if [index] is not a valid index on [list].
1469 /// 1471 ///
1470 /// This function assumes that [index] is an integer. 1472 /// This function assumes that [index] is an integer.
1471 /// 1473 ///
1472 /// Returns a CPS fragment whose context is the branch where no error 1474 /// Returns a CPS fragment whose context is the branch where no error
1473 /// was thrown. 1475 /// was thrown.
1474 Primitive makeBoundsCheck(CpsFragment cps, 1476 Primitive makeBoundsCheck(CpsFragment cps,
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1508 cps.ifTruthy(lengthChanged).invokeStaticThrower( 1510 cps.ifTruthy(lengthChanged).invokeStaticThrower(
1509 helpers.throwConcurrentModificationError, 1511 helpers.throwConcurrentModificationError,
1510 <Primitive>[list]); 1512 <Primitive>[list]);
1511 return cps; 1513 return cps;
1512 } 1514 }
1513 1515
1514 /// Tries to replace [node] with a direct `length` or index access. 1516 /// Tries to replace [node] with a direct `length` or index access.
1515 /// 1517 ///
1516 /// Returns `true` if the node was replaced. 1518 /// Returns `true` if the node was replaced.
1517 specializeIndexableAccess(InvokeMethod node) { 1519 specializeIndexableAccess(InvokeMethod node) {
1518 Primitive receiver = node.dartReceiver; 1520 Primitive receiver = node.receiver;
1519 AbstractConstantValue receiverValue = getValue(receiver); 1521 AbstractConstantValue receiverValue = getValue(receiver);
1520 if (!typeSystem.isDefinitelyIndexable(receiverValue.type, 1522 if (!typeSystem.isDefinitelyIndexable(receiverValue.type,
1521 allowNull: true)) { 1523 allowNull: true)) {
1522 return null; 1524 return null;
1523 } 1525 }
1524 switch (node.selector.name) { 1526 switch (node.selector.name) {
1525 case 'length': 1527 case 'length':
1526 if (node.selector.isGetter) { 1528 if (node.selector.isGetter) {
1527 return new GetLength(receiver); 1529 return new GetLength(receiver);
1528 } 1530 }
1529 if (node.selector.isSetter) { 1531 if (node.selector.isSetter) {
1530 if (!typeSystem.isDefinitelyExtendableArray(receiver.type, 1532 if (!typeSystem.isDefinitelyExtendableArray(receiver.type,
1531 allowNull: true)) { 1533 allowNull: true)) {
1532 return null; 1534 return null;
1533 } 1535 }
1534 CpsFragment cps = new CpsFragment(node.sourceInformation); 1536 CpsFragment cps = new CpsFragment(node.sourceInformation);
1535 Primitive newLength = node.dartArgument(0); 1537 Primitive newLength = node.argument(0);
1536 if (!typeSystem.isDefinitelyUint(newLength.type)) { 1538 if (!typeSystem.isDefinitelyUint(newLength.type)) {
1537 // TODO(asgerf): We could let the SetLength instruction throw for 1539 // TODO(asgerf): We could let the SetLength instruction throw for
1538 // negative right-hand sides (see length setter in js_array.dart). 1540 // negative right-hand sides (see length setter in js_array.dart).
1539 if (compiler.trustPrimitives) { 1541 if (compiler.trustPrimitives) {
1540 newLength = cps.refine(newLength, typeSystem.uint32Type); 1542 newLength = cps.refine(newLength, typeSystem.uint32Type);
1541 newLength.type = typeSystem.uint32Type; 1543 newLength.type = typeSystem.uint32Type;
1542 } else { 1544 } else {
1543 return null; 1545 return null;
1544 } 1546 }
1545 } 1547 }
1546 cps.letPrim(new ApplyBuiltinMethod( 1548 cps.letPrim(new ApplyBuiltinMethod(
1547 BuiltinMethod.SetLength, 1549 BuiltinMethod.SetLength,
1548 receiver, 1550 receiver,
1549 [newLength], 1551 [newLength],
1550 node.sourceInformation)); 1552 node.sourceInformation));
1551 if (!typeSystem.isDefinitelyUint32(newLength.type)) { 1553 if (!typeSystem.isDefinitelyUint32(newLength.type)) {
1552 // If the setter succeeded, the length must have been a uint32. 1554 // If the setter succeeded, the length must have been a uint32.
1553 cps.refine(newLength, typeSystem.uint32Type); 1555 cps.refine(newLength, typeSystem.uint32Type);
1554 } 1556 }
1555 return cps; 1557 return cps;
1556 } 1558 }
1557 return null; 1559 return null;
1558 1560
1559 case '[]': 1561 case '[]':
1560 Primitive index = node.dartArgument(0); 1562 Primitive index = node.argument(0);
1561 CpsFragment cps = new CpsFragment(node.sourceInformation); 1563 CpsFragment cps = new CpsFragment(node.sourceInformation);
1562 receiver = makeBoundsCheck(cps, receiver, index); 1564 receiver = makeBoundsCheck(cps, receiver, index);
1563 GetIndex get = cps.letPrim(new GetIndex(receiver, index)); 1565 GetIndex get = cps.letPrim(new GetIndex(receiver, index));
1564 node.replaceUsesWith(get); 1566 node.replaceUsesWith(get);
1565 // TODO(asgerf): Make replaceUsesWith set the hint? 1567 // TODO(asgerf): Make replaceUsesWith set the hint?
1566 get.hint = node.hint; 1568 get.hint = node.hint;
1567 return cps; 1569 return cps;
1568 1570
1569 case '[]=': 1571 case '[]=':
1570 if (!typeSystem.isDefinitelyMutableIndexable(receiverValue.type, 1572 if (!typeSystem.isDefinitelyMutableIndexable(receiverValue.type,
1571 allowNull: true)) { 1573 allowNull: true)) {
1572 return null; 1574 return null;
1573 } 1575 }
1574 Primitive index = node.dartArgument(0); 1576 Primitive index = node.argument(0);
1575 Primitive value = node.dartArgument(1); 1577 Primitive value = node.argument(1);
1576 CpsFragment cps = new CpsFragment(node.sourceInformation); 1578 CpsFragment cps = new CpsFragment(node.sourceInformation);
1577 receiver = makeBoundsCheck(cps, receiver, index); 1579 receiver = makeBoundsCheck(cps, receiver, index);
1578 cps.letPrim(new SetIndex(receiver, index, value)); 1580 cps.letPrim(new SetIndex(receiver, index, value));
1579 assert(node.hasNoUses); 1581 assert(node.hasNoUses);
1580 return cps; 1582 return cps;
1581 1583
1582 case 'isEmpty': 1584 case 'isEmpty':
1583 if (!node.selector.isGetter) return null; 1585 if (!node.selector.isGetter) return null;
1584 CpsFragment cps = new CpsFragment(node.sourceInformation); 1586 CpsFragment cps = new CpsFragment(node.sourceInformation);
1585 Primitive length = cps.letPrim(new GetLength(receiver)); 1587 Primitive length = cps.letPrim(new GetLength(receiver));
(...skipping 17 matching lines...) Expand all
1603 1605
1604 default: 1606 default:
1605 return null; 1607 return null;
1606 } 1608 }
1607 } 1609 }
1608 1610
1609 /// Tries to replace [node] with one or more direct array access operations. 1611 /// Tries to replace [node] with one or more direct array access operations.
1610 /// 1612 ///
1611 /// Returns `true` if the node was replaced. 1613 /// Returns `true` if the node was replaced.
1612 CpsFragment specializeArrayAccess(InvokeMethod node) { 1614 CpsFragment specializeArrayAccess(InvokeMethod node) {
1613 Primitive list = node.dartReceiver; 1615 Primitive list = node.receiver;
1614 AbstractConstantValue listValue = getValue(list); 1616 AbstractConstantValue listValue = getValue(list);
1615 // Ensure that the object is a native list or null. 1617 // Ensure that the object is a native list or null.
1616 if (!lattice.isDefinitelyArray(listValue, allowNull: true)) { 1618 if (!lattice.isDefinitelyArray(listValue, allowNull: true)) {
1617 return null; 1619 return null;
1618 } 1620 }
1619 bool isFixedLength = 1621 bool isFixedLength =
1620 lattice.isDefinitelyFixedArray(listValue, allowNull: true); 1622 lattice.isDefinitelyFixedArray(listValue, allowNull: true);
1621 bool isExtendable = 1623 bool isExtendable =
1622 lattice.isDefinitelyExtendableArray(listValue, allowNull: true); 1624 lattice.isDefinitelyExtendableArray(listValue, allowNull: true);
1623 SourceInformation sourceInfo = node.sourceInformation; 1625 SourceInformation sourceInfo = node.sourceInformation;
1624 switch (node.selector.name) { 1626 switch (node.selector.name) {
1625 case 'add': 1627 case 'add':
1626 if (!node.selector.isCall || 1628 if (!node.selector.isCall ||
1627 node.selector.positionalArgumentCount != 1 || 1629 node.selector.positionalArgumentCount != 1 ||
1628 node.selector.namedArgumentCount != 0) { 1630 node.selector.namedArgumentCount != 0) {
1629 return null; 1631 return null;
1630 } 1632 }
1631 if (!isExtendable) return null; 1633 if (!isExtendable) return null;
1632 Primitive addedItem = node.dartArgument(0); 1634 Primitive addedItem = node.argument(0);
1633 CpsFragment cps = new CpsFragment(sourceInfo); 1635 CpsFragment cps = new CpsFragment(sourceInfo);
1634 cps.invokeBuiltin(BuiltinMethod.Push, 1636 cps.invokeBuiltin(BuiltinMethod.Push,
1635 list, 1637 list,
1636 <Primitive>[addedItem]); 1638 <Primitive>[addedItem]);
1637 if (node.hasAtLeastOneUse) { 1639 if (node.hasAtLeastOneUse) {
1638 node.replaceUsesWith(cps.makeNull()); 1640 node.replaceUsesWith(cps.makeNull());
1639 } 1641 }
1640 return cps; 1642 return cps;
1641 1643
1642 case 'removeLast': 1644 case 'removeLast':
(...skipping 11 matching lines...) Expand all
1654 removedItem.hint = node.hint; 1656 removedItem.hint = node.hint;
1655 node.replaceUsesWith(removedItem); 1657 node.replaceUsesWith(removedItem);
1656 return cps; 1658 return cps;
1657 1659
1658 case 'addAll': 1660 case 'addAll':
1659 if (!node.selector.isCall || 1661 if (!node.selector.isCall ||
1660 node.selector.argumentCount != 1) { 1662 node.selector.argumentCount != 1) {
1661 return null; 1663 return null;
1662 } 1664 }
1663 if (!isExtendable) return null; 1665 if (!isExtendable) return null;
1664 Primitive addedList = node.dartArgument(0); 1666 Primitive addedList = node.argument(0);
1665 // Rewrite addAll([x1, ..., xN]) to push(x1), ..., push(xN). 1667 // Rewrite addAll([x1, ..., xN]) to push(x1), ..., push(xN).
1666 // Ensure that the list is not mutated between creation and use. 1668 // Ensure that the list is not mutated between creation and use.
1667 // We aim for the common case where this is the only use of the list, 1669 // We aim for the common case where this is the only use of the list,
1668 // which also guarantees that this list is not mutated before use. 1670 // which also guarantees that this list is not mutated before use.
1669 if (addedList is! LiteralList || !addedList.hasExactlyOneUse) { 1671 if (addedList is! LiteralList || !addedList.hasExactlyOneUse) {
1670 return null; 1672 return null;
1671 } 1673 }
1672 LiteralList addedLiteral = addedList; 1674 LiteralList addedLiteral = addedList;
1673 CpsFragment cps = new CpsFragment(sourceInfo); 1675 CpsFragment cps = new CpsFragment(sourceInfo);
1674 for (Reference value in addedLiteral.valueRefs) { 1676 for (Reference value in addedLiteral.valueRefs) {
1675 cps.invokeBuiltin(BuiltinMethod.Push, 1677 cps.invokeBuiltin(BuiltinMethod.Push,
1676 list, 1678 list,
1677 <Primitive>[value.definition]); 1679 <Primitive>[value.definition]);
1678 } 1680 }
1679 if (node.hasAtLeastOneUse) { 1681 if (node.hasAtLeastOneUse) {
1680 node.replaceUsesWith(cps.makeNull()); 1682 node.replaceUsesWith(cps.makeNull());
1681 } 1683 }
1682 return cps; 1684 return cps;
1683 1685
1684 case 'elementAt': 1686 case 'elementAt':
1685 if (!node.selector.isCall || 1687 if (!node.selector.isCall ||
1686 node.selector.positionalArgumentCount != 1 || 1688 node.selector.positionalArgumentCount != 1 ||
1687 node.selector.namedArgumentCount != 0) { 1689 node.selector.namedArgumentCount != 0) {
1688 return null; 1690 return null;
1689 } 1691 }
1690 if (listValue.isNullable) return null; 1692 if (listValue.isNullable) return null;
1691 Primitive index = node.dartArgument(0); 1693 Primitive index = node.argument(0);
1692 if (!lattice.isDefinitelyInt(getValue(index))) return null; 1694 if (!lattice.isDefinitelyInt(getValue(index))) return null;
1693 CpsFragment cps = new CpsFragment(node.sourceInformation); 1695 CpsFragment cps = new CpsFragment(node.sourceInformation);
1694 list = makeBoundsCheck(cps, list, index); 1696 list = makeBoundsCheck(cps, list, index);
1695 GetIndex get = cps.letPrim(new GetIndex(list, index)); 1697 GetIndex get = cps.letPrim(new GetIndex(list, index));
1696 get.hint = node.hint; 1698 get.hint = node.hint;
1697 node.replaceUsesWith(get); 1699 node.replaceUsesWith(get);
1698 return cps; 1700 return cps;
1699 1701
1700 case 'forEach': 1702 case 'forEach':
1701 Element element = 1703 Element element =
1702 compiler.world.locateSingleElement(node.selector, listValue.type); 1704 compiler.world.locateSingleElement(node.selector, listValue.type);
1703 if (element == null || 1705 if (element == null ||
1704 !element.isFunction || 1706 !element.isFunction ||
1705 !node.selector.isCall) return null; 1707 !node.selector.isCall) return null;
1706 assert(node.selector.positionalArgumentCount == 1); 1708 assert(node.selector.positionalArgumentCount == 1);
1707 assert(node.selector.namedArgumentCount == 0); 1709 assert(node.selector.namedArgumentCount == 0);
1708 FunctionDefinition target = functionCompiler.compileToCpsIr(element); 1710 FunctionDefinition target = functionCompiler.compileToCpsIr(element);
1709 1711
1710 CpsFragment cps = new CpsFragment(node.sourceInformation); 1712 CpsFragment cps = new CpsFragment(node.sourceInformation);
1711 Primitive result = cps.inlineFunction(target, 1713 Primitive result = cps.inlineFunction(target,
1712 node.receiver, 1714 node.receiver,
1713 node.arguments.toList(), 1715 node.arguments.toList(),
1716 interceptor: node.interceptor,
1714 hint: node.hint); 1717 hint: node.hint);
1715 node.replaceUsesWith(result); 1718 node.replaceUsesWith(result);
1716 return cps; 1719 return cps;
1717 1720
1718 case 'iterator': 1721 case 'iterator':
1719 // TODO(asgerf): This should be done differently. 1722 // TODO(asgerf): This should be done differently.
1720 // The types are recomputed in a very error-prone manner. 1723 // The types are recomputed in a very error-prone manner.
1721 if (!node.selector.isGetter) return null; 1724 if (!node.selector.isGetter) return null;
1722 Primitive iterator = node; 1725 Primitive iterator = node;
1723 LetPrim iteratorBinding = node.parent; 1726 LetPrim iteratorBinding = node.parent;
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
1891 /// => 1894 /// =>
1892 /// obj.foo$<n>(<args>) 1895 /// obj.foo$<n>(<args>)
1893 /// 1896 ///
1894 Primitive specializeClosureCall(InvokeMethod node) { 1897 Primitive specializeClosureCall(InvokeMethod node) {
1895 Selector call = node.selector; 1898 Selector call = node.selector;
1896 if (!call.isClosureCall) return null; 1899 if (!call.isClosureCall) return null;
1897 1900
1898 assert(!isInterceptedSelector(call)); 1901 assert(!isInterceptedSelector(call));
1899 assert(call.argumentCount == node.argumentRefs.length); 1902 assert(call.argumentCount == node.argumentRefs.length);
1900 1903
1901 Primitive tearOff = node.dartReceiver.effectiveDefinition; 1904 Primitive tearOff = node.receiver.effectiveDefinition;
1902 // Note: We don't know if [tearOff] is actually a tear-off. 1905 // Note: We don't know if [tearOff] is actually a tear-off.
1903 // We name variables based on the pattern we are trying to match. 1906 // We name variables based on the pattern we are trying to match.
1904 1907
1905 if (tearOff is GetStatic && tearOff.element.isFunction) { 1908 if (tearOff is GetStatic && tearOff.element.isFunction) {
1906 FunctionElement target = tearOff.element; 1909 FunctionElement target = tearOff.element;
1907 FunctionSignature signature = target.functionSignature; 1910 FunctionSignature signature = target.functionSignature;
1908 1911
1909 // If the selector does not apply, don't bother (will throw at runtime). 1912 // If the selector does not apply, don't bother (will throw at runtime).
1910 if (!call.signatureApplies(target)) return null; 1913 if (!call.signatureApplies(target)) return null;
1911 1914
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
2021 // engines typically do poor optimization of the entire function containing 2024 // engines typically do poor optimization of the entire function containing
2022 // the 'try'. 2025 // the 'try'.
2023 if (functionElement.resolvedAst.elements.containsTryStatement) return null; 2026 if (functionElement.resolvedAst.elements.containsTryStatement) return null;
2024 2027
2025 FunctionDefinition target = 2028 FunctionDefinition target =
2026 functionCompiler.compileToCpsIr(functionElement); 2029 functionCompiler.compileToCpsIr(functionElement);
2027 2030
2028 // Accesses to closed-over values are field access primitives. We we don't 2031 // Accesses to closed-over values are field access primitives. We we don't
2029 // inline if there are other uses of 'this' since that could be an escape or 2032 // inline if there are other uses of 'this' since that could be an escape or
2030 // a recursive call. 2033 // a recursive call.
2031 for (Reference ref = target.thisParameter.firstRef; 2034 for (Reference ref = target.receiverParameter.firstRef;
2032 ref != null; 2035 ref != null;
2033 ref = ref.next) { 2036 ref = ref.next) {
2034 Node use = ref.parent; 2037 Node use = ref.parent;
2035 if (use is GetField) continue; 2038 if (use is GetField) continue;
2036 // Closures do not currently have writable fields, but closure conversion 2039 // Closures do not currently have writable fields, but closure conversion
2037 // could esily be changed to allocate some cells in a closure object. 2040 // could esily be changed to allocate some cells in a closure object.
2038 if (use is SetField && ref == use.objectRef) continue; 2041 if (use is SetField && ref == use.objectRef) continue;
2039 return null; 2042 return null;
2040 } 2043 }
2041 2044
(...skipping 25 matching lines...) Expand all
2067 } 2070 }
2068 2071
2069 visitInvokeMethodDirectly(InvokeMethodDirectly node) { 2072 visitInvokeMethodDirectly(InvokeMethodDirectly node) {
2070 Element target = node.target; 2073 Element target = node.target;
2071 if (target is ConstructorBodyElement) { 2074 if (target is ConstructorBodyElement) {
2072 ConstructorBodyElement constructorBody = target; 2075 ConstructorBodyElement constructorBody = target;
2073 target = constructorBody.constructor; 2076 target = constructorBody.constructor;
2074 } 2077 }
2075 node.effects = 2078 node.effects =
2076 Effects.from(compiler.world.getSideEffectsOfElement(target)); 2079 Effects.from(compiler.world.getSideEffectsOfElement(target));
2077 TypeMask receiverType = node.dartReceiver.type; 2080 TypeMask receiverType = node.receiver.type;
2078 if (node.callingConvention == CallingConvention.Intercepted && 2081 if (node.callingConvention == CallingConvention.Intercepted &&
2079 typeSystem.areDisjoint(receiverType, typeSystem.interceptorType)) { 2082 typeSystem.areDisjoint(receiverType, typeSystem.interceptorType)) {
2080 // Some direct calls take an interceptor because the target class is 2083 // Some direct calls take an interceptor because the target class is
2081 // mixed into a native class. If it is known at the call site that the 2084 // mixed into a native class. If it is known at the call site that the
2082 // receiver is non-intercepted, get rid of the interceptor. 2085 // receiver is non-intercepted, get rid of the interceptor.
2083 node.receiverRef.changeTo(node.dartReceiver); 2086 node.interceptorRef.changeTo(node.receiver);
2084 } 2087 }
2085 } 2088 }
2086 2089
2087 visitInvokeMethod(InvokeMethod node) { 2090 visitInvokeMethod(InvokeMethod node) {
2088 var specialized = 2091 var specialized =
2089 specializeOperatorCall(node) ?? 2092 specializeOperatorCall(node) ??
2090 specializeFieldAccess(node) ?? 2093 specializeFieldAccess(node) ??
2091 specializeIndexableAccess(node) ?? 2094 specializeIndexableAccess(node) ??
2092 specializeArrayAccess(node) ?? 2095 specializeArrayAccess(node) ??
2093 specializeSingleUseClosureCall(node) ?? 2096 specializeSingleUseClosureCall(node) ??
2094 specializeClosureCall(node); 2097 specializeClosureCall(node);
2095 if (specialized != null) return specialized; 2098 if (specialized != null) return specialized;
2096 2099
2097 TypeMask receiverType = node.dartReceiver.type; 2100 TypeMask receiverType = node.receiver.type;
2098 node.mask = typeSystem.intersection(node.mask, receiverType); 2101 node.mask = typeSystem.intersection(node.mask, receiverType);
2099 2102
2100 node.effects = Effects.from( 2103 node.effects = Effects.from(
2101 compiler.world.getSideEffectsOfSelector(node.selector, node.mask)); 2104 compiler.world.getSideEffectsOfSelector(node.selector, node.mask));
2102 2105
2103 bool canBeNonThrowingCallOnNull = 2106 bool canBeNonThrowingCallOnNull =
2104 selectorsOnNull.contains(node.selector) && 2107 selectorsOnNull.contains(node.selector) &&
2105 receiverType.isNullable; 2108 receiverType.isNullable;
2106 2109
2107 if (node.callingConvention == CallingConvention.Intercepted && 2110 if (node.callingConvention == CallingConvention.Intercepted &&
2108 !canBeNonThrowingCallOnNull && 2111 !canBeNonThrowingCallOnNull &&
2109 typeSystem.areDisjoint(receiverType, typeSystem.interceptorType)) { 2112 typeSystem.areDisjoint(receiverType, typeSystem.interceptorType)) {
2110 // Use the Dart receiver as the JS receiver. This changes the wording of 2113 // Use the Dart receiver as the JS receiver. This changes the wording of
2111 // the error message when the receiver is null, but we accept this. 2114 // the error message when the receiver is null, but we accept this.
2112 node.receiverRef.changeTo(node.dartReceiver); 2115 node.interceptorRef.changeTo(node.receiver);
2113 2116
2114 // Replace the extra receiver argument with a dummy value if the 2117 // Replace the extra receiver argument with a dummy value if the
2115 // target definitely does not use it. 2118 // target definitely does not use it.
2116 if (typeSystem.targetIgnoresReceiverArgument(receiverType, 2119 if (typeSystem.targetIgnoresReceiverArgument(receiverType,
2117 node.selector)) { 2120 node.selector)) {
2118 Constant dummy = makeConstantPrimitive(new IntConstantValue(0)); 2121 node.makeDummyIntercepted();
2119 new LetPrim(dummy).insertAbove(node.parent);
2120 node.argumentRefs[0].changeTo(dummy);
2121 node.callingConvention = CallingConvention.DummyIntercepted;
2122 } 2122 }
2123 } 2123 }
2124 } 2124 }
2125 2125
2126 CpsFragment visitTypeCast(TypeCast node) { 2126 CpsFragment visitTypeCast(TypeCast node) {
2127 AbstractConstantValue value = getValue(node.value); 2127 AbstractConstantValue value = getValue(node.value);
2128 switch (lattice.isSubtypeOf(value, node.dartType, allowNull: true)) { 2128 switch (lattice.isSubtypeOf(value, node.dartType, allowNull: true)) {
2129 case AbstractBool.Maybe: 2129 case AbstractBool.Maybe:
2130 case AbstractBool.Nothing: 2130 case AbstractBool.Nothing:
2131 return null; 2131 return null;
(...skipping 16 matching lines...) Expand all
2148 Primitive argument = node.argument(0); 2148 Primitive argument = node.argument(0);
2149 AbstractConstantValue value = getValue(argument); 2149 AbstractConstantValue value = getValue(argument);
2150 if (lattice.isDefinitelyString(value)) { 2150 if (lattice.isDefinitelyString(value)) {
2151 node.replaceUsesWith(argument); 2151 node.replaceUsesWith(argument);
2152 return new CpsFragment(); 2152 return new CpsFragment();
2153 } else if (typeSystem.isDefinitelySelfInterceptor(value.type)) { 2153 } else if (typeSystem.isDefinitelySelfInterceptor(value.type)) {
2154 TypeMask toStringReturn = typeSystem.getInvokeReturnType( 2154 TypeMask toStringReturn = typeSystem.getInvokeReturnType(
2155 Selectors.toString_, value.type); 2155 Selectors.toString_, value.type);
2156 if (typeSystem.isDefinitelyString(toStringReturn)) { 2156 if (typeSystem.isDefinitelyString(toStringReturn)) {
2157 CpsFragment cps = new CpsFragment(node.sourceInformation); 2157 CpsFragment cps = new CpsFragment(node.sourceInformation);
2158 Primitive invoke = cps.invokeMethod(argument, 2158 Primitive invoke = cps.invokeMethod(
2159 argument,
2159 Selectors.toString_, 2160 Selectors.toString_,
2160 value.type, 2161 value.type,
2161 [cps.makeZero()], 2162 [],
2162 CallingConvention.DummyIntercepted); 2163 callingConvention: CallingConvention.DummyIntercepted);
2163 node.replaceUsesWith(invoke); 2164 node.replaceUsesWith(invoke);
2164 return cps; 2165 return cps;
2165 } 2166 }
2166 } 2167 }
2167 } else if (node.target == compiler.identicalFunction) { 2168 } else if (node.target == compiler.identicalFunction) {
2168 if (node.argumentRefs.length == 2) { 2169 if (node.argumentRefs.length == 2) {
2169 return new ApplyBuiltinOperator(BuiltinOperator.Identical, 2170 return new ApplyBuiltinOperator(BuiltinOperator.Identical,
2170 [node.argument(0), node.argument(1)], 2171 [node.argument(0), node.argument(1)],
2171 node.sourceInformation); 2172 node.sourceInformation);
2172 } 2173 }
(...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after
2673 } 2674 }
2674 2675
2675 bool isInterceptedSelector(Selector selector) { 2676 bool isInterceptedSelector(Selector selector) {
2676 return backend.isInterceptedSelector(selector); 2677 return backend.isInterceptedSelector(selector);
2677 } 2678 }
2678 2679
2679 // -------------------------- Visitor overrides ------------------------------ 2680 // -------------------------- Visitor overrides ------------------------------
2680 void visit(Node node) { node.accept(this); } 2681 void visit(Node node) { node.accept(this); }
2681 2682
2682 void visitFunctionDefinition(FunctionDefinition node) { 2683 void visitFunctionDefinition(FunctionDefinition node) {
2683 bool isIntercepted = backend.isInterceptedMethod(node.element); 2684 if (node.interceptorParameter != null) {
2684 2685 setValue(node.interceptorParameter, nonConstant(typeSystem.nonNullType));
2686 }
2685 // If the abstract value of the function parameters is Nothing, use the 2687 // If the abstract value of the function parameters is Nothing, use the
2686 // inferred parameter type. Otherwise (e.g., when inlining) do not 2688 // inferred parameter type. Otherwise (e.g., when inlining) do not
2687 // change the abstract value. 2689 // change the abstract value.
2688 if (node.thisParameter != null && getValue(node.thisParameter).isNothing) { 2690 if (node.receiverParameter != null &&
2689 if (isIntercepted && 2691 getValue(node.receiverParameter).isNothing) {
2690 !typeSystem.methodIgnoresReceiverArgument(node.element)) { 2692 setValue(node.receiverParameter,
2691 setValue(node.thisParameter, nonConstant(typeSystem.nonNullType)); 2693 nonConstant(typeSystem.getReceiverType(node.element)));
2692 } else {
2693 setValue(node.thisParameter,
2694 nonConstant(typeSystem.getReceiverType(node.element)));
2695 }
2696 }
2697 if (isIntercepted && getValue(node.parameters[0]).isNothing) {
2698 if (typeSystem.methodIgnoresReceiverArgument(node.element)) {
2699 setValue(node.parameters[0], nonConstant());
2700 } else {
2701 setValue(node.parameters[0],
2702 nonConstant(typeSystem.getReceiverType(node.element)));
2703 }
2704 } 2694 }
2705 bool hasParameterWithoutValue = false; 2695 bool hasParameterWithoutValue = false;
2706 for (Parameter param in node.parameters.skip(isIntercepted ? 1 : 0)) { 2696 for (Parameter param in node.parameters) {
2707 if (getValue(param).isNothing) { 2697 if (getValue(param).isNothing) {
2708 TypeMask type = param.hint is ParameterElement 2698 TypeMask type = param.hint is ParameterElement
2709 ? typeSystem.getParameterType(param.hint) 2699 ? typeSystem.getParameterType(param.hint)
2710 : typeSystem.dynamicType; 2700 : typeSystem.dynamicType;
2711 setValue(param, lattice.fromMask(type)); 2701 setValue(param, lattice.fromMask(type));
2712 if (type.isEmpty) hasParameterWithoutValue = true; 2702 if (type.isEmpty) hasParameterWithoutValue = true;
2713 } 2703 }
2714 } 2704 }
2715 if (!hasParameterWithoutValue) { // Don't analyze unreachable code. 2705 if (!hasParameterWithoutValue) { // Don't analyze unreachable code.
2716 push(node.body); 2706 push(node.body);
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
2766 // Forward the constant status of all continuation invokes to the 2756 // Forward the constant status of all continuation invokes to the
2767 // continuation. Note that this is effectively a phi node in SSA terms. 2757 // continuation. Note that this is effectively a phi node in SSA terms.
2768 for (int i = 0; i < node.argumentRefs.length; i++) { 2758 for (int i = 0; i < node.argumentRefs.length; i++) {
2769 Primitive def = node.argument(i); 2759 Primitive def = node.argument(i);
2770 AbstractConstantValue cell = getValue(def); 2760 AbstractConstantValue cell = getValue(def);
2771 setValue(cont.parameters[i], cell); 2761 setValue(cont.parameters[i], cell);
2772 } 2762 }
2773 } 2763 }
2774 2764
2775 void visitInvokeMethod(InvokeMethod node) { 2765 void visitInvokeMethod(InvokeMethod node) {
2776 AbstractConstantValue receiver = getValue(node.dartReceiver); 2766 AbstractConstantValue receiver = getValue(node.receiver);
2777 if (receiver.isNothing) { 2767 if (receiver.isNothing) {
2778 return setResult(node, lattice.nothing); 2768 return setResult(node, lattice.nothing);
2779 } 2769 }
2780 2770
2781 void finish(AbstractConstantValue result, {bool canReplace: false}) { 2771 void finish(AbstractConstantValue result, {bool canReplace: false}) {
2782 if (result == null) { 2772 if (result == null) {
2783 canReplace = false; 2773 canReplace = false;
2784 result = lattice.getInvokeReturnType(node.selector, receiver); 2774 result = lattice.getInvokeReturnType(node.selector, receiver);
2785 } 2775 }
2786 setResult(node, result, canReplace: canReplace); 2776 setResult(node, result, canReplace: canReplace);
2787 } 2777 }
2788 2778
2789 if (node.selector.isGetter) { 2779 if (node.selector.isGetter) {
2790 // Constant fold known length of containers. 2780 // Constant fold known length of containers.
2791 if (node.selector == Selectors.length) { 2781 if (node.selector == Selectors.length) {
2792 if (typeSystem.isDefinitelyIndexable(receiver.type, allowNull: true)) { 2782 if (typeSystem.isDefinitelyIndexable(receiver.type, allowNull: true)) {
2793 AbstractConstantValue length = lattice.lengthSpecial(receiver); 2783 AbstractConstantValue length = lattice.lengthSpecial(receiver);
2794 return finish(length, canReplace: !receiver.isNullable); 2784 return finish(length, canReplace: !receiver.isNullable);
2795 } 2785 }
2796 } 2786 }
2797 return finish(null); 2787 return finish(null);
2798 } 2788 }
2799 2789
2800 if (node.selector.isCall) { 2790 if (node.selector.isCall) {
2801 if (node.selector == Selectors.codeUnitAt) { 2791 if (node.selector == Selectors.codeUnitAt) {
2802 AbstractConstantValue right = getValue(node.dartArgument(0)); 2792 AbstractConstantValue right = getValue(node.argument(0));
2803 AbstractConstantValue result = 2793 AbstractConstantValue result =
2804 lattice.codeUnitAtSpecial(receiver, right); 2794 lattice.codeUnitAtSpecial(receiver, right);
2805 return finish(result, canReplace: !receiver.isNullable); 2795 return finish(result, canReplace: !receiver.isNullable);
2806 } 2796 }
2807 return finish(null); 2797 return finish(null);
2808 } 2798 }
2809 2799
2810 if (node.selector == Selectors.index) { 2800 if (node.selector == Selectors.index) {
2811 AbstractConstantValue right = getValue(node.dartArgument(0)); 2801 AbstractConstantValue right = getValue(node.argument(0));
2812 AbstractConstantValue result = lattice.indexSpecial(receiver, right); 2802 AbstractConstantValue result = lattice.indexSpecial(receiver, right);
2813 return finish(result, canReplace: !receiver.isNullable); 2803 return finish(result, canReplace: !receiver.isNullable);
2814 } 2804 }
2815 2805
2816 if (!node.selector.isOperator) { 2806 if (!node.selector.isOperator) {
2817 return finish(null); 2807 return finish(null);
2818 } 2808 }
2819 2809
2820 // Calculate the resulting constant if possible. 2810 // Calculate the resulting constant if possible.
2821 String opname = node.selector.name; 2811 String opname = node.selector.name;
2822 if (node.dartArgumentsLength == 0) { 2812 if (node.argumentRefs.length == 0) {
2823 // Unary operator. 2813 // Unary operator.
2824 if (opname == "unary-") { 2814 if (opname == "unary-") {
2825 opname = "-"; 2815 opname = "-";
2826 } 2816 }
2827 UnaryOperator operator = UnaryOperator.parse(opname); 2817 UnaryOperator operator = UnaryOperator.parse(opname);
2828 AbstractConstantValue result = lattice.unaryOp(operator, receiver); 2818 AbstractConstantValue result = lattice.unaryOp(operator, receiver);
2829 return finish(result, canReplace: !receiver.isNullable); 2819 return finish(result, canReplace: !receiver.isNullable);
2830 } else if (node.dartArgumentsLength == 1) { 2820 } else if (node.argumentRefs.length == 1) {
2831 // Binary operator. 2821 // Binary operator.
2832 AbstractConstantValue right = getValue(node.dartArgument(0)); 2822 AbstractConstantValue right = getValue(node.argument(0));
2833 BinaryOperator operator = BinaryOperator.parse(opname); 2823 BinaryOperator operator = BinaryOperator.parse(opname);
2834 AbstractConstantValue result = 2824 AbstractConstantValue result =
2835 lattice.binaryOp(operator, receiver, right); 2825 lattice.binaryOp(operator, receiver, right);
2836 return finish(result, canReplace: !receiver.isNullable); 2826 return finish(result, canReplace: !receiver.isNullable);
2837 } 2827 }
2838 return finish(null); 2828 return finish(null);
2839 } 2829 }
2840 2830
2841 void visitApplyBuiltinOperator(ApplyBuiltinOperator node) { 2831 void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
2842 2832
(...skipping 714 matching lines...) Expand 10 before | Expand all | Expand 10 after
3557 } 3547 }
3558 3548
3559 Primitive makeCheck(CpsFragment cps, Primitive value) { 3549 Primitive makeCheck(CpsFragment cps, Primitive value) {
3560 return cps.applyBuiltin(negatedOperator, [value]); 3550 return cps.applyBuiltin(negatedOperator, [value]);
3561 } 3551 }
3562 3552
3563 Primitive makeRefinement(CpsFragment cps, Primitive value, World world) { 3553 Primitive makeRefinement(CpsFragment cps, Primitive value, World world) {
3564 return cps.refine(value, new TypeMask.nonNullSubclass(classElement, world)); 3554 return cps.refine(value, new TypeMask.nonNullSubclass(classElement, world));
3565 } 3555 }
3566 } 3556 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/path_based_optimizer.dart ('k') | pkg/compiler/lib/src/js_backend/codegen/glue.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698