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

Side by Side Diff: src/objects.cc

Issue 10697015: Separating transitions from descriptors. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 8 years, 5 months 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 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 398 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 if (r.IsProperty()) { 409 if (r.IsProperty()) {
410 return GetPropertyAttributeWithFailedAccessCheck(receiver, 410 return GetPropertyAttributeWithFailedAccessCheck(receiver,
411 &r, 411 &r,
412 name, 412 name,
413 continue_search); 413 continue_search);
414 } 414 }
415 break; 415 break;
416 } 416 }
417 417
418 case HANDLER: 418 case HANDLER:
419 case MAP_TRANSITION: 419 case TRANSITION:
420 case CONSTANT_TRANSITION:
421 case NONEXISTENT: 420 case NONEXISTENT:
422 UNREACHABLE(); 421 UNREACHABLE();
423 } 422 }
424 } 423 }
425 424
426 GetIsolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); 425 GetIsolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
427 return ABSENT; 426 return ABSENT;
428 } 427 }
429 428
430 429
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
634 case CALLBACKS: 633 case CALLBACKS:
635 return result->holder()->GetPropertyWithCallback( 634 return result->holder()->GetPropertyWithCallback(
636 receiver, result->GetCallbackObject(), name); 635 receiver, result->GetCallbackObject(), name);
637 case HANDLER: 636 case HANDLER:
638 return result->proxy()->GetPropertyWithHandler(receiver, name); 637 return result->proxy()->GetPropertyWithHandler(receiver, name);
639 case INTERCEPTOR: { 638 case INTERCEPTOR: {
640 JSObject* recvr = JSObject::cast(receiver); 639 JSObject* recvr = JSObject::cast(receiver);
641 return result->holder()->GetPropertyWithInterceptor( 640 return result->holder()->GetPropertyWithInterceptor(
642 recvr, name, attributes); 641 recvr, name, attributes);
643 } 642 }
644 case MAP_TRANSITION: 643 case TRANSITION:
645 case CONSTANT_TRANSITION:
646 break;
647 case NONEXISTENT: 644 case NONEXISTENT:
648 UNREACHABLE(); 645 UNREACHABLE();
649 break; 646 break;
650 } 647 }
651 UNREACHABLE(); 648 UNREACHABLE();
652 return NULL; 649 return NULL;
653 } 650 }
654 651
655 652
656 MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) { 653 MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
(...skipping 828 matching lines...) Expand 10 before | Expand all | Expand 10 after
1485 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name(); 1482 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
1486 } 1483 }
1487 // TODO(rossberg): what about proxies? 1484 // TODO(rossberg): what about proxies?
1488 // If the constructor is not present, return "Object". 1485 // If the constructor is not present, return "Object".
1489 return GetHeap()->Object_symbol(); 1486 return GetHeap()->Object_symbol();
1490 } 1487 }
1491 1488
1492 1489
1493 MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map, 1490 MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1494 String* name, 1491 String* name,
1495 Object* value) { 1492 Object* value,
1496 int index = new_map->PropertyIndexFor(name); 1493 int field_index) {
1497 if (map()->unused_property_fields() == 0) { 1494 if (map()->unused_property_fields() == 0) {
1498 ASSERT(map()->unused_property_fields() == 0);
1499 int new_unused = new_map->unused_property_fields(); 1495 int new_unused = new_map->unused_property_fields();
1500 Object* values; 1496 Object* values;
1501 { MaybeObject* maybe_values = 1497 { MaybeObject* maybe_values =
1502 properties()->CopySize(properties()->length() + new_unused + 1); 1498 properties()->CopySize(properties()->length() + new_unused + 1);
1503 if (!maybe_values->ToObject(&values)) return maybe_values; 1499 if (!maybe_values->To(&values)) return maybe_values;
1504 } 1500 }
1505 set_properties(FixedArray::cast(values)); 1501 set_properties(FixedArray::cast(values));
Jakob Kummerow 2012/06/29 16:31:36 While you're at it, you can get rid of the cast he
Toon Verwaest 2012/07/05 12:56:11 Done.
1506 } 1502 }
1507 set_map(new_map); 1503 set_map(new_map);
1508 return FastPropertyAtPut(index, value); 1504 return FastPropertyAtPut(field_index, value);
1509 } 1505 }
1510 1506
1511 1507
1512 static bool IsIdentifier(UnicodeCache* cache, 1508 static bool IsIdentifier(UnicodeCache* cache,
1513 unibrow::CharacterStream* buffer) { 1509 unibrow::CharacterStream* buffer) {
1514 // Checks whether the buffer contains an identifier (no escape). 1510 // Checks whether the buffer contains an identifier (no escape).
1515 if (!buffer->has_more()) return false; 1511 if (!buffer->has_more()) return false;
1516 if (!cache->IsIdentifierStart(buffer->GetNext())) { 1512 if (!cache->IsIdentifierStart(buffer->GetNext())) {
1517 return false; 1513 return false;
1518 } 1514 }
(...skipping 25 matching lines...) Expand all
1544 } 1540 }
1545 return AddSlowProperty(name, value, attributes); 1541 return AddSlowProperty(name, value, attributes);
1546 } 1542 }
1547 1543
1548 DescriptorArray* old_descriptors = map()->instance_descriptors(); 1544 DescriptorArray* old_descriptors = map()->instance_descriptors();
1549 // Compute the new index for new field. 1545 // Compute the new index for new field.
1550 int index = map()->NextFreePropertyIndex(); 1546 int index = map()->NextFreePropertyIndex();
1551 1547
1552 // Allocate new instance descriptors with (name, index) added 1548 // Allocate new instance descriptors with (name, index) added
1553 FieldDescriptor new_field(name, index, attributes); 1549 FieldDescriptor new_field(name, index, attributes);
1554 Object* new_descriptors; 1550 DescriptorArray* new_descriptors;
1555 { MaybeObject* maybe_new_descriptors = 1551 { MaybeObject* maybe_new_descriptors =
1556 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS); 1552 old_descriptors->CopyInsert(&new_field);
1557 if (!maybe_new_descriptors->ToObject(&new_descriptors)) { 1553 if (!maybe_new_descriptors->To(&new_descriptors)) {
1558 return maybe_new_descriptors; 1554 return maybe_new_descriptors;
1559 } 1555 }
1560 } 1556 }
1561 1557
1562 // Only allow map transition if the object isn't the global object and there 1558 // Only allow map transition if the object isn't the global object and there
1563 // is not a transition for the name, or there's a transition for the name but 1559 // is not a transition for the name, or there's a transition for the name but
1564 // it's unrelated to properties. 1560 // it's unrelated to properties.
1565 int descriptor_index = old_descriptors->Search(name); 1561 int descriptor_index = old_descriptors->SearchWithCache(name);
1566 1562
1567 // Element transitions are stored in the descriptor for property "", which is 1563 // Element transitions are stored in the descriptor for property "", which is
1568 // not a identifier and should have forced a switch to slow properties above. 1564 // not a identifier and should have forced a switch to slow properties above.
1569 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound; 1565 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound;
1570 bool allow_map_transition = 1566 bool allow_map_transition =
1571 can_insert_transition && 1567 can_insert_transition &&
1572 (isolate->context()->global_context()->object_function()->map() != map()); 1568 (isolate->context()->global_context()->object_function()->map() != map());
1573 1569
1574 ASSERT(index < map()->inobject_properties() || 1570 ASSERT(index < map()->inobject_properties() ||
1575 (index - map()->inobject_properties()) < properties()->length() || 1571 (index - map()->inobject_properties()) < properties()->length() ||
1576 map()->unused_property_fields() == 0); 1572 map()->unused_property_fields() == 0);
1577 // Allocate a new map for the object. 1573 // Allocate a new map for the object.
1578 Object* r; 1574 Object* r;
1579 { MaybeObject* maybe_r = map()->CopyDropDescriptors(); 1575 { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1580 if (!maybe_r->ToObject(&r)) return maybe_r; 1576 if (!maybe_r->ToObject(&r)) return maybe_r;
1581 } 1577 }
1582 Map* new_map = Map::cast(r); 1578 Map* new_map = Map::cast(r);
1579
1580 TransitionArray* new_transitions = NULL;
1583 if (allow_map_transition) { 1581 if (allow_map_transition) {
1584 // Allocate new instance descriptors for the old map with map transition. 1582 MaybeObject* maybe_new_transitions =
1585 MapTransitionDescriptor d(name, Map::cast(new_map), attributes); 1583 map()->transitions()->CopyInsert(name, new_map);
1586 Object* r; 1584 if (!maybe_new_transitions->To(&new_transitions)) {
1587 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS); 1585 // We have accomplished the main goal, so return success.
Jakob Kummerow 2012/06/29 16:31:36 Huh?
Toon Verwaest 2012/07/05 12:56:11 Done.
1588 if (!maybe_r->ToObject(&r)) return maybe_r; 1586 return maybe_new_transitions;
1589 } 1587 }
1590 old_descriptors = DescriptorArray::cast(r);
1591 } 1588 }
1592 1589
1593 if (map()->unused_property_fields() == 0) { 1590 if (map()->unused_property_fields() == 0) {
1594 if (TooManyFastProperties(properties()->length(), store_mode)) { 1591 if (TooManyFastProperties(properties()->length(), store_mode)) {
1595 Object* obj; 1592 Object* obj;
1596 { MaybeObject* maybe_obj = 1593 { MaybeObject* maybe_obj =
1597 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 1594 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1598 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1595 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1599 } 1596 }
1600 return AddSlowProperty(name, value, attributes); 1597 return AddSlowProperty(name, value, attributes);
1601 } 1598 }
1602 // Make room for the new value 1599 // Make room for the new value
1603 Object* values; 1600 Object* values;
1604 { MaybeObject* maybe_values = 1601 { MaybeObject* maybe_values =
1605 properties()->CopySize(properties()->length() + kFieldsAdded); 1602 properties()->CopySize(properties()->length() + kFieldsAdded);
1606 if (!maybe_values->ToObject(&values)) return maybe_values; 1603 if (!maybe_values->ToObject(&values)) return maybe_values;
1607 } 1604 }
1608 set_properties(FixedArray::cast(values)); 1605 set_properties(FixedArray::cast(values));
1609 new_map->set_unused_property_fields(kFieldsAdded - 1); 1606 new_map->set_unused_property_fields(kFieldsAdded - 1);
1610 } else { 1607 } else {
1611 new_map->set_unused_property_fields(map()->unused_property_fields() - 1); 1608 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
1612 } 1609 }
1613 // We have now allocated all the necessary objects. 1610 // Apply all changes at once, so they are atomic.
1614 // All the changes can be applied at once, so they are atomic.
1615 if (allow_map_transition) { 1611 if (allow_map_transition) {
1616 map()->set_instance_descriptors(old_descriptors); 1612 MaybeObject* transition_added = map()->set_transitions(new_transitions);
1613 if (transition_added->IsFailure()) return transition_added;
1617 } 1614 }
1615 new_map->set_instance_descriptors(new_descriptors);
1618 new_map->SetBackPointer(map()); 1616 new_map->SetBackPointer(map());
1619 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1620 set_map(new_map); 1617 set_map(new_map);
1621 return FastPropertyAtPut(index, value); 1618 return FastPropertyAtPut(index, value);
1622 } 1619 }
1623 1620
1624 1621
1625 MaybeObject* JSObject::AddConstantFunctionProperty( 1622 MaybeObject* JSObject::AddConstantFunctionProperty(
1626 String* name, 1623 String* name,
1627 JSFunction* function, 1624 JSFunction* function,
1628 PropertyAttributes attributes) { 1625 PropertyAttributes attributes) {
1629 // Allocate new instance descriptors with (name, function) added 1626 // Allocate new instance descriptors with (name, function) added
1630 ConstantFunctionDescriptor d(name, function, attributes); 1627 ConstantFunctionDescriptor d(name, function, attributes);
1631 Object* new_descriptors; 1628 DescriptorArray* new_descriptors;
1632 { MaybeObject* maybe_new_descriptors = 1629 { MaybeObject* maybe_new_descriptors =
1633 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS); 1630 map()->instance_descriptors()->CopyInsert(&d);
1634 if (!maybe_new_descriptors->ToObject(&new_descriptors)) { 1631 if (!maybe_new_descriptors->To(&new_descriptors)) {
1635 return maybe_new_descriptors; 1632 return maybe_new_descriptors;
1636 } 1633 }
1637 } 1634 }
1638 1635
1639 // Allocate a new map for the object. 1636 // Allocate a new map for the object.
1640 Object* new_map; 1637 Object* new_map;
Jakob Kummerow 2012/06/29 16:31:36 Why not "Map* new_map"?
Toon Verwaest 2012/07/05 12:56:11 Done.
1641 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); 1638 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1642 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; 1639 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1643 } 1640 }
1644 1641
1645 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors); 1642 Map::cast(new_map)->set_instance_descriptors(new_descriptors);
1646 Map::cast(new_map)->set_instance_descriptors(descriptors);
1647 Map* old_map = map(); 1643 Map* old_map = map();
1648 set_map(Map::cast(new_map)); 1644 set_map(Map::cast(new_map));
1649 1645
1650 // If the old map is the global object map (from new Object()), 1646 // If the old map is the global object map (from new Object()),
1651 // then transitions are not added to it, so we are done. 1647 // then transitions are not added to it, so we are done.
1652 Heap* heap = GetHeap(); 1648 Heap* heap = GetHeap();
1653 if (old_map == heap->isolate()->context()->global_context()-> 1649 if (old_map == heap->isolate()->context()->global_context()->
1654 object_function()->map()) { 1650 object_function()->map()) {
1655 return function; 1651 return function;
1656 } 1652 }
1657 1653
1658 // Do not add CONSTANT_TRANSITIONS to global objects 1654 // Do not add CONSTANT_TRANSITIONS to global objects
Jakob Kummerow 2012/06/29 16:31:36 update comment?
Toon Verwaest 2012/07/05 12:56:11 Done.
1659 if (IsGlobalObject()) { 1655 if (IsGlobalObject()) {
1660 return function; 1656 return function;
1661 } 1657 }
1662 1658
1663 // Add a CONSTANT_TRANSITION descriptor to the old map, 1659 // Add a CONSTANT_TRANSITION descriptor to the old map,
Jakob Kummerow 2012/06/29 16:31:36 update comment?
Toon Verwaest 2012/07/05 12:56:11 Done.
1664 // so future assignments to this property on other objects 1660 // so future assignments to this property on other objects
1665 // of the same type will create a normal field, not a constant function. 1661 // of the same type will create a normal field, not a constant function.
1666 // Don't do this for special properties, with non-trival attributes. 1662 // Don't do this for special properties, with non-trival attributes.
1667 if (attributes != NONE) { 1663 if (attributes != NONE) {
1668 return function; 1664 return function;
1669 } 1665 }
1670 ConstTransitionDescriptor mark(name, Map::cast(new_map)); 1666
1671 { MaybeObject* maybe_new_descriptors = 1667 TransitionArray* new_transitions;
1672 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS); 1668 MaybeObject* maybe_new_transitions =
Jakob Kummerow 2012/06/29 16:31:36 Not sure how important it is, but so far we've bee
Toon Verwaest 2012/07/05 12:56:11 Done.
1673 if (!maybe_new_descriptors->ToObject(&new_descriptors)) { 1669 old_map->transitions()->CopyInsert(name, Map::cast(new_map));
1674 // We have accomplished the main goal, so return success. 1670 if (!maybe_new_transitions->To(&new_transitions)) {
1675 return function; 1671 // We have accomplished the main goal, so return success.
Jakob Kummerow 2012/06/29 16:31:36 I'm not convinced that returning success here is r
Toon Verwaest 2012/07/05 12:56:11 Done.
1676 } 1672 return function;
1677 } 1673 }
1678 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); 1674
1675 MaybeObject* transition_added = old_map->set_transitions(new_transitions);
Jakob Kummerow 2012/06/29 16:31:36 see above.
Toon Verwaest 2012/07/05 12:56:11 Done.
1676 // We have accomplished the main goal, so return success.
1677 if (transition_added->IsFailure()) {
1678 return function;
1679 }
1680
1679 Map::cast(new_map)->SetBackPointer(old_map); 1681 Map::cast(new_map)->SetBackPointer(old_map);
1680
1681 return function; 1682 return function;
1682 } 1683 }
1683 1684
1684 1685
1685 // Add property in slow mode 1686 // Add property in slow mode
1686 MaybeObject* JSObject::AddSlowProperty(String* name, 1687 MaybeObject* JSObject::AddSlowProperty(String* name,
1687 Object* value, 1688 Object* value,
1688 PropertyAttributes attributes) { 1689 PropertyAttributes attributes) {
1689 ASSERT(!HasFastProperties()); 1690 ASSERT(!HasFastProperties());
1690 StringDictionary* dict = property_dictionary(); 1691 StringDictionary* dict = property_dictionary();
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
1791 1792
1792 1793
1793 MaybeObject* JSObject::ReplaceSlowProperty(String* name, 1794 MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1794 Object* value, 1795 Object* value,
1795 PropertyAttributes attributes) { 1796 PropertyAttributes attributes) {
1796 StringDictionary* dictionary = property_dictionary(); 1797 StringDictionary* dictionary = property_dictionary();
1797 int old_index = dictionary->FindEntry(name); 1798 int old_index = dictionary->FindEntry(name);
1798 int new_enumeration_index = 0; // 0 means "Use the next available index." 1799 int new_enumeration_index = 0; // 0 means "Use the next available index."
1799 if (old_index != -1) { 1800 if (old_index != -1) {
1800 // All calls to ReplaceSlowProperty have had all transitions removed. 1801 // All calls to ReplaceSlowProperty have had all transitions removed.
1801 ASSERT(!dictionary->ContainsTransition(old_index));
1802 new_enumeration_index = dictionary->DetailsAt(old_index).index(); 1802 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1803 } 1803 }
1804 1804
1805 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index); 1805 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
1806 return SetNormalizedProperty(name, value, new_details); 1806 return SetNormalizedProperty(name, value, new_details);
1807 } 1807 }
1808 1808
1809 1809
1810 MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition( 1810 MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
1811 String* name, 1811 String* name,
1812 Object* new_value, 1812 Object* new_value,
1813 PropertyAttributes attributes) { 1813 PropertyAttributes attributes) {
1814 Map* old_map = map(); 1814 Map* old_map = map();
1815 Object* result; 1815 Object* result;
1816 { MaybeObject* maybe_result = 1816 { MaybeObject* maybe_result =
1817 ConvertDescriptorToField(name, new_value, attributes); 1817 ConvertDescriptorToField(name, new_value, attributes);
1818 if (!maybe_result->ToObject(&result)) return maybe_result; 1818 if (!maybe_result->To(&result)) return maybe_result;
1819 } 1819 }
1820 // If we get to this point we have succeeded - do not return failure 1820 // If we get to this point we have succeeded - do not return failure
1821 // after this point. Later stuff is optional. 1821 // after this point. Later stuff is optional.
1822 if (!HasFastProperties()) { 1822 if (!HasFastProperties()) {
1823 return result; 1823 return result;
1824 } 1824 }
1825 // Do not add transitions to the map of "new Object()". 1825 // Do not add transitions to the map of "new Object()".
1826 if (map() == GetIsolate()->context()->global_context()-> 1826 if (map() == GetIsolate()->context()->global_context()->
1827 object_function()->map()) { 1827 object_function()->map()) {
1828 return result; 1828 return result;
1829 } 1829 }
1830 1830
1831 MapTransitionDescriptor transition(name, 1831 TransitionArray* new_transitions;
1832 map(), 1832 MaybeObject* maybe_new_transitions =
Jakob Kummerow 2012/06/29 16:31:36 Again, please wrap in {}.
Toon Verwaest 2012/07/05 12:56:11 Done.
1833 attributes); 1833 old_map->transitions()->CopyInsert(name, map());
1834 Object* new_descriptors; 1834 if (!maybe_new_transitions->To(&new_transitions)) {
1835 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()-> 1835 // We have accomplished the main goal, so return success.
1836 CopyInsert(&transition, KEEP_TRANSITIONS); 1836 return result;
1837 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1838 return result; // Yes, return _result_.
1839 }
1840 } 1837 }
1841 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); 1838
1842 map()->SetBackPointer(old_map); 1839 MaybeObject* transition_added = old_map->set_transitions(new_transitions);
Jakob Kummerow 2012/06/29 16:31:36 Again.
Toon Verwaest 2012/07/05 12:56:11 Done.
1840 // Return success if failure since we accomplished the main goal. Otherwise
1841 // also set backpointer.
1842 if (!transition_added->IsFailure()) {
1843 map()->SetBackPointer(old_map);
1844 }
1843 return result; 1845 return result;
1844 } 1846 }
1845 1847
1846 1848
1847 MaybeObject* JSObject::ConvertDescriptorToField(String* name, 1849 MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1848 Object* new_value, 1850 Object* new_value,
1849 PropertyAttributes attributes) { 1851 PropertyAttributes attributes) {
1850 if (map()->unused_property_fields() == 0 && 1852 if (map()->unused_property_fields() == 0 &&
1851 TooManyFastProperties(properties()->length(), MAY_BE_STORE_FROM_KEYED)) { 1853 TooManyFastProperties(properties()->length(), MAY_BE_STORE_FROM_KEYED)) {
1852 Object* obj; 1854 Object* obj;
1853 { MaybeObject* maybe_obj = 1855 { MaybeObject* maybe_obj =
1854 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); 1856 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1855 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1857 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1856 } 1858 }
1857 return ReplaceSlowProperty(name, new_value, attributes); 1859 return ReplaceSlowProperty(name, new_value, attributes);
1858 } 1860 }
1859 1861
1860 int index = map()->NextFreePropertyIndex(); 1862 int index = map()->NextFreePropertyIndex();
1861 FieldDescriptor new_field(name, index, attributes); 1863 FieldDescriptor new_field(name, index, attributes);
1862 // Make a new DescriptorArray replacing an entry with FieldDescriptor. 1864 // Make a new DescriptorArray replacing an entry with FieldDescriptor.
1863 Object* descriptors_unchecked; 1865 Object* descriptors_unchecked;
1864 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()-> 1866 { MaybeObject* maybe_descriptors_unchecked =
1865 CopyInsert(&new_field, REMOVE_TRANSITIONS); 1867 map()->instance_descriptors()->CopyInsert(&new_field);
1866 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) { 1868 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1867 return maybe_descriptors_unchecked; 1869 return maybe_descriptors_unchecked;
1868 } 1870 }
1869 } 1871 }
1870 DescriptorArray* new_descriptors = 1872 DescriptorArray* new_descriptors =
1871 DescriptorArray::cast(descriptors_unchecked); 1873 DescriptorArray::cast(descriptors_unchecked);
1872 1874
1873 // Make a new map for the object. 1875 // Make a new map for the object.
1874 Object* new_map_unchecked; 1876 Object* new_map_unchecked;
1875 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors(); 1877 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after
2149 case CALLBACKS: { 2151 case CALLBACKS: {
2150 if (!FLAG_es5_readonly && result.IsReadOnly()) break; 2152 if (!FLAG_es5_readonly && result.IsReadOnly()) break;
2151 *done = true; 2153 *done = true;
2152 return SetPropertyWithCallback(result.GetCallbackObject(), 2154 return SetPropertyWithCallback(result.GetCallbackObject(),
2153 name, value, result.holder(), strict_mode); 2155 name, value, result.holder(), strict_mode);
2154 } 2156 }
2155 case HANDLER: { 2157 case HANDLER: {
2156 return result.proxy()->SetPropertyViaPrototypesWithHandler( 2158 return result.proxy()->SetPropertyViaPrototypesWithHandler(
2157 this, name, value, attributes, strict_mode, done); 2159 this, name, value, attributes, strict_mode, done);
2158 } 2160 }
2159 case MAP_TRANSITION: 2161 case TRANSITION:
2160 case CONSTANT_TRANSITION:
2161 break;
2162 case NONEXISTENT: 2162 case NONEXISTENT:
2163 UNREACHABLE(); 2163 UNREACHABLE();
2164 break; 2164 break;
2165 } 2165 }
2166 } 2166 }
2167 2167
2168 // If we get here with *done true, we have encountered a read-only property. 2168 // If we get here with *done true, we have encountered a read-only property.
2169 if (!FLAG_es5_readonly) *done = false; 2169 if (!FLAG_es5_readonly) *done = false;
2170 if (*done) { 2170 if (*done) {
2171 if (strict_mode == kNonStrictMode) return value; 2171 if (strict_mode == kNonStrictMode) return value;
2172 Handle<Object> args[] = { Handle<Object>(name), Handle<Object>(this)}; 2172 Handle<Object> args[] = { Handle<Object>(name), Handle<Object>(this)};
2173 return isolate->Throw(*isolate->factory()->NewTypeError( 2173 return isolate->Throw(*isolate->factory()->NewTypeError(
2174 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)))); 2174 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))));
2175 } 2175 }
2176 return heap->the_hole_value(); 2176 return heap->the_hole_value();
2177 } 2177 }
2178 2178
2179 2179
2180 void JSObject::LookupInDescriptor(String* name, LookupResult* result) { 2180 void Map::LookupDescriptor(JSObject* holder,
2181 DescriptorArray* descriptors = map()->instance_descriptors(); 2181 String* name,
2182 LookupResult* result) {
2183 DescriptorArray* descriptors = this->instance_descriptors();
2182 int number = descriptors->SearchWithCache(name); 2184 int number = descriptors->SearchWithCache(name);
2183 if (number != DescriptorArray::kNotFound) { 2185 if (number != DescriptorArray::kNotFound) {
2184 result->DescriptorResult(this, descriptors->GetDetails(number), number);
2185 } else {
2186 result->NotFound();
2187 }
2188 }
2189
2190
2191 void Map::LookupInDescriptors(JSObject* holder,
2192 String* name,
2193 LookupResult* result) {
2194 DescriptorArray* descriptors = instance_descriptors();
2195 DescriptorLookupCache* cache =
2196 GetHeap()->isolate()->descriptor_lookup_cache();
2197 int number = cache->Lookup(descriptors, name);
2198 if (number == DescriptorLookupCache::kAbsent) {
2199 number = descriptors->Search(name);
2200 cache->Update(descriptors, name, number);
2201 }
2202 if (number != DescriptorArray::kNotFound) {
2203 result->DescriptorResult(holder, descriptors->GetDetails(number), number); 2186 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
2204 } else { 2187 } else {
2205 result->NotFound(); 2188 result->NotFound();
2206 } 2189 }
2207 } 2190 }
2208 2191
2209 2192
2193 static void LookupTransition(Map* map,
Jakob Kummerow 2012/06/29 16:31:36 Why is this a local static function? It would be m
Toon Verwaest 2012/07/05 12:56:11 Done.
2194 JSObject* holder,
2195 String* name,
2196 LookupResult* result) {
2197 TransitionArray* transition_array = map->transitions();
2198 int number = transition_array->Search(name);
2199 if (number != TransitionArray::kNotFound) {
2200 result->TransitionResult(holder, number);
2201 } else {
2202 result->NotFound();
2203 }
2204 }
2205
2206
2207 void Map::LookupTransitionOrDescriptor(JSObject* holder,
2208 String* name,
2209 LookupResult* result) {
2210 // AccessorPairs containing both a Descriptor and a Transition are shared
2211 // between the DescriptorArray and the Transition array. This is why looking
2212 // up the AccessorPair solely in the DescriptorArray works.
2213 // TODO(verwaest) This should be implemented differently so the
2214 // DescriptorArray is free of transitions; and so we can freely share it.
2215 this->LookupDescriptor(holder, name, result);
2216 if (result->IsFound()) return;
2217 LookupTransition(this, holder, name, result);
2218 }
2219
2220
2210 static bool ContainsMap(MapHandleList* maps, Handle<Map> map) { 2221 static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
2211 ASSERT(!map.is_null()); 2222 ASSERT(!map.is_null());
2212 for (int i = 0; i < maps->length(); ++i) { 2223 for (int i = 0; i < maps->length(); ++i) {
2213 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true; 2224 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
2214 } 2225 }
2215 return false; 2226 return false;
2216 } 2227 }
2217 2228
2218 2229
2219 template <class T> 2230 template <class T>
(...skipping 29 matching lines...) Expand all
2249 static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) { 2260 static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
2250 Map* current_map = map; 2261 Map* current_map = map;
2251 int index = GetSequenceIndexFromFastElementsKind(map->elements_kind()); 2262 int index = GetSequenceIndexFromFastElementsKind(map->elements_kind());
2252 int to_index = IsFastElementsKind(to_kind) 2263 int to_index = IsFastElementsKind(to_kind)
2253 ? GetSequenceIndexFromFastElementsKind(to_kind) 2264 ? GetSequenceIndexFromFastElementsKind(to_kind)
2254 : GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND); 2265 : GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
2255 2266
2256 ASSERT(index <= to_index); 2267 ASSERT(index <= to_index);
2257 2268
2258 for (; index < to_index; ++index) { 2269 for (; index < to_index; ++index) {
2270 if (!current_map->HasElementsTransition()) return current_map;
2271 current_map = current_map->elements_transition_map();
2272 }
2273 if (!IsFastElementsKind(to_kind) && current_map->HasElementsTransition()) {
2259 Map* next_map = current_map->elements_transition_map(); 2274 Map* next_map = current_map->elements_transition_map();
2260 if (next_map == NULL) { 2275 if (next_map->elements_kind() == to_kind) return next_map;
2261 return current_map;
2262 }
2263 current_map = next_map;
2264 } 2276 }
2265 if (!IsFastElementsKind(to_kind)) { 2277 ASSERT(IsFastElementsKind(to_kind)
2266 Map* next_map = current_map->elements_transition_map(); 2278 ? current_map->elements_kind() == to_kind
2267 if (next_map != NULL && next_map->elements_kind() == to_kind) { 2279 : current_map->elements_kind() == TERMINAL_FAST_ELEMENTS_KIND);
2268 return next_map;
2269 }
2270 ASSERT(current_map->elements_kind() == TERMINAL_FAST_ELEMENTS_KIND);
2271 } else {
2272 ASSERT(current_map->elements_kind() == to_kind);
2273 }
2274 return current_map; 2280 return current_map;
2275 } 2281 }
2276 2282
2277 2283
2278 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) { 2284 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
2279 Map* to_map = FindClosestElementsTransition(this, to_kind); 2285 Map* to_map = FindClosestElementsTransition(this, to_kind);
2280 if (to_map->elements_kind() == to_kind) return to_map; 2286 if (to_map->elements_kind() == to_kind) return to_map;
2281 return NULL; 2287 return NULL;
2282 } 2288 }
2283 2289
2284 2290
2285 MaybeObject* Map::CreateNextElementsTransition(ElementsKind next_kind) { 2291 MaybeObject* Map::CreateNextElementsTransition(ElementsKind next_kind) {
2286 ASSERT(elements_transition_map() == NULL || 2292 ASSERT(!HasElementsTransition() ||
2287 ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS || 2293 ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS ||
2288 IsExternalArrayElementsKind( 2294 IsExternalArrayElementsKind(
2289 elements_transition_map()->elements_kind())) && 2295 elements_transition_map()->elements_kind())) &&
2290 (next_kind == DICTIONARY_ELEMENTS || 2296 (next_kind == DICTIONARY_ELEMENTS ||
2291 IsExternalArrayElementsKind(next_kind)))); 2297 IsExternalArrayElementsKind(next_kind))));
2292 ASSERT(!IsFastElementsKind(next_kind) || 2298 ASSERT(!IsFastElementsKind(next_kind) ||
2293 IsMoreGeneralElementsKindTransition(elements_kind(), next_kind)); 2299 IsMoreGeneralElementsKindTransition(elements_kind(), next_kind));
2294 ASSERT(next_kind != elements_kind()); 2300 ASSERT(next_kind != elements_kind());
2295 2301
2296 Map* next_map; 2302 Map* next_map;
2297 MaybeObject* maybe_next_map = 2303 MaybeObject* maybe_next_map =
2298 this->CopyDropTransitions(DescriptorArray::CANNOT_BE_SHARED); 2304 this->CopyDropTransitions(DescriptorArray::CANNOT_BE_SHARED);
2299 if (!maybe_next_map->To(&next_map)) return maybe_next_map; 2305 if (!maybe_next_map->To(&next_map)) return maybe_next_map;
2300 2306
2307 MaybeObject* added_elements = this->set_elements_transition_map(next_map);
Jakob Kummerow 2012/06/29 16:31:36 Wrap in {} please.
Toon Verwaest 2012/07/05 12:56:11 Done.
2308 if (added_elements->IsFailure()) return added_elements;
2309
2301 next_map->set_elements_kind(next_kind); 2310 next_map->set_elements_kind(next_kind);
2302 next_map->SetBackPointer(this); 2311 next_map->SetBackPointer(this);
2303 this->set_elements_transition_map(next_map);
2304 return next_map; 2312 return next_map;
2305 } 2313 }
2306 2314
2307 2315
2308 static MaybeObject* AddMissingElementsTransitions(Map* map, 2316 static MaybeObject* AddMissingElementsTransitions(Map* map,
2309 ElementsKind to_kind) { 2317 ElementsKind to_kind) {
2310 ASSERT(IsFastElementsKind(map->elements_kind())); 2318 ASSERT(IsFastElementsKind(map->elements_kind()));
2311 int index = GetSequenceIndexFromFastElementsKind(map->elements_kind()); 2319 int index = GetSequenceIndexFromFastElementsKind(map->elements_kind());
2312 int to_index = IsFastElementsKind(to_kind) 2320 int to_index = IsFastElementsKind(to_kind)
2313 ? GetSequenceIndexFromFastElementsKind(to_kind) 2321 ? GetSequenceIndexFromFastElementsKind(to_kind)
(...skipping 25 matching lines...) Expand all
2339 2347
2340 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object, 2348 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
2341 ElementsKind to_kind) { 2349 ElementsKind to_kind) {
2342 Isolate* isolate = object->GetIsolate(); 2350 Isolate* isolate = object->GetIsolate();
2343 CALL_HEAP_FUNCTION(isolate, 2351 CALL_HEAP_FUNCTION(isolate,
2344 object->GetElementsTransitionMap(isolate, to_kind), 2352 object->GetElementsTransitionMap(isolate, to_kind),
2345 Map); 2353 Map);
2346 } 2354 }
2347 2355
2348 2356
2349 // If the map is using the empty descriptor array, install a new empty
2350 // descriptor array that will contain an element transition.
2351 // TODO(verwaest) Goes away once the descriptor array is immutable.
2352 static MaybeObject* EnsureMayContainTransitions(Map* map) {
2353 if (map->instance_descriptors()->MayContainTransitions()) return map;
2354 DescriptorArray* descriptor_array;
2355 MaybeObject* maybe_descriptor_array =
2356 DescriptorArray::Allocate(0, DescriptorArray::CANNOT_BE_SHARED);
2357 if (!maybe_descriptor_array->To(&descriptor_array)) {
2358 return maybe_descriptor_array;
2359 }
2360 map->set_instance_descriptors(descriptor_array);
2361 return map;
2362 }
2363
2364
2365 MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) { 2357 MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
2366 Map* start_map = map(); 2358 Map* start_map = map();
2367 ElementsKind from_kind = start_map->elements_kind(); 2359 ElementsKind from_kind = start_map->elements_kind();
2368 2360
2369 if (from_kind == to_kind) { 2361 if (from_kind == to_kind) {
2370 return start_map; 2362 return start_map;
2371 } 2363 }
2372 2364
2373 Context* global_context = GetIsolate()->context()->global_context(); 2365 Context* global_context = GetIsolate()->context()->global_context();
2374 bool allow_store_transition = 2366 bool allow_store_transition =
(...skipping 14 matching lines...) Expand all
2389 if (!allow_store_transition) { 2381 if (!allow_store_transition) {
2390 // Create a new free-floating map only if we are not allowed to store it. 2382 // Create a new free-floating map only if we are not allowed to store it.
2391 Map* new_map = NULL; 2383 Map* new_map = NULL;
2392 MaybeObject* maybe_new_map = 2384 MaybeObject* maybe_new_map =
2393 start_map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED); 2385 start_map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
2394 if (!maybe_new_map->To(&new_map)) return maybe_new_map; 2386 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
2395 new_map->set_elements_kind(to_kind); 2387 new_map->set_elements_kind(to_kind);
2396 return new_map; 2388 return new_map;
2397 } 2389 }
2398 2390
2399 EnsureMayContainTransitions(start_map);
2400 Map* closest_map = FindClosestElementsTransition(start_map, to_kind); 2391 Map* closest_map = FindClosestElementsTransition(start_map, to_kind);
2401 2392
2402 if (closest_map->elements_kind() == to_kind) { 2393 if (closest_map->elements_kind() == to_kind) {
2403 return closest_map; 2394 return closest_map;
2404 } 2395 }
2405 2396
2406 return AddMissingElementsTransitions(closest_map, to_kind); 2397 return AddMissingElementsTransitions(closest_map, to_kind);
2407 } 2398 }
2408 2399
2409 2400
2410 void JSObject::LocalLookupRealNamedProperty(String* name, 2401 void JSObject::LocalLookupRealNamedProperty(String* name,
2411 LookupResult* result) { 2402 LookupResult* result) {
2412 if (IsJSGlobalProxy()) { 2403 if (IsJSGlobalProxy()) {
2413 Object* proto = GetPrototype(); 2404 Object* proto = GetPrototype();
2414 if (proto->IsNull()) return result->NotFound(); 2405 if (proto->IsNull()) return result->NotFound();
2415 ASSERT(proto->IsJSGlobalObject()); 2406 ASSERT(proto->IsJSGlobalObject());
2416 // A GlobalProxy's prototype should always be a proper JSObject. 2407 // A GlobalProxy's prototype should always be a proper JSObject.
2417 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result); 2408 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2418 } 2409 }
2419 2410
2420 if (HasFastProperties()) { 2411 if (HasFastProperties()) {
2421 LookupInDescriptor(name, result); 2412 map()->LookupTransitionOrDescriptor(this, name, result);
2422 if (result->IsFound()) { 2413 // A property or a map transition was found. We return all of these result
2423 // A property, a map transition or a null descriptor was found. 2414 // types because LocalLookupRealNamedProperty is used when setting
2424 // We return all of these result types because 2415 // properties where map transitions are handled.
2425 // LocalLookupRealNamedProperty is used when setting properties 2416 ASSERT(!result->IsFound() ||
2426 // where map transitions and null descriptors are handled. 2417 (result->holder() == this && result->IsFastPropertyType()));
2427 ASSERT(result->holder() == this && result->IsFastPropertyType()); 2418 // Disallow caching for uninitialized constants. These can only
2428 // Disallow caching for uninitialized constants. These can only 2419 // occur as fields.
2429 // occur as fields. 2420 if (result->IsField() &&
2430 if (result->IsField() && 2421 result->IsReadOnly() &&
2431 result->IsReadOnly() && 2422 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
2432 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) { 2423 result->DisallowCaching();
2433 result->DisallowCaching(); 2424 }
2425 return;
2426 }
2427
2428 int entry = property_dictionary()->FindEntry(name);
2429 if (entry != StringDictionary::kNotFound) {
2430 Object* value = property_dictionary()->ValueAt(entry);
2431 if (IsGlobalObject()) {
2432 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2433 if (d.IsDeleted()) {
2434 result->NotFound();
2435 return;
2434 } 2436 }
2435 return; 2437 value = JSGlobalPropertyCell::cast(value)->value();
2436 } 2438 }
2437 } else { 2439 // Make sure to disallow caching for uninitialized constants
2438 int entry = property_dictionary()->FindEntry(name); 2440 // found in the dictionary-mode objects.
2439 if (entry != StringDictionary::kNotFound) { 2441 if (value->IsTheHole()) result->DisallowCaching();
2440 Object* value = property_dictionary()->ValueAt(entry); 2442 result->DictionaryResult(this, entry);
2441 if (IsGlobalObject()) { 2443 return;
2442 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2443 if (d.IsDeleted()) {
2444 result->NotFound();
2445 return;
2446 }
2447 value = JSGlobalPropertyCell::cast(value)->value();
2448 }
2449 // Make sure to disallow caching for uninitialized constants
2450 // found in the dictionary-mode objects.
2451 if (value->IsTheHole()) result->DisallowCaching();
2452 result->DictionaryResult(this, entry);
2453 return;
2454 }
2455 } 2444 }
2445
2456 result->NotFound(); 2446 result->NotFound();
2457 } 2447 }
2458 2448
2459 2449
2460 void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) { 2450 void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2461 LocalLookupRealNamedProperty(name, result); 2451 LocalLookupRealNamedProperty(name, result);
2462 if (result->IsProperty()) return; 2452 if (result->IsProperty()) return;
2463 2453
2464 LookupRealNamedPropertyInPrototypes(name, result); 2454 LookupRealNamedPropertyInPrototypes(name, result);
2465 } 2455 }
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after
2872 bool done = false; 2862 bool done = false;
2873 MaybeObject* result_object = 2863 MaybeObject* result_object =
2874 SetPropertyViaPrototypes(name, value, attributes, strict_mode, &done); 2864 SetPropertyViaPrototypes(name, value, attributes, strict_mode, &done);
2875 if (done) return result_object; 2865 if (done) return result_object;
2876 } 2866 }
2877 2867
2878 if (!result->IsFound()) { 2868 if (!result->IsFound()) {
2879 // Neither properties nor transitions found. 2869 // Neither properties nor transitions found.
2880 return AddProperty(name, value, attributes, strict_mode, store_mode); 2870 return AddProperty(name, value, attributes, strict_mode, store_mode);
2881 } 2871 }
2882 if (result->IsReadOnly() && result->IsProperty()) { 2872 if (result->IsProperty() && result->IsReadOnly()) {
2883 if (strict_mode == kStrictMode) { 2873 if (strict_mode == kStrictMode) {
2884 Handle<JSObject> self(this); 2874 Handle<JSObject> self(this);
2885 Handle<String> hname(name); 2875 Handle<String> hname(name);
2886 Handle<Object> args[] = { hname, self }; 2876 Handle<Object> args[] = { hname, self };
2887 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError( 2877 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
2888 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)))); 2878 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))));
2889 } else { 2879 } else {
2890 return value; 2880 return value;
2891 } 2881 }
2892 } 2882 }
2883
2893 // This is a real property that is not read-only, or it is a 2884 // This is a real property that is not read-only, or it is a
2894 // transition or null descriptor and there are no setters in the prototypes. 2885 // transition or null descriptor and there are no setters in the prototypes.
2895 switch (result->type()) { 2886 switch (result->type()) {
2896 case NORMAL: 2887 case NORMAL:
2897 return SetNormalizedProperty(result, value); 2888 return SetNormalizedProperty(result, value);
2898 case FIELD: 2889 case FIELD:
2899 return FastPropertyAtPut(result->GetFieldIndex(), value); 2890 return FastPropertyAtPut(result->GetFieldIndex(), value);
2900 case MAP_TRANSITION:
2901 if (attributes == result->GetAttributes()) {
2902 // Only use map transition if the attributes match.
2903 return AddFastPropertyUsingMap(result->GetTransitionMap(),
2904 name,
2905 value);
2906 }
2907 return ConvertDescriptorToField(name, value, attributes);
2908 case CONSTANT_FUNCTION: 2891 case CONSTANT_FUNCTION:
2909 // Only replace the function if necessary. 2892 // Only replace the function if necessary.
2910 if (value == result->GetConstantFunction()) return value; 2893 if (value == result->GetConstantFunction()) return value;
2911 // Preserve the attributes of this existing property. 2894 // Preserve the attributes of this existing property.
2912 attributes = result->GetAttributes(); 2895 attributes = result->GetAttributes();
2913 return ConvertDescriptorToField(name, value, attributes); 2896 return ConvertDescriptorToField(name, value, attributes);
2914 case CALLBACKS: { 2897 case CALLBACKS: {
2915 Object* callback_object = result->GetCallbackObject(); 2898 Object* callback_object = result->GetCallbackObject();
2916 if (callback_object->IsAccessorPair() &&
2917 !AccessorPair::cast(callback_object)->ContainsAccessor()) {
2918 return ConvertDescriptorToField(name, value, attributes);
2919 }
2920 return SetPropertyWithCallback(callback_object, 2899 return SetPropertyWithCallback(callback_object,
2921 name, 2900 name,
2922 value, 2901 value,
2923 result->holder(), 2902 result->holder(),
2924 strict_mode); 2903 strict_mode);
2925 } 2904 }
2926 case INTERCEPTOR: 2905 case INTERCEPTOR:
2927 return SetPropertyWithInterceptor(name, value, attributes, strict_mode); 2906 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
2928 case CONSTANT_TRANSITION: { 2907 case TRANSITION: {
2908 Object* transition = result->GetTransitionValue();
2909
2910 if (transition->IsAccessorPair()) {
2911 if (!AccessorPair::cast(transition)->ContainsAccessor()) {
2912 return ConvertDescriptorToField(name, value, attributes);
2913 }
2914 return SetPropertyWithCallback(transition,
2915 name,
2916 value,
2917 result->holder(),
2918 strict_mode);
2919 }
2920
2921 Map* transition_map = Map::cast(transition);
2922 DescriptorArray* descriptors = transition_map->instance_descriptors();
2923 int descriptor = descriptors->SearchWithCache(name);
2924 PropertyDetails details = descriptors->GetDetails(descriptor);
2925 ASSERT(details.type() == FIELD || details.type() == CONSTANT_FUNCTION);
2926
2927 if (details.type() == FIELD) {
2928 if (attributes == details.attributes()) {
2929 int field_index = descriptors->GetFieldIndex(descriptor);
2930 return AddFastPropertyUsingMap(transition_map,
2931 name,
2932 value,
2933 field_index);
2934 }
2935 return ConvertDescriptorToField(name, value, attributes);
2936 }
2937
2938 // Is transition to CONSTANT_FUNCTION
Jakob Kummerow 2012/06/29 16:31:36 nit: missing full stop.
Toon Verwaest 2012/07/05 12:56:11 Done.
2939 Object* constant_function = descriptors->GetValue(descriptor);
2929 // If the same constant function is being added we can simply 2940 // If the same constant function is being added we can simply
2930 // transition to the target map. 2941 // transition to the target map.
2931 Map* target_map = result->GetTransitionMap(); 2942 if (constant_function == value) {
2932 DescriptorArray* target_descriptors = target_map->instance_descriptors(); 2943 set_map(transition_map);
2933 int number = target_descriptors->SearchWithCache(name); 2944 return this;
2934 ASSERT(number != DescriptorArray::kNotFound);
2935 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2936 JSFunction* function =
2937 JSFunction::cast(target_descriptors->GetValue(number));
2938 if (value == function) {
2939 set_map(target_map);
2940 return value;
2941 } 2945 }
2942 // Otherwise, replace with a MAP_TRANSITION to a new map with a 2946 // Otherwise, replace with a map transition to a new map with a FIELD,
2943 // FIELD, even if the value is a constant function. 2947 // even if the value is a constant function.
2944 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); 2948 return ConvertDescriptorToFieldAndMapTransition(
2949 name, value, attributes);
2945 } 2950 }
2946 case HANDLER: 2951 case HANDLER:
2947 case NONEXISTENT: 2952 case NONEXISTENT:
2948 UNREACHABLE(); 2953 UNREACHABLE();
2949 return value; 2954 return value;
2950 } 2955 }
2951 UNREACHABLE(); // keep the compiler happy 2956 UNREACHABLE(); // keep the compiler happy
2952 return value; 2957 return value;
2953 } 2958 }
2954 2959
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
3004 value, 3009 value,
3005 attributes); 3010 attributes);
3006 } 3011 }
3007 3012
3008 // Check for accessor in prototype chain removed here in clone. 3013 // Check for accessor in prototype chain removed here in clone.
3009 if (!result.IsFound()) { 3014 if (!result.IsFound()) {
3010 // Neither properties nor transitions found. 3015 // Neither properties nor transitions found.
3011 return AddProperty(name, value, attributes, kNonStrictMode); 3016 return AddProperty(name, value, attributes, kNonStrictMode);
3012 } 3017 }
3013 3018
3014 PropertyDetails details = PropertyDetails(attributes, NORMAL);
3015
3016 // Check of IsReadOnly removed from here in clone. 3019 // Check of IsReadOnly removed from here in clone.
3017 switch (result.type()) { 3020 switch (result.type()) {
3018 case NORMAL: 3021 case NORMAL: {
3022 PropertyDetails details = PropertyDetails(attributes, NORMAL);
3019 return SetNormalizedProperty(name, value, details); 3023 return SetNormalizedProperty(name, value, details);
3024 }
3020 case FIELD: 3025 case FIELD:
3021 return FastPropertyAtPut(result.GetFieldIndex(), value); 3026 return FastPropertyAtPut(result.GetFieldIndex(), value);
3022 case MAP_TRANSITION:
3023 if (attributes == result.GetAttributes()) {
3024 // Only use map transition if the attributes match.
3025 return AddFastPropertyUsingMap(result.GetTransitionMap(),
3026 name,
3027 value);
3028 }
3029 return ConvertDescriptorToField(name, value, attributes);
3030 case CONSTANT_FUNCTION: 3027 case CONSTANT_FUNCTION:
3031 // Only replace the function if necessary. 3028 // Only replace the function if necessary.
3032 if (value == result.GetConstantFunction()) return value; 3029 if (value == result.GetConstantFunction()) return value;
3033 // Preserve the attributes of this existing property. 3030 // Preserve the attributes of this existing property.
3034 attributes = result.GetAttributes(); 3031 attributes = result.GetAttributes();
3035 return ConvertDescriptorToField(name, value, attributes); 3032 return ConvertDescriptorToField(name, value, attributes);
3036 case CALLBACKS: 3033 case CALLBACKS:
3037 case INTERCEPTOR: 3034 case INTERCEPTOR:
3038 // Override callback in clone 3035 // Override callback in clone
3039 return ConvertDescriptorToField(name, value, attributes); 3036 return ConvertDescriptorToField(name, value, attributes);
3040 case CONSTANT_TRANSITION: 3037 case TRANSITION: {
3041 // Replace with a MAP_TRANSITION to a new map with a FIELD, even 3038 Object* transition = result.GetTransitionValue();
3042 // if the value is a function. 3039
3040 if (transition->IsAccessorPair()) {
3041 return ConvertDescriptorToField(name, value, attributes);
3042 }
3043
3044 Map* transition_map = Map::cast(transition);
3045 DescriptorArray* descriptors = transition_map->instance_descriptors();
3046 int descriptor = descriptors->Search(name);
3047 PropertyDetails details = descriptors->GetDetails(descriptor);
3048 ASSERT(details.type() == FIELD || details.type() == CONSTANT_FUNCTION);
3049
3050 if (details.type() == FIELD) {
3051 if (attributes == details.attributes()) {
3052 int field_index = descriptors->GetFieldIndex(descriptor);
3053 return AddFastPropertyUsingMap(transition_map,
3054 name,
3055 value,
3056 field_index);
3057 }
3058 return ConvertDescriptorToField(name, value, attributes);
3059 }
3060
3061 // Was transition to CONSTANT_FUNCTION. Replace with a map transition to a
3062 // new map with a FIELD, even if the value is a function.
3043 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); 3063 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
3064 }
3044 case HANDLER: 3065 case HANDLER:
3045 case NONEXISTENT: 3066 case NONEXISTENT:
3046 UNREACHABLE(); 3067 UNREACHABLE();
3047 } 3068 }
3048 UNREACHABLE(); // keep the compiler happy 3069 UNREACHABLE(); // keep the compiler happy
3049 return value; 3070 return value;
3050 } 3071 }
3051 3072
3052 3073
3053 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor( 3074 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
3157 case CONSTANT_FUNCTION: 3178 case CONSTANT_FUNCTION:
3158 case CALLBACKS: 3179 case CALLBACKS:
3159 return result->GetAttributes(); 3180 return result->GetAttributes();
3160 case HANDLER: { 3181 case HANDLER: {
3161 return JSProxy::cast(result->proxy())->GetPropertyAttributeWithHandler( 3182 return JSProxy::cast(result->proxy())->GetPropertyAttributeWithHandler(
3162 receiver, name); 3183 receiver, name);
3163 } 3184 }
3164 case INTERCEPTOR: 3185 case INTERCEPTOR:
3165 return result->holder()->GetPropertyAttributeWithInterceptor( 3186 return result->holder()->GetPropertyAttributeWithInterceptor(
3166 JSObject::cast(receiver), name, continue_search); 3187 JSObject::cast(receiver), name, continue_search);
3167 default: 3188 case TRANSITION:
3189 case NONEXISTENT:
3168 UNREACHABLE(); 3190 UNREACHABLE();
3169 } 3191 }
3170 } 3192 }
3171 return ABSENT; 3193 return ABSENT;
3172 } 3194 }
3173 3195
3174 3196
3175 PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) { 3197 PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
3176 // Check whether the name is an array index. 3198 // Check whether the name is an array index.
3177 uint32_t index = 0; 3199 uint32_t index = 0;
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
3314 case FIELD: { 3336 case FIELD: {
3315 PropertyDetails d = 3337 PropertyDetails d =
3316 PropertyDetails(details.attributes(), NORMAL, details.index()); 3338 PropertyDetails(details.attributes(), NORMAL, details.index());
3317 Object* value = FastPropertyAt(descs->GetFieldIndex(i)); 3339 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
3318 MaybeObject* maybe_dictionary = 3340 MaybeObject* maybe_dictionary =
3319 dictionary->Add(descs->GetKey(i), value, d); 3341 dictionary->Add(descs->GetKey(i), value, d);
3320 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; 3342 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
3321 break; 3343 break;
3322 } 3344 }
3323 case CALLBACKS: { 3345 case CALLBACKS: {
3324 if (!descs->IsProperty(i)) break;
3325 Object* value = descs->GetCallbacksObject(i); 3346 Object* value = descs->GetCallbacksObject(i);
3326 if (value->IsAccessorPair()) { 3347 if (value->IsAccessorPair()) {
3327 MaybeObject* maybe_copy = 3348 MaybeObject* maybe_copy =
3328 AccessorPair::cast(value)->CopyWithoutTransitions(); 3349 AccessorPair::cast(value)->CopyWithoutTransitions();
3329 if (!maybe_copy->To(&value)) return maybe_copy; 3350 if (!maybe_copy->To(&value)) return maybe_copy;
3330 } 3351 }
3331 MaybeObject* maybe_dictionary = 3352 MaybeObject* maybe_dictionary =
3332 dictionary->Add(descs->GetKey(i), value, details); 3353 dictionary->Add(descs->GetKey(i), value, details);
3333 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; 3354 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
3334 break; 3355 break;
3335 } 3356 }
3336 case MAP_TRANSITION:
3337 case CONSTANT_TRANSITION:
3338 case INTERCEPTOR: 3357 case INTERCEPTOR:
3339 break; 3358 break;
3340 case HANDLER: 3359 case HANDLER:
3341 case NORMAL: 3360 case NORMAL:
3361 case TRANSITION:
3342 case NONEXISTENT: 3362 case NONEXISTENT:
3343 UNREACHABLE(); 3363 UNREACHABLE();
3344 break; 3364 break;
3345 } 3365 }
3346 } 3366 }
3347 3367
3348 Heap* current_heap = GetHeap(); 3368 Heap* current_heap = GetHeap();
3349 3369
3350 // Copy the next enumeration index from instance descriptor. 3370 // Copy the next enumeration index from instance descriptor.
3351 int index = map_of_this->instance_descriptors()->NextEnumerationIndex(); 3371 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after
3671 MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) { 3691 MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) {
3672 ASSERT(!IsJSGlobalProxy()); 3692 ASSERT(!IsJSGlobalProxy());
3673 if (HasFastProperties()) { 3693 if (HasFastProperties()) {
3674 // If the object has fast properties, check whether the first slot 3694 // If the object has fast properties, check whether the first slot
3675 // in the descriptor array matches the hidden symbol. Since the 3695 // in the descriptor array matches the hidden symbol. Since the
3676 // hidden symbols hash code is zero (and no other string has hash 3696 // hidden symbols hash code is zero (and no other string has hash
3677 // code zero) it will always occupy the first entry if present. 3697 // code zero) it will always occupy the first entry if present.
3678 DescriptorArray* descriptors = this->map()->instance_descriptors(); 3698 DescriptorArray* descriptors = this->map()->instance_descriptors();
3679 if ((descriptors->number_of_descriptors() > 0) && 3699 if ((descriptors->number_of_descriptors() > 0) &&
3680 (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) { 3700 (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
3681 if (descriptors->GetType(0) == FIELD) { 3701 ASSERT(descriptors->GetType(0) == FIELD);
3682 Object* hidden_store = 3702 Object* hidden_store =
3683 this->FastPropertyAt(descriptors->GetFieldIndex(0)); 3703 this->FastPropertyAt(descriptors->GetFieldIndex(0));
3684 return StringDictionary::cast(hidden_store); 3704 return StringDictionary::cast(hidden_store);
3685 } else {
3686 ASSERT(descriptors->GetType(0) == MAP_TRANSITION);
3687 }
3688 } 3705 }
3689 } else { 3706 } else {
3690 PropertyAttributes attributes; 3707 PropertyAttributes attributes;
3691 // You can't install a getter on a property indexed by the hidden symbol, 3708 // You can't install a getter on a property indexed by the hidden symbol,
3692 // so we can be sure that GetLocalPropertyPostInterceptor returns a real 3709 // so we can be sure that GetLocalPropertyPostInterceptor returns a real
3693 // object. 3710 // object.
3694 Object* lookup = 3711 Object* lookup =
3695 GetLocalPropertyPostInterceptor(this, 3712 GetLocalPropertyPostInterceptor(this,
3696 GetHeap()->hidden_symbol(), 3713 GetHeap()->hidden_symbol(),
3697 &attributes)->ToObjectUnchecked(); 3714 &attributes)->ToObjectUnchecked();
(...skipping 22 matching lines...) Expand all
3720 ASSERT(!IsJSGlobalProxy()); 3737 ASSERT(!IsJSGlobalProxy());
3721 ASSERT(HasHiddenProperties()); 3738 ASSERT(HasHiddenProperties());
3722 if (HasFastProperties()) { 3739 if (HasFastProperties()) {
3723 // If the object has fast properties, check whether the first slot 3740 // If the object has fast properties, check whether the first slot
3724 // in the descriptor array matches the hidden symbol. Since the 3741 // in the descriptor array matches the hidden symbol. Since the
3725 // hidden symbols hash code is zero (and no other string has hash 3742 // hidden symbols hash code is zero (and no other string has hash
3726 // code zero) it will always occupy the first entry if present. 3743 // code zero) it will always occupy the first entry if present.
3727 DescriptorArray* descriptors = this->map()->instance_descriptors(); 3744 DescriptorArray* descriptors = this->map()->instance_descriptors();
3728 if ((descriptors->number_of_descriptors() > 0) && 3745 if ((descriptors->number_of_descriptors() > 0) &&
3729 (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) { 3746 (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
3730 if (descriptors->GetType(0) == FIELD) { 3747 ASSERT(descriptors->GetType(0) == FIELD);
3731 this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary); 3748 this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary);
3732 return this; 3749 return this;
3733 } else {
3734 ASSERT(descriptors->GetType(0) == MAP_TRANSITION);
3735 }
3736 } 3750 }
3737 } 3751 }
3738 MaybeObject* store_result = 3752 MaybeObject* store_result =
3739 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(), 3753 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3740 dictionary, 3754 dictionary,
3741 DONT_ENUM, 3755 DONT_ENUM,
3742 kNonStrictMode, 3756 kNonStrictMode,
3743 OMIT_EXTENSIBILITY_CHECK); 3757 OMIT_EXTENSIBILITY_CHECK);
3744 if (store_result->IsFailure()) return store_result; 3758 if (store_result->IsFailure()) return store_result;
3745 return this; 3759 return this;
(...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after
4160 } 4174 }
4161 return true; 4175 return true;
4162 } 4176 }
4163 4177
4164 4178
4165 int Map::NumberOfDescribedProperties(PropertyAttributes filter) { 4179 int Map::NumberOfDescribedProperties(PropertyAttributes filter) {
4166 int result = 0; 4180 int result = 0;
4167 DescriptorArray* descs = instance_descriptors(); 4181 DescriptorArray* descs = instance_descriptors();
4168 for (int i = 0; i < descs->number_of_descriptors(); i++) { 4182 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4169 PropertyDetails details = descs->GetDetails(i); 4183 PropertyDetails details = descs->GetDetails(i);
4170 if (descs->IsProperty(i) && (details.attributes() & filter) == 0) { 4184 if ((details.attributes() & filter) == 0) {
4171 result++; 4185 result++;
4172 } 4186 }
4173 } 4187 }
4174 return result; 4188 return result;
4175 } 4189 }
4176 4190
4177 4191
4178 int Map::PropertyIndexFor(String* name) { 4192 int Map::PropertyIndexFor(String* name) {
4179 DescriptorArray* descs = instance_descriptors(); 4193 DescriptorArray* descs = instance_descriptors();
4180 for (int i = 0; i < descs->number_of_descriptors(); i++) { 4194 for (int i = 0; i < descs->number_of_descriptors(); i++) {
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
4263 } 4277 }
4264 4278
4265 4279
4266 // Search object and its prototype chain for callback properties. 4280 // Search object and its prototype chain for callback properties.
4267 void JSObject::LookupCallback(String* name, LookupResult* result) { 4281 void JSObject::LookupCallback(String* name, LookupResult* result) {
4268 Heap* heap = GetHeap(); 4282 Heap* heap = GetHeap();
4269 for (Object* current = this; 4283 for (Object* current = this;
4270 current != heap->null_value() && current->IsJSObject(); 4284 current != heap->null_value() && current->IsJSObject();
4271 current = JSObject::cast(current)->GetPrototype()) { 4285 current = JSObject::cast(current)->GetPrototype()) {
4272 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result); 4286 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
4287 // TODO(verwaest) clean test
Jakob Kummerow 2012/06/29 16:31:36 ?
Toon Verwaest 2012/07/05 12:56:11 Done.
4273 if (result->IsCallbacks()) return; 4288 if (result->IsCallbacks()) return;
4274 } 4289 }
4275 result->NotFound(); 4290 result->NotFound();
4276 } 4291 }
4277 4292
4278 4293
4279 // Try to update an accessor in an elements dictionary. Return true if the 4294 // Try to update an accessor in an elements dictionary. Return true if the
4280 // update succeeded, and false otherwise. 4295 // update succeeded, and false otherwise.
4281 static bool UpdateGetterSetterInDictionary( 4296 static bool UpdateGetterSetterInDictionary(
4282 SeededNumberDictionary* dictionary, 4297 SeededNumberDictionary* dictionary,
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
4366 } 4381 }
4367 accessors->SetComponents(getter, setter); 4382 accessors->SetComponents(getter, setter);
4368 4383
4369 return SetElementCallback(index, accessors, attributes); 4384 return SetElementCallback(index, accessors, attributes);
4370 } 4385 }
4371 4386
4372 4387
4373 MaybeObject* JSObject::CreateAccessorPairFor(String* name) { 4388 MaybeObject* JSObject::CreateAccessorPairFor(String* name) {
4374 LookupResult result(GetHeap()->isolate()); 4389 LookupResult result(GetHeap()->isolate());
4375 LocalLookupRealNamedProperty(name, &result); 4390 LocalLookupRealNamedProperty(name, &result);
4376 if (result.IsProperty() && result.IsCallbacks()) { 4391 if (result.IsPropertyCallbacks()) {
4377 // Note that the result can actually have IsDontDelete() == true when we 4392 // Note that the result can actually have IsDontDelete() == true when we
4378 // e.g. have to fall back to the slow case while adding a setter after 4393 // e.g. have to fall back to the slow case while adding a setter after
4379 // successfully reusing a map transition for a getter. Nevertheless, this is 4394 // successfully reusing a map transition for a getter. Nevertheless, this is
4380 // OK, because the assertion only holds for the whole addition of both 4395 // OK, because the assertion only holds for the whole addition of both
4381 // accessors, not for the addition of each part. See first comment in 4396 // accessors, not for the addition of each part. See first comment in
4382 // DefinePropertyAccessor below. 4397 // DefinePropertyAccessor below.
4383 Object* obj = result.GetCallbackObject(); 4398 Object* obj = result.GetCallbackObject();
4384 if (obj->IsAccessorPair()) { 4399 if (obj->IsAccessorPair()) {
4385 return AccessorPair::cast(obj)->CopyWithoutTransitions(); 4400 return AccessorPair::cast(obj)->CopyWithoutTransitions();
4386 } 4401 }
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
4575 { MaybeObject* maybe_accessors2 = heap->AllocateAccessorPair(); 4590 { MaybeObject* maybe_accessors2 = heap->AllocateAccessorPair();
4576 if (!maybe_accessors2->To(&accessors2)) return maybe_accessors2; 4591 if (!maybe_accessors2->To(&accessors2)) return maybe_accessors2;
4577 } 4592 }
4578 accessors2->set(component, accessor); 4593 accessors2->set(component, accessor);
4579 4594
4580 // step 2: create a copy of the descriptors, incl. the new getter/setter pair 4595 // step 2: create a copy of the descriptors, incl. the new getter/setter pair
4581 Map* map1 = obj->map(); 4596 Map* map1 = obj->map();
4582 CallbacksDescriptor callbacks_descr2(name, accessors2, attributes); 4597 CallbacksDescriptor callbacks_descr2(name, accessors2, attributes);
4583 DescriptorArray* descriptors2; 4598 DescriptorArray* descriptors2;
4584 { MaybeObject* maybe_descriptors2 = 4599 { MaybeObject* maybe_descriptors2 =
4585 map1->instance_descriptors()->CopyInsert(&callbacks_descr2, 4600 map1->instance_descriptors()->CopyInsert(&callbacks_descr2);
4586 REMOVE_TRANSITIONS);
4587 if (!maybe_descriptors2->To(&descriptors2)) return maybe_descriptors2; 4601 if (!maybe_descriptors2->To(&descriptors2)) return maybe_descriptors2;
4588 } 4602 }
4589 4603
4590 // step 3: create a new map with the new descriptors 4604 // step 3: create a new map with the new descriptors
4591 Map* map2; 4605 Map* map2;
4592 { MaybeObject* maybe_map2 = map1->CopyDropDescriptors(); 4606 { MaybeObject* maybe_map2 = map1->CopyDropDescriptors();
4593 if (!maybe_map2->To(&map2)) return maybe_map2; 4607 if (!maybe_map2->To(&map2)) return maybe_map2;
4594 } 4608 }
4595 map2->set_instance_descriptors(descriptors2); 4609 map2->set_instance_descriptors(descriptors2);
4596 4610
4597 // step 4: create a new getter/setter pair with a transition to the new map 4611 // step 4: create a new getter/setter pair with a transition to the new map
4598 AccessorPair* accessors1; 4612 AccessorPair* accessors1;
4599 { MaybeObject* maybe_accessors1 = heap->AllocateAccessorPair(); 4613 { MaybeObject* maybe_accessors1 = heap->AllocateAccessorPair();
4600 if (!maybe_accessors1->To(&accessors1)) return maybe_accessors1; 4614 if (!maybe_accessors1->To(&accessors1)) return maybe_accessors1;
4601 } 4615 }
4602 accessors1->set(component, map2); 4616 accessors1->set(component, map2);
4603 4617
4604 // step 5: create a copy of the descriptors, incl. the new getter/setter pair 4618 // step 5: create a copy of the descriptors, incl. the new getter/setter pair
4605 // with the transition 4619 // with the transition
4606 CallbacksDescriptor callbacks_descr1(name, accessors1, attributes); 4620 TransitionArray* new_transitions;
4607 DescriptorArray* descriptors1; 4621 MaybeObject* maybe_new_transitions =
Jakob Kummerow 2012/06/29 16:31:36 Wrap in {} please.
Toon Verwaest 2012/07/05 12:56:11 Done.
4608 { MaybeObject* maybe_descriptors1 = 4622 map1->transitions()->CopyInsert(name, accessors1);
4609 map1->instance_descriptors()->CopyInsert(&callbacks_descr1, 4623 if (!maybe_new_transitions->To(&new_transitions)) {
4610 KEEP_TRANSITIONS); 4624 // We have accomplished the main goal, so return success.
Jakob Kummerow 2012/06/29 16:31:36 Comment is wrong.
Toon Verwaest 2012/07/05 12:56:11 Done.
4611 if (!maybe_descriptors1->To(&descriptors1)) return maybe_descriptors1; 4625 return maybe_new_transitions;
4612 } 4626 }
4613 4627
4614 // step 6: everything went well so far, so we make our changes visible 4628 // step 6: everything went well so far, so we make our changes visible
4629 MaybeObject* transition_added = map1->set_transitions(new_transitions);
Jakob Kummerow 2012/06/29 16:31:36 again, {} please.
Toon Verwaest 2012/07/05 12:56:11 Done.
4630 if (transition_added->IsFailure()) return transition_added;
4631 map2->SetBackPointer(map1);
4615 obj->set_map(map2); 4632 obj->set_map(map2);
4616 map1->set_instance_descriptors(descriptors1);
4617 map2->SetBackPointer(map1);
4618 return obj; 4633 return obj;
4619 } 4634 }
4620 4635
4621 4636
4622 static bool TransitionToSameAccessor(Object* map, 4637 static bool TransitionToSameAccessor(Object* map,
4623 String* name, 4638 String* name,
4624 AccessorComponent component, 4639 AccessorComponent component,
4625 Object* accessor, 4640 Object* accessor,
4626 PropertyAttributes attributes ) { 4641 PropertyAttributes attributes ) {
4627 DescriptorArray* descs = Map::cast(map)->instance_descriptors(); 4642 DescriptorArray* descs = Map::cast(map)->instance_descriptors();
(...skipping 17 matching lines...) Expand all
4645 { MaybeObject* maybe_accessors3 = accessors2->CopyWithoutTransitions(); 4660 { MaybeObject* maybe_accessors3 = accessors2->CopyWithoutTransitions();
4646 if (!maybe_accessors3->To(&accessors3)) return maybe_accessors3; 4661 if (!maybe_accessors3->To(&accessors3)) return maybe_accessors3;
4647 } 4662 }
4648 accessors3->set(component, accessor); 4663 accessors3->set(component, accessor);
4649 4664
4650 // step 2: create a copy of the descriptors, incl. the new getter/setter pair 4665 // step 2: create a copy of the descriptors, incl. the new getter/setter pair
4651 Map* map2 = obj->map(); 4666 Map* map2 = obj->map();
4652 CallbacksDescriptor callbacks_descr3(name, accessors3, attributes); 4667 CallbacksDescriptor callbacks_descr3(name, accessors3, attributes);
4653 DescriptorArray* descriptors3; 4668 DescriptorArray* descriptors3;
4654 { MaybeObject* maybe_descriptors3 = 4669 { MaybeObject* maybe_descriptors3 =
4655 map2->instance_descriptors()->CopyInsert(&callbacks_descr3, 4670 map2->instance_descriptors()->CopyInsert(&callbacks_descr3);
4656 REMOVE_TRANSITIONS);
4657 if (!maybe_descriptors3->To(&descriptors3)) return maybe_descriptors3; 4671 if (!maybe_descriptors3->To(&descriptors3)) return maybe_descriptors3;
4658 } 4672 }
4659 4673
4660 // step 3: create a new map with the new descriptors 4674 // step 3: create a new map with the new descriptors
4661 Map* map3; 4675 Map* map3;
4662 { MaybeObject* maybe_map3 = map2->CopyDropDescriptors(); 4676 { MaybeObject* maybe_map3 = map2->CopyDropDescriptors();
4663 if (!maybe_map3->To(&map3)) return maybe_map3; 4677 if (!maybe_map3->To(&map3)) return maybe_map3;
4664 } 4678 }
4665 map3->set_instance_descriptors(descriptors3); 4679 map3->set_instance_descriptors(descriptors3);
4666 4680
4667 // step 4: everything went well so far, so we make our changes visible 4681 // step 4: add a new transition to the new map
4682 TransitionArray* new_transitions;
4683 MaybeObject* maybe_transitions =
Jakob Kummerow 2012/06/29 16:31:36 {}
Toon Verwaest 2012/07/05 12:56:11 Done.
4684 map2->transitions()->CopyInsert(name, accessors2);
4685 if (!maybe_transitions->To(&new_transitions)) return maybe_transitions;
4686
4687 // step 5: everything went well so far, so we make our changes visible
4688 MaybeObject* transition_added = map2->set_transitions(new_transitions);
Jakob Kummerow 2012/06/29 16:31:36 {}
Toon Verwaest 2012/07/05 12:56:11 Done.
4689 if (transition_added->IsFailure()) return transition_added;
4690
4691 map3->SetBackPointer(map2);
4668 obj->set_map(map3); 4692 obj->set_map(map3);
4669 accessors2->set(component, map3); 4693 accessors2->set(component, map3);
4670 map3->SetBackPointer(map2);
4671 return obj; 4694 return obj;
4672 } 4695 }
4673 4696
4674 4697
4675 MaybeObject* JSObject::DefineFastAccessor(String* name, 4698 MaybeObject* JSObject::DefineFastAccessor(String* name,
4676 AccessorComponent component, 4699 AccessorComponent component,
4677 Object* accessor, 4700 Object* accessor,
4678 PropertyAttributes attributes) { 4701 PropertyAttributes attributes) {
4679 ASSERT(accessor->IsSpecFunction() || accessor->IsUndefined()); 4702 ASSERT(accessor->IsSpecFunction() || accessor->IsUndefined());
4680 LookupResult result(GetIsolate()); 4703 LookupResult result(GetIsolate());
4681 LocalLookup(name, &result); 4704 LocalLookup(name, &result);
4682 4705
4683 // If we have a new property, create a fresh accessor plus a transition to it. 4706 // If we have a new property, create a fresh accessor plus a transition to it.
4684 if (!result.IsFound()) { 4707 if (!result.IsFound()) {
4685 return CreateFreshAccessor(this, name, component, accessor, attributes); 4708 return CreateFreshAccessor(this, name, component, accessor, attributes);
4686 } 4709 }
4687 4710
4688 // If the property is not a JavaScript accessor, fall back to the slow case. 4711 // If the property is not a JavaScript accessor, fall back to the slow case.
4689 if (result.type() != CALLBACKS) return GetHeap()->null_value(); 4712 if (!result.IsCallbacks()) return GetHeap()->null_value();
4713
4690 Object* callback_value = result.GetCallbackObject(); 4714 Object* callback_value = result.GetCallbackObject();
4691 if (!callback_value->IsAccessorPair()) return GetHeap()->null_value(); 4715 if (!callback_value->IsAccessorPair()) return GetHeap()->null_value();
4692 AccessorPair* accessors = AccessorPair::cast(callback_value); 4716 AccessorPair* accessors = AccessorPair::cast(callback_value);
4693 4717
4694 // Follow a callback transition, if there is a fitting one. 4718 // Follow a callback transition, if there is a fitting one.
4695 Object* entry = accessors->get(component); 4719 Object* entry = accessors->get(component);
4696 if (entry->IsMap() && 4720 if (entry->IsMap() &&
4697 TransitionToSameAccessor(entry, name, component, accessor, attributes)) { 4721 TransitionToSameAccessor(entry, name, component, accessor, attributes)) {
4698 set_map(Map::cast(entry)); 4722 set_map(Map::cast(entry));
4699 return this; 4723 return this;
4700 } 4724 }
4701 4725
4702 // When we re-add the same accessor again, there is nothing to do.
4703 if (entry == accessor && result.GetAttributes() == attributes) return this; 4726 if (entry == accessor && result.GetAttributes() == attributes) return this;
4704 4727
4705 // Only the other accessor has been set so far, create a new transition. 4728 // Only the other accessor has been set so far, create a new transition.
4706 if (entry->IsTheHole()) { 4729 if (entry->IsTheHole()) {
4707 return NewCallbackTransition(this, 4730 return NewCallbackTransition(this,
4708 name, 4731 name,
4709 component, 4732 component,
4710 accessor, 4733 accessor,
4711 attributes, 4734 attributes,
4712 accessors); 4735 accessors);
(...skipping 21 matching lines...) Expand all
4734 return JSObject::cast(proto)->DefineAccessor(info); 4757 return JSObject::cast(proto)->DefineAccessor(info);
4735 } 4758 }
4736 4759
4737 // Make sure that the top context does not change when doing callbacks or 4760 // Make sure that the top context does not change when doing callbacks or
4738 // interceptor calls. 4761 // interceptor calls.
4739 AssertNoContextChange ncc; 4762 AssertNoContextChange ncc;
4740 4763
4741 // Try to flatten before operating on the string. 4764 // Try to flatten before operating on the string.
4742 name->TryFlatten(); 4765 name->TryFlatten();
4743 4766
4744 if (!CanSetCallback(name)) { 4767 if (!CanSetCallback(name)) return isolate->heap()->undefined_value();
4745 return isolate->heap()->undefined_value();
4746 }
4747 4768
4748 uint32_t index = 0; 4769 uint32_t index = 0;
4749 bool is_element = name->AsArrayIndex(&index); 4770 bool is_element = name->AsArrayIndex(&index);
4750 4771
4751 if (is_element) { 4772 if (is_element) {
4752 if (IsJSArray()) return isolate->heap()->undefined_value(); 4773 if (IsJSArray()) return isolate->heap()->undefined_value();
4753 4774
4754 // Accessors overwrite previous callbacks (cf. with getters/setters). 4775 // Accessors overwrite previous callbacks (cf. with getters/setters).
4755 switch (GetElementsKind()) { 4776 switch (GetElementsKind()) {
4756 case FAST_SMI_ELEMENTS: 4777 case FAST_SMI_ELEMENTS:
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
4836 } 4857 }
4837 } 4858 }
4838 } else { 4859 } else {
4839 for (Object* obj = this; 4860 for (Object* obj = this;
4840 obj != heap->null_value(); 4861 obj != heap->null_value();
4841 obj = JSObject::cast(obj)->GetPrototype()) { 4862 obj = JSObject::cast(obj)->GetPrototype()) {
4842 LookupResult result(heap->isolate()); 4863 LookupResult result(heap->isolate());
4843 JSObject::cast(obj)->LocalLookup(name, &result); 4864 JSObject::cast(obj)->LocalLookup(name, &result);
4844 if (result.IsProperty()) { 4865 if (result.IsProperty()) {
4845 if (result.IsReadOnly()) return heap->undefined_value(); 4866 if (result.IsReadOnly()) return heap->undefined_value();
4846 if (result.IsCallbacks()) { 4867 if (result.IsPropertyCallbacks()) {
4847 Object* obj = result.GetCallbackObject(); 4868 Object* obj = result.GetCallbackObject();
4848 if (obj->IsAccessorPair()) { 4869 if (obj->IsAccessorPair()) {
4849 return AccessorPair::cast(obj)->GetComponent(component); 4870 return AccessorPair::cast(obj)->GetComponent(component);
4850 } 4871 }
4851 } 4872 }
4852 } 4873 }
4853 } 4874 }
4854 } 4875 }
4855 return heap->undefined_value(); 4876 return heap->undefined_value();
4856 } 4877 }
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
4896 Map::cast(result)->set_inobject_properties(inobject_properties()); 4917 Map::cast(result)->set_inobject_properties(inobject_properties());
4897 Map::cast(result)->set_unused_property_fields(unused_property_fields()); 4918 Map::cast(result)->set_unused_property_fields(unused_property_fields());
4898 4919
4899 // If the map has pre-allocated properties always start out with a descriptor 4920 // If the map has pre-allocated properties always start out with a descriptor
4900 // array describing these properties. 4921 // array describing these properties.
4901 if (pre_allocated_property_fields() > 0) { 4922 if (pre_allocated_property_fields() > 0) {
4902 ASSERT(constructor()->IsJSFunction()); 4923 ASSERT(constructor()->IsJSFunction());
4903 JSFunction* ctor = JSFunction::cast(constructor()); 4924 JSFunction* ctor = JSFunction::cast(constructor());
4904 Object* descriptors; 4925 Object* descriptors;
4905 { MaybeObject* maybe_descriptors = 4926 { MaybeObject* maybe_descriptors =
4906 ctor->initial_map()->instance_descriptors()->RemoveTransitions( 4927 ctor->initial_map()->instance_descriptors()->Copy(
4907 DescriptorArray::MAY_BE_SHARED); 4928 DescriptorArray::MAY_BE_SHARED);
4908 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors; 4929 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4909 } 4930 }
4910 Map::cast(result)->set_instance_descriptors( 4931 Map::cast(result)->set_instance_descriptors(
4911 DescriptorArray::cast(descriptors)); 4932 DescriptorArray::cast(descriptors));
4912 Map::cast(result)->set_pre_allocated_property_fields( 4933 Map::cast(result)->set_pre_allocated_property_fields(
4913 pre_allocated_property_fields()); 4934 pre_allocated_property_fields());
4914 } 4935 }
4915 Map::cast(result)->set_bit_field(bit_field()); 4936 Map::cast(result)->set_bit_field(bit_field());
4916 Map::cast(result)->set_bit_field2(bit_field2()); 4937 Map::cast(result)->set_bit_field2(bit_field2());
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
4959 4980
4960 4981
4961 MaybeObject* Map::CopyDropTransitions( 4982 MaybeObject* Map::CopyDropTransitions(
4962 DescriptorArray::SharedMode shared_mode) { 4983 DescriptorArray::SharedMode shared_mode) {
4963 Object* new_map; 4984 Object* new_map;
4964 { MaybeObject* maybe_new_map = CopyDropDescriptors(); 4985 { MaybeObject* maybe_new_map = CopyDropDescriptors();
4965 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; 4986 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4966 } 4987 }
4967 Object* descriptors; 4988 Object* descriptors;
4968 { MaybeObject* maybe_descriptors = 4989 { MaybeObject* maybe_descriptors =
4969 instance_descriptors()->RemoveTransitions(shared_mode); 4990 instance_descriptors()->Copy(shared_mode);
4970 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors; 4991 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4971 } 4992 }
4972 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors)); 4993 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
4973 return new_map; 4994 return new_map;
4974 } 4995 }
4975 4996
4976 4997
4977 void Map::UpdateCodeCache(Handle<Map> map, 4998 void Map::UpdateCodeCache(Handle<Map> map,
4978 Handle<String> name, 4999 Handle<String> name,
4979 Handle<Code> code) { 5000 Handle<Code> code) {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
5023 // RemoveFromCodeCache so the code cache must be there. 5044 // RemoveFromCodeCache so the code cache must be there.
5024 ASSERT(!code_cache()->IsFixedArray()); 5045 ASSERT(!code_cache()->IsFixedArray());
5025 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index); 5046 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
5026 } 5047 }
5027 5048
5028 5049
5029 // An iterator over all map transitions in an descriptor array, reusing the map 5050 // An iterator over all map transitions in an descriptor array, reusing the map
5030 // field of the contens array while it is running. 5051 // field of the contens array while it is running.
5031 class IntrusiveMapTransitionIterator { 5052 class IntrusiveMapTransitionIterator {
5032 public: 5053 public:
5033 explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array) 5054 explicit IntrusiveMapTransitionIterator(TransitionArray* transition_array)
5034 : descriptor_array_(descriptor_array) { } 5055 : transition_array_(transition_array) { }
5035 5056
5036 void Start() { 5057 void Start() {
5037 ASSERT(!IsIterating()); 5058 ASSERT(!IsIterating());
5038 if (descriptor_array_->MayContainTransitions()) 5059 if (transition_array_ != NULL)
5039 *DescriptorArrayHeader() = Smi::FromInt(0); 5060 *TransitionArrayHeader() = Smi::FromInt(0);
Jakob Kummerow 2012/06/29 16:31:36 nit: {} please.
Toon Verwaest 2012/07/05 12:56:11 Done.
5040 } 5061 }
5041 5062
5042 bool IsIterating() { 5063 bool IsIterating() {
5043 return descriptor_array_->MayContainTransitions() && 5064 return transition_array_ != NULL &&
5044 (*DescriptorArrayHeader())->IsSmi(); 5065 (*TransitionArrayHeader())->IsSmi();
5045 } 5066 }
5046 5067
5047 Map* Next() { 5068 Map* Next() {
5048 ASSERT(IsIterating()); 5069 ASSERT(IsIterating());
5049 // Attention, tricky index manipulation ahead: Two consecutive indices are 5070 // Attention, tricky index manipulation ahead: Two consecutive indices are
5050 // assigned to each descriptor. Most descriptors directly advance to the 5071 // assigned to each descriptor. Most descriptors directly advance to the
5051 // next descriptor by adding 2 to the index. The exceptions are the 5072 // next descriptor by adding 2 to the index. The exceptions are the
5052 // CALLBACKS entries: An even index means we look at its getter, and an odd 5073 // CALLBACKS entries: An even index means we look at its getter, and an odd
5053 // index means we look at its setter. 5074 // index means we look at its setter.
5054 int raw_index = Smi::cast(*DescriptorArrayHeader())->value(); 5075 int raw_index = Smi::cast(*TransitionArrayHeader())->value();
5055 int index = raw_index / 2; 5076 int index = raw_index / 2;
5056 int number_of_descriptors = descriptor_array_->number_of_descriptors(); 5077 int number_of_transitions = transition_array_->number_of_transitions();
5057 while (index < number_of_descriptors) { 5078 while (index < number_of_transitions) {
5058 PropertyDetails details(descriptor_array_->GetDetails(index)); 5079 Object* value = transition_array_->GetValue(index);
5059 switch (details.type()) { 5080 if (value->IsMap()) {
5060 case MAP_TRANSITION: 5081 *TransitionArrayHeader() = Smi::FromInt(raw_index + 2);
5061 case CONSTANT_TRANSITION: 5082 return static_cast<Map*>(value);
5062 // We definitely have a map transition. 5083 } else if (value->IsAccessorPair()) {
5063 *DescriptorArrayHeader() = Smi::FromInt(raw_index + 2); 5084 // We might have a map transition in a getter or in a setter.
5064 return static_cast<Map*>(descriptor_array_->GetValue(index)); 5085 AccessorPair* accessors = static_cast<AccessorPair*>(value);
5065 case CALLBACKS: { 5086 Object* accessor;
5066 // We might have a map transition in a getter or in a setter. 5087 if ((raw_index & 1) == 0) {
5067 AccessorPair* accessors = 5088 accessor = accessors->setter();
5068 static_cast<AccessorPair*>(descriptor_array_->GetValue(index)); 5089 } else {
5069 Object* accessor; 5090 ++index;
5070 if ((raw_index & 1) == 0) { 5091 accessor = accessors->getter();
5071 accessor = accessors->setter();
5072 } else {
5073 ++index;
5074 accessor = accessors->getter();
5075 }
5076 ++raw_index;
5077 if (accessor->IsMap()) {
5078 *DescriptorArrayHeader() = Smi::FromInt(raw_index);
5079 return static_cast<Map*>(accessor);
5080 }
5081 break;
5082 } 5092 }
5083 case NORMAL: 5093 ++raw_index;
5084 case FIELD: 5094 if (accessor->IsMap()) {
5085 case CONSTANT_FUNCTION: 5095 *TransitionArrayHeader() = Smi::FromInt(raw_index);
5086 case HANDLER: 5096 return static_cast<Map*>(accessor);
5087 case INTERCEPTOR: 5097 }
5088 // We definitely have no map transition. 5098 break;
Jakob Kummerow 2012/06/29 16:31:36 This doesn't look right. Did you mean "continue"?
Toon Verwaest 2012/07/05 12:56:11 Done.
5089 raw_index += 2;
5090 ++index;
5091 break;
5092 case NONEXISTENT:
5093 UNREACHABLE();
5094 break;
5095 } 5099 }
5100 // We definitely have no map transition.
5101 raw_index += 2;
5102 ++index;
5096 } 5103 }
5097 if (index == descriptor_array_->number_of_descriptors()) { 5104 if (index == transition_array_->number_of_transitions()) {
5098 Map* elements_transition = descriptor_array_->elements_transition_map(); 5105 Map* elements_transition = transition_array_->elements();
5099 if (elements_transition != NULL) { 5106 if (elements_transition != NULL) {
5100 *DescriptorArrayHeader() = Smi::FromInt(raw_index + 2); 5107 *TransitionArrayHeader() = Smi::FromInt(raw_index + 2);
5101 return elements_transition; 5108 return elements_transition;
5102 } 5109 }
5103 } 5110 }
5104 *DescriptorArrayHeader() = descriptor_array_->GetHeap()->fixed_array_map(); 5111 *TransitionArrayHeader() = transition_array_->GetHeap()->fixed_array_map();
5105 return NULL; 5112 return NULL;
5106 } 5113 }
5107 5114
5108 private: 5115 private:
5109 Object** DescriptorArrayHeader() { 5116 Object** TransitionArrayHeader() {
5110 return HeapObject::RawField(descriptor_array_, DescriptorArray::kMapOffset); 5117 return HeapObject::RawField(transition_array_, TransitionArray::kMapOffset);
5111 } 5118 }
5112 5119
5113 DescriptorArray* descriptor_array_; 5120 TransitionArray* transition_array_;
5114 }; 5121 };
5115 5122
5116 5123
5117 // An iterator over all prototype transitions, reusing the map field of the 5124 // An iterator over all prototype transitions, reusing the map field of the
5118 // underlying array while it is running. 5125 // underlying array while it is running.
5119 class IntrusivePrototypeTransitionIterator { 5126 class IntrusivePrototypeTransitionIterator {
5120 public: 5127 public:
5121 explicit IntrusivePrototypeTransitionIterator(HeapObject* proto_trans) 5128 explicit IntrusivePrototypeTransitionIterator(HeapObject* proto_trans)
5122 : proto_trans_(proto_trans) { } 5129 : proto_trans_(proto_trans) { }
5123 5130
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
5203 5210
5204 // Reset the current map's map, returning the parent previously stored in it. 5211 // Reset the current map's map, returning the parent previously stored in it.
5205 TraversableMap* GetAndResetParent() { 5212 TraversableMap* GetAndResetParent() {
5206 TraversableMap* old_parent = static_cast<TraversableMap*>(map()); 5213 TraversableMap* old_parent = static_cast<TraversableMap*>(map());
5207 set_map_no_write_barrier(GetHeap()->meta_map()); 5214 set_map_no_write_barrier(GetHeap()->meta_map());
5208 return old_parent; 5215 return old_parent;
5209 } 5216 }
5210 5217
5211 // Can either be Smi (no instance descriptors), or a descriptor array with the 5218 // Can either be Smi (no instance descriptors), or a descriptor array with the
5212 // header overwritten as a Smi (thus iterating). 5219 // header overwritten as a Smi (thus iterating).
5213 DescriptorArray* MutatedInstanceDescriptors() { 5220 TransitionArray* MutatedTransitions() {
5221 if (!instance_descriptors()->HasTransitionArray()) return NULL;
5214 Object* object = 5222 Object* object =
5215 *HeapObject::RawField(this, kInstanceDescriptorsOrBitField3Offset); 5223 *HeapObject::RawField(instance_descriptors(),
5224 DescriptorArray::kTransitionsOffset);
5216 if (object->IsSmi()) { 5225 if (object->IsSmi()) {
5217 return GetHeap()->empty_descriptor_array(); 5226 return NULL;
5218 } else { 5227 } else {
5219 DescriptorArray* descriptor_array = 5228 TransitionArray* transition_array =
5220 static_cast<DescriptorArray*>(object); 5229 static_cast<TransitionArray*>(object);
5221 return descriptor_array; 5230 return transition_array;
5222 } 5231 }
5223 } 5232 }
5224 5233
5225 // Start iterating over this map's children, possibly destroying a FixedArray 5234 // Start iterating over this map's children, possibly destroying a FixedArray
5226 // map (see explanation above). 5235 // map (see explanation above).
5227 void ChildIteratorStart() { 5236 void ChildIteratorStart() {
5228 IntrusiveMapTransitionIterator(instance_descriptors()).Start(); 5237 IntrusiveMapTransitionIterator(transitions()).Start();
5229 IntrusivePrototypeTransitionIterator( 5238 IntrusivePrototypeTransitionIterator(
5230 unchecked_prototype_transitions()).Start(); 5239 unchecked_prototype_transitions()).Start();
5231 } 5240 }
5232 5241
5233 // If we have an unvisited child map, return that one and advance. If we have 5242 // If we have an unvisited child map, return that one and advance. If we have
5234 // none, return NULL and reset any destroyed FixedArray maps. 5243 // none, return NULL and reset any destroyed FixedArray maps.
5235 TraversableMap* ChildIteratorNext() { 5244 TraversableMap* ChildIteratorNext() {
5236 IntrusivePrototypeTransitionIterator 5245 IntrusivePrototypeTransitionIterator
5237 proto_iterator(unchecked_prototype_transitions()); 5246 proto_iterator(unchecked_prototype_transitions());
5238 if (proto_iterator.IsIterating()) { 5247 if (proto_iterator.IsIterating()) {
5239 Map* next = proto_iterator.Next(); 5248 Map* next = proto_iterator.Next();
5240 if (next != NULL) return static_cast<TraversableMap*>(next); 5249 if (next != NULL) return static_cast<TraversableMap*>(next);
5241 } 5250 }
5242 IntrusiveMapTransitionIterator 5251 IntrusiveMapTransitionIterator
5243 descriptor_iterator(MutatedInstanceDescriptors()); 5252 descriptor_iterator(MutatedTransitions());
5244 if (descriptor_iterator.IsIterating()) { 5253 if (descriptor_iterator.IsIterating()) {
5245 Map* next = descriptor_iterator.Next(); 5254 Map* next = descriptor_iterator.Next();
5246 if (next != NULL) return static_cast<TraversableMap*>(next); 5255 if (next != NULL) return static_cast<TraversableMap*>(next);
5247 } 5256 }
5248 return NULL; 5257 return NULL;
5249 } 5258 }
5250 }; 5259 };
5251 5260
5252 5261
5253 // Traverse the transition tree in postorder without using the C++ stack by 5262 // Traverse the transition tree in postorder without using the C++ stack by
(...skipping 611 matching lines...) Expand 10 before | Expand all | Expand 10 after
5865 MaybeObject* maybe_copy = 5874 MaybeObject* maybe_copy =
5866 AccessorPair::cast(value)->CopyWithoutTransitions(); 5875 AccessorPair::cast(value)->CopyWithoutTransitions();
5867 if (!maybe_copy->To(&value)) return maybe_copy; 5876 if (!maybe_copy->To(&value)) return maybe_copy;
5868 } 5877 }
5869 Descriptor desc(src->GetKey(src_index), value, details); 5878 Descriptor desc(src->GetKey(src_index), value, details);
5870 Set(dst_index, &desc, witness); 5879 Set(dst_index, &desc, witness);
5871 return this; 5880 return this;
5872 } 5881 }
5873 5882
5874 5883
5875 MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor, 5884 MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor) {
5876 TransitionFlag transition_flag) {
5877 // Transitions are only kept when inserting another transition.
5878 // This precondition is not required by this function's implementation, but
5879 // is currently required by the semantics of maps, so we check it.
5880 // Conversely, we filter after replacing, so replacing a transition and
5881 // removing all other transitions is not supported.
5882 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
5883 ASSERT(remove_transitions == !descriptor->ContainsTransition());
5884
5885 // Ensure the key is a symbol. 5885 // Ensure the key is a symbol.
5886 { MaybeObject* maybe_result = descriptor->KeyToSymbol(); 5886 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
5887 if (maybe_result->IsFailure()) return maybe_result; 5887 if (maybe_result->IsFailure()) return maybe_result;
5888 } 5888 }
5889 5889
5890 int new_size = 0; 5890 int new_size = number_of_descriptors();
5891 for (int i = 0; i < number_of_descriptors(); i++) {
5892 if (remove_transitions && IsTransitionOnly(i)) continue;
5893 new_size++;
5894 }
5895 5891
5896 // If key is in descriptor, we replace it in-place when filtering. 5892 // If key is in descriptor, we replace it in-place when filtering.
5897 // Count a null descriptor for key as inserted, not replaced. 5893 // Count a null descriptor for key as inserted, not replaced.
5898 int index = Search(descriptor->GetKey()); 5894 int index = SearchWithCache(descriptor->GetKey());
5899 const bool replacing = (index != kNotFound); 5895 const bool replacing = (index != kNotFound);
5900 bool keep_enumeration_index = false; 5896 bool keep_enumeration_index = false;
5901 if (!replacing) { 5897 if (replacing) {
5902 ++new_size;
5903 } else if (!IsTransitionOnly(index)) {
5904 // We are replacing an existing descriptor. We keep the enumeration index 5898 // We are replacing an existing descriptor. We keep the enumeration index
5905 // of a visible property. 5899 // of a visible property.
5906 keep_enumeration_index = true; 5900 keep_enumeration_index = true;
5907 } else if (remove_transitions) { 5901 } else {
5908 // Replaced descriptor has been counted as removed if it is a transition
5909 // that will be replaced. Adjust count in this case.
5910 ++new_size; 5902 ++new_size;
5911 } 5903 }
5912 5904
5913 DescriptorArray* new_descriptors; 5905 DescriptorArray* new_descriptors;
5914 { SharedMode mode = remove_transitions ? MAY_BE_SHARED : CANNOT_BE_SHARED; 5906 { MaybeObject* maybe_result = Allocate(new_size, MAY_BE_SHARED);
5915 MaybeObject* maybe_result = Allocate(new_size, mode);
5916 if (!maybe_result->To(&new_descriptors)) return maybe_result; 5907 if (!maybe_result->To(&new_descriptors)) return maybe_result;
5917 } 5908 }
5918 5909
5919 DescriptorArray::WhitenessWitness witness(new_descriptors); 5910 DescriptorArray::WhitenessWitness witness(new_descriptors);
5920 5911
5921 // Set the enumeration index in the descriptors and set the enumeration index 5912 // Set the enumeration index in the descriptors and set the enumeration index
5922 // in the result. 5913 // in the result.
5923 int enumeration_index = NextEnumerationIndex(); 5914 int enumeration_index = NextEnumerationIndex();
5924 if (!descriptor->ContainsTransition()) { 5915 if (keep_enumeration_index) {
5925 if (keep_enumeration_index) { 5916 descriptor->SetEnumerationIndex(GetDetails(index).index());
5926 descriptor->SetEnumerationIndex(GetDetails(index).index()); 5917 } else {
5927 } else { 5918 descriptor->SetEnumerationIndex(enumeration_index);
5928 descriptor->SetEnumerationIndex(enumeration_index); 5919 ++enumeration_index;
5929 ++enumeration_index;
5930 }
5931 }
5932 Map* old_elements_transition = elements_transition_map();
5933 if ((!remove_transitions) && (old_elements_transition != NULL)) {
5934 new_descriptors->set_elements_transition_map(old_elements_transition);
5935 } 5920 }
5936 new_descriptors->SetNextEnumerationIndex(enumeration_index); 5921 new_descriptors->SetNextEnumerationIndex(enumeration_index);
5937 5922
5938 // Copy the descriptors, filtering out transitions and null descriptors, 5923 // Copy the descriptors, filtering out transitions and null descriptors,
Jakob Kummerow 2012/06/29 16:31:36 update comment?
Toon Verwaest 2012/07/05 12:56:11 Done.
5939 // and inserting or replacing a descriptor. 5924 // and inserting or replacing a descriptor.
5940 int to_index = 0; 5925 int to_index = 0;
5941 int insertion_index = -1; 5926 int insertion_index = -1;
5942 int from_index = 0; 5927 int from_index = 0;
5943 while (from_index < number_of_descriptors()) { 5928 while (from_index < number_of_descriptors()) {
5944 if (insertion_index < 0 && 5929 if (insertion_index < 0 &&
5945 InsertionPointFound(GetKey(from_index), descriptor->GetKey())) { 5930 InsertionPointFound(GetKey(from_index), descriptor->GetKey())) {
5946 insertion_index = to_index++; 5931 insertion_index = to_index++;
5947 if (replacing) from_index++; 5932 if (replacing) from_index++;
5948 } else { 5933 } else {
5949 if (!(remove_transitions && IsTransitionOnly(from_index))) { 5934 MaybeObject* copy_result =
5950 MaybeObject* copy_result = 5935 new_descriptors->CopyFrom(to_index++, this, from_index, witness);
5951 new_descriptors->CopyFrom(to_index++, this, from_index, witness); 5936 if (copy_result->IsFailure()) return copy_result;
5952 if (copy_result->IsFailure()) return copy_result;
5953 }
5954 from_index++; 5937 from_index++;
5955 } 5938 }
5956 } 5939 }
5957 if (insertion_index < 0) insertion_index = to_index++; 5940 if (insertion_index < 0) insertion_index = to_index++;
5958 5941
5959 ASSERT(insertion_index < new_descriptors->number_of_descriptors()); 5942 ASSERT(insertion_index < new_descriptors->number_of_descriptors());
5960 new_descriptors->Set(insertion_index, descriptor, witness); 5943 new_descriptors->Set(insertion_index, descriptor, witness);
5961 5944
5962 ASSERT(to_index == new_descriptors->number_of_descriptors()); 5945 ASSERT(to_index == new_descriptors->number_of_descriptors());
5963 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); 5946 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
5964 5947
5965 return new_descriptors; 5948 return new_descriptors;
5966 } 5949 }
5967 5950
5968 5951
5969 MaybeObject* DescriptorArray::RemoveTransitions(SharedMode shared_mode) { 5952 MaybeObject* DescriptorArray::Copy(SharedMode shared_mode) {
5970 // Allocate the new descriptor array. 5953 // Allocate the new descriptor array.
5971 int new_number_of_descriptors = 0; 5954 int number_of_descriptors = this->number_of_descriptors();
5972 for (int i = 0; i < number_of_descriptors(); i++) {
5973 if (IsProperty(i)) new_number_of_descriptors++;
5974 }
5975 DescriptorArray* new_descriptors; 5955 DescriptorArray* new_descriptors;
5976 { MaybeObject* maybe_result = Allocate(new_number_of_descriptors, 5956 { MaybeObject* maybe_result = Allocate(number_of_descriptors,
5977 shared_mode); 5957 shared_mode);
5978 if (!maybe_result->To(&new_descriptors)) return maybe_result; 5958 if (!maybe_result->To(&new_descriptors)) return maybe_result;
5979 } 5959 }
5980 5960
5981 // Copy the content. 5961 // Copy the content.
5982 DescriptorArray::WhitenessWitness witness(new_descriptors); 5962 DescriptorArray::WhitenessWitness witness(new_descriptors);
5983 int next_descriptor = 0; 5963 for (int i = 0; i < number_of_descriptors; i++) {
5984 for (int i = 0; i < number_of_descriptors(); i++) { 5964 MaybeObject* copy_result =
5985 if (IsProperty(i)) { 5965 new_descriptors->CopyFrom(i, this, i, witness);
5986 MaybeObject* copy_result = 5966 if (copy_result->IsFailure()) return copy_result;
5987 new_descriptors->CopyFrom(next_descriptor++, this, i, witness);
5988 if (copy_result->IsFailure()) return copy_result;
5989 }
5990 } 5967 }
5991 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
5992 new_descriptors->SetNextEnumerationIndex(NextEnumerationIndex()); 5968 new_descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
5993
5994 return new_descriptors; 5969 return new_descriptors;
5995 } 5970 }
5996 5971
5997 // We need the whiteness witness since sort will reshuffle the entries in the 5972 // We need the whiteness witness since sort will reshuffle the entries in the
5998 // descriptor array. If the descriptor array were to be black, the shuffling 5973 // descriptor array. If the descriptor array were to be black, the shuffling
5999 // would move a slot that was already recorded as pointing into an evacuation 5974 // would move a slot that was already recorded as pointing into an evacuation
6000 // candidate. This would result in missing updates upon evacuation. 5975 // candidate. This would result in missing updates upon evacuation.
6001 void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) { 5976 void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) {
6002 // In-place heap sort. 5977 // In-place heap sort.
6003 int len = number_of_descriptors(); 5978 int len = number_of_descriptors();
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
6050 } 6025 }
6051 } 6026 }
6052 6027
6053 6028
6054 void DescriptorArray::Sort(const WhitenessWitness& witness) { 6029 void DescriptorArray::Sort(const WhitenessWitness& witness) {
6055 SortUnchecked(witness); 6030 SortUnchecked(witness);
6056 SLOW_ASSERT(IsSortedNoDuplicates()); 6031 SLOW_ASSERT(IsSortedNoDuplicates());
6057 } 6032 }
6058 6033
6059 6034
6060 int DescriptorArray::BinarySearch(String* name, int low, int high) {
6061 uint32_t hash = name->Hash();
6062 int limit = high;
6063
6064 ASSERT(low <= high);
6065
6066 while (low != high) {
6067 int mid = (low + high) / 2;
6068 String* mid_name = GetKey(mid);
6069 uint32_t mid_hash = mid_name->Hash();
6070
6071 if (mid_hash >= hash) {
6072 high = mid;
6073 } else {
6074 low = mid + 1;
6075 }
6076 }
6077
6078 for (; low <= limit && GetKey(low)->Hash() == hash; ++low) {
6079 if (GetKey(low)->Equals(name)) return low;
6080 }
6081
6082 return kNotFound;
6083 }
6084
6085
6086 int DescriptorArray::LinearSearch(SearchMode mode, String* name, int len) {
6087 uint32_t hash = name->Hash();
6088 for (int number = 0; number < len; number++) {
6089 String* entry = GetKey(number);
6090 if (mode == EXPECT_SORTED && entry->Hash() > hash) break;
6091 if (name->Equals(entry)) return number;
6092 }
6093 return kNotFound;
6094 }
6095
6096
6097 MaybeObject* AccessorPair::CopyWithoutTransitions() { 6035 MaybeObject* AccessorPair::CopyWithoutTransitions() {
6098 Heap* heap = GetHeap(); 6036 Heap* heap = GetHeap();
6099 AccessorPair* copy; 6037 AccessorPair* copy;
6100 { MaybeObject* maybe_copy = heap->AllocateAccessorPair(); 6038 { MaybeObject* maybe_copy = heap->AllocateAccessorPair();
6101 if (!maybe_copy->To(&copy)) return maybe_copy; 6039 if (!maybe_copy->To(&copy)) return maybe_copy;
6102 } 6040 }
6103 copy->set_getter(getter()->IsMap() ? heap->the_hole_value() : getter()); 6041 copy->set_getter(getter()->IsMap() ? heap->the_hole_value() : getter());
6104 copy->set_setter(setter()->IsMap() ? heap->the_hole_value() : setter()); 6042 copy->set_setter(setter()->IsMap() ? heap->the_hole_value() : setter());
6105 return copy; 6043 return copy;
6106 } 6044 }
(...skipping 1222 matching lines...) Expand 10 before | Expand all | Expand 10 after
7329 7267
7330 7268
7331 void String::PrintOn(FILE* file) { 7269 void String::PrintOn(FILE* file) {
7332 int length = this->length(); 7270 int length = this->length();
7333 for (int i = 0; i < length; i++) { 7271 for (int i = 0; i < length; i++) {
7334 fprintf(file, "%c", Get(i)); 7272 fprintf(file, "%c", Get(i));
7335 } 7273 }
7336 } 7274 }
7337 7275
7338 7276
7339 // Clear a possible back pointer in case the transition leads to a dead map.
7340 // Return true in case a back pointer has been cleared and false otherwise.
7341 static bool ClearBackPointer(Heap* heap, Object* target) {
7342 ASSERT(target->IsMap());
7343 Map* map = Map::cast(target);
7344 if (Marking::MarkBitFrom(map).Get()) return false;
7345 map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER);
7346 return true;
7347 }
7348
7349
7350 // This function should only be called from within the GC, since it uses 7277 // This function should only be called from within the GC, since it uses
7351 // IncrementLiveBytesFromGC. If called from anywhere else, this results in an 7278 // IncrementLiveBytesFromGC. If called from anywhere else, this results in an
7352 // inconsistent live-bytes count. 7279 // inconsistent live-bytes count.
7353 static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) { 7280 static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) {
7354 ASSERT(elms->map() != HEAP->fixed_cow_array_map()); 7281 ASSERT(elms->map() != HEAP->fixed_cow_array_map());
7355 // For now this trick is only applied to fixed arrays in new and paged space. 7282 // For now this trick is only applied to fixed arrays in new and paged space.
7356 // In large object space the object's start must coincide with chunk 7283 // In large object space the object's start must coincide with chunk
7357 // and thus the trick is just not applicable. 7284 // and thus the trick is just not applicable.
7358 ASSERT(!HEAP->lo_space()->Contains(elms)); 7285 ASSERT(!HEAP->lo_space()->Contains(elms));
7359 7286
(...skipping 20 matching lines...) Expand all
7380 7307
7381 elms->set_length(len - to_trim); 7308 elms->set_length(len - to_trim);
7382 7309
7383 // Maintain marking consistency for IncrementalMarking. 7310 // Maintain marking consistency for IncrementalMarking.
7384 if (Marking::IsBlack(Marking::MarkBitFrom(elms))) { 7311 if (Marking::IsBlack(Marking::MarkBitFrom(elms))) {
7385 MemoryChunk::IncrementLiveBytesFromGC(elms->address(), -size_delta); 7312 MemoryChunk::IncrementLiveBytesFromGC(elms->address(), -size_delta);
7386 } 7313 }
7387 } 7314 }
7388 7315
7389 7316
7390 // If the descriptor describes a transition to a dead map, the back pointer 7317 // Clear a possible back pointer in case the transition leads to a dead map.
7391 // of this map is cleared and we return true. Otherwise we return false. 7318 // Return true in case a back pointer has been cleared and false otherwise.
7392 static bool ClearNonLiveTransitionsFromDescriptor(Heap* heap, 7319 static bool ClearBackPointer(Heap* heap, Object* target) {
7393 DescriptorArray* d, 7320 ASSERT(target->IsMap());
7394 int descriptor_index) { 7321 Map* map = Map::cast(target);
7395 // If the pair (value, details) is a map transition, check if the target is 7322 if (Marking::MarkBitFrom(map).Get()) return false;
7396 // live. If not, null the descriptor. Also drop the back pointer for that 7323 map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER);
7397 // map transition, so that this map is not reached again by following a back 7324 return true;
7398 // pointer from that non-live map. 7325 }
7399 PropertyDetails details(d->GetDetails(descriptor_index)); 7326
7400 switch (details.type()) { 7327
7401 case MAP_TRANSITION: 7328 static bool ClearAccessorComponent(Heap* heap,
7402 case CONSTANT_TRANSITION: 7329 AccessorPair* accessors,
7403 return ClearBackPointer(heap, d->GetValue(descriptor_index)); 7330 AccessorComponent component) {
7404 case CALLBACKS: { 7331 Object* component_value = accessors->get(component);
7405 Object* object = d->GetValue(descriptor_index); 7332 if (!component_value->IsMap()) return true;
7406 if (object->IsAccessorPair()) { 7333 if (ClearBackPointer(heap, component_value)) {
7407 bool cleared = true; 7334 accessors->set(component, heap->the_hole_value());
7408 AccessorPair* accessors = AccessorPair::cast(object); 7335 return true;
7409 Object* getter = accessors->getter(); 7336 }
7410 if (getter->IsMap()) { 7337 return false;
7411 if (ClearBackPointer(heap, getter)) { 7338 }
7412 accessors->set_getter(heap->the_hole_value()); 7339
7413 } else { 7340
7414 cleared = false; 7341 static bool ClearNonLiveTransition(Heap* heap,
7415 } 7342 TransitionArray* t,
7416 } else if (!getter->IsTheHole()) { 7343 int transition_index) {
7417 cleared = false; 7344 // If the value is a map, check if the target is live. If not, clear the
7418 } 7345 // transition. Also drop the back pointer for that map transition, so that
7419 Object* setter = accessors->setter(); 7346 // this map is not reached again by following a back pointer from that
7420 if (setter->IsMap()) { 7347 // non-live map.
7421 if (ClearBackPointer(heap, setter)) { 7348 Object* value = t->GetValue(transition_index);
7422 accessors->set_setter(heap->the_hole_value()); 7349 if (value->IsMap()) {
7423 } else { 7350 return ClearBackPointer(heap, t->GetValue(transition_index));
Jakob Kummerow 2012/06/29 16:31:36 nit: indentation is off
Toon Verwaest 2012/07/05 12:56:11 Done.
7424 cleared = false; 7351 } else if (value->IsAccessorPair()) {
7425 } 7352 AccessorPair* accessors = AccessorPair::cast(value);
7426 } else if (!setter->IsTheHole()) { 7353 bool getter = ClearAccessorComponent(heap, accessors, ACCESSOR_GETTER);
7427 cleared = false; 7354 bool setter = ClearAccessorComponent(heap, accessors, ACCESSOR_SETTER);
7428 } 7355 return getter && setter;
Jakob Kummerow 2012/06/29 16:31:36 Shouldn't this be "getter || setter"?
Toon Verwaest 2012/07/05 12:56:11 No. Getter and setter are booleans indicating that
7429 return cleared;
7430 }
7431 return false;
7432 }
7433 case NORMAL:
7434 case FIELD:
7435 case CONSTANT_FUNCTION:
7436 case HANDLER:
7437 case INTERCEPTOR:
7438 return false;
7439 case NONEXISTENT:
7440 break;
7441 } 7356 }
7442 UNREACHABLE(); 7357 UNREACHABLE();
7443 return true; 7358 return true;
7444 } 7359 }
7445 7360
7446 7361
7447 // TODO(mstarzinger): This method should be moved into MarkCompactCollector, 7362 // TODO(mstarzinger): This method should be moved into MarkCompactCollector,
7448 // because it cannot be called from outside the GC and we already have methods 7363 // because it cannot be called from outside the GC and we already have methods
7449 // depending on the transitions layout in the GC anyways. 7364 // depending on the transitions layout in the GC anyways.
7450 void Map::ClearNonLiveTransitions(Heap* heap) { 7365 void Map::ClearNonLiveTransitions(Heap* heap) {
7451 Object* array = *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset); 7366 TransitionArray* t = transitions();
7452 // If there are no descriptors to be cleared, return. 7367 // If there are no transitions to be cleared, return.
7453 // TODO(verwaest) Should be an assert, otherwise back pointers are not 7368 // TODO(verwaest) Should be an assert, otherwise back pointers are not
7454 // properly cleared. 7369 // properly cleared.
7455 if (array->IsSmi()) return; 7370 if (t == NULL) return;
7456 DescriptorArray* d = DescriptorArray::cast(array);
7457 7371
7458 int descriptor_index = 0; 7372 int transition_index = 0;
7373
7459 // Compact all live descriptors to the left. 7374 // Compact all live descriptors to the left.
7460 for (int i = 0; i < d->number_of_descriptors(); ++i) { 7375 for (int i = 0; i < t->number_of_transitions(); ++i) {
7461 if (!ClearNonLiveTransitionsFromDescriptor(heap, d, i)) { 7376 if (!ClearNonLiveTransition(heap, t, i)) {
7462 if (i != descriptor_index) { 7377 if (i != transition_index) {
7463 String* key = d->GetKey(i); 7378 String* key = t->GetKey(i);
7464 Object* value = d->GetValue(i); 7379 Object* value = t->GetValue(i);
7465 d->SetKeyUnchecked(heap, descriptor_index, key); 7380 t->SetKeyUnchecked(heap, transition_index, key);
7466 d->SetDetailsUnchecked(descriptor_index, d->GetDetails(i).AsSmi()); 7381 t->SetValueUnchecked(heap, transition_index, value);
7467 d->SetValueUnchecked(heap, descriptor_index, value);
7468 MarkCompactCollector* collector = heap->mark_compact_collector(); 7382 MarkCompactCollector* collector = heap->mark_compact_collector();
7469 Object** key_slot = d->GetKeySlot(descriptor_index); 7383 Object** key_slot = t->GetKeySlot(transition_index);
7470 collector->RecordSlot(key_slot, key_slot, key); 7384 collector->RecordSlot(key_slot, key_slot, key);
7471 if (value->IsHeapObject()) { 7385 Object** value_slot = t->GetValueSlot(transition_index);
7472 Object** value_slot = d->GetValueSlot(descriptor_index); 7386 collector->RecordSlot(value_slot, value_slot, value);
7473 collector->RecordSlot(value_slot, value_slot, value);
7474 }
7475 } 7387 }
7476 descriptor_index++; 7388 transition_index++;
7477 } 7389 }
7478 } 7390 }
7479 7391
7480 Map* elements_transition = d->elements_transition_map(); 7392 if (t->HasElementsTransition() && ClearBackPointer(heap, t->elements())) {
7481 if (elements_transition != NULL && 7393 t->ClearElements();
7482 ClearBackPointer(heap, elements_transition)) {
7483 elements_transition = NULL;
7484 d->ClearElementsTransition();
7485 } else { 7394 } else {
7486 // If there are no descriptors to be cleared, return. 7395 // If there are no transitions to be cleared, return.
7487 // TODO(verwaest) Should be an assert, otherwise back pointers are not 7396 // TODO(verwaest) Should be an assert, otherwise back pointers are not
7488 // properly cleared. 7397 // properly cleared.
7489 if (descriptor_index == d->number_of_descriptors()) return; 7398 if (transition_index == t->number_of_transitions()) return;
7490 } 7399 }
7491 7400
7492 // If the final descriptor array does not contain any live descriptors, remove 7401 // If the final transition array does not contain any live transitions, remove
7493 // the descriptor array from the map. 7402 // the transition array from the map.
7494 if (descriptor_index == 0 && elements_transition == NULL) { 7403 if (transition_index == 0 && !t->HasElementsTransition()) {
7495 ClearDescriptorArray(); 7404 return ClearTransitions();
7496 return;
7497 } 7405 }
7498 7406
7499 int trim = d->number_of_descriptors() - descriptor_index; 7407 int trim = t->number_of_transitions() - transition_index;
7500 if (trim > 0) { 7408 if (trim > 0) {
7501 RightTrimFixedArray(heap, d, trim * DescriptorArray::kDescriptorSize); 7409 RightTrimFixedArray(heap, t, trim * TransitionArray::kTransitionSize);
7502 } 7410 }
7503 } 7411 }
7504 7412
7505 7413
7506 int Map::Hash() { 7414 int Map::Hash() {
7507 // For performance reasons we only hash the 3 most variable fields of a map: 7415 // For performance reasons we only hash the 3 most variable fields of a map:
7508 // constructor, prototype and bit_field2. 7416 // constructor, prototype and bit_field2.
7509 7417
7510 // Shift away the tag. 7418 // Shift away the tag.
7511 int hash = (static_cast<uint32_t>( 7419 int hash = (static_cast<uint32_t>(
(...skipping 3174 matching lines...) Expand 10 before | Expand all | Expand 10 after
10686 } 10594 }
10687 10595
10688 10596
10689 // Fill in the names of local properties into the supplied storage. The main 10597 // Fill in the names of local properties into the supplied storage. The main
10690 // purpose of this function is to provide reflection information for the object 10598 // purpose of this function is to provide reflection information for the object
10691 // mirrors. 10599 // mirrors.
10692 void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) { 10600 void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
10693 ASSERT(storage->length() >= (NumberOfLocalProperties() - index)); 10601 ASSERT(storage->length() >= (NumberOfLocalProperties() - index));
10694 if (HasFastProperties()) { 10602 if (HasFastProperties()) {
10695 DescriptorArray* descs = map()->instance_descriptors(); 10603 DescriptorArray* descs = map()->instance_descriptors();
10604 ASSERT(storage->length() >= index + descs->number_of_descriptors());
10696 for (int i = 0; i < descs->number_of_descriptors(); i++) { 10605 for (int i = 0; i < descs->number_of_descriptors(); i++) {
10697 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i)); 10606 storage->set(index + i, descs->GetKey(i));
10698 } 10607 }
10699 ASSERT(storage->length() >= index);
10700 } else { 10608 } else {
10701 property_dictionary()->CopyKeysTo(storage, 10609 property_dictionary()->CopyKeysTo(storage,
10702 index, 10610 index,
10703 StringDictionary::UNSORTED); 10611 StringDictionary::UNSORTED);
10704 } 10612 }
10705 } 10613 }
10706 10614
10707 10615
10708 int JSObject::NumberOfLocalElements(PropertyAttributes filter) { 10616 int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
10709 return GetLocalElementKeys(NULL, filter); 10617 return GetLocalElementKeys(NULL, filter);
(...skipping 607 matching lines...) Expand 10 before | Expand all | Expand 10 after
11317 set(index, key); 11225 set(index, key);
11318 return entry; 11226 return entry;
11319 } 11227 }
11320 ASSERT(element->IsTheHole() || !String::cast(element)->Equals(key)); 11228 ASSERT(element->IsTheHole() || !String::cast(element)->Equals(key));
11321 entry = NextProbe(entry, count++, capacity); 11229 entry = NextProbe(entry, count++, capacity);
11322 } 11230 }
11323 return kNotFound; 11231 return kNotFound;
11324 } 11232 }
11325 11233
11326 11234
11327 bool StringDictionary::ContainsTransition(int entry) {
11328 switch (DetailsAt(entry).type()) {
11329 case MAP_TRANSITION:
11330 case CONSTANT_TRANSITION:
11331 return true;
11332 case CALLBACKS: {
11333 Object* value = ValueAt(entry);
11334 if (!value->IsAccessorPair()) return false;
11335 AccessorPair* accessors = AccessorPair::cast(value);
11336 return accessors->getter()->IsMap() || accessors->setter()->IsMap();
11337 }
11338 case NORMAL:
11339 case FIELD:
11340 case CONSTANT_FUNCTION:
11341 case HANDLER:
11342 case INTERCEPTOR:
11343 return false;
11344 case NONEXISTENT:
11345 UNREACHABLE();
11346 break;
11347 }
11348 UNREACHABLE(); // Keep the compiler happy.
11349 return false;
11350 }
11351
11352
11353 template<typename Shape, typename Key> 11235 template<typename Shape, typename Key>
11354 MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) { 11236 MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
11355 ASSERT(NumberOfElements() < new_table->Capacity()); 11237 ASSERT(NumberOfElements() < new_table->Capacity());
11356 11238
11357 AssertNoAllocation no_gc; 11239 AssertNoAllocation no_gc;
11358 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc); 11240 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
11359 11241
11360 // Copy prefix to new array. 11242 // Copy prefix to new array.
11361 for (int i = kPrefixStartIndex; 11243 for (int i = kPrefixStartIndex;
11362 i < kPrefixStartIndex + Shape::kPrefixSize; 11244 i < kPrefixStartIndex + Shape::kPrefixSize;
(...skipping 2014 matching lines...) Expand 10 before | Expand all | Expand 10 after
13377 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); 13259 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
13378 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); 13260 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
13379 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); 13261 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
13380 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); 13262 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
13381 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); 13263 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
13382 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); 13264 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
13383 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); 13265 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
13384 } 13266 }
13385 13267
13386 } } // namespace v8::internal 13268 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698