Commit a3ef2489 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

Cache fewer StoreIC-Transition handlers

Many handlers are not used again, so we can improve the cache hit rate
by caching fewer handlers. Specifically, in this CL, when a StoreIC
miss causes a new map transition to be created, then the handler is not
cached right away yet (it will be cached next time, when the transition
exists already).

Also, fix an embarrassing bug where growing a TransitionArray dropped
cached handlers. That further improves the cache hit rate. ;-)

Bug: chromium:752867, chromium:753819
Change-Id: Id8db5ca1e780a5fe8fc61db7f20996e61c65a90e
Reviewed-on: https://chromium-review.googlesource.com/619851Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47433}
parent da774d8c
...@@ -1562,7 +1562,8 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value, ...@@ -1562,7 +1562,8 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
if (it->HolderIsReceiverOrHiddenPrototype()) return false; if (it->HolderIsReceiverOrHiddenPrototype()) return false;
if (it->ExtendingNonExtensible(receiver)) return false; if (it->ExtendingNonExtensible(receiver)) return false;
it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode); created_new_transition_ = it->PrepareTransitionToDataProperty(
receiver, value, NONE, store_mode);
return it->IsCacheableTransition(); return it->IsCacheableTransition();
} }
} }
...@@ -1570,7 +1571,8 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value, ...@@ -1570,7 +1571,8 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
receiver = it->GetStoreTarget(); receiver = it->GetStoreTarget();
if (it->ExtendingNonExtensible(receiver)) return false; if (it->ExtendingNonExtensible(receiver)) return false;
it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode); created_new_transition_ =
it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode);
return it->IsCacheableTransition(); return it->IsCacheableTransition();
} }
...@@ -1793,8 +1795,10 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { ...@@ -1793,8 +1795,10 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransitionDH); TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransitionDH);
Handle<Object> handler = Handle<Object> handler =
StoreTransition(receiver_map(), holder, transition, lookup->name()); StoreTransition(receiver_map(), holder, transition, lookup->name());
TransitionsAccessor(receiver_map()) if (!created_new_transition_) {
.UpdateHandler(*lookup->name(), *handler); TransitionsAccessor(receiver_map())
.UpdateHandler(*lookup->name(), *handler);
}
return handler; return handler;
} }
......
...@@ -373,6 +373,8 @@ class StoreIC : public IC { ...@@ -373,6 +373,8 @@ class StoreIC : public IC {
Handle<Map> transition, Handle<Name> name); Handle<Map> transition, Handle<Name> name);
friend class IC; friend class IC;
bool created_new_transition_ = false;
}; };
class StoreGlobalIC : public StoreIC { class StoreGlobalIC : public StoreIC {
......
...@@ -382,11 +382,13 @@ void LookupIterator::ReconfigureDataProperty(Handle<Object> value, ...@@ -382,11 +382,13 @@ void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
// Can only be called when the receiver is a JSObject. JSProxy has to be handled // Can only be called when the receiver is a JSObject. JSProxy has to be handled
// via a trap. Adding properties to primitive values is not observable. // via a trap. Adding properties to primitive values is not observable.
void LookupIterator::PrepareTransitionToDataProperty( // Returns true if a new transition has been created, or false if an existing
// transition was followed.
bool LookupIterator::PrepareTransitionToDataProperty(
Handle<JSObject> receiver, Handle<Object> value, Handle<JSObject> receiver, Handle<Object> value,
PropertyAttributes attributes, Object::StoreFromKeyed store_mode) { PropertyAttributes attributes, Object::StoreFromKeyed store_mode) {
DCHECK(receiver.is_identical_to(GetStoreTarget())); DCHECK(receiver.is_identical_to(GetStoreTarget()));
if (state_ == TRANSITION) return; if (state_ == TRANSITION) return false;
if (!IsElement() && name()->IsPrivate()) { if (!IsElement() && name()->IsPrivate()) {
attributes = static_cast<PropertyAttributes>(attributes | DONT_ENUM); attributes = static_cast<PropertyAttributes>(attributes | DONT_ENUM);
...@@ -432,11 +434,13 @@ void LookupIterator::PrepareTransitionToDataProperty( ...@@ -432,11 +434,13 @@ void LookupIterator::PrepareTransitionToDataProperty(
PropertyDetails(kData, attributes, PropertyCellType::kNoCell); PropertyDetails(kData, attributes, PropertyCellType::kNoCell);
transition_ = map; transition_ = map;
} }
return; return false;
} }
bool created_new_map;
Handle<Map> transition = Map::TransitionToDataProperty( Handle<Map> transition = Map::TransitionToDataProperty(
map, name_, value, attributes, kDefaultFieldConstness, store_mode); map, name_, value, attributes, kDefaultFieldConstness, store_mode,
&created_new_map);
state_ = TRANSITION; state_ = TRANSITION;
transition_ = transition; transition_ = transition;
...@@ -448,6 +452,7 @@ void LookupIterator::PrepareTransitionToDataProperty( ...@@ -448,6 +452,7 @@ void LookupIterator::PrepareTransitionToDataProperty(
property_details_ = transition->GetLastDescriptorDetails(); property_details_ = transition->GetLastDescriptorDetails();
has_property_ = true; has_property_ = true;
} }
return created_new_map;
} }
void LookupIterator::ApplyTransitionToDataProperty(Handle<JSObject> receiver) { void LookupIterator::ApplyTransitionToDataProperty(Handle<JSObject> receiver) {
......
...@@ -214,7 +214,7 @@ class V8_EXPORT_PRIVATE LookupIterator final BASE_EMBEDDED { ...@@ -214,7 +214,7 @@ class V8_EXPORT_PRIVATE LookupIterator final BASE_EMBEDDED {
(IsElement() || !name_->IsPrivate()); (IsElement() || !name_->IsPrivate());
} }
void PrepareForDataProperty(Handle<Object> value); void PrepareForDataProperty(Handle<Object> value);
void PrepareTransitionToDataProperty(Handle<JSObject> receiver, bool PrepareTransitionToDataProperty(Handle<JSObject> receiver,
Handle<Object> value, Handle<Object> value,
PropertyAttributes attributes, PropertyAttributes attributes,
Object::StoreFromKeyed store_mode); Object::StoreFromKeyed store_mode);
......
...@@ -9477,7 +9477,8 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name, ...@@ -9477,7 +9477,8 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
Handle<Object> value, Handle<Object> value,
PropertyAttributes attributes, PropertyAttributes attributes,
PropertyConstness constness, PropertyConstness constness,
StoreFromKeyed store_mode) { StoreFromKeyed store_mode,
bool* created_new_map) {
RuntimeCallTimerScope stats_scope( RuntimeCallTimerScope stats_scope(
*map, map->is_prototype_map() *map, map->is_prototype_map()
? &RuntimeCallStats::PrototypeMap_TransitionToDataProperty ? &RuntimeCallStats::PrototypeMap_TransitionToDataProperty
...@@ -9492,6 +9493,7 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name, ...@@ -9492,6 +9493,7 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
Map* maybe_transition = Map* maybe_transition =
TransitionsAccessor(map).SearchTransition(*name, kData, attributes); TransitionsAccessor(map).SearchTransition(*name, kData, attributes);
if (maybe_transition != NULL) { if (maybe_transition != NULL) {
*created_new_map = false;
Handle<Map> transition(maybe_transition); Handle<Map> transition(maybe_transition);
int descriptor = transition->LastAdded(); int descriptor = transition->LastAdded();
...@@ -9502,6 +9504,7 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name, ...@@ -9502,6 +9504,7 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
return UpdateDescriptorForValue(transition, descriptor, constness, value); return UpdateDescriptorForValue(transition, descriptor, constness, value);
} }
*created_new_map = true;
TransitionFlag flag = INSERT_TRANSITION; TransitionFlag flag = INSERT_TRANSITION;
MaybeHandle<Map> maybe_map; MaybeHandle<Map> maybe_map;
if (!FLAG_track_constant_fields && value->IsJSFunction()) { if (!FLAG_track_constant_fields && value->IsJSFunction()) {
......
...@@ -528,12 +528,10 @@ class Map : public HeapObject { ...@@ -528,12 +528,10 @@ class Map : public HeapObject {
// transitions to avoid an explosion in the number of maps for objects used as // transitions to avoid an explosion in the number of maps for objects used as
// dictionaries. // dictionaries.
inline bool TooManyFastProperties(StoreFromKeyed store_mode) const; inline bool TooManyFastProperties(StoreFromKeyed store_mode) const;
static Handle<Map> TransitionToDataProperty(Handle<Map> map, static Handle<Map> TransitionToDataProperty(
Handle<Name> name, Handle<Map> map, Handle<Name> name, Handle<Object> value,
Handle<Object> value, PropertyAttributes attributes, PropertyConstness constness,
PropertyAttributes attributes, StoreFromKeyed store_mode, bool* created_new_map);
PropertyConstness constness,
StoreFromKeyed store_mode);
static Handle<Map> TransitionToAccessorProperty( static Handle<Map> TransitionToAccessorProperty(
Isolate* isolate, Handle<Map> map, Handle<Name> name, int descriptor, Isolate* isolate, Handle<Map> map, Handle<Name> name, int descriptor,
Handle<Object> getter, Handle<Object> setter, Handle<Object> getter, Handle<Object> setter,
......
...@@ -200,11 +200,11 @@ void TransitionsAccessor::Insert(Handle<Name> name, Handle<Map> target, ...@@ -200,11 +200,11 @@ void TransitionsAccessor::Insert(Handle<Name> name, Handle<Map> target,
DCHECK_NE(kNotFound, insertion_index); DCHECK_NE(kNotFound, insertion_index);
for (int i = 0; i < insertion_index; ++i) { for (int i = 0; i < insertion_index; ++i) {
result->Set(i, array->GetKey(i), array->GetTarget(i)); result->Set(i, array->GetKey(i), array->GetRawTarget(i));
} }
result->Set(insertion_index, *name, *target); result->Set(insertion_index, *name, *target);
for (int i = insertion_index; i < number_of_transitions; ++i) { for (int i = insertion_index; i < number_of_transitions; ++i) {
result->Set(i + 1, array->GetKey(i), array->GetTarget(i)); result->Set(i + 1, array->GetKey(i), array->GetRawTarget(i));
} }
SLOW_DCHECK(result->IsSortedNoDuplicates()); SLOW_DCHECK(result->IsSortedNoDuplicates());
...@@ -258,7 +258,7 @@ Object* TransitionsAccessor::SearchHandler(Name* name, ...@@ -258,7 +258,7 @@ Object* TransitionsAccessor::SearchHandler(Name* name,
out_transition); out_transition);
} }
if (raw_handler->IsFixedArray()) { if (raw_handler->IsFixedArray()) {
return StoreHandler::ValidFixedArrayHandlerOrNull(raw_handler, name, return StoreHandler::ValidFixedArrayHandlerOrNull(raw_handler, nullptr,
out_transition); out_transition);
} }
return nullptr; return nullptr;
......
...@@ -366,9 +366,10 @@ class Expectations { ...@@ -366,9 +366,10 @@ class Expectations {
heap_type); heap_type);
Handle<String> name = MakeName("prop", property_index); Handle<String> name = MakeName("prop", property_index);
bool created_new_map;
return Map::TransitionToDataProperty( return Map::TransitionToDataProperty(
map, name, value, attributes, constness, map, name, value, attributes, constness,
Object::CERTAINLY_NOT_STORE_FROM_KEYED); Object::CERTAINLY_NOT_STORE_FROM_KEYED, &created_new_map);
} }
Handle<Map> TransitionToDataConstant(Handle<Map> map, Handle<Map> TransitionToDataConstant(Handle<Map> map,
...@@ -379,9 +380,10 @@ class Expectations { ...@@ -379,9 +380,10 @@ class Expectations {
SetDataConstant(property_index, attributes, value); SetDataConstant(property_index, attributes, value);
Handle<String> name = MakeName("prop", property_index); Handle<String> name = MakeName("prop", property_index);
return Map::TransitionToDataProperty( bool created_new_map;
map, name, value, attributes, kConst, return Map::TransitionToDataProperty(map, name, value, attributes, kConst,
Object::CERTAINLY_NOT_STORE_FROM_KEYED); Object::CERTAINLY_NOT_STORE_FROM_KEYED,
&created_new_map);
} }
Handle<Map> FollowDataTransition(Handle<Map> map, Handle<Map> FollowDataTransition(Handle<Map> map,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment