From 5242700da494d9fac6b3781bed5b7f3790c32335 Mon Sep 17 00:00:00 2001 From: ulan Date: Thu, 19 Feb 2015 01:56:06 -0800 Subject: [PATCH] Revert "Remove IC age from Code." This reverts commit 3cd889 for regressing Kraken benchmark BUG=chromium:457174 LOG=N Review URL: https://codereview.chromium.org/941503003 Cr-Commit-Position: refs/heads/master@{#26740} --- src/factory.cc | 1 + src/heap/heap.cc | 1 + src/heap/objects-visiting-inl.h | 3 +- src/objects-inl.h | 1 + src/objects.cc | 4 ++ src/objects.h | 15 +++-- test/cctest/test-heap.cc | 100 ++++++++++++++++++++++++++++++++ 7 files changed, 120 insertions(+), 5 deletions(-) diff --git a/src/factory.cc b/src/factory.cc index fc5af36a9f..a07d656d75 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1457,6 +1457,7 @@ Handle Factory::NewCode(const CodeDesc& desc, // fact that no allocation will happen from this point on. DisallowHeapAllocation no_gc; code->set_gc_metadata(Smi::FromInt(0)); + code->set_ic_age(isolate()->heap()->global_ic_age()); code->set_instruction_size(desc.instr_size); code->set_relocation_info(*reloc_info); code->set_flags(flags); diff --git a/src/heap/heap.cc b/src/heap/heap.cc index a67bf050b2..e1817ba8b4 100644 --- a/src/heap/heap.cc +++ b/src/heap/heap.cc @@ -3691,6 +3691,7 @@ AllocationResult Heap::AllocateCode(int object_size, bool immovable) { DCHECK(isolate_->code_range() == NULL || !isolate_->code_range()->valid() || isolate_->code_range()->contains(code->address())); code->set_gc_metadata(Smi::FromInt(0)); + code->set_ic_age(global_ic_age_); return code; } diff --git a/src/heap/objects-visiting-inl.h b/src/heap/objects-visiting-inl.h index 857fa7c0a6..58afeae016 100644 --- a/src/heap/objects-visiting-inl.h +++ b/src/heap/objects-visiting-inl.h @@ -262,7 +262,8 @@ void StaticMarkingVisitor::VisitCodeTarget(Heap* heap, // when they might be keeping a Context alive, or when the heap is about // to be serialized. if (FLAG_cleanup_code_caches_at_gc && target->is_inline_cache_stub() && - !target->is_call_stub() && heap->isolate()->serializer_enabled()) { + !target->is_call_stub() && (heap->isolate()->serializer_enabled() || + target->ic_age() != heap->global_ic_age())) { ICUtility::Clear(heap->isolate(), rinfo->pc(), rinfo->host()->constant_pool()); target = Code::GetCodeFromTargetAddress(rinfo->target_address()); diff --git a/src/objects-inl.h b/src/objects-inl.h index dca7004a4f..926e1c7a73 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -6439,6 +6439,7 @@ void Code::set_stub_key(uint32_t key) { ACCESSORS(Code, gc_metadata, Object, kGCMetadataOffset) +INT_ACCESSORS(Code, ic_age, kICAgeOffset) byte* Code::instruction_start() { diff --git a/src/objects.cc b/src/objects.cc index 49097c6680..598c638f5c 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -10657,6 +10657,10 @@ void JSFunction::StartInobjectSlackTracking() { void SharedFunctionInfo::ResetForNewContext(int new_ic_age) { + code()->ClearInlineCaches(); + // If we clear ICs, we need to clear the type feedback vector too, since + // CallICs are synced with a feedback vector slot. + ClearTypeFeedbackInfo(); set_ic_age(new_ic_age); if (code()->kind() == Code::FUNCTION) { code()->set_profiler_ticks(0); diff --git a/src/objects.h b/src/objects.h index 7d0a0eeee4..5aceb10236 100644 --- a/src/objects.h +++ b/src/objects.h @@ -5057,6 +5057,11 @@ class Code: public HeapObject { // it is only used by the garbage collector itself. DECL_ACCESSORS(gc_metadata, Object) + // [ic_age]: Inline caching age: the value of the Heap::global_ic_age + // at the moment when this object was created. + inline void set_ic_age(int count); + inline int ic_age() const; + // [prologue_offset]: Offset of the function prologue, used for aging // FUNCTIONs and OPTIMIZED_FUNCTIONs. inline int prologue_offset() const; @@ -5412,15 +5417,17 @@ class Code: public HeapObject { kDeoptimizationDataOffset + kPointerSize; static const int kNextCodeLinkOffset = kTypeFeedbackInfoOffset + kPointerSize; static const int kGCMetadataOffset = kNextCodeLinkOffset + kPointerSize; - static const int kConstantPoolOffset = kGCMetadataOffset + kPointerSize; - static const int kInstructionSizeOffset = kConstantPoolOffset + kPointerSize; - static const int kFlagsOffset = kInstructionSizeOffset + kIntSize; + static const int kInstructionSizeOffset = kGCMetadataOffset + kPointerSize; + static const int kICAgeOffset = kInstructionSizeOffset + kIntSize; + static const int kFlagsOffset = kICAgeOffset + kIntSize; static const int kKindSpecificFlags1Offset = kFlagsOffset + kIntSize; static const int kKindSpecificFlags2Offset = kKindSpecificFlags1Offset + kIntSize; // Note: We might be able to squeeze this into the flags above. static const int kPrologueOffset = kKindSpecificFlags2Offset + kIntSize; - static const int kHeaderPaddingStart = kPrologueOffset + kIntSize; + static const int kConstantPoolOffset = kPrologueOffset + kIntSize; + + static const int kHeaderPaddingStart = kConstantPoolOffset + kPointerSize; // Add padding to align the instruction start following right after // the Code object header. diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc index e80f4f1d06..c3094a43b3 100644 --- a/test/cctest/test-heap.cc +++ b/test/cctest/test-heap.cc @@ -3393,6 +3393,15 @@ static void CheckVectorIC(Handle f, int ic_slot_index, } +static void CheckVectorICCleared(Handle f, int ic_slot_index) { + Handle vector = + Handle(f->shared()->feedback_vector()); + FeedbackVectorICSlot slot(ic_slot_index); + LoadICNexus nexus(vector, slot); + CHECK(IC::IsCleared(&nexus)); +} + + TEST(IncrementalMarkingPreservesMonomorphicIC) { if (i::FLAG_always_opt) return; CcTest::InitializeVM(); @@ -3428,6 +3437,48 @@ TEST(IncrementalMarkingPreservesMonomorphicIC) { } +TEST(IncrementalMarkingClearsMonomorphicIC) { + if (i::FLAG_always_opt) return; + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + v8::Local obj1; + + { + LocalContext env; + CompileRun("function fun() { this.x = 1; }; var obj = new fun();"); + obj1 = env->Global()->Get(v8_str("obj")); + } + + // Prepare function f that contains a monomorphic IC for object + // originating from a different native context. + CcTest::global()->Set(v8_str("obj1"), obj1); + CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);"); + Handle f = v8::Utils::OpenHandle( + *v8::Handle::Cast(CcTest::global()->Get(v8_str("f")))); + + Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); + if (FLAG_vector_ics) { + CheckVectorIC(f, 0, MONOMORPHIC); + CHECK(ic_before->ic_state() == DEFAULT); + } else { + CHECK(ic_before->ic_state() == MONOMORPHIC); + } + + // Fire context dispose notification. + CcTest::isolate()->ContextDisposedNotification(); + SimulateIncrementalMarking(CcTest::heap()); + CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); + + Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); + if (FLAG_vector_ics) { + CheckVectorICCleared(f, 0); + CHECK(ic_after->ic_state() == DEFAULT); + } else { + CHECK(IC::IsCleared(ic_after)); + } +} + + TEST(IncrementalMarkingPreservesPolymorphicIC) { if (i::FLAG_always_opt) return; CcTest::InitializeVM(); @@ -3476,6 +3527,55 @@ TEST(IncrementalMarkingPreservesPolymorphicIC) { } +TEST(IncrementalMarkingClearsPolymorphicIC) { + if (i::FLAG_always_opt) return; + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + v8::Local obj1, obj2; + + { + LocalContext env; + CompileRun("function fun() { this.x = 1; }; var obj = new fun();"); + obj1 = env->Global()->Get(v8_str("obj")); + } + + { + LocalContext env; + CompileRun("function fun() { this.x = 2; }; var obj = new fun();"); + obj2 = env->Global()->Get(v8_str("obj")); + } + + // Prepare function f that contains a polymorphic IC for objects + // originating from two different native contexts. + CcTest::global()->Set(v8_str("obj1"), obj1); + CcTest::global()->Set(v8_str("obj2"), obj2); + CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);"); + Handle f = v8::Utils::OpenHandle( + *v8::Handle::Cast(CcTest::global()->Get(v8_str("f")))); + + Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); + if (FLAG_vector_ics) { + CheckVectorIC(f, 0, POLYMORPHIC); + CHECK(ic_before->ic_state() == DEFAULT); + } else { + CHECK(ic_before->ic_state() == POLYMORPHIC); + } + + // Fire context dispose notification. + CcTest::isolate()->ContextDisposedNotification(); + SimulateIncrementalMarking(CcTest::heap()); + CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); + + Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); + if (FLAG_vector_ics) { + CheckVectorICCleared(f, 0); + CHECK(ic_before->ic_state() == DEFAULT); + } else { + CHECK(IC::IsCleared(ic_after)); + } +} + + class SourceResource : public v8::String::ExternalOneByteStringResource { public: explicit SourceResource(const char* data)