[turboprop] Record handle to map in dynamic map checks operator
Monomorphic loads are quite common and it is important to keep these load accesses fast. Dynamic map checks increases the overhead for these monomorphic accesses by having to actually verify the IC state and check against a map from the feedback vector This was causing a significant (~2-3%) regression in JavaScript duration. To keep the common case of monomorphic checks fast, we now want to add a check against expected map (which passes in most cases) and move the rest of the checks to a builtin. i.e. we want dynamic map checks (when generating the code for loads in monomorphic state) to look like: if (incoming_map != HeapConstant(expected_map)) call_builtin; This helps us to keep the most common case fast and still gets the benefits of dynamic map checks. This cl is the first in the series of cls that will add this functionality. This cl makes the expected_map available for dynamic map checks operator. In follow up cls, we will add a builtin and update the code to use the builtin. Bug: v8:10582 Change-Id: I10992c6ba1fb005592de962310c208cff6829119 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2397894 Reviewed-by: Georg Neis <neis@chromium.org> Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Commit-Queue: Mythri Alle <mythria@chromium.org> Cr-Commit-Position: refs/heads/master@{#69798}
This commit is contained in:
parent
9c67790b74
commit
adfdccc0f1
@ -4667,12 +4667,12 @@ bool ElementAccessFeedback::HasOnlyStringMaps(JSHeapBroker* broker) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MinimorphicLoadPropertyAccessFeedback::MinimorphicLoadPropertyAccessFeedback(
|
MinimorphicLoadPropertyAccessFeedback::MinimorphicLoadPropertyAccessFeedback(
|
||||||
NameRef const& name, FeedbackSlotKind slot_kind, bool is_monomorphic,
|
NameRef const& name, FeedbackSlotKind slot_kind, Handle<Object> handler,
|
||||||
Handle<Object> handler, bool has_migration_target_maps)
|
MaybeHandle<Map> maybe_map, bool has_migration_target_maps)
|
||||||
: ProcessedFeedback(kMinimorphicPropertyAccess, slot_kind),
|
: ProcessedFeedback(kMinimorphicPropertyAccess, slot_kind),
|
||||||
name_(name),
|
name_(name),
|
||||||
is_monomorphic_(is_monomorphic),
|
|
||||||
handler_(handler),
|
handler_(handler),
|
||||||
|
maybe_map_(maybe_map),
|
||||||
has_migration_target_maps_(has_migration_target_maps) {
|
has_migration_target_maps_(has_migration_target_maps) {
|
||||||
DCHECK(IsLoadICKind(slot_kind));
|
DCHECK(IsLoadICKind(slot_kind));
|
||||||
}
|
}
|
||||||
@ -4810,9 +4810,13 @@ ProcessedFeedback const& JSHeapBroker::ReadFeedbackForPropertyAccess(
|
|||||||
static_name.has_value() ? static_name : GetNameFeedback(nexus);
|
static_name.has_value() ? static_name : GetNameFeedback(nexus);
|
||||||
MaybeObjectHandle handler = TryGetMinimorphicHandler(maps_and_handlers, kind);
|
MaybeObjectHandle handler = TryGetMinimorphicHandler(maps_and_handlers, kind);
|
||||||
if (!handler.is_null()) {
|
if (!handler.is_null()) {
|
||||||
|
MaybeHandle<Map> maybe_map;
|
||||||
|
if (nexus.ic_state() == MONOMORPHIC) {
|
||||||
|
DCHECK_EQ(maps.size(), 1);
|
||||||
|
maybe_map = maps[0];
|
||||||
|
}
|
||||||
return *zone()->New<MinimorphicLoadPropertyAccessFeedback>(
|
return *zone()->New<MinimorphicLoadPropertyAccessFeedback>(
|
||||||
*name, kind, nexus.ic_state() == MONOMORPHIC, handler.object(),
|
*name, kind, handler.object(), maybe_map, HasMigrationTargets(maps));
|
||||||
HasMigrationTargets(maps));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FilterRelevantReceiverMaps(isolate(), &maps);
|
FilterRelevantReceiverMaps(isolate(), &maps);
|
||||||
|
@ -1071,13 +1071,10 @@ Reduction JSNativeContextSpecialization::ReduceMinimorphicPropertyAccess(
|
|||||||
if (feedback.has_migration_target_maps()) {
|
if (feedback.has_migration_target_maps()) {
|
||||||
flags |= CheckMapsFlag::kTryMigrateInstance;
|
flags |= CheckMapsFlag::kTryMigrateInstance;
|
||||||
}
|
}
|
||||||
effect = graph()->NewNode(
|
effect =
|
||||||
simplified()->DynamicCheckMaps(
|
graph()->NewNode(simplified()->DynamicCheckMaps(flags, feedback.handler(),
|
||||||
flags, feedback.handler(), source,
|
feedback.map(), source),
|
||||||
feedback.is_monomorphic()
|
receiver, effect, control);
|
||||||
? DynamicCheckMapsParameters::ICState::kMonomorphic
|
|
||||||
: DynamicCheckMapsParameters::ICState::kPolymorphic),
|
|
||||||
receiver, effect, control);
|
|
||||||
value = access_builder.BuildMinimorphicLoadDataField(
|
value = access_builder.BuildMinimorphicLoadDataField(
|
||||||
feedback.name(), access_info, receiver, &effect, &control);
|
feedback.name(), access_info, receiver, &effect, &control);
|
||||||
|
|
||||||
|
@ -177,19 +177,20 @@ class MinimorphicLoadPropertyAccessFeedback : public ProcessedFeedback {
|
|||||||
public:
|
public:
|
||||||
MinimorphicLoadPropertyAccessFeedback(NameRef const& name,
|
MinimorphicLoadPropertyAccessFeedback(NameRef const& name,
|
||||||
FeedbackSlotKind slot_kind,
|
FeedbackSlotKind slot_kind,
|
||||||
bool is_monomorphic,
|
|
||||||
Handle<Object> handler,
|
Handle<Object> handler,
|
||||||
|
MaybeHandle<Map> maybe_map,
|
||||||
bool has_migration_target_maps);
|
bool has_migration_target_maps);
|
||||||
|
|
||||||
NameRef const& name() const { return name_; }
|
NameRef const& name() const { return name_; }
|
||||||
bool is_monomorphic() const { return is_monomorphic_; }
|
bool is_monomorphic() const { return !maybe_map_.is_null(); }
|
||||||
Handle<Object> handler() const { return handler_; }
|
Handle<Object> handler() const { return handler_; }
|
||||||
|
MaybeHandle<Map> map() const { return maybe_map_; }
|
||||||
bool has_migration_target_maps() const { return has_migration_target_maps_; }
|
bool has_migration_target_maps() const { return has_migration_target_maps_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NameRef const name_;
|
NameRef const name_;
|
||||||
bool const is_monomorphic_;
|
|
||||||
Handle<Object> const handler_;
|
Handle<Object> const handler_;
|
||||||
|
MaybeHandle<Map> const maybe_map_;
|
||||||
bool const has_migration_target_maps_;
|
bool const has_migration_target_maps_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -289,19 +289,26 @@ CheckMapsParameters const& CheckMapsParametersOf(Operator const* op) {
|
|||||||
|
|
||||||
bool operator==(DynamicCheckMapsParameters const& lhs,
|
bool operator==(DynamicCheckMapsParameters const& lhs,
|
||||||
DynamicCheckMapsParameters const& rhs) {
|
DynamicCheckMapsParameters const& rhs) {
|
||||||
return lhs.handler().address() == rhs.handler().address() &&
|
// FeedbackSource is sufficient as an equality check. FeedbackSource uniquely
|
||||||
lhs.feedback() == rhs.feedback() && lhs.state() == rhs.state();
|
// determines all other properties (handler, flags and the monomorphic map
|
||||||
|
DCHECK_IMPLIES(lhs.feedback() == rhs.feedback(),
|
||||||
|
lhs.flags() == rhs.flags() && lhs.state() == rhs.state() &&
|
||||||
|
lhs.handler().address() == rhs.handler().address() &&
|
||||||
|
lhs.map().address() == rhs.map().address());
|
||||||
|
return lhs.feedback() == rhs.feedback();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t hash_value(DynamicCheckMapsParameters const& p) {
|
size_t hash_value(DynamicCheckMapsParameters const& p) {
|
||||||
FeedbackSource::Hash feedback_hash;
|
FeedbackSource::Hash feedback_hash;
|
||||||
return base::hash_combine(p.handler().address(), feedback_hash(p.feedback()),
|
// FeedbackSource is sufficient for hashing. FeedbackSource uniquely
|
||||||
p.state());
|
// determines all other properties (handler, flags and the monomorphic map
|
||||||
|
return base::hash_combine(feedback_hash(p.feedback()));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os,
|
std::ostream& operator<<(std::ostream& os,
|
||||||
DynamicCheckMapsParameters const& p) {
|
DynamicCheckMapsParameters const& p) {
|
||||||
return os << p.handler() << ", " << p.feedback() << "," << p.state();
|
return os << p.handler() << ", " << p.feedback() << "," << p.state() << ","
|
||||||
|
<< p.flags() << "," << p.map().address();
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicCheckMapsParameters const& DynamicCheckMapsParametersOf(
|
DynamicCheckMapsParameters const& DynamicCheckMapsParametersOf(
|
||||||
@ -1474,11 +1481,10 @@ const Operator* SimplifiedOperatorBuilder::CheckMaps(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Operator* SimplifiedOperatorBuilder::DynamicCheckMaps(
|
const Operator* SimplifiedOperatorBuilder::DynamicCheckMaps(
|
||||||
CheckMapsFlags flags, Handle<Object> handler,
|
CheckMapsFlags flags, Handle<Object> handler, MaybeHandle<Map> maybe_map,
|
||||||
const FeedbackSource& feedback,
|
const FeedbackSource& feedback) {
|
||||||
DynamicCheckMapsParameters::ICState ic_state) {
|
DynamicCheckMapsParameters const parameters(flags, handler, maybe_map,
|
||||||
DynamicCheckMapsParameters const parameters(flags, handler, feedback,
|
feedback);
|
||||||
ic_state);
|
|
||||||
return zone()->New<Operator1<DynamicCheckMapsParameters>>( // --
|
return zone()->New<Operator1<DynamicCheckMapsParameters>>( // --
|
||||||
IrOpcode::kDynamicCheckMaps, // opcode
|
IrOpcode::kDynamicCheckMaps, // opcode
|
||||||
Operator::kNoThrow | Operator::kNoWrite, // flags
|
Operator::kNoThrow | Operator::kNoWrite, // flags
|
||||||
|
@ -432,19 +432,26 @@ class DynamicCheckMapsParameters final {
|
|||||||
enum ICState { kMonomorphic, kPolymorphic };
|
enum ICState { kMonomorphic, kPolymorphic };
|
||||||
|
|
||||||
DynamicCheckMapsParameters(CheckMapsFlags flags, Handle<Object> handler,
|
DynamicCheckMapsParameters(CheckMapsFlags flags, Handle<Object> handler,
|
||||||
const FeedbackSource& feedback, ICState state)
|
MaybeHandle<Map> maybe_map,
|
||||||
: flags_(flags), handler_(handler), feedback_(feedback), state_(state) {}
|
const FeedbackSource& feedback)
|
||||||
|
: flags_(flags),
|
||||||
|
handler_(handler),
|
||||||
|
maybe_map_(maybe_map),
|
||||||
|
feedback_(feedback) {}
|
||||||
|
|
||||||
CheckMapsFlags flags() const { return flags_; }
|
CheckMapsFlags flags() const { return flags_; }
|
||||||
Handle<Object> handler() const { return handler_; }
|
Handle<Object> handler() const { return handler_; }
|
||||||
|
MaybeHandle<Map> map() const { return maybe_map_; }
|
||||||
FeedbackSource const& feedback() const { return feedback_; }
|
FeedbackSource const& feedback() const { return feedback_; }
|
||||||
ICState const& state() const { return state_; }
|
ICState state() const {
|
||||||
|
return maybe_map_.is_null() ? ICState::kPolymorphic : ICState::kMonomorphic;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CheckMapsFlags const flags_;
|
CheckMapsFlags const flags_;
|
||||||
Handle<Object> const handler_;
|
Handle<Object> const handler_;
|
||||||
|
MaybeHandle<Map> const maybe_map_;
|
||||||
FeedbackSource const feedback_;
|
FeedbackSource const feedback_;
|
||||||
ICState const state_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool operator==(DynamicCheckMapsParameters const&,
|
bool operator==(DynamicCheckMapsParameters const&,
|
||||||
@ -875,10 +882,9 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
|
|||||||
const Operator* CheckInternalizedString();
|
const Operator* CheckInternalizedString();
|
||||||
const Operator* CheckMaps(CheckMapsFlags, ZoneHandleSet<Map>,
|
const Operator* CheckMaps(CheckMapsFlags, ZoneHandleSet<Map>,
|
||||||
const FeedbackSource& = FeedbackSource());
|
const FeedbackSource& = FeedbackSource());
|
||||||
const Operator* DynamicCheckMaps(
|
const Operator* DynamicCheckMaps(CheckMapsFlags flags, Handle<Object> handler,
|
||||||
CheckMapsFlags flags, Handle<Object> handler,
|
MaybeHandle<Map> map,
|
||||||
const FeedbackSource& feedback,
|
const FeedbackSource& feedback);
|
||||||
DynamicCheckMapsParameters::ICState ic_state);
|
|
||||||
const Operator* CheckNotTaggedHole();
|
const Operator* CheckNotTaggedHole();
|
||||||
const Operator* CheckNumber(const FeedbackSource& feedback);
|
const Operator* CheckNumber(const FeedbackSource& feedback);
|
||||||
const Operator* CheckReceiver();
|
const Operator* CheckReceiver();
|
||||||
|
Loading…
Reference in New Issue
Block a user