Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(115)

Side by Side Diff: runtime/vm/flow_graph_optimizer.cc

Issue 105143011: Optimize one byte string comparisons. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698