OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 1600 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1611 stream->Add("%u", index()); | 1611 stream->Add("%u", index()); |
1612 } | 1612 } |
1613 | 1613 |
1614 | 1614 |
1615 void HLoadNamedField::PrintDataTo(StringStream* stream) { | 1615 void HLoadNamedField::PrintDataTo(StringStream* stream) { |
1616 object()->PrintNameTo(stream); | 1616 object()->PrintNameTo(stream); |
1617 stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : ""); | 1617 stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : ""); |
1618 } | 1618 } |
1619 | 1619 |
1620 | 1620 |
| 1621 // Returns true if an instance of this map can never find a property with this |
| 1622 // name in its prototype chain. This means all prototypes up to the top are |
| 1623 // fast and don't have the name in them. It would be good if we could optimize |
| 1624 // polymorphic loads where the property is sometimes found in the prototype |
| 1625 // chain. |
| 1626 static bool PrototypeChainCanNeverResolve( |
| 1627 Handle<Map> map, Handle<String> name) { |
| 1628 Isolate* isolate = map->GetIsolate(); |
| 1629 Object* current = map->prototype(); |
| 1630 while (current != isolate->heap()->null_value()) { |
| 1631 if (current->IsJSGlobalProxy() || |
| 1632 current->IsGlobalObject() || |
| 1633 !current->IsJSObject() || |
| 1634 JSObject::cast(current)->IsAccessCheckNeeded() || |
| 1635 !JSObject::cast(current)->HasFastProperties()) { |
| 1636 return false; |
| 1637 } |
| 1638 |
| 1639 LookupResult lookup(isolate); |
| 1640 JSObject::cast(current)->map()->LookupInDescriptors(NULL, *name, &lookup); |
| 1641 if (lookup.IsFound()) { |
| 1642 if (lookup.type() != MAP_TRANSITION) return false; |
| 1643 } else if (!lookup.IsCacheable()) { |
| 1644 return false; |
| 1645 } |
| 1646 |
| 1647 current = JSObject::cast(current)->GetPrototype(); |
| 1648 } |
| 1649 return true; |
| 1650 } |
| 1651 |
| 1652 |
1621 HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context, | 1653 HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context, |
1622 HValue* object, | 1654 HValue* object, |
1623 SmallMapList* types, | 1655 SmallMapList* types, |
1624 Handle<String> name, | 1656 Handle<String> name, |
1625 Zone* zone) | 1657 Zone* zone) |
1626 : types_(Min(types->length(), kMaxLoadPolymorphism), zone), | 1658 : types_(Min(types->length(), kMaxLoadPolymorphism), zone), |
1627 name_(name), | 1659 name_(name), |
1628 need_generic_(false) { | 1660 need_generic_(false) { |
1629 SetOperandAt(0, context); | 1661 SetOperandAt(0, context); |
1630 SetOperandAt(1, object); | 1662 SetOperandAt(1, object); |
1631 set_representation(Representation::Tagged()); | 1663 set_representation(Representation::Tagged()); |
1632 SetGVNFlag(kDependsOnMaps); | 1664 SetGVNFlag(kDependsOnMaps); |
1633 int map_transitions = 0; | 1665 SmallMapList negative_lookups; |
1634 for (int i = 0; | 1666 for (int i = 0; |
1635 i < types->length() && types_.length() < kMaxLoadPolymorphism; | 1667 i < types->length() && types_.length() < kMaxLoadPolymorphism; |
1636 ++i) { | 1668 ++i) { |
1637 Handle<Map> map = types->at(i); | 1669 Handle<Map> map = types->at(i); |
1638 LookupResult lookup(map->GetIsolate()); | 1670 LookupResult lookup(map->GetIsolate()); |
1639 map->LookupInDescriptors(NULL, *name, &lookup); | 1671 map->LookupInDescriptors(NULL, *name, &lookup); |
1640 if (lookup.IsFound()) { | 1672 if (lookup.IsFound()) { |
1641 switch (lookup.type()) { | 1673 switch (lookup.type()) { |
1642 case FIELD: { | 1674 case FIELD: { |
1643 int index = lookup.GetLocalFieldIndexFromMap(*map); | 1675 int index = lookup.GetLocalFieldIndexFromMap(*map); |
1644 if (index < 0) { | 1676 if (index < 0) { |
1645 SetGVNFlag(kDependsOnInobjectFields); | 1677 SetGVNFlag(kDependsOnInobjectFields); |
1646 } else { | 1678 } else { |
1647 SetGVNFlag(kDependsOnBackingStoreFields); | 1679 SetGVNFlag(kDependsOnBackingStoreFields); |
1648 } | 1680 } |
1649 types_.Add(types->at(i), zone); | 1681 types_.Add(types->at(i), zone); |
1650 break; | 1682 break; |
1651 } | 1683 } |
1652 case CONSTANT_FUNCTION: | 1684 case CONSTANT_FUNCTION: |
1653 types_.Add(types->at(i), zone); | 1685 types_.Add(types->at(i), zone); |
1654 break; | 1686 break; |
1655 case MAP_TRANSITION: | 1687 case MAP_TRANSITION: |
1656 // We should just ignore these since they are not relevant to a load | 1688 if (PrototypeChainCanNeverResolve(map, name)) { |
1657 // operation. This means we will deopt if we actually see this map | 1689 negative_lookups.Add(types->at(i), zone); |
1658 // from optimized code. | 1690 } |
1659 map_transitions++; | |
1660 break; | 1691 break; |
1661 default: | 1692 default: |
1662 break; | 1693 break; |
1663 } | 1694 } |
| 1695 } else if (lookup.IsCacheable()) { |
| 1696 if (PrototypeChainCanNeverResolve(map, name)) { |
| 1697 negative_lookups.Add(types->at(i), zone); |
| 1698 } |
1664 } | 1699 } |
1665 } | 1700 } |
1666 | 1701 |
1667 if (types_.length() + map_transitions == types->length() && | 1702 bool need_generic = |
1668 FLAG_deoptimize_uncommon_cases) { | 1703 (types->length() != negative_lookups.length() + types_.length()); |
| 1704 if (!need_generic && FLAG_deoptimize_uncommon_cases) { |
1669 SetFlag(kUseGVN); | 1705 SetFlag(kUseGVN); |
| 1706 for (int i = 0; i < negative_lookups.length(); i++) { |
| 1707 types_.Add(negative_lookups.at(i), zone); |
| 1708 } |
1670 } else { | 1709 } else { |
| 1710 // We don't have an easy way to handle both a call (to the generic stub) and |
| 1711 // a deopt in the same hydrogen instruction, so in this case we don't add |
| 1712 // the negative lookups which can deopt - just let the generic stub handle |
| 1713 // them. |
1671 SetAllSideEffects(); | 1714 SetAllSideEffects(); |
1672 need_generic_ = true; | 1715 need_generic_ = true; |
1673 } | 1716 } |
1674 } | 1717 } |
1675 | 1718 |
1676 | 1719 |
1677 bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) { | 1720 bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) { |
1678 HLoadNamedFieldPolymorphic* other = HLoadNamedFieldPolymorphic::cast(value); | 1721 HLoadNamedFieldPolymorphic* other = HLoadNamedFieldPolymorphic::cast(value); |
1679 if (types_.length() != other->types()->length()) return false; | 1722 if (types_.length() != other->types()->length()) return false; |
1680 if (!name_.is_identical_to(other->name())) return false; | 1723 if (!name_.is_identical_to(other->name())) return false; |
(...skipping 796 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2477 | 2520 |
2478 | 2521 |
2479 void HCheckPrototypeMaps::Verify() { | 2522 void HCheckPrototypeMaps::Verify() { |
2480 HInstruction::Verify(); | 2523 HInstruction::Verify(); |
2481 ASSERT(HasNoUses()); | 2524 ASSERT(HasNoUses()); |
2482 } | 2525 } |
2483 | 2526 |
2484 #endif | 2527 #endif |
2485 | 2528 |
2486 } } // namespace v8::internal | 2529 } } // namespace v8::internal |
OLD | NEW |