Commit ee9cc344 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[objects] Extract compilation-cache-table.cc

Rename files to match contents (src/objects/compilation-cache-table*),
and extract implementations from objects.cc into dedicated .cc file.

Bug: v8:8888
Change-Id: I02915316ee62186f94373b1859c7d8119a1953f1
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2516473
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Commit-Queue: Dominik Inführ <dinfuehr@chromium.org>
Auto-Submit: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70944}
parent 19463165
......@@ -2868,8 +2868,9 @@ v8_source_set("v8_base_without_compiler") {
"src/objects/code-kind.h",
"src/objects/code.cc",
"src/objects/code.h",
"src/objects/compilation-cache-inl.h",
"src/objects/compilation-cache.h",
"src/objects/compilation-cache-table-inl.h",
"src/objects/compilation-cache-table.cc",
"src/objects/compilation-cache-table.h",
"src/objects/compressed-slots-inl.h",
"src/objects/compressed-slots.h",
"src/objects/contexts-inl.h",
......
......@@ -8,7 +8,7 @@
#include "src/heap/factory.h"
#include "src/logging/counters.h"
#include "src/logging/log.h"
#include "src/objects/compilation-cache-inl.h"
#include "src/objects/compilation-cache-table-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/slots.h"
#include "src/objects/visitors.h"
......
......@@ -6,7 +6,7 @@
#define V8_CODEGEN_COMPILATION_CACHE_H_
#include "src/base/hashmap.h"
#include "src/objects/compilation-cache.h"
#include "src/objects/compilation-cache-table.h"
#include "src/utils/allocation.h"
namespace v8 {
......
......@@ -16,7 +16,7 @@
#include "src/heap/heap-inl.h"
#include "src/heap/mark-compact.h"
#include "src/logging/counters.h"
#include "src/objects/compilation-cache-inl.h"
#include "src/objects/compilation-cache-table-inl.h"
#include "src/objects/heap-object.h"
#include "src/objects/js-array-inl.h"
#include "src/objects/js-collection-inl.h"
......
......@@ -16,7 +16,7 @@
#include "src/objects/bigint-inl.h"
#include "src/objects/cell-inl.h"
#include "src/objects/code-inl.h"
#include "src/objects/compilation-cache-inl.h"
#include "src/objects/compilation-cache-table-inl.h"
#include "src/objects/compressed-slots-inl.h"
#include "src/objects/contexts-inl.h"
#include "src/objects/data-handler-inl.h"
......
......@@ -2,11 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_OBJECTS_COMPILATION_CACHE_INL_H_
#define V8_OBJECTS_COMPILATION_CACHE_INL_H_
#include "src/objects/compilation-cache.h"
#ifndef V8_OBJECTS_COMPILATION_CACHE_TABLE_INL_H_
#define V8_OBJECTS_COMPILATION_CACHE_TABLE_INL_H_
#include "src/objects/compilation-cache-table.h"
#include "src/objects/name-inl.h"
#include "src/objects/script-inl.h"
#include "src/objects/shared-function-info.h"
......@@ -93,4 +92,4 @@ InfoCellPair::InfoCellPair(Isolate* isolate, SharedFunctionInfo shared,
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_COMPILATION_CACHE_INL_H_
#endif // V8_OBJECTS_COMPILATION_CACHE_TABLE_INL_H_
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/objects/compilation-cache-table.h"
#include "src/objects/compilation-cache-table-inl.h"
namespace v8 {
namespace internal {
namespace {
const int kLiteralEntryLength = 2;
const int kLiteralInitialLength = 2;
const int kLiteralContextOffset = 0;
const int kLiteralLiteralsOffset = 1;
int SearchLiteralsMapEntry(CompilationCacheTable cache, int cache_entry,
Context native_context) {
DisallowHeapAllocation no_gc;
DCHECK(native_context.IsNativeContext());
Object obj = cache.get(cache_entry);
// Check that there's no confusion between FixedArray and WeakFixedArray (the
// object used to be a FixedArray here).
DCHECK(!obj.IsFixedArray());
if (obj.IsWeakFixedArray()) {
WeakFixedArray literals_map = WeakFixedArray::cast(obj);
int length = literals_map.length();
for (int i = 0; i < length; i += kLiteralEntryLength) {
DCHECK(literals_map.Get(i + kLiteralContextOffset)->IsWeakOrCleared());
if (literals_map.Get(i + kLiteralContextOffset) ==
HeapObjectReference::Weak(native_context)) {
return i;
}
}
}
return -1;
}
void AddToFeedbackCellsMap(Handle<CompilationCacheTable> cache, int cache_entry,
Handle<Context> native_context,
Handle<FeedbackCell> feedback_cell) {
Isolate* isolate = native_context->GetIsolate();
DCHECK(native_context->IsNativeContext());
STATIC_ASSERT(kLiteralEntryLength == 2);
Handle<WeakFixedArray> new_literals_map;
int entry;
Object obj = cache->get(cache_entry);
// Check that there's no confusion between FixedArray and WeakFixedArray (the
// object used to be a FixedArray here).
DCHECK(!obj.IsFixedArray());
if (!obj.IsWeakFixedArray() || WeakFixedArray::cast(obj).length() == 0) {
new_literals_map = isolate->factory()->NewWeakFixedArray(
kLiteralInitialLength, AllocationType::kOld);
entry = 0;
} else {
Handle<WeakFixedArray> old_literals_map(WeakFixedArray::cast(obj), isolate);
entry = SearchLiteralsMapEntry(*cache, cache_entry, *native_context);
if (entry >= 0) {
// Just set the code of the entry.
old_literals_map->Set(entry + kLiteralLiteralsOffset,
HeapObjectReference::Weak(*feedback_cell));
return;
}
// Can we reuse an entry?
DCHECK_LT(entry, 0);
int length = old_literals_map->length();
for (int i = 0; i < length; i += kLiteralEntryLength) {
if (old_literals_map->Get(i + kLiteralContextOffset)->IsCleared()) {
new_literals_map = old_literals_map;
entry = i;
break;
}
}
if (entry < 0) {
// Copy old optimized code map and append one new entry.
new_literals_map = isolate->factory()->CopyWeakFixedArrayAndGrow(
old_literals_map, kLiteralEntryLength);
entry = old_literals_map->length();
}
}
new_literals_map->Set(entry + kLiteralContextOffset,
HeapObjectReference::Weak(*native_context));
new_literals_map->Set(entry + kLiteralLiteralsOffset,
HeapObjectReference::Weak(*feedback_cell));
#ifdef DEBUG
for (int i = 0; i < new_literals_map->length(); i += kLiteralEntryLength) {
MaybeObject object = new_literals_map->Get(i + kLiteralContextOffset);
DCHECK(object->IsCleared() ||
object->GetHeapObjectAssumeWeak().IsNativeContext());
object = new_literals_map->Get(i + kLiteralLiteralsOffset);
DCHECK(object->IsCleared() ||
object->GetHeapObjectAssumeWeak().IsFeedbackCell());
}
#endif
Object old_literals_map = cache->get(cache_entry);
if (old_literals_map != *new_literals_map) {
cache->set(cache_entry, *new_literals_map);
}
}
FeedbackCell SearchLiteralsMap(CompilationCacheTable cache, int cache_entry,
Context native_context) {
FeedbackCell result;
int entry = SearchLiteralsMapEntry(cache, cache_entry, native_context);
if (entry >= 0) {
WeakFixedArray literals_map = WeakFixedArray::cast(cache.get(cache_entry));
DCHECK_LE(entry + kLiteralEntryLength, literals_map.length());
MaybeObject object = literals_map.Get(entry + kLiteralLiteralsOffset);
if (!object->IsCleared()) {
result = FeedbackCell::cast(object->GetHeapObjectAssumeWeak());
}
}
DCHECK(result.is_null() || result.IsFeedbackCell());
return result;
}
// StringSharedKeys are used as keys in the eval cache.
class StringSharedKey : public HashTableKey {
public:
// This tuple unambiguously identifies calls to eval() or
// CreateDynamicFunction() (such as through the Function() constructor).
// * source is the string passed into eval(). For dynamic functions, this is
// the effective source for the function, some of which is implicitly
// generated.
// * shared is the shared function info for the function containing the call
// to eval(). for dynamic functions, shared is the native context closure.
// * When positive, position is the position in the source where eval is
// called. When negative, position is the negation of the position in the
// dynamic function's effective source where the ')' ends the parameters.
StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
LanguageMode language_mode, int position)
: HashTableKey(CompilationCacheShape::StringSharedHash(
*source, *shared, language_mode, position)),
source_(source),
shared_(shared),
language_mode_(language_mode),
position_(position) {}
bool IsMatch(Object other) override {
DisallowHeapAllocation no_allocation;
if (!other.IsFixedArray()) {
DCHECK(other.IsNumber());
uint32_t other_hash = static_cast<uint32_t>(other.Number());
return Hash() == other_hash;
}
FixedArray other_array = FixedArray::cast(other);
SharedFunctionInfo shared = SharedFunctionInfo::cast(other_array.get(0));
if (shared != *shared_) return false;
int language_unchecked = Smi::ToInt(other_array.get(2));
DCHECK(is_valid_language_mode(language_unchecked));
LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
if (language_mode != language_mode_) return false;
int position = Smi::ToInt(other_array.get(3));
if (position != position_) return false;
String source = String::cast(other_array.get(1));
return source.Equals(*source_);
}
Handle<Object> AsHandle(Isolate* isolate) {
Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
array->set(0, *shared_);
array->set(1, *source_);
array->set(2, Smi::FromEnum(language_mode_));
array->set(3, Smi::FromInt(position_));
array->set_map(ReadOnlyRoots(isolate).fixed_cow_array_map());
return array;
}
private:
Handle<String> source_;
Handle<SharedFunctionInfo> shared_;
LanguageMode language_mode_;
int position_;
};
// RegExpKey carries the source and flags of a regular expression as key.
class RegExpKey : public HashTableKey {
public:
RegExpKey(Handle<String> string, JSRegExp::Flags flags)
: HashTableKey(
CompilationCacheShape::RegExpHash(*string, Smi::FromInt(flags))),
string_(string),
flags_(Smi::FromInt(flags)) {}
// Rather than storing the key in the hash table, a pointer to the
// stored value is stored where the key should be. IsMatch then
// compares the search key to the found object, rather than comparing
// a key to a key.
bool IsMatch(Object obj) override {
FixedArray val = FixedArray::cast(obj);
return string_->Equals(String::cast(val.get(JSRegExp::kSourceIndex))) &&
(flags_ == val.get(JSRegExp::kFlagsIndex));
}
Handle<String> string_;
Smi flags_;
};
// CodeKey carries the SharedFunctionInfo key associated with a Code
// object value.
class CodeKey : public HashTableKey {
public:
explicit CodeKey(Handle<SharedFunctionInfo> key)
: HashTableKey(key->Hash()), key_(key) {}
bool IsMatch(Object string) override { return *key_ == string; }
Handle<SharedFunctionInfo> key_;
};
} // namespace
MaybeHandle<SharedFunctionInfo> CompilationCacheTable::LookupScript(
Handle<CompilationCacheTable> table, Handle<String> src,
Handle<Context> native_context, LanguageMode language_mode) {
// We use the empty function SFI as part of the key. Although the
// empty_function is native context dependent, the SFI is de-duped on
// snapshot builds by the StartupObjectCache, and so this does not prevent
// reuse of scripts in the compilation cache across native contexts.
Handle<SharedFunctionInfo> shared(native_context->empty_function().shared(),
native_context->GetIsolate());
Isolate* isolate = native_context->GetIsolate();
src = String::Flatten(isolate, src);
StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
InternalIndex entry = table->FindEntry(isolate, &key);
if (entry.is_not_found()) return MaybeHandle<SharedFunctionInfo>();
int index = EntryToIndex(entry);
if (!table->get(index).IsFixedArray()) {
return MaybeHandle<SharedFunctionInfo>();
}
Object obj = table->get(index + 1);
if (obj.IsSharedFunctionInfo()) {
return handle(SharedFunctionInfo::cast(obj), native_context->GetIsolate());
}
return MaybeHandle<SharedFunctionInfo>();
}
InfoCellPair CompilationCacheTable::LookupEval(
Handle<CompilationCacheTable> table, Handle<String> src,
Handle<SharedFunctionInfo> outer_info, Handle<Context> native_context,
LanguageMode language_mode, int position) {
InfoCellPair empty_result;
Isolate* isolate = native_context->GetIsolate();
src = String::Flatten(isolate, src);
StringSharedKey key(src, outer_info, language_mode, position);
InternalIndex entry = table->FindEntry(isolate, &key);
if (entry.is_not_found()) return empty_result;
int index = EntryToIndex(entry);
if (!table->get(index).IsFixedArray()) return empty_result;
Object obj = table->get(index + 1);
if (obj.IsSharedFunctionInfo()) {
FeedbackCell feedback_cell =
SearchLiteralsMap(*table, index + 2, *native_context);
return InfoCellPair(isolate, SharedFunctionInfo::cast(obj), feedback_cell);
}
return empty_result;
}
Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
JSRegExp::Flags flags) {
Isolate* isolate = GetIsolate();
DisallowHeapAllocation no_allocation;
RegExpKey key(src, flags);
InternalIndex entry = FindEntry(isolate, &key);
if (entry.is_not_found()) return isolate->factory()->undefined_value();
return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
}
MaybeHandle<Code> CompilationCacheTable::LookupCode(
Handle<SharedFunctionInfo> key) {
Isolate* isolate = GetIsolate();
DisallowHeapAllocation no_allocation;
CodeKey k(key);
InternalIndex entry = FindEntry(isolate, &k);
if (entry.is_not_found()) return {};
return Handle<Code>(Code::cast(get(EntryToIndex(entry) + 1)), isolate);
}
Handle<CompilationCacheTable> CompilationCacheTable::PutScript(
Handle<CompilationCacheTable> cache, Handle<String> src,
Handle<Context> native_context, LanguageMode language_mode,
Handle<SharedFunctionInfo> value) {
Isolate* isolate = native_context->GetIsolate();
// We use the empty function SFI as part of the key. Although the
// empty_function is native context dependent, the SFI is de-duped on
// snapshot builds by the StartupObjectCache, and so this does not prevent
// reuse of scripts in the compilation cache across native contexts.
Handle<SharedFunctionInfo> shared(native_context->empty_function().shared(),
isolate);
src = String::Flatten(isolate, src);
StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
Handle<Object> k = key.AsHandle(isolate);
cache = EnsureCapacity(isolate, cache);
InternalIndex entry = cache->FindInsertionEntry(isolate, key.Hash());
cache->set(EntryToIndex(entry), *k);
cache->set(EntryToIndex(entry) + 1, *value);
cache->ElementAdded();
return cache;
}
Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
Handle<CompilationCacheTable> cache, Handle<String> src,
Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
Handle<Context> native_context, Handle<FeedbackCell> feedback_cell,
int position) {
Isolate* isolate = native_context->GetIsolate();
src = String::Flatten(isolate, src);
StringSharedKey key(src, outer_info, value->language_mode(), position);
{
Handle<Object> k = key.AsHandle(isolate);
InternalIndex entry = cache->FindEntry(isolate, &key);
if (entry.is_found()) {
cache->set(EntryToIndex(entry), *k);
cache->set(EntryToIndex(entry) + 1, *value);
// AddToFeedbackCellsMap may allocate a new sub-array to live in the
// entry, but it won't change the cache array. Therefore EntryToIndex
// and entry remains correct.
AddToFeedbackCellsMap(cache, EntryToIndex(entry) + 2, native_context,
feedback_cell);
// Add hash again even on cache hit to avoid unnecessary cache delay in
// case of hash collisions.
}
}
cache = EnsureCapacity(isolate, cache);
InternalIndex entry = cache->FindInsertionEntry(isolate, key.Hash());
Handle<Object> k =
isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
cache->set(EntryToIndex(entry), *k);
cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
cache->ElementAdded();
return cache;
}
Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
Isolate* isolate, Handle<CompilationCacheTable> cache, Handle<String> src,
JSRegExp::Flags flags, Handle<FixedArray> value) {
RegExpKey key(src, flags);
cache = EnsureCapacity(isolate, cache);
InternalIndex entry = cache->FindInsertionEntry(isolate, key.Hash());
// We store the value in the key slot, and compare the search key
// to the stored value with a custom IsMatch function during lookups.
cache->set(EntryToIndex(entry), *value);
cache->set(EntryToIndex(entry) + 1, *value);
cache->ElementAdded();
return cache;
}
Handle<CompilationCacheTable> CompilationCacheTable::PutCode(
Isolate* isolate, Handle<CompilationCacheTable> cache,
Handle<SharedFunctionInfo> key, Handle<Code> value) {
CodeKey k(key);
{
InternalIndex entry = cache->FindEntry(isolate, &k);
if (entry.is_found()) {
// Update.
cache->set(EntryToIndex(entry), *key);
cache->set(EntryToIndex(entry) + 1, *value);
return cache;
}
}
// Insert.
cache = EnsureCapacity(isolate, cache);
InternalIndex entry = cache->FindInsertionEntry(isolate, k.Hash());
cache->set(EntryToIndex(entry), *key);
cache->set(EntryToIndex(entry) + 1, *value);
cache->ElementAdded();
return cache;
}
void CompilationCacheTable::Age() {
DisallowHeapAllocation no_allocation;
Object the_hole_value = GetReadOnlyRoots().the_hole_value();
for (InternalIndex entry : IterateEntries()) {
int entry_index = EntryToIndex(entry);
int value_index = entry_index + 1;
if (get(entry_index).IsNumber()) {
Smi count = Smi::cast(get(value_index));
count = Smi::FromInt(count.value() - 1);
if (count.value() == 0) {
NoWriteBarrierSet(*this, entry_index, the_hole_value);
NoWriteBarrierSet(*this, value_index, the_hole_value);
ElementRemoved();
} else {
NoWriteBarrierSet(*this, value_index, count);
}
} else if (get(entry_index).IsFixedArray()) {
SharedFunctionInfo info = SharedFunctionInfo::cast(get(value_index));
if (info.IsInterpreted() && info.GetBytecodeArray().IsOld()) {
for (int i = 0; i < kEntrySize; i++) {
NoWriteBarrierSet(*this, entry_index + i, the_hole_value);
}
ElementRemoved();
}
}
}
}
void CompilationCacheTable::Remove(Object value) {
DisallowHeapAllocation no_allocation;
Object the_hole_value = GetReadOnlyRoots().the_hole_value();
for (InternalIndex entry : IterateEntries()) {
int entry_index = EntryToIndex(entry);
int value_index = entry_index + 1;
if (get(value_index) == value) {
for (int i = 0; i < kEntrySize; i++) {
NoWriteBarrierSet(*this, entry_index + i, the_hole_value);
}
ElementRemoved();
}
}
}
} // namespace internal
} // namespace v8
......@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_OBJECTS_COMPILATION_CACHE_H_
#define V8_OBJECTS_COMPILATION_CACHE_H_
#ifndef V8_OBJECTS_COMPILATION_CACHE_TABLE_H_
#define V8_OBJECTS_COMPILATION_CACHE_TABLE_H_
#include "src/objects/feedback-cell.h"
#include "src/objects/hash-table.h"
......@@ -136,4 +136,4 @@ class CompilationCacheTable
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_COMPILATION_CACHE_H_
#endif // V8_OBJECTS_COMPILATION_CACHE_TABLE_H_
......@@ -51,7 +51,7 @@
#include "src/objects/bigint.h"
#include "src/objects/cell-inl.h"
#include "src/objects/code-inl.h"
#include "src/objects/compilation-cache-inl.h"
#include "src/objects/compilation-cache-table-inl.h"
#include "src/objects/debug-objects-inl.h"
#include "src/objects/elements.h"
#include "src/objects/embedder-data-array-inl.h"
......@@ -5226,65 +5226,6 @@ void Symbol::SymbolShortPrint(std::ostream& os) {
os << ">";
}
// StringSharedKeys are used as keys in the eval cache.
class StringSharedKey : public HashTableKey {
public:
// This tuple unambiguously identifies calls to eval() or
// CreateDynamicFunction() (such as through the Function() constructor).
// * source is the string passed into eval(). For dynamic functions, this is
// the effective source for the function, some of which is implicitly
// generated.
// * shared is the shared function info for the function containing the call
// to eval(). for dynamic functions, shared is the native context closure.
// * When positive, position is the position in the source where eval is
// called. When negative, position is the negation of the position in the
// dynamic function's effective source where the ')' ends the parameters.
StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
LanguageMode language_mode, int position)
: HashTableKey(CompilationCacheShape::StringSharedHash(
*source, *shared, language_mode, position)),
source_(source),
shared_(shared),
language_mode_(language_mode),
position_(position) {}
bool IsMatch(Object other) override {
DisallowHeapAllocation no_allocation;
if (!other.IsFixedArray()) {
DCHECK(other.IsNumber());
uint32_t other_hash = static_cast<uint32_t>(other.Number());
return Hash() == other_hash;
}
FixedArray other_array = FixedArray::cast(other);
SharedFunctionInfo shared = SharedFunctionInfo::cast(other_array.get(0));
if (shared != *shared_) return false;
int language_unchecked = Smi::ToInt(other_array.get(2));
DCHECK(is_valid_language_mode(language_unchecked));
LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
if (language_mode != language_mode_) return false;
int position = Smi::ToInt(other_array.get(3));
if (position != position_) return false;
String source = String::cast(other_array.get(1));
return source.Equals(*source_);
}
Handle<Object> AsHandle(Isolate* isolate) {
Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
array->set(0, *shared_);
array->set(1, *source_);
array->set(2, Smi::FromEnum(language_mode_));
array->set(3, Smi::FromInt(position_));
array->set_map(ReadOnlyRoots(isolate).fixed_cow_array_map());
return array;
}
private:
Handle<String> source_;
Handle<SharedFunctionInfo> shared_;
LanguageMode language_mode_;
int position_;
};
v8::Promise::PromiseState JSPromise::status() const {
int value = flags() & StatusBits::kMask;
DCHECK(value == 0 || value == 1 || value == 2);
......@@ -5602,41 +5543,6 @@ Handle<Object> JSPromise::TriggerPromiseReactions(Isolate* isolate,
return isolate->factory()->undefined_value();
}
// RegExpKey carries the source and flags of a regular expression as key.
class RegExpKey : public HashTableKey {
public:
RegExpKey(Handle<String> string, JSRegExp::Flags flags)
: HashTableKey(
CompilationCacheShape::RegExpHash(*string, Smi::FromInt(flags))),
string_(string),
flags_(Smi::FromInt(flags)) {}
// Rather than storing the key in the hash table, a pointer to the
// stored value is stored where the key should be. IsMatch then
// compares the search key to the found object, rather than comparing
// a key to a key.
bool IsMatch(Object obj) override {
FixedArray val = FixedArray::cast(obj);
return string_->Equals(String::cast(val.get(JSRegExp::kSourceIndex))) &&
(flags_ == val.get(JSRegExp::kFlagsIndex));
}
Handle<String> string_;
Smi flags_;
};
// CodeKey carries the SharedFunctionInfo key associated with a Code
// object value.
class CodeKey : public HashTableKey {
public:
explicit CodeKey(Handle<SharedFunctionInfo> key)
: HashTableKey(key->Hash()), key_(key) {}
bool IsMatch(Object string) override { return *key_ == string; }
Handle<SharedFunctionInfo> key_;
};
template <typename Derived, typename Shape>
void HashTable<Derived, Shape>::IteratePrefix(ObjectVisitor* v) {
BodyDescriptorBase::IteratePointers(*this, 0, kElementsStartOffset, v);
......@@ -5931,328 +5837,6 @@ Handle<ObjectHashSet> ObjectHashSet::Add(Isolate* isolate,
return set;
}
namespace {
const int kLiteralEntryLength = 2;
const int kLiteralInitialLength = 2;
const int kLiteralContextOffset = 0;
const int kLiteralLiteralsOffset = 1;
int SearchLiteralsMapEntry(CompilationCacheTable cache, int cache_entry,
Context native_context) {
DisallowHeapAllocation no_gc;
DCHECK(native_context.IsNativeContext());
Object obj = cache.get(cache_entry);
// Check that there's no confusion between FixedArray and WeakFixedArray (the
// object used to be a FixedArray here).
DCHECK(!obj.IsFixedArray());
if (obj.IsWeakFixedArray()) {
WeakFixedArray literals_map = WeakFixedArray::cast(obj);
int length = literals_map.length();
for (int i = 0; i < length; i += kLiteralEntryLength) {
DCHECK(literals_map.Get(i + kLiteralContextOffset)->IsWeakOrCleared());
if (literals_map.Get(i + kLiteralContextOffset) ==
HeapObjectReference::Weak(native_context)) {
return i;
}
}
}
return -1;
}
void AddToFeedbackCellsMap(Handle<CompilationCacheTable> cache, int cache_entry,
Handle<Context> native_context,
Handle<FeedbackCell> feedback_cell) {
Isolate* isolate = native_context->GetIsolate();
DCHECK(native_context->IsNativeContext());
STATIC_ASSERT(kLiteralEntryLength == 2);
Handle<WeakFixedArray> new_literals_map;
int entry;
Object obj = cache->get(cache_entry);
// Check that there's no confusion between FixedArray and WeakFixedArray (the
// object used to be a FixedArray here).
DCHECK(!obj.IsFixedArray());
if (!obj.IsWeakFixedArray() || WeakFixedArray::cast(obj).length() == 0) {
new_literals_map = isolate->factory()->NewWeakFixedArray(
kLiteralInitialLength, AllocationType::kOld);
entry = 0;
} else {
Handle<WeakFixedArray> old_literals_map(WeakFixedArray::cast(obj), isolate);
entry = SearchLiteralsMapEntry(*cache, cache_entry, *native_context);
if (entry >= 0) {
// Just set the code of the entry.
old_literals_map->Set(entry + kLiteralLiteralsOffset,
HeapObjectReference::Weak(*feedback_cell));
return;
}
// Can we reuse an entry?
DCHECK_LT(entry, 0);
int length = old_literals_map->length();
for (int i = 0; i < length; i += kLiteralEntryLength) {
if (old_literals_map->Get(i + kLiteralContextOffset)->IsCleared()) {
new_literals_map = old_literals_map;
entry = i;
break;
}
}
if (entry < 0) {
// Copy old optimized code map and append one new entry.
new_literals_map = isolate->factory()->CopyWeakFixedArrayAndGrow(
old_literals_map, kLiteralEntryLength);
entry = old_literals_map->length();
}
}
new_literals_map->Set(entry + kLiteralContextOffset,
HeapObjectReference::Weak(*native_context));
new_literals_map->Set(entry + kLiteralLiteralsOffset,
HeapObjectReference::Weak(*feedback_cell));
#ifdef DEBUG
for (int i = 0; i < new_literals_map->length(); i += kLiteralEntryLength) {
MaybeObject object = new_literals_map->Get(i + kLiteralContextOffset);
DCHECK(object->IsCleared() ||
object->GetHeapObjectAssumeWeak().IsNativeContext());
object = new_literals_map->Get(i + kLiteralLiteralsOffset);
DCHECK(object->IsCleared() ||
object->GetHeapObjectAssumeWeak().IsFeedbackCell());
}
#endif
Object old_literals_map = cache->get(cache_entry);
if (old_literals_map != *new_literals_map) {
cache->set(cache_entry, *new_literals_map);
}
}
FeedbackCell SearchLiteralsMap(CompilationCacheTable cache, int cache_entry,
Context native_context) {
FeedbackCell result;
int entry = SearchLiteralsMapEntry(cache, cache_entry, native_context);
if (entry >= 0) {
WeakFixedArray literals_map = WeakFixedArray::cast(cache.get(cache_entry));
DCHECK_LE(entry + kLiteralEntryLength, literals_map.length());
MaybeObject object = literals_map.Get(entry + kLiteralLiteralsOffset);
if (!object->IsCleared()) {
result = FeedbackCell::cast(object->GetHeapObjectAssumeWeak());
}
}
DCHECK(result.is_null() || result.IsFeedbackCell());
return result;
}
} // namespace
MaybeHandle<SharedFunctionInfo> CompilationCacheTable::LookupScript(
Handle<CompilationCacheTable> table, Handle<String> src,
Handle<Context> native_context, LanguageMode language_mode) {
// We use the empty function SFI as part of the key. Although the
// empty_function is native context dependent, the SFI is de-duped on
// snapshot builds by the StartupObjectCache, and so this does not prevent
// reuse of scripts in the compilation cache across native contexts.
Handle<SharedFunctionInfo> shared(native_context->empty_function().shared(),
native_context->GetIsolate());
Isolate* isolate = native_context->GetIsolate();
src = String::Flatten(isolate, src);
StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
InternalIndex entry = table->FindEntry(isolate, &key);
if (entry.is_not_found()) return MaybeHandle<SharedFunctionInfo>();
int index = EntryToIndex(entry);
if (!table->get(index).IsFixedArray()) {
return MaybeHandle<SharedFunctionInfo>();
}
Object obj = table->get(index + 1);
if (obj.IsSharedFunctionInfo()) {
return handle(SharedFunctionInfo::cast(obj), native_context->GetIsolate());
}
return MaybeHandle<SharedFunctionInfo>();
}
InfoCellPair CompilationCacheTable::LookupEval(
Handle<CompilationCacheTable> table, Handle<String> src,
Handle<SharedFunctionInfo> outer_info, Handle<Context> native_context,
LanguageMode language_mode, int position) {
InfoCellPair empty_result;
Isolate* isolate = native_context->GetIsolate();
src = String::Flatten(isolate, src);
StringSharedKey key(src, outer_info, language_mode, position);
InternalIndex entry = table->FindEntry(isolate, &key);
if (entry.is_not_found()) return empty_result;
int index = EntryToIndex(entry);
if (!table->get(index).IsFixedArray()) return empty_result;
Object obj = table->get(index + 1);
if (obj.IsSharedFunctionInfo()) {
FeedbackCell feedback_cell =
SearchLiteralsMap(*table, index + 2, *native_context);
return InfoCellPair(isolate, SharedFunctionInfo::cast(obj), feedback_cell);
}
return empty_result;
}
Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
JSRegExp::Flags flags) {
Isolate* isolate = GetIsolate();
DisallowHeapAllocation no_allocation;
RegExpKey key(src, flags);
InternalIndex entry = FindEntry(isolate, &key);
if (entry.is_not_found()) return isolate->factory()->undefined_value();
return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
}
MaybeHandle<Code> CompilationCacheTable::LookupCode(
Handle<SharedFunctionInfo> key) {
Isolate* isolate = GetIsolate();
DisallowHeapAllocation no_allocation;
CodeKey k(key);
InternalIndex entry = FindEntry(isolate, &k);
if (entry.is_not_found()) return {};
return Handle<Code>(Code::cast(get(EntryToIndex(entry) + 1)), isolate);
}
Handle<CompilationCacheTable> CompilationCacheTable::PutScript(
Handle<CompilationCacheTable> cache, Handle<String> src,
Handle<Context> native_context, LanguageMode language_mode,
Handle<SharedFunctionInfo> value) {
Isolate* isolate = native_context->GetIsolate();
// We use the empty function SFI as part of the key. Although the
// empty_function is native context dependent, the SFI is de-duped on
// snapshot builds by the StartupObjectCache, and so this does not prevent
// reuse of scripts in the compilation cache across native contexts.
Handle<SharedFunctionInfo> shared(native_context->empty_function().shared(),
isolate);
src = String::Flatten(isolate, src);
StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
Handle<Object> k = key.AsHandle(isolate);
cache = EnsureCapacity(isolate, cache);
InternalIndex entry = cache->FindInsertionEntry(isolate, key.Hash());
cache->set(EntryToIndex(entry), *k);
cache->set(EntryToIndex(entry) + 1, *value);
cache->ElementAdded();
return cache;
}
Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
Handle<CompilationCacheTable> cache, Handle<String> src,
Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
Handle<Context> native_context, Handle<FeedbackCell> feedback_cell,
int position) {
Isolate* isolate = native_context->GetIsolate();
src = String::Flatten(isolate, src);
StringSharedKey key(src, outer_info, value->language_mode(), position);
{
Handle<Object> k = key.AsHandle(isolate);
InternalIndex entry = cache->FindEntry(isolate, &key);
if (entry.is_found()) {
cache->set(EntryToIndex(entry), *k);
cache->set(EntryToIndex(entry) + 1, *value);
// AddToFeedbackCellsMap may allocate a new sub-array to live in the
// entry, but it won't change the cache array. Therefore EntryToIndex
// and entry remains correct.
AddToFeedbackCellsMap(cache, EntryToIndex(entry) + 2, native_context,
feedback_cell);
// Add hash again even on cache hit to avoid unnecessary cache delay in
// case of hash collisions.
}
}
cache = EnsureCapacity(isolate, cache);
InternalIndex entry = cache->FindInsertionEntry(isolate, key.Hash());
Handle<Object> k =
isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
cache->set(EntryToIndex(entry), *k);
cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
cache->ElementAdded();
return cache;
}
Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
Isolate* isolate, Handle<CompilationCacheTable> cache, Handle<String> src,
JSRegExp::Flags flags, Handle<FixedArray> value) {
RegExpKey key(src, flags);
cache = EnsureCapacity(isolate, cache);
InternalIndex entry = cache->FindInsertionEntry(isolate, key.Hash());
// We store the value in the key slot, and compare the search key
// to the stored value with a custom IsMatch function during lookups.
cache->set(EntryToIndex(entry), *value);
cache->set(EntryToIndex(entry) + 1, *value);
cache->ElementAdded();
return cache;
}
Handle<CompilationCacheTable> CompilationCacheTable::PutCode(
Isolate* isolate, Handle<CompilationCacheTable> cache,
Handle<SharedFunctionInfo> key, Handle<Code> value) {
CodeKey k(key);
{
InternalIndex entry = cache->FindEntry(isolate, &k);
if (entry.is_found()) {
// Update.
cache->set(EntryToIndex(entry), *key);
cache->set(EntryToIndex(entry) + 1, *value);
return cache;
}
}
// Insert.
cache = EnsureCapacity(isolate, cache);
InternalIndex entry = cache->FindInsertionEntry(isolate, k.Hash());
cache->set(EntryToIndex(entry), *key);
cache->set(EntryToIndex(entry) + 1, *value);
cache->ElementAdded();
return cache;
}
void CompilationCacheTable::Age() {
DisallowHeapAllocation no_allocation;
Object the_hole_value = GetReadOnlyRoots().the_hole_value();
for (InternalIndex entry : IterateEntries()) {
int entry_index = EntryToIndex(entry);
int value_index = entry_index + 1;
if (get(entry_index).IsNumber()) {
Smi count = Smi::cast(get(value_index));
count = Smi::FromInt(count.value() - 1);
if (count.value() == 0) {
NoWriteBarrierSet(*this, entry_index, the_hole_value);
NoWriteBarrierSet(*this, value_index, the_hole_value);
ElementRemoved();
} else {
NoWriteBarrierSet(*this, value_index, count);
}
} else if (get(entry_index).IsFixedArray()) {
SharedFunctionInfo info = SharedFunctionInfo::cast(get(value_index));
if (info.IsInterpreted() && info.GetBytecodeArray().IsOld()) {
for (int i = 0; i < kEntrySize; i++) {
NoWriteBarrierSet(*this, entry_index + i, the_hole_value);
}
ElementRemoved();
}
}
}
}
void CompilationCacheTable::Remove(Object value) {
DisallowHeapAllocation no_allocation;
Object the_hole_value = GetReadOnlyRoots().the_hole_value();
for (InternalIndex entry : IterateEntries()) {
int entry_index = EntryToIndex(entry);
int value_index = entry_index + 1;
if (get(value_index) == value) {
for (int i = 0; i < kEntrySize; i++) {
NoWriteBarrierSet(*this, entry_index + i, the_hole_value);
}
ElementRemoved();
}
}
}
template <typename Derived, typename Shape>
template <typename LocalIsolate>
Handle<Derived> BaseNameDictionary<Derived, Shape>::New(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment