| 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();
|
| }
|
|
|
|
|