[ic] Inline constant fields in IC

Previously, the handler would load the constant field from the holder
everytime by using the descriptor index. Instead, this patch inlines
the constant field directly into the handler.

Change-Id: Ia731811b135897033f4c5dc973031a30f25a64ed
Bug: v8:9616
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1688829
Commit-Queue: Sathya Gunasekaran  <gsathya@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63332}
This commit is contained in:
Sathya Gunasekaran 2019-08-22 10:13:26 +01:00 committed by Commit Bot
parent e66cee7e9e
commit 8ee507f1ca
5 changed files with 54 additions and 21 deletions

View File

@ -301,6 +301,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
TNode<WordT> handler_word = SmiUntag(smi_handler);
TNode<IntPtrT> handler_kind =
Signed(DecodeWord<LoadHandler::KindBits>(handler_word));
if (support_elements == kSupportElements) {
TVARIABLE(IntPtrT, var_intptr_index);
Label if_element(this), if_indexed_string(this), if_property(this),
@ -429,9 +430,11 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
module_export(this, Label::kDeferred), proxy(this, Label::kDeferred),
native_data_property(this, Label::kDeferred),
api_getter(this, Label::kDeferred);
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)), &field);
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kConstant)),
GotoIf(WordEqual(handler_kind,
IntPtrConstant(LoadHandler::kConstantFromPrototype)),
&constant);
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNonExistent)),
@ -479,11 +482,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
BIND(&constant);
{
Comment("constant_load");
TNode<IntPtrT> descriptor =
Signed(DecodeWord<LoadHandler::DescriptorBits>(handler_word));
Node* value = LoadDescriptorValue(LoadMap(holder), descriptor);
exit_point->Return(value);
exit_point->Return(holder);
}
BIND(&normal);
@ -625,7 +624,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase(
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)),
&return_true);
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kConstant)),
GotoIf(WordEqual(handler_kind,
IntPtrConstant(LoadHandler::kConstantFromPrototype)),
&return_true);
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNonExistent)),
@ -835,21 +835,37 @@ void AccessorAssembler::HandleLoadICProtoHandler(
},
miss, ic_mode);
TNode<MaybeObject> maybe_holder = LoadHandlerDataField(handler, 1);
TNode<MaybeObject> maybe_holder_or_constant =
LoadHandlerDataField(handler, 1);
Label load_from_cached_holder(this), done(this);
Label load_from_cached_holder(this), is_smi(this), done(this);
Branch(IsStrongReferenceTo(maybe_holder, NullConstant()), &done,
GotoIf(TaggedIsSmi(maybe_holder_or_constant), &is_smi);
Branch(IsStrongReferenceTo(maybe_holder_or_constant, NullConstant()), &done,
&load_from_cached_holder);
BIND(&is_smi);
{
CSA_ASSERT(
this,
WordEqual(
Signed(DecodeWord<LoadHandler::KindBits>(SmiUntag(smi_handler))),
IntPtrConstant(LoadHandler::kConstantFromPrototype)));
if (access_mode == LoadAccessMode::kHas) {
exit_point->Return(TrueConstant());
} else {
exit_point->Return(maybe_holder_or_constant);
}
}
BIND(&load_from_cached_holder);
{
// For regular holders, having passed the receiver map check and the
// validity cell check implies that |holder| is alive. However, for global
// object receivers, |maybe_holder| may be cleared.
CSA_ASSERT(this, IsWeakOrCleared(maybe_holder));
Node* holder = GetHeapObjectAssumeWeak(maybe_holder, miss);
// For regular holders, having passed the receiver map check and
// the validity cell check implies that |holder| is
// alive. However, for global object receivers, |maybe_holder| may
// be cleared.
CSA_ASSERT(this, IsWeakOrCleared(maybe_holder_or_constant));
Node* holder = GetHeapObjectAssumeWeak(maybe_holder_or_constant, miss);
var_holder->Bind(holder);
Goto(&done);
}

View File

@ -51,8 +51,8 @@ Handle<Smi> LoadHandler::LoadField(Isolate* isolate, FieldIndex field_index) {
return handle(Smi::FromInt(config), isolate);
}
Handle<Smi> LoadHandler::LoadConstant(Isolate* isolate, int descriptor) {
int config = KindBits::encode(kConstant) | DescriptorBits::encode(descriptor);
Handle<Smi> LoadHandler::LoadConstantFromPrototype(Isolate* isolate) {
int config = KindBits::encode(kConstantFromPrototype);
return handle(Smi::FromInt(config), isolate);
}

View File

@ -37,7 +37,7 @@ class LoadHandler final : public DataHandler {
kNormal,
kGlobal,
kField,
kConstant,
kConstantFromPrototype,
kAccessor,
kNativeDataProperty,
kApiGetter,
@ -116,8 +116,9 @@ class LoadHandler final : public DataHandler {
// Creates a Smi-handler for loading a field from fast object.
static inline Handle<Smi> LoadField(Isolate* isolate, FieldIndex field_index);
// Creates a Smi-handler for loading a constant from fast object.
static inline Handle<Smi> LoadConstant(Isolate* isolate, int descriptor);
// Creates a Smi-handler for loading a cached constant from fast
// prototype object.
static inline Handle<Smi> LoadConstantFromPrototype(Isolate* isolate);
// Creates a Smi-handler for calling a getter on a fast object.
static inline Handle<Smi> LoadAccessor(Isolate* isolate, int descriptor);

View File

@ -897,6 +897,18 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
if (receiver_is_holder) return smi_handler;
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH);
}
if (lookup->constness() == PropertyConstness::kConst &&
!receiver_is_holder) {
DCHECK(!lookup->is_dictionary_holder());
smi_handler = LoadHandler::LoadConstantFromPrototype(isolate());
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
Handle<Object> value = lookup->GetDataValue();
MaybeObjectHandle weak_value =
value->IsSmi() ? MaybeObjectHandle(*value, isolate())
: MaybeObjectHandle::Weak(*value, isolate());
return LoadHandler::LoadFromPrototype(isolate(), map, holder,
smi_handler, weak_value);
}
return LoadHandler::LoadFromPrototype(isolate(), map, holder,
smi_handler);
}

View File

@ -680,6 +680,10 @@ void Map::UpdateFieldType(Isolate* isolate, int descriptor, Handle<Name> name,
if (details.location() != kField) return;
DCHECK_EQ(kData, details.kind());
if (new_constness != details.constness() && is_prototype_map()) {
JSObject::InvalidatePrototypeChains(*this);
}
Zone zone(isolate->allocator(), ZONE_NAME);
ZoneQueue<Map> backlog(&zone);
backlog.push(*this);