Chromium Code Reviews| Index: src/ic/ic.cc |
| diff --git a/src/ic/ic.cc b/src/ic/ic.cc |
| index 02fd01aff77f3df14674d8bc45699f5b8970dd5a..887fd8bb641b32588bbc1f4cc05a83362b883518 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. |
| @@ -883,8 +883,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++; |
| @@ -895,8 +894,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++; |
| } |
| @@ -904,19 +902,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); |
| if (receiver_map->IsJSGlobalObjectMap()) { |
| @@ -942,15 +946,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()); |
| @@ -977,8 +981,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; |
| } |
| @@ -1819,6 +1823,65 @@ 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()); |
| + |
| + // Stub is never generated for objects that require access checks. |
|
Jakob Kummerow
2016/11/10 14:13:07
No stubs are generated at all ;-) Suggestion:
"Dec
Igor Sheludko
2016/11/10 15:31:55
Done.
|
| + 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()); |
| + |
| + // Stub is never generated for objects that require access checks. |
|
Jakob Kummerow
2016/11/10 14:13:07
You've already checked this above.
Igor Sheludko
2016/11/10 15:31:55
Done.
|
| + DCHECK(!transition->is_access_check_needed()); |
| + |
| + 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( |
| + LoadHandler::kFirstPrototypeIndex + checks_count, TENURED)); |
|
Jakob Kummerow
2016/11/10 14:13:07
s/LoadHandler/StoreHandler/ here and in the next t
Igor Sheludko
2016/11/10 15:31:55
Done.
|
| + handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler); |
| + handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell); |
| + handler_array->set(LoadHandler::kHolderCellIndex, *transition_cell); |
|
Jakob Kummerow
2016/11/10 14:13:07
s/kHolderCellIndex/kTransitionCellIndex/
Igor Sheludko
2016/11/10 15:31:55
Done.
|
| + 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, |
| @@ -1855,8 +1918,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. |
| } |
| @@ -1996,6 +2064,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()); |