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 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
6 | 6 |
7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
9 #include "vm/dart_entry.h" | 9 #include "vm/dart_entry.h" |
10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
(...skipping 1463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1474 last->LinkTo(call); | 1474 last->LinkTo(call); |
1475 // Remove through the iterator. | 1475 // Remove through the iterator. |
1476 ASSERT(current_iterator()->Current() == call); | 1476 ASSERT(current_iterator()->Current() == call); |
1477 current_iterator()->RemoveCurrentFromGraph(); | 1477 current_iterator()->RemoveCurrentFromGraph(); |
1478 call->set_previous(NULL); | 1478 call->set_previous(NULL); |
1479 call->set_next(NULL); | 1479 call->set_next(NULL); |
1480 return true; | 1480 return true; |
1481 } | 1481 } |
1482 | 1482 |
1483 | 1483 |
| 1484 // Return true if d is a string of length one (a constant or result from |
| 1485 // from string-from-char-code instruction. |
| 1486 static bool IsLengthOneString(Definition* d) { |
| 1487 if (d->IsConstant()) { |
| 1488 const Object& obj = d->AsConstant()->value(); |
| 1489 if (obj.IsString()) { |
| 1490 return String::Cast(obj).Length() == 1; |
| 1491 } else { |
| 1492 return false; |
| 1493 } |
| 1494 } else { |
| 1495 return d->IsStringFromCharCode(); |
| 1496 } |
| 1497 } |
| 1498 |
| 1499 |
| 1500 // Returns true if the string comparison was converted into char-code |
| 1501 // comparison. Conversion is only possible for strings of length one. |
| 1502 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes. |
| 1503 // TODO(srdjan): Expand for two-byte and external strings. |
| 1504 bool FlowGraphOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, |
| 1505 Token::Kind op_kind) { |
| 1506 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid)); |
| 1507 // Check that left and right are length one strings (either string constants |
| 1508 // or results of string-from-char-code. |
| 1509 Definition* left = call->ArgumentAt(0); |
| 1510 Definition* right = call->ArgumentAt(1); |
| 1511 Value* left_val = NULL; |
| 1512 Definition* to_remove_left = NULL; |
| 1513 if (IsLengthOneString(right)) { |
| 1514 // Swap, since we know that both arguments are strings |
| 1515 Definition* temp = left; |
| 1516 left = right; |
| 1517 right = temp; |
| 1518 } |
| 1519 if (IsLengthOneString(left)) { |
| 1520 // Optimize if left is a string with length one (either constant or |
| 1521 // result of string-from-char-code. |
| 1522 if (left->IsConstant()) { |
| 1523 ConstantInstr* left_const = left->AsConstant(); |
| 1524 const String& str = String::Cast(left_const->value()); |
| 1525 ASSERT(str.Length() == 1); |
| 1526 ConstantInstr* char_code_left = |
| 1527 flow_graph()->GetConstant(Smi::ZoneHandle(Smi::New(str.CharAt(0)))); |
| 1528 left_val = new Value(char_code_left); |
| 1529 } else if (left->IsStringFromCharCode()) { |
| 1530 // Use input of string-from-charcode as left value. |
| 1531 StringFromCharCodeInstr* instr = left->AsStringFromCharCode(); |
| 1532 left_val = new Value(instr->char_code()->definition()); |
| 1533 to_remove_left = instr; |
| 1534 } else { |
| 1535 // IsLengthOneString(left) should have been false. |
| 1536 UNREACHABLE(); |
| 1537 } |
| 1538 |
| 1539 Definition* to_remove_right = NULL; |
| 1540 Value* right_val = NULL; |
| 1541 if (right->IsStringFromCharCode()) { |
| 1542 // Skip string-from-char-code, and use its input as right value. |
| 1543 StringFromCharCodeInstr* right_instr = right->AsStringFromCharCode(); |
| 1544 right_val = new Value(right_instr->char_code()->definition()); |
| 1545 to_remove_right = right_instr; |
| 1546 } else { |
| 1547 const ICData& unary_checks_1 = |
| 1548 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecksForArgNr(1)); |
| 1549 AddCheckClass(right, |
| 1550 unary_checks_1, |
| 1551 call->deopt_id(), |
| 1552 call->env(), |
| 1553 call); |
| 1554 // String-to-char-code instructions returns -1 (illegal charcode) if |
| 1555 // string is not of length one. |
| 1556 StringToCharCodeInstr* char_code_right = |
| 1557 new StringToCharCodeInstr(new Value(right), kOneByteStringCid); |
| 1558 InsertBefore(call, char_code_right, call->env(), Definition::kValue); |
| 1559 right_val = new Value(char_code_right); |
| 1560 } |
| 1561 |
| 1562 // Comparing char-codes instead of strings. |
| 1563 EqualityCompareInstr* comp = |
| 1564 new EqualityCompareInstr(call->token_pos(), |
| 1565 op_kind, |
| 1566 left_val, |
| 1567 right_val, |
| 1568 kSmiCid, |
| 1569 call->deopt_id()); |
| 1570 ReplaceCall(call, comp); |
| 1571 |
| 1572 // Remove dead instructions. |
| 1573 if ((to_remove_left != NULL) && |
| 1574 (to_remove_left->input_use_list() == NULL)) { |
| 1575 to_remove_left->ReplaceUsesWith(flow_graph()->constant_null()); |
| 1576 to_remove_left->RemoveFromGraph(); |
| 1577 } |
| 1578 if ((to_remove_right != NULL) && |
| 1579 (to_remove_right->input_use_list() == NULL)) { |
| 1580 to_remove_right->ReplaceUsesWith(flow_graph()->constant_null()); |
| 1581 to_remove_right->RemoveFromGraph(); |
| 1582 } |
| 1583 return true; |
| 1584 } |
| 1585 return false; |
| 1586 } |
| 1587 |
| 1588 |
1484 static bool SmiFitsInDouble() { return kSmiBits < 53; } | 1589 static bool SmiFitsInDouble() { return kSmiBits < 53; } |
1485 | 1590 |
1486 bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, | 1591 bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
1487 Token::Kind op_kind) { | 1592 Token::Kind op_kind) { |
1488 const ICData& ic_data = *call->ic_data(); | 1593 const ICData& ic_data = *call->ic_data(); |
1489 ASSERT(ic_data.num_args_tested() == 2); | 1594 ASSERT(ic_data.num_args_tested() == 2); |
1490 | 1595 |
1491 ASSERT(call->ArgumentCount() == 2); | 1596 ASSERT(call->ArgumentCount() == 2); |
1492 Definition* left = call->ArgumentAt(0); | 1597 Definition* left = call->ArgumentAt(0); |
1493 Definition* right = call->ArgumentAt(1); | 1598 Definition* right = call->ArgumentAt(1); |
1494 | 1599 |
1495 intptr_t cid = kIllegalCid; | 1600 intptr_t cid = kIllegalCid; |
1496 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 1601 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { |
| 1602 if (TryStringLengthOneEquality(call, op_kind)) { |
| 1603 return true; |
| 1604 } else { |
| 1605 return false; |
| 1606 } |
| 1607 } else if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
1497 InsertBefore(call, | 1608 InsertBefore(call, |
1498 new CheckSmiInstr(new Value(left), call->deopt_id()), | 1609 new CheckSmiInstr(new Value(left), call->deopt_id()), |
1499 call->env(), | 1610 call->env(), |
1500 Definition::kEffect); | 1611 Definition::kEffect); |
1501 InsertBefore(call, | 1612 InsertBefore(call, |
1502 new CheckSmiInstr(new Value(right), call->deopt_id()), | 1613 new CheckSmiInstr(new Value(right), call->deopt_id()), |
1503 call->env(), | 1614 call->env(), |
1504 Definition::kEffect); | 1615 Definition::kEffect); |
1505 cid = kSmiCid; | 1616 cid = kSmiCid; |
1506 } else if (HasTwoMintOrSmi(ic_data) && | 1617 } else if (HasTwoMintOrSmi(ic_data) && |
(...skipping 5149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6656 } | 6767 } |
6657 | 6768 |
6658 | 6769 |
6659 void ConstantPropagator::VisitNativeCall(NativeCallInstr* instr) { | 6770 void ConstantPropagator::VisitNativeCall(NativeCallInstr* instr) { |
6660 SetValue(instr, non_constant_); | 6771 SetValue(instr, non_constant_); |
6661 } | 6772 } |
6662 | 6773 |
6663 | 6774 |
6664 void ConstantPropagator::VisitStringFromCharCode( | 6775 void ConstantPropagator::VisitStringFromCharCode( |
6665 StringFromCharCodeInstr* instr) { | 6776 StringFromCharCodeInstr* instr) { |
6666 SetValue(instr, non_constant_); | 6777 const Object& o = instr->char_code()->definition()->constant_value(); |
| 6778 if (o.IsNull() || IsNonConstant(o)) { |
| 6779 SetValue(instr, non_constant_); |
| 6780 } else if (IsConstant(o)) { |
| 6781 const intptr_t ch_code = Smi::Cast(o).Value(); |
| 6782 ASSERT(ch_code >= 0); |
| 6783 if (ch_code < Symbols::kMaxOneCharCodeSymbol) { |
| 6784 RawString** table = Symbols::PredefinedAddress(); |
| 6785 SetValue(instr, String::ZoneHandle(table[ch_code])); |
| 6786 } else { |
| 6787 SetValue(instr, non_constant_); |
| 6788 } |
| 6789 } |
6667 } | 6790 } |
6668 | 6791 |
6669 | 6792 |
| 6793 void ConstantPropagator::VisitStringToCharCode(StringToCharCodeInstr* instr) { |
| 6794 const Object& o = instr->str()->definition()->constant_value(); |
| 6795 if (o.IsNull() || IsNonConstant(o)) { |
| 6796 SetValue(instr, non_constant_); |
| 6797 } else if (IsConstant(o)) { |
| 6798 const String& str = String::Cast(o); |
| 6799 const intptr_t result = (str.Length() == 1) ? str.CharAt(0) : -1; |
| 6800 SetValue(instr, Smi::ZoneHandle(Smi::New(result))); |
| 6801 } |
| 6802 } |
| 6803 |
| 6804 |
| 6805 |
| 6806 |
6670 void ConstantPropagator::VisitStringInterpolate(StringInterpolateInstr* instr) { | 6807 void ConstantPropagator::VisitStringInterpolate(StringInterpolateInstr* instr) { |
6671 SetValue(instr, non_constant_); | 6808 SetValue(instr, non_constant_); |
6672 return; | 6809 return; |
6673 } | 6810 } |
6674 | 6811 |
6675 | 6812 |
6676 void ConstantPropagator::VisitLoadIndexed(LoadIndexedInstr* instr) { | 6813 void ConstantPropagator::VisitLoadIndexed(LoadIndexedInstr* instr) { |
6677 const Object& array_obj = instr->array()->definition()->constant_value(); | 6814 const Object& array_obj = instr->array()->definition()->constant_value(); |
6678 const Object& index_obj = instr->index()->definition()->constant_value(); | 6815 const Object& index_obj = instr->index()->definition()->constant_value(); |
6679 if (IsNonConstant(array_obj) || IsNonConstant(index_obj)) { | 6816 if (IsNonConstant(array_obj) || IsNonConstant(index_obj)) { |
(...skipping 1466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8146 } | 8283 } |
8147 | 8284 |
8148 // Insert materializations at environment uses. | 8285 // Insert materializations at environment uses. |
8149 for (intptr_t i = 0; i < exits.length(); i++) { | 8286 for (intptr_t i = 0; i < exits.length(); i++) { |
8150 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 8287 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
8151 } | 8288 } |
8152 } | 8289 } |
8153 | 8290 |
8154 | 8291 |
8155 } // namespace dart | 8292 } // namespace dart |
OLD | NEW |