OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/objects.h" | 5 #include "src/objects.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <iomanip> | 8 #include <iomanip> |
9 #include <sstream> | 9 #include <sstream> |
10 | 10 |
(...skipping 10046 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10057 simple_flag); | 10057 simple_flag); |
10058 } | 10058 } |
10059 | 10059 |
10060 | 10060 |
10061 void Map::UpdateCodeCache(Handle<Map> map, | 10061 void Map::UpdateCodeCache(Handle<Map> map, |
10062 Handle<Name> name, | 10062 Handle<Name> name, |
10063 Handle<Code> code) { | 10063 Handle<Code> code) { |
10064 Isolate* isolate = map->GetIsolate(); | 10064 Isolate* isolate = map->GetIsolate(); |
10065 HandleScope scope(isolate); | 10065 HandleScope scope(isolate); |
10066 // Allocate the code cache if not present. | 10066 // Allocate the code cache if not present. |
10067 if (map->code_cache()->IsFixedArray()) { | 10067 if (!map->has_code_cache()) { |
10068 Handle<Object> result = isolate->factory()->NewCodeCache(); | 10068 Handle<Object> result = |
| 10069 CodeCacheHashTable::New(isolate, CodeCacheHashTable::kInitialSize); |
10069 map->set_code_cache(*result); | 10070 map->set_code_cache(*result); |
10070 } | 10071 } |
10071 | 10072 |
10072 // Update the code cache. | 10073 // Update the code cache. |
10073 Handle<CodeCache> code_cache(CodeCache::cast(map->code_cache()), isolate); | 10074 Handle<CodeCacheHashTable> cache(CodeCacheHashTable::cast(map->code_cache()), |
10074 CodeCache::Update(code_cache, name, code); | 10075 isolate); |
| 10076 Handle<Object> new_cache = CodeCacheHashTable::Put(cache, name, code); |
| 10077 map->set_code_cache(*new_cache); |
| 10078 } |
| 10079 |
| 10080 Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) { |
| 10081 if (!has_code_cache()) return nullptr; |
| 10082 return CodeCacheHashTable::cast(code_cache())->Lookup(name, flags); |
10075 } | 10083 } |
10076 | 10084 |
10077 | 10085 |
10078 Object* Map::FindInCodeCache(Name* name, Code::Flags flags) { | |
10079 // Do a lookup if a code cache exists. | |
10080 if (!code_cache()->IsFixedArray()) { | |
10081 return CodeCache::cast(code_cache())->Lookup(name, flags); | |
10082 } else { | |
10083 return GetHeap()->undefined_value(); | |
10084 } | |
10085 } | |
10086 | |
10087 | |
10088 int Map::IndexInCodeCache(Object* name, Code* code) { | |
10089 // Get the internal index if a code cache exists. | |
10090 if (!code_cache()->IsFixedArray()) { | |
10091 return CodeCache::cast(code_cache())->GetIndex(name, code); | |
10092 } | |
10093 return -1; | |
10094 } | |
10095 | |
10096 | |
10097 void Map::RemoveFromCodeCache(Name* name, Code* code, int index) { | |
10098 // No GC is supposed to happen between a call to IndexInCodeCache and | |
10099 // RemoveFromCodeCache so the code cache must be there. | |
10100 DCHECK(!code_cache()->IsFixedArray()); | |
10101 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index); | |
10102 } | |
10103 | |
10104 | |
10105 void CodeCache::Update( | |
10106 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) { | |
10107 // The number of monomorphic stubs for normal load/store/call IC's can grow to | |
10108 // a large number and therefore they need to go into a hash table. They are | |
10109 // used to load global properties from cells. | |
10110 if (code->type() == Code::NORMAL) { | |
10111 // Make sure that a hash table is allocated for the normal load code cache. | |
10112 if (code_cache->normal_type_cache()->IsUndefined()) { | |
10113 Handle<Object> result = | |
10114 CodeCacheHashTable::New(code_cache->GetIsolate(), | |
10115 CodeCacheHashTable::kInitialSize); | |
10116 code_cache->set_normal_type_cache(*result); | |
10117 } | |
10118 UpdateNormalTypeCache(code_cache, name, code); | |
10119 } else { | |
10120 DCHECK(code_cache->default_cache()->IsFixedArray()); | |
10121 UpdateDefaultCache(code_cache, name, code); | |
10122 } | |
10123 } | |
10124 | |
10125 | |
10126 void CodeCache::UpdateDefaultCache( | |
10127 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) { | |
10128 Isolate* isolate = code_cache->GetIsolate(); | |
10129 // When updating the default code cache we disregard the type encoded in the | |
10130 // flags. This allows call constant stubs to overwrite call field | |
10131 // stubs, etc. | |
10132 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags()); | |
10133 | |
10134 // First check whether we can update existing code cache without | |
10135 // extending it. | |
10136 Handle<FixedArray> cache = handle(code_cache->default_cache()); | |
10137 int length = cache->length(); | |
10138 { | |
10139 DisallowHeapAllocation no_alloc; | |
10140 int deleted_index = -1; | |
10141 Object* null = isolate->heap()->null_value(); | |
10142 Object* undefined = isolate->heap()->undefined_value(); | |
10143 DCHECK(name->IsUniqueName()); | |
10144 for (int i = 0; i < length; i += kCodeCacheEntrySize) { | |
10145 Object* key = cache->get(i); | |
10146 if (key == null) { | |
10147 if (deleted_index < 0) deleted_index = i; | |
10148 continue; | |
10149 } | |
10150 if (key == undefined) { | |
10151 if (deleted_index >= 0) i = deleted_index; | |
10152 cache->set(i + kCodeCacheEntryNameOffset, *name); | |
10153 cache->set(i + kCodeCacheEntryCodeOffset, *code); | |
10154 return; | |
10155 } | |
10156 DCHECK(key->IsUniqueName()); | |
10157 if (*name == key) { | |
10158 Code::Flags found = | |
10159 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags(); | |
10160 if (Code::RemoveTypeFromFlags(found) == flags) { | |
10161 cache->set(i + kCodeCacheEntryCodeOffset, *code); | |
10162 return; | |
10163 } | |
10164 } | |
10165 } | |
10166 | |
10167 // Reached the end of the code cache. If there were deleted | |
10168 // elements, reuse the space for the first of them. | |
10169 if (deleted_index >= 0) { | |
10170 cache->set(deleted_index + kCodeCacheEntryNameOffset, *name); | |
10171 cache->set(deleted_index + kCodeCacheEntryCodeOffset, *code); | |
10172 return; | |
10173 } | |
10174 } | |
10175 | |
10176 // Extend the code cache with some new entries (at least one). Must be a | |
10177 // multiple of the entry size. | |
10178 int new_length = length + (length >> 1) + kCodeCacheEntrySize; | |
10179 new_length = new_length - new_length % kCodeCacheEntrySize; | |
10180 DCHECK((new_length % kCodeCacheEntrySize) == 0); | |
10181 cache = isolate->factory()->CopyFixedArrayAndGrow(cache, new_length - length); | |
10182 | |
10183 // Add the (name, code) pair to the new cache. | |
10184 cache->set(length + kCodeCacheEntryNameOffset, *name); | |
10185 cache->set(length + kCodeCacheEntryCodeOffset, *code); | |
10186 code_cache->set_default_cache(*cache); | |
10187 } | |
10188 | |
10189 | |
10190 void CodeCache::UpdateNormalTypeCache( | |
10191 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) { | |
10192 // Adding a new entry can cause a new cache to be allocated. | |
10193 Handle<CodeCacheHashTable> cache( | |
10194 CodeCacheHashTable::cast(code_cache->normal_type_cache())); | |
10195 Handle<Object> new_cache = CodeCacheHashTable::Put(cache, name, code); | |
10196 code_cache->set_normal_type_cache(*new_cache); | |
10197 } | |
10198 | |
10199 | |
10200 Object* CodeCache::Lookup(Name* name, Code::Flags flags) { | |
10201 Object* result = LookupDefaultCache(name, Code::RemoveTypeFromFlags(flags)); | |
10202 if (result->IsCode()) { | |
10203 if (Code::cast(result)->flags() == flags) return result; | |
10204 return GetHeap()->undefined_value(); | |
10205 } | |
10206 return LookupNormalTypeCache(name, flags); | |
10207 } | |
10208 | |
10209 | |
10210 Object* CodeCache::LookupDefaultCache(Name* name, Code::Flags flags) { | |
10211 FixedArray* cache = default_cache(); | |
10212 Heap* heap = GetHeap(); | |
10213 Object* null = heap->null_value(); | |
10214 Object* undefined = heap->undefined_value(); | |
10215 int length = cache->length(); | |
10216 DCHECK(name->IsUniqueName()); | |
10217 for (int i = 0; i < length; i += kCodeCacheEntrySize) { | |
10218 Object* key = cache->get(i + kCodeCacheEntryNameOffset); | |
10219 // Skip deleted elements. | |
10220 if (key == null) continue; | |
10221 if (key == undefined) return key; | |
10222 DCHECK(key->IsUniqueName()); | |
10223 if (name == key) { | |
10224 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset)); | |
10225 if (Code::RemoveTypeFromFlags(code->flags()) == flags) { | |
10226 return code; | |
10227 } | |
10228 } | |
10229 } | |
10230 return GetHeap()->undefined_value(); | |
10231 } | |
10232 | |
10233 | |
10234 Object* CodeCache::LookupNormalTypeCache(Name* name, Code::Flags flags) { | |
10235 if (!normal_type_cache()->IsUndefined()) { | |
10236 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache()); | |
10237 return cache->Lookup(name, flags); | |
10238 } else { | |
10239 return GetHeap()->undefined_value(); | |
10240 } | |
10241 } | |
10242 | |
10243 | |
10244 int CodeCache::GetIndex(Object* name, Code* code) { | |
10245 if (code->type() == Code::NORMAL) { | |
10246 if (normal_type_cache()->IsUndefined()) return -1; | |
10247 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache()); | |
10248 return cache->GetIndex(Name::cast(name), code->flags()); | |
10249 } | |
10250 | |
10251 FixedArray* array = default_cache(); | |
10252 int len = array->length(); | |
10253 for (int i = 0; i < len; i += kCodeCacheEntrySize) { | |
10254 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1; | |
10255 } | |
10256 return -1; | |
10257 } | |
10258 | |
10259 | |
10260 void CodeCache::RemoveByIndex(Object* name, Code* code, int index) { | |
10261 if (code->type() == Code::NORMAL) { | |
10262 DCHECK(!normal_type_cache()->IsUndefined()); | |
10263 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache()); | |
10264 DCHECK(cache->GetIndex(Name::cast(name), code->flags()) == index); | |
10265 cache->RemoveByIndex(index); | |
10266 } else { | |
10267 FixedArray* array = default_cache(); | |
10268 DCHECK(array->length() >= index && array->get(index)->IsCode()); | |
10269 // Use null instead of undefined for deleted elements to distinguish | |
10270 // deleted elements from unused elements. This distinction is used | |
10271 // when looking up in the cache and when updating the cache. | |
10272 DCHECK_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset); | |
10273 array->set_null(index - 1); // Name. | |
10274 array->set_null(index); // Code. | |
10275 } | |
10276 } | |
10277 | |
10278 | |
10279 // The key in the code cache hash table consists of the property name and the | 10086 // The key in the code cache hash table consists of the property name and the |
10280 // code object. The actual match is on the name and the code flags. If a key | 10087 // code object. The actual match is on the name and the code flags. If a key |
10281 // is created using the flags and not a code object it can only be used for | 10088 // is created using the flags and not a code object it can only be used for |
10282 // lookup not to create a new entry. | 10089 // lookup not to create a new entry. |
10283 class CodeCacheHashTableKey : public HashTableKey { | 10090 class CodeCacheHashTableKey : public HashTableKey { |
10284 public: | 10091 public: |
10285 CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags) | 10092 CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags) |
10286 : name_(name), flags_(flags), code_() { } | 10093 : name_(name), flags_(flags), code_() { |
| 10094 DCHECK(name_->IsUniqueName()); |
| 10095 } |
10287 | 10096 |
10288 CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code) | 10097 CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code) |
10289 : name_(name), flags_(code->flags()), code_(code) { } | 10098 : name_(name), flags_(code->flags()), code_(code) { |
| 10099 DCHECK(name_->IsUniqueName()); |
| 10100 } |
10290 | 10101 |
10291 bool IsMatch(Object* other) override { | 10102 bool IsMatch(Object* other) override { |
10292 if (!other->IsFixedArray()) return false; | 10103 DCHECK(other->IsFixedArray()); |
10293 FixedArray* pair = FixedArray::cast(other); | 10104 FixedArray* pair = FixedArray::cast(other); |
10294 Name* name = Name::cast(pair->get(0)); | 10105 Name* name = Name::cast(pair->get(0)); |
10295 Code::Flags flags = Code::cast(pair->get(1))->flags(); | 10106 Code::Flags flags = Code::cast(pair->get(1))->flags(); |
10296 if (flags != flags_) { | 10107 if (flags != flags_) return false; |
10297 return false; | 10108 DCHECK(name->IsUniqueName()); |
10298 } | 10109 return *name_ == name; |
10299 return name_->Equals(name); | |
10300 } | 10110 } |
10301 | 10111 |
10302 static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) { | 10112 static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) { |
10303 return name->Hash() ^ flags; | 10113 return name->Hash() ^ flags; |
10304 } | 10114 } |
10305 | 10115 |
10306 uint32_t Hash() override { return NameFlagsHashHelper(*name_, flags_); } | 10116 uint32_t Hash() override { return NameFlagsHashHelper(*name_, flags_); } |
10307 | 10117 |
10308 uint32_t HashForObject(Object* obj) override { | 10118 uint32_t HashForObject(Object* obj) override { |
10309 FixedArray* pair = FixedArray::cast(obj); | 10119 FixedArray* pair = FixedArray::cast(obj); |
(...skipping 11 matching lines...) Expand all Loading... |
10321 } | 10131 } |
10322 | 10132 |
10323 private: | 10133 private: |
10324 Handle<Name> name_; | 10134 Handle<Name> name_; |
10325 Code::Flags flags_; | 10135 Code::Flags flags_; |
10326 // TODO(jkummerow): We should be able to get by without this. | 10136 // TODO(jkummerow): We should be able to get by without this. |
10327 MaybeHandle<Code> code_; | 10137 MaybeHandle<Code> code_; |
10328 }; | 10138 }; |
10329 | 10139 |
10330 | 10140 |
10331 Object* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) { | |
10332 DisallowHeapAllocation no_alloc; | |
10333 CodeCacheHashTableKey key(handle(name), flags); | |
10334 int entry = FindEntry(&key); | |
10335 if (entry == kNotFound) return GetHeap()->undefined_value(); | |
10336 return get(EntryToIndex(entry) + 1); | |
10337 } | |
10338 | |
10339 | |
10340 Handle<CodeCacheHashTable> CodeCacheHashTable::Put( | 10141 Handle<CodeCacheHashTable> CodeCacheHashTable::Put( |
10341 Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) { | 10142 Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) { |
10342 CodeCacheHashTableKey key(name, code); | 10143 CodeCacheHashTableKey key(name, code); |
10343 | 10144 |
10344 Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key); | 10145 Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key); |
10345 | 10146 |
10346 int entry = new_cache->FindInsertionEntry(key.Hash()); | 10147 int entry = new_cache->FindInsertionEntry(key.Hash()); |
10347 Handle<Object> k = key.AsHandle(cache->GetIsolate()); | 10148 Handle<Object> k = key.AsHandle(cache->GetIsolate()); |
10348 | 10149 |
10349 new_cache->set(EntryToIndex(entry), *k); | 10150 new_cache->set(EntryToIndex(entry), *k); |
10350 new_cache->set(EntryToIndex(entry) + 1, *code); | |
10351 new_cache->ElementAdded(); | 10151 new_cache->ElementAdded(); |
10352 return new_cache; | 10152 return new_cache; |
10353 } | 10153 } |
10354 | 10154 |
10355 | 10155 Code* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) { |
10356 int CodeCacheHashTable::GetIndex(Name* name, Code::Flags flags) { | |
10357 DisallowHeapAllocation no_alloc; | 10156 DisallowHeapAllocation no_alloc; |
10358 CodeCacheHashTableKey key(handle(name), flags); | 10157 CodeCacheHashTableKey key(handle(name), flags); |
10359 int entry = FindEntry(&key); | 10158 int entry = FindEntry(&key); |
10360 return (entry == kNotFound) ? -1 : entry; | 10159 if (entry == kNotFound) return nullptr; |
| 10160 return Code::cast(FixedArray::cast(get(EntryToIndex(entry)))->get(1)); |
10361 } | 10161 } |
10362 | 10162 |
10363 | |
10364 void CodeCacheHashTable::RemoveByIndex(int index) { | |
10365 DCHECK(index >= 0); | |
10366 Heap* heap = GetHeap(); | |
10367 set(EntryToIndex(index), heap->the_hole_value()); | |
10368 set(EntryToIndex(index) + 1, heap->the_hole_value()); | |
10369 ElementRemoved(); | |
10370 } | |
10371 | |
10372 | |
10373 void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> code_cache, | |
10374 MapHandleList* maps, | |
10375 Code::Flags flags, | |
10376 Handle<Code> code) { | |
10377 Isolate* isolate = code_cache->GetIsolate(); | |
10378 if (code_cache->cache()->IsUndefined()) { | |
10379 Handle<PolymorphicCodeCacheHashTable> result = | |
10380 PolymorphicCodeCacheHashTable::New( | |
10381 isolate, | |
10382 PolymorphicCodeCacheHashTable::kInitialSize); | |
10383 code_cache->set_cache(*result); | |
10384 } else { | |
10385 // This entry shouldn't be contained in the cache yet. | |
10386 DCHECK(PolymorphicCodeCacheHashTable::cast(code_cache->cache()) | |
10387 ->Lookup(maps, flags)->IsUndefined()); | |
10388 } | |
10389 Handle<PolymorphicCodeCacheHashTable> hash_table = | |
10390 handle(PolymorphicCodeCacheHashTable::cast(code_cache->cache())); | |
10391 Handle<PolymorphicCodeCacheHashTable> new_cache = | |
10392 PolymorphicCodeCacheHashTable::Put(hash_table, maps, flags, code); | |
10393 code_cache->set_cache(*new_cache); | |
10394 } | |
10395 | |
10396 | |
10397 Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps, | |
10398 Code::Flags flags) { | |
10399 if (!cache()->IsUndefined()) { | |
10400 PolymorphicCodeCacheHashTable* hash_table = | |
10401 PolymorphicCodeCacheHashTable::cast(cache()); | |
10402 return Handle<Object>(hash_table->Lookup(maps, flags), GetIsolate()); | |
10403 } else { | |
10404 return GetIsolate()->factory()->undefined_value(); | |
10405 } | |
10406 } | |
10407 | |
10408 | |
10409 // Despite their name, object of this class are not stored in the actual | |
10410 // hash table; instead they're temporarily used for lookups. It is therefore | |
10411 // safe to have a weak (non-owning) pointer to a MapList as a member field. | |
10412 class PolymorphicCodeCacheHashTableKey : public HashTableKey { | |
10413 public: | |
10414 // Callers must ensure that |maps| outlives the newly constructed object. | |
10415 PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags) | |
10416 : maps_(maps), | |
10417 code_flags_(code_flags) {} | |
10418 | |
10419 bool IsMatch(Object* other) override { | |
10420 MapHandleList other_maps(kDefaultListAllocationSize); | |
10421 int other_flags; | |
10422 FromObject(other, &other_flags, &other_maps); | |
10423 if (code_flags_ != other_flags) return false; | |
10424 if (maps_->length() != other_maps.length()) return false; | |
10425 // Compare just the hashes first because it's faster. | |
10426 int this_hash = MapsHashHelper(maps_, code_flags_); | |
10427 int other_hash = MapsHashHelper(&other_maps, other_flags); | |
10428 if (this_hash != other_hash) return false; | |
10429 | |
10430 // Full comparison: for each map in maps_, look for an equivalent map in | |
10431 // other_maps. This implementation is slow, but probably good enough for | |
10432 // now because the lists are short (<= 4 elements currently). | |
10433 for (int i = 0; i < maps_->length(); ++i) { | |
10434 bool match_found = false; | |
10435 for (int j = 0; j < other_maps.length(); ++j) { | |
10436 if (*(maps_->at(i)) == *(other_maps.at(j))) { | |
10437 match_found = true; | |
10438 break; | |
10439 } | |
10440 } | |
10441 if (!match_found) return false; | |
10442 } | |
10443 return true; | |
10444 } | |
10445 | |
10446 static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) { | |
10447 uint32_t hash = code_flags; | |
10448 for (int i = 0; i < maps->length(); ++i) { | |
10449 hash ^= maps->at(i)->Hash(); | |
10450 } | |
10451 return hash; | |
10452 } | |
10453 | |
10454 uint32_t Hash() override { return MapsHashHelper(maps_, code_flags_); } | |
10455 | |
10456 uint32_t HashForObject(Object* obj) override { | |
10457 MapHandleList other_maps(kDefaultListAllocationSize); | |
10458 int other_flags; | |
10459 FromObject(obj, &other_flags, &other_maps); | |
10460 return MapsHashHelper(&other_maps, other_flags); | |
10461 } | |
10462 | |
10463 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override { | |
10464 // The maps in |maps_| must be copied to a newly allocated FixedArray, | |
10465 // both because the referenced MapList is short-lived, and because C++ | |
10466 // objects can't be stored in the heap anyway. | |
10467 Handle<FixedArray> list = | |
10468 isolate->factory()->NewUninitializedFixedArray(maps_->length() + 1); | |
10469 list->set(0, Smi::FromInt(code_flags_)); | |
10470 for (int i = 0; i < maps_->length(); ++i) { | |
10471 list->set(i + 1, *maps_->at(i)); | |
10472 } | |
10473 return list; | |
10474 } | |
10475 | |
10476 private: | |
10477 static MapHandleList* FromObject(Object* obj, | |
10478 int* code_flags, | |
10479 MapHandleList* maps) { | |
10480 FixedArray* list = FixedArray::cast(obj); | |
10481 maps->Rewind(0); | |
10482 *code_flags = Smi::cast(list->get(0))->value(); | |
10483 for (int i = 1; i < list->length(); ++i) { | |
10484 maps->Add(Handle<Map>(Map::cast(list->get(i)))); | |
10485 } | |
10486 return maps; | |
10487 } | |
10488 | |
10489 MapHandleList* maps_; // weak. | |
10490 int code_flags_; | |
10491 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1; | |
10492 }; | |
10493 | |
10494 | |
10495 Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps, | |
10496 int code_kind) { | |
10497 DisallowHeapAllocation no_alloc; | |
10498 PolymorphicCodeCacheHashTableKey key(maps, code_kind); | |
10499 int entry = FindEntry(&key); | |
10500 if (entry == kNotFound) return GetHeap()->undefined_value(); | |
10501 return get(EntryToIndex(entry) + 1); | |
10502 } | |
10503 | |
10504 | |
10505 Handle<PolymorphicCodeCacheHashTable> PolymorphicCodeCacheHashTable::Put( | |
10506 Handle<PolymorphicCodeCacheHashTable> hash_table, | |
10507 MapHandleList* maps, | |
10508 int code_kind, | |
10509 Handle<Code> code) { | |
10510 PolymorphicCodeCacheHashTableKey key(maps, code_kind); | |
10511 Handle<PolymorphicCodeCacheHashTable> cache = | |
10512 EnsureCapacity(hash_table, 1, &key); | |
10513 int entry = cache->FindInsertionEntry(key.Hash()); | |
10514 | |
10515 Handle<Object> obj = key.AsHandle(hash_table->GetIsolate()); | |
10516 cache->set(EntryToIndex(entry), *obj); | |
10517 cache->set(EntryToIndex(entry) + 1, *code); | |
10518 cache->ElementAdded(); | |
10519 return cache; | |
10520 } | |
10521 | |
10522 | |
10523 void FixedArray::Shrink(int new_length) { | 10163 void FixedArray::Shrink(int new_length) { |
10524 DCHECK(0 <= new_length && new_length <= length()); | 10164 DCHECK(0 <= new_length && new_length <= length()); |
10525 if (new_length < length()) { | 10165 if (new_length < length()) { |
10526 GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>( | 10166 GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>( |
10527 this, length() - new_length); | 10167 this, length() - new_length); |
10528 } | 10168 } |
10529 } | 10169 } |
10530 | 10170 |
10531 | 10171 |
10532 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) { | 10172 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) { |
(...skipping 4263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
14796 << handler_offset << " (prediction=" << prediction << ")\n"; | 14436 << handler_offset << " (prediction=" << prediction << ")\n"; |
14797 } | 14437 } |
14798 } | 14438 } |
14799 | 14439 |
14800 | 14440 |
14801 const char* Code::ICState2String(InlineCacheState state) { | 14441 const char* Code::ICState2String(InlineCacheState state) { |
14802 switch (state) { | 14442 switch (state) { |
14803 case UNINITIALIZED: return "UNINITIALIZED"; | 14443 case UNINITIALIZED: return "UNINITIALIZED"; |
14804 case PREMONOMORPHIC: return "PREMONOMORPHIC"; | 14444 case PREMONOMORPHIC: return "PREMONOMORPHIC"; |
14805 case MONOMORPHIC: return "MONOMORPHIC"; | 14445 case MONOMORPHIC: return "MONOMORPHIC"; |
14806 case PROTOTYPE_FAILURE: | 14446 case RECOMPUTE_HANDLER: |
14807 return "PROTOTYPE_FAILURE"; | 14447 return "RECOMPUTE_HANDLER"; |
14808 case POLYMORPHIC: return "POLYMORPHIC"; | 14448 case POLYMORPHIC: return "POLYMORPHIC"; |
14809 case MEGAMORPHIC: return "MEGAMORPHIC"; | 14449 case MEGAMORPHIC: return "MEGAMORPHIC"; |
14810 case GENERIC: return "GENERIC"; | 14450 case GENERIC: return "GENERIC"; |
14811 case DEBUG_STUB: return "DEBUG_STUB"; | 14451 case DEBUG_STUB: return "DEBUG_STUB"; |
14812 } | 14452 } |
14813 UNREACHABLE(); | 14453 UNREACHABLE(); |
14814 return NULL; | 14454 return NULL; |
14815 } | 14455 } |
14816 | 14456 |
14817 | 14457 |
14818 const char* Code::StubType2String(StubType type) { | |
14819 switch (type) { | |
14820 case NORMAL: return "NORMAL"; | |
14821 case FAST: return "FAST"; | |
14822 } | |
14823 UNREACHABLE(); // keep the compiler happy | |
14824 return NULL; | |
14825 } | |
14826 | |
14827 | |
14828 void Code::PrintExtraICState(std::ostream& os, // NOLINT | 14458 void Code::PrintExtraICState(std::ostream& os, // NOLINT |
14829 Kind kind, ExtraICState extra) { | 14459 Kind kind, ExtraICState extra) { |
14830 os << "extra_ic_state = "; | 14460 os << "extra_ic_state = "; |
14831 if ((kind == STORE_IC || kind == KEYED_STORE_IC) && | 14461 if ((kind == STORE_IC || kind == KEYED_STORE_IC) && |
14832 is_strict(static_cast<LanguageMode>(extra))) { | 14462 is_strict(static_cast<LanguageMode>(extra))) { |
14833 os << "STRICT\n"; | 14463 os << "STRICT\n"; |
14834 } else { | 14464 } else { |
14835 os << extra << "\n"; | 14465 os << extra << "\n"; |
14836 } | 14466 } |
14837 } | 14467 } |
14838 | 14468 |
14839 | 14469 |
14840 void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT | 14470 void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT |
14841 os << "kind = " << Kind2String(kind()) << "\n"; | 14471 os << "kind = " << Kind2String(kind()) << "\n"; |
14842 if (IsCodeStubOrIC()) { | 14472 if (IsCodeStubOrIC()) { |
14843 const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this)); | 14473 const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this)); |
14844 os << "major_key = " << (n == NULL ? "null" : n) << "\n"; | 14474 os << "major_key = " << (n == NULL ? "null" : n) << "\n"; |
14845 } | 14475 } |
14846 if (is_inline_cache_stub()) { | 14476 if (is_inline_cache_stub()) { |
14847 os << "ic_state = " << ICState2String(ic_state()) << "\n"; | 14477 os << "ic_state = " << ICState2String(ic_state()) << "\n"; |
14848 PrintExtraICState(os, kind(), extra_ic_state()); | 14478 PrintExtraICState(os, kind(), extra_ic_state()); |
14849 if (ic_state() == MONOMORPHIC) { | |
14850 os << "type = " << StubType2String(type()) << "\n"; | |
14851 } | |
14852 if (is_compare_ic_stub()) { | 14479 if (is_compare_ic_stub()) { |
14853 DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC); | 14480 DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC); |
14854 CompareICStub stub(stub_key(), GetIsolate()); | 14481 CompareICStub stub(stub_key(), GetIsolate()); |
14855 os << "compare_state = " << CompareICState::GetStateName(stub.left()) | 14482 os << "compare_state = " << CompareICState::GetStateName(stub.left()) |
14856 << "*" << CompareICState::GetStateName(stub.right()) << " -> " | 14483 << "*" << CompareICState::GetStateName(stub.right()) << " -> " |
14857 << CompareICState::GetStateName(stub.state()) << "\n"; | 14484 << CompareICState::GetStateName(stub.state()) << "\n"; |
14858 os << "compare_operation = " << Token::Name(stub.op()) << "\n"; | 14485 os << "compare_operation = " << Token::Name(stub.op()) << "\n"; |
14859 } | 14486 } |
14860 } | 14487 } |
14861 if ((name != nullptr) && (name[0] != '\0')) { | 14488 if ((name != nullptr) && (name[0] != '\0')) { |
(...skipping 2297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17159 | 16786 |
17160 // Copy prefix to new array. | 16787 // Copy prefix to new array. |
17161 for (int i = kPrefixStartIndex; | 16788 for (int i = kPrefixStartIndex; |
17162 i < kPrefixStartIndex + Shape::kPrefixSize; | 16789 i < kPrefixStartIndex + Shape::kPrefixSize; |
17163 i++) { | 16790 i++) { |
17164 new_table->set(i, get(i), mode); | 16791 new_table->set(i, get(i), mode); |
17165 } | 16792 } |
17166 | 16793 |
17167 // Rehash the elements. | 16794 // Rehash the elements. |
17168 int capacity = this->Capacity(); | 16795 int capacity = this->Capacity(); |
| 16796 Heap* heap = new_table->GetHeap(); |
| 16797 Object* the_hole = heap->the_hole_value(); |
| 16798 Object* undefined = heap->undefined_value(); |
17169 for (int i = 0; i < capacity; i++) { | 16799 for (int i = 0; i < capacity; i++) { |
17170 uint32_t from_index = EntryToIndex(i); | 16800 uint32_t from_index = EntryToIndex(i); |
17171 Object* k = this->get(from_index); | 16801 Object* k = this->get(from_index); |
17172 if (IsKey(k)) { | 16802 if (k != the_hole && k != undefined) { |
17173 uint32_t hash = this->HashForObject(key, k); | 16803 uint32_t hash = this->HashForObject(key, k); |
17174 uint32_t insertion_index = | 16804 uint32_t insertion_index = |
17175 EntryToIndex(new_table->FindInsertionEntry(hash)); | 16805 EntryToIndex(new_table->FindInsertionEntry(hash)); |
17176 for (int j = 0; j < Shape::kEntrySize; j++) { | 16806 for (int j = 0; j < Shape::kEntrySize; j++) { |
17177 new_table->set(insertion_index + j, get(from_index + j), mode); | 16807 new_table->set(insertion_index + j, get(from_index + j), mode); |
17178 } | 16808 } |
17179 } | 16809 } |
17180 } | 16810 } |
17181 new_table->SetNumberOfElements(NumberOfElements()); | 16811 new_table->SetNumberOfElements(NumberOfElements()); |
17182 new_table->SetNumberOfDeletedElements(0); | 16812 new_table->SetNumberOfDeletedElements(0); |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17326 return new_table; | 16956 return new_table; |
17327 } | 16957 } |
17328 | 16958 |
17329 | 16959 |
17330 template<typename Derived, typename Shape, typename Key> | 16960 template<typename Derived, typename Shape, typename Key> |
17331 uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) { | 16961 uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) { |
17332 uint32_t capacity = Capacity(); | 16962 uint32_t capacity = Capacity(); |
17333 uint32_t entry = FirstProbe(hash, capacity); | 16963 uint32_t entry = FirstProbe(hash, capacity); |
17334 uint32_t count = 1; | 16964 uint32_t count = 1; |
17335 // EnsureCapacity will guarantee the hash table is never full. | 16965 // EnsureCapacity will guarantee the hash table is never full. |
| 16966 Heap* heap = GetHeap(); |
| 16967 Object* the_hole = heap->the_hole_value(); |
| 16968 Object* undefined = heap->undefined_value(); |
17336 while (true) { | 16969 while (true) { |
17337 Object* element = KeyAt(entry); | 16970 Object* element = KeyAt(entry); |
17338 if (element->IsUndefined() || element->IsTheHole()) break; | 16971 if (element == the_hole || element == undefined) break; |
17339 entry = NextProbe(entry, count++, capacity); | 16972 entry = NextProbe(entry, count++, capacity); |
17340 } | 16973 } |
17341 return entry; | 16974 return entry; |
17342 } | 16975 } |
17343 | 16976 |
17344 | 16977 |
17345 // Force instantiation of template instances class. | 16978 // Force instantiation of template instances class. |
17346 // Please note this list is compiler dependent. | 16979 // Please note this list is compiler dependent. |
17347 | 16980 |
17348 template class HashTable<StringTable, StringTableShape, HashTableKey*>; | 16981 template class HashTable<StringTable, StringTableShape, HashTableKey*>; |
(...skipping 1463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
18812 // and point the bucket to the new entry. | 18445 // and point the bucket to the new entry. |
18813 table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry)); | 18446 table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry)); |
18814 table->SetNumberOfElements(nof + 1); | 18447 table->SetNumberOfElements(nof + 1); |
18815 return table; | 18448 return table; |
18816 } | 18449 } |
18817 | 18450 |
18818 | 18451 |
18819 template<class Derived, class Iterator, int entrysize> | 18452 template<class Derived, class Iterator, int entrysize> |
18820 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash( | 18453 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash( |
18821 Handle<Derived> table, int new_capacity) { | 18454 Handle<Derived> table, int new_capacity) { |
| 18455 Isolate* isolate = table->GetIsolate(); |
| 18456 Heap* heap = isolate->heap(); |
18822 DCHECK(!table->IsObsolete()); | 18457 DCHECK(!table->IsObsolete()); |
18823 | 18458 |
18824 Handle<Derived> new_table = | 18459 Handle<Derived> new_table = Allocate( |
18825 Allocate(table->GetIsolate(), | 18460 isolate, new_capacity, heap->InNewSpace(*table) ? NOT_TENURED : TENURED); |
18826 new_capacity, | |
18827 table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED); | |
18828 int nof = table->NumberOfElements(); | 18461 int nof = table->NumberOfElements(); |
18829 int nod = table->NumberOfDeletedElements(); | 18462 int nod = table->NumberOfDeletedElements(); |
18830 int new_buckets = new_table->NumberOfBuckets(); | 18463 int new_buckets = new_table->NumberOfBuckets(); |
18831 int new_entry = 0; | 18464 int new_entry = 0; |
18832 int removed_holes_index = 0; | 18465 int removed_holes_index = 0; |
18833 | 18466 |
| 18467 DisallowHeapAllocation no_gc; |
| 18468 Object* the_hole = heap->the_hole_value(); |
18834 for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) { | 18469 for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) { |
18835 Object* key = table->KeyAt(old_entry); | 18470 Object* key = table->KeyAt(old_entry); |
18836 if (key->IsTheHole()) { | 18471 if (key == the_hole) { |
18837 table->SetRemovedIndexAt(removed_holes_index++, old_entry); | 18472 table->SetRemovedIndexAt(removed_holes_index++, old_entry); |
18838 continue; | 18473 continue; |
18839 } | 18474 } |
18840 | 18475 |
18841 Object* hash = key->GetHash(); | 18476 Object* hash = key->GetHash(); |
18842 int bucket = Smi::cast(hash)->value() & (new_buckets - 1); | 18477 int bucket = Smi::cast(hash)->value() & (new_buckets - 1); |
18843 Object* chain_entry = new_table->get(kHashTableStartIndex + bucket); | 18478 Object* chain_entry = new_table->get(kHashTableStartIndex + bucket); |
18844 new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry)); | 18479 new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry)); |
18845 int new_index = new_table->EntryToIndex(new_entry); | 18480 int new_index = new_table->EntryToIndex(new_entry); |
18846 int old_index = table->EntryToIndex(old_entry); | 18481 int old_index = table->EntryToIndex(old_entry); |
(...skipping 916 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
19763 if (cell->value() != *new_value) { | 19398 if (cell->value() != *new_value) { |
19764 cell->set_value(*new_value); | 19399 cell->set_value(*new_value); |
19765 Isolate* isolate = cell->GetIsolate(); | 19400 Isolate* isolate = cell->GetIsolate(); |
19766 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 19401 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
19767 isolate, DependentCode::kPropertyCellChangedGroup); | 19402 isolate, DependentCode::kPropertyCellChangedGroup); |
19768 } | 19403 } |
19769 } | 19404 } |
19770 | 19405 |
19771 } // namespace internal | 19406 } // namespace internal |
19772 } // namespace v8 | 19407 } // namespace v8 |
OLD | NEW |