Commit 7677b2ef authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

Revert "[ic] Don't transition to premonomorphic state"

This reverts commit 159df248.

Reason for revert: Breaks large-classes-properties test (https://logs.chromium.org/logs/v8/buildbucket/cr-buildbucket.appspot.com/8906338563361079200/+/steps/Bisect_159df248/0/steps/Retry_-_isolates/0/logs/large-classes-properties/0)

Original change's description:
> [ic] Don't transition to premonomorphic state
> 
> We used to use premonomorphic state to delay initializing the ICs.
> This optimization was to avoid the cost of setting up handlers if the
> code executed only once. With lazy feedback allocation we no longer
> need this.
> 
> This cl also renames LoadIC_Uninitialized to LoadIC_Nofeedback and
> StoreIC_Uninitialized to StoreIC_Nofeedback since we now miss to
> runtime in the uninitialized state and use the builtin when there
> is no feedback.
> 
> 
> Change-Id: I1633e61ea74664da51348e362c34c47a017a264a
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1683525
> Commit-Queue: Mythri Alle <mythria@chromium.org>
> Reviewed-by: Toon Verwaest <verwaest@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#63020}

TBR=mythria@chromium.org,verwaest@chromium.org

Change-Id: I4fad4e8b881d4a3f8d12149e1797b217a317eaee
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1730995Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63023}
parent 33b93f3d
...@@ -222,9 +222,9 @@ namespace internal { ...@@ -222,9 +222,9 @@ namespace internal {
TFH(LoadIC_Slow, LoadWithVector) \ TFH(LoadIC_Slow, LoadWithVector) \
TFH(LoadIC_StringLength, LoadWithVector) \ TFH(LoadIC_StringLength, LoadWithVector) \
TFH(LoadIC_StringWrapperLength, LoadWithVector) \ TFH(LoadIC_StringWrapperLength, LoadWithVector) \
TFH(LoadIC_Nofeedback, Load) \ TFH(LoadIC_Uninitialized, LoadWithVector) \
TFH(StoreGlobalIC_Slow, StoreWithVector) \ TFH(StoreGlobalIC_Slow, StoreWithVector) \
TFH(StoreIC_Nofeedback, Store) \ TFH(StoreIC_Uninitialized, StoreWithVector) \
TFH(StoreInArrayLiteralIC_Slow, StoreWithVector) \ TFH(StoreInArrayLiteralIC_Slow, StoreWithVector) \
TFH(KeyedLoadIC_SloppyArguments, LoadWithVector) \ TFH(KeyedLoadIC_SloppyArguments, LoadWithVector) \
TFH(LoadIndexedInterceptorIC, LoadWithVector) \ TFH(LoadIndexedInterceptorIC, LoadWithVector) \
......
...@@ -66,9 +66,9 @@ void Builtins::Generate_KeyedStoreIC_Megamorphic( ...@@ -66,9 +66,9 @@ void Builtins::Generate_KeyedStoreIC_Megamorphic(
KeyedStoreGenericGenerator::Generate(state); KeyedStoreGenericGenerator::Generate(state);
} }
void Builtins::Generate_StoreIC_Nofeedback( void Builtins::Generate_StoreIC_Uninitialized(
compiler::CodeAssemblerState* state) { compiler::CodeAssemblerState* state) {
StoreICNofeedbackGenerator::Generate(state); StoreICUninitializedGenerator::Generate(state);
} }
// TODO(mythria): Check if we can remove feedback vector and slot parameters in // TODO(mythria): Check if we can remove feedback vector and slot parameters in
......
...@@ -23,7 +23,7 @@ namespace internal { ...@@ -23,7 +23,7 @@ namespace internal {
IC_BUILTIN(LoadIC) IC_BUILTIN(LoadIC)
IC_BUILTIN(LoadIC_Megamorphic) IC_BUILTIN(LoadIC_Megamorphic)
IC_BUILTIN(LoadIC_Noninlined) IC_BUILTIN(LoadIC_Noninlined)
IC_BUILTIN(LoadIC_Nofeedback) IC_BUILTIN(LoadIC_Uninitialized)
IC_BUILTIN(LoadICTrampoline) IC_BUILTIN(LoadICTrampoline)
IC_BUILTIN(LoadICTrampoline_Megamorphic) IC_BUILTIN(LoadICTrampoline_Megamorphic)
IC_BUILTIN(KeyedLoadIC) IC_BUILTIN(KeyedLoadIC)
......
...@@ -2524,8 +2524,8 @@ void AccessorAssembler::LoadIC_BytecodeHandler(const LazyLoadICParameters* p, ...@@ -2524,8 +2524,8 @@ void AccessorAssembler::LoadIC_BytecodeHandler(const LazyLoadICParameters* p,
Comment("LoadIC_BytecodeHandler_nofeedback"); Comment("LoadIC_BytecodeHandler_nofeedback");
// Call into the stub that implements the non-inlined parts of LoadIC. // Call into the stub that implements the non-inlined parts of LoadIC.
exit_point->ReturnCallStub( exit_point->ReturnCallStub(
Builtins::CallableFor(isolate(), Builtins::kLoadIC_Nofeedback), Builtins::CallableFor(isolate(), Builtins::kLoadIC_Uninitialized),
p->context(), p->receiver(), p->name(), p->slot()); p->context(), p->receiver(), p->name(), p->slot(), p->vector());
} }
BIND(&miss); BIND(&miss);
...@@ -2589,6 +2589,8 @@ void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p, ...@@ -2589,6 +2589,8 @@ void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p,
TVariable<MaybeObject>* var_handler, TVariable<MaybeObject>* var_handler,
Label* if_handler, Label* miss, Label* if_handler, Label* miss,
ExitPoint* exit_point) { ExitPoint* exit_point) {
Label try_uninitialized(this, Label::kDeferred);
// Neither deprecated map nor monomorphic. These cases are handled in the // Neither deprecated map nor monomorphic. These cases are handled in the
// bytecode handler. // bytecode handler.
CSA_ASSERT(this, Word32BinaryNot(IsDeprecatedMap(receiver_map))); CSA_ASSERT(this, Word32BinaryNot(IsDeprecatedMap(receiver_map)));
...@@ -2599,20 +2601,41 @@ void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p, ...@@ -2599,20 +2601,41 @@ void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p,
{ {
// Check megamorphic case. // Check megamorphic case.
GotoIfNot(WordEqual(feedback, LoadRoot(RootIndex::kmegamorphic_symbol)), GotoIfNot(WordEqual(feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
miss); &try_uninitialized);
TryProbeStubCache(isolate()->load_stub_cache(), p->receiver(), p->name(), TryProbeStubCache(isolate()->load_stub_cache(), p->receiver(), p->name(),
if_handler, var_handler, miss); if_handler, var_handler, miss);
} }
BIND(&try_uninitialized);
{
// Check uninitialized case.
GotoIfNot(WordEqual(feedback, LoadRoot(RootIndex::kuninitialized_symbol)),
miss);
exit_point->ReturnCallStub(
Builtins::CallableFor(isolate(), Builtins::kLoadIC_Uninitialized),
p->context(), p->receiver(), p->name(), p->slot(), p->vector());
}
} }
void AccessorAssembler::LoadIC_Nofeedback(const LoadICParameters* p) { void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) {
Label miss(this, Label::kDeferred); Label miss(this, Label::kDeferred),
check_function_prototype(this);
Node* receiver = p->receiver(); Node* receiver = p->receiver();
GotoIf(TaggedIsSmi(receiver), &miss); GotoIf(TaggedIsSmi(receiver), &miss);
Node* receiver_map = LoadMap(receiver); Node* receiver_map = LoadMap(receiver);
Node* instance_type = LoadMapInstanceType(receiver_map); Node* instance_type = LoadMapInstanceType(receiver_map);
GotoIf(IsUndefined(p->vector()), &check_function_prototype);
// Optimistically write the state transition to the vector.
StoreFeedbackVectorSlot(p->vector(), p->slot(),
LoadRoot(RootIndex::kpremonomorphic_symbol),
SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
StoreWeakReferenceInFeedbackVector(p->vector(), p->slot(), receiver_map,
kTaggedSize, SMI_PARAMETERS);
Goto(&check_function_prototype);
BIND(&check_function_prototype);
{ {
// Special case for Function.prototype load, because it's very common // Special case for Function.prototype load, because it's very common
// for ICs that are only executed once (MyFunc.prototype.foo = ...). // for ICs that are only executed once (MyFunc.prototype.foo = ...).
...@@ -2632,6 +2655,15 @@ void AccessorAssembler::LoadIC_Nofeedback(const LoadICParameters* p) { ...@@ -2632,6 +2655,15 @@ void AccessorAssembler::LoadIC_Nofeedback(const LoadICParameters* p) {
BIND(&miss); BIND(&miss);
{ {
Label call_runtime(this, Label::kDeferred);
GotoIf(IsUndefined(p->vector()), &call_runtime);
// Undo the optimistic state transition.
StoreFeedbackVectorSlot(p->vector(), p->slot(),
LoadRoot(RootIndex::kuninitialized_symbol),
SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
Goto(&call_runtime);
BIND(&call_runtime);
TailCallRuntime(Runtime::kLoadIC_Miss, p->context(), p->receiver(), TailCallRuntime(Runtime::kLoadIC_Miss, p->context(), p->receiver(),
p->name(), p->slot(), p->vector()); p->name(), p->slot(), p->vector());
} }
...@@ -2740,7 +2772,6 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p, ...@@ -2740,7 +2772,6 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p,
TVARIABLE(MaybeObject, var_handler); TVARIABLE(MaybeObject, var_handler);
Label if_handler(this, &var_handler), try_polymorphic(this, Label::kDeferred), Label if_handler(this, &var_handler), try_polymorphic(this, Label::kDeferred),
try_megamorphic(this, Label::kDeferred), try_megamorphic(this, Label::kDeferred),
try_uninitialized(this, Label::kDeferred),
try_polymorphic_name(this, Label::kDeferred), try_polymorphic_name(this, Label::kDeferred),
miss(this, Label::kDeferred), generic(this, Label::kDeferred); miss(this, Label::kDeferred), generic(this, Label::kDeferred);
...@@ -2777,7 +2808,7 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p, ...@@ -2777,7 +2808,7 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p,
// Check megamorphic case. // Check megamorphic case.
Comment("KeyedLoadIC_try_megamorphic"); Comment("KeyedLoadIC_try_megamorphic");
Branch(WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)), Branch(WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
&generic, &try_uninitialized); &generic, &try_polymorphic_name);
} }
BIND(&generic); BIND(&generic);
...@@ -2790,15 +2821,6 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p, ...@@ -2790,15 +2821,6 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p,
p->vector()); p->vector());
} }
BIND(&try_uninitialized);
{
// Check uninitialized case.
Comment("KeyedLoadIC_try_uninitialized");
Branch(
WordEqual(strong_feedback, LoadRoot(RootIndex::kuninitialized_symbol)),
&miss, &try_polymorphic_name);
}
BIND(&try_polymorphic_name); BIND(&try_polymorphic_name);
{ {
// We might have a name in feedback, and a weak fixed array in the next // We might have a name in feedback, and a weak fixed array in the next
...@@ -2992,7 +3014,8 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) { ...@@ -2992,7 +3014,8 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) {
Label if_handler(this, &var_handler), Label if_handler(this, &var_handler),
if_handler_from_stub_cache(this, &var_handler, Label::kDeferred), if_handler_from_stub_cache(this, &var_handler, Label::kDeferred),
try_polymorphic(this, Label::kDeferred), try_polymorphic(this, Label::kDeferred),
try_megamorphic(this, Label::kDeferred), miss(this, Label::kDeferred), try_megamorphic(this, Label::kDeferred),
try_uninitialized(this, Label::kDeferred), miss(this, Label::kDeferred),
no_feedback(this, Label::kDeferred); no_feedback(this, Label::kDeferred);
Node* receiver_map = LoadReceiverMap(p->receiver()); Node* receiver_map = LoadReceiverMap(p->receiver());
...@@ -3026,16 +3049,24 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) { ...@@ -3026,16 +3049,24 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) {
// Check megamorphic case. // Check megamorphic case.
GotoIfNot( GotoIfNot(
WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)), WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
&miss); &try_uninitialized);
TryProbeStubCache(isolate()->store_stub_cache(), p->receiver(), p->name(), TryProbeStubCache(isolate()->store_stub_cache(), p->receiver(), p->name(),
&if_handler, &var_handler, &miss); &if_handler, &var_handler, &miss);
} }
BIND(&try_uninitialized);
{
// Check uninitialized case.
Branch(
WordEqual(strong_feedback, LoadRoot(RootIndex::kuninitialized_symbol)),
&no_feedback, &miss);
}
BIND(&no_feedback); BIND(&no_feedback);
{ {
TailCallBuiltin(Builtins::kStoreIC_Nofeedback, p->context(), p->receiver(), TailCallBuiltin(Builtins::kStoreIC_Uninitialized, p->context(),
p->name(), p->value(), p->slot()); p->receiver(), p->name(), p->value(), p->slot(),
p->vector());
} }
BIND(&miss); BIND(&miss);
...@@ -3054,10 +3085,6 @@ void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) { ...@@ -3054,10 +3085,6 @@ void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) {
BIND(&if_heapobject); BIND(&if_heapobject);
{ {
Label try_handler(this), miss(this, Label::kDeferred); Label try_handler(this), miss(this, Label::kDeferred);
// We use pre-monomorphic state for global stores that run into
// interceptors because the property doesn't exist yet. Using
// pre-monomorphic state gives it a chance to find more information the
// second time.
GotoIf( GotoIf(
WordEqual(maybe_weak_ref, LoadRoot(RootIndex::kpremonomorphic_symbol)), WordEqual(maybe_weak_ref, LoadRoot(RootIndex::kpremonomorphic_symbol)),
&miss); &miss);
...@@ -3405,16 +3432,17 @@ void AccessorAssembler::GenerateLoadIC_Noninlined() { ...@@ -3405,16 +3432,17 @@ void AccessorAssembler::GenerateLoadIC_Noninlined() {
slot, vector); slot, vector);
} }
void AccessorAssembler::GenerateLoadIC_Nofeedback() { void AccessorAssembler::GenerateLoadIC_Uninitialized() {
using Descriptor = LoadDescriptor; using Descriptor = LoadWithVectorDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver); Node* receiver = Parameter(Descriptor::kReceiver);
Node* name = Parameter(Descriptor::kName); Node* name = Parameter(Descriptor::kName);
Node* slot = Parameter(Descriptor::kSlot); Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext)); TNode<Context> context = CAST(Parameter(Descriptor::kContext));
LoadICParameters p(context, receiver, name, slot, UndefinedConstant()); LoadICParameters p(context, receiver, name, slot, vector);
LoadIC_Nofeedback(&p); LoadIC_Uninitialized(&p);
} }
void AccessorAssembler::GenerateLoadICTrampoline() { void AccessorAssembler::GenerateLoadICTrampoline() {
......
...@@ -30,7 +30,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { ...@@ -30,7 +30,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
void GenerateLoadIC(); void GenerateLoadIC();
void GenerateLoadIC_Megamorphic(); void GenerateLoadIC_Megamorphic();
void GenerateLoadIC_Noninlined(); void GenerateLoadIC_Noninlined();
void GenerateLoadIC_Nofeedback(); void GenerateLoadIC_Uninitialized();
void GenerateLoadICTrampoline(); void GenerateLoadICTrampoline();
void GenerateLoadICTrampoline_Megamorphic(); void GenerateLoadICTrampoline_Megamorphic();
void GenerateKeyedLoadIC(); void GenerateKeyedLoadIC();
...@@ -214,7 +214,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { ...@@ -214,7 +214,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
TNode<MaybeObject> LoadDescriptorValueOrFieldType( TNode<MaybeObject> LoadDescriptorValueOrFieldType(
TNode<Map> map, TNode<IntPtrT> descriptor_entry); TNode<Map> map, TNode<IntPtrT> descriptor_entry);
void LoadIC_Nofeedback(const LoadICParameters* p); void LoadIC_Uninitialized(const LoadICParameters* p);
void KeyedLoadIC(const LoadICParameters* p, LoadAccessMode access_mode); void KeyedLoadIC(const LoadICParameters* p, LoadAccessMode access_mode);
void KeyedLoadICGeneric(const LoadICParameters* p); void KeyedLoadICGeneric(const LoadICParameters* p);
......
...@@ -400,8 +400,10 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { ...@@ -400,8 +400,10 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
if (MigrateDeprecated(isolate(), object)) use_ic = false; if (MigrateDeprecated(isolate(), object)) use_ic = false;
JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate()); if (state() != UNINITIALIZED) {
update_receiver_map(object); JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate());
update_receiver_map(object);
}
LookupIterator it(isolate(), object, name); LookupIterator it(isolate(), object, name);
...@@ -646,6 +648,15 @@ void IC::PatchCache(Handle<Name> name, const MaybeObjectHandle& handler) { ...@@ -646,6 +648,15 @@ void IC::PatchCache(Handle<Name> name, const MaybeObjectHandle& handler) {
} }
void LoadIC::UpdateCaches(LookupIterator* lookup) { void LoadIC::UpdateCaches(LookupIterator* lookup) {
if (state() == UNINITIALIZED && !IsLoadGlobalIC()) {
// This is the first time we execute this inline cache. Set the target to
// the pre monomorphic stub to delay setting the monomorphic state.
TRACE_HANDLER_STATS(isolate(), LoadIC_Premonomorphic);
ConfigureVectorState(receiver_map());
TraceIC("LoadIC", lookup->name());
return;
}
Handle<Object> code; Handle<Object> code;
if (lookup->state() == LookupIterator::ACCESS_CHECK) { if (lookup->state() == LookupIterator::ACCESS_CHECK) {
code = slow_stub(); code = slow_stub();
...@@ -1404,7 +1415,9 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, ...@@ -1404,7 +1415,9 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name); return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name);
} }
JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate()); if (state() != UNINITIALIZED) {
JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
}
LookupIterator it(isolate(), object, name); LookupIterator it(isolate(), object, name);
if (name->IsPrivate()) { if (name->IsPrivate()) {
...@@ -1429,6 +1442,15 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, ...@@ -1429,6 +1442,15 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value, void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
StoreOrigin store_origin) { StoreOrigin store_origin) {
if (state() == UNINITIALIZED && !IsStoreGlobalIC()) {
// This is the first time we execute this inline cache. Transition
// to premonomorphic state to delay setting the monomorphic state.
TRACE_HANDLER_STATS(isolate(), StoreIC_Premonomorphic);
ConfigureVectorState(receiver_map());
TraceIC("StoreIC", lookup->name());
return;
}
MaybeObjectHandle handler; MaybeObjectHandle handler;
if (LookupForWrite(lookup, value, store_origin)) { if (LookupForWrite(lookup, value, store_origin)) {
if (IsStoreGlobalIC()) { if (IsStoreGlobalIC()) {
...@@ -1788,8 +1810,10 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, ...@@ -1788,8 +1810,10 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
handlers.reserve(target_receiver_maps.size()); handlers.reserve(target_receiver_maps.size());
StoreElementPolymorphicHandlers(&target_receiver_maps, &handlers, store_mode); StoreElementPolymorphicHandlers(&target_receiver_maps, &handlers, store_mode);
if (target_receiver_maps.size() == 0) { if (target_receiver_maps.size() == 0) {
Handle<Object> handler = StoreElementHandler(receiver_map, store_mode); // Transition to PREMONOMORPHIC state here and remember a weak-reference
ConfigureVectorState(Handle<Name>(), receiver_map, handler); // to the {receiver_map} in case TurboFan sees this function before the
// IC can transition further.
ConfigureVectorState(receiver_map);
} else if (target_receiver_maps.size() == 1) { } else if (target_receiver_maps.size() == 1) {
ConfigureVectorState(Handle<Name>(), target_receiver_maps[0], handlers[0]); ConfigureVectorState(Handle<Name>(), target_receiver_maps[0], handlers[0]);
} else { } else {
......
...@@ -30,7 +30,7 @@ class KeyedStoreGenericAssembler : public AccessorAssembler { ...@@ -30,7 +30,7 @@ class KeyedStoreGenericAssembler : public AccessorAssembler {
void KeyedStoreGeneric(); void KeyedStoreGeneric();
void StoreIC_Nofeedback(); void StoreIC_Uninitialized();
// Generates code for [[Set]] operation, the |unique_name| is supposed to be // Generates code for [[Set]] operation, the |unique_name| is supposed to be
// unique otherwise this code will always go to runtime. // unique otherwise this code will always go to runtime.
...@@ -138,9 +138,10 @@ void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state) { ...@@ -138,9 +138,10 @@ void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state) {
assembler.KeyedStoreGeneric(); assembler.KeyedStoreGeneric();
} }
void StoreICNofeedbackGenerator::Generate(compiler::CodeAssemblerState* state) { void StoreICUninitializedGenerator::Generate(
compiler::CodeAssemblerState* state) {
KeyedStoreGenericAssembler assembler(state, StoreMode::kOrdinary); KeyedStoreGenericAssembler assembler(state, StoreMode::kOrdinary);
assembler.StoreIC_Nofeedback(); assembler.StoreIC_Uninitialized();
} }
void KeyedStoreGenericGenerator::SetProperty( void KeyedStoreGenericGenerator::SetProperty(
...@@ -1042,13 +1043,14 @@ void KeyedStoreGenericAssembler::SetProperty(TNode<Context> context, ...@@ -1042,13 +1043,14 @@ void KeyedStoreGenericAssembler::SetProperty(TNode<Context> context,
KeyedStoreGeneric(context, receiver, key, value, Just(language_mode)); KeyedStoreGeneric(context, receiver, key, value, Just(language_mode));
} }
void KeyedStoreGenericAssembler::StoreIC_Nofeedback() { void KeyedStoreGenericAssembler::StoreIC_Uninitialized() {
using Descriptor = StoreDescriptor; using Descriptor = StoreWithVectorDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver); Node* receiver = Parameter(Descriptor::kReceiver);
Node* name = Parameter(Descriptor::kName); Node* name = Parameter(Descriptor::kName);
Node* value = Parameter(Descriptor::kValue); Node* value = Parameter(Descriptor::kValue);
Node* slot = Parameter(Descriptor::kSlot); Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
Node* context = Parameter(Descriptor::kContext); Node* context = Parameter(Descriptor::kContext);
Label miss(this, Label::kDeferred), store_property(this); Label miss(this, Label::kDeferred), store_property(this);
...@@ -1059,16 +1061,33 @@ void KeyedStoreGenericAssembler::StoreIC_Nofeedback() { ...@@ -1059,16 +1061,33 @@ void KeyedStoreGenericAssembler::StoreIC_Nofeedback() {
// Receivers requiring non-standard element accesses (interceptors, access // Receivers requiring non-standard element accesses (interceptors, access
// checks, strings and string wrappers, proxies) are handled in the runtime. // checks, strings and string wrappers, proxies) are handled in the runtime.
GotoIf(IsSpecialReceiverInstanceType(instance_type), &miss); GotoIf(IsSpecialReceiverInstanceType(instance_type), &miss);
// Optimistically write the state transition to the vector.
GotoIf(IsUndefined(vector), &store_property);
StoreFeedbackVectorSlot(vector, slot,
LoadRoot(RootIndex::kpremonomorphic_symbol),
SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
Goto(&store_property);
BIND(&store_property);
{ {
StoreICParameters p(CAST(context), receiver, name, value, slot, StoreICParameters p(CAST(context), receiver, name, value, slot, vector);
UndefinedConstant());
EmitGenericPropertyStore(receiver, receiver_map, &p, &miss); EmitGenericPropertyStore(receiver, receiver_map, &p, &miss);
} }
BIND(&miss); BIND(&miss);
{ {
TailCallRuntime(Runtime::kStoreIC_Miss, context, value, slot, Label call_runtime(this);
UndefinedConstant(), receiver, name); // Undo the optimistic state transition.
GotoIf(IsUndefined(vector), &call_runtime);
StoreFeedbackVectorSlot(vector, slot,
LoadRoot(RootIndex::kuninitialized_symbol),
SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
Goto(&call_runtime);
BIND(&call_runtime);
TailCallRuntime(Runtime::kStoreIC_Miss, context, value, slot, vector,
receiver, name);
} }
} }
......
...@@ -37,7 +37,7 @@ class KeyedStoreGenericGenerator { ...@@ -37,7 +37,7 @@ class KeyedStoreGenericGenerator {
TNode<Object> value); TNode<Object> value);
}; };
class StoreICNofeedbackGenerator { class StoreICUninitializedGenerator {
public: public:
static void Generate(compiler::CodeAssemblerState* state); static void Generate(compiler::CodeAssemblerState* state);
}; };
......
...@@ -438,7 +438,9 @@ TEST(VectorLoadICStates) { ...@@ -438,7 +438,9 @@ TEST(VectorLoadICStates) {
Handle<FeedbackVector>(f->feedback_vector(), isolate); Handle<FeedbackVector>(f->feedback_vector(), isolate);
FeedbackSlot slot(0); FeedbackSlot slot(0);
FeedbackNexus nexus(feedback_vector, slot); FeedbackNexus nexus(feedback_vector, slot);
CHECK_EQ(PREMONOMORPHIC, nexus.ic_state());
CompileRun("f(o)");
CHECK_EQ(MONOMORPHIC, nexus.ic_state()); CHECK_EQ(MONOMORPHIC, nexus.ic_state());
// Verify that the monomorphic map is the one we expect. // Verify that the monomorphic map is the one we expect.
v8::MaybeLocal<v8::Value> v8_o = v8::MaybeLocal<v8::Value> v8_o =
...@@ -524,13 +526,16 @@ TEST(VectorLoadICOnSmi) { ...@@ -524,13 +526,16 @@ TEST(VectorLoadICOnSmi) {
CompileRun( CompileRun(
"var o = { foo: 3 };" "var o = { foo: 3 };"
"%EnsureFeedbackVectorForFunction(f);" "%EnsureFeedbackVectorForFunction(f);"
"function f(a) { return a.foo; } f(34);"); "function f(a) { return a.foo; } f(o);");
Handle<JSFunction> f = GetFunction("f"); Handle<JSFunction> f = GetFunction("f");
// There should be one IC. // There should be one IC.
Handle<FeedbackVector> feedback_vector = Handle<FeedbackVector> feedback_vector =
Handle<FeedbackVector>(f->feedback_vector(), isolate); Handle<FeedbackVector>(f->feedback_vector(), isolate);
FeedbackSlot slot(0); FeedbackSlot slot(0);
FeedbackNexus nexus(feedback_vector, slot); FeedbackNexus nexus(feedback_vector, slot);
CHECK_EQ(PREMONOMORPHIC, nexus.ic_state());
CompileRun("f(34)");
CHECK_EQ(MONOMORPHIC, nexus.ic_state()); CHECK_EQ(MONOMORPHIC, nexus.ic_state());
// Verify that the monomorphic map is the one we expect. // Verify that the monomorphic map is the one we expect.
Map number_map = ReadOnlyRoots(heap).heap_number_map(); Map number_map = ReadOnlyRoots(heap).heap_number_map();
......
...@@ -8,14 +8,14 @@ ...@@ -8,14 +8,14 @@
// This is to test for dictionary mode when there more than // This is to test for dictionary mode when there more than
// kMaxNumberOfDescriptors (1024) properties. // kMaxNumberOfDescriptors (1024) properties.
const kLimit = 1030; const kLimit = 1030;
let evalString = "function f(i) { " + let evalString = "(function(i) { " +
"let clazz = class { " + "let clazz = class { " +
" constructor(i) { this.value = i;"; " constructor(i) { this.value = i;";
for (let i = 0; i < kLimit ; i++) { for (let i = 0; i < kLimit ; i++) {
evalString += "this.property"+i +" = "+i+"; " evalString += "this.property"+i +" = "+i+"; "
} }
evalString += "}};" + evalString += "}};" +
" return (new clazz(i)); }; f;"; " return (new clazz(i)); })";
let fn = eval(evalString); let fn = eval(evalString);
%PrepareFunctionForOptimization(fn); %PrepareFunctionForOptimization(fn);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment