From 1812f63fd261b4e086fcbc2db45a8115803ff83e Mon Sep 17 00:00:00 2001 From: "mvstanton@chromium.org" Date: Fri, 7 Mar 2014 10:12:17 +0000 Subject: [PATCH] Moved type feedback vector to SharedFunctionInfo. Type Vector followup: the type vector currently lives off the code object. This CL moves it to the SharedFunctionInfo, facilitating re-use and continued use in crankshafted code if desired. R=bmeurer@chromium.org Review URL: https://codereview.chromium.org/178463007 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19712 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/a64/full-codegen-a64.cc | 14 +------------- src/arm/full-codegen-arm.cc | 14 +------------- src/compiler.cc | 31 +++++++++++++++++++++++++++++-- src/compiler.h | 6 ++++++ src/factory.cc | 4 +++- src/factory.h | 3 ++- src/full-codegen.cc | 16 ++-------------- src/full-codegen.h | 7 +------ src/heap-snapshot-generator.cc | 3 +++ src/heap.cc | 2 +- src/hydrogen.cc | 1 + src/ia32/full-codegen-ia32.cc | 15 +-------------- src/mips/full-codegen-mips.cc | 14 +------------- src/objects-debug.cc | 2 +- src/objects-inl.h | 8 +++----- src/objects-printer.cc | 4 ++-- src/objects-visiting-inl.h | 6 +++--- src/objects.cc | 23 ++++++++++------------- src/objects.h | 24 +++++++++++++----------- src/runtime.cc | 3 ++- src/type-info.cc | 16 ++++++---------- src/type-info.h | 1 + src/typing.cc | 1 + src/x64/full-codegen-x64.cc | 15 +-------------- test/cctest/test-compiler.cc | 34 ++++++++++++++++++++++++++++++++++ test/cctest/test-heap.cc | 3 +-- 26 files changed, 130 insertions(+), 140 deletions(-) diff --git a/src/a64/full-codegen-a64.cc b/src/a64/full-codegen-a64.cc index b24263862..4414cb391 100644 --- a/src/a64/full-codegen-a64.cc +++ b/src/a64/full-codegen-a64.cc @@ -129,8 +129,6 @@ void FullCodeGenerator::Generate() { handler_table_ = isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); - InitializeFeedbackVector(); - profiling_counter_ = isolate()->factory()->NewCell( Handle(Smi::FromInt(FLAG_interrupt_budget), isolate())); SetFunctionPosition(function()); @@ -1162,12 +1160,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // We got a fixed array in register x0. Iterate through that. __ Bind(&fixed_array); - Handle feedback = Handle( - Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker), - isolate()); - StoreFeedbackVectorSlot(slot, feedback); __ LoadObject(x1, FeedbackVector()); - __ Mov(x10, Operand(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker))); + __ Mov(x10, Operand(TypeFeedbackInfo::MegamorphicSentinel(isolate()))); __ Str(x10, FieldMemOperand(x1, FixedArray::OffsetOfElementAt(slot))); __ Mov(x1, Operand(Smi::FromInt(1))); // Smi indicates slow check. @@ -2415,9 +2409,6 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) { // Record source position for debugger. SetSourcePosition(expr->position()); - Handle uninitialized = - TypeFeedbackInfo::UninitializedSentinel(isolate()); - StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized); __ LoadObject(x2, FeedbackVector()); __ Mov(x3, Operand(Smi::FromInt(expr->CallFeedbackSlot()))); @@ -2614,9 +2605,6 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) { __ Peek(x1, arg_count * kXRegSizeInBytes); // Record call targets in unoptimized code. - Handle uninitialized = - TypeFeedbackInfo::UninitializedSentinel(isolate()); - StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized); __ LoadObject(x2, FeedbackVector()); __ Mov(x3, Operand(Smi::FromInt(expr->CallNewFeedbackSlot()))); diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 24ac4ffd2..760afba63 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -131,8 +131,6 @@ void FullCodeGenerator::Generate() { handler_table_ = isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); - InitializeFeedbackVector(); - profiling_counter_ = isolate()->factory()->NewCell( Handle(Smi::FromInt(FLAG_interrupt_budget), isolate())); SetFunctionPosition(function()); @@ -1167,12 +1165,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { Label non_proxy; __ bind(&fixed_array); - Handle feedback = Handle( - Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker), - isolate()); - StoreFeedbackVectorSlot(slot, feedback); __ Move(r1, FeedbackVector()); - __ mov(r2, Operand(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker))); + __ mov(r2, Operand(TypeFeedbackInfo::MegamorphicSentinel(isolate()))); __ str(r2, FieldMemOperand(r1, FixedArray::OffsetOfElementAt(slot))); __ mov(r1, Operand(Smi::FromInt(1))); // Smi indicates slow check @@ -2714,9 +2708,6 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) { // Record source position for debugger. SetSourcePosition(expr->position()); - Handle uninitialized = - TypeFeedbackInfo::UninitializedSentinel(isolate()); - StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized); __ Move(r2, FeedbackVector()); __ mov(r3, Operand(Smi::FromInt(expr->CallFeedbackSlot()))); @@ -2903,9 +2894,6 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) { __ ldr(r1, MemOperand(sp, arg_count * kPointerSize)); // Record call targets in unoptimized code. - Handle uninitialized = - TypeFeedbackInfo::UninitializedSentinel(isolate()); - StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized); __ Move(r2, FeedbackVector()); __ mov(r3, Operand(Smi::FromInt(expr->CallNewFeedbackSlot()))); diff --git a/src/compiler.cc b/src/compiler.cc index b5cdc1e5e..89864e049 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -141,6 +141,15 @@ void CompilationInfo::Initialize(Isolate* isolate, SetLanguageMode(shared_info_->language_mode()); } set_bailout_reason(kUnknown); + + if (!shared_info().is_null()) { + FixedArray* info_feedback_vector = shared_info()->feedback_vector(); + if (info_feedback_vector->length() > 0) { + // We should initialize the CompilationInfo feedback vector from the + // passed in shared info, rather than creating a new one. + feedback_vector_ = Handle(info_feedback_vector, isolate); + } + } } @@ -250,6 +259,20 @@ void CompilationInfo::PrepareForCompilation(Scope* scope) { ASSERT(scope_ == NULL); scope_ = scope; function()->ProcessFeedbackSlots(isolate_); + int length = function()->slot_count(); + if (feedback_vector_.is_null()) { + // Allocate the feedback vector too. + feedback_vector_ = isolate()->factory()->NewFixedArray(length, TENURED); + // Ensure we can skip the write barrier + ASSERT_EQ(isolate()->heap()->uninitialized_symbol(), + *TypeFeedbackInfo::UninitializedSentinel(isolate())); + for (int i = 0; i < length; i++) { + feedback_vector_->set(i, + *TypeFeedbackInfo::UninitializedSentinel(isolate()), + SKIP_WRITE_BARRIER); + } + } + ASSERT(feedback_vector_->length() == length); } @@ -571,6 +594,8 @@ static void UpdateSharedFunctionInfo(CompilationInfo* info) { shared->ReplaceCode(*code); if (shared->optimization_disabled()) code->set_optimizable(false); + shared->set_feedback_vector(*info->feedback_vector()); + // Set the expected number of properties for instances. FunctionLiteral* lit = info->function(); int expected = lit->expected_property_count(); @@ -826,7 +851,8 @@ static Handle CompileToplevel(CompilationInfo* info) { lit->materialized_literal_count(), lit->is_generator(), info->code(), - ScopeInfo::Create(info->scope(), info->zone())); + ScopeInfo::Create(info->scope(), info->zone()), + info->feedback_vector()); ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position()); SetFunctionInfo(result, lit, true, script); @@ -1033,7 +1059,8 @@ Handle Compiler::BuildFunctionInfo(FunctionLiteral* literal, literal->materialized_literal_count(), literal->is_generator(), info.code(), - scope_info); + scope_info, + info.feedback_vector()); SetFunctionInfo(result, literal, false, script); RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result); result->set_allows_lazy_compilation(allow_lazy); diff --git a/src/compiler.h b/src/compiler.h index 3f47677cd..2f8304367 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -181,6 +181,9 @@ class CompilationInfo { ASSERT(global_scope_ == NULL); global_scope_ = global_scope; } + Handle feedback_vector() const { + return feedback_vector_; + } void SetCode(Handle code) { code_ = code; } void SetExtension(v8::Extension* extension) { ASSERT(!is_lazy()); @@ -409,6 +412,9 @@ class CompilationInfo { // global script. Will be a null handle otherwise. Handle context_; + // Used by codegen, ultimately kept rooted by the SharedFunctionInfo. + Handle feedback_vector_; + // Compilation mode flag and whether deoptimization is allowed. Mode mode_; BailoutId osr_ast_id_; diff --git a/src/factory.cc b/src/factory.cc index d9d105c48..60727d952 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1541,10 +1541,12 @@ Handle Factory::NewSharedFunctionInfo( int number_of_literals, bool is_generator, Handle code, - Handle scope_info) { + Handle scope_info, + Handle feedback_vector) { Handle shared = NewSharedFunctionInfo(name); shared->set_code(*code); shared->set_scope_info(*scope_info); + shared->set_feedback_vector(*feedback_vector); int literals_array_size = number_of_literals; // If the function contains object, regexp or array literals, // allocate extra space for a literals array prefix containing the diff --git a/src/factory.h b/src/factory.h index 00ae587d6..86c26044c 100644 --- a/src/factory.h +++ b/src/factory.h @@ -516,7 +516,8 @@ class Factory { int number_of_literals, bool is_generator, Handle code, - Handle scope_info); + Handle scope_info, + Handle feedback_vector); Handle NewSharedFunctionInfo(Handle name); Handle NewJSMessageObject( diff --git a/src/full-codegen.cc b/src/full-codegen.cc index 75fdf735f..96410747a 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -386,18 +386,6 @@ unsigned FullCodeGenerator::EmitBackEdgeTable() { } -void FullCodeGenerator::InitializeFeedbackVector() { - int length = info_->function()->slot_count(); - feedback_vector_ = isolate()->factory()->NewFixedArray(length, TENURED); - Handle sentinel = TypeFeedbackInfo::UninitializedSentinel(isolate()); - // Ensure that it's safe to set without using a write barrier. - ASSERT_EQ(isolate()->heap()->uninitialized_symbol(), *sentinel); - for (int i = 0; i < length; i++) { - feedback_vector_->set(i, *sentinel, SKIP_WRITE_BARRIER); - } -} - - void FullCodeGenerator::PopulateDeoptimizationData(Handle code) { // Fill in the deoptimization information. ASSERT(info_->HasDeoptimizationSupport() || bailout_entries_.is_empty()); @@ -416,7 +404,6 @@ void FullCodeGenerator::PopulateDeoptimizationData(Handle code) { void FullCodeGenerator::PopulateTypeFeedbackInfo(Handle code) { Handle info = isolate()->factory()->NewTypeFeedbackInfo(); info->set_ic_total_count(ic_total_count_); - info->set_feedback_vector(*FeedbackVector()); ASSERT(!isolate()->heap()->InNewSpace(*info)); code->set_type_feedback_info(*info); } @@ -1590,7 +1577,8 @@ void FullCodeGenerator::VisitNativeFunctionLiteral( bool is_generator = false; Handle shared = isolate()->factory()->NewSharedFunctionInfo(name, literals, is_generator, - code, Handle(fun->shared()->scope_info())); + code, Handle(fun->shared()->scope_info()), + Handle(fun->shared()->feedback_vector())); shared->set_construct_stub(*construct_stub); // Copy the function data to the shared function info. diff --git a/src/full-codegen.h b/src/full-codegen.h index 4adc1bd9b..bc85d570a 100644 --- a/src/full-codegen.h +++ b/src/full-codegen.h @@ -437,12 +437,8 @@ class FullCodeGenerator: public AstVisitor { // Feedback slot support. The feedback vector will be cleared during gc and // collected by the type-feedback oracle. Handle FeedbackVector() { - return feedback_vector_; + return info_->feedback_vector(); } - void StoreFeedbackVectorSlot(int slot, Handle object) { - feedback_vector_->set(slot, *object); - } - void InitializeFeedbackVector(); // Record a call's return site offset, used to rebuild the frame if the // called function was inlined at the site. @@ -848,7 +844,6 @@ class FullCodeGenerator: public AstVisitor { ZoneList back_edges_; int ic_total_count_; Handle handler_table_; - Handle feedback_vector_; Handle profiling_counter_; bool generate_debug_code_; diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc index 8894f238c..f5fb87ef4 100644 --- a/src/heap-snapshot-generator.cc +++ b/src/heap-snapshot-generator.cc @@ -1327,6 +1327,9 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences( SetInternalReference(obj, entry, "optimized_code_map", shared->optimized_code_map(), SharedFunctionInfo::kOptimizedCodeMapOffset); + SetInternalReference(obj, entry, + "feedback_vector", shared->feedback_vector(), + SharedFunctionInfo::kFeedbackVectorOffset); SetWeakReference(obj, entry, "initial_map", shared->initial_map(), SharedFunctionInfo::kInitialMapOffset); diff --git a/src/heap.cc b/src/heap.cc index 2d6b16ed7..4e0e8a67c 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -2684,7 +2684,6 @@ MaybeObject* Heap::AllocateTypeFeedbackInfo() { if (!maybe_info->To(&info)) return maybe_info; } info->initialize_storage(); - info->set_feedback_vector(empty_fixed_array(), SKIP_WRITE_BARRIER); return info; } @@ -3806,6 +3805,7 @@ MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) { share->set_script(undefined_value(), SKIP_WRITE_BARRIER); share->set_debug_info(undefined_value(), SKIP_WRITE_BARRIER); share->set_inferred_name(empty_string(), SKIP_WRITE_BARRIER); + share->set_feedback_vector(empty_fixed_array(), SKIP_WRITE_BARRIER); share->set_initial_map(undefined_value(), SKIP_WRITE_BARRIER); share->set_ast_node_count(0); share->set_counters(0); diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 1f819357f..5324ef39c 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -7210,6 +7210,7 @@ bool HOptimizedGraphBuilder::TryInline(Handle target, target_shared->set_scope_info(*target_scope_info); } target_shared->EnableDeoptimizationSupport(*target_info.code()); + target_shared->set_feedback_vector(*target_info.feedback_vector()); Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG, &target_info, target_shared); diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index a6ec56b28..380b15e3b 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -119,8 +119,6 @@ void FullCodeGenerator::Generate() { handler_table_ = isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); - InitializeFeedbackVector(); - profiling_counter_ = isolate()->factory()->NewCell( Handle(Smi::FromInt(FLAG_interrupt_budget), isolate())); SetFunctionPosition(function()); @@ -1104,15 +1102,10 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { Label non_proxy; __ bind(&fixed_array); - Handle feedback = Handle( - Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker), - isolate()); - StoreFeedbackVectorSlot(slot, feedback); - // No need for a write barrier, we are storing a Smi in the feedback vector. __ LoadHeapObject(ebx, FeedbackVector()); __ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(slot)), - Immediate(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker))); + Immediate(TypeFeedbackInfo::MegamorphicSentinel(isolate()))); __ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check __ mov(ecx, Operand(esp, 0 * kPointerSize)); // Get enumerated object @@ -2666,9 +2659,6 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) { // Record source position for debugger. SetSourcePosition(expr->position()); - Handle uninitialized = - TypeFeedbackInfo::UninitializedSentinel(isolate()); - StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized); __ LoadHeapObject(ebx, FeedbackVector()); __ mov(edx, Immediate(Smi::FromInt(expr->CallFeedbackSlot()))); @@ -2846,9 +2836,6 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) { __ mov(edi, Operand(esp, arg_count * kPointerSize)); // Record call targets in unoptimized code. - Handle uninitialized = - TypeFeedbackInfo::UninitializedSentinel(isolate()); - StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized); __ LoadHeapObject(ebx, FeedbackVector()); __ mov(edx, Immediate(Smi::FromInt(expr->CallNewFeedbackSlot()))); diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index 1601b6e76..9eec0a314 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -139,8 +139,6 @@ void FullCodeGenerator::Generate() { handler_table_ = isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); - InitializeFeedbackVector(); - profiling_counter_ = isolate()->factory()->NewCell( Handle(Smi::FromInt(FLAG_interrupt_budget), isolate())); SetFunctionPosition(function()); @@ -1176,12 +1174,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { Label non_proxy; __ bind(&fixed_array); - Handle feedback = Handle( - Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker), - isolate()); - StoreFeedbackVectorSlot(slot, feedback); __ li(a1, FeedbackVector()); - __ li(a2, Operand(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker))); + __ li(a2, Operand(TypeFeedbackInfo::MegamorphicSentinel(isolate()))); __ sw(a2, FieldMemOperand(a1, FixedArray::OffsetOfElementAt(slot))); __ li(a1, Operand(Smi::FromInt(1))); // Smi indicates slow check @@ -2737,9 +2731,6 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) { // Record source position for debugger. SetSourcePosition(expr->position()); - Handle uninitialized = - TypeFeedbackInfo::UninitializedSentinel(isolate()); - StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized); __ li(a2, FeedbackVector()); __ li(a3, Operand(Smi::FromInt(expr->CallFeedbackSlot()))); @@ -2924,9 +2915,6 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) { __ lw(a1, MemOperand(sp, arg_count * kPointerSize)); // Record call targets in unoptimized code. - Handle uninitialized = - TypeFeedbackInfo::UninitializedSentinel(isolate()); - StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized); __ li(a2, FeedbackVector()); __ li(a3, Operand(Smi::FromInt(expr->CallNewFeedbackSlot()))); diff --git a/src/objects-debug.cc b/src/objects-debug.cc index d64c8f979..31a59cbfb 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -368,7 +368,6 @@ void PolymorphicCodeCache::PolymorphicCodeCacheVerify() { void TypeFeedbackInfo::TypeFeedbackInfoVerify() { VerifyObjectField(kStorage1Offset); VerifyObjectField(kStorage2Offset); - VerifyHeapPointer(feedback_vector()); } @@ -545,6 +544,7 @@ void SharedFunctionInfo::SharedFunctionInfoVerify() { VerifyObjectField(kNameOffset); VerifyObjectField(kCodeOffset); VerifyObjectField(kOptimizedCodeMapOffset); + VerifyObjectField(kFeedbackVectorOffset); VerifyObjectField(kScopeInfoOffset); VerifyObjectField(kInstanceClassNameOffset); VerifyObjectField(kFunctionDataOffset); diff --git a/src/objects-inl.h b/src/objects-inl.h index a73dc5b35..74a252c63 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -1474,7 +1474,7 @@ AllocationSiteMode AllocationSite::GetMode( AllocationSiteMode AllocationSite::GetMode(ElementsKind from, ElementsKind to) { if (IsFastSmiElementsKind(from) && - IsMoreGeneralElementsKindTransition(from, to)) { + IsMoreGeneralElementsKindTransition(from, to)) { return TRACK_ALLOCATION_SITE; } @@ -4945,6 +4945,8 @@ ACCESSORS(SharedFunctionInfo, name, Object, kNameOffset) ACCESSORS(SharedFunctionInfo, optimized_code_map, Object, kOptimizedCodeMapOffset) ACCESSORS(SharedFunctionInfo, construct_stub, Code, kConstructStubOffset) +ACCESSORS(SharedFunctionInfo, feedback_vector, FixedArray, + kFeedbackVectorOffset) ACCESSORS(SharedFunctionInfo, initial_map, Object, kInitialMapOffset) ACCESSORS(SharedFunctionInfo, instance_class_name, Object, kInstanceClassNameOffset) @@ -6624,10 +6626,6 @@ bool TypeFeedbackInfo::matches_inlined_type_change_checksum(int checksum) { } -ACCESSORS(TypeFeedbackInfo, feedback_vector, FixedArray, - kFeedbackVectorOffset) - - SMI_ACCESSORS(AliasedArgumentsEntry, aliased_context_slot, kAliasedContextSlot) diff --git a/src/objects-printer.cc b/src/objects-printer.cc index bc8c7c7b6..6cf179860 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -566,8 +566,6 @@ void TypeFeedbackInfo::TypeFeedbackInfoPrint(FILE* out) { HeapObject::PrintHeader(out, "TypeFeedbackInfo"); PrintF(out, " - ic_total_count: %d, ic_with_type_info_count: %d\n", ic_total_count(), ic_with_type_info_count()); - PrintF(out, " - feedback_vector: "); - feedback_vector()->FixedArrayPrint(out); } @@ -878,6 +876,8 @@ void SharedFunctionInfo::SharedFunctionInfoPrint(FILE* out) { PrintF(out, "\n - length = %d", length()); PrintF(out, "\n - optimized_code_map = "); optimized_code_map()->ShortPrint(out); + PrintF(out, "\n - feedback_vector = "); + feedback_vector()->FixedArrayPrint(out); PrintF(out, "\n"); } diff --git a/src/objects-visiting-inl.h b/src/objects-visiting-inl.h index 010f3068a..c671e632b 100644 --- a/src/objects-visiting-inl.h +++ b/src/objects-visiting-inl.h @@ -426,9 +426,6 @@ void StaticMarkingVisitor::VisitCode( Map* map, HeapObject* object) { Heap* heap = map->GetHeap(); Code* code = Code::cast(object); - if (FLAG_cleanup_code_caches_at_gc) { - code->ClearTypeFeedbackInfo(heap); - } if (FLAG_age_code && !Serializer::enabled()) { code->MakeOlder(heap->mark_compact_collector()->marking_parity()); } @@ -444,6 +441,9 @@ void StaticMarkingVisitor::VisitSharedFunctionInfo( if (shared->ic_age() != heap->global_ic_age()) { shared->ResetForNewContext(heap->global_ic_age()); } + if (FLAG_cleanup_code_caches_at_gc) { + shared->ClearTypeFeedbackInfo(heap); + } if (FLAG_cache_optimized_code && FLAG_flush_optimized_code_cache && !shared->optimized_code_map()->IsSmi()) { diff --git a/src/objects.cc b/src/objects.cc index ad29c70fd..8e96c850d 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -10642,19 +10642,16 @@ void Code::ClearInlineCaches(Code::Kind* kind) { } -void Code::ClearTypeFeedbackInfo(Heap* heap) { - if (kind() != FUNCTION) return; - Object* raw_info = type_feedback_info(); - if (raw_info->IsTypeFeedbackInfo()) { - FixedArray* feedback_vector = - TypeFeedbackInfo::cast(raw_info)->feedback_vector(); - for (int i = 0; i < feedback_vector->length(); i++) { - Object* obj = feedback_vector->get(i); - if (!obj->IsAllocationSite()) { - // TODO(mvstanton): Can't I avoid a write barrier for this sentinel? - feedback_vector->set(i, - TypeFeedbackInfo::RawUninitializedSentinel(heap)); - } +void SharedFunctionInfo::ClearTypeFeedbackInfo(Heap* heap) { + FixedArray* vector = feedback_vector(); + for (int i = 0; i < vector->length(); i++) { + Object* obj = vector->get(i); + if (!obj->IsAllocationSite()) { + // The assert verifies we can skip the write barrier. + ASSERT(heap->uninitialized_symbol() == + TypeFeedbackInfo::RawUninitializedSentinel(heap)); + vector->set(i, TypeFeedbackInfo::RawUninitializedSentinel(heap), + SKIP_WRITE_BARRIER); } } } diff --git a/src/objects.h b/src/objects.h index 18fe68889..32741572b 100644 --- a/src/objects.h +++ b/src/objects.h @@ -5469,8 +5469,6 @@ class Code: public HeapObject { void ClearInlineCaches(); void ClearInlineCaches(Kind kind); - void ClearTypeFeedbackInfo(Heap* heap); - BailoutId TranslatePcOffsetToAstId(uint32_t pc_offset); uint32_t TranslateAstIdToPcOffset(BailoutId ast_id); @@ -6666,6 +6664,8 @@ class SharedFunctionInfo: public HeapObject { // Removed a specific optimized code object from the optimized code map. void EvictFromOptimizedCodeMap(Code* optimized_code, const char* reason); + void ClearTypeFeedbackInfo(Heap* heap); + // Trims the optimized code map after entries have been removed. void TrimOptimizedCodeMap(int shrink_by); @@ -6781,6 +6781,12 @@ class SharedFunctionInfo: public HeapObject { inline int construction_count(); inline void set_construction_count(int value); + // [feedback_vector] - accumulates ast node feedback from full-codegen and + // (increasingly) from crankshafted code where sufficient feedback isn't + // available. Currently the field is duplicated in + // TypeFeedbackInfo::feedback_vector, but the allocation is done here. + DECL_ACCESSORS(feedback_vector, FixedArray) + // [initial_map]: initial map of the first function called as a constructor. // Saved for the duration of the tracking phase. // This is a weak link (GC resets it to undefined_value if no other live @@ -7072,8 +7078,10 @@ class SharedFunctionInfo: public HeapObject { static const int kScriptOffset = kFunctionDataOffset + kPointerSize; static const int kDebugInfoOffset = kScriptOffset + kPointerSize; static const int kInferredNameOffset = kDebugInfoOffset + kPointerSize; - static const int kInitialMapOffset = + static const int kFeedbackVectorOffset = kInferredNameOffset + kPointerSize; + static const int kInitialMapOffset = + kFeedbackVectorOffset + kPointerSize; // ast_node_count is a Smi field. It could be grouped with another Smi field // into a PSEUDO_SMI_ACCESSORS pair (on x64), if one becomes available. static const int kAstNodeCountOffset = @@ -8168,8 +8176,6 @@ class TypeFeedbackInfo: public Struct { inline void set_inlined_type_change_checksum(int checksum); inline bool matches_inlined_type_change_checksum(int checksum); - DECL_ACCESSORS(feedback_vector, FixedArray) - static inline TypeFeedbackInfo* cast(Object* obj); // Dispatched behavior. @@ -8178,10 +8184,9 @@ class TypeFeedbackInfo: public Struct { static const int kStorage1Offset = HeapObject::kHeaderSize; static const int kStorage2Offset = kStorage1Offset + kPointerSize; - static const int kFeedbackVectorOffset = - kStorage2Offset + kPointerSize; - static const int kSize = kFeedbackVectorOffset + kPointerSize; + static const int kSize = kStorage2Offset + kPointerSize; + // TODO(mvstanton): move these sentinel declarations to shared function info. // The object that indicates an uninitialized cache. static inline Handle UninitializedSentinel(Isolate* isolate); @@ -8197,9 +8202,6 @@ class TypeFeedbackInfo: public Struct { // garbage collection (e.g., for patching the cache). static inline Object* RawUninitializedSentinel(Heap* heap); - static const int kForInFastCaseMarker = 0; - static const int kForInSlowCaseMarker = 1; - private: static const int kTypeChangeChecksumBits = 7; diff --git a/src/runtime.cc b/src/runtime.cc index bc67204f1..c67c8f6a3 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -2942,6 +2942,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { // Set the code, scope info, formal parameter count, and the length // of the target shared function info. target_shared->ReplaceCode(source_shared->code()); + target_shared->set_feedback_vector(source_shared->feedback_vector()); target_shared->set_scope_info(source_shared->scope_info()); target_shared->set_length(source_shared->length()); target_shared->set_formal_parameter_count( @@ -8488,10 +8489,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearFunctionTypeFeedback) { HandleScope scope(isolate); ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); + function->shared()->ClearTypeFeedbackInfo(isolate->heap()); Code* unoptimized = function->shared()->code(); if (unoptimized->kind() == Code::FUNCTION) { unoptimized->ClearInlineCaches(); - unoptimized->ClearTypeFeedbackInfo(isolate->heap()); } return isolate->heap()->undefined_value(); } diff --git a/src/type-info.cc b/src/type-info.cc index f17ea0d54..c01053373 100644 --- a/src/type-info.cc +++ b/src/type-info.cc @@ -43,16 +43,12 @@ namespace internal { TypeFeedbackOracle::TypeFeedbackOracle(Handle code, + Handle feedback_vector, Handle native_context, Zone* zone) : native_context_(native_context), - zone_(zone) { - Object* raw_info = code->type_feedback_info(); - if (raw_info->IsTypeFeedbackInfo()) { - feedback_vector_ = Handle(TypeFeedbackInfo::cast(raw_info)-> - feedback_vector()); - } - + zone_(zone), + feedback_vector_(feedback_vector) { BuildDictionary(code); ASSERT(dictionary_->IsDictionary()); } @@ -132,9 +128,9 @@ bool TypeFeedbackOracle::CallNewIsMonomorphic(int slot) { byte TypeFeedbackOracle::ForInType(int feedback_vector_slot) { Handle value = GetInfo(feedback_vector_slot); - return value->IsSmi() && - Smi::cast(*value)->value() == TypeFeedbackInfo::kForInFastCaseMarker - ? ForInStatement::FAST_FOR_IN : ForInStatement::SLOW_FOR_IN; + return value.is_identical_to( + TypeFeedbackInfo::UninitializedSentinel(isolate())) + ? ForInStatement::FAST_FOR_IN : ForInStatement::SLOW_FOR_IN; } diff --git a/src/type-info.h b/src/type-info.h index 6de92cec0..f0994e4c7 100644 --- a/src/type-info.h +++ b/src/type-info.h @@ -44,6 +44,7 @@ class SmallMapList; class TypeFeedbackOracle: public ZoneObject { public: TypeFeedbackOracle(Handle code, + Handle feedback_vector, Handle native_context, Zone* zone); diff --git a/src/typing.cc b/src/typing.cc index b925dc610..b62e909f4 100644 --- a/src/typing.cc +++ b/src/typing.cc @@ -40,6 +40,7 @@ AstTyper::AstTyper(CompilationInfo* info) : info_(info), oracle_( Handle(info->closure()->shared()->code()), + Handle(info->closure()->shared()->feedback_vector()), Handle(info->closure()->context()->native_context()), info->zone()), store_(info->zone()) { diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index efcf51917..ea5019119 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -119,8 +119,6 @@ void FullCodeGenerator::Generate() { handler_table_ = isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); - InitializeFeedbackVector(); - profiling_counter_ = isolate()->factory()->NewCell( Handle(Smi::FromInt(FLAG_interrupt_budget), isolate())); SetFunctionPosition(function()); @@ -1127,15 +1125,10 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { Label non_proxy; __ bind(&fixed_array); - Handle feedback = Handle( - Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker), - isolate()); - StoreFeedbackVectorSlot(slot, feedback); - // No need for a write barrier, we are storing a Smi in the feedback vector. __ Move(rbx, FeedbackVector()); __ Move(FieldOperand(rbx, FixedArray::OffsetOfElementAt(slot)), - Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker)); + TypeFeedbackInfo::MegamorphicSentinel(isolate())); __ Move(rbx, Smi::FromInt(1)); // Smi indicates slow check __ movp(rcx, Operand(rsp, 0 * kPointerSize)); // Get enumerated object STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); @@ -2649,9 +2642,6 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) { // Record source position for debugger. SetSourcePosition(expr->position()); - Handle uninitialized = - TypeFeedbackInfo::UninitializedSentinel(isolate()); - StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized); __ Move(rbx, FeedbackVector()); __ Move(rdx, Smi::FromInt(expr->CallFeedbackSlot())); @@ -2829,9 +2819,6 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) { __ movp(rdi, Operand(rsp, arg_count * kPointerSize)); // Record call targets in unoptimized code, but not in the snapshot. - Handle uninitialized = - TypeFeedbackInfo::UninitializedSentinel(isolate()); - StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized); __ Move(rbx, FeedbackVector()); __ Move(rdx, Smi::FromInt(expr->CallNewFeedbackSlot())); diff --git a/test/cctest/test-compiler.cc b/test/cctest/test-compiler.cc index 24eb87c22..065a58dad 100644 --- a/test/cctest/test-compiler.cc +++ b/test/cctest/test-compiler.cc @@ -312,6 +312,40 @@ TEST(GetScriptLineNumber) { } +TEST(FeedbackVectorPreservedAcrossRecompiles) { + if (i::FLAG_always_opt || !i::FLAG_crankshaft) return; + i::FLAG_allow_natives_syntax = true; + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + + // Make sure function f has a call that uses a type feedback slot. + CompileRun("function fun() {};" + "fun1 = fun;" + "function f(a) { a(); } f(fun1);"); + + Handle f = + v8::Utils::OpenHandle( + *v8::Handle::Cast( + CcTest::global()->Get(v8_str("f")))); + + // We shouldn't have deoptimization support. We want to recompile and + // verify that our feedback vector preserves information. + CHECK(!f->shared()->has_deoptimization_support()); + Handle feedback_vector(f->shared()->feedback_vector()); + + // Verify that we gathered feedback. + CHECK_EQ(1, feedback_vector->length()); + CHECK(feedback_vector->get(0)->IsJSFunction()); + + CompileRun("%OptimizeFunctionOnNextCall(f); f(fun1);"); + + // Verify that the feedback is still "gathered" despite a recompilation + // of the full code. + CHECK(f->shared()->has_deoptimization_support()); + CHECK(f->shared()->feedback_vector()->get(0)->IsJSFunction()); +} + + // Test that optimized code for different closures is actually shared // immediately by the FastNewClosureStub when run in the same context. TEST(OptimizedCodeSharing) { diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc index 059fd8fc3..3157f3e53 100644 --- a/test/cctest/test-heap.cc +++ b/test/cctest/test-heap.cc @@ -2855,8 +2855,7 @@ TEST(IncrementalMarkingClearsTypeFeedbackInfo) { *v8::Handle::Cast( CcTest::global()->Get(v8_str("f")))); - Handle feedback_vector(TypeFeedbackInfo::cast( - f->shared()->code()->type_feedback_info())->feedback_vector()); + Handle feedback_vector(f->shared()->feedback_vector()); CHECK_EQ(2, feedback_vector->length()); CHECK(feedback_vector->get(0)->IsJSFunction()); -- 2.34.1