OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 1010 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1021 return context->symbol_function()->instance_prototype(); | 1021 return context->symbol_function()->instance_prototype(); |
1022 } | 1022 } |
1023 if (heap_object->IsBoolean()) { | 1023 if (heap_object->IsBoolean()) { |
1024 return context->boolean_function()->instance_prototype(); | 1024 return context->boolean_function()->instance_prototype(); |
1025 } else { | 1025 } else { |
1026 return isolate->heap()->null_value(); | 1026 return isolate->heap()->null_value(); |
1027 } | 1027 } |
1028 } | 1028 } |
1029 | 1029 |
1030 | 1030 |
1031 MaybeObject* Object::GetHash(CreationFlag flag) { | 1031 Object* Object::GetHash() { |
1032 // The object is either a number, a name, an odd-ball, | 1032 // The object is either a number, a name, an odd-ball, |
1033 // a real JS object, or a Harmony proxy. | 1033 // a real JS object, or a Harmony proxy. |
1034 if (IsNumber()) { | 1034 if (IsNumber()) { |
1035 uint32_t hash = ComputeLongHash(double_to_uint64(Number())); | 1035 uint32_t hash = ComputeLongHash(double_to_uint64(Number())); |
1036 return Smi::FromInt(hash & Smi::kMaxValue); | 1036 return Smi::FromInt(hash & Smi::kMaxValue); |
1037 } | 1037 } |
1038 if (IsName()) { | 1038 if (IsName()) { |
1039 uint32_t hash = Name::cast(this)->Hash(); | 1039 uint32_t hash = Name::cast(this)->Hash(); |
1040 return Smi::FromInt(hash); | 1040 return Smi::FromInt(hash); |
1041 } | 1041 } |
1042 if (IsOddball()) { | 1042 if (IsOddball()) { |
1043 uint32_t hash = Oddball::cast(this)->to_string()->Hash(); | 1043 uint32_t hash = Oddball::cast(this)->to_string()->Hash(); |
1044 return Smi::FromInt(hash); | 1044 return Smi::FromInt(hash); |
1045 } | 1045 } |
1046 if (IsJSReceiver()) { | |
1047 return JSReceiver::cast(this)->GetIdentityHash(flag); | |
1048 } | |
1049 | 1046 |
1050 UNREACHABLE(); | 1047 ASSERT(IsJSReceiver()); |
1051 return Smi::FromInt(0); | 1048 return JSReceiver::cast(this)->GetIdentityHash(); |
1052 } | 1049 } |
1053 | 1050 |
1054 | 1051 |
| 1052 Handle<Object> Object::GetOrCreateHash(Handle<Object> object, |
| 1053 Isolate* isolate) { |
| 1054 Handle<Object> hash(object->GetHash(), isolate); |
| 1055 if (hash->IsSmi()) |
| 1056 return hash; |
| 1057 |
| 1058 ASSERT(object->IsJSReceiver()); |
| 1059 return JSReceiver::GetOrCreateIdentityHash(Handle<JSReceiver>::cast(object)); |
| 1060 } |
| 1061 |
| 1062 |
1055 bool Object::SameValue(Object* other) { | 1063 bool Object::SameValue(Object* other) { |
1056 if (other == this) return true; | 1064 if (other == this) return true; |
1057 | 1065 |
1058 // The object is either a number, a name, an odd-ball, | 1066 // The object is either a number, a name, an odd-ball, |
1059 // a real JS object, or a Harmony proxy. | 1067 // a real JS object, or a Harmony proxy. |
1060 if (IsNumber() && other->IsNumber()) { | 1068 if (IsNumber() && other->IsNumber()) { |
1061 double this_value = Number(); | 1069 double this_value = Number(); |
1062 double other_value = other->Number(); | 1070 double other_value = other->Number(); |
1063 bool equal = this_value == other_value; | 1071 bool equal = this_value == other_value; |
1064 // SameValue(NaN, NaN) is true. | 1072 // SameValue(NaN, NaN) is true. |
(...skipping 2683 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3748 Handle<JSReceiver> receiver(receiver_raw); | 3756 Handle<JSReceiver> receiver(receiver_raw); |
3749 Handle<String> name = isolate->factory()->Uint32ToString(index); | 3757 Handle<String> name = isolate->factory()->Uint32ToString(index); |
3750 return proxy->GetPropertyAttributeWithHandler(*receiver, *name); | 3758 return proxy->GetPropertyAttributeWithHandler(*receiver, *name); |
3751 } | 3759 } |
3752 | 3760 |
3753 | 3761 |
3754 void JSProxy::Fix(Handle<JSProxy> proxy) { | 3762 void JSProxy::Fix(Handle<JSProxy> proxy) { |
3755 Isolate* isolate = proxy->GetIsolate(); | 3763 Isolate* isolate = proxy->GetIsolate(); |
3756 | 3764 |
3757 // Save identity hash. | 3765 // Save identity hash. |
3758 Handle<Object> hash = JSProxy::GetIdentityHash(proxy, OMIT_CREATION); | 3766 Handle<Object> hash(proxy->GetIdentityHash(), isolate); |
3759 | 3767 |
3760 if (proxy->IsJSFunctionProxy()) { | 3768 if (proxy->IsJSFunctionProxy()) { |
3761 isolate->factory()->BecomeJSFunction(proxy); | 3769 isolate->factory()->BecomeJSFunction(proxy); |
3762 // Code will be set on the JavaScript side. | 3770 // Code will be set on the JavaScript side. |
3763 } else { | 3771 } else { |
3764 isolate->factory()->BecomeJSObject(proxy); | 3772 isolate->factory()->BecomeJSObject(proxy); |
3765 } | 3773 } |
3766 ASSERT(proxy->IsJSObject()); | 3774 ASSERT(proxy->IsJSObject()); |
3767 | 3775 |
3768 // Inherit identity, if it was present. | 3776 // Inherit identity, if it was present. |
3769 if (hash->IsSmi()) { | 3777 if (hash->IsSmi()) { |
3770 JSObject::SetIdentityHash(Handle<JSObject>::cast(proxy), Smi::cast(*hash)); | 3778 JSObject::SetIdentityHash(Handle<JSObject>::cast(proxy), |
| 3779 Handle<Smi>::cast(hash)); |
3771 } | 3780 } |
3772 } | 3781 } |
3773 | 3782 |
3774 | 3783 |
3775 MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name, | 3784 MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name, |
3776 Handle<Object> derived, | 3785 Handle<Object> derived, |
3777 int argc, | 3786 int argc, |
3778 Handle<Object> argv[]) { | 3787 Handle<Object> argv[]) { |
3779 Isolate* isolate = GetIsolate(); | 3788 Isolate* isolate = GetIsolate(); |
3780 Handle<Object> handler(this->handler(), isolate); | 3789 Handle<Object> handler(this->handler(), isolate); |
(...skipping 1000 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4781 // within a smi. | 4790 // within a smi. |
4782 hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue; | 4791 hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue; |
4783 attempts++; | 4792 attempts++; |
4784 } while (hash_value == 0 && attempts < 30); | 4793 } while (hash_value == 0 && attempts < 30); |
4785 hash_value = hash_value != 0 ? hash_value : 1; // never return 0 | 4794 hash_value = hash_value != 0 ? hash_value : 1; // never return 0 |
4786 | 4795 |
4787 return Smi::FromInt(hash_value); | 4796 return Smi::FromInt(hash_value); |
4788 } | 4797 } |
4789 | 4798 |
4790 | 4799 |
4791 void JSObject::SetIdentityHash(Handle<JSObject> object, Smi* hash) { | 4800 void JSObject::SetIdentityHash(Handle<JSObject> object, Handle<Smi> hash) { |
4792 CALL_HEAP_FUNCTION_VOID(object->GetIsolate(), | 4801 Isolate* isolate = object->GetIsolate(); |
4793 object->SetHiddenProperty( | 4802 SetHiddenProperty(object, isolate->factory()->identity_hash_string(), hash); |
4794 object->GetHeap()->identity_hash_string(), hash)); | |
4795 } | 4803 } |
4796 | 4804 |
4797 | 4805 |
4798 int JSObject::GetIdentityHash(Handle<JSObject> object) { | 4806 Object* JSObject::GetIdentityHash() { |
4799 CALL_AND_RETRY_OR_DIE(object->GetIsolate(), | 4807 Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_string()); |
4800 object->GetIdentityHash(ALLOW_CREATION), | 4808 return stored_value->IsSmi() ? stored_value : GetHeap()->undefined_value(); |
4801 return Smi::cast(__object__)->value(), | |
4802 return 0); | |
4803 } | 4809 } |
4804 | 4810 |
4805 | 4811 |
4806 MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) { | 4812 Handle<Object> JSObject::GetOrCreateIdentityHash(Handle<JSObject> object) { |
4807 Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_string()); | 4813 Handle<Object> hash(object->GetIdentityHash(), object->GetIsolate()); |
4808 if (stored_value->IsSmi()) return stored_value; | 4814 if (hash->IsSmi()) |
| 4815 return hash; |
4809 | 4816 |
4810 // Do not generate permanent identity hash code if not requested. | 4817 Isolate* isolate = object->GetIsolate(); |
4811 if (flag == OMIT_CREATION) return GetHeap()->undefined_value(); | |
4812 | 4818 |
4813 Smi* hash = GenerateIdentityHash(); | 4819 hash = handle(object->GenerateIdentityHash(), isolate); |
4814 MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_string(), | 4820 Handle<Object> result = SetHiddenProperty(object, |
4815 hash); | 4821 isolate->factory()->identity_hash_string(), hash); |
4816 if (result->IsFailure()) return result; | 4822 |
4817 if (result->ToObjectUnchecked()->IsUndefined()) { | 4823 if (result->IsUndefined()) { |
4818 // Trying to get hash of detached proxy. | 4824 // Trying to get hash of detached proxy. |
4819 return Smi::FromInt(0); | 4825 return handle(Smi::FromInt(0), isolate); |
4820 } | 4826 } |
| 4827 |
4821 return hash; | 4828 return hash; |
4822 } | 4829 } |
4823 | 4830 |
4824 | 4831 |
4825 Handle<Object> JSProxy::GetIdentityHash(Handle<JSProxy> proxy, | 4832 Object* JSProxy::GetIdentityHash() { |
4826 CreationFlag flag) { | 4833 return this->hash(); |
4827 CALL_HEAP_FUNCTION(proxy->GetIsolate(), proxy->GetIdentityHash(flag), Object); | |
4828 } | 4834 } |
4829 | 4835 |
4830 | 4836 |
4831 MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) { | 4837 Handle<Object> JSProxy::GetOrCreateIdentityHash(Handle<JSProxy> proxy) { |
4832 Object* hash = this->hash(); | 4838 Isolate* isolate = proxy->GetIsolate(); |
4833 if (!hash->IsSmi() && flag == ALLOW_CREATION) { | 4839 |
4834 hash = GenerateIdentityHash(); | 4840 Handle<Object> hash(proxy->GetIdentityHash(), isolate); |
4835 set_hash(hash); | 4841 if (hash->IsSmi()) |
4836 } | 4842 return hash; |
| 4843 |
| 4844 hash = handle(proxy->GenerateIdentityHash(), isolate); |
| 4845 proxy->set_hash(*hash); |
4837 return hash; | 4846 return hash; |
4838 } | 4847 } |
4839 | 4848 |
4840 | 4849 |
4841 Object* JSObject::GetHiddenProperty(Name* key) { | 4850 Object* JSObject::GetHiddenProperty(Name* key) { |
4842 ASSERT(key->IsUniqueName()); | 4851 ASSERT(key->IsUniqueName()); |
4843 if (IsJSGlobalProxy()) { | 4852 if (IsJSGlobalProxy()) { |
4844 // For a proxy, use the prototype as target object. | 4853 // For a proxy, use the prototype as target object. |
4845 Object* proxy_parent = GetPrototype(); | 4854 Object* proxy_parent = GetPrototype(); |
4846 // If the proxy is detached, return undefined. | 4855 // If the proxy is detached, return undefined. |
4847 if (proxy_parent->IsNull()) return GetHeap()->the_hole_value(); | 4856 if (proxy_parent->IsNull()) return GetHeap()->the_hole_value(); |
4848 ASSERT(proxy_parent->IsJSGlobalObject()); | 4857 ASSERT(proxy_parent->IsJSGlobalObject()); |
4849 return JSObject::cast(proxy_parent)->GetHiddenProperty(key); | 4858 return JSObject::cast(proxy_parent)->GetHiddenProperty(key); |
4850 } | 4859 } |
4851 ASSERT(!IsJSGlobalProxy()); | 4860 ASSERT(!IsJSGlobalProxy()); |
4852 MaybeObject* hidden_lookup = | 4861 Object* inline_value = GetHiddenPropertiesHashTable(); |
4853 GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE); | |
4854 Object* inline_value = hidden_lookup->ToObjectUnchecked(); | |
4855 | 4862 |
4856 if (inline_value->IsSmi()) { | 4863 if (inline_value->IsSmi()) { |
4857 // Handle inline-stored identity hash. | 4864 // Handle inline-stored identity hash. |
4858 if (key == GetHeap()->identity_hash_string()) { | 4865 if (key == GetHeap()->identity_hash_string()) { |
4859 return inline_value; | 4866 return inline_value; |
4860 } else { | 4867 } else { |
4861 return GetHeap()->the_hole_value(); | 4868 return GetHeap()->the_hole_value(); |
4862 } | 4869 } |
4863 } | 4870 } |
4864 | 4871 |
4865 if (inline_value->IsUndefined()) return GetHeap()->the_hole_value(); | 4872 if (inline_value->IsUndefined()) return GetHeap()->the_hole_value(); |
4866 | 4873 |
4867 ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value); | 4874 ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value); |
4868 Object* entry = hashtable->Lookup(key); | 4875 Object* entry = hashtable->Lookup(key); |
4869 return entry; | 4876 return entry; |
4870 } | 4877 } |
4871 | 4878 |
4872 | 4879 |
4873 Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj, | 4880 Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> object, |
4874 Handle<Name> key, | 4881 Handle<Name> key, |
4875 Handle<Object> value) { | 4882 Handle<Object> value) { |
4876 CALL_HEAP_FUNCTION(obj->GetIsolate(), | 4883 Isolate* isolate = object->GetIsolate(); |
4877 obj->SetHiddenProperty(*key, *value), | 4884 |
4878 Object); | 4885 ASSERT(key->IsUniqueName()); |
| 4886 if (object->IsJSGlobalProxy()) { |
| 4887 // For a proxy, use the prototype as target object. |
| 4888 Handle<Object> proxy_parent(object->GetPrototype(), isolate); |
| 4889 // If the proxy is detached, return undefined. |
| 4890 if (proxy_parent->IsNull()) return isolate->factory()->undefined_value(); |
| 4891 ASSERT(proxy_parent->IsJSGlobalObject()); |
| 4892 return SetHiddenProperty(Handle<JSObject>::cast(proxy_parent), key, value); |
| 4893 } |
| 4894 ASSERT(!object->IsJSGlobalProxy()); |
| 4895 |
| 4896 Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate); |
| 4897 |
| 4898 // If there is no backing store yet, store the identity hash inline. |
| 4899 if (value->IsSmi() && |
| 4900 *key == *isolate->factory()->identity_hash_string() && |
| 4901 (inline_value->IsUndefined() || inline_value->IsSmi())) { |
| 4902 return JSObject::SetHiddenPropertiesHashTable(object, value); |
| 4903 } |
| 4904 |
| 4905 Handle<ObjectHashTable> hashtable = |
| 4906 GetOrCreateHiddenPropertiesHashtable(object); |
| 4907 |
| 4908 // If it was found, check if the key is already in the dictionary. |
| 4909 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(hashtable, key, |
| 4910 value); |
| 4911 if (*new_table != *hashtable) { |
| 4912 // If adding the key expanded the dictionary (i.e., Add returned a new |
| 4913 // dictionary), store it back to the object. |
| 4914 SetHiddenPropertiesHashTable(object, new_table); |
| 4915 } |
| 4916 |
| 4917 // Return this to mark success. |
| 4918 return object; |
4879 } | 4919 } |
4880 | 4920 |
4881 | 4921 |
4882 MaybeObject* JSObject::SetHiddenProperty(Name* key, Object* value) { | |
4883 ASSERT(key->IsUniqueName()); | |
4884 if (IsJSGlobalProxy()) { | |
4885 // For a proxy, use the prototype as target object. | |
4886 Object* proxy_parent = GetPrototype(); | |
4887 // If the proxy is detached, return undefined. | |
4888 if (proxy_parent->IsNull()) return GetHeap()->undefined_value(); | |
4889 ASSERT(proxy_parent->IsJSGlobalObject()); | |
4890 return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value); | |
4891 } | |
4892 ASSERT(!IsJSGlobalProxy()); | |
4893 MaybeObject* hidden_lookup = | |
4894 GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE); | |
4895 Object* inline_value = hidden_lookup->ToObjectUnchecked(); | |
4896 | |
4897 // If there is no backing store yet, store the identity hash inline. | |
4898 if (value->IsSmi() && | |
4899 key == GetHeap()->identity_hash_string() && | |
4900 (inline_value->IsUndefined() || inline_value->IsSmi())) { | |
4901 return SetHiddenPropertiesHashTable(value); | |
4902 } | |
4903 | |
4904 hidden_lookup = GetHiddenPropertiesHashTable(CREATE_NEW_IF_ABSENT); | |
4905 ObjectHashTable* hashtable; | |
4906 if (!hidden_lookup->To(&hashtable)) return hidden_lookup; | |
4907 | |
4908 // If it was found, check if the key is already in the dictionary. | |
4909 MaybeObject* insert_result = hashtable->Put(key, value); | |
4910 ObjectHashTable* new_table; | |
4911 if (!insert_result->To(&new_table)) return insert_result; | |
4912 if (new_table != hashtable) { | |
4913 // If adding the key expanded the dictionary (i.e., Add returned a new | |
4914 // dictionary), store it back to the object. | |
4915 MaybeObject* store_result = SetHiddenPropertiesHashTable(new_table); | |
4916 if (store_result->IsFailure()) return store_result; | |
4917 } | |
4918 // Return this to mark success. | |
4919 return this; | |
4920 } | |
4921 | |
4922 | |
4923 void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) { | 4922 void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) { |
4924 Isolate* isolate = object->GetIsolate(); | 4923 Isolate* isolate = object->GetIsolate(); |
4925 ASSERT(key->IsUniqueName()); | 4924 ASSERT(key->IsUniqueName()); |
4926 | 4925 |
4927 if (object->IsJSGlobalProxy()) { | 4926 if (object->IsJSGlobalProxy()) { |
4928 Handle<Object> proto(object->GetPrototype(), isolate); | 4927 Handle<Object> proto(object->GetPrototype(), isolate); |
4929 if (proto->IsNull()) return; | 4928 if (proto->IsNull()) return; |
4930 ASSERT(proto->IsJSGlobalObject()); | 4929 ASSERT(proto->IsJSGlobalObject()); |
4931 return DeleteHiddenProperty(Handle<JSObject>::cast(proto), key); | 4930 return DeleteHiddenProperty(Handle<JSObject>::cast(proto), key); |
4932 } | 4931 } |
4933 | 4932 |
4934 MaybeObject* hidden_lookup = | 4933 Object* inline_value = object->GetHiddenPropertiesHashTable(); |
4935 object->GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE); | |
4936 Object* inline_value = hidden_lookup->ToObjectUnchecked(); | |
4937 | 4934 |
4938 // We never delete (inline-stored) identity hashes. | 4935 // We never delete (inline-stored) identity hashes. |
4939 ASSERT(*key != isolate->heap()->identity_hash_string()); | 4936 ASSERT(*key != *isolate->factory()->identity_hash_string()); |
4940 if (inline_value->IsUndefined() || inline_value->IsSmi()) return; | 4937 if (inline_value->IsUndefined() || inline_value->IsSmi()) return; |
4941 | 4938 |
4942 Handle<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value)); | 4939 Handle<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value)); |
4943 PutIntoObjectHashTable(hashtable, key, isolate->factory()->the_hole_value()); | 4940 ObjectHashTable::Put(hashtable, key, isolate->factory()->the_hole_value()); |
4944 } | 4941 } |
4945 | 4942 |
4946 | 4943 |
4947 bool JSObject::HasHiddenProperties() { | 4944 bool JSObject::HasHiddenProperties() { |
4948 return GetPropertyAttributePostInterceptor(this, | 4945 return GetPropertyAttributePostInterceptor(this, |
4949 GetHeap()->hidden_string(), | 4946 GetHeap()->hidden_string(), |
4950 false) != ABSENT; | 4947 false) != ABSENT; |
4951 } | 4948 } |
4952 | 4949 |
4953 | 4950 |
4954 MaybeObject* JSObject::GetHiddenPropertiesHashTable( | 4951 Object* JSObject::GetHiddenPropertiesHashTable() { |
4955 InitializeHiddenProperties init_option) { | |
4956 ASSERT(!IsJSGlobalProxy()); | 4952 ASSERT(!IsJSGlobalProxy()); |
4957 Object* inline_value; | |
4958 if (HasFastProperties()) { | 4953 if (HasFastProperties()) { |
4959 // If the object has fast properties, check whether the first slot | 4954 // If the object has fast properties, check whether the first slot |
4960 // in the descriptor array matches the hidden string. Since the | 4955 // in the descriptor array matches the hidden string. Since the |
4961 // hidden strings hash code is zero (and no other name has hash | 4956 // hidden strings hash code is zero (and no other name has hash |
4962 // code zero) it will always occupy the first entry if present. | 4957 // code zero) it will always occupy the first entry if present. |
4963 DescriptorArray* descriptors = this->map()->instance_descriptors(); | 4958 DescriptorArray* descriptors = this->map()->instance_descriptors(); |
4964 if (descriptors->number_of_descriptors() > 0) { | 4959 if (descriptors->number_of_descriptors() > 0) { |
4965 int sorted_index = descriptors->GetSortedKeyIndex(0); | 4960 int sorted_index = descriptors->GetSortedKeyIndex(0); |
4966 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() && | 4961 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() && |
4967 sorted_index < map()->NumberOfOwnDescriptors()) { | 4962 sorted_index < map()->NumberOfOwnDescriptors()) { |
4968 ASSERT(descriptors->GetType(sorted_index) == FIELD); | 4963 ASSERT(descriptors->GetType(sorted_index) == FIELD); |
4969 ASSERT(descriptors->GetDetails(sorted_index).representation(). | 4964 ASSERT(descriptors->GetDetails(sorted_index).representation(). |
4970 IsCompatibleForLoad(Representation::Tagged())); | 4965 IsCompatibleForLoad(Representation::Tagged())); |
4971 inline_value = this->RawFastPropertyAt( | 4966 return this->RawFastPropertyAt( |
4972 descriptors->GetFieldIndex(sorted_index)); | 4967 descriptors->GetFieldIndex(sorted_index)); |
4973 } else { | 4968 } else { |
4974 inline_value = GetHeap()->undefined_value(); | 4969 return GetHeap()->undefined_value(); |
4975 } | 4970 } |
4976 } else { | 4971 } else { |
4977 inline_value = GetHeap()->undefined_value(); | 4972 return GetHeap()->undefined_value(); |
4978 } | 4973 } |
4979 } else { | 4974 } else { |
4980 PropertyAttributes attributes; | 4975 PropertyAttributes attributes; |
4981 // You can't install a getter on a property indexed by the hidden string, | 4976 // You can't install a getter on a property indexed by the hidden string, |
4982 // so we can be sure that GetLocalPropertyPostInterceptor returns a real | 4977 // so we can be sure that GetLocalPropertyPostInterceptor returns a real |
4983 // object. | 4978 // object. |
4984 inline_value = | 4979 return GetLocalPropertyPostInterceptor(this, |
4985 GetLocalPropertyPostInterceptor(this, | 4980 GetHeap()->hidden_string(), |
4986 GetHeap()->hidden_string(), | 4981 &attributes)->ToObjectUnchecked(); |
4987 &attributes)->ToObjectUnchecked(); | 4982 } |
| 4983 } |
| 4984 |
| 4985 Handle<ObjectHashTable> JSObject::GetOrCreateHiddenPropertiesHashtable( |
| 4986 Handle<JSObject> object) { |
| 4987 Isolate* isolate = object->GetIsolate(); |
| 4988 |
| 4989 static const int kInitialCapacity = 4; |
| 4990 Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate); |
| 4991 if (inline_value->IsHashTable()) { |
| 4992 return Handle<ObjectHashTable>::cast(inline_value); |
4988 } | 4993 } |
4989 | 4994 |
4990 if (init_option == ONLY_RETURN_INLINE_VALUE || | 4995 Handle<ObjectHashTable> hashtable = isolate->factory()->NewObjectHashTable( |
4991 inline_value->IsHashTable()) { | 4996 kInitialCapacity, |
4992 return inline_value; | 4997 USE_CUSTOM_MINIMUM_CAPACITY); |
4993 } | |
4994 | |
4995 ObjectHashTable* hashtable; | |
4996 static const int kInitialCapacity = 4; | |
4997 MaybeObject* maybe_obj = | |
4998 ObjectHashTable::Allocate(GetHeap(), | |
4999 kInitialCapacity, | |
5000 ObjectHashTable::USE_CUSTOM_MINIMUM_CAPACITY); | |
5001 if (!maybe_obj->To<ObjectHashTable>(&hashtable)) return maybe_obj; | |
5002 | 4998 |
5003 if (inline_value->IsSmi()) { | 4999 if (inline_value->IsSmi()) { |
5004 // We were storing the identity hash inline and now allocated an actual | 5000 // We were storing the identity hash inline and now allocated an actual |
5005 // dictionary. Put the identity hash into the new dictionary. | 5001 // dictionary. Put the identity hash into the new dictionary. |
5006 MaybeObject* insert_result = | 5002 hashtable = ObjectHashTable::Put(hashtable, |
5007 hashtable->Put(GetHeap()->identity_hash_string(), inline_value); | 5003 isolate->factory()->identity_hash_string(), |
5008 ObjectHashTable* new_table; | 5004 inline_value); |
5009 if (!insert_result->To(&new_table)) return insert_result; | |
5010 // We expect no resizing for the first insert. | |
5011 ASSERT_EQ(hashtable, new_table); | |
5012 } | 5005 } |
5013 | 5006 |
5014 MaybeObject* store_result = SetLocalPropertyIgnoreAttributesTrampoline( | 5007 JSObject::SetLocalPropertyIgnoreAttributes( |
5015 GetHeap()->hidden_string(), | 5008 object, |
| 5009 isolate->factory()->hidden_string(), |
5016 hashtable, | 5010 hashtable, |
5017 DONT_ENUM, | 5011 DONT_ENUM, |
5018 OPTIMAL_REPRESENTATION, | 5012 OPTIMAL_REPRESENTATION, |
5019 ALLOW_AS_CONSTANT, | 5013 ALLOW_AS_CONSTANT, |
5020 OMIT_EXTENSIBILITY_CHECK); | 5014 OMIT_EXTENSIBILITY_CHECK); |
5021 if (store_result->IsFailure()) return store_result; | 5015 |
5022 return hashtable; | 5016 return hashtable; |
5023 } | 5017 } |
5024 | 5018 |
5025 | 5019 |
5026 MaybeObject* JSObject::SetHiddenPropertiesHashTable(Object* value) { | 5020 Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object, |
5027 ASSERT(!IsJSGlobalProxy()); | 5021 Handle<Object> value) { |
| 5022 ASSERT(!object->IsJSGlobalProxy()); |
| 5023 |
| 5024 Isolate* isolate = object->GetIsolate(); |
| 5025 |
5028 // We can store the identity hash inline iff there is no backing store | 5026 // We can store the identity hash inline iff there is no backing store |
5029 // for hidden properties yet. | 5027 // for hidden properties yet. |
5030 ASSERT(HasHiddenProperties() != value->IsSmi()); | 5028 ASSERT(object->HasHiddenProperties() != value->IsSmi()); |
5031 if (HasFastProperties()) { | 5029 if (object->HasFastProperties()) { |
5032 // If the object has fast properties, check whether the first slot | 5030 // If the object has fast properties, check whether the first slot |
5033 // in the descriptor array matches the hidden string. Since the | 5031 // in the descriptor array matches the hidden string. Since the |
5034 // hidden strings hash code is zero (and no other name has hash | 5032 // hidden strings hash code is zero (and no other name has hash |
5035 // code zero) it will always occupy the first entry if present. | 5033 // code zero) it will always occupy the first entry if present. |
5036 DescriptorArray* descriptors = this->map()->instance_descriptors(); | 5034 DescriptorArray* descriptors = object->map()->instance_descriptors(); |
5037 if (descriptors->number_of_descriptors() > 0) { | 5035 if (descriptors->number_of_descriptors() > 0) { |
5038 int sorted_index = descriptors->GetSortedKeyIndex(0); | 5036 int sorted_index = descriptors->GetSortedKeyIndex(0); |
5039 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() && | 5037 if (descriptors->GetKey(sorted_index) == isolate->heap()->hidden_string() |
5040 sorted_index < map()->NumberOfOwnDescriptors()) { | 5038 && sorted_index < object->map()->NumberOfOwnDescriptors()) { |
5041 ASSERT(descriptors->GetType(sorted_index) == FIELD); | 5039 ASSERT(descriptors->GetType(sorted_index) == FIELD); |
5042 FastPropertyAtPut(descriptors->GetFieldIndex(sorted_index), value); | 5040 object->FastPropertyAtPut(descriptors->GetFieldIndex(sorted_index), |
5043 return this; | 5041 *value); |
| 5042 return object; |
5044 } | 5043 } |
5045 } | 5044 } |
5046 } | 5045 } |
5047 MaybeObject* store_result = SetLocalPropertyIgnoreAttributesTrampoline( | 5046 |
5048 GetHeap()->hidden_string(), | 5047 SetLocalPropertyIgnoreAttributes(object, |
5049 value, | 5048 isolate->factory()->hidden_string(), |
5050 DONT_ENUM, | 5049 value, |
5051 OPTIMAL_REPRESENTATION, | 5050 DONT_ENUM, |
5052 ALLOW_AS_CONSTANT, | 5051 OPTIMAL_REPRESENTATION, |
5053 OMIT_EXTENSIBILITY_CHECK); | 5052 ALLOW_AS_CONSTANT, |
5054 if (store_result->IsFailure()) return store_result; | 5053 OMIT_EXTENSIBILITY_CHECK); |
5055 return this; | 5054 return object; |
5056 } | 5055 } |
5057 | 5056 |
5058 | 5057 |
5059 Handle<Object> JSObject::DeletePropertyPostInterceptor(Handle<JSObject> object, | 5058 Handle<Object> JSObject::DeletePropertyPostInterceptor(Handle<JSObject> object, |
5060 Handle<Name> name, | 5059 Handle<Name> name, |
5061 DeleteMode mode) { | 5060 DeleteMode mode) { |
5062 // Check local property, ignore interceptor. | 5061 // Check local property, ignore interceptor. |
5063 Isolate* isolate = object->GetIsolate(); | 5062 Isolate* isolate = object->GetIsolate(); |
5064 LookupResult result(isolate); | 5063 LookupResult result(isolate); |
5065 object->LocalLookupRealNamedProperty(*name, &result); | 5064 object->LocalLookupRealNamedProperty(*name, &result); |
(...skipping 10065 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15131 | 15130 |
15132 template<typename Shape, typename Key> | 15131 template<typename Shape, typename Key> |
15133 MaybeObject* Dictionary<Shape, Key>::Allocate(Heap* heap, | 15132 MaybeObject* Dictionary<Shape, Key>::Allocate(Heap* heap, |
15134 int at_least_space_for, | 15133 int at_least_space_for, |
15135 PretenureFlag pretenure) { | 15134 PretenureFlag pretenure) { |
15136 Object* obj; | 15135 Object* obj; |
15137 { MaybeObject* maybe_obj = | 15136 { MaybeObject* maybe_obj = |
15138 HashTable<Shape, Key>::Allocate( | 15137 HashTable<Shape, Key>::Allocate( |
15139 heap, | 15138 heap, |
15140 at_least_space_for, | 15139 at_least_space_for, |
15141 HashTable<Shape, Key>::USE_DEFAULT_MINIMUM_CAPACITY, | 15140 USE_DEFAULT_MINIMUM_CAPACITY, |
15142 pretenure); | 15141 pretenure); |
15143 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 15142 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
15144 } | 15143 } |
15145 // Initialize the next enumeration index. | 15144 // Initialize the next enumeration index. |
15146 Dictionary<Shape, Key>::cast(obj)-> | 15145 Dictionary<Shape, Key>::cast(obj)-> |
15147 SetNextEnumerationIndex(PropertyDetails::kInitialIndex); | 15146 SetNextEnumerationIndex(PropertyDetails::kInitialIndex); |
15148 return obj; | 15147 return obj; |
15149 } | 15148 } |
15150 | 15149 |
15151 | 15150 |
(...skipping 545 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15697 obj->set_properties(fields); | 15696 obj->set_properties(fields); |
15698 ASSERT(obj->IsJSObject()); | 15697 ASSERT(obj->IsJSObject()); |
15699 | 15698 |
15700 // Check that it really works. | 15699 // Check that it really works. |
15701 ASSERT(obj->HasFastProperties()); | 15700 ASSERT(obj->HasFastProperties()); |
15702 | 15701 |
15703 return obj; | 15702 return obj; |
15704 } | 15703 } |
15705 | 15704 |
15706 | 15705 |
| 15706 Handle<ObjectHashSet> ObjectHashSet::EnsureCapacity( |
| 15707 Handle<ObjectHashSet> table, |
| 15708 int n, |
| 15709 Handle<Object> key, |
| 15710 PretenureFlag pretenure) { |
| 15711 Handle<HashTable<ObjectHashTableShape<1>, Object*> > table_base = table; |
| 15712 CALL_HEAP_FUNCTION(table_base->GetIsolate(), |
| 15713 table_base->EnsureCapacity(n, *key, pretenure), |
| 15714 ObjectHashSet); |
| 15715 } |
| 15716 |
| 15717 |
| 15718 Handle<ObjectHashSet> ObjectHashSet::Shrink(Handle<ObjectHashSet> table, |
| 15719 Handle<Object> key) { |
| 15720 Handle<HashTable<ObjectHashTableShape<1>, Object*> > table_base = table; |
| 15721 CALL_HEAP_FUNCTION(table_base->GetIsolate(), |
| 15722 table_base->Shrink(*key), |
| 15723 ObjectHashSet); |
| 15724 } |
| 15725 |
| 15726 |
15707 bool ObjectHashSet::Contains(Object* key) { | 15727 bool ObjectHashSet::Contains(Object* key) { |
15708 ASSERT(IsKey(key)); | 15728 ASSERT(IsKey(key)); |
15709 | 15729 |
15710 // If the object does not have an identity hash, it was never used as a key. | 15730 // If the object does not have an identity hash, it was never used as a key. |
15711 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION); | 15731 Object* hash = key->GetHash(); |
15712 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return false; | 15732 if (hash->IsUndefined()) return false; |
15713 } | 15733 |
15714 return (FindEntry(key) != kNotFound); | 15734 return (FindEntry(key) != kNotFound); |
15715 } | 15735 } |
15716 | 15736 |
15717 | 15737 |
15718 MaybeObject* ObjectHashSet::Add(Object* key) { | 15738 Handle<ObjectHashSet> ObjectHashSet::Add(Handle<ObjectHashSet> table, |
15719 ASSERT(IsKey(key)); | 15739 Handle<Object> key) { |
| 15740 ASSERT(table->IsKey(*key)); |
15720 | 15741 |
15721 // Make sure the key object has an identity hash code. | 15742 // Make sure the key object has an identity hash code. |
15722 int hash; | 15743 Handle<Object> object_hash = Object::GetOrCreateHash(key, |
15723 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION); | 15744 table->GetIsolate()); |
15724 if (maybe_hash->IsFailure()) return maybe_hash; | 15745 |
15725 ASSERT(key->GetHash(OMIT_CREATION) == maybe_hash); | 15746 int entry = table->FindEntry(*key); |
15726 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value(); | |
15727 } | |
15728 int entry = FindEntry(key); | |
15729 | 15747 |
15730 // Check whether key is already present. | 15748 // Check whether key is already present. |
15731 if (entry != kNotFound) return this; | 15749 if (entry != kNotFound) return table; |
15732 | 15750 |
15733 // Check whether the hash set should be extended and add entry. | 15751 // Check whether the hash set should be extended and add entry. |
15734 Object* obj; | 15752 Handle<ObjectHashSet> new_table = |
15735 { MaybeObject* maybe_obj = EnsureCapacity(1, key); | 15753 ObjectHashSet::EnsureCapacity(table, 1, key); |
15736 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 15754 entry = new_table->FindInsertionEntry(Smi::cast(*object_hash)->value()); |
15737 } | 15755 new_table->set(EntryToIndex(entry), *key); |
15738 ObjectHashSet* table = ObjectHashSet::cast(obj); | 15756 new_table->ElementAdded(); |
15739 entry = table->FindInsertionEntry(hash); | 15757 return new_table; |
15740 table->set(EntryToIndex(entry), key); | |
15741 table->ElementAdded(); | |
15742 return table; | |
15743 } | 15758 } |
15744 | 15759 |
15745 | 15760 |
15746 MaybeObject* ObjectHashSet::Remove(Object* key) { | 15761 Handle<ObjectHashSet> ObjectHashSet::Remove(Handle<ObjectHashSet> table, |
15747 ASSERT(IsKey(key)); | 15762 Handle<Object> key) { |
| 15763 ASSERT(table->IsKey(*key)); |
15748 | 15764 |
15749 // If the object does not have an identity hash, it was never used as a key. | 15765 // If the object does not have an identity hash, it was never used as a key. |
15750 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION); | 15766 if (key->GetHash()->IsUndefined()) return table; |
15751 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return this; | 15767 |
15752 } | 15768 int entry = table->FindEntry(*key); |
15753 int entry = FindEntry(key); | |
15754 | 15769 |
15755 // Check whether key is actually present. | 15770 // Check whether key is actually present. |
15756 if (entry == kNotFound) return this; | 15771 if (entry == kNotFound) return table; |
15757 | 15772 |
15758 // Remove entry and try to shrink this hash set. | 15773 // Remove entry and try to shrink this hash set. |
15759 set_the_hole(EntryToIndex(entry)); | 15774 table->set_the_hole(EntryToIndex(entry)); |
15760 ElementRemoved(); | 15775 table->ElementRemoved(); |
15761 return Shrink(key); | 15776 |
| 15777 return ObjectHashSet::Shrink(table, key); |
15762 } | 15778 } |
15763 | 15779 |
15764 | 15780 |
| 15781 Handle<ObjectHashTable> ObjectHashTable::EnsureCapacity( |
| 15782 Handle<ObjectHashTable> table, |
| 15783 int n, |
| 15784 Handle<Object> key, |
| 15785 PretenureFlag pretenure) { |
| 15786 Handle<HashTable<ObjectHashTableShape<2>, Object*> > table_base = table; |
| 15787 CALL_HEAP_FUNCTION(table_base->GetIsolate(), |
| 15788 table_base->EnsureCapacity(n, *key, pretenure), |
| 15789 ObjectHashTable); |
| 15790 } |
| 15791 |
| 15792 |
| 15793 Handle<ObjectHashTable> ObjectHashTable::Shrink( |
| 15794 Handle<ObjectHashTable> table, Handle<Object> key) { |
| 15795 Handle<HashTable<ObjectHashTableShape<2>, Object*> > table_base = table; |
| 15796 CALL_HEAP_FUNCTION(table_base->GetIsolate(), |
| 15797 table_base->Shrink(*key), |
| 15798 ObjectHashTable); |
| 15799 } |
| 15800 |
| 15801 |
15765 Object* ObjectHashTable::Lookup(Object* key) { | 15802 Object* ObjectHashTable::Lookup(Object* key) { |
15766 ASSERT(IsKey(key)); | 15803 ASSERT(IsKey(key)); |
15767 | 15804 |
15768 // If the object does not have an identity hash, it was never used as a key. | 15805 // If the object does not have an identity hash, it was never used as a key. |
15769 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION); | 15806 Object* hash = key->GetHash(); |
15770 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) { | 15807 if (hash->IsUndefined()) { |
15771 return GetHeap()->the_hole_value(); | 15808 return GetHeap()->the_hole_value(); |
15772 } | |
15773 } | 15809 } |
15774 int entry = FindEntry(key); | 15810 int entry = FindEntry(key); |
15775 if (entry == kNotFound) return GetHeap()->the_hole_value(); | 15811 if (entry == kNotFound) return GetHeap()->the_hole_value(); |
15776 return get(EntryToIndex(entry) + 1); | 15812 return get(EntryToIndex(entry) + 1); |
15777 } | 15813 } |
15778 | 15814 |
15779 | 15815 |
15780 MaybeObject* ObjectHashTable::Put(Object* key, Object* value) { | 15816 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table, |
15781 ASSERT(IsKey(key)); | 15817 Handle<Object> key, |
| 15818 Handle<Object> value) { |
| 15819 ASSERT(table->IsKey(*key)); |
| 15820 |
| 15821 Isolate* isolate = table->GetIsolate(); |
15782 | 15822 |
15783 // Make sure the key object has an identity hash code. | 15823 // Make sure the key object has an identity hash code. |
15784 int hash; | 15824 Handle<Object> hash = Object::GetOrCreateHash(key, isolate); |
15785 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION); | 15825 |
15786 if (maybe_hash->IsFailure()) return maybe_hash; | 15826 int entry = table->FindEntry(*key); |
15787 ASSERT(key->GetHash(OMIT_CREATION) == maybe_hash); | |
15788 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value(); | |
15789 } | |
15790 int entry = FindEntry(key); | |
15791 | 15827 |
15792 // Check whether to perform removal operation. | 15828 // Check whether to perform removal operation. |
15793 if (value->IsTheHole()) { | 15829 if (value->IsTheHole()) { |
15794 if (entry == kNotFound) return this; | 15830 if (entry == kNotFound) return table; |
15795 RemoveEntry(entry); | 15831 table->RemoveEntry(entry); |
15796 return Shrink(key); | 15832 return Shrink(table, key); |
15797 } | 15833 } |
15798 | 15834 |
15799 // Key is already in table, just overwrite value. | 15835 // Key is already in table, just overwrite value. |
15800 if (entry != kNotFound) { | 15836 if (entry != kNotFound) { |
15801 set(EntryToIndex(entry) + 1, value); | 15837 table->set(EntryToIndex(entry) + 1, *value); |
15802 return this; | 15838 return table; |
15803 } | 15839 } |
15804 | 15840 |
15805 // Check whether the hash table should be extended. | 15841 // Check whether the hash table should be extended. |
15806 Object* obj; | 15842 table = EnsureCapacity(table, 1, key); |
15807 { MaybeObject* maybe_obj = EnsureCapacity(1, key); | 15843 table->AddEntry(table->FindInsertionEntry(Handle<Smi>::cast(hash)->value()), |
15808 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 15844 *key, |
15809 } | 15845 *value); |
15810 ObjectHashTable* table = ObjectHashTable::cast(obj); | |
15811 table->AddEntry(table->FindInsertionEntry(hash), key, value); | |
15812 return table; | 15846 return table; |
15813 } | 15847 } |
15814 | 15848 |
15815 | 15849 |
15816 void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) { | 15850 void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) { |
15817 set(EntryToIndex(entry), key); | 15851 set(EntryToIndex(entry), key); |
15818 set(EntryToIndex(entry) + 1, value); | 15852 set(EntryToIndex(entry) + 1, value); |
15819 ElementAdded(); | 15853 ElementAdded(); |
15820 } | 15854 } |
15821 | 15855 |
(...skipping 574 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16396 #define ERROR_MESSAGES_TEXTS(C, T) T, | 16430 #define ERROR_MESSAGES_TEXTS(C, T) T, |
16397 static const char* error_messages_[] = { | 16431 static const char* error_messages_[] = { |
16398 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) | 16432 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) |
16399 }; | 16433 }; |
16400 #undef ERROR_MESSAGES_TEXTS | 16434 #undef ERROR_MESSAGES_TEXTS |
16401 return error_messages_[reason]; | 16435 return error_messages_[reason]; |
16402 } | 16436 } |
16403 | 16437 |
16404 | 16438 |
16405 } } // namespace v8::internal | 16439 } } // namespace v8::internal |
OLD | NEW |