Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 8c05ff8bdd3e07349b54771eed2d323b41614d74..85066cc322b59488392cb4f4f1a1a810ea10eca9 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -11987,45 +11987,19 @@ void JSFunction::AttemptConcurrentOptimization() { |
} |
// static |
-Handle<TypeFeedbackVector> SharedFunctionInfo::FindOrCreateVector( |
- Handle<SharedFunctionInfo> shared, Handle<Context> native_context) { |
- Isolate* isolate = shared->GetIsolate(); |
- CodeAndVector result = |
- shared->SearchOptimizedCodeMap(*native_context, BailoutId::None()); |
- if (result.vector != nullptr) { |
- DCHECK(shared->feedback_metadata()->is_empty() || |
- !result.vector->is_empty()); |
- return handle(result.vector, isolate); |
- } |
- |
- Handle<TypeFeedbackVector> vector = |
- TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata())); |
- Handle<Code> code; |
- if (result.code != nullptr) { |
- code = Handle<Code>(result.code, isolate); |
- } |
- AddToOptimizedCodeMap(shared, native_context, code, vector, |
- BailoutId::None()); |
- return vector; |
-} |
- |
-// static |
void SharedFunctionInfo::AddToOptimizedCodeMap( |
Handle<SharedFunctionInfo> shared, Handle<Context> native_context, |
- MaybeHandle<Code> code, Handle<TypeFeedbackVector> vector, |
- BailoutId osr_ast_id) { |
+ Handle<Code> code, BailoutId osr_ast_id) { |
Isolate* isolate = shared->GetIsolate(); |
if (isolate->serializer_enabled()) return; |
- DCHECK(code.is_null() || |
- code.ToHandleChecked()->kind() == Code::OPTIMIZED_FUNCTION); |
+ DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION); |
DCHECK(native_context->IsNativeContext()); |
- STATIC_ASSERT(kEntryLength == 3); |
+ STATIC_ASSERT(kEntryLength == 2); |
Handle<FixedArray> new_code_map; |
int entry; |
if (!osr_ast_id.IsNone()) { |
- Context::AddToOptimizedCodeMap(native_context, shared, |
- code.ToHandleChecked(), vector, osr_ast_id); |
+ Context::AddToOptimizedCodeMap(native_context, shared, code, osr_ast_id); |
return; |
} |
@@ -12037,14 +12011,9 @@ void SharedFunctionInfo::AddToOptimizedCodeMap( |
Handle<FixedArray> old_code_map(shared->optimized_code_map(), isolate); |
entry = shared->SearchOptimizedCodeMapEntry(*native_context); |
if (entry >= kEntriesStart) { |
- // Just set the code and vector of the entry. |
- if (!code.is_null()) { |
- Handle<WeakCell> code_cell = |
- isolate->factory()->NewWeakCell(code.ToHandleChecked()); |
- old_code_map->set(entry + kCachedCodeOffset, *code_cell); |
- } |
- Handle<WeakCell> vector_cell = isolate->factory()->NewWeakCell(vector); |
- old_code_map->set(entry + kFeedbackVectorOffset, *vector_cell); |
+ // Just set the code of the entry. |
+ Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code); |
+ old_code_map->set(entry + kCachedCodeOffset, *code_cell); |
return; |
} |
@@ -12072,15 +12041,11 @@ void SharedFunctionInfo::AddToOptimizedCodeMap( |
} |
} |
- Handle<WeakCell> code_cell = |
- code.is_null() ? isolate->factory()->empty_weak_cell() |
- : isolate->factory()->NewWeakCell(code.ToHandleChecked()); |
- Handle<WeakCell> vector_cell = isolate->factory()->NewWeakCell(vector); |
+ Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code); |
WeakCell* context_cell = native_context->self_weak_cell(); |
new_code_map->set(entry + kContextOffset, context_cell); |
new_code_map->set(entry + kCachedCodeOffset, *code_cell); |
- new_code_map->set(entry + kFeedbackVectorOffset, *vector_cell); |
#ifdef DEBUG |
for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) { |
@@ -12090,8 +12055,6 @@ void SharedFunctionInfo::AddToOptimizedCodeMap( |
DCHECK(cell->cleared() || |
(cell->value()->IsCode() && |
Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION)); |
- cell = WeakCell::cast(new_code_map->get(i + kFeedbackVectorOffset)); |
- DCHECK(cell->cleared() || cell->value()->IsFixedArray()); |
} |
#endif |
@@ -12129,7 +12092,7 @@ void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code, |
ShortPrint(); |
PrintF("]\n"); |
} |
- // Just clear the code in order to continue sharing a feedback vector. |
+ // Just clear the code. |
code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(), |
SKIP_WRITE_BARRIER); |
} |
@@ -12146,12 +12109,44 @@ void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code, |
void JSFunction::EnsureLiterals(Handle<JSFunction> function) { |
Handle<SharedFunctionInfo> shared(function->shared()); |
Handle<Context> native_context(function->context()->native_context()); |
- if (function->feedback_vector() == |
- function->GetIsolate()->heap()->empty_type_feedback_vector()) { |
- Handle<TypeFeedbackVector> vector = |
- SharedFunctionInfo::FindOrCreateVector(shared, native_context); |
- function->set_feedback_vector(*vector); |
+ Isolate* isolate = shared->GetIsolate(); |
+ |
+ Cell* cell = function->feedback_vector_cell(); |
+ if (cell == isolate->heap()->undefined_cell()) { |
+ if (FLAG_trace_strong_rooted_literals) { |
+ PrintF("EnsureLiterals: Installing literals cell in %s %p\n", |
+ shared->DebugName()->ToCString().get(), |
+ reinterpret_cast<void*>(*function)); |
+ } |
+ // Top level code didn't get it's literals installed. |
+ Handle<TypeFeedbackVector> feedback_vector = |
+ TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata())); |
+ Handle<Cell> new_cell = isolate->factory()->NewCell(feedback_vector); |
+ function->set_feedback_vector_cell(*new_cell); |
+ } else if (!cell->value()->IsTypeFeedbackVector() || |
+ !function->has_feedback_vector()) { |
+ DCHECK(cell != isolate->heap()->undefined_cell()); |
+ if (FLAG_trace_strong_rooted_literals) { |
+ PrintF("EnsureLiterals: Update literals cell in %s %p\n", |
+ shared->DebugName()->ToCString().get(), |
+ reinterpret_cast<void*>(*function)); |
+ } |
+ Handle<TypeFeedbackVector> feedback_vector = |
+ TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata())); |
+ // Re-get the feedback_vector() value as GC may have occurred. |
+ function->feedback_vector_cell()->set_value(*feedback_vector); |
+ } else { |
+ if (FLAG_trace_strong_rooted_literals) { |
+ PrintF("EnsureLiterals: did nothing for %s %p\n", |
+ shared->DebugName()->ToCString().get(), |
+ reinterpret_cast<void*>(*function)); |
+ } |
} |
+ |
+ // No matter what, ensure some post-conditions. |
+ DCHECK(shared->feedback_metadata()->slot_count() != 0 || |
+ function->feedback_vector() == |
+ shared->GetIsolate()->heap()->empty_type_feedback_vector()); |
} |
static void GetMinInobjectSlack(Map* map, void* data) { |
@@ -13730,15 +13725,11 @@ void SharedFunctionInfo::ClearCodeFromOptimizedCodeMap() { |
} |
} |
-CodeAndVector SharedFunctionInfo::SearchOptimizedCodeMap( |
- Context* native_context, BailoutId osr_ast_id) { |
- CodeAndVector result = {nullptr, nullptr}; |
+Code* SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context, |
+ BailoutId osr_ast_id) { |
+ Code* result = nullptr; |
if (!osr_ast_id.IsNone()) { |
- Code* code; |
- TypeFeedbackVector* vector; |
- native_context->SearchOptimizedCodeMap(this, osr_ast_id, &code, &vector); |
- result = {code, vector}; |
- return result; |
+ return native_context->SearchOptimizedCodeMap(this, osr_ast_id); |
} |
DCHECK(osr_ast_id.IsNone()); |
@@ -13747,12 +13738,7 @@ CodeAndVector SharedFunctionInfo::SearchOptimizedCodeMap( |
FixedArray* code_map = optimized_code_map(); |
DCHECK_LE(entry + kEntryLength, code_map->length()); |
WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset)); |
- WeakCell* vector_cell = |
- WeakCell::cast(code_map->get(entry + kFeedbackVectorOffset)); |
- |
- result = {cell->cleared() ? nullptr : Code::cast(cell->value()), |
- vector_cell->cleared() ? nullptr : TypeFeedbackVector::cast( |
- vector_cell->value())}; |
+ result = cell->cleared() ? nullptr : Code::cast(cell->value()); |
} |
return result; |
} |
@@ -14032,11 +14018,17 @@ int AbstractCode::SourceStatementPosition(int offset) { |
} |
void JSFunction::ClearTypeFeedbackInfo() { |
- feedback_vector()->ClearSlots(shared()); |
+ if (feedback_vector_cell()->value()->IsTypeFeedbackVector()) { |
+ TypeFeedbackVector* vector = feedback_vector(); |
+ vector->ClearSlots(shared()); |
+ } |
} |
void JSFunction::ClearTypeFeedbackInfoAtGCTime() { |
- feedback_vector()->ClearSlotsAtGCTime(shared()); |
+ if (feedback_vector_cell()->value()->IsTypeFeedbackVector()) { |
+ TypeFeedbackVector* vector = feedback_vector(); |
+ vector->ClearSlotsAtGCTime(shared()); |
+ } |
} |
BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) { |
@@ -17475,22 +17467,157 @@ Handle<Object> CompilationCacheTable::Lookup(Handle<String> src, |
return Handle<Object>(get(index + 1), isolate); |
} |
+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); |
+ |
+ if (obj->IsFixedArray()) { |
+ FixedArray* literals_map = FixedArray::cast(obj); |
+ int length = literals_map->length(); |
+ for (int i = 0; i < length; i += kLiteralEntryLength) { |
+ if (WeakCell::cast(literals_map->get(i + kLiteralContextOffset)) |
+ ->value() == native_context) { |
+ return i; |
+ } |
+ } |
+ } |
+ return -1; |
+} |
+ |
+void AddToLiteralsMap(Handle<CompilationCacheTable> cache, int cache_entry, |
+ Handle<Context> native_context, Handle<Cell> literals) { |
+ Isolate* isolate = native_context->GetIsolate(); |
+ DCHECK(native_context->IsNativeContext()); |
+ STATIC_ASSERT(kLiteralEntryLength == 2); |
+ Handle<FixedArray> new_literals_map; |
+ int entry; |
+ |
+ Object* obj = cache->get(cache_entry); |
+ |
+ if (!obj->IsFixedArray() || FixedArray::cast(obj)->length() == 0) { |
+ new_literals_map = |
+ isolate->factory()->NewFixedArray(kLiteralInitialLength, TENURED); |
+ entry = 0; |
+ } else { |
+ Handle<FixedArray> old_literals_map(FixedArray::cast(obj), isolate); |
+ entry = SearchLiteralsMapEntry(*cache, cache_entry, *native_context); |
+ if (entry >= 0) { |
+ // Just set the code of the entry. |
+ Handle<WeakCell> literals_cell = |
+ isolate->factory()->NewWeakCell(literals); |
+ old_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell); |
+ return; |
+ } |
+ |
+ // Can we reuse an entry? |
+ DCHECK(entry < 0); |
+ int length = old_literals_map->length(); |
+ for (int i = 0; i < length; i += kLiteralEntryLength) { |
+ if (WeakCell::cast(old_literals_map->get(i + kLiteralContextOffset)) |
+ ->cleared()) { |
+ 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()->CopyFixedArrayAndGrow( |
+ old_literals_map, kLiteralEntryLength, TENURED); |
+ entry = old_literals_map->length(); |
+ } |
+ } |
+ |
+ Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals); |
+ WeakCell* context_cell = native_context->self_weak_cell(); |
+ |
+ new_literals_map->set(entry + kLiteralContextOffset, context_cell); |
+ new_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell); |
+ |
+#ifdef DEBUG |
+ for (int i = 0; i < new_literals_map->length(); i += kLiteralEntryLength) { |
+ WeakCell* cell = |
+ WeakCell::cast(new_literals_map->get(i + kLiteralContextOffset)); |
+ DCHECK(cell->cleared() || cell->value()->IsNativeContext()); |
+ cell = WeakCell::cast(new_literals_map->get(i + kLiteralLiteralsOffset)); |
+ DCHECK(cell->cleared() || (cell->value()->IsCell())); |
+ } |
+#endif |
+ |
+ Object* old_literals_map = cache->get(cache_entry); |
+ if (old_literals_map != *new_literals_map) { |
+ cache->set(cache_entry, *new_literals_map); |
+ } |
+} |
+ |
+Cell* SearchLiteralsMap(CompilationCacheTable* cache, int cache_entry, |
+ Context* native_context) { |
+ Cell* result = nullptr; |
+ int entry = SearchLiteralsMapEntry(cache, cache_entry, native_context); |
+ if (entry >= 0) { |
+ FixedArray* literals_map = FixedArray::cast(cache->get(cache_entry)); |
+ DCHECK_LE(entry + kLiteralEntryLength, literals_map->length()); |
+ WeakCell* cell = |
+ WeakCell::cast(literals_map->get(entry + kLiteralLiteralsOffset)); |
+ |
+ result = cell->cleared() ? nullptr : Cell::cast(cell->value()); |
+ } |
+ DCHECK(result == nullptr || result->IsCell()); |
+ return result; |
+} |
+ |
+} // namespace |
+ |
+InfoVectorPair CompilationCacheTable::LookupScript(Handle<String> src, |
+ Handle<Context> context, |
+ LanguageMode language_mode) { |
+ InfoVectorPair empty_result; |
+ Handle<SharedFunctionInfo> shared(context->closure()->shared()); |
+ StringSharedKey key(src, shared, language_mode, kNoSourcePosition); |
+ int entry = FindEntry(&key); |
+ if (entry == kNotFound) return empty_result; |
+ int index = EntryToIndex(entry); |
+ if (!get(index)->IsFixedArray()) return empty_result; |
+ Object* obj = get(index + 1); |
+ if (obj->IsSharedFunctionInfo()) { |
+ Cell* literals = |
+ SearchLiteralsMap(this, index + 2, context->native_context()); |
+ return InfoVectorPair(SharedFunctionInfo::cast(obj), literals); |
+ } |
+ return empty_result; |
+} |
-Handle<Object> CompilationCacheTable::LookupEval( |
+InfoVectorPair CompilationCacheTable::LookupEval( |
Handle<String> src, Handle<SharedFunctionInfo> outer_info, |
- LanguageMode language_mode, int scope_position) { |
- Isolate* isolate = GetIsolate(); |
+ Handle<Context> native_context, LanguageMode language_mode, |
+ int scope_position) { |
+ InfoVectorPair empty_result; |
// Cache key is the tuple (source, outer shared function info, scope position) |
// to unambiguously identify the context chain the cached eval code assumes. |
StringSharedKey key(src, outer_info, language_mode, scope_position); |
int entry = FindEntry(&key); |
- if (entry == kNotFound) return isolate->factory()->undefined_value(); |
+ if (entry == kNotFound) return empty_result; |
int index = EntryToIndex(entry); |
- if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value(); |
- return Handle<Object>(get(EntryToIndex(entry) + 1), isolate); |
+ if (!get(index)->IsFixedArray()) return empty_result; |
+ Object* obj = get(EntryToIndex(entry) + 1); |
+ if (obj->IsSharedFunctionInfo()) { |
+ Cell* literals = |
+ SearchLiteralsMap(this, EntryToIndex(entry) + 2, *native_context); |
+ return InfoVectorPair(SharedFunctionInfo::cast(obj), literals); |
+ } |
+ return empty_result; |
} |
- |
Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src, |
JSRegExp::Flags flags) { |
Isolate* isolate = GetIsolate(); |
@@ -17517,20 +17644,41 @@ Handle<CompilationCacheTable> CompilationCacheTable::Put( |
return cache; |
} |
+Handle<CompilationCacheTable> CompilationCacheTable::PutScript( |
+ Handle<CompilationCacheTable> cache, Handle<String> src, |
+ Handle<Context> context, LanguageMode language_mode, |
+ Handle<SharedFunctionInfo> value, Handle<Cell> literals) { |
+ Isolate* isolate = cache->GetIsolate(); |
+ Handle<SharedFunctionInfo> shared(context->closure()->shared()); |
+ Handle<Context> native_context(context->native_context()); |
+ StringSharedKey key(src, shared, language_mode, kNoSourcePosition); |
+ Handle<Object> k = key.AsHandle(isolate); |
+ cache = EnsureCapacity(cache, 1, &key); |
+ int entry = cache->FindInsertionEntry(key.Hash()); |
+ cache->set(EntryToIndex(entry), *k); |
+ cache->set(EntryToIndex(entry) + 1, *value); |
+ AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context, literals); |
+ cache->ElementAdded(); |
+ return cache; |
+} |
Handle<CompilationCacheTable> CompilationCacheTable::PutEval( |
Handle<CompilationCacheTable> cache, Handle<String> src, |
Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value, |
- int scope_position) { |
+ Handle<Context> native_context, Handle<Cell> literals, int scope_position) { |
Isolate* isolate = cache->GetIsolate(); |
StringSharedKey key(src, outer_info, value->language_mode(), scope_position); |
{ |
Handle<Object> k = key.AsHandle(isolate); |
- DisallowHeapAllocation no_allocation_scope; |
int entry = cache->FindEntry(&key); |
if (entry != kNotFound) { |
cache->set(EntryToIndex(entry), *k); |
cache->set(EntryToIndex(entry) + 1, *value); |
+ // AddToLiteralsMap 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. |
+ AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context, |
+ literals); |
return cache; |
} |
} |
@@ -17585,8 +17733,9 @@ void CompilationCacheTable::Age() { |
? info->bytecode_array()->IsOld() |
: info->code()->kind() != Code::FUNCTION || info->code()->IsOld(); |
if (is_old) { |
- NoWriteBarrierSet(this, entry_index, the_hole_value); |
- NoWriteBarrierSet(this, value_index, the_hole_value); |
+ for (int i = 0; i < kEntrySize; i++) { |
+ NoWriteBarrierSet(this, entry_index + i, the_hole_value); |
+ } |
ElementRemoved(); |
} |
} |
@@ -17601,8 +17750,9 @@ void CompilationCacheTable::Remove(Object* value) { |
int entry_index = EntryToIndex(entry); |
int value_index = entry_index + 1; |
if (get(value_index) == value) { |
- NoWriteBarrierSet(this, entry_index, the_hole_value); |
- NoWriteBarrierSet(this, value_index, the_hole_value); |
+ for (int i = 0; i < kEntrySize; i++) { |
+ NoWriteBarrierSet(this, entry_index + i, the_hole_value); |
+ } |
ElementRemoved(); |
} |
} |