[ic] Support data handlers that represent transitioning stores.

BUG=v8:5561

Review-Url: https://codereview.chromium.org/2488673004
Cr-Commit-Position: refs/heads/master@{#40946}
This commit is contained in:
ishell 2016-11-13 01:37:35 -08:00 committed by Commit bot
parent 5d3ce7ea4f
commit bcb3af59be
7 changed files with 347 additions and 59 deletions

View File

@ -5635,8 +5635,7 @@ void CodeStubAssembler::HandleLoadICHandlerCase(
Bind(&try_proto_handler);
{
GotoIf(WordEqual(LoadMap(handler), LoadRoot(Heap::kCodeMapRootIndex)),
&call_handler);
GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
HandleLoadICProtoHandler(p, handler, &var_holder, &var_smi_handler,
&if_smi_handler, miss);
}
@ -6086,11 +6085,26 @@ void CodeStubAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
}
}
void CodeStubAssembler::HandleStoreFieldAndReturn(
Node* handler_word, Node* holder, Representation representation,
Node* value, bool transition_to_field, Label* miss) {
void CodeStubAssembler::HandleStoreFieldAndReturn(Node* handler_word,
Node* holder,
Representation representation,
Node* value, Node* transition,
Label* miss) {
bool transition_to_field = transition != nullptr;
Node* prepared_value = PrepareValueForWrite(value, representation, miss);
if (transition_to_field) {
Label storage_extended(this);
GotoUnless(IsSetWord<StoreHandler::ExtendStorageBits>(handler_word),
&storage_extended);
Comment("[ Extend storage");
ExtendPropertiesBackingStore(holder);
Comment("] Extend storage");
Goto(&storage_extended);
Bind(&storage_extended);
}
Node* offset = DecodeWord<StoreHandler::FieldOffsetBits>(handler_word);
Label if_inobject(this), if_out_of_object(this);
Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject,
@ -6100,6 +6114,9 @@ void CodeStubAssembler::HandleStoreFieldAndReturn(
{
StoreNamedField(holder, offset, true, representation, prepared_value,
transition_to_field);
if (transition_to_field) {
StoreObjectField(holder, JSObject::kMapOffset, transition);
}
Return(value);
}
@ -6107,15 +6124,33 @@ void CodeStubAssembler::HandleStoreFieldAndReturn(
{
StoreNamedField(holder, offset, false, representation, prepared_value,
transition_to_field);
if (transition_to_field) {
StoreObjectField(holder, JSObject::kMapOffset, transition);
}
Return(value);
}
}
void CodeStubAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
Node* holder, Node* value,
bool transition_to_field,
Node* transition,
Label* miss) {
Comment(transition_to_field ? "transitioning field store" : "field store");
Comment(transition ? "transitioning field store" : "field store");
#ifdef DEBUG
Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
if (transition) {
CSA_ASSERT(
this,
WordOr(WordEqual(handler_kind,
IntPtrConstant(StoreHandler::kTransitionToField)),
WordEqual(handler_kind,
IntPtrConstant(StoreHandler::kTransitionToConstant))));
} else {
CSA_ASSERT(this, WordEqual(handler_kind,
IntPtrConstant(StoreHandler::kStoreField)));
}
#endif
Node* field_representation =
DecodeWord<StoreHandler::FieldRepresentationBits>(handler_word);
@ -6138,14 +6173,14 @@ void CodeStubAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
{
Comment("store tagged field");
HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(),
value, transition_to_field, miss);
value, transition, miss);
}
Bind(&if_double_field);
{
Comment("store double field");
HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(),
value, transition_to_field, miss);
value, transition, miss);
}
Bind(&if_heap_object_field);
@ -6156,7 +6191,8 @@ void CodeStubAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
PrepareValueForWrite(value, Representation::HeapObject(), miss);
Node* value_index_in_descriptor =
DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word);
Node* descriptors = LoadMapDescriptors(LoadMap(holder));
Node* descriptors =
LoadMapDescriptors(transition ? transition : LoadMap(holder));
Node* maybe_field_type = LoadFixedArrayElement(
descriptors, value_index_in_descriptor, 0, INTPTR_PARAMETERS);
Label do_store(this);
@ -6168,22 +6204,23 @@ void CodeStubAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
}
Bind(&do_store);
HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(),
prepared_value, transition_to_field, miss);
prepared_value, transition, miss);
}
Bind(&if_smi_field);
{
Comment("store smi field");
HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(),
value, transition_to_field, miss);
value, transition, miss);
}
}
void CodeStubAssembler::HandleStoreICHandlerCase(const StoreICParameters* p,
Node* handler, Label* miss) {
Label if_smi_handler(this), call_handler(this);
Label if_smi_handler(this);
Label try_proto_handler(this), call_handler(this);
Branch(TaggedIsSmi(handler), &if_smi_handler, &call_handler);
Branch(TaggedIsSmi(handler), &if_smi_handler, &try_proto_handler);
// |handler| is a Smi, encoding what to do. See SmiHandler methods
// for the encoding format.
@ -6192,8 +6229,14 @@ void CodeStubAssembler::HandleStoreICHandlerCase(const StoreICParameters* p,
Node* holder = p->receiver;
Node* handler_word = SmiUntag(handler);
// Handle non-transitioning stores.
HandleStoreICSmiHandlerCase(handler_word, holder, p->value, false, miss);
// Handle non-transitioning field stores.
HandleStoreICSmiHandlerCase(handler_word, holder, p->value, nullptr, miss);
}
Bind(&try_proto_handler);
{
GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
HandleStoreICProtoHandler(p, handler, miss);
}
// |handler| is a heap object. Must be code, call it.
@ -6205,6 +6248,99 @@ void CodeStubAssembler::HandleStoreICHandlerCase(const StoreICParameters* p,
}
}
void CodeStubAssembler::HandleStoreICProtoHandler(const StoreICParameters* p,
Node* handler, Label* miss) {
// IC dispatchers rely on these assumptions to be held.
STATIC_ASSERT(FixedArray::kLengthOffset ==
StoreHandler::kTransitionCellOffset);
DCHECK_EQ(FixedArray::OffsetOfElementAt(StoreHandler::kSmiHandlerIndex),
StoreHandler::kSmiHandlerOffset);
DCHECK_EQ(FixedArray::OffsetOfElementAt(StoreHandler::kValidityCellIndex),
StoreHandler::kValidityCellOffset);
// Both FixedArray and Tuple3 handlers have validity cell at the same offset.
Label validity_cell_check_done(this);
Node* validity_cell =
LoadObjectField(handler, StoreHandler::kValidityCellOffset);
GotoIf(WordEqual(validity_cell, IntPtrConstant(0)),
&validity_cell_check_done);
Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
GotoIf(WordNotEqual(cell_value,
SmiConstant(Smi::FromInt(Map::kPrototypeChainValid))),
miss);
Goto(&validity_cell_check_done);
Bind(&validity_cell_check_done);
Node* smi_handler = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset);
CSA_ASSERT(this, TaggedIsSmi(smi_handler));
Node* maybe_transition_cell =
LoadObjectField(handler, StoreHandler::kTransitionCellOffset);
Label array_handler(this), tuple_handler(this);
Branch(TaggedIsSmi(maybe_transition_cell), &array_handler, &tuple_handler);
Variable var_transition(this, MachineRepresentation::kTagged);
Label if_transition(this), if_transition_to_constant(this);
Bind(&tuple_handler);
{
Node* transition = LoadWeakCellValue(maybe_transition_cell, miss);
var_transition.Bind(transition);
Goto(&if_transition);
}
Bind(&array_handler);
{
Node* length = SmiUntag(maybe_transition_cell);
BuildFastLoop(MachineType::PointerRepresentation(),
IntPtrConstant(StoreHandler::kFirstPrototypeIndex), length,
[this, p, handler, miss](CodeStubAssembler*, Node* current) {
Node* prototype_cell = LoadFixedArrayElement(
handler, current, 0, INTPTR_PARAMETERS);
CheckPrototype(prototype_cell, p->name, miss);
},
1, IndexAdvanceMode::kPost);
Node* maybe_transition_cell = LoadFixedArrayElement(
handler, IntPtrConstant(StoreHandler::kTransitionCellIndex), 0,
INTPTR_PARAMETERS);
Node* transition = LoadWeakCellValue(maybe_transition_cell, miss);
var_transition.Bind(transition);
Goto(&if_transition);
}
Bind(&if_transition);
{
Node* holder = p->receiver;
Node* transition = var_transition.value();
Node* handler_word = SmiUntag(smi_handler);
GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(transition)), miss);
Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
GotoIf(WordEqual(handler_kind,
IntPtrConstant(StoreHandler::kTransitionToConstant)),
&if_transition_to_constant);
// Handle transitioning field stores.
HandleStoreICSmiHandlerCase(handler_word, holder, p->value, transition,
miss);
Bind(&if_transition_to_constant);
{
// Check that constant matches value.
Node* value_index_in_descriptor =
DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word);
Node* descriptors = LoadMapDescriptors(transition);
Node* constant = LoadFixedArrayElement(
descriptors, value_index_in_descriptor, 0, INTPTR_PARAMETERS);
GotoIf(WordNotEqual(p->value, constant), miss);
StoreObjectField(p->receiver, JSObject::kMapOffset, transition);
Return(p->value);
}
}
}
void CodeStubAssembler::StoreIC(const StoreICParameters* p) {
Variable var_handler(this, MachineRepresentation::kTagged);
// TODO(ishell): defer blocks when it works.

View File

@ -24,6 +24,7 @@ enum class IterationKind { kKeys, kValues, kEntries };
#define HEAP_CONSTANT_LIST(V) \
V(BooleanMap, BooleanMap) \
V(CodeMap, CodeMap) \
V(empty_string, EmptyString) \
V(EmptyFixedArray, EmptyFixedArray) \
V(FalseValue, False) \
@ -1152,16 +1153,23 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
void NameDictionaryNegativeLookup(compiler::Node* object,
compiler::Node* name, Label* miss);
// If |transition| is nullptr then the normal field store is generated or
// transitioning store otherwise.
void HandleStoreFieldAndReturn(compiler::Node* handler_word,
compiler::Node* holder,
Representation representation,
compiler::Node* value,
bool transition_to_field, Label* miss);
compiler::Node* transition, Label* miss);
// If |transition| is nullptr then the normal field store is generated or
// transitioning store otherwise.
void HandleStoreICSmiHandlerCase(compiler::Node* handler_word,
compiler::Node* holder,
compiler::Node* value,
bool transition_to_field, Label* miss);
compiler::Node* transition, Label* miss);
void HandleStoreICProtoHandler(const StoreICParameters* p,
compiler::Node* handler, Label* miss);
compiler::Node* TryToIntptr(compiler::Node* key, Label* miss);
void EmitFastElementsBoundsCheck(compiler::Node* object,

View File

@ -800,6 +800,7 @@ class RuntimeCallTimer {
V(StoreIC_StoreNormal) \
V(StoreIC_StoreScriptContextFieldStub) \
V(StoreIC_StoreTransition) \
V(StoreIC_StoreTransitionDH) \
V(StoreIC_StoreViaSetter)
class RuntimeCallStats {

View File

@ -79,9 +79,10 @@ Handle<Object> LoadHandler::LoadElement(Isolate* isolate,
return handle(Smi::FromInt(config), isolate);
}
Handle<Object> StoreHandler::StoreField(Isolate* isolate, int descriptor,
FieldIndex field_index,
Representation representation) {
Handle<Object> StoreHandler::StoreField(Isolate* isolate, Kind kind,
int descriptor, FieldIndex field_index,
Representation representation,
bool extend_storage) {
StoreHandler::FieldRepresentation field_rep;
switch (representation.kind()) {
case Representation::kSmi:
@ -102,7 +103,11 @@ Handle<Object> StoreHandler::StoreField(Isolate* isolate, int descriptor,
}
int value_index = DescriptorArray::ToValueIndex(descriptor);
int config = StoreHandler::KindBits::encode(StoreHandler::kForFields) |
DCHECK(kind == kStoreField || kind == kTransitionToField);
DCHECK_IMPLIES(kind == kStoreField, !extend_storage);
int config = StoreHandler::KindBits::encode(kind) |
StoreHandler::ExtendStorageBits::encode(extend_storage) |
StoreHandler::IsInobjectBits::encode(field_index.is_inobject()) |
StoreHandler::FieldRepresentationBits::encode(field_rep) |
StoreHandler::DescriptorValueIndexBits::encode(value_index) |
@ -110,6 +115,30 @@ Handle<Object> StoreHandler::StoreField(Isolate* isolate, int descriptor,
return handle(Smi::FromInt(config), isolate);
}
Handle<Object> StoreHandler::StoreField(Isolate* isolate, int descriptor,
FieldIndex field_index,
Representation representation) {
return StoreField(isolate, kStoreField, descriptor, field_index,
representation, false);
}
Handle<Object> StoreHandler::TransitionToField(Isolate* isolate, int descriptor,
FieldIndex field_index,
Representation representation,
bool extend_storage) {
return StoreField(isolate, kTransitionToField, descriptor, field_index,
representation, extend_storage);
}
Handle<Object> StoreHandler::TransitionToConstant(Isolate* isolate,
int descriptor) {
int value_index = DescriptorArray::ToValueIndex(descriptor);
int config =
StoreHandler::KindBits::encode(StoreHandler::kTransitionToConstant) |
StoreHandler::DescriptorValueIndexBits::encode(value_index);
return handle(Smi::FromInt(config), isolate);
}
} // namespace internal
} // namespace v8

View File

@ -37,6 +37,7 @@ class LoadHandler {
class IsAccessorInfoBits
: public BitField<bool, DoNegativeLookupOnReceiverBits::kNext, 1> {};
// Index of a value entry in the descriptor array.
// +2 here is because each descriptor entry occupies 3 slots in array.
class DescriptorValueIndexBits
: public BitField<unsigned, IsAccessorInfoBits::kNext,
@ -117,32 +118,83 @@ class LoadHandler {
// A set of bit fields representing Smi handlers for stores.
class StoreHandler {
public:
enum Kind { kForElements, kForFields };
class KindBits : public BitField<Kind, 0, 1> {};
enum Kind {
kStoreElement,
kStoreField,
kTransitionToField,
kTransitionToConstant
};
class KindBits : public BitField<Kind, 0, 2> {};
enum FieldRepresentation { kSmi, kDouble, kHeapObject, kTagged };
//
// Encoding when KindBits contains kForFields.
//
class IsInobjectBits : public BitField<bool, KindBits::kNext, 1> {};
class FieldRepresentationBits
: public BitField<FieldRepresentation, IsInobjectBits::kNext, 2> {};
// Applicable to kStoreField, kTransitionToField and kTransitionToConstant
// kinds.
// Index of a value entry in the descriptor array.
// +2 here is because each descriptor entry occupies 3 slots in array.
class DescriptorValueIndexBits
: public BitField<unsigned, FieldRepresentationBits::kNext,
: public BitField<unsigned, KindBits::kNext,
kDescriptorIndexBitCount + 2> {};
//
// Encoding when KindBits contains kTransitionToConstant.
//
// Make sure we don't overflow the smi.
STATIC_ASSERT(DescriptorValueIndexBits::kNext <= kSmiValueSize);
//
// Encoding when KindBits contains kStoreField or kTransitionToField.
//
class ExtendStorageBits
: public BitField<bool, DescriptorValueIndexBits::kNext, 1> {};
class IsInobjectBits : public BitField<bool, ExtendStorageBits::kNext, 1> {};
class FieldRepresentationBits
: public BitField<FieldRepresentation, IsInobjectBits::kNext, 2> {};
// +1 here is to cover all possible JSObject header sizes.
class FieldOffsetBits
: public BitField<unsigned, DescriptorValueIndexBits::kNext,
: public BitField<unsigned, FieldRepresentationBits::kNext,
kDescriptorIndexBitCount + 1 + kPointerSizeLog2> {};
// Make sure we don't overflow the smi.
STATIC_ASSERT(FieldOffsetBits::kNext <= kSmiValueSize);
// The layout of an Tuple3 handler representing a transitioning store
// when prototype chain checks do not include non-existing lookups or access
// checks.
static const int kTransitionCellOffset = Tuple3::kValue1Offset;
static const int kSmiHandlerOffset = Tuple3::kValue2Offset;
static const int kValidityCellOffset = Tuple3::kValue3Offset;
// The layout of an array handler representing a transitioning store
// when prototype chain checks include non-existing lookups and access checks.
static const int kSmiHandlerIndex = 0;
static const int kValidityCellIndex = 1;
static const int kTransitionCellIndex = 2;
static const int kFirstPrototypeIndex = 3;
// Creates a Smi-handler for storing a field to fast object.
static inline Handle<Object> StoreField(Isolate* isolate, int descriptor,
FieldIndex field_index,
Representation representation);
// Creates a Smi-handler for transitioning store to a field.
static inline Handle<Object> TransitionToField(Isolate* isolate,
int descriptor,
FieldIndex field_index,
Representation representation,
bool extend_storage);
// Creates a Smi-handler for transitioning store to a constant field (in this
// case the only thing that needs to be done is an update of a map).
static inline Handle<Object> TransitionToConstant(Isolate* isolate,
int descriptor);
private:
static inline Handle<Object> StoreField(Isolate* isolate, Kind kind,
int descriptor,
FieldIndex field_index,
Representation representation,
bool extend_storage);
};
} // namespace internal

View File

@ -852,10 +852,10 @@ Handle<Object> LoadIC::SimpleFieldLoad(FieldIndex index) {
namespace {
template <bool fill_array>
template <bool fill_array = true>
int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
Handle<JSObject> holder, Handle<FixedArray> array,
Handle<Name> name) {
Handle<Name> name, int first_index) {
DCHECK(holder.is_null() || holder->HasFastProperties());
// The following kinds of receiver maps require custom handler compilation.
@ -898,8 +898,7 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
global, name, PropertyCellType::kInvalidated);
DCHECK(cell->value()->IsTheHole(isolate));
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
array->set(LoadHandler::kFirstPrototypeIndex + checks_count,
*weak_cell);
array->set(first_index + checks_count, *weak_cell);
}
checks_count++;
@ -910,8 +909,7 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
current->property_dictionary()->FindEntry(name));
Handle<WeakCell> weak_cell =
Map::GetOrCreatePrototypeWeakCell(current, isolate);
array->set(LoadHandler::kFirstPrototypeIndex + checks_count,
*weak_cell);
array->set(first_index + checks_count, *weak_cell);
}
checks_count++;
}
@ -919,19 +917,25 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
return checks_count;
}
} // namespace
int LoadIC::GetPrototypeCheckCount(Handle<Map> receiver_map,
Handle<JSObject> holder) {
return InitPrototypeChecks<false>(isolate(), receiver_map, holder,
Handle<FixedArray>(), Handle<Name>());
// Returns 0 if the validity cell check is enough to ensure that the
// prototype chain from |receiver_map| till |holder| did not change.
// If the |holder| is an empty handle then the full prototype chain is
// checked.
// Returns -1 if the handler has to be compiled or the number of prototype
// checks otherwise.
int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map,
Handle<JSObject> holder) {
return InitPrototypeChecks<false>(isolate, receiver_map, holder,
Handle<FixedArray>(), Handle<Name>(), 0);
}
} // namespace
Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
Handle<JSObject> holder,
Handle<Name> name,
Handle<Object> smi_handler) {
int checks_count = GetPrototypeCheckCount(receiver_map, holder);
int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder);
DCHECK_LE(0, checks_count);
DCHECK(!receiver_map->IsJSGlobalObjectMap());
@ -961,15 +965,15 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler);
handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell);
handler_array->set(LoadHandler::kHolderCellIndex, *holder_cell);
InitPrototypeChecks<true>(isolate(), receiver_map, holder, handler_array,
name);
InitPrototypeChecks(isolate(), receiver_map, holder, handler_array, name,
LoadHandler::kFirstPrototypeIndex);
return handler_array;
}
Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map,
Handle<Name> name) {
Handle<JSObject> holder; // null handle
int checks_count = GetPrototypeCheckCount(receiver_map, holder);
int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder);
DCHECK_LE(0, checks_count);
DCHECK(!receiver_map->IsJSGlobalObjectMap());
@ -1003,8 +1007,8 @@ Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map,
handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler);
handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell);
handler_array->set(LoadHandler::kHolderCellIndex, *factory->null_value());
InitPrototypeChecks<true>(isolate(), receiver_map, holder, handler_array,
name);
InitPrototypeChecks(isolate(), receiver_map, holder, handler_array, name,
LoadHandler::kFirstPrototypeIndex);
return handler_array;
}
@ -1861,6 +1865,62 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
TRACE_IC("StoreIC", lookup->name());
}
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;
if (details.type() == DATA_CONSTANT) {
smi_handler = StoreHandler::TransitionToConstant(isolate(), descriptor);
} else {
DCHECK_EQ(DATA, details.type());
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);
}
int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder);
DCHECK_LE(0, checks_count);
DCHECK(!receiver_map->IsJSGlobalObjectMap());
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
if (validity_cell.is_null()) {
// This must be a case when receiver's prototype is null.
DCHECK_EQ(*isolate()->factory()->null_value(),
receiver_map->GetPrototypeChainRootMap(isolate())->prototype());
DCHECK_EQ(0, checks_count);
validity_cell = handle(Smi::FromInt(0), isolate());
}
Handle<WeakCell> transition_cell = Map::WeakCellForMap(transition);
Factory* factory = isolate()->factory();
if (checks_count == 0) {
return factory->NewTuple3(transition_cell, smi_handler, validity_cell);
}
Handle<FixedArray> handler_array(factory->NewFixedArray(
StoreHandler::kFirstPrototypeIndex + checks_count, TENURED));
handler_array->set(StoreHandler::kSmiHandlerIndex, *smi_handler);
handler_array->set(StoreHandler::kValidityCellIndex, *validity_cell);
handler_array->set(StoreHandler::kTransitionCellIndex, *transition_cell);
InitPrototypeChecks(isolate(), receiver_map, holder, handler_array, name,
StoreHandler::kFirstPrototypeIndex);
return handler_array;
}
static Handle<Code> PropertyCellStoreHandler(
Isolate* isolate, Handle<JSObject> receiver, Handle<JSGlobalObject> holder,
@ -1897,8 +1957,13 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return slow_stub();
}
DCHECK(lookup->IsCacheableTransition());
if (FLAG_tf_store_ic_stub) {
Handle<Map> transition = lookup->transition_map();
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransitionDH);
return StoreTransition(receiver_map(), holder, transition,
lookup->name());
}
break; // Custom-compiled handler.
}
@ -2038,6 +2103,7 @@ Handle<Object> StoreIC::CompileHandler(LookupIterator* lookup,
cell->set_value(isolate()->heap()->the_hole_value());
return code;
}
DCHECK(!FLAG_tf_store_ic_stub);
Handle<Map> transition = lookup->transition_map();
// Currently not handled by CompileStoreTransition.
DCHECK(holder->HasFastProperties());

View File

@ -314,14 +314,6 @@ class LoadIC : public IC {
// Creates a data handler that represents a load of a field by given index.
Handle<Object> SimpleFieldLoad(FieldIndex index);
// Returns 0 if the validity cell check is enough to ensure that the
// prototype chain from |receiver_map| till |holder| did not change.
// If the |holder| is an empty handle then the full prototype chain is
// checked.
// Returns -1 if the handler has to be compiled or the number of prototype
// checks otherwise.
int GetPrototypeCheckCount(Handle<Map> receiver_map, Handle<JSObject> holder);
// Creates a data handler that represents a prototype chain check followed
// by given Smi-handler that encoded a load from the holder.
// Can be used only if GetPrototypeCheckCount() returns non negative value.
@ -425,6 +417,10 @@ class StoreIC : public IC {
CacheHolderFlag cache_holder) override;
private:
Handle<Object> StoreTransition(Handle<Map> receiver_map,
Handle<JSObject> holder,
Handle<Map> transition, Handle<Name> name);
friend class IC;
};