Chromium Code Reviews| 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 |