Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 class SsaCodeGeneratorTask extends CompilerTask { | 5 class SsaCodeGeneratorTask extends CompilerTask { |
| 6 final JavaScriptBackend backend; | 6 final JavaScriptBackend backend; |
| 7 SsaCodeGeneratorTask(JavaScriptBackend backend) | 7 SsaCodeGeneratorTask(JavaScriptBackend backend) |
| 8 : this.backend = backend, | 8 : this.backend = backend, |
| 9 super(backend.compiler); | 9 super(backend.compiler); |
| 10 String get name() => 'SSA code generator'; | 10 String get name() => 'SSA code generator'; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 116 static final int STATE_EXPRESSION = 3; | 116 static final int STATE_EXPRESSION = 3; |
| 117 static final int STATE_DECLARATION = 4; | 117 static final int STATE_DECLARATION = 4; |
| 118 | 118 |
| 119 /** | 119 /** |
| 120 * When analyzing a [HStatementGraph] we try to recognize if it has | 120 * When analyzing a [HStatementGraph] we try to recognize if it has |
| 121 * the following properties. | 121 * the following properties. |
| 122 */ | 122 */ |
| 123 static final int ONE_STATEMENT = 0; | 123 static final int ONE_STATEMENT = 0; |
| 124 static final int ONE_EXPRESSION = 1; | 124 static final int ONE_EXPRESSION = 1; |
| 125 static final int EMPTY = 2; | 125 static final int EMPTY = 2; |
| 126 static final int MULTIPLE_STATEMENTS = 3; | 126 static final int IF_STATEMENT = 3; |
| 127 static final int MULTIPLE_STATEMENTS = 4; | |
| 127 | 128 |
| 128 /** | 129 /** |
| 129 * Returned by [expressionType] to tell how code can be generated for | 130 * Returned by [expressionType] to tell how code can be generated for |
| 130 * a subgraph. | 131 * a subgraph. |
| 131 * - [TYPE_STATEMENT] means that the graph must be generated as a statement, | 132 * - [TYPE_STATEMENT] means that the graph must be generated as a statement, |
| 132 * which is always possible. | 133 * which is always possible. |
| 133 * - [TYPE_EXPRESSION] means that the graph can be generated as an expression, | 134 * - [TYPE_EXPRESSION] means that the graph can be generated as an expression, |
| 134 * or possibly several comma-separated expressions. | 135 * or possibly several comma-separated expressions. |
| 135 * - [TYPE_DECLARATION] means that the graph can be generated as an | 136 * - [TYPE_DECLARATION] means that the graph can be generated as an |
| 136 * expression, and that it only generates expressions of the form | 137 * expression, and that it only generates expressions of the form |
| (...skipping 1171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1308 // information in [visitTryInfo], or not at all, in the case of the bailout | 1309 // information in [visitTryInfo], or not at all, in the case of the bailout |
| 1309 // generator. | 1310 // generator. |
| 1310 compiler.internalError('visitTry should not be called', instruction: node); | 1311 compiler.internalError('visitTry should not be called', instruction: node); |
| 1311 } | 1312 } |
| 1312 | 1313 |
| 1313 /** | 1314 /** |
| 1314 * Analyzes the given [graph] to know whether it is empty, or | 1315 * Analyzes the given [graph] to know whether it is empty, or |
| 1315 * contains one statement, one expression, or multiple statements. | 1316 * contains one statement, one expression, or multiple statements. |
| 1316 */ | 1317 */ |
| 1317 int analyzeGraphForCodegen(HStatementInformation graph) { | 1318 int analyzeGraphForCodegen(HStatementInformation graph) { |
| 1318 HBasicBlock start = graph.start; | 1319 return analyzeBlocksForCodegen(graph.start, graph.end); |
| 1319 HBasicBlock end = graph.end; | 1320 } |
| 1320 // Only deal with single blocks for now. TODO(ngeoffray): analyze | |
| 1321 // all blocks. | |
| 1322 if (start !== end) return MULTIPLE_STATEMENTS; | |
| 1323 | 1321 |
| 1322 int analyzeBlocksForCodegen(HBasicBlock start, HBasicBlock end) { | |
| 1324 int kind = EMPTY; | 1323 int kind = EMPTY; |
| 1325 bool updateKind(int newKind) { | 1324 bool updateKind(int newKind) { |
| 1326 if (kind != EMPTY) return false; | 1325 if (kind != EMPTY) return false; |
| 1327 kind = newKind; | 1326 kind = newKind; |
| 1328 return true; | 1327 return true; |
| 1329 } | 1328 } |
| 1330 | 1329 |
| 1331 for (HInstruction instruction = start.first; | 1330 for (HInstruction instruction = start.first; |
| 1332 instruction != start.last; | 1331 instruction != start.last; |
| 1333 instruction = instruction.next) { | 1332 instruction = instruction.next) { |
| 1334 if (instruction.isStatement()) { | 1333 if (instruction.isStatement()) { |
| 1335 if (!updateKind(ONE_STATEMENT)) return MULTIPLE_STATEMENTS; | 1334 if (!updateKind(ONE_STATEMENT)) return MULTIPLE_STATEMENTS; |
| 1336 } else if (!isGenerateAtUseSite(instruction)) { | 1335 } else if (!isGenerateAtUseSite(instruction)) { |
| 1337 if (!updateKind(ONE_EXPRESSION)) return MULTIPLE_STATEMENTS; | 1336 if (!updateKind(ONE_EXPRESSION)) return MULTIPLE_STATEMENTS; |
| 1338 } | 1337 } |
| 1339 } | 1338 } |
| 1340 | 1339 |
| 1341 HInstruction last = start.last; | 1340 HInstruction last = start.last; |
| 1342 if (last is !HGoto) { | 1341 if (last is HGoto) { |
| 1343 if (!updateKind(last.isStatement() ? ONE_STATEMENT : ONE_EXPRESSION)) { | 1342 if (start !== end) { |
| 1343 int nextKind = analyzeBlocksForCodegen(start.successors[0], end); | |
| 1344 if (!updateKind(nextKind)) return MULTIPLE_STATEMENTS; | |
| 1345 } | |
| 1346 } else if (last is HIf) { | |
| 1347 HIf ifInstruction = last; | |
| 1348 if (ifInstruction.joinBlock !== null | |
| 1349 && analyzeBlocksForCodegen(ifInstruction.joinBlock, end) != EMPTY) { | |
| 1344 return MULTIPLE_STATEMENTS; | 1350 return MULTIPLE_STATEMENTS; |
| 1345 } | 1351 } |
| 1352 int ifKind = controlFlowOperators.contains(ifInstruction) | |
| 1353 ? ONE_EXPRESSION | |
| 1354 : IF_STATEMENT; | |
|
Lasse Reichstein Nielsen
2012/06/15 08:31:01
Maybe (later) consider whether the if-"statement"
| |
| 1355 if (!updateKind(ifKind)) return MULTIPLE_STATEMENTS; | |
| 1356 } else if (start !== end) { | |
| 1357 return MULTIPLE_STATEMENTS; | |
| 1358 } else if (!updateKind(last.isStatement() ? ONE_STATEMENT : ONE_EXPRESSION)) { | |
| 1359 return MULTIPLE_STATEMENTS; | |
| 1346 } | 1360 } |
| 1347 | 1361 |
| 1348 CopyHandler handler = variableNames.getCopyHandler(start); | 1362 CopyHandler handler = variableNames.getCopyHandler(start); |
| 1349 if (handler !== null && !handler.isEmpty()) { | 1363 if (handler !== null && !handler.isEmpty()) { |
| 1350 if (handler.assignments.length > 1) return MULTIPLE_STATEMENTS; | 1364 if (handler.assignments.length > 1) return MULTIPLE_STATEMENTS; |
| 1351 if (handler.assignments.length == 1) { | 1365 if (handler.assignments.length == 1) { |
| 1352 if (!updateKind(ONE_STATEMENT)) return MULTIPLE_STATEMENTS; | 1366 if (!updateKind(ONE_STATEMENT)) return MULTIPLE_STATEMENTS; |
| 1353 } | 1367 } |
| 1354 // If the block has a copy where the destination and source are | 1368 // If the block has a copy where the destination and source are |
| 1355 // different, we will emit that copy, and therefore the block is | 1369 // different, we will emit that copy, and therefore the block is |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 1369 if (!controlFlowOperators.contains(node)) return false; | 1383 if (!controlFlowOperators.contains(node)) return false; |
| 1370 HPhi phi = node.joinBlock.phis.first; | 1384 HPhi phi = node.joinBlock.phis.first; |
| 1371 bool atUseSite = isGenerateAtUseSite(phi); | 1385 bool atUseSite = isGenerateAtUseSite(phi); |
| 1372 // Don't generate a conditional operator in this situation: | 1386 // Don't generate a conditional operator in this situation: |
| 1373 // i = condition ? bar() : i; | 1387 // i = condition ? bar() : i; |
| 1374 // But generate this instead: | 1388 // But generate this instead: |
| 1375 // if (condition) i = bar(); | 1389 // if (condition) i = bar(); |
| 1376 // Usually, the variable name is longer than 'if' and it takes up | 1390 // Usually, the variable name is longer than 'if' and it takes up |
| 1377 // more space to duplicate the name. | 1391 // more space to duplicate the name. |
| 1378 if (!atUseSite | 1392 if (!atUseSite |
| 1393 && !generatingInlineStatement | |
| 1379 && variableNames.getName(phi) == variableNames.getName(phi.inputs[1])) { | 1394 && variableNames.getName(phi) == variableNames.getName(phi.inputs[1])) { |
| 1380 return false; | 1395 return false; |
| 1381 } | 1396 } |
| 1382 if (!atUseSite) define(phi); | 1397 if (!atUseSite) define(phi); |
| 1383 visitBasicBlock(node.joinBlock); | 1398 visitBasicBlock(node.joinBlock); |
| 1384 return true; | 1399 return true; |
| 1385 } | 1400 } |
| 1386 | 1401 |
| 1387 void generateIf(HIf node, HIfBlockInformation info) { | 1402 void generateIf(HIf node, HIfBlockInformation info) { |
| 1388 HStatementInformation thenGraph = info.thenGraph; | 1403 HStatementInformation thenGraph = info.thenGraph; |
| 1389 HStatementInformation elseGraph = info.elseGraph; | 1404 HStatementInformation elseGraph = info.elseGraph; |
| 1390 int thenKind = analyzeGraphForCodegen(thenGraph); | 1405 int thenKind = analyzeGraphForCodegen(thenGraph); |
| 1391 int elseKind = analyzeGraphForCodegen(elseGraph); | 1406 int elseKind = analyzeGraphForCodegen(elseGraph); |
| 1392 | 1407 |
| 1393 void visitWithoutIndent(HStatementInformation toVisit) { | 1408 void visitWithoutIndent(HStatementInformation toVisit) { |
| 1394 int oldIndent = indent; | 1409 generatingInlineStatement = true; |
| 1395 indent = 0; | 1410 visitSubGraph(new SubGraph(toVisit.start, toVisit.end)); |
| 1396 generateStatements(toVisit); | |
| 1397 indent = oldIndent; | |
| 1398 } | 1411 } |
| 1399 | 1412 |
| 1400 void visitWithIndent(HStatementInformation toVisit) { | 1413 void visitWithIndent(HStatementInformation toVisit) { |
| 1401 buffer.add('{\n'); | 1414 buffer.add('{\n'); |
| 1402 indent++; | 1415 indent++; |
| 1403 generateStatements(toVisit); | 1416 visitSubGraph(new SubGraph(toVisit.start, toVisit.end)); |
| 1404 indent--; | 1417 indent--; |
| 1405 addIndented('}'); | 1418 addIndented('}'); |
| 1406 } | 1419 } |
| 1407 | 1420 |
| 1408 void emitIf() { | 1421 void emitIf() { |
| 1409 addIndented('if ('); | 1422 addIndented('if ('); |
| 1410 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); | 1423 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); |
| 1411 buffer.add(') '); | 1424 buffer.add(') '); |
| 1412 } | 1425 } |
| 1413 | 1426 |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 1437 use(node.inputs[0], JSPrecedence.STATEMENT_PRECEDENCE); | 1450 use(node.inputs[0], JSPrecedence.STATEMENT_PRECEDENCE); |
| 1438 buffer.add(';\n'); | 1451 buffer.add(';\n'); |
| 1439 } | 1452 } |
| 1440 break; | 1453 break; |
| 1441 | 1454 |
| 1442 case ONE_EXPRESSION: | 1455 case ONE_EXPRESSION: |
| 1443 generateAnd(elseGraph, () { generateNot(node.inputs[0]); }); | 1456 generateAnd(elseGraph, () { generateNot(node.inputs[0]); }); |
| 1444 break; | 1457 break; |
| 1445 | 1458 |
| 1446 case ONE_STATEMENT: | 1459 case ONE_STATEMENT: |
| 1460 case IF_STATEMENT: | |
| 1447 addIndented('if ('); | 1461 addIndented('if ('); |
| 1448 generateNot(node.inputs[0]); | 1462 generateNot(node.inputs[0]); |
| 1449 buffer.add(') '); | 1463 buffer.add(') '); |
| 1450 visitWithoutIndent(elseGraph); | 1464 visitWithoutIndent(elseGraph); |
| 1451 break; | 1465 break; |
| 1452 | 1466 |
| 1453 case MULTIPLE_STATEMENTS: | 1467 case MULTIPLE_STATEMENTS: |
| 1454 addIndented('if ('); | 1468 addIndented('if ('); |
| 1455 generateNot(node.inputs[0]); | 1469 generateNot(node.inputs[0]); |
| 1456 buffer.add(') '); | 1470 buffer.add(') '); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1469 int precedence = operatorPrecedence.left; | 1483 int precedence = operatorPrecedence.left; |
| 1470 generateAnd(thenGraph, () { use(node.inputs[0], precedence); }); | 1484 generateAnd(thenGraph, () { use(node.inputs[0], precedence); }); |
| 1471 } else { | 1485 } else { |
| 1472 emitIf(); | 1486 emitIf(); |
| 1473 visitWithoutIndent(thenGraph); | 1487 visitWithoutIndent(thenGraph); |
| 1474 } | 1488 } |
| 1475 break; | 1489 break; |
| 1476 | 1490 |
| 1477 case ONE_EXPRESSION: | 1491 case ONE_EXPRESSION: |
| 1478 case ONE_STATEMENT: | 1492 case ONE_STATEMENT: |
| 1493 case IF_STATEMENT: | |
| 1479 // TODO(ngeoffray): Generate a conditional. | 1494 // TODO(ngeoffray): Generate a conditional. |
| 1480 emitIf(); | 1495 emitIf(); |
| 1481 visitWithoutIndent(thenGraph); | 1496 visitWithoutIndent(thenGraph); |
| 1482 if (thenGraphHasSuccessor) { | 1497 if (thenGraphHasSuccessor) { |
| 1483 addIndented('else '); | 1498 addIndented('else '); |
| 1484 visitWithoutIndent(elseGraph); | 1499 visitWithoutIndent(elseGraph); |
| 1485 } else { | 1500 } else { |
| 1486 generateStatements(elseGraph); | 1501 generateStatements(elseGraph); |
| 1487 } | 1502 } |
| 1488 break; | 1503 break; |
| 1489 | 1504 |
| 1490 case MULTIPLE_STATEMENTS: | 1505 case MULTIPLE_STATEMENTS: |
| 1491 emitIf(); | 1506 emitIf(); |
| 1492 visitWithoutIndent(thenGraph); | 1507 visitWithoutIndent(thenGraph); |
| 1493 if (thenGraphHasSuccessor) { | 1508 if (thenGraphHasSuccessor) { |
| 1494 addIndented('else '); | 1509 addIndented('else '); |
| 1495 visitWithIndent(elseGraph); | 1510 visitWithIndent(elseGraph); |
| 1496 buffer.add('\n'); | 1511 buffer.add('\n'); |
| 1497 } else { | 1512 } else { |
| 1498 generateStatements(elseGraph); | 1513 generateStatements(elseGraph); |
| 1499 } | 1514 } |
| 1500 break; | 1515 break; |
| 1501 } | 1516 } |
| 1502 break; | 1517 break; |
| 1503 | 1518 |
| 1504 case MULTIPLE_STATEMENTS: | 1519 case MULTIPLE_STATEMENTS: |
| 1520 case IF_STATEMENT: | |
| 1505 emitIf(); | 1521 emitIf(); |
| 1506 visitWithIndent(thenGraph); | 1522 visitWithIndent(thenGraph); |
| 1507 | 1523 |
| 1508 switch (elseKind) { | 1524 switch (elseKind) { |
| 1509 case EMPTY: | 1525 case EMPTY: |
| 1510 buffer.add('\n'); | 1526 buffer.add('\n'); |
| 1511 break; | 1527 break; |
| 1512 | 1528 |
| 1513 case ONE_EXPRESSION: | 1529 case ONE_EXPRESSION: |
| 1514 case ONE_STATEMENT: | 1530 case ONE_STATEMENT: |
| 1531 case IF_STATEMENT: | |
| 1515 if (thenGraphHasSuccessor) { | 1532 if (thenGraphHasSuccessor) { |
| 1516 buffer.add(' else '); | 1533 buffer.add(' else '); |
| 1517 visitWithoutIndent(elseGraph); | 1534 visitWithoutIndent(elseGraph); |
| 1518 } else { | 1535 } else { |
| 1519 buffer.add('\n'); | 1536 buffer.add('\n'); |
| 1520 generateStatements(elseGraph); | 1537 generateStatements(elseGraph); |
| 1521 } | 1538 } |
| 1522 break; | 1539 break; |
| 1523 | 1540 |
| 1524 case MULTIPLE_STATEMENTS: | 1541 case MULTIPLE_STATEMENTS: |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 1547 return; | 1564 return; |
| 1548 } | 1565 } |
| 1549 | 1566 |
| 1550 HInstruction condition = node.inputs[0]; | 1567 HInstruction condition = node.inputs[0]; |
| 1551 HIfBlockInformation info = node.blockInformation.body; | 1568 HIfBlockInformation info = node.blockInformation.body; |
| 1552 | 1569 |
| 1553 if (condition.isConstant()) { | 1570 if (condition.isConstant()) { |
| 1554 HConstant constant = condition; | 1571 HConstant constant = condition; |
| 1555 if (constant.constant.isTrue()) { | 1572 if (constant.constant.isTrue()) { |
| 1556 generateStatements(info.thenGraph); | 1573 generateStatements(info.thenGraph); |
| 1574 int thenKind = analyzeGraphForCodegen(info.thenGraph); | |
| 1575 if (thenKind == EMPTY && generatingInlineStatement) { | |
| 1576 generatingInlineStatement = false; | |
|
Lasse Reichstein Nielsen
2012/06/15 08:31:01
Explain why you set generatingInlineStatement to f
ngeoffray
2012/06/18 15:43:25
Done.
| |
| 1577 buffer.add(';\n'); | |
| 1578 } | |
| 1557 } else { | 1579 } else { |
| 1558 generateStatements(info.elseGraph); | 1580 generateStatements(info.elseGraph); |
| 1581 int elseKind = analyzeGraphForCodegen(info.elseGraph); | |
| 1582 if (elseKind == EMPTY && generatingInlineStatement) { | |
| 1583 generatingInlineStatement = false; | |
| 1584 buffer.add(';\n'); | |
| 1585 } | |
| 1559 } | 1586 } |
| 1560 } else { | 1587 } else { |
| 1561 generateIf(node, info); | 1588 generateIf(node, info); |
| 1562 } | 1589 } |
| 1563 | 1590 |
| 1564 HBasicBlock joinBlock = node.joinBlock; | 1591 HBasicBlock joinBlock = node.joinBlock; |
| 1565 if (joinBlock !== null && joinBlock.dominator !== node.block) { | 1592 if (joinBlock !== null && joinBlock.dominator !== node.block) { |
| 1566 // The join block is dominated by a block in one of the branches. | 1593 // The join block is dominated by a block in one of the branches. |
| 1567 // The subgraph traversal never reached it, so we visit it here | 1594 // The subgraph traversal never reached it, so we visit it here |
| 1568 // instead. | 1595 // instead. |
| (...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1995 world.registerStaticUse(helper); | 2022 world.registerStaticUse(helper); |
| 1996 buffer.add('throw '); | 2023 buffer.add('throw '); |
| 1997 beginExpression(JSPrecedence.EXPRESSION_PRECEDENCE); | 2024 beginExpression(JSPrecedence.EXPRESSION_PRECEDENCE); |
| 1998 beginExpression(JSPrecedence.CALL_PRECEDENCE); | 2025 beginExpression(JSPrecedence.CALL_PRECEDENCE); |
| 1999 buffer.add(compiler.namer.isolateAccess(helper)); | 2026 buffer.add(compiler.namer.isolateAccess(helper)); |
| 2000 visitArguments([null, argument]); | 2027 visitArguments([null, argument]); |
| 2001 endExpression(JSPrecedence.CALL_PRECEDENCE); | 2028 endExpression(JSPrecedence.CALL_PRECEDENCE); |
| 2002 endExpression(JSPrecedence.EXPRESSION_PRECEDENCE); | 2029 endExpression(JSPrecedence.EXPRESSION_PRECEDENCE); |
| 2003 } | 2030 } |
| 2004 | 2031 |
| 2032 bool generatingInlineStatement = false; | |
|
Lasse Reichstein Nielsen
2012/06/15 08:31:01
Move this field to the top of the class, and docum
ngeoffray
2012/06/18 15:43:25
Done.
| |
| 2005 void addIndentation() { | 2033 void addIndentation() { |
| 2006 for (int i = 0; i < indent; i++) { | 2034 if (generatingInlineStatement) { |
| 2007 buffer.add(' '); | 2035 generatingInlineStatement = false; |
| 2036 } else { | |
| 2037 for (int i = 0; i < indent; i++) { | |
| 2038 buffer.add(' '); | |
| 2039 } | |
| 2008 } | 2040 } |
| 2009 } | 2041 } |
| 2010 | 2042 |
| 2011 void addIndented(String text) { | 2043 void addIndented(String text) { |
| 2012 addIndentation(); | 2044 addIndentation(); |
| 2013 buffer.add(text); | 2045 buffer.add(text); |
| 2014 } | 2046 } |
| 2015 | 2047 |
| 2016 void visitSwitch(HSwitch node) { | 2048 void visitSwitch(HSwitch node) { |
| 2017 // Switches are handled using [visitSwitchInfo]. | 2049 // Switches are handled using [visitSwitchInfo]. |
| (...skipping 876 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2894 startBailoutSwitch(); | 2926 startBailoutSwitch(); |
| 2895 } | 2927 } |
| 2896 } | 2928 } |
| 2897 | 2929 |
| 2898 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2930 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2899 if (labeledBlockInfo.body.start.hasGuards()) { | 2931 if (labeledBlockInfo.body.start.hasGuards()) { |
| 2900 endBailoutSwitch(); | 2932 endBailoutSwitch(); |
| 2901 } | 2933 } |
| 2902 } | 2934 } |
| 2903 } | 2935 } |
| OLD | NEW |