diff options
Diffstat (limited to 'deps/v8/src/ic/ic.cc')
-rw-r--r-- | deps/v8/src/ic/ic.cc | 523 |
1 files changed, 242 insertions, 281 deletions
diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc index 7e0cefdca9..fa04e0fca0 100644 --- a/deps/v8/src/ic/ic.cc +++ b/deps/v8/src/ic/ic.cc @@ -21,6 +21,7 @@ #include "src/ic/handler-configuration-inl.h" #include "src/ic/ic-compiler.h" #include "src/ic/ic-inl.h" +#include "src/ic/ic-stats.h" #include "src/ic/stub-cache.h" #include "src/isolate-inl.h" #include "src/macro-assembler.h" @@ -29,6 +30,7 @@ #include "src/runtime/runtime-utils.h" #include "src/runtime/runtime.h" #include "src/tracing/trace-event.h" +#include "src/tracing/tracing-category-observer.h" namespace v8 { namespace internal { @@ -90,7 +92,7 @@ const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) { void IC::TraceIC(const char* type, Handle<Object> name) { - if (FLAG_trace_ic) { + if (FLAG_ic_stats) { if (AddressIsDeoptimizedCode()) return; DCHECK(UseVector()); State new_state = nexus()->StateFromFeedback(); @@ -101,8 +103,17 @@ void IC::TraceIC(const char* type, Handle<Object> name) { void IC::TraceIC(const char* type, Handle<Object> name, State old_state, State new_state) { - if (!FLAG_trace_ic) return; - PrintF("[%s%s in ", is_keyed() ? "Keyed" : "", type); + if (V8_LIKELY(!FLAG_ic_stats)) return; + + if (FLAG_ic_stats & + v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) { + ICStats::instance()->Begin(); + ICInfo& ic_info = ICStats::instance()->Current(); + ic_info.type = is_keyed() ? "Keyed" : ""; + ic_info.type += type; + } else { + PrintF("[%s%s in ", is_keyed() ? "Keyed" : "", type); + } // TODO(jkummerow): Add support for "apply". The logic is roughly: // marker = [fp_ + kMarkerOffset]; @@ -121,8 +132,14 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state, code_offset = static_cast<int>(pc() - function->code()->instruction_start()); } - JavaScriptFrame::PrintFunctionAndOffset(function, function->abstract_code(), - code_offset, stdout, true); + if (FLAG_ic_stats & + v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) { + JavaScriptFrame::CollectFunctionAndOffsetForICStats( + function, function->abstract_code(), code_offset); + } else { + JavaScriptFrame::PrintFunctionAndOffset( + function, function->abstract_code(), code_offset, stdout, true); + } } const char* modifier = ""; @@ -135,17 +152,45 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state, if (!receiver_map().is_null()) { map = *receiver_map(); } - PrintF(" (%c->%c%s) map=(%p", TransitionMarkFromState(old_state), - TransitionMarkFromState(new_state), modifier, - reinterpret_cast<void*>(map)); + if (FLAG_ic_stats & + v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) { + ICInfo& ic_info = ICStats::instance()->Current(); + // Reverse enough space for IC transition state, the longest length is 17. + ic_info.state.reserve(17); + ic_info.state = "("; + ic_info.state += TransitionMarkFromState(old_state); + ic_info.state += "->"; + ic_info.state += TransitionMarkFromState(new_state); + ic_info.state += modifier; + ic_info.state += ")"; + ic_info.map = reinterpret_cast<void*>(map); + } else { + PrintF(" (%c->%c%s) map=(%p", TransitionMarkFromState(old_state), + TransitionMarkFromState(new_state), modifier, + reinterpret_cast<void*>(map)); + } if (map != nullptr) { - PrintF(" dict=%u own=%u type=", map->is_dictionary_map(), - map->NumberOfOwnDescriptors()); - std::cout << map->instance_type(); + if (FLAG_ic_stats & + v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) { + ICInfo& ic_info = ICStats::instance()->Current(); + ic_info.is_dictionary_map = map->is_dictionary_map(); + ic_info.number_of_own_descriptors = map->NumberOfOwnDescriptors(); + ic_info.instance_type = std::to_string(map->instance_type()); + } else { + PrintF(" dict=%u own=%u type=", map->is_dictionary_map(), + map->NumberOfOwnDescriptors()); + std::cout << map->instance_type(); + } + } + if (FLAG_ic_stats & + v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) { + // TODO(lpy) Add name as key field in ICStats. + ICStats::instance()->End(); + } else { + PrintF(") "); + name->ShortPrint(stdout); + PrintF("]\n"); } - PrintF(") "); - name->ShortPrint(stdout); - PrintF("]\n"); } @@ -342,7 +387,7 @@ void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { update_receiver_map(receiver); if (!name->IsString()) return; if (state() != MONOMORPHIC && state() != POLYMORPHIC) return; - if (receiver->IsUndefined(isolate()) || receiver->IsNull(isolate())) return; + if (receiver->IsNullOrUndefined(isolate())) return; // Remove the target from the code cache if it became invalid // because of changes in the prototype chain to avoid hitting it @@ -564,7 +609,7 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map, nexus->ConfigureMonomorphic(map, handler); } else if (kind() == Code::LOAD_GLOBAL_IC) { LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>(); - nexus->ConfigureHandlerMode(Handle<Code>::cast(handler)); + nexus->ConfigureHandlerMode(handler); } else if (kind() == Code::KEYED_LOAD_IC) { KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>(); nexus->ConfigureMonomorphic(name, map, handler); @@ -603,10 +648,9 @@ void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps, OnTypeFeedbackChanged(isolate(), get_host()); } - void IC::ConfigureVectorState(MapHandleList* maps, MapHandleList* transitioned_maps, - CodeHandleList* handlers) { + List<Handle<Object>>* handlers) { DCHECK(UseVector()); DCHECK(kind() == Code::KEYED_STORE_IC); KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>(); @@ -620,7 +664,14 @@ void IC::ConfigureVectorState(MapHandleList* maps, MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { // If the object is undefined or null it's illegal to try to get any // of its properties; throw a TypeError in that case. - if (object->IsUndefined(isolate()) || object->IsNull(isolate())) { + if (object->IsNullOrUndefined(isolate())) { + if (FLAG_use_ic && state() != UNINITIALIZED && state() != PREMONOMORPHIC) { + // Ensure the IC state progresses. + TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver); + update_receiver_map(object); + PatchCache(name, slow_stub()); + TRACE_IC("LoadIC", name); + } return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name); } @@ -794,6 +845,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) { DCHECK(IsHandler(*handler)); // Currently only LoadIC and KeyedLoadIC support non-code handlers. DCHECK_IMPLIES(!handler->IsCode(), kind() == Code::LOAD_IC || + kind() == Code::LOAD_GLOBAL_IC || kind() == Code::KEYED_LOAD_IC || kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC); @@ -831,23 +883,9 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) { } } -Handle<Code> KeyedStoreIC::ChooseMegamorphicStub(Isolate* isolate, - ExtraICState extra_state) { - DCHECK(!FLAG_tf_store_ic_stub); - LanguageMode mode = StoreICState::GetLanguageMode(extra_state); - return is_strict(mode) - ? isolate->builtins()->KeyedStoreIC_Megamorphic_Strict() - : isolate->builtins()->KeyedStoreIC_Megamorphic(); -} - -Handle<Object> LoadIC::SimpleFieldLoad(FieldIndex index) { - if (FLAG_tf_load_ic_stub) { - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH); - return LoadHandler::LoadField(isolate(), index); - } - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldStub); - LoadFieldStub stub(isolate(), index); - return stub.GetCode(); +Handle<Object> LoadIC::SimpleFieldLoad(Isolate* isolate, FieldIndex index) { + TRACE_HANDLER_STATS(isolate, LoadIC_LoadFieldDH); + return LoadHandler::LoadField(isolate, index); } namespace { @@ -1044,7 +1082,7 @@ bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) { if (holder->HasFastProperties()) { if (getter->IsJSFunction()) { Handle<JSFunction> function = Handle<JSFunction>::cast(getter); - if (!receiver->IsJSObject() && !function->shared()->IsBuiltin() && + if (!receiver->IsJSObject() && function->shared()->IsUserJavaScript() && is_sloppy(function->shared()->language_mode())) { // Calling sloppy non-builtins with a value as the receiver // requires boxing. @@ -1077,26 +1115,17 @@ 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) { TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH); code = LoadNonExistent(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. - if (code.is_null()) code = slow_stub(); } else { code = slow_stub(); } } else { if (kind() == Code::LOAD_GLOBAL_IC && lookup->state() == LookupIterator::DATA && - lookup->GetHolder<Object>()->IsJSGlobalObject()) { -#if DEBUG - Handle<Object> holder = lookup->GetHolder<Object>(); - Handle<Object> receiver = lookup->GetReceiver(); - DCHECK_EQ(*receiver, *holder); -#endif + lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) { + DCHECK(lookup->GetReceiver()->IsJSGlobalObject()); // Now update the cell in the feedback vector. LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>(); nexus->ConfigurePropertyCellMode(lookup->GetPropertyCell()); @@ -1108,22 +1137,15 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { code = slow_stub(); } } else if (lookup->state() == LookupIterator::INTERCEPTOR) { - if (kind() == Code::LOAD_GLOBAL_IC) { - // The interceptor handler requires name but it is not passed explicitly - // to LoadGlobalIC and the LoadGlobalIC dispatcher also does not load - // it so we will just use slow stub. + // Perform a lookup behind the interceptor. Copy the LookupIterator + // since the original iterator will be used to fetch the value. + LookupIterator it = *lookup; + it.Next(); + LookupForRead(&it); + if (it.state() == LookupIterator::ACCESSOR && + !IsCompatibleReceiver(&it, receiver_map())) { + TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type"); code = slow_stub(); - } else { - // Perform a lookup behind the interceptor. Copy the LookupIterator - // since the original iterator will be used to fetch the value. - LookupIterator it = *lookup; - it.Next(); - LookupForRead(&it); - if (it.state() == LookupIterator::ACCESSOR && - !IsCompatibleReceiver(&it, receiver_map())) { - TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type"); - code = slow_stub(); - } } } if (code.is_null()) code = ComputeHandler(lookup); @@ -1288,7 +1310,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { if (receiver->IsString() && Name::Equals(isolate()->factory()->length_string(), lookup->name())) { FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset); - return SimpleFieldLoad(index); + return SimpleFieldLoad(isolate(), index); } if (receiver->IsStringWrapper() && @@ -1326,7 +1348,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(), &object_offset)) { FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map); - return SimpleFieldLoad(index); + return SimpleFieldLoad(isolate(), index); } if (IsCompatibleReceiver(lookup, map)) { @@ -1356,26 +1378,15 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); return slow_stub(); } - if (FLAG_tf_load_ic_stub) { - Handle<Object> smi_handler = LoadHandler::LoadApiGetter( - isolate(), lookup->GetAccessorIndex()); - if (receiver_is_holder) { - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH); - return smi_handler; - } - if (kind() != Code::LOAD_GLOBAL_IC) { - TRACE_HANDLER_STATS(isolate(), - LoadIC_LoadApiGetterFromPrototypeDH); - return LoadFromPrototype(map, holder, lookup->name(), - smi_handler); - } - } else { - if (receiver_is_holder) { - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterStub); - int index = lookup->GetAccessorIndex(); - LoadApiGetterStub stub(isolate(), true, index); - return stub.GetCode(); - } + Handle<Object> smi_handler = + LoadHandler::LoadApiGetter(isolate(), lookup->GetAccessorIndex()); + if (receiver_is_holder) { + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH); + return smi_handler; + } + if (kind() != Code::LOAD_GLOBAL_IC) { + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH); + return LoadFromPrototype(map, holder, lookup->name(), smi_handler); } break; // Custom-compiled handler. } @@ -1385,6 +1396,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { } case LookupIterator::DATA: { + DCHECK_EQ(kData, lookup->property_details().kind()); if (lookup->is_dictionary_holder()) { if (kind() != Code::LOAD_IC && kind() != Code::LOAD_GLOBAL_IC) { TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); @@ -1406,40 +1418,26 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { } // -------------- Fields -------------- - if (lookup->property_details().type() == DATA) { + if (lookup->property_details().location() == kField) { FieldIndex field = lookup->GetFieldIndex(); - Handle<Object> smi_handler = SimpleFieldLoad(field); + Handle<Object> smi_handler = SimpleFieldLoad(isolate(), field); if (receiver_is_holder) { return smi_handler; } - if (FLAG_tf_load_ic_stub && kind() != Code::LOAD_GLOBAL_IC) { - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH); - return LoadFromPrototype(map, holder, lookup->name(), smi_handler); - } - break; // Custom-compiled handler. + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH); + return LoadFromPrototype(map, holder, lookup->name(), smi_handler); } // -------------- Constant properties -------------- - DCHECK(lookup->property_details().type() == DATA_CONSTANT); - if (FLAG_tf_load_ic_stub) { - Handle<Object> smi_handler = - LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex()); - if (receiver_is_holder) { - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH); - return smi_handler; - } - if (kind() != Code::LOAD_GLOBAL_IC) { - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH); - return LoadFromPrototype(map, holder, lookup->name(), smi_handler); - } - } else { - if (receiver_is_holder) { - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantStub); - LoadConstantStub stub(isolate(), lookup->GetConstantIndex()); - return stub.GetCode(); - } + DCHECK_EQ(kDescriptor, lookup->property_details().location()); + Handle<Object> smi_handler = + LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex()); + if (receiver_is_holder) { + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH); + return smi_handler; } - break; // Custom-compiled handler. + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH); + return LoadFromPrototype(map, holder, lookup->name(), smi_handler); } case LookupIterator::INTEGER_INDEXED_EXOTIC: @@ -1543,33 +1541,15 @@ Handle<Object> LoadIC::CompileHandler(LookupIterator* lookup, } case LookupIterator::DATA: { - if (lookup->is_dictionary_holder()) { - 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); - Handle<PropertyCell> cell = lookup->GetPropertyCell(); - Handle<Code> code = compiler.CompileLoadGlobal( - cell, lookup->name(), lookup->IsConfigurable()); - return code; - } - - // -------------- Fields -------------- - if (lookup->property_details().type() == DATA) { - FieldIndex field = lookup->GetFieldIndex(); - DCHECK(!receiver_is_holder); - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadField); - NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder); - return compiler.CompileLoadField(lookup->name(), field); - } - - // -------------- Constant properties -------------- - DCHECK(lookup->property_details().type() == DATA_CONSTANT); - DCHECK(!receiver_is_holder); - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstant); + DCHECK(lookup->is_dictionary_holder()); + 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); - return compiler.CompileLoadConstant(lookup->name(), - lookup->GetConstantIndex()); + Handle<PropertyCell> cell = lookup->GetPropertyCell(); + Handle<Code> code = compiler.CompileLoadGlobal(cell, lookup->name(), + lookup->IsConfigurable()); + return code; } case LookupIterator::INTEGER_INDEXED_EXOTIC: @@ -1839,7 +1819,14 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, // If the object is undefined or null it's illegal to try to set any // properties on it; throw a TypeError in that case. - if (object->IsUndefined(isolate()) || object->IsNull(isolate())) { + if (object->IsNullOrUndefined(isolate())) { + if (FLAG_use_ic && state() != UNINITIALIZED && state() != PREMONOMORPHIC) { + // Ensure the IC state progresses. + TRACE_HANDLER_STATS(isolate(), StoreIC_NonReceiver); + update_receiver_map(object); + PatchCache(name, slow_stub()); + TRACE_IC("StoreIC", name); + } return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name); } @@ -1890,11 +1877,12 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map, DCHECK(!transition->is_access_check_needed()); Handle<Object> smi_handler; - if (details.type() == DATA_CONSTANT) { + DCHECK_EQ(kData, details.kind()); + if (details.location() == kDescriptor) { smi_handler = StoreHandler::TransitionToConstant(isolate(), descriptor); } else { - DCHECK_EQ(DATA, details.type()); + DCHECK_EQ(kField, details.location()); bool extend_storage = Map::cast(transition->GetBackPointer())->unused_property_fields() == 0; @@ -1972,13 +1960,10 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { 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. + Handle<Map> transition = lookup->transition_map(); + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransitionDH); + return StoreTransition(receiver_map(), holder, transition, + lookup->name()); } case LookupIterator::INTERCEPTOR: { @@ -2044,6 +2029,7 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { } case LookupIterator::DATA: { + DCHECK_EQ(kData, lookup->property_details().kind()); if (lookup->is_dictionary_holder()) { if (holder->IsJSGlobalObject()) { break; // Custom-compiled handler. @@ -2054,32 +2040,16 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) { } // -------------- Fields -------------- - if (lookup->property_details().type() == DATA) { - if (FLAG_tf_store_ic_stub) { - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH); - int descriptor = lookup->GetFieldDescriptorIndex(); - FieldIndex index = lookup->GetFieldIndex(); - return StoreHandler::StoreField(isolate(), descriptor, index, - lookup->representation()); - } else { - bool use_stub = true; - if (lookup->representation().IsHeapObject()) { - // Only use a generic stub if no types need to be tracked. - Handle<FieldType> field_type = lookup->GetFieldType(); - use_stub = !field_type->IsClass(); - } - if (use_stub) { - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldStub); - StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), - lookup->representation()); - return stub.GetCode(); - } - } - break; // Custom-compiled handler. + if (lookup->property_details().location() == kField) { + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH); + int descriptor = lookup->GetFieldDescriptorIndex(); + FieldIndex index = lookup->GetFieldIndex(); + return StoreHandler::StoreField(isolate(), descriptor, index, + lookup->representation()); } // -------------- Constant properties -------------- - DCHECK(lookup->property_details().type() == DATA_CONSTANT); + DCHECK_EQ(kDescriptor, lookup->property_details().location()); TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property"); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); return slow_stub(); @@ -2117,15 +2087,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()); - - DCHECK(lookup->IsCacheableTransition()); - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransition); - NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder); - return compiler.CompileStoreTransition(transition, lookup->name()); + UNREACHABLE(); } case LookupIterator::INTERCEPTOR: @@ -2173,40 +2135,18 @@ Handle<Object> StoreIC::CompileHandler(LookupIterator* lookup, } case LookupIterator::DATA: { - if (lookup->is_dictionary_holder()) { - DCHECK(holder->IsJSGlobalObject()); - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobal); - DCHECK(holder.is_identical_to(receiver) || - receiver->map()->prototype() == *holder); - auto cell = lookup->GetPropertyCell(); - auto updated_type = - PropertyCell::UpdatedType(cell, value, lookup->property_details()); - auto code = PropertyCellStoreHandler( - isolate(), receiver, Handle<JSGlobalObject>::cast(holder), - lookup->name(), cell, updated_type); - return code; - } - - // -------------- Fields -------------- - if (lookup->property_details().type() == DATA) { - DCHECK(!FLAG_tf_store_ic_stub); -#ifdef DEBUG - bool use_stub = true; - if (lookup->representation().IsHeapObject()) { - // Only use a generic stub if no types need to be tracked. - Handle<FieldType> field_type = lookup->GetFieldType(); - use_stub = !field_type->IsClass(); - } - DCHECK(!use_stub); -#endif - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreField); - NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder); - return compiler.CompileStoreField(lookup); - } - - // -------------- Constant properties -------------- - DCHECK(lookup->property_details().type() == DATA_CONSTANT); - UNREACHABLE(); + DCHECK(lookup->is_dictionary_holder()); + DCHECK(holder->IsJSGlobalObject()); + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobal); + DCHECK(holder.is_identical_to(receiver) || + receiver->map()->prototype() == *holder); + auto cell = lookup->GetPropertyCell(); + auto updated_type = + PropertyCell::UpdatedType(cell, value, lookup->property_details()); + auto code = PropertyCellStoreHandler(isolate(), receiver, + Handle<JSGlobalObject>::cast(holder), + lookup->name(), cell, updated_type); + return code; } case LookupIterator::INTEGER_INDEXED_EXOTIC: @@ -2227,7 +2167,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver_map, store_mode); store_mode = GetNonTransitioningStoreMode(store_mode); - Handle<Code> handler = + Handle<Object> handler = PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(monomorphic_map, store_mode); return ConfigureVectorState(Handle<Name>(), monomorphic_map, handler); @@ -2261,7 +2201,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, // if they at least come from the same origin for a transitioning store, // stay MONOMORPHIC and use the map for the most generic ElementsKind. store_mode = GetNonTransitioningStoreMode(store_mode); - Handle<Code> handler = + Handle<Object> handler = PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler( transitioned_receiver_map, store_mode); ConfigureVectorState(Handle<Name>(), transitioned_receiver_map, handler); @@ -2275,7 +2215,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, // A "normal" IC that handles stores can switch to a version that can // grow at the end of the array, handle OOB accesses or copy COW arrays // and still stay MONOMORPHIC. - Handle<Code> handler = + Handle<Object> handler = PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(receiver_map, store_mode); return ConfigureVectorState(Handle<Name>(), receiver_map, handler); @@ -2336,7 +2276,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, } MapHandleList transitioned_maps(target_receiver_maps.length()); - CodeHandleList handlers(target_receiver_maps.length()); + List<Handle<Object>> handlers(target_receiver_maps.length()); PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers( &target_receiver_maps, &transitioned_maps, &handlers, store_mode); ConfigureVectorState(&target_receiver_maps, &transitioned_maps, &handlers); @@ -2485,17 +2425,14 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, } Handle<Map> old_receiver_map; - bool sloppy_arguments_elements = false; + bool is_arguments = false; bool key_is_valid_index = false; KeyedAccessStoreMode store_mode = STANDARD_STORE; if (use_ic && object->IsJSObject()) { Handle<JSObject> receiver = Handle<JSObject>::cast(object); old_receiver_map = handle(receiver->map(), isolate()); - sloppy_arguments_elements = - !is_sloppy(language_mode()) && - receiver->elements()->map() == - isolate()->heap()->sloppy_arguments_elements_map(); - if (!sloppy_arguments_elements) { + is_arguments = receiver->IsJSArgumentsObject(); + if (!is_arguments) { key_is_valid_index = key->IsSmi() && Smi::cast(*key)->value() >= 0; if (key_is_valid_index) { uint32_t index = static_cast<uint32_t>(Smi::cast(*key)->value()); @@ -2512,7 +2449,7 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, if (use_ic) { if (!old_receiver_map.is_null()) { - if (sloppy_arguments_elements) { + if (is_arguments) { TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "arguments receiver"); } else if (key_is_valid_index) { // We should go generic if receiver isn't a dictionary, but our @@ -2597,7 +2534,7 @@ RUNTIME_FUNCTION(Runtime_CallIC_Miss) { HandleScope scope(isolate); DCHECK_EQ(3, args.length()); // Runtime functions don't follow the IC's calling convention. - Handle<Object> function = args.at<Object>(0); + Handle<Object> function = args.at(0); Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1); Handle<Smi> slot = args.at<Smi>(2); FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); @@ -2613,7 +2550,8 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) { HandleScope scope(isolate); DCHECK_EQ(4, args.length()); // Runtime functions don't follow the IC's calling convention. - Handle<Object> receiver = args.at<Object>(0); + Handle<Object> receiver = args.at(0); + Handle<Name> key = args.at<Name>(1); Handle<Smi> slot = args.at<Smi>(2); Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3); FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); @@ -2622,15 +2560,12 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) { // set up outside the IC, handle that here. FeedbackVectorSlotKind kind = vector->GetKind(vector_slot); if (kind == FeedbackVectorSlotKind::LOAD_IC) { - Handle<Name> key = args.at<Name>(1); 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) { - Handle<Name> key(vector->GetName(vector_slot), isolate); - DCHECK_NE(*key, isolate->heap()->empty_string()); DCHECK_EQ(*isolate->global_object(), *receiver); LoadGlobalICNexus nexus(vector, vector_slot); LoadGlobalIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); @@ -2638,7 +2573,6 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) { RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key)); } else { - Handle<Name> key = args.at<Name>(1); DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, kind); KeyedLoadICNexus nexus(vector, vector_slot); KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); @@ -2650,16 +2584,13 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) { // Used from ic-<arch>.cc. RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) { HandleScope scope(isolate); - DCHECK_EQ(2, args.length()); + DCHECK_EQ(3, args.length()); // Runtime functions don't follow the IC's calling convention. Handle<JSGlobalObject> global = isolate->global_object(); - Handle<Smi> slot = args.at<Smi>(0); - Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1); + Handle<String> name = args.at<String>(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)); - Handle<String> name(vector->GetName(vector_slot), isolate); - DCHECK_NE(*name, isolate->heap()->empty_string()); LoadGlobalICNexus nexus(vector, vector_slot); LoadGlobalIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); @@ -2672,20 +2603,12 @@ RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) { RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) { HandleScope scope(isolate); - DCHECK_EQ(2, args.length()); - CONVERT_SMI_ARG_CHECKED(slot, 0); - CONVERT_ARG_HANDLE_CHECKED(TypeFeedbackVector, vector, 1); - - FeedbackVectorSlot vector_slot = vector->ToSlot(slot); - DCHECK_EQ(FeedbackVectorSlotKind::LOAD_GLOBAL_IC, - vector->GetKind(vector_slot)); - Handle<String> name(vector->GetName(vector_slot), isolate); - DCHECK_NE(*name, isolate->heap()->empty_string()); - - Handle<JSGlobalObject> global = isolate->global_object(); + DCHECK_EQ(1, args.length()); + CONVERT_ARG_HANDLE_CHECKED(String, name, 0); + Handle<Context> native_context = isolate->native_context(); Handle<ScriptContextTable> script_contexts( - global->native_context()->script_context_table()); + native_context->script_context_table()); ScriptContextTable::LookupResult lookup_result; if (ScriptContextTable::Lookup(script_contexts, name, &lookup_result)) { @@ -2700,6 +2623,7 @@ RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) { return *result; } + Handle<JSGlobalObject> global(native_context->global_object(), isolate); Handle<Object> result; bool is_found = false; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( @@ -2723,8 +2647,8 @@ RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) { HandleScope scope(isolate); DCHECK_EQ(4, args.length()); // Runtime functions don't follow the IC's calling convention. - Handle<Object> receiver = args.at<Object>(0); - Handle<Object> key = args.at<Object>(1); + Handle<Object> receiver = args.at(0); + Handle<Object> key = args.at(1); Handle<Smi> slot = args.at<Smi>(2); Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3); FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); @@ -2739,8 +2663,8 @@ RUNTIME_FUNCTION(Runtime_KeyedLoadIC_MissFromStubFailure) { HandleScope scope(isolate); typedef LoadWithVectorDescriptor Descriptor; DCHECK_EQ(Descriptor::kParameterCount, args.length()); - Handle<Object> receiver = args.at<Object>(Descriptor::kReceiver); - Handle<Object> key = args.at<Object>(Descriptor::kName); + Handle<Object> receiver = args.at(Descriptor::kReceiver); + Handle<Object> key = args.at(Descriptor::kName); Handle<Smi> slot = args.at<Smi>(Descriptor::kSlot); Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(Descriptor::kVector); @@ -2757,10 +2681,10 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) { HandleScope scope(isolate); DCHECK_EQ(5, args.length()); // Runtime functions don't follow the IC's calling convention. - Handle<Object> value = args.at<Object>(0); + Handle<Object> value = args.at(0); Handle<Smi> slot = args.at<Smi>(1); Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2); - Handle<Object> receiver = args.at<Object>(3); + Handle<Object> receiver = args.at(3); Handle<Name> key = args.at<Name>(4); FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::STORE_IC) { @@ -2784,11 +2708,11 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) { HandleScope scope(isolate); DCHECK_EQ(5, args.length()); // Runtime functions don't follow the IC's calling convention. - Handle<Object> value = args.at<Object>(0); + Handle<Object> value = args.at(0); Handle<Smi> slot = args.at<Smi>(1); Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2); - Handle<Object> receiver = args.at<Object>(3); - Handle<Object> key = args.at<Object>(4); + Handle<Object> receiver = args.at(3); + Handle<Object> key = args.at(4); FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); KeyedStoreICNexus nexus(vector, vector_slot); KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); @@ -2801,10 +2725,10 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) { HandleScope scope(isolate); DCHECK_EQ(5, args.length()); // Runtime functions don't follow the IC's calling convention. - Handle<Object> value = args.at<Object>(0); + Handle<Object> value = args.at(0); // slot and vector parameters are not used. - Handle<Object> object = args.at<Object>(3); - Handle<Object> key = args.at<Object>(4); + Handle<Object> object = args.at(3); + Handle<Object> key = args.at(4); LanguageMode language_mode; KeyedStoreICNexus nexus(isolate); KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); @@ -2818,9 +2742,9 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) { RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) { HandleScope scope(isolate); // Runtime functions don't follow the IC's calling convention. - Handle<Object> object = args.at<Object>(0); - Handle<Object> key = args.at<Object>(1); - Handle<Object> value = args.at<Object>(2); + Handle<Object> object = args.at(0); + Handle<Object> key = args.at(1); + Handle<Object> value = args.at(2); Handle<Map> map = args.at<Map>(3); LanguageMode language_mode; KeyedStoreICNexus nexus(isolate); @@ -2931,7 +2855,19 @@ MaybeHandle<Object> BinaryOpIC::Transition( } set_target(*new_target); - if (FLAG_trace_ic) { + if (FLAG_ic_stats & + v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) { + auto ic_stats = ICStats::instance(); + ic_stats->Begin(); + ICInfo& ic_info = ic_stats->Current(); + ic_info.type = "BinaryOpIC"; + ic_info.state = old_state.ToString(); + ic_info.state += " => "; + ic_info.state += state.ToString(); + JavaScriptFrame::CollectTopFrameForICStats(isolate()); + ic_stats->End(); + } else if (FLAG_ic_stats) { + // if (FLAG_trace_ic) { OFStream os(stdout); os << "[BinaryOpIC" << old_state << " => " << state << " @ " << static_cast<void*>(*new_target) << " <- "; @@ -2957,8 +2893,8 @@ RUNTIME_FUNCTION(Runtime_BinaryOpIC_Miss) { HandleScope scope(isolate); DCHECK_EQ(2, args.length()); typedef BinaryOpDescriptor Descriptor; - Handle<Object> left = args.at<Object>(Descriptor::kLeft); - Handle<Object> right = args.at<Object>(Descriptor::kRight); + Handle<Object> left = args.at(Descriptor::kLeft); + Handle<Object> right = args.at(Descriptor::kRight); BinaryOpIC ic(isolate); RETURN_RESULT_OR_FAILURE( isolate, ic.Transition(Handle<AllocationSite>::null(), left, right)); @@ -2971,8 +2907,8 @@ RUNTIME_FUNCTION(Runtime_BinaryOpIC_MissWithAllocationSite) { typedef BinaryOpWithAllocationSiteDescriptor Descriptor; Handle<AllocationSite> allocation_site = args.at<AllocationSite>(Descriptor::kAllocationSite); - Handle<Object> left = args.at<Object>(Descriptor::kLeft); - Handle<Object> right = args.at<Object>(Descriptor::kRight); + Handle<Object> left = args.at(Descriptor::kLeft); + Handle<Object> right = args.at(Descriptor::kRight); BinaryOpIC ic(isolate); RETURN_RESULT_OR_FAILURE(isolate, ic.Transition(allocation_site, left, right)); @@ -3005,7 +2941,30 @@ Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { Handle<Code> new_target = stub.GetCode(); set_target(*new_target); - if (FLAG_trace_ic) { + if (FLAG_ic_stats & + v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) { + auto ic_stats = ICStats::instance(); + ic_stats->Begin(); + ICInfo& ic_info = ic_stats->Current(); + ic_info.type = "CompareIC"; + JavaScriptFrame::CollectTopFrameForICStats(isolate()); + ic_info.state = "(("; + ic_info.state += CompareICState::GetStateName(old_stub.left()); + ic_info.state += "+"; + ic_info.state += CompareICState::GetStateName(old_stub.right()); + ic_info.state += "="; + ic_info.state += CompareICState::GetStateName(old_stub.state()); + ic_info.state += ")->("; + ic_info.state += CompareICState::GetStateName(new_left); + ic_info.state += "+"; + ic_info.state += CompareICState::GetStateName(new_right); + ic_info.state += "="; + ic_info.state += CompareICState::GetStateName(state); + ic_info.state += "))#"; + ic_info.state += Token::Name(op_); + ic_stats->End(); + } else if (FLAG_ic_stats) { + // if (FLAG_trace_ic) { PrintF("[CompareIC in "); JavaScriptFrame::PrintTop(isolate(), stdout, false, true); PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n", @@ -3032,7 +2991,7 @@ RUNTIME_FUNCTION(Runtime_CompareIC_Miss) { HandleScope scope(isolate); DCHECK(args.length() == 3); CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2))); - return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1)); + return ic.UpdateCaches(args.at(0), args.at(1)); } @@ -3055,7 +3014,7 @@ Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) { RUNTIME_FUNCTION(Runtime_ToBooleanIC_Miss) { DCHECK(args.length() == 1); HandleScope scope(isolate); - Handle<Object> object = args.at<Object>(0); + Handle<Object> object = args.at(0); ToBooleanIC ic(isolate); return *ic.ToBoolean(object); } @@ -3066,7 +3025,7 @@ RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) { Handle<JSObject> holder = args.at<JSObject>(1); Handle<HeapObject> callback_or_cell = args.at<HeapObject>(2); Handle<Name> name = args.at<Name>(3); - Handle<Object> value = args.at<Object>(4); + Handle<Object> value = args.at(4); CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 5); HandleScope scope(isolate); @@ -3110,7 +3069,7 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly) { Handle<Name> name = args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex); Handle<Object> receiver = - args.at<Object>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex); + args.at(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex); Handle<JSObject> holder = args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex); HandleScope scope(isolate); @@ -3146,7 +3105,7 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) { Handle<Name> name = args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex); Handle<Object> receiver = - args.at<Object>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex); + args.at(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex); Handle<JSObject> holder = args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex); @@ -3181,15 +3140,17 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) { if (it.IsFound()) return *result; -#ifdef DEBUG LoadICNexus nexus(isolate); LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); // It could actually be any kind of LoadICs here but the predicate handles // all the cases properly. - DCHECK(!ic.ShouldThrowReferenceError()); -#endif + if (!ic.ShouldThrowReferenceError()) { + return isolate->heap()->undefined_value(); + } - return isolate->heap()->undefined_value(); + // Throw a reference error. + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name())); } @@ -3200,7 +3161,7 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) { StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); Handle<JSObject> receiver = args.at<JSObject>(0); Handle<Name> name = args.at<Name>(1); - Handle<Object> value = args.at<Object>(2); + Handle<Object> value = args.at(2); DCHECK(receiver->HasNamedInterceptor()); InterceptorInfo* interceptor = receiver->GetNamedInterceptor(); |