OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 2471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2482 LookupResult result; | 2482 LookupResult result; |
2483 LocalLookup(name, &result); | 2483 LocalLookup(name, &result); |
2484 return GetPropertyAttribute(this, &result, name, false); | 2484 return GetPropertyAttribute(this, &result, name, false); |
2485 } | 2485 } |
2486 | 2486 |
2487 | 2487 |
2488 MaybeObject* NormalizedMapCache::Get(JSObject* obj, | 2488 MaybeObject* NormalizedMapCache::Get(JSObject* obj, |
2489 PropertyNormalizationMode mode) { | 2489 PropertyNormalizationMode mode) { |
2490 Isolate* isolate = obj->GetIsolate(); | 2490 Isolate* isolate = obj->GetIsolate(); |
2491 Map* fast = obj->map(); | 2491 Map* fast = obj->map(); |
2492 int index = Hash(fast) % kEntries; | 2492 int index = fast->Hash() % kEntries; |
2493 Object* result = get(index); | 2493 Object* result = get(index); |
2494 if (result->IsMap() && CheckHit(Map::cast(result), fast, mode)) { | 2494 if (result->IsMap() && |
| 2495 Map::cast(result)->EquivalentToForNormalization(fast, mode)) { |
2495 #ifdef DEBUG | 2496 #ifdef DEBUG |
| 2497 Map::cast(result)->SharedMapVerify(); |
2496 if (FLAG_enable_slow_asserts) { | 2498 if (FLAG_enable_slow_asserts) { |
2497 // The cached map should match newly created normalized map bit-by-bit. | 2499 // The cached map should match newly created normalized map bit-by-bit. |
2498 Object* fresh; | 2500 Object* fresh; |
2499 { MaybeObject* maybe_fresh = | 2501 { MaybeObject* maybe_fresh = |
2500 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); | 2502 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); |
2501 if (maybe_fresh->ToObject(&fresh)) { | 2503 if (maybe_fresh->ToObject(&fresh)) { |
2502 ASSERT(memcmp(Map::cast(fresh)->address(), | 2504 ASSERT(memcmp(Map::cast(fresh)->address(), |
2503 Map::cast(result)->address(), | 2505 Map::cast(result)->address(), |
2504 Map::kSize) == 0); | 2506 Map::kSize) == 0); |
2505 } | 2507 } |
(...skipping 15 matching lines...) Expand all Loading... |
2521 | 2523 |
2522 | 2524 |
2523 void NormalizedMapCache::Clear() { | 2525 void NormalizedMapCache::Clear() { |
2524 int entries = length(); | 2526 int entries = length(); |
2525 for (int i = 0; i != entries; i++) { | 2527 for (int i = 0; i != entries; i++) { |
2526 set_undefined(i); | 2528 set_undefined(i); |
2527 } | 2529 } |
2528 } | 2530 } |
2529 | 2531 |
2530 | 2532 |
2531 int NormalizedMapCache::Hash(Map* fast) { | |
2532 // For performance reasons we only hash the 3 most variable fields of a map: | |
2533 // constructor, prototype and bit_field2. | |
2534 | |
2535 // Shift away the tag. | |
2536 int hash = (static_cast<uint32_t>( | |
2537 reinterpret_cast<uintptr_t>(fast->constructor())) >> 2); | |
2538 | |
2539 // XOR-ing the prototype and constructor directly yields too many zero bits | |
2540 // when the two pointers are close (which is fairly common). | |
2541 // To avoid this we shift the prototype 4 bits relatively to the constructor. | |
2542 hash ^= (static_cast<uint32_t>( | |
2543 reinterpret_cast<uintptr_t>(fast->prototype())) << 2); | |
2544 | |
2545 return hash ^ (hash >> 16) ^ fast->bit_field2(); | |
2546 } | |
2547 | |
2548 | |
2549 bool NormalizedMapCache::CheckHit(Map* slow, | |
2550 Map* fast, | |
2551 PropertyNormalizationMode mode) { | |
2552 #ifdef DEBUG | |
2553 slow->SharedMapVerify(); | |
2554 #endif | |
2555 return | |
2556 slow->constructor() == fast->constructor() && | |
2557 slow->prototype() == fast->prototype() && | |
2558 slow->inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ? | |
2559 0 : | |
2560 fast->inobject_properties()) && | |
2561 slow->instance_type() == fast->instance_type() && | |
2562 slow->bit_field() == fast->bit_field() && | |
2563 slow->bit_field2() == fast->bit_field2() && | |
2564 (slow->bit_field3() & ~(1<<Map::kIsShared)) == fast->bit_field3(); | |
2565 } | |
2566 | |
2567 | |
2568 MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) { | 2533 MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) { |
2569 if (map()->is_shared()) { | 2534 if (map()->is_shared()) { |
2570 // Fast case maps are never marked as shared. | 2535 // Fast case maps are never marked as shared. |
2571 ASSERT(!HasFastProperties()); | 2536 ASSERT(!HasFastProperties()); |
2572 // Replace the map with an identical copy that can be safely modified. | 2537 // Replace the map with an identical copy that can be safely modified. |
2573 Object* obj; | 2538 Object* obj; |
2574 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES, | 2539 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES, |
2575 UNIQUE_NORMALIZED_MAP); | 2540 UNIQUE_NORMALIZED_MAP); |
2576 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 2541 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
2577 } | 2542 } |
(...skipping 1473 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4051 } | 4016 } |
4052 FixedArray* pair = FixedArray::cast(obj); | 4017 FixedArray* pair = FixedArray::cast(obj); |
4053 pair->set(0, name_); | 4018 pair->set(0, name_); |
4054 pair->set(1, code_); | 4019 pair->set(1, code_); |
4055 return pair; | 4020 return pair; |
4056 } | 4021 } |
4057 | 4022 |
4058 private: | 4023 private: |
4059 String* name_; | 4024 String* name_; |
4060 Code::Flags flags_; | 4025 Code::Flags flags_; |
| 4026 // TODO(jkummerow): We should be able to get by without this. |
4061 Code* code_; | 4027 Code* code_; |
4062 }; | 4028 }; |
4063 | 4029 |
4064 | 4030 |
4065 Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) { | 4031 Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) { |
4066 CodeCacheHashTableKey key(name, flags); | 4032 CodeCacheHashTableKey key(name, flags); |
4067 int entry = FindEntry(&key); | 4033 int entry = FindEntry(&key); |
4068 if (entry == kNotFound) return GetHeap()->undefined_value(); | 4034 if (entry == kNotFound) return GetHeap()->undefined_value(); |
4069 return get(EntryToIndex(entry) + 1); | 4035 return get(EntryToIndex(entry) + 1); |
4070 } | 4036 } |
4071 | 4037 |
4072 | 4038 |
4073 MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) { | 4039 MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) { |
4074 CodeCacheHashTableKey key(name, code); | 4040 CodeCacheHashTableKey key(name, code); |
4075 Object* obj; | 4041 Object* obj; |
4076 { MaybeObject* maybe_obj = EnsureCapacity(1, &key); | 4042 { MaybeObject* maybe_obj = EnsureCapacity(1, &key); |
4077 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 4043 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
4078 } | 4044 } |
4079 | 4045 |
4080 // Don't use this, as the table might have grown. | 4046 // Don't use |this|, as the table might have grown. |
4081 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj); | 4047 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj); |
4082 | 4048 |
4083 int entry = cache->FindInsertionEntry(key.Hash()); | 4049 int entry = cache->FindInsertionEntry(key.Hash()); |
4084 Object* k; | 4050 Object* k; |
4085 { MaybeObject* maybe_k = key.AsObject(); | 4051 { MaybeObject* maybe_k = key.AsObject(); |
4086 if (!maybe_k->ToObject(&k)) return maybe_k; | 4052 if (!maybe_k->ToObject(&k)) return maybe_k; |
4087 } | 4053 } |
4088 | 4054 |
4089 cache->set(EntryToIndex(entry), k); | 4055 cache->set(EntryToIndex(entry), k); |
4090 cache->set(EntryToIndex(entry) + 1, code); | 4056 cache->set(EntryToIndex(entry) + 1, code); |
(...skipping 25 matching lines...) Expand all Loading... |
4116 if (element->IsSmi() && key->IsSmi() && (element == key)) return true; | 4082 if (element->IsSmi() && key->IsSmi() && (element == key)) return true; |
4117 if (element->IsString() && | 4083 if (element->IsString() && |
4118 key->IsString() && String::cast(element)->Equals(String::cast(key))) { | 4084 key->IsString() && String::cast(element)->Equals(String::cast(key))) { |
4119 return true; | 4085 return true; |
4120 } | 4086 } |
4121 } | 4087 } |
4122 return false; | 4088 return false; |
4123 } | 4089 } |
4124 | 4090 |
4125 | 4091 |
| 4092 MaybeObject* PolymorphicCodeCache::Update(MapList* maps, |
| 4093 Code::Flags flags, |
| 4094 Code* code) { |
| 4095 // Initialize cache if necessary. |
| 4096 if (cache()->IsUndefined()) { |
| 4097 Object* result; |
| 4098 { MaybeObject* maybe_result = |
| 4099 PolymorphicCodeCacheHashTable::Allocate( |
| 4100 PolymorphicCodeCacheHashTable::kInitialSize); |
| 4101 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 4102 } |
| 4103 set_cache(result); |
| 4104 } else { |
| 4105 // This entry shouldn't be contained in the cache yet. |
| 4106 ASSERT(PolymorphicCodeCacheHashTable::cast(cache()) |
| 4107 ->Lookup(maps, flags)->IsUndefined()); |
| 4108 } |
| 4109 PolymorphicCodeCacheHashTable* hash_table = |
| 4110 PolymorphicCodeCacheHashTable::cast(cache()); |
| 4111 Object* new_cache; |
| 4112 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code); |
| 4113 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache; |
| 4114 } |
| 4115 set_cache(new_cache); |
| 4116 return this; |
| 4117 } |
| 4118 |
| 4119 |
| 4120 Object* PolymorphicCodeCache::Lookup(MapList* maps, Code::Flags flags) { |
| 4121 if (!cache()->IsUndefined()) { |
| 4122 PolymorphicCodeCacheHashTable* hash_table = |
| 4123 PolymorphicCodeCacheHashTable::cast(cache()); |
| 4124 return hash_table->Lookup(maps, flags); |
| 4125 } else { |
| 4126 return GetHeap()->undefined_value(); |
| 4127 } |
| 4128 } |
| 4129 |
| 4130 |
| 4131 // Despite their name, object of this class are not stored in the actual |
| 4132 // hash table; instead they're temporarily used for lookups. It is therefore |
| 4133 // safe to have a weak (non-owning) pointer to a MapList as a member field. |
| 4134 class PolymorphicCodeCacheHashTableKey : public HashTableKey { |
| 4135 public: |
| 4136 // Callers must ensure that |maps| outlives the newly constructed object. |
| 4137 PolymorphicCodeCacheHashTableKey(MapList* maps, int code_flags) |
| 4138 : maps_(maps), |
| 4139 code_flags_(code_flags) {} |
| 4140 |
| 4141 bool IsMatch(Object* other) { |
| 4142 MapList other_maps(kDefaultListAllocationSize); |
| 4143 int other_flags; |
| 4144 FromObject(other, &other_flags, &other_maps); |
| 4145 if (code_flags_ != other_flags) return false; |
| 4146 if (maps_->length() != other_maps.length()) return false; |
| 4147 // Compare just the hashes first because it's faster. |
| 4148 int this_hash = MapsHashHelper(maps_, code_flags_); |
| 4149 int other_hash = MapsHashHelper(&other_maps, other_flags); |
| 4150 if (this_hash != other_hash) return false; |
| 4151 |
| 4152 // Full comparison: for each map in maps_, look for an equivalent map in |
| 4153 // other_maps. This implementation is slow, but probably good enough for |
| 4154 // now because the lists are short (<= 4 elements currently). |
| 4155 for (int i = 0; i < maps_->length(); ++i) { |
| 4156 bool match_found = false; |
| 4157 for (int j = 0; j < other_maps.length(); ++j) { |
| 4158 if (maps_->at(i)->EquivalentTo(other_maps.at(j))) { |
| 4159 match_found = true; |
| 4160 break; |
| 4161 } |
| 4162 } |
| 4163 if (!match_found) return false; |
| 4164 } |
| 4165 return true; |
| 4166 } |
| 4167 |
| 4168 static uint32_t MapsHashHelper(MapList* maps, int code_flags) { |
| 4169 uint32_t hash = code_flags; |
| 4170 for (int i = 0; i < maps->length(); ++i) { |
| 4171 hash ^= maps->at(i)->Hash(); |
| 4172 } |
| 4173 return hash; |
| 4174 } |
| 4175 |
| 4176 uint32_t Hash() { |
| 4177 return MapsHashHelper(maps_, code_flags_); |
| 4178 } |
| 4179 |
| 4180 uint32_t HashForObject(Object* obj) { |
| 4181 MapList other_maps(kDefaultListAllocationSize); |
| 4182 int other_flags; |
| 4183 FromObject(obj, &other_flags, &other_maps); |
| 4184 return MapsHashHelper(&other_maps, other_flags); |
| 4185 } |
| 4186 |
| 4187 MUST_USE_RESULT MaybeObject* AsObject() { |
| 4188 Object* obj; |
| 4189 // The maps in |maps_| must be copied to a newly allocated FixedArray, |
| 4190 // both because the referenced MapList is short-lived, and because C++ |
| 4191 // objects can't be stored in the heap anyway. |
| 4192 { MaybeObject* maybe_obj = |
| 4193 HEAP->AllocateUninitializedFixedArray(maps_->length() + 1); |
| 4194 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 4195 } |
| 4196 FixedArray* list = FixedArray::cast(obj); |
| 4197 list->set(0, Smi::FromInt(code_flags_)); |
| 4198 for (int i = 0; i < maps_->length(); ++i) { |
| 4199 list->set(i + 1, maps_->at(i)); |
| 4200 } |
| 4201 return list; |
| 4202 } |
| 4203 |
| 4204 private: |
| 4205 static MapList* FromObject(Object* obj, int* code_flags, MapList* maps) { |
| 4206 FixedArray* list = FixedArray::cast(obj); |
| 4207 maps->Rewind(0); |
| 4208 *code_flags = Smi::cast(list->get(0))->value(); |
| 4209 for (int i = 1; i < list->length(); ++i) { |
| 4210 maps->Add(Map::cast(list->get(i))); |
| 4211 } |
| 4212 return maps; |
| 4213 } |
| 4214 |
| 4215 MapList* maps_; // weak. |
| 4216 int code_flags_; |
| 4217 static const int kDefaultListAllocationSize = |
| 4218 KeyedIC::kMaxKeyedPolymorphism + 1; |
| 4219 }; |
| 4220 |
| 4221 |
| 4222 Object* PolymorphicCodeCacheHashTable::Lookup(MapList* maps, int code_flags) { |
| 4223 PolymorphicCodeCacheHashTableKey key(maps, code_flags); |
| 4224 int entry = FindEntry(&key); |
| 4225 if (entry == kNotFound) return GetHeap()->undefined_value(); |
| 4226 return get(EntryToIndex(entry) + 1); |
| 4227 } |
| 4228 |
| 4229 |
| 4230 MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps, |
| 4231 int code_flags, |
| 4232 Code* code) { |
| 4233 PolymorphicCodeCacheHashTableKey key(maps, code_flags); |
| 4234 Object* obj; |
| 4235 { MaybeObject* maybe_obj = EnsureCapacity(1, &key); |
| 4236 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 4237 } |
| 4238 PolymorphicCodeCacheHashTable* cache = |
| 4239 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj); |
| 4240 int entry = cache->FindInsertionEntry(key.Hash()); |
| 4241 { MaybeObject* maybe_obj = key.AsObject(); |
| 4242 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 4243 } |
| 4244 cache->set(EntryToIndex(entry), obj); |
| 4245 cache->set(EntryToIndex(entry) + 1, code); |
| 4246 cache->ElementAdded(); |
| 4247 return cache; |
| 4248 } |
| 4249 |
| 4250 |
4126 MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) { | 4251 MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) { |
4127 ASSERT(!array->HasExternalArrayElements()); | 4252 ASSERT(!array->HasExternalArrayElements()); |
4128 switch (array->GetElementsKind()) { | 4253 switch (array->GetElementsKind()) { |
4129 case JSObject::FAST_ELEMENTS: | 4254 case JSObject::FAST_ELEMENTS: |
4130 return UnionOfKeys(FixedArray::cast(array->elements())); | 4255 return UnionOfKeys(FixedArray::cast(array->elements())); |
4131 case JSObject::DICTIONARY_ELEMENTS: { | 4256 case JSObject::DICTIONARY_ELEMENTS: { |
4132 NumberDictionary* dict = array->element_dictionary(); | 4257 NumberDictionary* dict = array->element_dictionary(); |
4133 int size = dict->NumberOfElements(); | 4258 int size = dict->NumberOfElements(); |
4134 | 4259 |
4135 // Allocate a temporary fixed array. | 4260 // Allocate a temporary fixed array. |
(...skipping 1625 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5761 ASSERT(target->prototype() == this || | 5886 ASSERT(target->prototype() == this || |
5762 target->prototype() == real_prototype); | 5887 target->prototype() == real_prototype); |
5763 // Getter prototype() is read-only, set_prototype() has side effects. | 5888 // Getter prototype() is read-only, set_prototype() has side effects. |
5764 *RawField(target, Map::kPrototypeOffset) = real_prototype; | 5889 *RawField(target, Map::kPrototypeOffset) = real_prototype; |
5765 } | 5890 } |
5766 } | 5891 } |
5767 } | 5892 } |
5768 } | 5893 } |
5769 | 5894 |
5770 | 5895 |
| 5896 int Map::Hash() { |
| 5897 // For performance reasons we only hash the 3 most variable fields of a map: |
| 5898 // constructor, prototype and bit_field2. |
| 5899 |
| 5900 // Shift away the tag. |
| 5901 int hash = (static_cast<uint32_t>( |
| 5902 reinterpret_cast<uintptr_t>(constructor())) >> 2); |
| 5903 |
| 5904 // XOR-ing the prototype and constructor directly yields too many zero bits |
| 5905 // when the two pointers are close (which is fairly common). |
| 5906 // To avoid this we shift the prototype 4 bits relatively to the constructor. |
| 5907 hash ^= (static_cast<uint32_t>( |
| 5908 reinterpret_cast<uintptr_t>(prototype())) << 2); |
| 5909 |
| 5910 return hash ^ (hash >> 16) ^ bit_field2(); |
| 5911 } |
| 5912 |
| 5913 |
| 5914 bool Map::EquivalentToForNormalization(Map* other, |
| 5915 PropertyNormalizationMode mode) { |
| 5916 return |
| 5917 constructor() == other->constructor() && |
| 5918 prototype() == other->prototype() && |
| 5919 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ? |
| 5920 0 : |
| 5921 other->inobject_properties()) && |
| 5922 instance_type() == other->instance_type() && |
| 5923 bit_field() == other->bit_field() && |
| 5924 bit_field2() == other->bit_field2() && |
| 5925 (bit_field3() & ~(1<<Map::kIsShared)) == |
| 5926 (other->bit_field3() & ~(1<<Map::kIsShared)); |
| 5927 } |
| 5928 |
| 5929 |
5771 void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) { | 5930 void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) { |
5772 // Iterate over all fields in the body but take care in dealing with | 5931 // Iterate over all fields in the body but take care in dealing with |
5773 // the code entry. | 5932 // the code entry. |
5774 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset); | 5933 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset); |
5775 v->VisitCodeEntry(this->address() + kCodeEntryOffset); | 5934 v->VisitCodeEntry(this->address() + kCodeEntryOffset); |
5776 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size); | 5935 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size); |
5777 } | 5936 } |
5778 | 5937 |
5779 | 5938 |
5780 void JSFunction::MarkForLazyRecompilation() { | 5939 void JSFunction::MarkForLazyRecompilation() { |
(...skipping 4831 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10612 if (break_point_objects()->IsUndefined()) return 0; | 10771 if (break_point_objects()->IsUndefined()) return 0; |
10613 // Single beak point. | 10772 // Single beak point. |
10614 if (!break_point_objects()->IsFixedArray()) return 1; | 10773 if (!break_point_objects()->IsFixedArray()) return 1; |
10615 // Multiple break points. | 10774 // Multiple break points. |
10616 return FixedArray::cast(break_point_objects())->length(); | 10775 return FixedArray::cast(break_point_objects())->length(); |
10617 } | 10776 } |
10618 #endif | 10777 #endif |
10619 | 10778 |
10620 | 10779 |
10621 } } // namespace v8::internal | 10780 } } // namespace v8::internal |
OLD | NEW |