| 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 |