Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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(©)) return maybe_copy; | 6039 if (!maybe_copy->To(©)) 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |