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 9429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9440 | 9440 |
9441 SimpleTransitionFlag simple_flag = | 9441 SimpleTransitionFlag simple_flag = |
9442 (insertion_index == descriptors->number_of_descriptors() - 1) | 9442 (insertion_index == descriptors->number_of_descriptors() - 1) |
9443 ? SIMPLE_PROPERTY_TRANSITION | 9443 ? SIMPLE_PROPERTY_TRANSITION |
9444 : PROPERTY_TRANSITION; | 9444 : PROPERTY_TRANSITION; |
9445 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor, | 9445 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor, |
9446 flag, key, "CopyReplaceDescriptor", | 9446 flag, key, "CopyReplaceDescriptor", |
9447 simple_flag); | 9447 simple_flag); |
9448 } | 9448 } |
9449 | 9449 |
| 9450 // Helper class to manage a Map's code cache. The layout depends on the number |
| 9451 // of entries; this is worthwhile because most code caches are very small, |
| 9452 // but some are huge (thousands of entries). |
| 9453 // For zero entries, the EmptyFixedArray is used. |
| 9454 // For one entry, we use a 2-element FixedArray containing [name, code]. |
| 9455 // For 2..100 entries, we use a FixedArray with linear lookups, the layout is: |
| 9456 // [0] - number of slots that are currently in use |
| 9457 // [1] - first name |
| 9458 // [2] - first code |
| 9459 // [3] - second name |
| 9460 // [4] - second code |
| 9461 // etc. |
| 9462 // For more than 128 entries, we use a CodeCacheHashTable. |
| 9463 class CodeCache : public AllStatic { |
| 9464 public: |
| 9465 // Returns the new cache, to be stored on the map. |
| 9466 static Handle<FixedArray> Put(Isolate* isolate, Handle<FixedArray> cache, |
| 9467 Handle<Name> name, Handle<Code> code) { |
| 9468 int length = cache->length(); |
| 9469 if (length == 0) return PutFirstElement(isolate, name, code); |
| 9470 if (length == kEntrySize) { |
| 9471 return PutSecondElement(isolate, cache, name, code); |
| 9472 } |
| 9473 if (length <= kLinearMaxSize) { |
| 9474 Handle<FixedArray> result = PutLinearElement(isolate, cache, name, code); |
| 9475 if (!result.is_null()) return result; |
| 9476 // Fall through if linear storage is getting too large. |
| 9477 } |
| 9478 return PutHashTableElement(isolate, cache, name, code); |
| 9479 } |
| 9480 |
| 9481 static Code* Lookup(FixedArray* cache, Name* name, Code::Flags flags) { |
| 9482 int length = cache->length(); |
| 9483 if (length == 0) return nullptr; |
| 9484 if (length == kEntrySize) return OneElementLookup(cache, name, flags); |
| 9485 if (!cache->IsCodeCacheHashTable()) { |
| 9486 return LinearLookup(cache, name, flags); |
| 9487 } else { |
| 9488 return CodeCacheHashTable::cast(cache)->Lookup(name, flags); |
| 9489 } |
| 9490 } |
| 9491 |
| 9492 private: |
| 9493 static const int kNameIndex = 0; |
| 9494 static const int kCodeIndex = 1; |
| 9495 static const int kEntrySize = 2; |
| 9496 |
| 9497 static const int kLinearUsageIndex = 0; |
| 9498 static const int kLinearReservedSlots = 1; |
| 9499 static const int kLinearInitialCapacity = 2; |
| 9500 static const int kLinearMaxSize = 257; // == LinearSizeFor(128); |
| 9501 |
| 9502 static const int kHashTableInitialCapacity = 200; // Number of entries. |
| 9503 |
| 9504 static int LinearSizeFor(int entries) { |
| 9505 return kLinearReservedSlots + kEntrySize * entries; |
| 9506 } |
| 9507 |
| 9508 static int LinearNewSize(int old_size) { |
| 9509 int old_entries = (old_size - kLinearReservedSlots) / kEntrySize; |
| 9510 return LinearSizeFor(old_entries * 2); |
| 9511 } |
| 9512 |
| 9513 static Code* OneElementLookup(FixedArray* cache, Name* name, |
| 9514 Code::Flags flags) { |
| 9515 DCHECK_EQ(cache->length(), kEntrySize); |
| 9516 if (cache->get(kNameIndex) != name) return nullptr; |
| 9517 Code* maybe_code = Code::cast(cache->get(kCodeIndex)); |
| 9518 if (maybe_code->flags() != flags) return nullptr; |
| 9519 return maybe_code; |
| 9520 } |
| 9521 |
| 9522 static Code* LinearLookup(FixedArray* cache, Name* name, Code::Flags flags) { |
| 9523 DCHECK_GE(cache->length(), kEntrySize); |
| 9524 DCHECK(!cache->IsCodeCacheHashTable()); |
| 9525 int usage = GetLinearUsage(cache); |
| 9526 for (int i = kLinearReservedSlots; i < usage; i += kEntrySize) { |
| 9527 if (cache->get(i + kNameIndex) != name) continue; |
| 9528 Code* code = Code::cast(cache->get(i + kCodeIndex)); |
| 9529 if (code->flags() == flags) return code; |
| 9530 } |
| 9531 return nullptr; |
| 9532 } |
| 9533 |
| 9534 static Handle<FixedArray> PutFirstElement(Isolate* isolate, Handle<Name> name, |
| 9535 Handle<Code> code) { |
| 9536 Handle<FixedArray> cache = isolate->factory()->NewFixedArray(kEntrySize); |
| 9537 cache->set(kNameIndex, *name); |
| 9538 cache->set(kCodeIndex, *code); |
| 9539 return cache; |
| 9540 } |
| 9541 |
| 9542 static Handle<FixedArray> PutSecondElement(Isolate* isolate, |
| 9543 Handle<FixedArray> cache, |
| 9544 Handle<Name> name, |
| 9545 Handle<Code> code) { |
| 9546 DCHECK_EQ(cache->length(), kEntrySize); |
| 9547 Handle<FixedArray> new_cache = isolate->factory()->NewFixedArray( |
| 9548 LinearSizeFor(kLinearInitialCapacity)); |
| 9549 new_cache->set(kLinearReservedSlots + kNameIndex, cache->get(kNameIndex)); |
| 9550 new_cache->set(kLinearReservedSlots + kCodeIndex, cache->get(kCodeIndex)); |
| 9551 new_cache->set(LinearSizeFor(1) + kNameIndex, *name); |
| 9552 new_cache->set(LinearSizeFor(1) + kCodeIndex, *code); |
| 9553 new_cache->set(kLinearUsageIndex, Smi::FromInt(LinearSizeFor(2))); |
| 9554 return new_cache; |
| 9555 } |
| 9556 |
| 9557 static Handle<FixedArray> PutLinearElement(Isolate* isolate, |
| 9558 Handle<FixedArray> cache, |
| 9559 Handle<Name> name, |
| 9560 Handle<Code> code) { |
| 9561 int length = cache->length(); |
| 9562 int usage = GetLinearUsage(*cache); |
| 9563 DCHECK_LE(usage, length); |
| 9564 // Check if we need to grow. |
| 9565 if (usage == length) { |
| 9566 int new_length = LinearNewSize(length); |
| 9567 if (new_length > kLinearMaxSize) return Handle<FixedArray>::null(); |
| 9568 Handle<FixedArray> new_cache = |
| 9569 isolate->factory()->NewFixedArray(new_length); |
| 9570 for (int i = kLinearReservedSlots; i < length; i++) { |
| 9571 new_cache->set(i, cache->get(i)); |
| 9572 } |
| 9573 cache = new_cache; |
| 9574 } |
| 9575 // Store new entry. |
| 9576 DCHECK_GE(cache->length(), usage + kEntrySize); |
| 9577 cache->set(usage + kNameIndex, *name); |
| 9578 cache->set(usage + kCodeIndex, *code); |
| 9579 cache->set(kLinearUsageIndex, Smi::FromInt(usage + kEntrySize)); |
| 9580 return cache; |
| 9581 } |
| 9582 |
| 9583 static Handle<FixedArray> PutHashTableElement(Isolate* isolate, |
| 9584 Handle<FixedArray> cache, |
| 9585 Handle<Name> name, |
| 9586 Handle<Code> code) { |
| 9587 // Check if we need to transition from linear to hash table storage. |
| 9588 if (!cache->IsCodeCacheHashTable()) { |
| 9589 // Check that the initial hash table capacity is large enough. |
| 9590 DCHECK_EQ(kLinearMaxSize, LinearSizeFor(128)); |
| 9591 STATIC_ASSERT(kHashTableInitialCapacity > 128); |
| 9592 |
| 9593 int length = cache->length(); |
| 9594 // Only migrate from linear storage when it's full. |
| 9595 DCHECK_EQ(length, GetLinearUsage(*cache)); |
| 9596 DCHECK_EQ(length, kLinearMaxSize); |
| 9597 Handle<CodeCacheHashTable> table = |
| 9598 CodeCacheHashTable::New(isolate, kHashTableInitialCapacity); |
| 9599 HandleScope scope(isolate); |
| 9600 for (int i = kLinearReservedSlots; i < length; i += kEntrySize) { |
| 9601 Handle<Name> old_name(Name::cast(cache->get(i + kNameIndex)), isolate); |
| 9602 Handle<Code> old_code(Code::cast(cache->get(i + kCodeIndex)), isolate); |
| 9603 CodeCacheHashTable::Put(table, old_name, old_code); |
| 9604 } |
| 9605 cache = table; |
| 9606 } |
| 9607 // Store new entry. |
| 9608 DCHECK(cache->IsCodeCacheHashTable()); |
| 9609 return CodeCacheHashTable::Put(Handle<CodeCacheHashTable>::cast(cache), |
| 9610 name, code); |
| 9611 } |
| 9612 |
| 9613 static inline int GetLinearUsage(FixedArray* linear_cache) { |
| 9614 DCHECK_GT(linear_cache->length(), kEntrySize); |
| 9615 return Smi::cast(linear_cache->get(kLinearUsageIndex))->value(); |
| 9616 } |
| 9617 }; |
9450 | 9618 |
9451 void Map::UpdateCodeCache(Handle<Map> map, | 9619 void Map::UpdateCodeCache(Handle<Map> map, |
9452 Handle<Name> name, | 9620 Handle<Name> name, |
9453 Handle<Code> code) { | 9621 Handle<Code> code) { |
9454 Isolate* isolate = map->GetIsolate(); | 9622 Isolate* isolate = map->GetIsolate(); |
9455 HandleScope scope(isolate); | 9623 Handle<FixedArray> cache(map->code_cache(), isolate); |
9456 // Allocate the code cache if not present. | 9624 Handle<FixedArray> new_cache = CodeCache::Put(isolate, cache, name, code); |
9457 if (!map->has_code_cache()) { | |
9458 Handle<Object> result = | |
9459 CodeCacheHashTable::New(isolate, CodeCacheHashTable::kInitialSize); | |
9460 map->set_code_cache(*result); | |
9461 } | |
9462 | |
9463 // Update the code cache. | |
9464 Handle<CodeCacheHashTable> cache(CodeCacheHashTable::cast(map->code_cache()), | |
9465 isolate); | |
9466 Handle<Object> new_cache = CodeCacheHashTable::Put(cache, name, code); | |
9467 map->set_code_cache(*new_cache); | 9625 map->set_code_cache(*new_cache); |
9468 } | 9626 } |
9469 | 9627 |
9470 Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) { | 9628 Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) { |
9471 if (!has_code_cache()) return nullptr; | 9629 return CodeCache::Lookup(code_cache(), name, flags); |
9472 return CodeCacheHashTable::cast(code_cache())->Lookup(name, flags); | |
9473 } | 9630 } |
9474 | 9631 |
9475 | 9632 |
9476 // The key in the code cache hash table consists of the property name and the | 9633 // The key in the code cache hash table consists of the property name and the |
9477 // code object. The actual match is on the name and the code flags. If a key | 9634 // code object. The actual match is on the name and the code flags. If a key |
9478 // is created using the flags and not a code object it can only be used for | 9635 // is created using the flags and not a code object it can only be used for |
9479 // lookup not to create a new entry. | 9636 // lookup not to create a new entry. |
9480 class CodeCacheHashTableKey : public HashTableKey { | 9637 class CodeCacheHashTableKey : public HashTableKey { |
9481 public: | 9638 public: |
9482 CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags) | 9639 CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags) |
(...skipping 9103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
18586 if (cell->value() != *new_value) { | 18743 if (cell->value() != *new_value) { |
18587 cell->set_value(*new_value); | 18744 cell->set_value(*new_value); |
18588 Isolate* isolate = cell->GetIsolate(); | 18745 Isolate* isolate = cell->GetIsolate(); |
18589 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 18746 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
18590 isolate, DependentCode::kPropertyCellChangedGroup); | 18747 isolate, DependentCode::kPropertyCellChangedGroup); |
18591 } | 18748 } |
18592 } | 18749 } |
18593 | 18750 |
18594 } // namespace internal | 18751 } // namespace internal |
18595 } // namespace v8 | 18752 } // namespace v8 |
OLD | NEW |