Commit efc0c14d authored by Mythri A's avatar Mythri A Committed by Commit Bot

[ic] Adds a builtin to handle LdaGlobal when there is no feedback

With lazy feedback allocation we always miss to runtime for LdaGlobal till
the feedback vector is allocated. This cl adds and uses a new builtin to
handle some of the common cases in builtins instead of missing to runtime.

Bug: chromium:988402
Change-Id: I5fe0a157234007d8771501df9f2a5ea3a9116862
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1841354
Commit-Queue: Mythri Alle <mythria@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64671}
parent 9cba7a85
......@@ -218,10 +218,11 @@ namespace internal {
TFH(KeyedLoadIC_Slow, LoadWithVector) \
TFH(KeyedStoreIC_Megamorphic, Store) \
TFH(KeyedStoreIC_Slow, StoreWithVector) \
TFH(LoadGlobalIC_NoFeedback, LoadGlobalNoFeedback) \
TFH(LoadIC_FunctionPrototype, LoadWithVector) \
TFH(LoadIC_StringLength, LoadWithVector) \
TFH(LoadIC_StringWrapperLength, LoadWithVector) \
TFH(LoadIC_NoFeedback, Load) \
TFH(LoadIC_NoFeedback, LoadNoFeedback) \
TFH(StoreGlobalIC_Slow, StoreWithVector) \
TFH(StoreIC_NoFeedback, Store) \
TFH(StoreInArrayLiteralIC_Slow, StoreWithVector) \
......
......@@ -31,6 +31,7 @@ IC_BUILTIN(KeyedLoadIC_Megamorphic)
IC_BUILTIN(KeyedLoadIC_PolymorphicName)
IC_BUILTIN(KeyedLoadICTrampoline)
IC_BUILTIN(KeyedLoadICTrampoline_Megamorphic)
IC_BUILTIN(LoadGlobalIC_NoFeedback)
IC_BUILTIN(StoreGlobalIC)
IC_BUILTIN(StoreGlobalICTrampoline)
IC_BUILTIN(StoreIC)
......
......@@ -200,12 +200,24 @@ void LoadDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void LoadNoFeedbackDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {ReceiverRegister(), NameRegister(), ICKindRegister()};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void LoadGlobalDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {NameRegister(), SlotRegister()};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void LoadGlobalNoFeedbackDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {NameRegister(), ICKindRegister()};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void LoadGlobalWithVectorDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {NameRegister(), SlotRegister(), VectorRegister()};
......
......@@ -68,6 +68,8 @@ namespace internal {
V(JSTrampoline) \
V(Load) \
V(LoadGlobal) \
V(LoadGlobalNoFeedback) \
V(LoadNoFeedback) \
V(LoadGlobalWithVector) \
V(LoadWithVector) \
V(NewArgumentsElements) \
......@@ -595,6 +597,43 @@ class LoadDescriptor : public CallInterfaceDescriptor {
static const Register SlotRegister();
};
class LoadGlobalNoFeedbackDescriptor : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS(kName, kICKind)
DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(), // kName
MachineType::TaggedSigned()) // kICKind
DECLARE_DESCRIPTOR(LoadGlobalNoFeedbackDescriptor, CallInterfaceDescriptor)
static const Register NameRegister() {
return LoadDescriptor::NameRegister();
}
static const Register ICKindRegister() {
return LoadDescriptor::SlotRegister();
}
};
class LoadNoFeedbackDescriptor : public LoadGlobalNoFeedbackDescriptor {
public:
DEFINE_PARAMETERS(kReceiver, kName, kICKind)
DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(), // kReceiver
MachineType::AnyTagged(), // kName
MachineType::TaggedSigned()) // kICKind
DECLARE_DESCRIPTOR(LoadNoFeedbackDescriptor, LoadGlobalNoFeedbackDescriptor)
static const Register ReceiverRegister() {
return LoadDescriptor::ReceiverRegister();
}
static const Register NameRegister() {
return LoadGlobalNoFeedbackDescriptor::NameRegister();
}
static const Register ICKindRegister() {
return LoadGlobalNoFeedbackDescriptor::ICKindRegister();
}
};
class LoadGlobalDescriptor : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS(kName, kSlot)
......
......@@ -2640,11 +2640,11 @@ void AccessorAssembler::LoadIC_BytecodeHandler(const LazyLoadICParameters* p,
Label stub_call(this, Label::kDeferred), miss(this, Label::kDeferred),
no_feedback(this, Label::kDeferred);
GotoIf(IsUndefined(p->vector()), &no_feedback);
TNode<Map> recv_map = LoadReceiverMap(p->receiver());
GotoIf(IsDeprecatedMap(recv_map), &miss);
GotoIf(IsUndefined(p->vector()), &no_feedback);
// Inlined fast path.
{
Comment("LoadIC_BytecodeHandler_fast");
......@@ -2688,7 +2688,8 @@ void AccessorAssembler::LoadIC_BytecodeHandler(const LazyLoadICParameters* p,
// Call into the stub that implements the non-inlined parts of LoadIC.
exit_point->ReturnCallStub(
Builtins::CallableFor(isolate(), Builtins::kLoadIC_NoFeedback),
p->context(), p->receiver(), p->name(), p->slot());
p->context(), p->receiver(), p->name(),
SmiConstant(FeedbackSlotKind::kLoadProperty));
}
BIND(&miss);
......@@ -2768,11 +2769,14 @@ void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p,
}
}
void AccessorAssembler::LoadIC_NoFeedback(const LoadICParameters* p) {
void AccessorAssembler::LoadIC_NoFeedback(const LoadICParameters* p,
TNode<Smi> ic_kind) {
Label miss(this, Label::kDeferred);
Node* receiver = p->receiver();
GotoIf(TaggedIsSmi(receiver), &miss);
TNode<Map> receiver_map = LoadMap(receiver);
GotoIf(IsDeprecatedMap(receiver_map), &miss);
TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
{
......@@ -2794,8 +2798,8 @@ void AccessorAssembler::LoadIC_NoFeedback(const LoadICParameters* p) {
BIND(&miss);
{
TailCallRuntime(Runtime::kLoadIC_Miss, p->context(), p->receiver(),
p->name(), p->slot(), p->vector());
TailCallRuntime(Runtime::kLoadNoFeedbackIC_Miss, p->context(),
p->receiver(), p->name(), ic_kind);
}
}
......@@ -2806,8 +2810,10 @@ void AccessorAssembler::LoadGlobalIC(TNode<HeapObject> maybe_feedback_vector,
const LazyNode<Name>& lazy_name,
TypeofMode typeof_mode,
ExitPoint* exit_point) {
Label try_handler(this, Label::kDeferred), miss(this, Label::kDeferred);
GotoIf(IsUndefined(maybe_feedback_vector), &miss);
Label try_handler(this, Label::kDeferred), miss(this, Label::kDeferred),
no_feedback(this, Label::kDeferred);
GotoIf(IsUndefined(maybe_feedback_vector), &no_feedback);
{
TNode<FeedbackVector> vector = CAST(maybe_feedback_vector);
TNode<UintPtrT> slot = lazy_slot();
......@@ -2828,6 +2834,17 @@ void AccessorAssembler::LoadGlobalIC(TNode<HeapObject> maybe_feedback_vector,
lazy_smi_slot(), maybe_feedback_vector,
SmiConstant(typeof_mode));
}
BIND(&no_feedback);
{
int ic_kind =
static_cast<int>((typeof_mode == INSIDE_TYPEOF)
? FeedbackSlotKind::kLoadGlobalInsideTypeof
: FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
exit_point->ReturnCallStub(
Builtins::CallableFor(isolate(), Builtins::kLoadGlobalIC_NoFeedback),
lazy_context(), lazy_name(), SmiConstant(ic_kind));
}
}
void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase(
......@@ -2899,6 +2916,81 @@ void AccessorAssembler::LoadGlobalIC_TryHandlerCase(
on_nonexistent);
}
void AccessorAssembler::ScriptContextTableLookup(
TNode<Name> name, TNode<NativeContext> native_context, Label* found_hole,
Label* not_found) {
TNode<ScriptContextTable> script_context_table = CAST(
LoadContextElement(native_context, Context::SCRIPT_CONTEXT_TABLE_INDEX));
TVARIABLE(IntPtrT, context_index, IntPtrConstant(-1));
Label loop(this, &context_index);
TNode<IntPtrT> num_script_contexts = SmiUntag(CAST(LoadFixedArrayElement(
script_context_table, ScriptContextTable::kUsedSlotIndex)));
Goto(&loop);
BIND(&loop);
{
context_index = IntPtrAdd(context_index.value(), IntPtrConstant(1));
GotoIf(IntPtrGreaterThanOrEqual(context_index.value(), num_script_contexts),
not_found);
TNode<Context> script_context = CAST(LoadFixedArrayElement(
script_context_table, context_index.value(),
ScriptContextTable::kFirstContextSlotIndex * kTaggedSize));
TNode<ScopeInfo> scope_info =
CAST(LoadContextElement(script_context, Context::SCOPE_INFO_INDEX));
TNode<IntPtrT> length = LoadAndUntagFixedArrayBaseLength(scope_info);
GotoIf(IntPtrLessThanOrEqual(length, IntPtrConstant(0)), &loop);
TVARIABLE(IntPtrT, scope_var_index,
IntPtrConstant(ScopeInfo::kVariablePartIndex - 1));
TNode<IntPtrT> num_scope_vars = SmiUntag(CAST(LoadFixedArrayElement(
scope_info, IntPtrConstant(ScopeInfo::Fields::kContextLocalCount))));
TNode<IntPtrT> end_index = IntPtrAdd(
num_scope_vars, IntPtrConstant(ScopeInfo::kVariablePartIndex));
Label loop_scope_info(this, &scope_var_index);
Goto(&loop_scope_info);
BIND(&loop_scope_info);
{
scope_var_index = IntPtrAdd(scope_var_index.value(), IntPtrConstant(1));
GotoIf(IntPtrGreaterThanOrEqual(scope_var_index.value(), end_index),
&loop);
TNode<Object> var_name =
LoadFixedArrayElement(scope_info, scope_var_index.value(), 0);
GotoIf(TaggedNotEqual(var_name, name), &loop_scope_info);
TNode<IntPtrT> var_index =
IntPtrAdd(IntPtrConstant(Context::MIN_CONTEXT_SLOTS),
IntPtrSub(scope_var_index.value(),
IntPtrConstant(ScopeInfo::kVariablePartIndex)));
TNode<Object> result = LoadContextElement(script_context, var_index);
GotoIf(IsTheHole(result), found_hole);
Return(result);
}
}
}
void AccessorAssembler::LoadGlobalIC_NoFeedback(TNode<Context> context,
TNode<Object> name,
TNode<Smi> smi_typeof_mode) {
TNode<NativeContext> native_context = LoadNativeContext(context);
Label regular_load(this), throw_reference_error(this, Label::kDeferred);
GotoIfNot(IsString(CAST(name)), &regular_load);
ScriptContextTableLookup(CAST(name), native_context, &throw_reference_error,
&regular_load);
BIND(&throw_reference_error);
Return(CallRuntime(Runtime::kThrowReferenceError, context, name));
BIND(&regular_load);
TNode<JSGlobalObject> global_object =
CAST(LoadContextElement(native_context, Context::EXTENSION_INDEX));
TailCallStub(Builtins::CallableFor(isolate(), Builtins::kLoadIC_NoFeedback),
context, global_object, name, smi_typeof_mode);
}
void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p,
LoadAccessMode access_mode) {
ExitPoint direct_exit(this);
......@@ -3585,15 +3677,18 @@ void AccessorAssembler::GenerateLoadIC_Noninlined() {
}
void AccessorAssembler::GenerateLoadIC_NoFeedback() {
using Descriptor = LoadDescriptor;
using Descriptor = LoadNoFeedbackDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
TNode<Object> name = CAST(Parameter(Descriptor::kName));
TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<Smi> ic_kind = CAST(Parameter(Descriptor::kICKind));
LoadICParameters p(context, receiver, name, slot, UndefinedConstant());
LoadIC_NoFeedback(&p);
LoadICParameters p(
context, receiver, name,
SmiConstant(static_cast<int>(FeedbackSlot::Invalid().ToInt())),
UndefinedConstant());
LoadIC_NoFeedback(&p, ic_kind);
}
void AccessorAssembler::GenerateLoadICTrampoline() {
......@@ -3621,6 +3716,16 @@ void AccessorAssembler::GenerateLoadICTrampoline_Megamorphic() {
vector);
}
void AccessorAssembler::GenerateLoadGlobalIC_NoFeedback() {
using Descriptor = LoadGlobalNoFeedbackDescriptor;
TNode<Object> name = CAST(Parameter(Descriptor::kName));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<Smi> ic_kind = CAST(Parameter(Descriptor::kICKind));
LoadGlobalIC_NoFeedback(context, name, ic_kind);
}
void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
using Descriptor = LoadGlobalWithVectorDescriptor;
......
......@@ -28,6 +28,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
void GenerateLoadIC_Megamorphic();
void GenerateLoadIC_Noninlined();
void GenerateLoadIC_NoFeedback();
void GenerateLoadGlobalIC_NoFeedback();
void GenerateLoadICTrampoline();
void GenerateLoadICTrampoline_Megamorphic();
void GenerateKeyedLoadIC();
......@@ -214,7 +215,9 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
TNode<MaybeObject> LoadDescriptorValueOrFieldType(
TNode<Map> map, TNode<IntPtrT> descriptor_entry);
void LoadIC_NoFeedback(const LoadICParameters* p);
void LoadIC_NoFeedback(const LoadICParameters* p, TNode<Smi> smi_typeof_mode);
void LoadGlobalIC_NoFeedback(TNode<Context> context, TNode<Object> name,
TNode<Smi> smi_typeof_mode);
void KeyedLoadIC(const LoadICParameters* p, LoadAccessMode access_mode);
void KeyedLoadICGeneric(const LoadICParameters* p);
......@@ -307,6 +310,11 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
TypeofMode typeof_mode,
ExitPoint* exit_point, Label* miss);
// This is a copy of ScriptContextTable::Lookup. They should be kept in sync.
void ScriptContextTableLookup(TNode<Name> name,
TNode<NativeContext> native_context,
Label* found_hole, Label* not_found);
// StoreIC implementation.
void HandleStoreICProtoHandler(const StoreICParameters* p,
......
......@@ -2164,24 +2164,13 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
Handle<Object> receiver = args.at(0);
Handle<Name> key = args.at<Name>(1);
Handle<Smi> slot = args.at<Smi>(2);
Handle<HeapObject> maybe_vector = args.at<HeapObject>(3);
Handle<FeedbackVector> vector = args.at<FeedbackVector>(3);
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
Handle<FeedbackVector> vector = Handle<FeedbackVector>();
if (!maybe_vector->IsUndefined()) {
DCHECK(maybe_vector->IsFeedbackVector());
vector = Handle<FeedbackVector>::cast(maybe_vector);
}
// 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.
// The only case where we call without a vector is from the LoadNamedProperty
// bytecode handler. Also, when there is no feedback vector, there is no
// difference between LoadProperty or LoadKeyed kind.
FeedbackSlotKind kind = FeedbackSlotKind::kLoadProperty;
if (!vector.is_null()) {
kind = vector->GetKind(vector_slot);
}
FeedbackSlotKind kind = vector->GetKind(vector_slot);
if (IsLoadICKind(kind)) {
LoadIC ic(isolate, vector, vector_slot, kind);
ic.UpdateState(receiver, key);
......@@ -2202,6 +2191,24 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
}
}
RUNTIME_FUNCTION(Runtime_LoadNoFeedbackIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> receiver = args.at(0);
Handle<Name> key = args.at<Name>(1);
CONVERT_INT32_ARG_CHECKED(slot_kind, 2);
FeedbackSlotKind kind = static_cast<FeedbackSlotKind>(slot_kind);
Handle<FeedbackVector> vector = Handle<FeedbackVector>();
FeedbackSlot vector_slot = FeedbackSlot::Invalid();
// This function is only called after looking up in the ScriptContextTable so
// it is safe to call LoadIC::Load for global loads as well.
LoadIC ic(isolate, vector, vector_slot, kind);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
}
RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(4, args.length());
......
......@@ -578,6 +578,7 @@ namespace internal {
F(LoadGlobalIC_Miss, 4, 1) \
F(LoadGlobalIC_Slow, 3, 1) \
F(LoadIC_Miss, 4, 1) \
F(LoadNoFeedbackIC_Miss, 4, 1) \
F(LoadPropertyWithInterceptor, 5, 1) \
F(StoreCallbackProperty, 5, 1) \
F(StoreGlobalIC_Miss, 4, 1) \
......
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