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 static bool IsStringFromCharCode(Definition* d) { | |
1485 return (d->IsStringCharCode() && | |
1486 (d->AsStringCharCode()->kind() == StringCharCodeInstr::kFromCharCode)); | |
1487 } | |
1488 | |
1489 | |
1490 // Return true if d is a string of length one (a constant or result from | |
1491 // from string-from-char-code instruction. | |
1492 static bool IsLengthOneString(Definition* d) { | |
1493 if (d->IsConstant()) { | |
1494 const Object& obj = d->AsConstant()->value(); | |
1495 if (obj.IsString()) { | |
1496 return String::Cast(obj).Length() == 1; | |
1497 } else { | |
1498 return false; | |
1499 } | |
1500 } else { | |
1501 return IsStringFromCharCode(d); | |
1502 } | |
1503 } | |
1504 | |
1505 | |
1506 // Returns true if the string comparison was converted into char-code | |
1507 // comparison. Conversion is only possible for strings of length one. | |
1508 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes. | |
1509 // TODO(srdjan): Expand for two-byte and external strings. | |
1510 bool FlowGraphOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, | |
1511 Token::Kind op_kind) { | |
1512 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid)); | |
1513 // Check that left and right are length one strings (either string constants | |
1514 // or results of string-from-char-code. | |
1515 Definition* left = call->ArgumentAt(0); | |
1516 Definition* right = call->ArgumentAt(1); | |
1517 Value* left_val = NULL; | |
1518 Definition* to_remove_left = NULL; | |
1519 if (IsLengthOneString(right)) { | |
1520 // Swap, since we know that both arguments are strings | |
1521 Definition* temp = left; | |
1522 left = right; | |
1523 right = temp; | |
1524 } | |
1525 if (IsLengthOneString(left)) { | |
1526 // Optimize if left is a string with length one (either constant or | |
1527 // result of string-from-char-code. | |
1528 if (left->IsConstant()) { | |
1529 ConstantInstr* left_const = left->AsConstant(); | |
1530 const String& str = String::Cast(left_const->value()); | |
1531 ASSERT(str.Length() == 1); | |
1532 ConstantInstr* char_code_left = | |
1533 new ConstantInstr(Smi::ZoneHandle(Smi::New(str.CharAt(0)))); | |
Florian Schneider
2013/12/20 09:29:12
Use flow_graph()->GetConstant(Smi::Handle(Smi::New
srdjan
2013/12/20 19:48:03
Done, and using ZoneHandle since the handle escape
| |
1534 InsertBefore(call, char_code_left, NULL, Definition::kValue); | |
1535 left_val = new Value(char_code_left); | |
1536 } else if (IsStringFromCharCode(left)) { | |
1537 // Use input of string-from-charcode as left value. | |
1538 StringCharCodeInstr* instr = left->AsStringCharCode(); | |
1539 left_val = new Value(instr->char_code()->definition()); | |
1540 to_remove_left = instr; | |
1541 } else { | |
1542 // IsLengthOneString(left) should have been false. | |
1543 UNREACHABLE(); | |
1544 } | |
1545 | |
1546 Definition* to_remove_right = NULL; | |
1547 Value* right_val = NULL; | |
1548 if (IsStringFromCharCode(right)) { | |
1549 // Skip string-from-char-code, and use its input as right value. | |
1550 StringCharCodeInstr* right_instr = right->AsStringCharCode(); | |
1551 right_val = new Value(right_instr->char_code()->definition()); | |
1552 to_remove_right = right_instr; | |
1553 } else { | |
1554 const ICData& unary_checks_1 = | |
1555 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecksForArgNr(1)); | |
1556 AddCheckClass(right, | |
1557 unary_checks_1, | |
1558 call->deopt_id(), | |
1559 call->env(), | |
1560 call); | |
1561 // String-to-char-code instructions returns -1 (illegal charcode) if | |
1562 // string is not of length one. | |
1563 StringCharCodeInstr* char_code_right = new StringCharCodeInstr( | |
1564 new Value(right), | |
1565 kOneByteStringCid, | |
1566 StringCharCodeInstr::kToCharCode); | |
1567 InsertBefore(call, char_code_right, call->env(), Definition::kValue); | |
1568 right_val = new Value(char_code_right); | |
1569 } | |
1570 | |
1571 // Comparing char-codes instead of strings. | |
1572 EqualityCompareInstr* comp = | |
1573 new EqualityCompareInstr(call->token_pos(), | |
1574 op_kind, | |
1575 left_val, | |
1576 right_val, | |
1577 kSmiCid, | |
1578 call->deopt_id()); | |
1579 ReplaceCall(call, comp); | |
1580 | |
1581 // Remove dead instructions. | |
1582 if ((to_remove_left != NULL) && | |
1583 (to_remove_left->input_use_list() == NULL)) { | |
1584 ConstantInstr* null = new ConstantInstr(Instance::ZoneHandle()); | |
Florian Schneider
2013/12/20 09:29:12
Use flow_grah()->constant_null().
srdjan
2013/12/20 19:48:03
Done.
| |
1585 to_remove_left->ReplaceUsesWith(null); | |
1586 to_remove_left->RemoveFromGraph(); | |
1587 } | |
1588 if ((to_remove_right != NULL) && | |
1589 (to_remove_right->input_use_list() == NULL)) { | |
1590 ConstantInstr* null = new ConstantInstr(Instance::ZoneHandle()); | |
Florian Schneider
2013/12/20 09:29:12
Use flow_grah()->constant_null().
srdjan
2013/12/20 19:48:03
Done.
| |
1591 to_remove_right->ReplaceUsesWith(null); | |
1592 to_remove_right->RemoveFromGraph(); | |
1593 } | |
1594 return true; | |
1595 } | |
1596 return false; | |
1597 } | |
1598 | |
1599 | |
1484 static bool SmiFitsInDouble() { return kSmiBits < 53; } | 1600 static bool SmiFitsInDouble() { return kSmiBits < 53; } |
1485 | 1601 |
1486 bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, | 1602 bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
1487 Token::Kind op_kind) { | 1603 Token::Kind op_kind) { |
1488 const ICData& ic_data = *call->ic_data(); | 1604 const ICData& ic_data = *call->ic_data(); |
1489 ASSERT(ic_data.num_args_tested() == 2); | 1605 ASSERT(ic_data.num_args_tested() == 2); |
1490 | 1606 |
1491 ASSERT(call->ArgumentCount() == 2); | 1607 ASSERT(call->ArgumentCount() == 2); |
1492 Definition* left = call->ArgumentAt(0); | 1608 Definition* left = call->ArgumentAt(0); |
1493 Definition* right = call->ArgumentAt(1); | 1609 Definition* right = call->ArgumentAt(1); |
1494 | 1610 |
1495 intptr_t cid = kIllegalCid; | 1611 intptr_t cid = kIllegalCid; |
1496 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 1612 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { |
1613 if (TryStringLengthOneEquality(call, op_kind)) { | |
1614 return true; | |
1615 } else { | |
1616 return false; | |
1617 } | |
1618 } else if (HasOnlyTwoOf(ic_data, kSmiCid)) { | |
1497 InsertBefore(call, | 1619 InsertBefore(call, |
1498 new CheckSmiInstr(new Value(left), call->deopt_id()), | 1620 new CheckSmiInstr(new Value(left), call->deopt_id()), |
1499 call->env(), | 1621 call->env(), |
1500 Definition::kEffect); | 1622 Definition::kEffect); |
1501 InsertBefore(call, | 1623 InsertBefore(call, |
1502 new CheckSmiInstr(new Value(right), call->deopt_id()), | 1624 new CheckSmiInstr(new Value(right), call->deopt_id()), |
1503 call->env(), | 1625 call->env(), |
1504 Definition::kEffect); | 1626 Definition::kEffect); |
1505 cid = kSmiCid; | 1627 cid = kSmiCid; |
1506 } else if (HasTwoMintOrSmi(ic_data) && | 1628 } else if (HasTwoMintOrSmi(ic_data) && |
(...skipping 841 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2348 LoadIndexedInstr* instr = BuildStringCodeUnitAt(call, class_ids[0]); | 2470 LoadIndexedInstr* instr = BuildStringCodeUnitAt(call, class_ids[0]); |
2349 ReplaceCall(call, instr); | 2471 ReplaceCall(call, instr); |
2350 return true; | 2472 return true; |
2351 } | 2473 } |
2352 if ((class_ids[0] == kOneByteStringCid) && (ic_data.NumberOfChecks() == 1)) { | 2474 if ((class_ids[0] == kOneByteStringCid) && (ic_data.NumberOfChecks() == 1)) { |
2353 if (recognized_kind == MethodRecognizer::kStringBaseCharAt) { | 2475 if (recognized_kind == MethodRecognizer::kStringBaseCharAt) { |
2354 // TODO(fschneider): Handle TwoByteString. | 2476 // TODO(fschneider): Handle TwoByteString. |
2355 LoadIndexedInstr* load_char_code = | 2477 LoadIndexedInstr* load_char_code = |
2356 BuildStringCodeUnitAt(call, class_ids[0]); | 2478 BuildStringCodeUnitAt(call, class_ids[0]); |
2357 InsertBefore(call, load_char_code, NULL, Definition::kValue); | 2479 InsertBefore(call, load_char_code, NULL, Definition::kValue); |
2358 StringFromCharCodeInstr* char_at = | 2480 StringCharCodeInstr* char_at = |
2359 new StringFromCharCodeInstr(new Value(load_char_code), | 2481 new StringCharCodeInstr(new Value(load_char_code), |
2360 kOneByteStringCid); | 2482 kOneByteStringCid, |
2483 StringCharCodeInstr::kFromCharCode); | |
2361 ReplaceCall(call, char_at); | 2484 ReplaceCall(call, char_at); |
2362 return true; | 2485 return true; |
2363 } | 2486 } |
2364 if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) { | 2487 if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) { |
2365 // This is an internal method, no need to check argument types nor | 2488 // This is an internal method, no need to check argument types nor |
2366 // range. | 2489 // range. |
2367 Definition* str = call->ArgumentAt(0); | 2490 Definition* str = call->ArgumentAt(0); |
2368 Definition* index = call->ArgumentAt(1); | 2491 Definition* index = call->ArgumentAt(1); |
2369 Definition* value = call->ArgumentAt(2); | 2492 Definition* value = call->ArgumentAt(2); |
2370 StoreIndexedInstr* store_op = new StoreIndexedInstr( | 2493 StoreIndexedInstr* store_op = new StoreIndexedInstr( |
(...skipping 4283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6654 } | 6777 } |
6655 } | 6778 } |
6656 } | 6779 } |
6657 | 6780 |
6658 | 6781 |
6659 void ConstantPropagator::VisitNativeCall(NativeCallInstr* instr) { | 6782 void ConstantPropagator::VisitNativeCall(NativeCallInstr* instr) { |
6660 SetValue(instr, non_constant_); | 6783 SetValue(instr, non_constant_); |
6661 } | 6784 } |
6662 | 6785 |
6663 | 6786 |
6664 void ConstantPropagator::VisitStringFromCharCode( | 6787 void ConstantPropagator::VisitStringCharCode(StringCharCodeInstr* instr) { |
6665 StringFromCharCodeInstr* instr) { | 6788 if (instr->kind() == StringCharCodeInstr::kFromCharCode) { |
6666 SetValue(instr, non_constant_); | 6789 const Object& o = instr->char_code()->definition()->constant_value(); |
6790 if (IsNonConstant(o)) { | |
6791 SetValue(instr, non_constant_); | |
6792 } else if (IsConstant(o)) { | |
6793 const intptr_t ch_code = Smi::Cast(o).Value(); | |
6794 ASSERT(ch_code >= 0); | |
6795 if (ch_code < Symbols::kMaxOneCharCodeSymbol) { | |
6796 RawString** table = Symbols::PredefinedAddress(); | |
6797 SetValue(instr, String::ZoneHandle(table[ch_code])); | |
6798 } else { | |
6799 SetValue(instr, non_constant_); | |
6800 } | |
6801 } | |
6802 } else { | |
6803 ASSERT(instr->kind() == StringCharCodeInstr::kToCharCode); | |
6804 const Object& o = instr->str()->definition()->constant_value(); | |
6805 if (IsNonConstant(o)) { | |
6806 SetValue(instr, non_constant_); | |
6807 } else if (IsConstant(o)) { | |
6808 const String& str = String::Cast(o); | |
6809 const intptr_t result = (str.Length() == 1) ? str.CharAt(0) : -1; | |
Florian Schneider
2013/12/20 09:29:12
Can the case of Length() > 1 occur at all?
srdjan
2013/12/20 19:48:03
Yes, length 0 as well. StringToCharCode has as its
| |
6810 SetValue(instr, Smi::ZoneHandle(Smi::New(result))); | |
6811 } | |
6812 } | |
6667 } | 6813 } |
6668 | 6814 |
6669 | 6815 |
6670 void ConstantPropagator::VisitStringInterpolate(StringInterpolateInstr* instr) { | 6816 void ConstantPropagator::VisitStringInterpolate(StringInterpolateInstr* instr) { |
6671 SetValue(instr, non_constant_); | 6817 SetValue(instr, non_constant_); |
6672 return; | 6818 return; |
6673 } | 6819 } |
6674 | 6820 |
6675 | 6821 |
6676 void ConstantPropagator::VisitLoadIndexed(LoadIndexedInstr* instr) { | 6822 void ConstantPropagator::VisitLoadIndexed(LoadIndexedInstr* instr) { |
(...skipping 1469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8146 } | 8292 } |
8147 | 8293 |
8148 // Insert materializations at environment uses. | 8294 // Insert materializations at environment uses. |
8149 for (intptr_t i = 0; i < exits.length(); i++) { | 8295 for (intptr_t i = 0; i < exits.length(); i++) { |
8150 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 8296 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
8151 } | 8297 } |
8152 } | 8298 } |
8153 | 8299 |
8154 | 8300 |
8155 } // namespace dart | 8301 } // namespace dart |
OLD | NEW |