Index: src/ic/ic.cc |
diff --git a/src/ic/ic.cc b/src/ic/ic.cc |
index 65aa2fc9178f67559b8e4cf39b9fe98815122e64..52735ddb63130dc54abdb0d026e2d22195a7490d 100644 |
--- a/src/ic/ic.cc |
+++ b/src/ic/ic.cc |
@@ -277,7 +277,7 @@ bool IC::ShouldRecomputeHandler(Handle<Object> receiver, Handle<String> name) { |
// This is a contextual access, always just update the handler and stay |
// monomorphic. |
- if (receiver->IsJSGlobalObject()) return true; |
+ if (kind() == Code::LOAD_GLOBAL_IC) return true; |
// The current map wasn't handled yet. There's no reason to stay monomorphic, |
// *unless* we're moving from a deprecated map to its replacement, or |
@@ -464,6 +464,12 @@ void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) { |
OnTypeFeedbackChanged(isolate, host); |
} |
+void LoadGlobalIC::Clear(Isolate* isolate, Code* host, |
+ LoadGlobalICNexus* nexus) { |
+ if (IsCleared(nexus)) return; |
+ nexus->ConfigureUninitialized(); |
+ OnTypeFeedbackChanged(isolate, host); |
+} |
void StoreIC::Clear(Isolate* isolate, Code* host, StoreICNexus* nexus) { |
if (IsCleared(nexus)) return; |
@@ -541,6 +547,9 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map, |
if (kind() == Code::LOAD_IC) { |
LoadICNexus* nexus = casted_nexus<LoadICNexus>(); |
nexus->ConfigureMonomorphic(map, handler); |
+ } else if (kind() == Code::LOAD_GLOBAL_IC) { |
+ LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>(); |
+ nexus->ConfigureMonomorphic(map, handler); |
} else if (kind() == Code::KEYED_LOAD_IC) { |
KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>(); |
nexus->ConfigureMonomorphic(name, map, handler); |
@@ -621,34 +630,6 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { |
bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic; |
- if (object->IsJSGlobalObject() && name->IsString()) { |
- // Look up in script context table. |
- Handle<String> str_name = Handle<String>::cast(name); |
- Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object); |
- Handle<ScriptContextTable> script_contexts( |
- global->native_context()->script_context_table()); |
- |
- ScriptContextTable::LookupResult lookup_result; |
- if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) { |
- Handle<Object> result = |
- FixedArray::get(*ScriptContextTable::GetContext( |
- script_contexts, lookup_result.context_index), |
- lookup_result.slot_index, isolate()); |
- if (result->IsTheHole(isolate())) { |
- // Do not install stubs and stay pre-monomorphic for |
- // uninitialized accesses. |
- return ReferenceError(name); |
- } |
- |
- if (use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) { |
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadScriptContextFieldStub); |
- LoadScriptContextFieldStub stub(isolate(), &lookup_result); |
- PatchCache(name, stub.GetCode()); |
- } |
- return result; |
- } |
- } |
- |
if (state() != UNINITIALIZED) { |
JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate()); |
update_receiver_map(object); |
@@ -657,7 +638,7 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { |
LookupIterator it(object, name); |
LookupForRead(&it); |
- if (it.IsFound() || !ShouldThrowReferenceError(object)) { |
+ if (it.IsFound() || !ShouldThrowReferenceError()) { |
// Update inline cache and stub cache. |
if (use_ic) UpdateCaches(&it); |
@@ -668,7 +649,7 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { |
Object); |
if (it.IsFound()) { |
return result; |
- } else if (!ShouldThrowReferenceError(object)) { |
+ } else if (!ShouldThrowReferenceError()) { |
LOG(isolate(), SuspectReadEvent(*name, *object)); |
return result; |
} |
@@ -676,6 +657,38 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { |
return ReferenceError(name); |
} |
+MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) { |
+ Handle<JSGlobalObject> global = isolate()->global_object(); |
+ |
+ if (name->IsString()) { |
+ // Look up in script context table. |
+ Handle<String> str_name = Handle<String>::cast(name); |
+ Handle<ScriptContextTable> script_contexts( |
+ global->native_context()->script_context_table()); |
+ |
+ ScriptContextTable::LookupResult lookup_result; |
+ if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) { |
+ Handle<Object> result = |
+ FixedArray::get(*ScriptContextTable::GetContext( |
+ script_contexts, lookup_result.context_index), |
+ lookup_result.slot_index, isolate()); |
+ if (result->IsTheHole(isolate())) { |
+ // Do not install stubs and stay pre-monomorphic for |
+ // uninitialized accesses. |
+ return ReferenceError(name); |
+ } |
+ |
+ if (FLAG_use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) { |
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadScriptContextFieldStub); |
+ LoadScriptContextFieldStub stub(isolate(), &lookup_result); |
+ PatchCache(name, stub.GetCode()); |
+ TRACE_IC("LoadGlobalIC", name); |
+ } |
+ return result; |
+ } |
+ } |
+ return LoadIC::Load(global, name); |
+} |
static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, |
Handle<Map> new_receiver_map) { |
@@ -793,6 +806,11 @@ void IC::PatchCache(Handle<Name> name, Handle<Code> code) { |
break; |
case RECOMPUTE_HANDLER: |
case MONOMORPHIC: |
+ if (kind() == Code::LOAD_GLOBAL_IC) { |
+ UpdateMonomorphicIC(code, name); |
+ break; |
+ } |
+ // Fall through. |
case POLYMORPHIC: |
if (!is_keyed() || state() == RECOMPUTE_HANDLER) { |
if (UpdatePolymorphicIC(name, code)) break; |
@@ -823,6 +841,11 @@ Handle<Code> LoadIC::initialize_stub_in_optimized_code( |
return LoadICStub(isolate, LoadICState(extra_state)).GetCode(); |
} |
+Handle<Code> LoadGlobalIC::initialize_stub_in_optimized_code( |
+ Isolate* isolate, ExtraICState extra_state) { |
+ return LoadGlobalICStub(isolate, LoadICState(extra_state)).GetCode(); |
+} |
+ |
Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code( |
Isolate* isolate, ExtraICState extra_state) { |
return KeyedLoadICStub(isolate, LoadICState(extra_state)).GetCode(); |
@@ -904,7 +927,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { |
lookup->state() == LookupIterator::ACCESS_CHECK) { |
code = slow_stub(); |
} else if (!lookup->IsFound()) { |
- if (kind() == Code::LOAD_IC) { |
+ if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC) { |
code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(), |
receiver_map()); |
// TODO(jkummerow/verwaest): Introduce a builtin that handles this case. |
@@ -954,7 +977,8 @@ Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) { |
lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>()); |
CacheHolderFlag flag; |
Handle<Map> stub_holder_map; |
- if (kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC) { |
+ if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC || |
+ kind() == Code::KEYED_LOAD_IC) { |
stub_holder_map = IC::GetHandlerCacheHolder( |
receiver_map(), receiver_is_holder, isolate(), &flag); |
} else { |
@@ -1089,7 +1113,7 @@ Handle<Code> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { |
case LookupIterator::DATA: { |
if (lookup->is_dictionary_holder()) { |
- if (kind() != Code::LOAD_IC) { |
+ if (kind() != Code::LOAD_IC && kind() != Code::LOAD_GLOBAL_IC) { |
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); |
return slow_stub(); |
} |
@@ -1226,7 +1250,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup, |
case LookupIterator::DATA: { |
if (lookup->is_dictionary_holder()) { |
- DCHECK(kind() == Code::LOAD_IC); |
+ DCHECK(kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC); |
DCHECK(holder->IsJSGlobalObject()); |
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobal); |
NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder); |
@@ -2268,14 +2292,22 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) { |
// A monomorphic or polymorphic KeyedLoadIC with a string key can call the |
// LoadIC miss handler if the handler misses. Since the vector Nexus is |
// set up outside the IC, handle that here. |
- if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::LOAD_IC) { |
+ FeedbackVectorSlotKind kind = vector->GetKind(vector_slot); |
+ if (kind == FeedbackVectorSlotKind::LOAD_IC) { |
LoadICNexus nexus(vector, vector_slot); |
LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); |
ic.UpdateState(receiver, key); |
RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key)); |
+ |
+ } else if (kind == FeedbackVectorSlotKind::LOAD_GLOBAL_IC) { |
+ DCHECK_EQ(*isolate->global_object(), *receiver); |
+ LoadGlobalICNexus nexus(vector, vector_slot); |
+ LoadGlobalIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); |
+ ic.UpdateState(receiver, key); |
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key)); |
+ |
} else { |
- DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, |
- vector->GetKind(vector_slot)); |
+ DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, kind); |
KeyedLoadICNexus nexus(vector, vector_slot); |
KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); |
ic.UpdateState(receiver, key); |
@@ -2283,6 +2315,27 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) { |
} |
} |
+// Used from ic-<arch>.cc. |
+RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) { |
+ TimerEventScope<TimerEventIcMiss> timer(isolate); |
+ HandleScope scope(isolate); |
+ DCHECK_EQ(3, args.length()); |
+ Handle<JSGlobalObject> global = isolate->global_object(); |
+ Handle<Name> name = args.at<Name>(0); |
+ Handle<Smi> slot = args.at<Smi>(1); |
+ Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2); |
+ FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); |
+ DCHECK_EQ(FeedbackVectorSlotKind::LOAD_GLOBAL_IC, |
+ vector->GetKind(vector_slot)); |
+ |
+ LoadGlobalICNexus nexus(vector, vector_slot); |
+ LoadGlobalIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); |
+ ic.UpdateState(global, name); |
+ |
+ Handle<Object> result; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(name)); |
+ return *result; |
+} |
// Used from ic-<arch>.cc |
RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) { |
@@ -2850,7 +2903,9 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) { |
LoadICNexus nexus(isolate); |
LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); |
- if (!ic.ShouldThrowReferenceError(it.GetReceiver())) { |
+ // It could actually be any kind of LoadICs here but the predicate handles |
+ // all the cases properly. |
+ if (!ic.ShouldThrowReferenceError()) { |
return isolate->heap()->undefined_value(); |
} |