| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 // IrNodes are kept in a separate library to have precise control over their | 5 // IrNodes are kept in a separate library to have precise control over their |
| 6 // dependencies on other parts of the system. | 6 // dependencies on other parts of the system. |
| 7 library dart2js.ir_nodes; | 7 library dart2js.ir_nodes; |
| 8 | 8 |
| 9 import '../constants/expressions.dart'; | 9 import '../constants/expressions.dart'; |
| 10 import '../constants/values.dart' as values show ConstantValue; | 10 import '../constants/values.dart' as values show ConstantValue; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 /// All primitives are named using the identity of the [Primitive] object. | 58 /// All primitives are named using the identity of the [Primitive] object. |
| 59 /// | 59 /// |
| 60 /// Primitives may allocate objects, this is not considered side-effect here. | 60 /// Primitives may allocate objects, this is not considered side-effect here. |
| 61 /// | 61 /// |
| 62 /// Although primitives may not mutate state, they may depend on state. | 62 /// Although primitives may not mutate state, they may depend on state. |
| 63 abstract class Primitive extends Definition<Primitive> { | 63 abstract class Primitive extends Definition<Primitive> { |
| 64 /// The [VariableElement] or [ParameterElement] from which the primitive | 64 /// The [VariableElement] or [ParameterElement] from which the primitive |
| 65 /// binding originated. | 65 /// binding originated. |
| 66 Entity hint; | 66 Entity hint; |
| 67 | 67 |
| 68 /// Register in which the variable binding this primitive can be allocated. | |
| 69 /// Separate register spaces are used for primitives with different [element]. | |
| 70 /// Assigned by [RegisterAllocator], is null before that phase. | |
| 71 int registerIndex; | |
| 72 | |
| 73 /// Use the given element as a hint for naming this primitive. | 68 /// Use the given element as a hint for naming this primitive. |
| 74 /// | 69 /// |
| 75 /// Has no effect if this primitive already has a non-null [element]. | 70 /// Has no effect if this primitive already has a non-null [element]. |
| 76 void useElementAsHint(Entity hint) { | 71 void useElementAsHint(Entity hint) { |
| 77 if (this.hint == null) { | 72 if (this.hint == null) { |
| 78 this.hint = hint; | 73 this.hint = hint; |
| 79 } | 74 } |
| 80 } | 75 } |
| 81 } | 76 } |
| 82 | 77 |
| (...skipping 940 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1023 if (!node.isAbstract) { | 1018 if (!node.isAbstract) { |
| 1024 visit(node.body); | 1019 visit(node.body); |
| 1025 } | 1020 } |
| 1026 } | 1021 } |
| 1027 | 1022 |
| 1028 processConstructorDefinition(ConstructorDefinition node) {} | 1023 processConstructorDefinition(ConstructorDefinition node) {} |
| 1029 visitConstructorDefinition(ConstructorDefinition node) { | 1024 visitConstructorDefinition(ConstructorDefinition node) { |
| 1030 processConstructorDefinition(node); | 1025 processConstructorDefinition(node); |
| 1031 if (node.thisParameter != null) visit(node.thisParameter); | 1026 if (node.thisParameter != null) visit(node.thisParameter); |
| 1032 node.parameters.forEach(visit); | 1027 node.parameters.forEach(visit); |
| 1033 node.initializers.forEach(visit); | 1028 if (!node.isAbstract) { |
| 1034 visit(node.body); | 1029 node.initializers.forEach(visit); |
| 1030 visit(node.body); |
| 1031 } |
| 1035 } | 1032 } |
| 1036 | 1033 |
| 1037 processFieldInitializer(FieldInitializer node) {} | 1034 processFieldInitializer(FieldInitializer node) {} |
| 1038 visitFieldInitializer(FieldInitializer node) { | 1035 visitFieldInitializer(FieldInitializer node) { |
| 1039 processFieldInitializer(node); | 1036 processFieldInitializer(node); |
| 1040 visit(node.body); | 1037 visit(node.body); |
| 1041 } | 1038 } |
| 1042 | 1039 |
| 1043 processSuperInitializer(SuperInitializer node) {} | 1040 processSuperInitializer(SuperInitializer node) {} |
| 1044 visitSuperInitializer(SuperInitializer node) { | 1041 visitSuperInitializer(SuperInitializer node) { |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1262 processReference(node.target); | 1259 processReference(node.target); |
| 1263 } | 1260 } |
| 1264 | 1261 |
| 1265 processTypeExpression(TypeExpression node) {} | 1262 processTypeExpression(TypeExpression node) {} |
| 1266 @override | 1263 @override |
| 1267 visitTypeExpression(TypeExpression node) { | 1264 visitTypeExpression(TypeExpression node) { |
| 1268 processTypeExpression(node); | 1265 processTypeExpression(node); |
| 1269 node.arguments.forEach(processReference); | 1266 node.arguments.forEach(processReference); |
| 1270 } | 1267 } |
| 1271 } | 1268 } |
| 1272 | |
| 1273 /// Keeps track of currently unused register indices. | |
| 1274 class RegisterArray { | |
| 1275 int nextIndex = 0; | |
| 1276 final List<int> freeStack = <int>[]; | |
| 1277 | |
| 1278 /// Returns an index that is currently unused. | |
| 1279 int makeIndex() { | |
| 1280 if (freeStack.isEmpty) { | |
| 1281 return nextIndex++; | |
| 1282 } else { | |
| 1283 return freeStack.removeLast(); | |
| 1284 } | |
| 1285 } | |
| 1286 | |
| 1287 void releaseIndex(int index) { | |
| 1288 freeStack.add(index); | |
| 1289 } | |
| 1290 } | |
| 1291 | |
| 1292 /// Assigns indices to each primitive in the IR such that primitives that are | |
| 1293 /// live simultaneously never get assigned the same index. | |
| 1294 /// This information is used by the dart tree builder to generate fewer | |
| 1295 /// redundant variables. | |
| 1296 /// Currently, the liveness analysis is very simple and is often inadequate | |
| 1297 /// for removing all of the redundant variables. | |
| 1298 class RegisterAllocator implements Visitor { | |
| 1299 final dart2js.InternalErrorFunction internalError; | |
| 1300 | |
| 1301 /// Separate register spaces for each source-level variable/parameter. | |
| 1302 /// Note that null is used as key for primitives without hints. | |
| 1303 final Map<Local, RegisterArray> elementRegisters = <Local, RegisterArray>{}; | |
| 1304 | |
| 1305 RegisterAllocator(this.internalError); | |
| 1306 | |
| 1307 RegisterArray getRegisterArray(Local local) { | |
| 1308 RegisterArray registers = elementRegisters[local]; | |
| 1309 if (registers == null) { | |
| 1310 registers = new RegisterArray(); | |
| 1311 elementRegisters[local] = registers; | |
| 1312 } | |
| 1313 return registers; | |
| 1314 } | |
| 1315 | |
| 1316 void allocate(Primitive primitive) { | |
| 1317 if (primitive.registerIndex == null) { | |
| 1318 primitive.registerIndex = getRegisterArray(primitive.hint).makeIndex(); | |
| 1319 } | |
| 1320 } | |
| 1321 | |
| 1322 void release(Primitive primitive) { | |
| 1323 // Do not share indices for temporaries as this may obstruct inlining. | |
| 1324 if (primitive.hint == null) return; | |
| 1325 if (primitive.registerIndex != null) { | |
| 1326 getRegisterArray(primitive.hint).releaseIndex(primitive.registerIndex); | |
| 1327 } | |
| 1328 } | |
| 1329 | |
| 1330 void visit(Node node) => node.accept(this); | |
| 1331 | |
| 1332 void visitReference(Reference reference) { | |
| 1333 allocate(reference.definition); | |
| 1334 } | |
| 1335 | |
| 1336 void visitFieldDefinition(FieldDefinition node) { | |
| 1337 if (node.hasInitializer) { | |
| 1338 visit(node.body); | |
| 1339 } | |
| 1340 } | |
| 1341 | |
| 1342 void visitRunnableBody(RunnableBody node) { | |
| 1343 visit(node.body); | |
| 1344 } | |
| 1345 | |
| 1346 void visitFunctionDefinition(FunctionDefinition node) { | |
| 1347 if (!node.isAbstract) { | |
| 1348 visit(node.body); | |
| 1349 } | |
| 1350 // Assign indices to unused parameters. | |
| 1351 for (Definition param in node.parameters) { | |
| 1352 if (param is Primitive) { | |
| 1353 allocate(param); | |
| 1354 } | |
| 1355 } | |
| 1356 } | |
| 1357 | |
| 1358 void visitConstructorDefinition(ConstructorDefinition node) { | |
| 1359 if (!node.isAbstract) { | |
| 1360 node.initializers.forEach(visit); | |
| 1361 visit(node.body); | |
| 1362 } | |
| 1363 // Assign indices to unused parameters. | |
| 1364 for (Definition param in node.parameters) { | |
| 1365 if (param is Primitive) { | |
| 1366 allocate(param); | |
| 1367 } | |
| 1368 } | |
| 1369 } | |
| 1370 | |
| 1371 void visitFieldInitializer(FieldInitializer node) { | |
| 1372 visit(node.body.body); | |
| 1373 } | |
| 1374 | |
| 1375 void visitSuperInitializer(SuperInitializer node) { | |
| 1376 node.arguments.forEach(visit); | |
| 1377 } | |
| 1378 | |
| 1379 void visitLetPrim(LetPrim node) { | |
| 1380 visit(node.body); | |
| 1381 release(node.primitive); | |
| 1382 visit(node.primitive); | |
| 1383 } | |
| 1384 | |
| 1385 void visitLetCont(LetCont node) { | |
| 1386 node.continuations.forEach(visit); | |
| 1387 visit(node.body); | |
| 1388 } | |
| 1389 | |
| 1390 void visitLetHandler(LetHandler node) { | |
| 1391 visit(node.handler); | |
| 1392 // Handler parameters that were not used in the handler body will not have | |
| 1393 // had register indexes assigned. Assign them here, otherwise they will | |
| 1394 // be eliminated later and they should not be (i.e., a catch clause that | |
| 1395 // does not use the exception parameter should not have the exception | |
| 1396 // parameter eliminated, because it would not be well-formed anymore). | |
| 1397 // In any case release the parameter indexes because the parameters are | |
| 1398 // not live in the try block. | |
| 1399 node.handler.parameters.forEach((Parameter parameter) { | |
| 1400 allocate(parameter); | |
| 1401 release(parameter); | |
| 1402 }); | |
| 1403 visit(node.body); | |
| 1404 } | |
| 1405 | |
| 1406 void visitLetMutable(LetMutable node) { | |
| 1407 visit(node.body); | |
| 1408 visitReference(node.value); | |
| 1409 } | |
| 1410 | |
| 1411 void visitInvokeStatic(InvokeStatic node) { | |
| 1412 node.arguments.forEach(visitReference); | |
| 1413 } | |
| 1414 | |
| 1415 void visitInvokeContinuation(InvokeContinuation node) { | |
| 1416 node.arguments.forEach(visitReference); | |
| 1417 } | |
| 1418 | |
| 1419 void visitInvokeMethod(InvokeMethod node) { | |
| 1420 visitReference(node.receiver); | |
| 1421 node.arguments.forEach(visitReference); | |
| 1422 } | |
| 1423 | |
| 1424 void visitInvokeMethodDirectly(InvokeMethodDirectly node) { | |
| 1425 visitReference(node.receiver); | |
| 1426 node.arguments.forEach(visitReference); | |
| 1427 } | |
| 1428 | |
| 1429 void visitInvokeConstructor(InvokeConstructor node) { | |
| 1430 node.arguments.forEach(visitReference); | |
| 1431 } | |
| 1432 | |
| 1433 void visitConcatenateStrings(ConcatenateStrings node) { | |
| 1434 node.arguments.forEach(visitReference); | |
| 1435 } | |
| 1436 | |
| 1437 void visitBranch(Branch node) { | |
| 1438 visit(node.condition); | |
| 1439 } | |
| 1440 | |
| 1441 void visitLiteralList(LiteralList node) { | |
| 1442 node.values.forEach(visitReference); | |
| 1443 } | |
| 1444 | |
| 1445 void visitLiteralMap(LiteralMap node) { | |
| 1446 for (LiteralMapEntry entry in node.entries) { | |
| 1447 visitReference(entry.key); | |
| 1448 visitReference(entry.value); | |
| 1449 } | |
| 1450 } | |
| 1451 | |
| 1452 void visitTypeOperator(TypeOperator node) { | |
| 1453 visitReference(node.receiver); | |
| 1454 } | |
| 1455 | |
| 1456 void visitConstant(Constant node) { | |
| 1457 } | |
| 1458 | |
| 1459 void visitReifyTypeVar(ReifyTypeVar node) { | |
| 1460 } | |
| 1461 | |
| 1462 void visitCreateFunction(CreateFunction node) { | |
| 1463 new RegisterAllocator(internalError).visit(node.definition); | |
| 1464 } | |
| 1465 | |
| 1466 void visitGetMutableVariable(GetMutableVariable node) { | |
| 1467 } | |
| 1468 | |
| 1469 void visitSetMutableVariable(SetMutableVariable node) { | |
| 1470 visit(node.body); | |
| 1471 visitReference(node.value); | |
| 1472 } | |
| 1473 | |
| 1474 void visitDeclareFunction(DeclareFunction node) { | |
| 1475 new RegisterAllocator(internalError).visit(node.definition); | |
| 1476 visit(node.body); | |
| 1477 } | |
| 1478 | |
| 1479 void visitParameter(Parameter node) { | |
| 1480 // Parameters are handled differently depending on whether they are | |
| 1481 // function parameters, continuation parameters, exception handler | |
| 1482 // parameters, etc. Thus we do not call visitParameter directly and | |
| 1483 // handle them explicitly in their parent IR node. | |
| 1484 internalError(dart2js.CURRENT_ELEMENT_SPANNABLE, | |
| 1485 'tried to allocate a parameter'); | |
| 1486 } | |
| 1487 | |
| 1488 void visitMutableVariable(MutableVariable node) {} | |
| 1489 | |
| 1490 void visitContinuation(Continuation node) { | |
| 1491 visit(node.body); | |
| 1492 | |
| 1493 // Arguments get allocated left-to-right, so we release parameters | |
| 1494 // right-to-left. This increases the likelihood that arguments can be | |
| 1495 // transferred without intermediate assignments. | |
| 1496 for (int i = node.parameters.length - 1; i >= 0; --i) { | |
| 1497 release(node.parameters[i]); | |
| 1498 } | |
| 1499 } | |
| 1500 | |
| 1501 void visitIsTrue(IsTrue node) { | |
| 1502 visitReference(node.value); | |
| 1503 } | |
| 1504 | |
| 1505 // JavaScript specific nodes. | |
| 1506 | |
| 1507 void visitSetField(SetField node) { | |
| 1508 visit(node.body); | |
| 1509 visitReference(node.value); | |
| 1510 visitReference(node.object); | |
| 1511 } | |
| 1512 | |
| 1513 void visitGetField(GetField node) { | |
| 1514 visitReference(node.object); | |
| 1515 } | |
| 1516 | |
| 1517 void visitCreateBox(CreateBox node) { | |
| 1518 } | |
| 1519 | |
| 1520 void visitCreateInstance(CreateInstance node) { | |
| 1521 node.arguments.forEach(visitReference); | |
| 1522 node.typeInformation.forEach(visitReference); | |
| 1523 } | |
| 1524 | |
| 1525 void visitIdentical(Identical node) { | |
| 1526 visitReference(node.left); | |
| 1527 visitReference(node.right); | |
| 1528 } | |
| 1529 | |
| 1530 void visitInterceptor(Interceptor node) { | |
| 1531 visitReference(node.input); | |
| 1532 } | |
| 1533 | |
| 1534 void visitReifyRuntimeType(ReifyRuntimeType node) { | |
| 1535 visitReference(node.value); | |
| 1536 } | |
| 1537 | |
| 1538 void visitReadTypeVariable(ReadTypeVariable node) { | |
| 1539 visitReference(node.target); | |
| 1540 } | |
| 1541 | |
| 1542 @override | |
| 1543 visitTypeExpression(TypeExpression node) { | |
| 1544 node.arguments.forEach(visitReference); | |
| 1545 } | |
| 1546 } | |
| OLD | NEW |