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