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

Side by Side Diff: src/objects.cc

Issue 10824042: Use linear backing store for hidden properties to save memory. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 3541 matching lines...) Expand 10 before | Expand all | Expand 10 after
3552 Object* JSObject::GetHiddenProperty(String* key) { 3552 Object* JSObject::GetHiddenProperty(String* key) {
3553 if (IsJSGlobalProxy()) { 3553 if (IsJSGlobalProxy()) {
3554 // For a proxy, use the prototype as target object. 3554 // For a proxy, use the prototype as target object.
3555 Object* proxy_parent = GetPrototype(); 3555 Object* proxy_parent = GetPrototype();
3556 // If the proxy is detached, return undefined. 3556 // If the proxy is detached, return undefined.
3557 if (proxy_parent->IsNull()) return GetHeap()->undefined_value(); 3557 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3558 ASSERT(proxy_parent->IsJSGlobalObject()); 3558 ASSERT(proxy_parent->IsJSGlobalObject());
3559 return JSObject::cast(proxy_parent)->GetHiddenProperty(key); 3559 return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
3560 } 3560 }
3561 ASSERT(!IsJSGlobalProxy()); 3561 ASSERT(!IsJSGlobalProxy());
3562 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false); 3562 MaybeObject* hidden_lookup = GetHiddenPropertiesArray(false);
3563 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg. 3563 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
3564 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) { 3564 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) {
3565 return GetHeap()->undefined_value(); 3565 return GetHeap()->undefined_value();
3566 } 3566 }
3567 StringDictionary* dictionary = 3567 HiddenPropertiesArray* hidden_properties =
3568 StringDictionary::cast(hidden_lookup->ToObjectUnchecked()); 3568 HiddenPropertiesArray::cast(hidden_lookup->ToObjectUnchecked());
3569 int entry = dictionary->FindEntry(key); 3569 return hidden_properties->Get(key);
3570 if (entry == StringDictionary::kNotFound) return GetHeap()->undefined_value();
3571 return dictionary->ValueAt(entry);
3572 } 3570 }
3573 3571
3574 3572
3575 Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj, 3573 Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj,
3576 Handle<String> key, 3574 Handle<String> key,
3577 Handle<Object> value) { 3575 Handle<Object> value) {
3578 CALL_HEAP_FUNCTION(obj->GetIsolate(), 3576 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3579 obj->SetHiddenProperty(*key, *value), 3577 obj->SetHiddenProperty(*key, *value),
3580 Object); 3578 Object);
3581 } 3579 }
3582 3580
3583 3581
3584 MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) { 3582 MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) {
3585 if (IsJSGlobalProxy()) { 3583 if (IsJSGlobalProxy()) {
3586 // For a proxy, use the prototype as target object. 3584 // For a proxy, use the prototype as target object.
3587 Object* proxy_parent = GetPrototype(); 3585 Object* proxy_parent = GetPrototype();
3588 // If the proxy is detached, return undefined. 3586 // If the proxy is detached, return undefined.
3589 if (proxy_parent->IsNull()) return GetHeap()->undefined_value(); 3587 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3590 ASSERT(proxy_parent->IsJSGlobalObject()); 3588 ASSERT(proxy_parent->IsJSGlobalObject());
3591 return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value); 3589 return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value);
3592 } 3590 }
3593 ASSERT(!IsJSGlobalProxy()); 3591 ASSERT(!IsJSGlobalProxy());
3594 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(true);
3595 StringDictionary* dictionary;
3596 if (!hidden_lookup->To<StringDictionary>(&dictionary)) return hidden_lookup;
3597 3592
3598 // If it was found, check if the key is already in the dictionary. 3593 HiddenPropertiesArray* hidden_properties;
3599 int entry = dictionary->FindEntry(key); 3594 { MaybeObject* maybe_obj = GetHiddenPropertiesArray(true);
3600 if (entry != StringDictionary::kNotFound) { 3595 if (!maybe_obj->To<HiddenPropertiesArray>(&hidden_properties)) {
3601 // If key was found, just update the value. 3596 return maybe_obj;
3602 dictionary->ValueAtPut(entry, value); 3597 }
3603 return this;
3604 } 3598 }
3605 // Key was not already in the dictionary, so add the entry. 3599
3606 MaybeObject* insert_result = dictionary->Add(key, 3600 HiddenPropertiesArray* new_hidden_properties;
3607 value, 3601 MaybeObject* store_result = hidden_properties->Set(key, value);
3608 PropertyDetails(NONE, NORMAL)); 3602 if (!store_result->To<HiddenPropertiesArray>(&new_hidden_properties)) {
3609 StringDictionary* new_dict; 3603 return store_result;
3610 if (!insert_result->To<StringDictionary>(&new_dict)) return insert_result; 3604 }
3611 if (new_dict != dictionary) { 3605
3612 // If adding the key expanded the dictionary (i.e., Add returned a new 3606 if (new_hidden_properties != hidden_properties) {
3613 // dictionary), store it back to the object. 3607 // Update the object if the backing store has been re-allocated.
3614 MaybeObject* store_result = SetHiddenPropertiesDictionary(new_dict); 3608 MaybeObject* maybe_obj = SetHiddenPropertiesArray(
3615 if (store_result->IsFailure()) return store_result; 3609 new_hidden_properties);
3610 if (maybe_obj->IsFailure()) return maybe_obj;
3616 } 3611 }
3617 // Return this to mark success. 3612 // Return this to mark success.
3618 return this; 3613 return this;
3619 } 3614 }
3620 3615
3621 3616
3622 void JSObject::DeleteHiddenProperty(String* key) { 3617 void JSObject::DeleteHiddenProperty(String* key) {
3623 if (IsJSGlobalProxy()) { 3618 if (IsJSGlobalProxy()) {
3624 // For a proxy, use the prototype as target object. 3619 // For a proxy, use the prototype as target object.
3625 Object* proxy_parent = GetPrototype(); 3620 Object* proxy_parent = GetPrototype();
3626 // If the proxy is detached, return immediately. 3621 // If the proxy is detached, return immediately.
3627 if (proxy_parent->IsNull()) return; 3622 if (proxy_parent->IsNull()) return;
3628 ASSERT(proxy_parent->IsJSGlobalObject()); 3623 ASSERT(proxy_parent->IsJSGlobalObject());
3629 JSObject::cast(proxy_parent)->DeleteHiddenProperty(key); 3624 JSObject::cast(proxy_parent)->DeleteHiddenProperty(key);
3630 return; 3625 return;
3631 } 3626 }
3632 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false); 3627 MaybeObject* hidden_lookup = GetHiddenPropertiesArray(false);
3633 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg. 3628 ASSERT(!hidden_lookup->IsFailure());
3634 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return; 3629 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return;
3635 StringDictionary* dictionary = 3630 HiddenPropertiesArray* hidden_properties =
3636 StringDictionary::cast(hidden_lookup->ToObjectUnchecked()); 3631 HiddenPropertiesArray::cast(hidden_lookup->ToObjectUnchecked());
3637 int entry = dictionary->FindEntry(key); 3632 hidden_properties->Delete(key);
3638 if (entry == StringDictionary::kNotFound) {
3639 // Key wasn't in dictionary. Deletion is a success.
3640 return;
3641 }
3642 // Key was in the dictionary. Remove it.
3643 dictionary->DeleteProperty(entry, JSReceiver::FORCE_DELETION);
3644 } 3633 }
3645 3634
3646 3635
3647 bool JSObject::HasHiddenProperties() { 3636 bool JSObject::HasHiddenProperties() {
3648 return GetPropertyAttributePostInterceptor(this, 3637 return GetPropertyAttributePostInterceptor(this,
3649 GetHeap()->hidden_symbol(), 3638 GetHeap()->hidden_symbol(),
3650 false) != ABSENT; 3639 false) != ABSENT;
3651 } 3640 }
3652 3641
3653 3642
3654 MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) { 3643 MaybeObject* JSObject::GetHiddenPropertiesArray(bool create_if_absent) {
3655 ASSERT(!IsJSGlobalProxy()); 3644 ASSERT(!IsJSGlobalProxy());
3656 if (HasFastProperties()) { 3645 if (HasFastProperties()) {
3657 // If the object has fast properties, check whether the first slot 3646 // If the object has fast properties, check whether the first slot
3658 // in the descriptor array matches the hidden symbol. Since the 3647 // in the descriptor array matches the hidden symbol. Since the
3659 // hidden symbols hash code is zero (and no other string has hash 3648 // hidden symbols hash code is zero (and no other string has hash
3660 // code zero) it will always occupy the first entry if present. 3649 // code zero) it will always occupy the first entry if present.
3661 DescriptorArray* descriptors = this->map()->instance_descriptors(); 3650 DescriptorArray* descriptors = this->map()->instance_descriptors();
3662 if ((descriptors->number_of_descriptors() > 0) && 3651 if ((descriptors->number_of_descriptors() > 0) &&
3663 (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) { 3652 (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
3664 ASSERT(descriptors->GetType(0) == FIELD); 3653 ASSERT(descriptors->GetType(0) == FIELD);
3665 Object* hidden_store = 3654 Object* hidden_properties =
3666 this->FastPropertyAt(descriptors->GetFieldIndex(0)); 3655 this->FastPropertyAt(descriptors->GetFieldIndex(0));
3667 return StringDictionary::cast(hidden_store); 3656 return HiddenPropertiesArray::cast(hidden_properties);
3668 } 3657 }
3669 } else { 3658 } else {
3670 PropertyAttributes attributes; 3659 PropertyAttributes attributes;
3671 // You can't install a getter on a property indexed by the hidden symbol, 3660 // You can't install a getter on a property indexed by the hidden symbol,
3672 // so we can be sure that GetLocalPropertyPostInterceptor returns a real 3661 // so we can be sure that GetLocalPropertyPostInterceptor returns a real
3673 // object. 3662 // object.
3674 Object* lookup = 3663 Object* lookup =
3675 GetLocalPropertyPostInterceptor(this, 3664 GetLocalPropertyPostInterceptor(this,
3676 GetHeap()->hidden_symbol(), 3665 GetHeap()->hidden_symbol(),
3677 &attributes)->ToObjectUnchecked(); 3666 &attributes)->ToObjectUnchecked();
3678 if (!lookup->IsUndefined()) { 3667 if (!lookup->IsUndefined()) {
3679 return StringDictionary::cast(lookup); 3668 return HiddenPropertiesArray::cast(lookup);
3680 } 3669 }
3681 } 3670 }
3682 if (!create_if_absent) return GetHeap()->undefined_value(); 3671 if (!create_if_absent) return GetHeap()->undefined_value();
3683 const int kInitialSize = 5; 3672
3684 MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize); 3673 HiddenPropertiesArray* hidden_properties;
3685 StringDictionary* dictionary; 3674 { MaybeObject* maybe_obj = HiddenPropertiesArray::Allocate();
3686 if (!dict_alloc->To<StringDictionary>(&dictionary)) return dict_alloc; 3675 if (!maybe_obj->To<HiddenPropertiesArray>(&hidden_properties)) {
3676 return maybe_obj;
3677 }
3678 }
3679
3687 MaybeObject* store_result = 3680 MaybeObject* store_result =
3688 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(), 3681 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3689 dictionary, 3682 hidden_properties,
3690 DONT_ENUM, 3683 DONT_ENUM,
3691 kNonStrictMode, 3684 kNonStrictMode,
3692 OMIT_EXTENSIBILITY_CHECK); 3685 OMIT_EXTENSIBILITY_CHECK);
3693 if (store_result->IsFailure()) return store_result; 3686 if (store_result->IsFailure()) return store_result;
3694 return dictionary; 3687 return hidden_properties;
3695 } 3688 }
3696 3689
3697 3690
3698 MaybeObject* JSObject::SetHiddenPropertiesDictionary( 3691 MaybeObject* JSObject::SetHiddenPropertiesArray(
3699 StringDictionary* dictionary) { 3692 HiddenPropertiesArray* hidden_properties) {
3700 ASSERT(!IsJSGlobalProxy()); 3693 ASSERT(!IsJSGlobalProxy());
3701 ASSERT(HasHiddenProperties()); 3694 ASSERT(HasHiddenProperties());
3702 if (HasFastProperties()) { 3695 if (HasFastProperties()) {
3703 // If the object has fast properties, check whether the first slot 3696 // If the object has fast properties, check whether the first slot
3704 // in the descriptor array matches the hidden symbol. Since the 3697 // in the descriptor array matches the hidden symbol. Since the
3705 // hidden symbols hash code is zero (and no other string has hash 3698 // hidden symbols hash code is zero (and no other string has hash
3706 // code zero) it will always occupy the first entry if present. 3699 // code zero) it will always occupy the first entry if present.
3707 DescriptorArray* descriptors = this->map()->instance_descriptors(); 3700 DescriptorArray* descriptors = this->map()->instance_descriptors();
3708 if ((descriptors->number_of_descriptors() > 0) && 3701 if ((descriptors->number_of_descriptors() > 0) &&
3709 (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) { 3702 (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
3710 ASSERT(descriptors->GetType(0) == FIELD); 3703 ASSERT(descriptors->GetType(0) == FIELD);
3711 this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary); 3704 this->FastPropertyAtPut(descriptors->GetFieldIndex(0), hidden_properties);
3712 return this; 3705 return this;
3713 } 3706 }
3714 } 3707 }
3715 MaybeObject* store_result = 3708 MaybeObject* store_result =
3716 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(), 3709 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3717 dictionary, 3710 hidden_properties,
3718 DONT_ENUM, 3711 DONT_ENUM,
3719 kNonStrictMode, 3712 kNonStrictMode,
3720 OMIT_EXTENSIBILITY_CHECK); 3713 OMIT_EXTENSIBILITY_CHECK);
3721 if (store_result->IsFailure()) return store_result; 3714 if (store_result->IsFailure()) return store_result;
3722 return this; 3715 return this;
3723 } 3716 }
3724 3717
3725 3718
3726 MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name, 3719 MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
3727 DeleteMode mode) { 3720 DeleteMode mode) {
(...skipping 9397 matching lines...) Expand 10 before | Expand all | Expand 10 after
13125 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); 13118 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
13126 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); 13119 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
13127 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); 13120 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
13128 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); 13121 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
13129 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); 13122 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
13130 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); 13123 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
13131 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); 13124 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
13132 } 13125 }
13133 13126
13134 } } // namespace v8::internal 13127 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698