[TurboFan] Never serialize FeedbackCells

The compiler is only interested in the contents if it contains a
FeedbackVector. If one is discovered, it is serialized, and we
ensure we'll either return it or nothing if the contents of
the cell changed on the main thread.

FeedbackCells can be reset if the bytecode for the associated
function is flushed. We have guarantees only for functions we
choose to inline that this doesn't happen (by holding a strong
handle to the SharedFunctionInfo).

Bug: v8:7790
Change-Id: I9ecff3f4aef39169d84501feae9e47f2d118054e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2434324
Commit-Queue: Michael Stanton <mvstanton@chromium.org>
Reviewed-by: Santiago Aboy Solanes <solanes@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72260}
This commit is contained in:
Mike Stanton 2021-01-22 12:07:59 +01:00 committed by Commit Bot
parent 5654bf0de9
commit 3fb206764d
16 changed files with 172 additions and 104 deletions

View File

@ -1048,7 +1048,7 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(
native_context_(native_context), native_context_(native_context),
shared_info_(shared_info), shared_info_(shared_info),
feedback_cell_(feedback_cell), feedback_cell_(feedback_cell),
feedback_vector_(feedback_cell.value().AsFeedbackVector()), feedback_vector_(feedback_cell.value()->AsFeedbackVector()),
invocation_frequency_(invocation_frequency), invocation_frequency_(invocation_frequency),
type_hint_lowering_( type_hint_lowering_(
broker, jsgraph, feedback_vector_, broker, jsgraph, feedback_vector_,
@ -4561,7 +4561,8 @@ void BuildGraphFromBytecode(JSHeapBroker* broker, Zone* local_zone,
BytecodeGraphBuilderFlags flags, BytecodeGraphBuilderFlags flags,
TickCounter* tick_counter) { TickCounter* tick_counter) {
DCHECK(broker->IsSerializedForCompilation( DCHECK(broker->IsSerializedForCompilation(
shared_info, feedback_cell.value().AsFeedbackVector())); shared_info, feedback_cell.value()->AsFeedbackVector()));
DCHECK(feedback_cell.value()->AsFeedbackVector().serialized());
BytecodeGraphBuilder builder( BytecodeGraphBuilder builder(
broker, local_zone, broker->target_native_context(), shared_info, broker, local_zone, broker->target_native_context(), shared_info,
feedback_cell, osr_offset, jsgraph, invocation_frequency, feedback_cell, osr_offset, jsgraph, invocation_frequency,

View File

@ -72,6 +72,7 @@ enum class OddballType : uint8_t {
V(ArrayBoilerplateDescription) \ V(ArrayBoilerplateDescription) \
V(CallHandlerInfo) \ V(CallHandlerInfo) \
V(Cell) \ V(Cell) \
V(FeedbackCell) \
V(SharedFunctionInfo) \ V(SharedFunctionInfo) \
V(TemplateObjectDescription) V(TemplateObjectDescription)
@ -116,7 +117,6 @@ enum class OddballType : uint8_t {
V(AllocationSite) \ V(AllocationSite) \
V(Code) \ V(Code) \
V(DescriptorArray) \ V(DescriptorArray) \
V(FeedbackCell) \
V(FeedbackVector) \ V(FeedbackVector) \
V(FixedArrayBase) \ V(FixedArrayBase) \
V(FunctionTemplateInfo) \ V(FunctionTemplateInfo) \
@ -544,7 +544,7 @@ class FeedbackCellRef : public HeapObjectRef {
Handle<FeedbackCell> object() const; Handle<FeedbackCell> object() const;
base::Optional<SharedFunctionInfoRef> shared_function_info() const; base::Optional<SharedFunctionInfoRef> shared_function_info() const;
HeapObjectRef value() const; base::Optional<FeedbackVectorRef> value() const;
}; };
class FeedbackVectorRef : public HeapObjectRef { class FeedbackVectorRef : public HeapObjectRef {

View File

@ -4073,8 +4073,13 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
return ReduceJSCall(node, SharedFunctionInfoRef(broker(), p.shared_info())); return ReduceJSCall(node, SharedFunctionInfoRef(broker(), p.shared_info()));
} else if (target->opcode() == IrOpcode::kCheckClosure) { } else if (target->opcode() == IrOpcode::kCheckClosure) {
FeedbackCellRef cell(broker(), FeedbackCellOf(target->op())); FeedbackCellRef cell(broker(), FeedbackCellOf(target->op()));
return ReduceJSCall(node, if (cell.shared_function_info().has_value()) {
cell.value().AsFeedbackVector().shared_function_info()); return ReduceJSCall(node, *cell.shared_function_info());
} else {
TRACE_BROKER_MISSING(broker(), "Unable to reduce JSCall. FeedbackCell "
<< cell << " has no FeedbackVector");
return NoChange();
}
} }
// If {target} is the result of a JSCreateBoundFunction operation, // If {target} is the result of a JSCreateBoundFunction operation,
@ -4153,11 +4158,10 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
} else if (feedback_target.has_value() && feedback_target->IsFeedbackCell()) { } else if (feedback_target.has_value() && feedback_target->IsFeedbackCell()) {
FeedbackCellRef feedback_cell( FeedbackCellRef feedback_cell(
broker(), feedback_target.value().AsFeedbackCell().object()); broker(), feedback_target.value().AsFeedbackCell().object());
if (feedback_cell.value().IsFeedbackVector()) { if (feedback_cell.value().has_value()) {
// Check that {target} is a closure with given {feedback_cell}, // Check that {target} is a closure with given {feedback_cell},
// which uniquely identifies a given function inside a native context. // which uniquely identifies a given function inside a native context.
FeedbackVectorRef feedback_vector = FeedbackVectorRef feedback_vector = *feedback_cell.value();
feedback_cell.value().AsFeedbackVector();
if (!feedback_vector.serialized()) { if (!feedback_vector.serialized()) {
TRACE_BROKER_MISSING( TRACE_BROKER_MISSING(
broker(), "feedback vector, not serialized: " << feedback_vector); broker(), "feedback vector, not serialized: " << feedback_vector);

View File

@ -1451,7 +1451,11 @@ class FeedbackCellData : public HeapObjectData {
FeedbackCellData::FeedbackCellData(JSHeapBroker* broker, ObjectData** storage, FeedbackCellData::FeedbackCellData(JSHeapBroker* broker, ObjectData** storage,
Handle<FeedbackCell> object) Handle<FeedbackCell> object)
: HeapObjectData(broker, storage, object), : HeapObjectData(broker, storage, object),
value_(broker->GetOrCreateData(object->value())) {} value_(object->value().IsFeedbackVector()
? broker->GetOrCreateData(object->value())
: nullptr) {
DCHECK(!FLAG_turbo_direct_heap_access);
}
class FeedbackVectorData : public HeapObjectData { class FeedbackVectorData : public HeapObjectData {
public: public:
@ -2776,62 +2780,93 @@ void JSHeapBroker::InitializeAndStartSerializing(
TRACE(this, "Finished serializing standard objects"); TRACE(this, "Finished serializing standard objects");
} }
// clang-format off
ObjectData* JSHeapBroker::GetOrCreateData(Handle<Object> object, ObjectData* JSHeapBroker::GetOrCreateData(Handle<Object> object,
ObjectRef::BackgroundSerialization background_serialization) { ObjectRef::BackgroundSerialization background_serialization) {
RefsMap::Entry* entry = refs_->LookupOrInsert(object.address()); ObjectData* return_value =
ObjectData* object_data = entry->value; TryGetOrCreateData(object, true, background_serialization);
DCHECK_NOT_NULL(return_value);
return return_value;
}
if (object_data == nullptr) { // clang-format off
ObjectData** data_storage = &(entry->value); ObjectData* JSHeapBroker::TryGetOrCreateData(Handle<Object> object,
// TODO(neis): Remove these Allow* once we serialize everything upfront. bool crash_on_error,
AllowHandleDereference handle_dereference; ObjectRef::BackgroundSerialization background_serialization) {
if (object->IsSmi()) { RefsMap::Entry* entry = refs_->Lookup(object.address());
object_data = zone()->New<ObjectData>(this, data_storage, object, kSmi); if (entry != nullptr) return entry->value;
} else if (IsReadOnlyHeapObject(*object)) {
object_data = zone()->New<ObjectData>(this, data_storage, object, if (mode() == JSHeapBroker::kDisabled) {
kUnserializedReadOnlyHeapObject); entry = refs_->LookupOrInsert(object.address());
ObjectData** storage = &(entry->value);
if (*storage == nullptr) {
entry->value = zone()->New<ObjectData>(
this, storage, object,
object->IsSmi() ? kSmi : kUnserializedHeapObject);
}
return *storage;
}
ObjectData* object_data;
if (object->IsSmi()) {
entry = refs_->LookupOrInsert(object.address());
object_data = zone()->New<ObjectData>(this, &(entry->value), object, kSmi);
} else if (IsReadOnlyHeapObject(*object)) {
entry = refs_->LookupOrInsert(object.address());
object_data = zone()->New<ObjectData>(this, &(entry->value), object,
kUnserializedReadOnlyHeapObject);
// TODO(solanes, v8:10866): Remove the if/else in this macro once we remove the // TODO(solanes, v8:10866): Remove the if/else in this macro once we remove the
// FLAG_turbo_direct_heap_access. // FLAG_turbo_direct_heap_access.
#define CREATE_DATA_FOR_DIRECT_READ(name) \ #define CREATE_DATA_FOR_DIRECT_READ(name) \
} else if (object->Is##name()) { \ } else if (object->Is##name()) { \
if (FLAG_turbo_direct_heap_access) { \ if (FLAG_turbo_direct_heap_access) { \
object_data = zone()->New<ObjectData>( \ entry = refs_->LookupOrInsert(object.address()); \
this, data_storage, object, kNeverSerializedHeapObject); \ object_data = zone()->New<ObjectData>( \
} else { \ this, &(entry->value), object, kNeverSerializedHeapObject); \
CHECK_EQ(mode(), kSerializing); \ } else if (mode() == kSerializing) { \
AllowHandleAllocation handle_allocation; \ AllowHandleAllocation handle_allocation; \
object_data = zone()->New<name##Data>(this, data_storage, \ entry = refs_->LookupOrInsert(object.address()); \
Handle<name>::cast(object)); \ object_data = zone()->New<name##Data>(this, &(entry->value), \
} Handle<name>::cast(object)); \
HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(CREATE_DATA_FOR_DIRECT_READ) } else { \
CHECK(!crash_on_error); \
return nullptr; \
}
HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(CREATE_DATA_FOR_DIRECT_READ)
#undef CREATE_DATA_FOR_DIRECT_READ #undef CREATE_DATA_FOR_DIRECT_READ
#define CREATE_DATA_FOR_POSSIBLE_SERIALIZATION(name) \ #define CREATE_DATA_FOR_POSSIBLE_SERIALIZATION(name) \
} else if (object->Is##name()) { \ } else if (object->Is##name()) { \
CHECK_IMPLIES(mode() == kSerialized, \ if (mode() == kSerialized && \
background_serialization \ background_serialization != \
== ObjectRef::BackgroundSerialization::kAllowed); \ ObjectRef::BackgroundSerialization::kAllowed) { \
AllowHandleAllocation handle_allocation; \ CHECK(!crash_on_error); \
object_data = zone()->New<name##Data>(this, data_storage, \ return nullptr; \
Handle<name>::cast(object)); } \
AllowHandleAllocation handle_allocation; \
entry = refs_->LookupOrInsert(object.address()); \
object_data = zone()->New<name##Data>(this, &(entry->value), \
Handle<name>::cast(object));
HEAP_BROKER_POSSIBLY_BACKGROUND_SERIALIZED_OBJECT_LIST( HEAP_BROKER_POSSIBLY_BACKGROUND_SERIALIZED_OBJECT_LIST(
CREATE_DATA_FOR_POSSIBLE_SERIALIZATION) CREATE_DATA_FOR_POSSIBLE_SERIALIZATION)
#undef CREATE_DATA_FOR_POSSIBLE_SERIALIZATION #undef CREATE_DATA_FOR_POSSIBLE_SERIALIZATION
#define CREATE_DATA_FOR_SERIALIZATION(name) \ #define CREATE_DATA_FOR_SERIALIZATION(name) \
} else if (object->Is##name()) { \ } else if (object->Is##name()) { \
CHECK_EQ(mode(), kSerializing); \ if (mode() == kSerializing) { \
AllowHandleAllocation handle_allocation; \ entry = refs_->LookupOrInsert(object.address()); \
object_data = zone()->New<name##Data>(this, data_storage, \ AllowHandleAllocation handle_allocation; \
Handle<name>::cast(object)); object_data = zone()->New<name##Data>(this, &(entry->value), \
HEAP_BROKER_SERIALIZED_OBJECT_LIST(CREATE_DATA_FOR_SERIALIZATION) Handle<name>::cast(object)); \
#undef CREATE_DATA_FOR_SERIALIZATION } else { \
} else { CHECK(!crash_on_error); \
UNREACHABLE(); return nullptr; \
} }
// At this point the entry pointer is not guaranteed to be valid as HEAP_BROKER_SERIALIZED_OBJECT_LIST(CREATE_DATA_FOR_SERIALIZATION)
// the refs_ hash hable could be resized by one of the constructors above. #undef CREATE_DATA_FOR_SERIALIZATION
DCHECK_EQ(object_data, refs_->Lookup(object.address())->value); } else {
UNREACHABLE();
} }
// At this point the entry pointer is not guaranteed to be valid as
// the refs_ hash hable could be resized by one of the constructors above.
DCHECK_EQ(object_data, refs_->Lookup(object.address())->value);
return object_data; return object_data;
} }
// clang-format on // clang-format on
@ -3583,7 +3618,24 @@ SharedFunctionInfo::Inlineability SharedFunctionInfoRef::GetInlineability()
return ObjectRef ::data()->AsSharedFunctionInfo()->GetInlineability(); return ObjectRef ::data()->AsSharedFunctionInfo()->GetInlineability();
} }
BIMODAL_ACCESSOR(FeedbackCell, HeapObject, value) base::Optional<FeedbackVectorRef> FeedbackCellRef::value() const {
if (data_->should_access_heap()) {
// Note that we use the synchronized accessor.
Object value = object()->value(kAcquireLoad);
if (!value.IsFeedbackVector()) return base::nullopt;
auto vector_handle = broker()->CanonicalPersistentHandle(value);
ObjectData* vector = broker()->TryGetOrCreateData(vector_handle, false);
if (vector) {
return FeedbackVectorRef(broker(), vector);
}
TRACE_BROKER_MISSING(
broker(),
"Unable to retrieve FeedbackVector from FeedbackCellRef " << *this);
return base::nullopt;
}
ObjectData* vector = ObjectRef::data()->AsFeedbackCell()->value();
return FeedbackVectorRef(broker(), vector->AsFeedbackVector());
}
base::Optional<ObjectRef> MapRef::GetStrongValue( base::Optional<ObjectRef> MapRef::GetStrongValue(
InternalIndex descriptor_index) const { InternalIndex descriptor_index) const {
@ -3900,28 +3952,9 @@ ObjectRef::ObjectRef(JSHeapBroker* broker, Handle<Object> object,
BackgroundSerialization background_serialization, BackgroundSerialization background_serialization,
bool check_type) bool check_type)
: broker_(broker) { : broker_(broker) {
switch (broker->mode()) { CHECK_NE(broker->mode(), JSHeapBroker::kRetired);
// We may have to create data in JSHeapBroker::kSerialized as well since we
// read the data from read only heap objects directly instead of serializing data_ = broker->GetOrCreateData(object, background_serialization);
// them.
case JSHeapBroker::kSerialized:
case JSHeapBroker::kSerializing:
data_ = broker->GetOrCreateData(object, background_serialization);
break;
case JSHeapBroker::kDisabled: {
RefsMap::Entry* entry = broker->refs_->LookupOrInsert(object.address());
ObjectData** storage = &(entry->value);
if (*storage == nullptr) {
entry->value = broker->zone()->New<ObjectData>(
broker, storage, object,
object->IsSmi() ? kSmi : kUnserializedHeapObject);
}
data_ = *storage;
break;
}
case JSHeapBroker::kRetired:
UNREACHABLE();
}
if (!data_) { // TODO(mslekova): Remove once we're on the background thread. if (!data_) { // TODO(mslekova): Remove once we're on the background thread.
object->Print(); object->Print();
} }
@ -4013,10 +4046,10 @@ Float64 FixedDoubleArrayData::Get(int i) const {
base::Optional<SharedFunctionInfoRef> FeedbackCellRef::shared_function_info() base::Optional<SharedFunctionInfoRef> FeedbackCellRef::shared_function_info()
const { const {
if (value().IsFeedbackVector()) { if (value()) {
FeedbackVectorRef vector = value().AsFeedbackVector(); FeedbackVectorRef vector = *value();
if (vector.serialized()) { if (vector.serialized()) {
return value().AsFeedbackVector().shared_function_info(); return vector.shared_function_info();
} }
} }
return base::nullopt; return base::nullopt;

View File

@ -158,6 +158,13 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
Object, ObjectRef::BackgroundSerialization background_serialization = Object, ObjectRef::BackgroundSerialization background_serialization =
ObjectRef::BackgroundSerialization::kDisallowed); ObjectRef::BackgroundSerialization::kDisallowed);
// Gets data only if we have it. However, thin wrappers will be created for
// smis, read-only objects and never-serialized objects.
ObjectData* TryGetOrCreateData(
Handle<Object>, bool crash_on_error,
ObjectRef::BackgroundSerialization background_serialization =
ObjectRef::BackgroundSerialization::kDisallowed);
// Check if {object} is any native context's %ArrayPrototype% or // Check if {object} is any native context's %ArrayPrototype% or
// %ObjectPrototype%. // %ObjectPrototype%.
bool IsArrayOrObjectPrototype(const JSObjectRef& object) const; bool IsArrayOrObjectPrototype(const JSObjectRef& object) const;

View File

@ -29,8 +29,10 @@ Reduction JSHeapCopyReducer::Reduce(Node* node) {
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kCheckClosure: { case IrOpcode::kCheckClosure: {
FeedbackCellRef cell(broker(), FeedbackCellOf(node->op())); FeedbackCellRef cell(broker(), FeedbackCellOf(node->op()));
FeedbackVectorRef feedback_vector = cell.value().AsFeedbackVector(); base::Optional<FeedbackVectorRef> feedback_vector = cell.value();
feedback_vector.Serialize(); if (feedback_vector.has_value()) {
feedback_vector->Serialize();
}
break; break;
} }
case IrOpcode::kHeapConstant: { case IrOpcode::kHeapConstant: {

View File

@ -111,12 +111,9 @@ JSInliningHeuristic::Candidate JSInliningHeuristic::CollectFunctions(
if (m.IsCheckClosure()) { if (m.IsCheckClosure()) {
DCHECK(!out.functions[0].has_value()); DCHECK(!out.functions[0].has_value());
FeedbackCellRef feedback_cell(broker(), FeedbackCellOf(m.op())); FeedbackCellRef feedback_cell(broker(), FeedbackCellOf(m.op()));
SharedFunctionInfoRef shared_info = SharedFunctionInfoRef shared_info = *feedback_cell.shared_function_info();
feedback_cell.shared_function_info().value();
out.shared_info = shared_info; out.shared_info = shared_info;
if (feedback_cell.value().IsFeedbackVector() && if (CanConsiderForInlining(broker(), shared_info, *feedback_cell.value())) {
CanConsiderForInlining(broker(), shared_info,
feedback_cell.value().AsFeedbackVector())) {
out.bytecode[0] = shared_info.GetBytecodeArray(); out.bytecode[0] = shared_info.GetBytecodeArray();
} }
out.num_functions = 1; out.num_functions = 1;
@ -129,9 +126,8 @@ JSInliningHeuristic::Candidate JSInliningHeuristic::CollectFunctions(
FeedbackCellRef feedback_cell = n.GetFeedbackCellRefChecked(broker()); FeedbackCellRef feedback_cell = n.GetFeedbackCellRefChecked(broker());
SharedFunctionInfoRef shared_info(broker(), p.shared_info()); SharedFunctionInfoRef shared_info(broker(), p.shared_info());
out.shared_info = shared_info; out.shared_info = shared_info;
if (feedback_cell.value().IsFeedbackVector() && if (feedback_cell.value().has_value() &&
CanConsiderForInlining(broker(), shared_info, CanConsiderForInlining(broker(), shared_info, *feedback_cell.value())) {
feedback_cell.value().AsFeedbackVector())) {
out.bytecode[0] = shared_info.GetBytecodeArray(); out.bytecode[0] = shared_info.GetBytecodeArray();
} }
out.num_functions = 1; out.num_functions = 1;

View File

@ -431,15 +431,19 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
shared_info->object()); shared_info->object());
} }
TRACE("Inlining " << *shared_info << " into " << outer_shared_info
<< ((exception_target != nullptr) ? " (inside try-block)"
: ""));
// Determine the target's feedback vector and its context. // Determine the target's feedback vector and its context.
Node* context; Node* context;
FeedbackCellRef feedback_cell = DetermineCallContext(node, &context); FeedbackCellRef feedback_cell = DetermineCallContext(node, &context);
CHECK(broker()->IsSerializedForCompilation( if (!broker()->IsSerializedForCompilation(*shared_info,
*shared_info, feedback_cell.value().AsFeedbackVector())); *feedback_cell.value())) {
TRACE("Not inlining " << *shared_info << " into " << outer_shared_info
<< " because it wasn't serialized for compilation.");
return NoChange();
}
TRACE("Inlining " << *shared_info << " into " << outer_shared_info
<< ((exception_target != nullptr) ? " (inside try-block)"
: ""));
// ---------------------------------------------------------------- // ----------------------------------------------------------------
// After this point, we've made a decision to inline this function. // After this point, we've made a decision to inline this function.
// We shall not bailout from inlining if we got here. // We shall not bailout from inlining if we got here.

View File

@ -1713,7 +1713,10 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) {
shared = SharedFunctionInfoRef(broker(), ccp.shared_info()); shared = SharedFunctionInfoRef(broker(), ccp.shared_info());
} else if (target->opcode() == IrOpcode::kCheckClosure) { } else if (target->opcode() == IrOpcode::kCheckClosure) {
FeedbackCellRef cell(broker(), FeedbackCellOf(target->op())); FeedbackCellRef cell(broker(), FeedbackCellOf(target->op()));
shared = cell.value().AsFeedbackVector().shared_function_info(); base::Optional<FeedbackVectorRef> feedback_vector = cell.value();
if (feedback_vector.has_value()) {
shared = feedback_vector->shared_function_info();
}
} }
if (shared.has_value()) { if (shared.has_value()) {

View File

@ -2142,10 +2142,8 @@ void SerializerForBackgroundCompilation::ProcessCallOrConstruct(
callee.AddConstant(target->object(), zone(), broker()); callee.AddConstant(target->object(), zone(), broker());
} else { } else {
// Call; target is feedback cell or callee. // Call; target is feedback cell or callee.
if (target->IsFeedbackCell() && if (target->IsFeedbackCell() && target->AsFeedbackCell().value()) {
target->AsFeedbackCell().value().IsFeedbackVector()) { FeedbackVectorRef vector = *target->AsFeedbackCell().value();
FeedbackVectorRef vector =
target->AsFeedbackCell().value().AsFeedbackVector();
vector.Serialize(); vector.Serialize();
VirtualClosure virtual_closure( VirtualClosure virtual_closure(
vector.shared_function_info().object(), vector.object(), vector.shared_function_info().object(), vector.object(),

View File

@ -1054,6 +1054,8 @@ void FeedbackVector::FeedbackVectorPrint(std::ostream& os) { // NOLINT
os << "\n - optimization tier: " << optimization_tier(); os << "\n - optimization tier: " << optimization_tier();
os << "\n - invocation count: " << invocation_count(); os << "\n - invocation count: " << invocation_count();
os << "\n - profiler ticks: " << profiler_ticks(); os << "\n - profiler ticks: " << profiler_ticks();
os << "\n - closure feedback cell array: ";
closure_feedback_cell_array().ClosureFeedbackCellArrayPrint(os);
FeedbackMetadataIterator iter(metadata()); FeedbackMetadataIterator iter(metadata());
while (iter.HasNext()) { while (iter.HasNext()) {
@ -1421,6 +1423,9 @@ void JSFunction::JSFunctionPrint(std::ostream& os) { // NOLINT
os << "feedback metadata is not available in SFI\n"; os << "feedback metadata is not available in SFI\n";
} else if (has_feedback_vector()) { } else if (has_feedback_vector()) {
feedback_vector().FeedbackVectorPrint(os); feedback_vector().FeedbackVectorPrint(os);
} else if (has_closure_feedback_cell_array()) {
os << "No feedback vector, but we have a closure feedback cell array\n";
closure_feedback_cell_array().ClosureFeedbackCellArrayPrint(os);
} else { } else {
os << "not available\n"; os << "not available\n";
} }

View File

@ -21,6 +21,8 @@ namespace internal {
TQ_OBJECT_CONSTRUCTORS_IMPL(FeedbackCell) TQ_OBJECT_CONSTRUCTORS_IMPL(FeedbackCell)
RELEASE_ACQUIRE_ACCESSORS(FeedbackCell, value, HeapObject, kValueOffset)
void FeedbackCell::clear_padding() { void FeedbackCell::clear_padding() {
if (FeedbackCell::kAlignedSize == FeedbackCell::kUnalignedSize) return; if (FeedbackCell::kAlignedSize == FeedbackCell::kUnalignedSize) return;
DCHECK_GE(FeedbackCell::kAlignedSize, FeedbackCell::kUnalignedSize); DCHECK_GE(FeedbackCell::kAlignedSize, FeedbackCell::kUnalignedSize);

View File

@ -28,6 +28,11 @@ class FeedbackCell : public TorqueGeneratedFeedbackCell<FeedbackCell, Struct> {
static const int kUnalignedSize = kSize; static const int kUnalignedSize = kSize;
static const int kAlignedSize = RoundUp<kObjectAlignment>(int{kSize}); static const int kAlignedSize = RoundUp<kObjectAlignment>(int{kSize});
using TorqueGeneratedFeedbackCell<FeedbackCell, Struct>::value;
using TorqueGeneratedFeedbackCell<FeedbackCell, Struct>::set_value;
DECL_RELEASE_ACQUIRE_ACCESSORS(value, HeapObject)
inline void clear_padding(); inline void clear_padding();
inline void reset_feedback_vector( inline void reset_feedback_vector(
base::Optional<std::function<void(HeapObject object, ObjectSlot slot, base::Optional<std::function<void(HeapObject object, ObjectSlot slot,

View File

@ -29,6 +29,8 @@ OBJECT_CONSTRUCTORS_IMPL(JSFunction, JSFunctionOrBoundFunction)
CAST_ACCESSOR(JSFunction) CAST_ACCESSOR(JSFunction)
ACCESSORS(JSFunction, raw_feedback_cell, FeedbackCell, kFeedbackCellOffset) ACCESSORS(JSFunction, raw_feedback_cell, FeedbackCell, kFeedbackCellOffset)
RELEASE_ACQUIRE_ACCESSORS(JSFunction, raw_feedback_cell, FeedbackCell,
kFeedbackCellOffset)
FeedbackVector JSFunction::feedback_vector() const { FeedbackVector JSFunction::feedback_vector() const {
DCHECK(has_feedback_vector()); DCHECK(has_feedback_vector());

View File

@ -282,9 +282,10 @@ void JSFunction::EnsureClosureFeedbackCellArray(Handle<JSFunction> function) {
if (function->raw_feedback_cell() == isolate->heap()->many_closures_cell()) { if (function->raw_feedback_cell() == isolate->heap()->many_closures_cell()) {
Handle<FeedbackCell> feedback_cell = Handle<FeedbackCell> feedback_cell =
isolate->factory()->NewOneClosureCell(feedback_cell_array); isolate->factory()->NewOneClosureCell(feedback_cell_array);
function->set_raw_feedback_cell(*feedback_cell); function->set_raw_feedback_cell(*feedback_cell, kReleaseStore);
} else { } else {
function->raw_feedback_cell().set_value(*feedback_cell_array); function->raw_feedback_cell().set_value(*feedback_cell_array,
kReleaseStore);
} }
} }
@ -310,7 +311,7 @@ void JSFunction::EnsureFeedbackVector(Handle<JSFunction> function,
// for more details. // for more details.
DCHECK(function->raw_feedback_cell() != DCHECK(function->raw_feedback_cell() !=
isolate->heap()->many_closures_cell()); isolate->heap()->many_closures_cell());
function->raw_feedback_cell().set_value(*feedback_vector); function->raw_feedback_cell().set_value(*feedback_vector, kReleaseStore);
function->raw_feedback_cell().SetInterruptBudget(); function->raw_feedback_cell().SetInterruptBudget();
} }

View File

@ -165,6 +165,11 @@ class JSFunction : public JSFunctionOrBoundFunction {
// the JSFunction's bytecode being flushed. // the JSFunction's bytecode being flushed.
DECL_ACCESSORS(raw_feedback_cell, FeedbackCell) DECL_ACCESSORS(raw_feedback_cell, FeedbackCell)
// [raw_feedback_cell] (synchronized version) When this is initialized from a
// newly allocated object (instead of a root sentinel), it should
// be written with release store semantics.
DECL_RELEASE_ACQUIRE_ACCESSORS(raw_feedback_cell, FeedbackCell)
// Functions related to feedback vector. feedback_vector() can be used once // Functions related to feedback vector. feedback_vector() can be used once
// the function has feedback vectors allocated. feedback vectors may not be // the function has feedback vectors allocated. feedback vectors may not be
// available after compile when lazily allocating feedback vectors. // available after compile when lazily allocating feedback vectors.