[heap] Verify FeedbackVector contents during heap verification.

Pre-work for in-place weak refs.

BUG=v8:7308

Change-Id: I5c7086bded14879f62ab366d0aba59302f0078d3
Reviewed-on: https://chromium-review.googlesource.com/1010069
Commit-Queue: Marja Hölttä <marja@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Michael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52681}
This commit is contained in:
Marja Hölttä 2018-04-18 08:53:33 +02:00 committed by Commit Bot
parent 30599649f5
commit 9d0154d6ed
3 changed files with 168 additions and 1 deletions

View File

@ -249,6 +249,7 @@ class FeedbackVector : public HeapObject {
DECL_PRINTER(FeedbackVector)
DECL_VERIFIER(FeedbackVector)
void FeedbackVectorVerifyDeep();
void FeedbackSlotPrint(std::ostream& os, FeedbackSlot slot); // NOLINT

View File

@ -10,6 +10,7 @@
#include "src/disassembler.h"
#include "src/elements.h"
#include "src/field-type.h"
#include "src/ic/ic-inl.h"
#include "src/layout-descriptor.h"
#include "src/macro-assembler.h"
#include "src/objects-inl.h"
@ -381,6 +382,150 @@ void FeedbackCell::FeedbackCellVerify() {
CHECK(value()->IsUndefined(isolate) || value()->IsFeedbackVector());
}
namespace {
void VerifyCellHandlerArray(FixedArray* array) {
const int increment = 2;
for (int i = 0; i < array->length(); i += increment) {
WeakCell* cell = WeakCell::cast(array->get(i));
CHECK(cell->cleared() || cell->value()->IsMap());
Object* code = array->get(i + increment - 1);
CHECK(IC::IsHandler(code));
}
}
void VerifyFeedbackNexus(FeedbackNexus* nexus, Isolate* isolate) {
Object* feedback = nexus->GetFeedback();
auto kind = nexus->kind();
switch (kind) {
case FeedbackSlotKind::kInvalid:
case FeedbackSlotKind::kKindsNumber:
UNREACHABLE();
break;
case FeedbackSlotKind::kCreateClosure: {
Object* value = FeedbackCell::cast(feedback)->value();
CHECK(value == isolate->heap()->undefined_value() ||
value->IsFeedbackVector());
break;
}
case FeedbackSlotKind::kLiteral: {
CHECK(feedback->IsSmi() || feedback->IsAllocationSite() ||
feedback->IsJSObject());
break;
}
case FeedbackSlotKind::kStoreGlobalSloppy:
case FeedbackSlotKind::kStoreGlobalStrict:
case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
Object* extra = nexus->GetFeedbackExtra();
if (feedback->IsSmi()) {
CHECK_EQ(extra, isolate->heap()->uninitialized_symbol());
} else if (feedback->IsWeakCell()) {
WeakCell* cell = WeakCell::cast(feedback);
CHECK(cell->cleared() || cell->value()->IsPropertyCell());
CHECK(extra == isolate->heap()->uninitialized_symbol() ||
IC::IsHandler(extra));
} else {
UNREACHABLE();
}
break;
}
case FeedbackSlotKind::kStoreNamedSloppy:
case FeedbackSlotKind::kStoreNamedStrict:
case FeedbackSlotKind::kStoreKeyedSloppy:
case FeedbackSlotKind::kStoreKeyedStrict:
case FeedbackSlotKind::kStoreInArrayLiteral:
case FeedbackSlotKind::kStoreOwnNamed:
case FeedbackSlotKind::kLoadProperty:
case FeedbackSlotKind::kLoadKeyed: {
Object* extra = nexus->GetFeedbackExtra();
if (feedback == *FeedbackVector::UninitializedSentinel(isolate) ||
feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
CHECK_EQ(extra, *FeedbackVector::UninitializedSentinel(isolate));
} else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
CHECK(extra->IsSmi());
} else if (feedback->IsFixedArray()) {
FixedArray* array = FixedArray::cast(feedback);
VerifyCellHandlerArray(array);
CHECK(extra == isolate->heap()->uninitialized_symbol());
} else if (feedback->IsWeakCell()) {
WeakCell* cell = WeakCell::cast(feedback);
CHECK(cell->cleared() || cell->value()->IsMap());
CHECK(IC::IsHandler(extra));
} else if (feedback->IsName()) {
CHECK(IsKeyedLoadICKind(kind) || IsKeyedStoreICKind(kind));
VerifyCellHandlerArray(FixedArray::cast(extra));
} else {
UNREACHABLE();
}
break;
}
case FeedbackSlotKind::kCall: {
Object* extra = nexus->GetFeedbackExtra();
if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
// "extra" can be a SMI here, since We don't clear the call count even
// if the feedback is reset back to uninitialized.
CHECK(extra == isolate->heap()->uninitialized_symbol() ||
extra->IsSmi());
} else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
CHECK(extra->IsSmi());
} else if (feedback->IsAllocationSite()) {
CHECK(extra->IsSmi());
} else if (feedback->IsWeakCell()) {
WeakCell* cell = WeakCell::cast(feedback);
CHECK(cell->cleared() || cell->value()->IsFunction());
CHECK(extra->IsSmi());
} else {
UNREACHABLE();
}
break;
}
case FeedbackSlotKind::kBinaryOp:
case FeedbackSlotKind::kCompareOp:
case FeedbackSlotKind::kForIn:
CHECK(feedback->IsSmi());
break;
case FeedbackSlotKind::kInstanceOf:
if (feedback->IsWeakCell()) {
WeakCell* cell = WeakCell::cast(feedback);
CHECK(cell->cleared() || cell->value()->IsJSFunction() ||
cell->value()->IsJSBoundFunction());
} else {
CHECK(feedback == *FeedbackVector::UninitializedSentinel(isolate) ||
feedback == *FeedbackVector::MegamorphicSentinel(isolate));
}
break;
case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
Object* extra = nexus->GetFeedbackExtra();
if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
CHECK(extra == isolate->heap()->uninitialized_symbol());
} else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
CHECK(extra->IsSmi());
} else if (feedback->IsWeakCell()) {
WeakCell* cell = WeakCell::cast(feedback);
CHECK(cell->cleared() || cell->value()->IsMap());
CHECK(extra == isolate->heap()->uninitialized_symbol() ||
extra->IsName());
} else {
UNREACHABLE();
}
break;
}
case FeedbackSlotKind::kTypeProfile: {
// The "IsSimpleNumberDictionary" case is never hit in
// tests. TODO(yangguo): Investigate why not (
// https://bugs.chromium.org/p/v8/issues/detail?id=7657 ).
CHECK(feedback == *FeedbackVector::UninitializedSentinel(isolate) ||
feedback->IsSimpleNumberDictionary());
break;
}
}
}
} // namespace
// This function also works for abandoned FeedbackVectors which might be
// inconsistent with their metadata.
void FeedbackVector::FeedbackVectorVerify() {
CHECK(IsFeedbackVector());
MaybeObject* code = optimized_code_weak_or_smi();
@ -389,6 +534,21 @@ void FeedbackVector::FeedbackVectorVerify() {
code->IsWeakHeapObject());
}
// Additional verification for FeedbackVectors which are live, i.e., attached to
// JSFunction.
void FeedbackVector::FeedbackVectorVerifyDeep() {
if (!shared_function_info()->HasFeedbackMetadata()) {
return;
}
FeedbackMetadataIterator iter(metadata());
Isolate* isolate = GetIsolate();
while (iter.HasNext()) {
FeedbackSlot slot = iter.Next();
FeedbackNexus nexus(this, slot);
VerifyFeedbackNexus(&nexus, isolate);
}
}
template <class Traits>
void FixedTypedArray<Traits>::FixedTypedArrayVerify() {
CHECK(IsHeapObject() &&
@ -859,6 +1019,12 @@ void JSFunction::JSFunctionVerify() {
CHECK(IsJSFunction());
JSObjectVerify();
VerifyHeapPointer(feedback_cell());
if (feedback_cell()->value()->IsFeedbackVector()) {
// Do the deep verification only for FeedbackVectors attached to
// JSFunction. This allows abandoned FeedbackVectors to be in an
// inconsistent state.
FeedbackVector::cast(feedback_cell()->value())->FeedbackVectorVerifyDeep();
}
CHECK(feedback_cell()->IsFeedbackCell());
CHECK(code()->IsCode());
CHECK(map()->is_callable());

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-gc
// Flags: --expose-gc --no-verify-heap
const f = eval(`(function f(i) {
if (i == 0) {