diff --git a/src/a64/full-codegen-a64.cc b/src/a64/full-codegen-a64.cc index a5f7311717..dcab182e67 100644 --- a/src/a64/full-codegen-a64.cc +++ b/src/a64/full-codegen-a64.cc @@ -129,6 +129,8 @@ 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()); @@ -1160,8 +1162,12 @@ 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(TypeFeedbackInfo::MegamorphicSentinel(isolate()))); + __ Mov(x10, Operand(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker))); __ Str(x10, FieldMemOperand(x1, FixedArray::OffsetOfElementAt(slot))); __ Mov(x1, Operand(Smi::FromInt(1))); // Smi indicates slow check. @@ -2408,6 +2414,9 @@ 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()))); @@ -2604,6 +2613,9 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) { __ Peek(x1, arg_count * kXRegSize); // 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 bad1003eea..8672ccbe03 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -131,6 +131,8 @@ 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()); @@ -1164,8 +1166,12 @@ 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(TypeFeedbackInfo::MegamorphicSentinel(isolate()))); + __ mov(r2, Operand(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker))); __ str(r2, FieldMemOperand(r1, FixedArray::OffsetOfElementAt(slot))); __ mov(r1, Operand(Smi::FromInt(1))); // Smi indicates slow check @@ -2705,6 +2711,9 @@ 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()))); @@ -2891,6 +2900,9 @@ 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 97f8e6f41a..fdee097b43 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -140,13 +140,6 @@ void CompilationInfo::Initialize(Isolate* isolate, SetStrictMode(shared_info_->strict_mode()); } set_bailout_reason(kUnknown); - - if (!shared_info().is_null() && shared_info()->is_compiled()) { - // We should initialize the CompilationInfo feedback vector from the - // passed in shared info, rather than creating a new one. - feedback_vector_ = Handle(shared_info()->feedback_vector(), - isolate); - } } @@ -256,20 +249,6 @@ 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); } @@ -591,8 +570,6 @@ 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(); @@ -846,8 +823,7 @@ static Handle CompileToplevel(CompilationInfo* info) { lit->materialized_literal_count(), lit->is_generator(), info->code(), - ScopeInfo::Create(info->scope(), info->zone()), - info->feedback_vector()); + ScopeInfo::Create(info->scope(), info->zone())); ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position()); SetFunctionInfo(result, lit, true, script); @@ -1046,8 +1022,7 @@ Handle Compiler::BuildFunctionInfo(FunctionLiteral* literal, literal->materialized_literal_count(), literal->is_generator(), info.code(), - scope_info, - info.feedback_vector()); + scope_info); 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 e4ade7b97a..f63475cfa9 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -175,9 +175,6 @@ 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()); @@ -406,9 +403,6 @@ 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 6f86647ef5..4dd7f770d1 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1542,12 +1542,10 @@ Handle Factory::NewSharedFunctionInfo( int number_of_literals, bool is_generator, Handle code, - Handle scope_info, - Handle feedback_vector) { + Handle scope_info) { 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 558ff85a98..a87af1df06 100644 --- a/src/factory.h +++ b/src/factory.h @@ -517,8 +517,7 @@ class Factory { int number_of_literals, bool is_generator, Handle code, - Handle scope_info, - Handle feedback_vector); + Handle scope_info); Handle NewSharedFunctionInfo(Handle name); Handle NewJSMessageObject( diff --git a/src/full-codegen.cc b/src/full-codegen.cc index 165d007571..2170b84212 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -386,6 +386,18 @@ 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()); @@ -404,6 +416,7 @@ 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); } @@ -1605,8 +1618,7 @@ void FullCodeGenerator::VisitNativeFunctionLiteral( bool is_generator = false; Handle shared = isolate()->factory()->NewSharedFunctionInfo(name, literals, is_generator, - code, Handle(fun->shared()->scope_info()), - Handle(fun->shared()->feedback_vector())); + code, Handle(fun->shared()->scope_info())); 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 f2e39de1ce..7d035279a9 100644 --- a/src/full-codegen.h +++ b/src/full-codegen.h @@ -437,8 +437,12 @@ 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 info_->feedback_vector(); + return 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. @@ -840,6 +844,7 @@ 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 a7c1c2eb93..10e177d4f0 100644 --- a/src/heap-snapshot-generator.cc +++ b/src/heap-snapshot-generator.cc @@ -1398,9 +1398,6 @@ 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 25f712158e..90173a71e0 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -2687,6 +2687,7 @@ 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; } @@ -3808,7 +3809,6 @@ 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 2881e90534..04a045b315 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -7206,7 +7206,6 @@ 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 06da7ba0e7..096e2edb11 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -119,6 +119,8 @@ 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()); @@ -1102,10 +1104,15 @@ 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(TypeFeedbackInfo::MegamorphicSentinel(isolate()))); + Immediate(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker))); __ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check __ mov(ecx, Operand(esp, 0 * kPointerSize)); // Get enumerated object @@ -2658,6 +2665,9 @@ 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()))); @@ -2835,6 +2845,9 @@ 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 8250ce0ebf..02a890a356 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -139,6 +139,8 @@ 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()); @@ -1174,8 +1176,12 @@ 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(TypeFeedbackInfo::MegamorphicSentinel(isolate()))); + __ li(a2, Operand(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker))); __ sw(a2, FieldMemOperand(a1, FixedArray::OffsetOfElementAt(slot))); __ li(a1, Operand(Smi::FromInt(1))); // Smi indicates slow check @@ -2729,6 +2735,9 @@ 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()))); @@ -2913,6 +2922,9 @@ 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 4fafc1515d..5ca07d5add 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -368,6 +368,7 @@ void PolymorphicCodeCache::PolymorphicCodeCacheVerify() { void TypeFeedbackInfo::TypeFeedbackInfoVerify() { VerifyObjectField(kStorage1Offset); VerifyObjectField(kStorage2Offset); + VerifyHeapPointer(feedback_vector()); } @@ -551,7 +552,6 @@ 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 49fd9d4816..75ff8393e0 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -1481,7 +1481,7 @@ AllocationSiteMode AllocationSite::GetMode( AllocationSiteMode AllocationSite::GetMode(ElementsKind from, ElementsKind to) { if (IsFastSmiElementsKind(from) && - IsMoreGeneralElementsKindTransition(from, to)) { + IsMoreGeneralElementsKindTransition(from, to)) { return TRACK_ALLOCATION_SITE; } @@ -4980,8 +4980,6 @@ 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) @@ -6654,6 +6652,10 @@ 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 e287691532..518167cc51 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -566,6 +566,8 @@ 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); } @@ -879,8 +881,6 @@ 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 db84664d42..4f1498844d 100644 --- a/src/objects-visiting-inl.h +++ b/src/objects-visiting-inl.h @@ -427,6 +427,9 @@ 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()); } @@ -442,9 +445,6 @@ 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 492f7528f0..f1ab81f3fe 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -10640,16 +10640,19 @@ void Code::ClearInlineCaches(Code::Kind* kind) { } -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); +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)); + } } } } diff --git a/src/objects.h b/src/objects.h index c7725788e8..7a1ae26bd6 100644 --- a/src/objects.h +++ b/src/objects.h @@ -5497,6 +5497,8 @@ 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); @@ -6692,8 +6694,6 @@ 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); @@ -6802,12 +6802,6 @@ 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 @@ -7088,10 +7082,8 @@ 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 kFeedbackVectorOffset = - kInferredNameOffset + kPointerSize; static const int kInitialMapOffset = - kFeedbackVectorOffset + kPointerSize; + kInferredNameOffset + 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 = @@ -8177,6 +8169,8 @@ 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. @@ -8185,9 +8179,10 @@ class TypeFeedbackInfo: public Struct { static const int kStorage1Offset = HeapObject::kHeaderSize; static const int kStorage2Offset = kStorage1Offset + kPointerSize; - static const int kSize = kStorage2Offset + kPointerSize; + static const int kFeedbackVectorOffset = + kStorage2Offset + kPointerSize; + static const int kSize = kFeedbackVectorOffset + kPointerSize; - // TODO(mvstanton): move these sentinel declarations to shared function info. // The object that indicates an uninitialized cache. static inline Handle UninitializedSentinel(Isolate* isolate); @@ -8203,6 +8198,9 @@ 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 b9dc4181c5..8f0c8a0f96 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -2929,7 +2929,6 @@ 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( @@ -8478,10 +8477,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 6282ef68f9..35beb1808a 100644 --- a/src/type-info.cc +++ b/src/type-info.cc @@ -43,12 +43,16 @@ namespace internal { TypeFeedbackOracle::TypeFeedbackOracle(Handle code, - Handle feedback_vector, Handle native_context, Zone* zone) : native_context_(native_context), - zone_(zone), - feedback_vector_(feedback_vector) { + zone_(zone) { + Object* raw_info = code->type_feedback_info(); + if (raw_info->IsTypeFeedbackInfo()) { + feedback_vector_ = Handle(TypeFeedbackInfo::cast(raw_info)-> + feedback_vector()); + } + BuildDictionary(code); ASSERT(dictionary_->IsDictionary()); } @@ -128,9 +132,9 @@ bool TypeFeedbackOracle::CallNewIsMonomorphic(int slot) { byte TypeFeedbackOracle::ForInType(int feedback_vector_slot) { Handle value = GetInfo(feedback_vector_slot); - return value.is_identical_to( - TypeFeedbackInfo::UninitializedSentinel(isolate())) - ? ForInStatement::FAST_FOR_IN : ForInStatement::SLOW_FOR_IN; + return value->IsSmi() && + Smi::cast(*value)->value() == TypeFeedbackInfo::kForInFastCaseMarker + ? ForInStatement::FAST_FOR_IN : ForInStatement::SLOW_FOR_IN; } diff --git a/src/type-info.h b/src/type-info.h index 84944248ed..5bf653f1c2 100644 --- a/src/type-info.h +++ b/src/type-info.h @@ -44,7 +44,6 @@ 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 b62e909f47..b925dc610f 100644 --- a/src/typing.cc +++ b/src/typing.cc @@ -40,7 +40,6 @@ 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 b146809a24..b40ee92977 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -119,6 +119,8 @@ 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()); @@ -1125,10 +1127,15 @@ 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)), - TypeFeedbackInfo::MegamorphicSentinel(isolate())); + Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker)); __ 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); @@ -2641,6 +2648,9 @@ 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())); @@ -2818,6 +2828,9 @@ 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 079b286faa..120a053385 100644 --- a/test/cctest/test-compiler.cc +++ b/test/cctest/test-compiler.cc @@ -312,78 +312,6 @@ TEST(GetScriptLineNumber) { } -TEST(FeedbackVectorPreservedAcrossRecompiles) { - if (i::FLAG_always_opt || !i::FLAG_crankshaft) return; - i::FLAG_allow_natives_syntax = true; - CcTest::InitializeVM(); - if (!CcTest::i_isolate()->use_crankshaft()) return; - 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(FeedbackVectorRecreatedOnScopeChanges) { - if (i::FLAG_always_opt || !i::FLAG_lazy) return; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - - CompileRun("function builder() {" - " call_target = function() { return 3; };" - " return (function() {" - " eval('');" - " return function() {" - " 'use strict';" - " call_target();" - " }" - " })();" - "}" - "morphing_call = builder();"); - - Handle f = - v8::Utils::OpenHandle( - *v8::Handle::Cast( - CcTest::global()->Get(v8_str("morphing_call")))); - - // morphing_call should have one feedback vector slot for the call to - // call_target(), scoping analysis having been performed. - CHECK_EQ(1, f->shared()->feedback_vector()->length()); - // And yet it's not compiled. - CHECK(!f->shared()->is_compiled()); - - CompileRun("morphing_call();"); - - // On scoping analysis after lazy compile, the call is now a global - // call which needs no feedback vector slot. - CHECK_EQ(0, f->shared()->feedback_vector()->length()); - CHECK(f->shared()->is_compiled()); -} - - // 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 07828a9a48..d8af3d198b 100644 --- a/test/cctest/test-heap.cc +++ b/test/cctest/test-heap.cc @@ -2857,7 +2857,8 @@ TEST(IncrementalMarkingClearsTypeFeedbackInfo) { *v8::Handle::Cast( CcTest::global()->Get(v8_str("f")))); - Handle feedback_vector(f->shared()->feedback_vector()); + Handle feedback_vector(TypeFeedbackInfo::cast( + f->shared()->code()->type_feedback_info())->feedback_vector()); CHECK_EQ(2, feedback_vector->length()); CHECK(feedback_vector->get(0)->IsJSFunction());