[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:
Mythri A 2020-09-09 18:10:39 +01:00 committed by Commit Bot
parent 9c67790b74
commit adfdccc0f1
5 changed files with 47 additions and 33 deletions

View File

@ -4667,12 +4667,12 @@ bool ElementAccessFeedback::HasOnlyStringMaps(JSHeapBroker* broker) const {
}
MinimorphicLoadPropertyAccessFeedback::MinimorphicLoadPropertyAccessFeedback(
NameRef const& name, FeedbackSlotKind slot_kind, bool is_monomorphic,
Handle<Object> handler, bool has_migration_target_maps)
NameRef const& name, FeedbackSlotKind slot_kind, Handle<Object> handler,
MaybeHandle<Map> maybe_map, bool has_migration_target_maps)
: ProcessedFeedback(kMinimorphicPropertyAccess, slot_kind),
name_(name),
is_monomorphic_(is_monomorphic),
handler_(handler),
maybe_map_(maybe_map),
has_migration_target_maps_(has_migration_target_maps) {
DCHECK(IsLoadICKind(slot_kind));
}
@ -4810,9 +4810,13 @@ ProcessedFeedback const& JSHeapBroker::ReadFeedbackForPropertyAccess(
static_name.has_value() ? static_name : GetNameFeedback(nexus);
MaybeObjectHandle handler = TryGetMinimorphicHandler(maps_and_handlers, kind);
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>(
*name, kind, nexus.ic_state() == MONOMORPHIC, handler.object(),
HasMigrationTargets(maps));
*name, kind, handler.object(), maybe_map, HasMigrationTargets(maps));
}
FilterRelevantReceiverMaps(isolate(), &maps);

View File

@ -1071,13 +1071,10 @@ Reduction JSNativeContextSpecialization::ReduceMinimorphicPropertyAccess(
if (feedback.has_migration_target_maps()) {
flags |= CheckMapsFlag::kTryMigrateInstance;
}
effect = graph()->NewNode(
simplified()->DynamicCheckMaps(
flags, feedback.handler(), source,
feedback.is_monomorphic()
? DynamicCheckMapsParameters::ICState::kMonomorphic
: DynamicCheckMapsParameters::ICState::kPolymorphic),
receiver, effect, control);
effect =
graph()->NewNode(simplified()->DynamicCheckMaps(flags, feedback.handler(),
feedback.map(), source),
receiver, effect, control);
value = access_builder.BuildMinimorphicLoadDataField(
feedback.name(), access_info, receiver, &effect, &control);

View File

@ -177,19 +177,20 @@ class MinimorphicLoadPropertyAccessFeedback : public ProcessedFeedback {
public:
MinimorphicLoadPropertyAccessFeedback(NameRef const& name,
FeedbackSlotKind slot_kind,
bool is_monomorphic,
Handle<Object> handler,
MaybeHandle<Map> maybe_map,
bool has_migration_target_maps);
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_; }
MaybeHandle<Map> map() const { return maybe_map_; }
bool has_migration_target_maps() const { return has_migration_target_maps_; }
private:
NameRef const name_;
bool const is_monomorphic_;
Handle<Object> const handler_;
MaybeHandle<Map> const maybe_map_;
bool const has_migration_target_maps_;
};

View File

@ -289,19 +289,26 @@ CheckMapsParameters const& CheckMapsParametersOf(Operator const* op) {
bool operator==(DynamicCheckMapsParameters const& lhs,
DynamicCheckMapsParameters const& rhs) {
return lhs.handler().address() == rhs.handler().address() &&
lhs.feedback() == rhs.feedback() && lhs.state() == rhs.state();
// FeedbackSource is sufficient as an equality check. FeedbackSource uniquely
// 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) {
FeedbackSource::Hash feedback_hash;
return base::hash_combine(p.handler().address(), feedback_hash(p.feedback()),
p.state());
// FeedbackSource is sufficient for hashing. FeedbackSource uniquely
// determines all other properties (handler, flags and the monomorphic map
return base::hash_combine(feedback_hash(p.feedback()));
}
std::ostream& operator<<(std::ostream& os,
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(
@ -1474,11 +1481,10 @@ const Operator* SimplifiedOperatorBuilder::CheckMaps(
}
const Operator* SimplifiedOperatorBuilder::DynamicCheckMaps(
CheckMapsFlags flags, Handle<Object> handler,
const FeedbackSource& feedback,
DynamicCheckMapsParameters::ICState ic_state) {
DynamicCheckMapsParameters const parameters(flags, handler, feedback,
ic_state);
CheckMapsFlags flags, Handle<Object> handler, MaybeHandle<Map> maybe_map,
const FeedbackSource& feedback) {
DynamicCheckMapsParameters const parameters(flags, handler, maybe_map,
feedback);
return zone()->New<Operator1<DynamicCheckMapsParameters>>( // --
IrOpcode::kDynamicCheckMaps, // opcode
Operator::kNoThrow | Operator::kNoWrite, // flags

View File

@ -432,19 +432,26 @@ class DynamicCheckMapsParameters final {
enum ICState { kMonomorphic, kPolymorphic };
DynamicCheckMapsParameters(CheckMapsFlags flags, Handle<Object> handler,
const FeedbackSource& feedback, ICState state)
: flags_(flags), handler_(handler), feedback_(feedback), state_(state) {}
MaybeHandle<Map> maybe_map,
const FeedbackSource& feedback)
: flags_(flags),
handler_(handler),
maybe_map_(maybe_map),
feedback_(feedback) {}
CheckMapsFlags flags() const { return flags_; }
Handle<Object> handler() const { return handler_; }
MaybeHandle<Map> map() const { return maybe_map_; }
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:
CheckMapsFlags const flags_;
Handle<Object> const handler_;
MaybeHandle<Map> const maybe_map_;
FeedbackSource const feedback_;
ICState const state_;
};
bool operator==(DynamicCheckMapsParameters const&,
@ -875,10 +882,9 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* CheckInternalizedString();
const Operator* CheckMaps(CheckMapsFlags, ZoneHandleSet<Map>,
const FeedbackSource& = FeedbackSource());
const Operator* DynamicCheckMaps(
CheckMapsFlags flags, Handle<Object> handler,
const FeedbackSource& feedback,
DynamicCheckMapsParameters::ICState ic_state);
const Operator* DynamicCheckMaps(CheckMapsFlags flags, Handle<Object> handler,
MaybeHandle<Map> map,
const FeedbackSource& feedback);
const Operator* CheckNotTaggedHole();
const Operator* CheckNumber(const FeedbackSource& feedback);
const Operator* CheckReceiver();