[ic] Don't use slow stub handler for fresh transitioning stores.

Given that we got a store transition handler for free (because it's just
a transition map) there's no need to wait for a second "use" of that
transition in order to install a normal store transition handler.

Bug: v8:5988
Change-Id: Iecdcfdd096a8efffdd0662f1b1d604943e57d85a
Reviewed-on: https://chromium-review.googlesource.com/997553
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52442}
This commit is contained in:
Igor Sheludko 2018-04-05 11:35:08 +02:00 committed by Commit Bot
parent 1f7d80cd97
commit d1532a1aef
7 changed files with 19 additions and 37 deletions

View File

@ -1300,8 +1300,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;
created_new_transition_ = it->PrepareTransitionToDataProperty( it->PrepareTransitionToDataProperty(receiver, value, NONE,
receiver, value, NONE, store_mode); store_mode);
return it->IsCacheableTransition(); return it->IsCacheableTransition();
} }
} }
@ -1310,8 +1310,7 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
receiver = it->GetStoreTarget<JSObject>(); receiver = it->GetStoreTarget<JSObject>();
if (it->ExtendingNonExtensible(receiver)) return false; if (it->ExtendingNonExtensible(receiver)) return false;
created_new_transition_ = it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode);
it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode);
return it->IsCacheableTransition(); return it->IsCacheableTransition();
} }
@ -1435,13 +1434,6 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
return; return;
} }
} }
if (created_new_transition_) {
// The first time a transition is performed, there's a good chance that
// it won't be taken again, so don't bother creating a handler.
set_slow_stub_reason("new transition");
TraceIC("StoreIC", lookup->name());
return;
}
handler = ComputeHandler(lookup); handler = ComputeHandler(lookup);
} else { } else {
set_slow_stub_reason("LookupForWrite said 'false'"); set_slow_stub_reason("LookupForWrite said 'false'");

View File

@ -329,8 +329,6 @@ class StoreIC : public IC {
Handle<Object> ComputeHandler(LookupIterator* lookup); Handle<Object> ComputeHandler(LookupIterator* lookup);
friend class IC; friend class IC;
bool created_new_transition_ = false;
}; };
class StoreGlobalIC : public StoreIC { class StoreGlobalIC : public StoreIC {

View File

@ -495,14 +495,12 @@ 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.
// Returns true if a new transition has been created, or false if an existing void LookupIterator::PrepareTransitionToDataProperty(
// transition was followed.
bool LookupIterator::PrepareTransitionToDataProperty(
Handle<JSReceiver> receiver, Handle<Object> value, Handle<JSReceiver> receiver, Handle<Object> value,
PropertyAttributes attributes, Object::StoreFromKeyed store_mode) { PropertyAttributes attributes, Object::StoreFromKeyed store_mode) {
DCHECK_IMPLIES(receiver->IsJSProxy(), name()->IsPrivate()); DCHECK_IMPLIES(receiver->IsJSProxy(), name()->IsPrivate());
DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>())); DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>()));
if (state_ == TRANSITION) return false; if (state_ == TRANSITION) return;
if (!IsElement() && name()->IsPrivate()) { if (!IsElement() && name()->IsPrivate()) {
attributes = static_cast<PropertyAttributes>(attributes | DONT_ENUM); attributes = static_cast<PropertyAttributes>(attributes | DONT_ENUM);
@ -548,13 +546,11 @@ bool LookupIterator::PrepareTransitionToDataProperty(
PropertyDetails(kData, attributes, PropertyCellType::kNoCell); PropertyDetails(kData, attributes, PropertyCellType::kNoCell);
transition_ = map; transition_ = map;
} }
return false; return;
} }
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;
@ -566,7 +562,6 @@ bool LookupIterator::PrepareTransitionToDataProperty(
property_details_ = transition->GetLastDescriptorDetails(); property_details_ = transition->GetLastDescriptorDetails();
has_property_ = true; has_property_ = true;
} }
return created_new_map;
} }
void LookupIterator::ApplyTransitionToDataProperty( void LookupIterator::ApplyTransitionToDataProperty(

View File

@ -216,7 +216,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);
bool PrepareTransitionToDataProperty(Handle<JSReceiver> receiver, void PrepareTransitionToDataProperty(Handle<JSReceiver> receiver,
Handle<Object> value, Handle<Object> value,
PropertyAttributes attributes, PropertyAttributes attributes,
Object::StoreFromKeyed store_mode); Object::StoreFromKeyed store_mode);

View File

@ -9744,8 +9744,7 @@ 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()
? RuntimeCallCounterId::kPrototypeMap_TransitionToDataProperty ? RuntimeCallCounterId::kPrototypeMap_TransitionToDataProperty
@ -9760,7 +9759,6 @@ 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 != nullptr) { if (maybe_transition != nullptr) {
*created_new_map = false;
Handle<Map> transition(maybe_transition); Handle<Map> transition(maybe_transition);
int descriptor = transition->LastAdded(); int descriptor = transition->LastAdded();
@ -9771,7 +9769,6 @@ 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()) {

View File

@ -681,10 +681,12 @@ 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( static Handle<Map> TransitionToDataProperty(Handle<Map> map,
Handle<Map> map, Handle<Name> name, Handle<Object> value, Handle<Name> name,
PropertyAttributes attributes, PropertyConstness constness, Handle<Object> value,
StoreFromKeyed store_mode, bool* created_new_map); PropertyAttributes attributes,
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,

View File

@ -368,10 +368,9 @@ 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, &created_new_map); Object::CERTAINLY_NOT_STORE_FROM_KEYED);
} }
Handle<Map> TransitionToDataConstant(Handle<Map> map, Handle<Map> TransitionToDataConstant(Handle<Map> map,
@ -382,10 +381,9 @@ 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);
bool created_new_map; return Map::TransitionToDataProperty(
return Map::TransitionToDataProperty(map, name, value, attributes, kConst, 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,