[ic] Support store-normal IC with prototype check

BUG=

Change-Id: I56b865a5ae4283876058e2c2edf73a296608fc97
Reviewed-on: https://chromium-review.googlesource.com/448219
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#43517}
This commit is contained in:
Toon Verwaest 2017-03-01 12:14:48 +01:00 committed by Commit Bot
parent 6cff2ddf7d
commit e4f1862b52
3 changed files with 68 additions and 22 deletions

View File

@ -631,7 +631,8 @@ void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p,
Branch(TaggedIsSmi(maybe_transition_cell), &array_handler, &tuple_handler);
Variable var_transition(this, MachineRepresentation::kTagged);
Label if_transition(this), if_transition_to_constant(this);
Label if_transition(this), if_transition_to_constant(this),
if_store_normal(this);
Bind(&tuple_handler);
{
Node* transition = LoadWeakCellValue(maybe_transition_cell, miss);
@ -666,6 +667,8 @@ void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p,
GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(transition)), miss);
Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kStoreNormal)),
&if_store_normal);
GotoIf(WordEqual(handler_kind,
IntPtrConstant(StoreHandler::kTransitionToConstant)),
&if_transition_to_constant);
@ -696,6 +699,42 @@ void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p,
StoreMap(p->receiver, transition);
Return(p->value);
}
Bind(&if_store_normal);
{
Node* properties = LoadProperties(p->receiver);
Variable var_name_index(this, MachineType::PointerRepresentation());
Label found(this, &var_name_index), not_found(this);
NameDictionaryLookup<NameDictionary>(properties, p->name, &found,
&var_name_index, &not_found);
Bind(&found);
{
Node* details = LoadDetailsByKeyIndex<NameDictionary>(
properties, var_name_index.value());
// Check that the property is a writable data property (no accessor).
const int kTypeAndReadOnlyMask =
PropertyDetails::KindField::kMask |
PropertyDetails::kAttributesReadOnlyMask;
STATIC_ASSERT(kData == 0);
GotoIf(IsSetWord32(details, kTypeAndReadOnlyMask), miss);
StoreValueByKeyIndex<NameDictionary>(properties, var_name_index.value(),
p->value);
Return(p->value);
}
Bind(&not_found);
{
Label slow(this);
Add<NameDictionary>(properties, p->name, p->value, &slow);
Return(p->value);
Bind(&slow);
TailCallRuntime(Runtime::kKeyedStoreIC_Slow, p->context, p->value,
p->slot, p->vector, p->receiver, p->name);
}
}
}
}

View File

@ -1818,28 +1818,33 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map,
Handle<JSObject> holder,
Handle<Map> transition,
Handle<Name> name) {
int descriptor = transition->LastAdded();
Handle<DescriptorArray> descriptors(transition->instance_descriptors());
PropertyDetails details = descriptors->GetDetails(descriptor);
Representation representation = details.representation();
DCHECK(!representation.IsNone());
// Declarative handlers don't support access checks.
DCHECK(!transition->is_access_check_needed());
Handle<Object> smi_handler;
DCHECK_EQ(kData, details.kind());
if (details.location() == kDescriptor) {
smi_handler = StoreHandler::TransitionToConstant(isolate(), descriptor);
if (transition->is_dictionary_map()) {
smi_handler = StoreHandler::StoreNormal(isolate());
} else {
DCHECK_EQ(kField, details.location());
bool extend_storage =
Map::cast(transition->GetBackPointer())->unused_property_fields() == 0;
int descriptor = transition->LastAdded();
Handle<DescriptorArray> descriptors(transition->instance_descriptors());
PropertyDetails details = descriptors->GetDetails(descriptor);
Representation representation = details.representation();
DCHECK(!representation.IsNone());
FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor);
smi_handler = StoreHandler::TransitionToField(
isolate(), descriptor, index, representation, extend_storage);
// Declarative handlers don't support access checks.
DCHECK(!transition->is_access_check_needed());
DCHECK_EQ(kData, details.kind());
if (details.location() == kDescriptor) {
smi_handler = StoreHandler::TransitionToConstant(isolate(), descriptor);
} else {
DCHECK_EQ(kField, details.location());
bool extend_storage =
Map::cast(transition->GetBackPointer())->unused_property_fields() ==
0;
FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor);
smi_handler = StoreHandler::TransitionToField(
isolate(), descriptor, index, representation, extend_storage);
}
}
// |holder| is either a receiver if the property is non-existent or
// one of the prototypes.
@ -1910,6 +1915,7 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return slow_stub();
}
DCHECK(lookup->IsCacheableTransition());
Handle<Map> transition = lookup->transition_map();
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransitionDH);

View File

@ -211,8 +211,9 @@ class V8_EXPORT_PRIVATE LookupIterator final BASE_EMBEDDED {
bool IsCacheableTransition() {
DCHECK_EQ(TRANSITION, state_);
return transition_->IsPropertyCell() ||
(!transition_map()->is_dictionary_map() &&
transition_map()->GetBackPointer()->IsMap());
(transition_map()->is_dictionary_map() &&
!GetStoreTarget()->HasFastProperties()) ||
transition_map()->GetBackPointer()->IsMap();
}
void ApplyTransitionToDataProperty(Handle<JSObject> receiver);
void ReconfigureDataProperty(Handle<Object> value,