Index: src/ic/ic.cc |
diff --git a/src/ic/ic.cc b/src/ic/ic.cc |
index dd310a9c201c5357a8f6915dd3dc406eb55c240e..9900f872892c705e531375ff25fa1b96daec2f63 100644 |
--- a/src/ic/ic.cc |
+++ b/src/ic/ic.cc |
@@ -859,7 +859,7 @@ template <bool fill_array> |
int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map, |
Handle<JSObject> holder, Handle<FixedArray> array, |
Handle<Name> name) { |
- DCHECK(holder->HasFastProperties()); |
+ DCHECK(holder.is_null() || holder->HasFastProperties()); |
// The following kinds of receiver maps require custom handler compilation. |
if (receiver_map->IsJSGlobalObjectMap()) { |
@@ -872,11 +872,11 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map, |
HandleScope scope(isolate); |
int checks_count = 0; |
- // Switch to custom compiled handler if the prototype chain contains global |
- // or dictionary objects. |
+ // Create/count entries for each global or dictionary prototype appeared in |
+ // the prototype chain contains from receiver till holder. |
for (PrototypeIterator iter(receiver_map); !iter.IsAtEnd(); iter.Advance()) { |
Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter); |
- if (*current == *holder) break; |
+ if (holder.is_identical_to(current)) break; |
Handle<Map> current_map(current->map(), isolate); |
if (current_map->IsJSGlobalObjectMap()) { |
@@ -950,6 +950,41 @@ Handle<Object> LoadIC::SimpleLoadFromPrototype(Handle<Map> receiver_map, |
return handler_array; |
} |
+Handle<Object> LoadIC::SimpleLoadNonExistent(Handle<Map> receiver_map, |
+ Handle<Name> name) { |
+ Handle<JSObject> holder; // null handle |
+ int checks_count = GetPrototypeCheckCount(receiver_map, holder); |
+ DCHECK_LE(0, checks_count); |
+ DCHECK(!receiver_map->IsJSGlobalObjectMap()); |
+ |
+ Handle<Object> smi_handler = LoadHandler::LoadNonExistent( |
+ isolate(), receiver_map->is_dictionary_map()); |
+ |
+ 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()); |
+ } |
+ |
+ Factory* factory = isolate()->factory(); |
+ if (checks_count == 0) { |
+ return factory->NewTuple3(factory->null_value(), smi_handler, |
+ validity_cell); |
+ } |
+ Handle<FixedArray> handler_array(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, *factory->null_value()); |
+ InitPrototypeChecks<true>(isolate(), receiver_map, holder, handler_array, |
+ name); |
+ return handler_array; |
+} |
+ |
bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) { |
DCHECK(lookup->state() == LookupIterator::ACCESSOR); |
Isolate* isolate = lookup->isolate(); |
@@ -1004,7 +1039,10 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { |
lookup->state() == LookupIterator::ACCESS_CHECK) { |
code = slow_stub(); |
} else if (!lookup->IsFound()) { |
- if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC) { |
+ if (kind() == Code::LOAD_IC) { |
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH); |
+ code = SimpleLoadNonExistent(receiver_map(), lookup->name()); |
+ } else if (kind() == Code::LOAD_GLOBAL_IC) { |
code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(), |
receiver_map()); |
// TODO(jkummerow/verwaest): Introduce a builtin that handles this case. |