[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:
parent
5654bf0de9
commit
3fb206764d
@ -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,
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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: {
|
||||||
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
@ -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()) {
|
||||||
|
@ -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(),
|
||||||
|
@ -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";
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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());
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user