Commit cd6705d1 authored by jameslahm's avatar jameslahm Committed by V8 LUCI CQ

[maglev] Support CopyDataPropertiesWithExcludedPropertiesOnStack

... intrinsic.

This CL also adds stack arguments support in CallBuiltin.

Bug: v8:7700
Change-Id: I59d900414585f724c48f1557ba606f5b61cfb6da
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3813073Reviewed-by: 's avatarVictor Gomes <victorgomes@chromium.org>
Commit-Queue: 王澳 <wangao.james@bytedance.com>
Cr-Commit-Position: refs/heads/main@{#82355}
parent 6d5f9030
......@@ -1894,7 +1894,20 @@ void MaglevGraphBuilder::VisitIntrinsicCopyDataProperties(
void MaglevGraphBuilder::
VisitIntrinsicCopyDataPropertiesWithExcludedPropertiesOnStack(
interpreter::RegisterList args) {
MAGLEV_UNIMPLEMENTED(CopyDataPropertiesWithExcludedPropertiesOnStack);
SmiConstant* excluded_property_count =
GetSmiConstant(args.register_count() - 1);
int kContext = 1;
int kExcludedPropertyCount = 1;
CallBuiltin* call_builtin = CreateNewNode<CallBuiltin>(
args.register_count() + kContext + kExcludedPropertyCount,
Builtin::kCopyDataPropertiesWithExcludedProperties, GetContext());
int arg_index = 0;
call_builtin->set_arg(arg_index++, GetTaggedValue(args[0]));
call_builtin->set_arg(arg_index++, excluded_property_count);
for (int i = 1; i < args.register_count(); i++) {
call_builtin->set_arg(arg_index++, GetTaggedValue(args[i]));
}
SetAccumulator(AddNode(call_builtin));
}
void MaglevGraphBuilder::VisitIntrinsicCreateIterResultObject(
......
......@@ -315,12 +315,14 @@ class MaglevGraphBuilder {
#ifdef DEBUG
// Check that the last parameters are kSlot and kVector.
using Descriptor = typename CallInterfaceDescriptorFor<kBuiltin>::type;
int slot_index = call_builtin->num_args(Descriptor::HasContextParameter());
int slot_index = call_builtin->InputCountWithoutContext();
int vector_index = slot_index + 1;
DCHECK_EQ(slot_index, Descriptor::kSlot);
// TODO(victorgomes): Rename all kFeedbackVector parameters in the builtins
// to kVector.
DCHECK_EQ(vector_index, Descriptor::kVector);
// Also check that the builtin does not allow var args.
DCHECK_EQ(Descriptor::kAllowVarArgs, false);
#endif // DEBUG
return call_builtin;
}
......
......@@ -276,9 +276,22 @@ class MaglevGraphVerifier {
ValueRepresentation::kTagged);
count--;
}
// Check rest of the inputs.
for (int i = 0; i < count; ++i) {
MachineType type = descriptor.GetParameterType(i);
// {all_input_count} includes the feedback slot and vector.
#ifdef DEBUG
int all_input_count = count + (call_builtin->has_feedback() ? 2 : 0);
if (descriptor.AllowVarArgs()) {
DCHECK_GE(all_input_count, descriptor.GetParameterCount());
} else {
DCHECK_EQ(all_input_count, descriptor.GetParameterCount());
}
#endif
int i = 0;
// Check the rest of inputs.
for (; i < count; ++i) {
MachineType type = i < descriptor.GetParameterCount()
? descriptor.GetParameterType(i)
: MachineType::AnyTagged();
CheckValueInputIs(call_builtin, i, ToValueRepresentation(type));
}
break;
......
......@@ -2727,38 +2727,104 @@ void Construct::GenerateCode(MaglevCodeGenState* code_gen_state,
}
void CallBuiltin::AllocateVreg(MaglevVregAllocationState* vreg_state) {
// TODO(v8:7700): Support stack arguments.
auto descriptor = Builtins::CallInterfaceDescriptorFor(builtin());
bool has_context = descriptor.HasContextParameter();
DCHECK_EQ(descriptor.GetRegisterParameterCount(),
num_args(has_context) + (has_feedback() ? 2 : 0));
int i = 0;
for (; i < num_args(has_context); i++) {
for (; i < InputsInRegisterCount(); i++) {
UseFixed(input(i), descriptor.GetRegisterParameter(i));
}
for (; i < InputCountWithoutContext(); i++) {
UseAny(input(i));
}
if (has_context) {
UseFixed(input(i), kContextRegister);
}
DCHECK_EQ(descriptor.GetReturnCount(), 1);
DefineAsFixed(vreg_state, this, kReturnRegister0);
}
void CallBuiltin::PassFeedbackSlotOnStack(MaglevCodeGenState* code_gen_state) {
DCHECK(has_feedback());
switch (slot_type()) {
case kTaggedIndex:
__ Push(TaggedIndex::FromIntptr(feedback().index()));
break;
case kSmi:
__ Push(Smi::FromInt(feedback().index()));
break;
}
}
void CallBuiltin::PassFeedbackSlotInRegister(
MaglevCodeGenState* code_gen_state) {
DCHECK(has_feedback());
auto descriptor = Builtins::CallInterfaceDescriptorFor(builtin());
int slot_index = InputCountWithoutContext();
switch (slot_type()) {
case kTaggedIndex:
__ Move(descriptor.GetRegisterParameter(slot_index),
TaggedIndex::FromIntptr(feedback().index()));
break;
case kSmi:
__ Move(descriptor.GetRegisterParameter(slot_index),
Smi::FromInt(feedback().index()));
break;
}
}
void CallBuiltin::PushFeedback(MaglevCodeGenState* code_gen_state) {
DCHECK(has_feedback());
auto descriptor = Builtins::CallInterfaceDescriptorFor(builtin());
int slot_index = InputCountWithoutContext();
int vector_index = slot_index + 1;
// There are three possibilities:
// 1. Feedback slot and vector are in register.
// 2. Feedback slot is in register and vector is on stack.
// 3. Feedback slot and vector are on stack.
if (vector_index < descriptor.GetRegisterParameterCount()) {
PassFeedbackSlotInRegister(code_gen_state);
__ Move(descriptor.GetRegisterParameter(vector_index), feedback().vector);
} else if (vector_index == descriptor.GetRegisterParameterCount()) {
PassFeedbackSlotInRegister(code_gen_state);
// We do not allow var args if has_feedback(), so here we have only one
// parameter on stack and do not need to check stack arguments order.
__ Push(feedback().vector);
} else {
// Same as above. We does not allow var args if has_feedback(), so feedback
// slot and vector must be last two inputs.
if (descriptor.GetStackArgumentOrder() == StackArgumentOrder::kDefault) {
PassFeedbackSlotOnStack(code_gen_state);
__ Push(feedback().vector);
} else {
DCHECK_EQ(descriptor.GetStackArgumentOrder(), StackArgumentOrder::kJS);
__ Push(feedback().vector);
PassFeedbackSlotOnStack(code_gen_state);
}
}
}
void CallBuiltin::GenerateCode(MaglevCodeGenState* code_gen_state,
const ProcessingState& state) {
if (has_feedback()) {
auto descriptor = Builtins::CallInterfaceDescriptorFor(builtin());
int slot_index = num_args(descriptor.HasContextParameter());
int vector_index = slot_index + 1;
switch (slot_type()) {
case kTaggedIndex:
__ Move(descriptor.GetRegisterParameter(slot_index),
TaggedIndex::FromIntptr(feedback().index()));
break;
case kSmi:
__ Move(descriptor.GetRegisterParameter(slot_index),
Smi::FromInt(feedback().index()));
break;
auto descriptor = Builtins::CallInterfaceDescriptorFor(builtin());
if (descriptor.GetStackArgumentOrder() == StackArgumentOrder::kDefault) {
for (int i = InputsInRegisterCount(); i < InputCountWithoutContext(); ++i) {
PushInput(code_gen_state, input(i));
}
if (has_feedback()) {
PushFeedback(code_gen_state);
}
} else {
DCHECK_EQ(descriptor.GetStackArgumentOrder(), StackArgumentOrder::kJS);
if (has_feedback()) {
PushFeedback(code_gen_state);
}
for (int i = InputCountWithoutContext() - 1; i >= InputsInRegisterCount();
--i) {
PushInput(code_gen_state, input(i));
}
__ Move(descriptor.GetRegisterParameter(vector_index), feedback().vector);
}
__ CallBuiltin(builtin());
code_gen_state->DefineLazyDeoptPoint(lazy_deopt_info());
......
......@@ -3070,13 +3070,34 @@ class CallBuiltin : public ValueNodeT<CallBuiltin> {
Builtin builtin() const { return builtin_; }
int num_args(bool has_context) const {
DCHECK_EQ(
has_context,
Builtins::CallInterfaceDescriptorFor(builtin_).HasContextParameter());
int InputCountWithoutContext() const {
auto descriptor = Builtins::CallInterfaceDescriptorFor(builtin_);
bool has_context = descriptor.HasContextParameter();
int extra_input_count = has_context ? 1 : 0;
return input_count() - extra_input_count;
}
int InputsInRegisterCount() const {
auto descriptor = Builtins::CallInterfaceDescriptorFor(builtin_);
if (has_feedback()) {
int slot_index = InputCountWithoutContext();
int vector_index = slot_index + 1;
// There are three possibilities:
// 1. Feedback slot and vector are in register.
// 2. Feedback slot is in register and vector is on stack.
// 3. Feedback slot and vector are on stack.
if (vector_index < descriptor.GetRegisterParameterCount()) {
return descriptor.GetRegisterParameterCount() - 2;
} else if (vector_index == descriptor.GetRegisterParameterCount()) {
return descriptor.GetRegisterParameterCount() - 1;
} else {
return descriptor.GetRegisterParameterCount();
}
}
return descriptor.GetRegisterParameterCount();
}
void set_arg(int i, ValueNode* node) { set_input(i, node); }
void AllocateVreg(MaglevVregAllocationState*);
......@@ -3084,6 +3105,10 @@ class CallBuiltin : public ValueNodeT<CallBuiltin> {
void PrintParams(std::ostream&, MaglevGraphLabeller*) const;
private:
void PassFeedbackSlotOnStack(MaglevCodeGenState*);
void PassFeedbackSlotInRegister(MaglevCodeGenState*);
void PushFeedback(MaglevCodeGenState*);
Builtin builtin_;
base::Optional<compiler::FeedbackSource> feedback_;
FeedbackSlotType slot_type_ = kTaggedIndex;
......
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --maglev --no-stress-opt --no-always-turbofan
function foo(x) {
const { a, b, ...rest } = {a:1, b:1, c:1, d:1};
return rest
}
%PrepareFunctionForOptimization(foo);
assertEquals({c:1, d:1}, foo());
assertEquals({c:1, d:1}, foo());
%OptimizeMaglevOnNextCall(foo);
assertEquals({c:1, d:1}, foo());
assertTrue(isMaglevved(foo));
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