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