| Index: src/ic/ic.cc
|
| diff --git a/src/ic/ic.cc b/src/ic/ic.cc
|
| index 91430790265c4a00a89bed9366a50f373ed53fba..bcd98f156ce7e203d610ea6b2b6893c9b0d02096 100644
|
| --- a/src/ic/ic.cc
|
| +++ b/src/ic/ic.cc
|
| @@ -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());
|
|
|