[heap] Properly clear the weak slot in CodeDataContainer.

During iteration of the optimized code list to process weak slots, we
need to clear the next_code_link in the CodeDataContainer of a dying
code object because the CodeDataContainer can still be alive.

BUG=v8:6792

Change-Id: Iec5f7430a4097cb622de2157bdec2a7d539dbba0
Reviewed-on: https://chromium-review.googlesource.com/751663
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49087}
This commit is contained in:
Ulan Degenbaev 2017-11-02 18:52:31 +01:00 committed by Commit Bot
parent aa371fac37
commit a274fc6536
2 changed files with 33 additions and 4 deletions

View File

@ -37,6 +37,10 @@ Object* VisitWeakList(Heap* heap, Object* list, WeakObjectRetainer* retainer) {
T* candidate = reinterpret_cast<T*>(list);
Object* retained = retainer->RetainAs(list);
// Move to the next element before the WeakNext is cleared.
list = WeakListVisitor<T>::WeakNext(candidate);
if (retained != nullptr) {
if (head == undefined) {
// First element in the list.
@ -63,9 +67,6 @@ Object* VisitWeakList(Heap* heap, Object* list, WeakObjectRetainer* retainer) {
} else {
WeakListVisitor<T>::VisitPhantomObject(heap, candidate);
}
// Move to next element in the list.
list = WeakListVisitor<T>::WeakNext(candidate);
}
// Terminate the list if there is one or more elements.
@ -103,7 +104,11 @@ struct WeakListVisitor<Code> {
static void VisitLiveObject(Heap*, Code*, WeakObjectRetainer*) {}
static void VisitPhantomObject(Heap*, Code*) {}
static void VisitPhantomObject(Heap* heap, Code* code) {
// Even though the code is dying, its code_data_container can still be
// alive. Clear the next_code_link slot to avoid a dangling pointer.
SetWeakNext(code, heap->undefined_value());
}
};

View File

@ -3909,6 +3909,30 @@ TEST(NextCodeLinkIsWeak) {
CHECK_EQ(code_chain_length_before - 1, code_chain_length_after);
}
TEST(NextCodeLinkInCodeDataContainerIsCleared) {
FLAG_always_opt = false;
FLAG_allow_natives_syntax = true;
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
v8::internal::Heap* heap = CcTest::heap();
if (!isolate->use_optimizer()) return;
HandleScope outer_scope(heap->isolate());
Handle<CodeDataContainer> code_data_container;
{
HandleScope scope(heap->isolate());
Handle<JSFunction> mortal1 =
OptimizeDummyFunction(CcTest::isolate(), "mortal1");
Handle<JSFunction> mortal2 =
OptimizeDummyFunction(CcTest::isolate(), "mortal2");
CHECK_EQ(mortal2->code()->next_code_link(), mortal1->code());
code_data_container = scope.CloseAndEscape(
Handle<CodeDataContainer>(mortal2->code()->code_data_container()));
CompileRun("mortal1 = null; mortal2 = null;");
}
CcTest::CollectAllAvailableGarbage();
CHECK(code_data_container->next_code_link()->IsUndefined(isolate));
}
static Handle<Code> DummyOptimizedCode(Isolate* isolate) {
i::byte buffer[i::Assembler::kMinimalBufferSize];