Commit 91491b1a authored by Victor Gomes's avatar Victor Gomes Committed by Commit Bot

[compiler] Port NewArgumentsElements to Torque

Rest arguments were using the builtin NewArgumentsElements to create its backing store. This does work when the rest elements are a suffix of the arguments in the stack, but this is not the case when V8_REVERSE_JSARGS is enabled.

This CL ports the builtin to Torque and fix the previous issues with V8_REVERSE_JSARGS.

Change-Id: I82db0dfd409d909336f34312f62c379ca5929e1e
Bug: v8:10201
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2284988Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68888}
parent 93b493bc
......@@ -189,7 +189,6 @@ namespace internal {
TFS(CopyFastSmiOrObjectElements, kObject) \
TFC(GrowFastDoubleElements, GrowArrayElements) \
TFC(GrowFastSmiOrObjectElements, GrowArrayElements) \
TFC(NewArgumentsElements, NewArgumentsElements) \
\
/* Debugger */ \
TFJ(DebugBreakTrampoline, kDontAdaptArgumentsSentinel) \
......
......@@ -71,99 +71,6 @@ TF_BUILTIN(GrowFastSmiOrObjectElements, CodeStubAssembler) {
key);
}
TF_BUILTIN(NewArgumentsElements, CodeStubAssembler) {
TNode<RawPtrT> frame = UncheckedCast<RawPtrT>(Parameter(Descriptor::kFrame));
TNode<IntPtrT> length = SmiToIntPtr(Parameter(Descriptor::kLength));
TNode<IntPtrT> mapped_count =
SmiToIntPtr(Parameter(Descriptor::kMappedCount));
// Check if we can allocate in new space.
ElementsKind kind = PACKED_ELEMENTS;
int max_elements = FixedArray::GetMaxLengthForNewSpaceAllocation(kind);
Label if_newspace(this), if_oldspace(this, Label::kDeferred);
Branch(IntPtrLessThan(length, IntPtrConstant(max_elements)), &if_newspace,
&if_oldspace);
BIND(&if_newspace);
{
// Prefer EmptyFixedArray in case of non-positive {length} (the {length}
// can be negative here for rest parameters).
Label if_empty(this), if_notempty(this);
Branch(IntPtrLessThanOrEqual(length, IntPtrConstant(0)), &if_empty,
&if_notempty);
BIND(&if_empty);
Return(EmptyFixedArrayConstant());
BIND(&if_notempty);
{
// Allocate a FixedArray in new space.
TNode<FixedArray> result = CAST(AllocateFixedArray(kind, length));
// The elements might be used to back mapped arguments. In that case fill
// the mapped elements (i.e. the first {mapped_count}) with the hole, but
// make sure not to overshoot the {length} if some arguments are missing.
TNode<IntPtrT> number_of_holes = IntPtrMin(mapped_count, length);
TNode<Oddball> the_hole = TheHoleConstant();
// Fill the first elements up to {number_of_holes} with the hole.
TVARIABLE(IntPtrT, var_index, IntPtrConstant(0));
Label loop1(this, &var_index), done_loop1(this);
Goto(&loop1);
BIND(&loop1);
{
// Load the current {index}.
TNode<IntPtrT> index = var_index.value();
// Check if we are done.
GotoIf(IntPtrEqual(index, number_of_holes), &done_loop1);
// Store the hole into the {result}.
StoreFixedArrayElement(result, index, the_hole, SKIP_WRITE_BARRIER);
// Continue with next {index}.
var_index = IntPtrAdd(index, IntPtrConstant(1));
Goto(&loop1);
}
BIND(&done_loop1);
// Copy the parameters from {frame} (starting at {offset}) to {result}.
CodeStubArguments args(this, length, frame);
Label loop2(this, &var_index), done_loop2(this);
Goto(&loop2);
BIND(&loop2);
{
// Load the current {index}.
TNode<IntPtrT> index = var_index.value();
// Check if we are done.
GotoIf(IntPtrEqual(index, length), &done_loop2);
// Load the parameter at the given {index}.
TNode<Object> value = args.AtIndex(index);
// Store the {value} into the {result}.
StoreFixedArrayElement(result, index, value, SKIP_WRITE_BARRIER);
// Continue with next {index}.
var_index = IntPtrAdd(index, IntPtrConstant(1));
Goto(&loop2);
}
BIND(&done_loop2);
Return(result);
}
}
BIND(&if_oldspace);
{
// Allocate in old space (or large object space).
TailCallRuntime(Runtime::kNewArgumentsElements, NoContextConstant(),
BitcastWordToTagged(frame), SmiFromIntPtr(length),
SmiFromIntPtr(mapped_count));
}
}
TF_BUILTIN(ReturnReceiver, CodeStubAssembler) {
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
Return(receiver);
......
......@@ -348,11 +348,6 @@ void GrowArrayElementsDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void NewArgumentsElementsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
DefaultInitializePlatformSpecific(data, kParameterCount);
}
void ArrayNoArgumentConstructorDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// This descriptor must use the same set of registers as the
......
......@@ -79,7 +79,6 @@ namespace internal {
V(LoadGlobalWithVector) \
V(LoadNoFeedback) \
V(LoadWithVector) \
V(NewArgumentsElements) \
V(NoContext) \
V(RecordWrite) \
V(ResumeGenerator) \
......@@ -1282,15 +1281,6 @@ class GrowArrayElementsDescriptor : public CallInterfaceDescriptor {
static const Register KeyRegister();
};
class NewArgumentsElementsDescriptor final : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS(kFrame, kLength, kMappedCount)
DEFINE_PARAMETER_TYPES(MachineType::Pointer(), // kFrame
MachineType::TaggedSigned(), // kLength
MachineType::TaggedSigned()) // kMappedCount
DECLARE_DESCRIPTOR(NewArgumentsElementsDescriptor, CallInterfaceDescriptor)
};
class V8_EXPORT_PRIVATE InterpreterDispatchDescriptor
: public CallInterfaceDescriptor {
public:
......
......@@ -3653,19 +3653,32 @@ Node* EffectControlLinearizer::LowerNewSmiOrObjectElements(Node* node) {
}
Node* EffectControlLinearizer::LowerNewArgumentsElements(Node* node) {
Node* frame = NodeProperties::GetValueInput(node, 0);
Node* length = NodeProperties::GetValueInput(node, 1);
int mapped_count = NewArgumentsElementsMappedCountOf(node->op());
Callable const callable =
Builtins::CallableFor(isolate(), Builtins::kNewArgumentsElements);
const NewArgumentsElementsParameters& parameters =
NewArgumentsElementsParametersOf(node->op());
CreateArgumentsType type = parameters.arguments_type();
Operator::Properties const properties = node->op()->properties();
CallDescriptor::Flags const flags = CallDescriptor::kNoFlags;
Node* frame = NodeProperties::GetValueInput(node, 0);
Node* arguments_count = NodeProperties::GetValueInput(node, 1);
Builtins::Name builtin_name;
switch (type) {
case CreateArgumentsType::kMappedArguments:
builtin_name = Builtins::kNewSloppyArgumentsElements;
break;
case CreateArgumentsType::kUnmappedArguments:
builtin_name = Builtins::kNewStrictArgumentsElements;
break;
case CreateArgumentsType::kRestParameter:
builtin_name = Builtins::kNewRestArgumentsElements;
break;
}
Callable const callable = Builtins::CallableFor(isolate(), builtin_name);
auto call_descriptor = Linkage::GetStubCallDescriptor(
graph()->zone(), callable.descriptor(),
callable.descriptor().GetStackParameterCount(), flags, properties);
return __ Call(call_descriptor, __ HeapConstant(callable.code()), frame,
length, __ SmiConstant(mapped_count), __ NoContextConstant());
__ IntPtrConstant(parameters.formal_parameter_count()),
arguments_count);
}
Node* EffectControlLinearizer::LowerNewConsString(Node* node) {
......
......@@ -229,7 +229,10 @@ void EscapeAnalysisReducer::VerifyReplacement() const {
void EscapeAnalysisReducer::Finalize() {
for (Node* node : arguments_elements_) {
int mapped_count = NewArgumentsElementsMappedCountOf(node->op());
const NewArgumentsElementsParameters& params =
NewArgumentsElementsParametersOf(node->op());
ArgumentsStateType type = params.arguments_type();
int mapped_count = params.formal_parameter_count();
Node* arguments_frame = NodeProperties::GetValueInput(node, 0);
if (arguments_frame->opcode() != IrOpcode::kArgumentsFrame) continue;
......@@ -243,11 +246,6 @@ void EscapeAnalysisReducer::Finalize() {
DCHECK_IMPLIES(
mapped_count != 0,
mapped_count == FormalParameterCountOf(arguments_length->op()));
ArgumentsStateType type = IsRestLengthOf(arguments_length->op())
? ArgumentsStateType::kRestParameter
: (mapped_count == 0)
? ArgumentsStateType::kUnmappedArguments
: ArgumentsStateType::kMappedArguments;
Node* arguments_length_state = nullptr;
for (Edge edge : arguments_length->use_edges()) {
......@@ -317,11 +315,21 @@ void EscapeAnalysisReducer::Finalize() {
switch (load->opcode()) {
case IrOpcode::kLoadElement: {
Node* index = NodeProperties::GetValueInput(load, 1);
#ifdef V8_REVERSE_JSARGS
Node* offset_to_first_elem = jsgraph()->Constant(
CommonFrameConstants::kFixedSlotCountAboveFp);
NodeProperties::SetType(offset_to_first_elem,
TypeCache::Get()->kArgumentsLengthType);
Node* offset = jsgraph()->graph()->NewNode(
jsgraph()->simplified()->NumberAdd(), index,
offset_to_first_elem);
#else
// {offset} is a reverted index starting from 1. The base address is
// adapted to allow offsets starting from 1.
Node* offset = jsgraph()->graph()->NewNode(
jsgraph()->simplified()->NumberSubtract(), arguments_length,
index);
#endif
NodeProperties::SetType(offset,
TypeCache::Get()->kArgumentsLengthType);
NodeProperties::ReplaceValueInput(load, arguments_frame, 0);
......
......@@ -207,7 +207,9 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
arguments_frame);
// Allocate the elements backing store.
Node* const elements = effect =
graph()->NewNode(simplified()->NewArgumentsElements(0),
graph()->NewNode(simplified()->NewArgumentsElements(
CreateArgumentsType::kUnmappedArguments,
shared.internal_formal_parameter_count()),
arguments_frame, arguments_length, effect);
// Load the arguments object map.
Node* const arguments_map =
......@@ -229,16 +231,20 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* const arguments_frame =
graph()->NewNode(simplified()->ArgumentsFrame());
Node* const length = graph()->NewNode(
simplified()->ArgumentsLength(
shared.internal_formal_parameter_count(), false),
arguments_frame);
Node* const rest_length = graph()->NewNode(
simplified()->ArgumentsLength(
shared.internal_formal_parameter_count(), true),
arguments_frame);
// Allocate the elements backing store. Since NewArgumentsElements
// copies from the end of the arguments adapter frame, this is a suffix
// of the actual arguments.
// Allocate the elements backing store.
Node* const elements = effect =
graph()->NewNode(simplified()->NewArgumentsElements(0),
arguments_frame, rest_length, effect);
graph()->NewNode(simplified()->NewArgumentsElements(
CreateArgumentsType::kRestParameter,
shared.internal_formal_parameter_count()),
arguments_frame, length, effect);
// Load the JSArray object map.
Node* const jsarray_map = jsgraph()->Constant(
native_context().js_array_packed_elements_map());
......@@ -1538,8 +1544,10 @@ Node* JSCreateLowering::AllocateAliasedArguments(
// special in any way, we can just return an unmapped backing store.
int parameter_count = shared.internal_formal_parameter_count();
if (parameter_count == 0) {
return graph()->NewNode(simplified()->NewArgumentsElements(0),
arguments_frame, arguments_length, effect);
return graph()->NewNode(
simplified()->NewArgumentsElements(
CreateArgumentsType::kUnmappedArguments, parameter_count),
arguments_frame, arguments_length, effect);
}
// From here on we are going to allocate a mapped (aka. aliased) elements
......@@ -1553,7 +1561,8 @@ Node* JSCreateLowering::AllocateAliasedArguments(
// then linked into the parameter map below, whereas mapped argument values
// (i.e. the first {mapped_count} elements) are replaced with a hole instead.
Node* arguments = effect =
graph()->NewNode(simplified()->NewArgumentsElements(mapped_count),
graph()->NewNode(simplified()->NewArgumentsElements(
CreateArgumentsType::kMappedArguments, mapped_count),
arguments_frame, arguments_length, effect);
// Actually allocate the backing store.
......
......@@ -1742,18 +1742,37 @@ const Operator* SimplifiedOperatorBuilder::NewSmiOrObjectElements(
}
const Operator* SimplifiedOperatorBuilder::NewArgumentsElements(
int mapped_count) {
return zone()->New<Operator1<int>>( // --
IrOpcode::kNewArgumentsElements, // opcode
Operator::kEliminatable, // flags
"NewArgumentsElements", // name
2, 1, 0, 1, 1, 0, // counts
mapped_count); // parameter
CreateArgumentsType type, int formal_parameter_count) {
return new (zone()) Operator1<NewArgumentsElementsParameters>( // --
IrOpcode::kNewArgumentsElements, // opcode
Operator::kEliminatable, // flags
"NewArgumentsElements", // name
2, 1, 0, 1, 1, 0, // counts
NewArgumentsElementsParameters(type,
formal_parameter_count)); // parameter
}
int NewArgumentsElementsMappedCountOf(const Operator* op) {
bool operator==(const NewArgumentsElementsParameters& lhs,
const NewArgumentsElementsParameters& rhs) {
return lhs.arguments_type() == rhs.arguments_type() &&
lhs.formal_parameter_count() == rhs.formal_parameter_count();
}
inline size_t hash_value(const NewArgumentsElementsParameters& params) {
return base::hash_combine(params.arguments_type(),
params.formal_parameter_count());
}
std::ostream& operator<<(std::ostream& os,
const NewArgumentsElementsParameters& params) {
return os << params.arguments_type()
<< ", parameter_count = " << params.formal_parameter_count();
}
const NewArgumentsElementsParameters& NewArgumentsElementsParametersOf(
const Operator* op) {
DCHECK_EQ(IrOpcode::kNewArgumentsElements, op->opcode());
return OpParameter<int>(op);
return OpParameter<NewArgumentsElementsParameters>(op);
}
const Operator* SimplifiedOperatorBuilder::Allocate(Type type,
......
......@@ -595,7 +595,29 @@ AbortReason AbortReasonOf(const Operator* op) V8_WARN_UNUSED_RESULT;
DeoptimizeReason DeoptimizeReasonOf(const Operator* op) V8_WARN_UNUSED_RESULT;
int NewArgumentsElementsMappedCountOf(const Operator* op) V8_WARN_UNUSED_RESULT;
class NewArgumentsElementsParameters {
public:
NewArgumentsElementsParameters(CreateArgumentsType type,
int formal_parameter_count)
: type_(type), formal_parameter_count_(formal_parameter_count) {}
CreateArgumentsType arguments_type() const { return type_; }
int formal_parameter_count() const { return formal_parameter_count_; }
private:
CreateArgumentsType type_;
int formal_parameter_count_;
};
bool operator==(const NewArgumentsElementsParameters&,
const NewArgumentsElementsParameters&);
inline size_t hash_value(const NewArgumentsElementsParameters&);
std::ostream& operator<<(std::ostream&, const NewArgumentsElementsParameters&);
const NewArgumentsElementsParameters& NewArgumentsElementsParametersOf(
const Operator*) V8_WARN_UNUSED_RESULT;
class FastApiCallParameters {
public:
......@@ -891,8 +913,9 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* NewDoubleElements(AllocationType);
const Operator* NewSmiOrObjectElements(AllocationType);
// new-arguments-elements arguments-frame, arguments-length
const Operator* NewArgumentsElements(int mapped_count);
// new-arguments-elements frame, arguments count
const Operator* NewArgumentsElements(CreateArgumentsType type,
int formal_parameter_count);
// new-cons-string length, first, second
const Operator* NewConsString();
......
......@@ -200,42 +200,64 @@ macro NewAllArguments(implicit context: Context)(
return NewJSArray(map, elements);
}
macro NewRestArgumentsElements(
frame: FrameWithArguments, formalParameterCount: intptr,
argumentCount: intptr): FixedArray {
const length = (formalParameterCount >= argumentCount) ?
0 :
argumentCount - formalParameterCount;
const arguments = GetFrameArguments(frame, argumentCount);
const it = ArgumentsIterator{arguments, current: formalParameterCount};
return NewFixedArray(length, it);
}
macro NewRestArguments(implicit context: Context)(info: FrameWithArgumentsInfo):
JSArray {
const argumentCount = Convert<intptr>(info.argument_count);
const formalParameterCount = Convert<intptr>(info.formal_parameter_count);
const map = GetFastPackedElementsJSArrayMap();
const length = (formalParameterCount >= argumentCount) ?
0 :
argumentCount - formalParameterCount;
const arguments = GetFrameArguments(info.frame, argumentCount);
const it = ArgumentsIterator{arguments, current: formalParameterCount};
const elements = NewFixedArray(length, it);
const elements =
NewRestArgumentsElements(info.frame, formalParameterCount, argumentCount);
return NewJSArray(map, elements);
}
macro NewStrictArgumentsElements(
frame: FrameWithArguments, argumentCount: intptr): FixedArray {
const arguments = GetFrameArguments(frame, argumentCount);
const it = ArgumentsIterator{arguments, current: 0};
return NewFixedArray(argumentCount, it);
}
macro NewStrictArguments(implicit context: Context)(
info: FrameWithArgumentsInfo): JSStrictArgumentsObject {
const argumentCount = Convert<intptr>(info.argument_count);
const arguments = GetFrameArguments(info.frame, argumentCount);
const it = ArgumentsIterator{arguments, current: 0};
const elements = NewFixedArray(argumentCount, it);
const elements = NewStrictArgumentsElements(info.frame, argumentCount);
return NewJSStrictArgumentsObject(elements);
}
macro NewSloppyArgumentsElements(
frame: FrameWithArguments, formalParameterCount: intptr,
argumentCount: intptr): FixedArray {
const arguments = GetFrameArguments(frame, argumentCount);
if (formalParameterCount == 0) {
const it = ArgumentsIterator{arguments, current: 0};
return NewFixedArray(argumentCount, it);
}
const mappedCount = IntPtrMin(formalParameterCount, argumentCount);
const it = NewParameterValueIterator(mappedCount, arguments);
return NewFixedArray(argumentCount, it);
}
macro NewSloppyArguments(implicit context: Context)(
info: FrameWithArgumentsInfo, callee: JSFunction): JSSloppyArgumentsObject {
const argumentCount = Convert<intptr>(info.argument_count);
const arguments = GetFrameArguments(info.frame, argumentCount);
const formalParameterCount = Convert<intptr>(info.formal_parameter_count);
const parameterValues = arguments::NewSloppyArgumentsElements(
info.frame, formalParameterCount, argumentCount);
if (formalParameterCount == 0) {
const it = ArgumentsIterator{arguments, current: 0};
const elements = NewFixedArray(argumentCount, it);
return NewJSSloppyArgumentsObject(elements, callee);
return NewJSSloppyArgumentsObject(parameterValues, callee);
}
const mappedCount = IntPtrMin(formalParameterCount, argumentCount);
const it = NewParameterValueIterator(mappedCount, arguments);
const parameterValues = NewFixedArray(argumentCount, it);
let paramIter =
NewParameterMapIterator(context, formalParameterCount, mappedCount);
const elementsLength = Convert<Smi>(mappedCount);
......@@ -273,3 +295,24 @@ macro EmitFastNewSloppyArguments(implicit context: Context)(f: JSFunction):
const info = GetFrameWithArgumentsInfo();
return arguments::NewSloppyArguments(info, f);
}
builtin NewSloppyArgumentsElements(
frame: FrameWithArguments, formalParameterCount: intptr,
argumentCount: Smi): FixedArray {
return arguments::NewSloppyArgumentsElements(
frame, formalParameterCount, Convert<intptr>(argumentCount));
}
builtin NewStrictArgumentsElements(
frame: FrameWithArguments, _formalParameterCount: intptr,
argumentCount: Smi): FixedArray {
return arguments::NewStrictArgumentsElements(
frame, Convert<intptr>(argumentCount));
}
builtin NewRestArgumentsElements(
frame: FrameWithArguments, formalParameterCount: intptr,
argumentCount: Smi): FixedArray {
return arguments::NewRestArgumentsElements(
frame, formalParameterCount, Convert<intptr>(argumentCount));
}
......@@ -552,30 +552,6 @@ RUNTIME_FUNCTION(Runtime_NewRestParameter) {
return *result;
}
RUNTIME_FUNCTION(Runtime_NewArgumentsElements) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
// Note that args[0] is the address of an array of full object pointers
// (a.k.a. FullObjectSlot), which looks like a Smi because it's aligned.
DCHECK(args[0].IsSmi());
FullObjectSlot frame(args[0].ptr());
CONVERT_SMI_ARG_CHECKED(length, 1);
CONVERT_SMI_ARG_CHECKED(mapped_count, 2);
Handle<FixedArray> result =
isolate->factory()->NewUninitializedFixedArray(length);
int const offset = length + 1;
DisallowHeapAllocation no_gc;
WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
int number_of_holes = Min(mapped_count, length);
for (int index = 0; index < number_of_holes; ++index) {
result->set_the_hole(isolate, index);
}
for (int index = number_of_holes; index < length; ++index) {
result->set(index, *(frame + (offset - index)), mode);
}
return *result;
}
RUNTIME_FUNCTION(Runtime_NewClosure) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
......
......@@ -399,7 +399,6 @@ namespace internal {
F(DeleteLookupSlot, 1, 1) \
F(LoadLookupSlot, 1, 1) \
F(LoadLookupSlotInsideTypeof, 1, 1) \
F(NewArgumentsElements, 3, 1) \
\
F(NewClosure, 2, 1) \
F(NewClosure_Tenured, 2, 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