Index: src/ic/ic.cc |
diff --git a/src/ic/ic.cc b/src/ic/ic.cc |
index b75e73b5fa1f70dd9e8cd4139834448eb26cf627..82d14f147cc4e1866ce986c1a45cd09d5b139372 100644 |
--- a/src/ic/ic.cc |
+++ b/src/ic/ic.cc |
@@ -846,36 +846,77 @@ Handle<Object> LoadIC::SimpleFieldLoad(FieldIndex index) { |
return stub.GetCode(); |
} |
-bool LoadIC::IsPrototypeValidityCellCheckEnough(Handle<Map> receiver_map, |
- Handle<JSObject> holder) { |
+namespace { |
+ |
+template <bool fill_array> |
+int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map, |
+ Handle<JSObject> holder, Handle<FixedArray> array, |
+ Handle<Name> name) { |
DCHECK(holder->HasFastProperties()); |
// The following kinds of receiver maps require custom handler compilation. |
if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap() || |
receiver_map->IsJSGlobalObjectMap()) { |
- return false; |
+ return -1; |
} |
+ HandleScope scope(isolate); |
+ int checks_count = 0; |
+ |
// Switch to custom compiled handler if the prototype chain contains global |
// or dictionary objects. |
- for (PrototypeIterator iter(*receiver_map); !iter.IsAtEnd(); iter.Advance()) { |
- JSObject* current = iter.GetCurrent<JSObject>(); |
- if (current == *holder) break; |
- Map* current_map = current->map(); |
+ for (PrototypeIterator iter(receiver_map); !iter.IsAtEnd(); iter.Advance()) { |
+ Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter); |
+ if (*current == *holder) break; |
+ Handle<Map> current_map(current->map(), isolate); |
+ |
+ // Only global objects and objects that do not require access |
+ // checks are allowed in stubs. |
+ DCHECK(current_map->IsJSGlobalProxyMap() || |
+ !current_map->is_access_check_needed()); |
+ |
if (current_map->IsJSGlobalObjectMap()) { |
- return false; |
+ if (fill_array) { |
+ Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(current); |
+ Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell( |
+ 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); |
+ } |
+ checks_count++; |
+ |
} else if (current_map->is_dictionary_map()) { |
DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. |
- return false; |
+ if (fill_array) { |
+ DCHECK_EQ(NameDictionary::kNotFound, |
+ current->property_dictionary()->FindEntry(name)); |
+ Handle<WeakCell> weak_cell = |
+ Map::GetOrCreatePrototypeWeakCell(current, isolate); |
+ array->set(LoadHandler::kFirstPrototypeIndex + checks_count, |
+ *weak_cell); |
+ } |
+ checks_count++; |
} |
} |
- return true; |
+ 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>()); |
} |
Handle<Object> LoadIC::SimpleLoadFromPrototype(Handle<Map> receiver_map, |
Handle<JSObject> holder, |
+ Handle<Name> name, |
Handle<Object> smi_handler) { |
- DCHECK(IsPrototypeValidityCellCheckEnough(receiver_map, holder)); |
+ int checks_count = GetPrototypeCheckCount(receiver_map, holder); |
+ DCHECK_LE(0, checks_count); |
if (receiver_map->IsJSGlobalProxyMap() || |
receiver_map->IsJSGlobalObjectMap()) { |
@@ -891,8 +932,19 @@ Handle<Object> LoadIC::SimpleLoadFromPrototype(Handle<Map> receiver_map, |
Handle<WeakCell> holder_cell = |
Map::GetOrCreatePrototypeWeakCell(holder, isolate()); |
- return isolate()->factory()->NewTuple3(validity_cell, holder_cell, |
- smi_handler); |
+ |
+ if (checks_count == 0) { |
+ return isolate()->factory()->NewTuple3(holder_cell, smi_handler, |
+ validity_cell); |
+ } |
+ Handle<FixedArray> handler_array(isolate()->factory()->NewFixedArray( |
+ LoadHandler::kFirstPrototypeIndex + checks_count, TENURED)); |
+ 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); |
+ return handler_array; |
} |
bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) { |
@@ -1230,10 +1282,10 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { |
if (receiver_is_holder) { |
return smi_handler; |
} |
- if (FLAG_tf_load_ic_stub && |
- IsPrototypeValidityCellCheckEnough(map, holder)) { |
+ if (FLAG_tf_load_ic_stub && GetPrototypeCheckCount(map, holder) >= 0) { |
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH); |
- return SimpleLoadFromPrototype(map, holder, smi_handler); |
+ return SimpleLoadFromPrototype(map, holder, lookup->name(), |
+ smi_handler); |
} |
break; // Custom-compiled handler. |
} |
@@ -1247,9 +1299,10 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { |
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH); |
return smi_handler; |
} |
- if (IsPrototypeValidityCellCheckEnough(map, holder)) { |
+ if (GetPrototypeCheckCount(map, holder) >= 0) { |
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH); |
- return SimpleLoadFromPrototype(map, holder, smi_handler); |
+ return SimpleLoadFromPrototype(map, holder, lookup->name(), |
+ smi_handler); |
} |
} else { |
if (receiver_is_holder) { |