[turbofan] Add escape analysis support for mapped arguments.
This adds support for the backing store of mapped arguments objects to escape analysis. It also unifies two simplified operators representing allocations of these backing stores into a single {NewArgumentsElements} operator and threads through the "mapped count" to the deoptimizer. R=tebbi@chromium.org Change-Id: I1864e29a5703348597b7b2e41deaf5fab73e2c93 Reviewed-on: https://chromium-review.googlesource.com/643208 Commit-Queue: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> Cr-Commit-Position: refs/heads/master@{#47800}
This commit is contained in:
parent
6377519f2e
commit
f3c87e63a8
@ -730,11 +730,11 @@ void CodeGenerator::TranslateStateValueDescriptor(
|
|||||||
}
|
}
|
||||||
} else if (desc->IsArgumentsElements()) {
|
} else if (desc->IsArgumentsElements()) {
|
||||||
if (translation != nullptr) {
|
if (translation != nullptr) {
|
||||||
translation->ArgumentsElements(desc->is_rest());
|
translation->ArgumentsElements(desc->arguments_type());
|
||||||
}
|
}
|
||||||
} else if (desc->IsArgumentsLength()) {
|
} else if (desc->IsArgumentsLength()) {
|
||||||
if (translation != nullptr) {
|
if (translation != nullptr) {
|
||||||
translation->ArgumentsLength(desc->is_rest());
|
translation->ArgumentsLength(desc->arguments_type());
|
||||||
}
|
}
|
||||||
} else if (desc->IsDuplicate()) {
|
} else if (desc->IsDuplicate()) {
|
||||||
if (translation != nullptr) {
|
if (translation != nullptr) {
|
||||||
|
@ -1235,24 +1235,28 @@ const Operator* CommonOperatorBuilder::TypedStateValues(
|
|||||||
TypedStateValueInfo(types, bitmask)); // parameters
|
TypedStateValueInfo(types, bitmask)); // parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
const Operator* CommonOperatorBuilder::ArgumentsElementsState(bool is_rest) {
|
const Operator* CommonOperatorBuilder::ArgumentsElementsState(
|
||||||
return new (zone()) Operator1<bool>( // --
|
ArgumentsStateType type) {
|
||||||
|
return new (zone()) Operator1<ArgumentsStateType>( // --
|
||||||
IrOpcode::kArgumentsElementsState, Operator::kPure, // opcode
|
IrOpcode::kArgumentsElementsState, Operator::kPure, // opcode
|
||||||
"ArgumentsElementsState", // name
|
"ArgumentsElementsState", // name
|
||||||
0, 0, 0, 1, 0, 0, is_rest); // counts
|
0, 0, 0, 1, 0, 0, // counts
|
||||||
|
type); // parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
const Operator* CommonOperatorBuilder::ArgumentsLengthState(bool is_rest) {
|
const Operator* CommonOperatorBuilder::ArgumentsLengthState(
|
||||||
return new (zone()) Operator1<bool>( // --
|
ArgumentsStateType type) {
|
||||||
|
return new (zone()) Operator1<ArgumentsStateType>( // --
|
||||||
IrOpcode::kArgumentsLengthState, Operator::kPure, // opcode
|
IrOpcode::kArgumentsLengthState, Operator::kPure, // opcode
|
||||||
"ArgumentsLengthState", // name
|
"ArgumentsLengthState", // name
|
||||||
0, 0, 0, 1, 0, 0, is_rest); // counts
|
0, 0, 0, 1, 0, 0, // counts
|
||||||
|
type); // parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsRestOf(Operator const* op) {
|
ArgumentsStateType ArgumentsStateTypeOf(Operator const* op) {
|
||||||
DCHECK(op->opcode() == IrOpcode::kArgumentsElementsState ||
|
DCHECK(op->opcode() == IrOpcode::kArgumentsElementsState ||
|
||||||
op->opcode() == IrOpcode::kArgumentsLengthState);
|
op->opcode() == IrOpcode::kArgumentsLengthState);
|
||||||
return OpParameter<bool>(op);
|
return OpParameter<ArgumentsStateType>(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Operator* CommonOperatorBuilder::ObjectState(int object_id,
|
const Operator* CommonOperatorBuilder::ObjectState(int object_id,
|
||||||
|
@ -311,10 +311,28 @@ SparseInputMask SparseInputMaskOf(Operator const*);
|
|||||||
ZoneVector<MachineType> const* MachineTypesOf(Operator const*)
|
ZoneVector<MachineType> const* MachineTypesOf(Operator const*)
|
||||||
WARN_UNUSED_RESULT;
|
WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
// The ArgumentsElementsState and ArgumentsLengthState can either describe an
|
// The ArgumentsElementsState and ArgumentsLengthState can describe the layout
|
||||||
// unmapped arguments backing store or the backing store of the rest parameters.
|
// for backing stores of arguments objects of various types:
|
||||||
// IsRestOf(op) is true in the second case.
|
//
|
||||||
bool IsRestOf(Operator const*);
|
// +------------------------------------+
|
||||||
|
// - kUnmappedArguments: | arg0, ... argK-1, argK, ... argN-1 | {length:N}
|
||||||
|
// +------------------------------------+
|
||||||
|
// +------------------------------------+
|
||||||
|
// - kMappedArguments: | hole, ... hole, argK, ... argN-1 | {length:N}
|
||||||
|
// +------------------------------------+
|
||||||
|
// +------------------+
|
||||||
|
// - kRestParameter: | argK, ... argN-1 | {length:N-K}
|
||||||
|
// +------------------+
|
||||||
|
//
|
||||||
|
// Here {K} represents the number for formal parameters of the active function,
|
||||||
|
// whereas {N} represents the actual number of arguments passed at runtime.
|
||||||
|
// Note that {N < K} can happen and causes {K} to be capped accordingly.
|
||||||
|
//
|
||||||
|
// Also note that it is possible for an arguments object of {kMappedArguments}
|
||||||
|
// type to carry a backing store of {kUnappedArguments} type when {K == 0}.
|
||||||
|
typedef CreateArgumentsType ArgumentsStateType;
|
||||||
|
|
||||||
|
ArgumentsStateType ArgumentsStateTypeOf(Operator const*) WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
uint32_t ObjectIdOf(Operator const*);
|
uint32_t ObjectIdOf(Operator const*);
|
||||||
|
|
||||||
@ -383,8 +401,8 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
|
|||||||
const Operator* StateValues(int arguments, SparseInputMask bitmask);
|
const Operator* StateValues(int arguments, SparseInputMask bitmask);
|
||||||
const Operator* TypedStateValues(const ZoneVector<MachineType>* types,
|
const Operator* TypedStateValues(const ZoneVector<MachineType>* types,
|
||||||
SparseInputMask bitmask);
|
SparseInputMask bitmask);
|
||||||
const Operator* ArgumentsElementsState(bool is_rest);
|
const Operator* ArgumentsElementsState(ArgumentsStateType type);
|
||||||
const Operator* ArgumentsLengthState(bool is_rest);
|
const Operator* ArgumentsLengthState(ArgumentsStateType type);
|
||||||
const Operator* ObjectState(int object_id, int pointer_slots);
|
const Operator* ObjectState(int object_id, int pointer_slots);
|
||||||
const Operator* TypedObjectState(int object_id,
|
const Operator* TypedObjectState(int object_id,
|
||||||
const ZoneVector<MachineType>* types);
|
const ZoneVector<MachineType>* types);
|
||||||
|
@ -748,11 +748,8 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
|
|||||||
case IrOpcode::kArgumentsLength:
|
case IrOpcode::kArgumentsLength:
|
||||||
result = LowerArgumentsLength(node);
|
result = LowerArgumentsLength(node);
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kNewMappedArgumentsElements:
|
case IrOpcode::kNewArgumentsElements:
|
||||||
result = LowerNewMappedArgumentsElements(node);
|
result = LowerNewArgumentsElements(node);
|
||||||
break;
|
|
||||||
case IrOpcode::kNewUnmappedArgumentsElements:
|
|
||||||
result = LowerNewUnmappedArgumentsElements(node);
|
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kArrayBufferWasNeutered:
|
case IrOpcode::kArrayBufferWasNeutered:
|
||||||
result = LowerArrayBufferWasNeutered(node);
|
result = LowerArrayBufferWasNeutered(node);
|
||||||
@ -2159,7 +2156,7 @@ Node* EffectControlLinearizer::LowerArgumentsFrame(Node* node) {
|
|||||||
return done.PhiAt(0);
|
return done.PhiAt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* EffectControlLinearizer::LowerNewMappedArgumentsElements(Node* node) {
|
Node* EffectControlLinearizer::LowerNewArgumentsElements(Node* node) {
|
||||||
Node* frame = NodeProperties::GetValueInput(node, 0);
|
Node* frame = NodeProperties::GetValueInput(node, 0);
|
||||||
Node* length = NodeProperties::GetValueInput(node, 1);
|
Node* length = NodeProperties::GetValueInput(node, 1);
|
||||||
int mapped_count = OpParameter<int>(node);
|
int mapped_count = OpParameter<int>(node);
|
||||||
@ -2174,20 +2171,6 @@ Node* EffectControlLinearizer::LowerNewMappedArgumentsElements(Node* node) {
|
|||||||
__ SmiConstant(mapped_count), __ NoContextConstant());
|
__ SmiConstant(mapped_count), __ NoContextConstant());
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* EffectControlLinearizer::LowerNewUnmappedArgumentsElements(Node* node) {
|
|
||||||
Node* frame = NodeProperties::GetValueInput(node, 0);
|
|
||||||
Node* length = NodeProperties::GetValueInput(node, 1);
|
|
||||||
|
|
||||||
Callable const callable =
|
|
||||||
Builtins::CallableFor(isolate(), Builtins::kNewArgumentsElements);
|
|
||||||
Operator::Properties const properties = node->op()->properties();
|
|
||||||
CallDescriptor::Flags const flags = CallDescriptor::kNoFlags;
|
|
||||||
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
|
|
||||||
isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
|
|
||||||
return __ Call(desc, __ HeapConstant(callable.code()), frame, length,
|
|
||||||
__ SmiConstant(0), __ NoContextConstant());
|
|
||||||
}
|
|
||||||
|
|
||||||
Node* EffectControlLinearizer::LowerArrayBufferWasNeutered(Node* node) {
|
Node* EffectControlLinearizer::LowerArrayBufferWasNeutered(Node* node) {
|
||||||
Node* value = node->InputAt(0);
|
Node* value = node->InputAt(0);
|
||||||
|
|
||||||
|
@ -96,8 +96,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
|
|||||||
Node* LowerObjectIsUndetectable(Node* node);
|
Node* LowerObjectIsUndetectable(Node* node);
|
||||||
Node* LowerArgumentsFrame(Node* node);
|
Node* LowerArgumentsFrame(Node* node);
|
||||||
Node* LowerArgumentsLength(Node* node);
|
Node* LowerArgumentsLength(Node* node);
|
||||||
Node* LowerNewMappedArgumentsElements(Node* node);
|
Node* LowerNewArgumentsElements(Node* node);
|
||||||
Node* LowerNewUnmappedArgumentsElements(Node* node);
|
|
||||||
Node* LowerArrayBufferWasNeutered(Node* node);
|
Node* LowerArrayBufferWasNeutered(Node* node);
|
||||||
Node* LowerStringCharAt(Node* node);
|
Node* LowerStringCharAt(Node* node);
|
||||||
Node* LowerStringCharCodeAt(Node* node);
|
Node* LowerStringCharCodeAt(Node* node);
|
||||||
|
@ -97,7 +97,7 @@ Reduction EscapeAnalysisReducer::Reduce(Node* node) {
|
|||||||
}
|
}
|
||||||
return NoChange();
|
return NoChange();
|
||||||
}
|
}
|
||||||
case IrOpcode::kNewUnmappedArgumentsElements:
|
case IrOpcode::kNewArgumentsElements:
|
||||||
arguments_elements_.insert(node);
|
arguments_elements_.insert(node);
|
||||||
return NoChange();
|
return NoChange();
|
||||||
default: {
|
default: {
|
||||||
@ -212,13 +212,27 @@ void EscapeAnalysisReducer::VerifyReplacement() const {
|
|||||||
|
|
||||||
void EscapeAnalysisReducer::Finalize() {
|
void EscapeAnalysisReducer::Finalize() {
|
||||||
for (Node* node : arguments_elements_) {
|
for (Node* node : arguments_elements_) {
|
||||||
DCHECK(node->opcode() == IrOpcode::kNewUnmappedArgumentsElements);
|
DCHECK(node->opcode() == IrOpcode::kNewArgumentsElements);
|
||||||
|
int mapped_count = OpParameter<int>(node);
|
||||||
|
|
||||||
Node* arguments_frame = NodeProperties::GetValueInput(node, 0);
|
Node* arguments_frame = NodeProperties::GetValueInput(node, 0);
|
||||||
if (arguments_frame->opcode() != IrOpcode::kArgumentsFrame) continue;
|
if (arguments_frame->opcode() != IrOpcode::kArgumentsFrame) continue;
|
||||||
Node* arguments_length = NodeProperties::GetValueInput(node, 1);
|
Node* arguments_length = NodeProperties::GetValueInput(node, 1);
|
||||||
if (arguments_length->opcode() != IrOpcode::kArgumentsLength) continue;
|
if (arguments_length->opcode() != IrOpcode::kArgumentsLength) continue;
|
||||||
|
|
||||||
|
// If mapped arguments are specified, then their number is always equal to
|
||||||
|
// the number of formal parameters. This allows to use just the three-value
|
||||||
|
// {ArgumentsStateType} enum because the deoptimizer can reconstruct the
|
||||||
|
// value of {mapped_count} from the number of formal parameters.
|
||||||
|
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;
|
Node* arguments_length_state = nullptr;
|
||||||
for (Edge edge : arguments_length->use_edges()) {
|
for (Edge edge : arguments_length->use_edges()) {
|
||||||
Node* use = edge.from();
|
Node* use = edge.from();
|
||||||
@ -229,8 +243,7 @@ void EscapeAnalysisReducer::Finalize() {
|
|||||||
case IrOpcode::kTypedStateValues:
|
case IrOpcode::kTypedStateValues:
|
||||||
if (!arguments_length_state) {
|
if (!arguments_length_state) {
|
||||||
arguments_length_state = jsgraph()->graph()->NewNode(
|
arguments_length_state = jsgraph()->graph()->NewNode(
|
||||||
jsgraph()->common()->ArgumentsLengthState(
|
jsgraph()->common()->ArgumentsLengthState(type));
|
||||||
IsRestLengthOf(arguments_length->op())));
|
|
||||||
NodeProperties::SetType(arguments_length_state,
|
NodeProperties::SetType(arguments_length_state,
|
||||||
Type::OtherInternal());
|
Type::OtherInternal());
|
||||||
}
|
}
|
||||||
@ -257,7 +270,11 @@ void EscapeAnalysisReducer::Finalize() {
|
|||||||
case IrOpcode::kTypedObjectState:
|
case IrOpcode::kTypedObjectState:
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kLoadElement:
|
case IrOpcode::kLoadElement:
|
||||||
loads.push_back(use);
|
if (mapped_count == 0) {
|
||||||
|
loads.push_back(use);
|
||||||
|
} else {
|
||||||
|
escaping_use = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kLoadField:
|
case IrOpcode::kLoadField:
|
||||||
if (FieldAccessOf(use->op()).offset == FixedArray::kLengthOffset) {
|
if (FieldAccessOf(use->op()).offset == FixedArray::kLengthOffset) {
|
||||||
@ -276,8 +293,7 @@ void EscapeAnalysisReducer::Finalize() {
|
|||||||
}
|
}
|
||||||
if (!escaping_use) {
|
if (!escaping_use) {
|
||||||
Node* arguments_elements_state = jsgraph()->graph()->NewNode(
|
Node* arguments_elements_state = jsgraph()->graph()->NewNode(
|
||||||
jsgraph()->common()->ArgumentsElementsState(
|
jsgraph()->common()->ArgumentsElementsState(type));
|
||||||
IsRestLengthOf(arguments_length->op())));
|
|
||||||
NodeProperties::SetType(arguments_elements_state, Type::OtherInternal());
|
NodeProperties::SetType(arguments_elements_state, Type::OtherInternal());
|
||||||
ReplaceWithValue(node, arguments_elements_state);
|
ReplaceWithValue(node, arguments_elements_state);
|
||||||
|
|
||||||
|
@ -530,7 +530,7 @@ size_t InstructionSelector::AddOperandToStateValueDescriptor(
|
|||||||
|
|
||||||
switch (input->opcode()) {
|
switch (input->opcode()) {
|
||||||
case IrOpcode::kArgumentsElementsState: {
|
case IrOpcode::kArgumentsElementsState: {
|
||||||
values->PushArgumentsElements(IsRestOf(input->op()));
|
values->PushArgumentsElements(ArgumentsStateTypeOf(input->op()));
|
||||||
// The elements backing store of an arguments object participates in the
|
// The elements backing store of an arguments object participates in the
|
||||||
// duplicate object counting, but can itself never appear duplicated.
|
// duplicate object counting, but can itself never appear duplicated.
|
||||||
DCHECK_EQ(StateObjectDeduplicator::kNotDuplicated,
|
DCHECK_EQ(StateObjectDeduplicator::kNotDuplicated,
|
||||||
@ -539,7 +539,7 @@ size_t InstructionSelector::AddOperandToStateValueDescriptor(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case IrOpcode::kArgumentsLengthState: {
|
case IrOpcode::kArgumentsLengthState: {
|
||||||
values->PushArgumentsLength(IsRestOf(input->op()));
|
values->PushArgumentsLength(ArgumentsStateTypeOf(input->op()));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case IrOpcode::kObjectState: {
|
case IrOpcode::kObjectState: {
|
||||||
|
@ -1123,16 +1123,16 @@ class StateValueDescriptor {
|
|||||||
StateValueDescriptor()
|
StateValueDescriptor()
|
||||||
: kind_(StateValueKind::kPlain), type_(MachineType::AnyTagged()) {}
|
: kind_(StateValueKind::kPlain), type_(MachineType::AnyTagged()) {}
|
||||||
|
|
||||||
static StateValueDescriptor ArgumentsElements(bool is_rest) {
|
static StateValueDescriptor ArgumentsElements(ArgumentsStateType type) {
|
||||||
StateValueDescriptor descr(StateValueKind::kArgumentsElements,
|
StateValueDescriptor descr(StateValueKind::kArgumentsElements,
|
||||||
MachineType::AnyTagged());
|
MachineType::AnyTagged());
|
||||||
descr.is_rest_ = is_rest;
|
descr.args_type_ = type;
|
||||||
return descr;
|
return descr;
|
||||||
}
|
}
|
||||||
static StateValueDescriptor ArgumentsLength(bool is_rest) {
|
static StateValueDescriptor ArgumentsLength(ArgumentsStateType type) {
|
||||||
StateValueDescriptor descr(StateValueKind::kArgumentsLength,
|
StateValueDescriptor descr(StateValueKind::kArgumentsLength,
|
||||||
MachineType::AnyTagged());
|
MachineType::AnyTagged());
|
||||||
descr.is_rest_ = is_rest;
|
descr.args_type_ = type;
|
||||||
return descr;
|
return descr;
|
||||||
}
|
}
|
||||||
static StateValueDescriptor Plain(MachineType type) {
|
static StateValueDescriptor Plain(MachineType type) {
|
||||||
@ -1171,10 +1171,10 @@ class StateValueDescriptor {
|
|||||||
kind_ == StateValueKind::kNested);
|
kind_ == StateValueKind::kNested);
|
||||||
return id_;
|
return id_;
|
||||||
}
|
}
|
||||||
int is_rest() const {
|
ArgumentsStateType arguments_type() const {
|
||||||
DCHECK(kind_ == StateValueKind::kArgumentsElements ||
|
DCHECK(kind_ == StateValueKind::kArgumentsElements ||
|
||||||
kind_ == StateValueKind::kArgumentsLength);
|
kind_ == StateValueKind::kArgumentsLength);
|
||||||
return is_rest_;
|
return args_type_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -1185,7 +1185,7 @@ class StateValueDescriptor {
|
|||||||
MachineType type_;
|
MachineType type_;
|
||||||
union {
|
union {
|
||||||
size_t id_;
|
size_t id_;
|
||||||
bool is_rest_;
|
ArgumentsStateType args_type_;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1245,11 +1245,11 @@ class StateValueList {
|
|||||||
nested_.push_back(nested);
|
nested_.push_back(nested);
|
||||||
return nested;
|
return nested;
|
||||||
}
|
}
|
||||||
void PushArgumentsElements(bool is_rest) {
|
void PushArgumentsElements(ArgumentsStateType type) {
|
||||||
fields_.push_back(StateValueDescriptor::ArgumentsElements(is_rest));
|
fields_.push_back(StateValueDescriptor::ArgumentsElements(type));
|
||||||
}
|
}
|
||||||
void PushArgumentsLength(bool is_rest) {
|
void PushArgumentsLength(ArgumentsStateType type) {
|
||||||
fields_.push_back(StateValueDescriptor::ArgumentsLength(is_rest));
|
fields_.push_back(StateValueDescriptor::ArgumentsLength(type));
|
||||||
}
|
}
|
||||||
void PushDuplicate(size_t id) {
|
void PushDuplicate(size_t id) {
|
||||||
fields_.push_back(StateValueDescriptor::Duplicate(id));
|
fields_.push_back(StateValueDescriptor::Duplicate(id));
|
||||||
|
@ -355,7 +355,7 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
|
|||||||
arguments_frame);
|
arguments_frame);
|
||||||
// Allocate the elements backing store.
|
// Allocate the elements backing store.
|
||||||
Node* const elements = effect =
|
Node* const elements = effect =
|
||||||
graph()->NewNode(simplified()->NewUnmappedArgumentsElements(),
|
graph()->NewNode(simplified()->NewArgumentsElements(0),
|
||||||
arguments_frame, arguments_length, effect);
|
arguments_frame, arguments_length, effect);
|
||||||
// Load the arguments object map.
|
// Load the arguments object map.
|
||||||
Node* const arguments_map = jsgraph()->HeapConstant(
|
Node* const arguments_map = jsgraph()->HeapConstant(
|
||||||
@ -381,11 +381,11 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
|
|||||||
simplified()->ArgumentsLength(
|
simplified()->ArgumentsLength(
|
||||||
shared->internal_formal_parameter_count(), true),
|
shared->internal_formal_parameter_count(), true),
|
||||||
arguments_frame);
|
arguments_frame);
|
||||||
// Allocate the elements backing store. Since
|
// Allocate the elements backing store. Since NewArgumentsElements
|
||||||
// NewUnmappedArgumentsElements copies from the end of the arguments
|
// copies from the end of the arguments adapter frame, this is a suffix
|
||||||
// adapter frame, this is a suffix of the actual arguments.
|
// of the actual arguments.
|
||||||
Node* const elements = effect =
|
Node* const elements = effect =
|
||||||
graph()->NewNode(simplified()->NewUnmappedArgumentsElements(),
|
graph()->NewNode(simplified()->NewArgumentsElements(0),
|
||||||
arguments_frame, rest_length, effect);
|
arguments_frame, rest_length, effect);
|
||||||
// Load the JSArray object map.
|
// Load the JSArray object map.
|
||||||
Node* const jsarray_map = jsgraph()->HeapConstant(handle(
|
Node* const jsarray_map = jsgraph()->HeapConstant(handle(
|
||||||
@ -1204,7 +1204,7 @@ Node* JSCreateLowering::AllocateAliasedArguments(
|
|||||||
// special in any way, we can just return an unmapped backing store.
|
// special in any way, we can just return an unmapped backing store.
|
||||||
int parameter_count = shared->internal_formal_parameter_count();
|
int parameter_count = shared->internal_formal_parameter_count();
|
||||||
if (parameter_count == 0) {
|
if (parameter_count == 0) {
|
||||||
return graph()->NewNode(simplified()->NewUnmappedArgumentsElements(),
|
return graph()->NewNode(simplified()->NewArgumentsElements(0),
|
||||||
arguments_frame, arguments_length, effect);
|
arguments_frame, arguments_length, effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1219,7 +1219,7 @@ Node* JSCreateLowering::AllocateAliasedArguments(
|
|||||||
// then linked into the parameter map below, whereas mapped argument values
|
// then linked into the parameter map below, whereas mapped argument values
|
||||||
// (i.e. the first {mapped_count} elements) are replaced with a hole instead.
|
// (i.e. the first {mapped_count} elements) are replaced with a hole instead.
|
||||||
Node* arguments =
|
Node* arguments =
|
||||||
graph()->NewNode(simplified()->NewMappedArgumentsElements(mapped_count),
|
graph()->NewNode(simplified()->NewArgumentsElements(mapped_count),
|
||||||
arguments_frame, arguments_length, effect);
|
arguments_frame, arguments_length, effect);
|
||||||
|
|
||||||
// Actually allocate the backing store.
|
// Actually allocate the backing store.
|
||||||
|
@ -364,8 +364,7 @@
|
|||||||
V(ObjectIsUndetectable) \
|
V(ObjectIsUndetectable) \
|
||||||
V(ArgumentsFrame) \
|
V(ArgumentsFrame) \
|
||||||
V(ArgumentsLength) \
|
V(ArgumentsLength) \
|
||||||
V(NewMappedArgumentsElements) \
|
V(NewArgumentsElements) \
|
||||||
V(NewUnmappedArgumentsElements) \
|
|
||||||
V(ArrayBufferWasNeutered) \
|
V(ArrayBufferWasNeutered) \
|
||||||
V(EnsureWritableFastElements) \
|
V(EnsureWritableFastElements) \
|
||||||
V(MaybeGrowFastElements) \
|
V(MaybeGrowFastElements) \
|
||||||
|
@ -2739,8 +2739,7 @@ class RepresentationSelector {
|
|||||||
MachineRepresentation::kTaggedSigned);
|
MachineRepresentation::kTaggedSigned);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case IrOpcode::kNewMappedArgumentsElements:
|
case IrOpcode::kNewArgumentsElements: {
|
||||||
case IrOpcode::kNewUnmappedArgumentsElements: {
|
|
||||||
VisitBinop(node, UseInfo::PointerInt(), UseInfo::TaggedSigned(),
|
VisitBinop(node, UseInfo::PointerInt(), UseInfo::TaggedSigned(),
|
||||||
MachineRepresentation::kTaggedPointer);
|
MachineRepresentation::kTaggedPointer);
|
||||||
return;
|
return;
|
||||||
|
@ -609,14 +609,6 @@ struct SimplifiedOperatorGlobalCache final {
|
|||||||
};
|
};
|
||||||
ArgumentsFrameOperator kArgumentsFrame;
|
ArgumentsFrameOperator kArgumentsFrame;
|
||||||
|
|
||||||
struct NewUnmappedArgumentsElementsOperator final : public Operator {
|
|
||||||
NewUnmappedArgumentsElementsOperator()
|
|
||||||
: Operator(IrOpcode::kNewUnmappedArgumentsElements,
|
|
||||||
Operator::kEliminatable, "NewUnmappedArgumentsElements", 2,
|
|
||||||
1, 0, 1, 1, 0) {}
|
|
||||||
};
|
|
||||||
NewUnmappedArgumentsElementsOperator kNewUnmappedArgumentsElements;
|
|
||||||
|
|
||||||
template <CheckForMinusZeroMode kMode>
|
template <CheckForMinusZeroMode kMode>
|
||||||
struct ChangeFloat64ToTaggedOperator final
|
struct ChangeFloat64ToTaggedOperator final
|
||||||
: public Operator1<CheckForMinusZeroMode> {
|
: public Operator1<CheckForMinusZeroMode> {
|
||||||
@ -789,7 +781,6 @@ GET_FROM_CACHE(ArgumentsFrame)
|
|||||||
GET_FROM_CACHE(LookupHashStorageIndex)
|
GET_FROM_CACHE(LookupHashStorageIndex)
|
||||||
GET_FROM_CACHE(LoadHashMapValue)
|
GET_FROM_CACHE(LoadHashMapValue)
|
||||||
GET_FROM_CACHE(LoadFieldByIndex)
|
GET_FROM_CACHE(LoadFieldByIndex)
|
||||||
GET_FROM_CACHE(NewUnmappedArgumentsElements)
|
|
||||||
#undef GET_FROM_CACHE
|
#undef GET_FROM_CACHE
|
||||||
|
|
||||||
const Operator* SimplifiedOperatorBuilder::ChangeFloat64ToTagged(
|
const Operator* SimplifiedOperatorBuilder::ChangeFloat64ToTagged(
|
||||||
@ -976,14 +967,14 @@ bool IsRestLengthOf(const Operator* op) {
|
|||||||
return OpParameter<ArgumentsLengthParameters>(op).is_rest_length;
|
return OpParameter<ArgumentsLengthParameters>(op).is_rest_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Operator* SimplifiedOperatorBuilder::NewMappedArgumentsElements(
|
const Operator* SimplifiedOperatorBuilder::NewArgumentsElements(
|
||||||
int mapped_count) {
|
int mapped_count) {
|
||||||
return new (zone()) Operator1<int>( // --
|
return new (zone()) Operator1<int>( // --
|
||||||
IrOpcode::kNewMappedArgumentsElements, // opcode
|
IrOpcode::kNewArgumentsElements, // opcode
|
||||||
Operator::kEliminatable, // flags
|
Operator::kEliminatable, // flags
|
||||||
"NewMappedArgumentsElements", // name
|
"NewArgumentsElements", // name
|
||||||
2, 1, 0, 1, 1, 0, // counts
|
2, 1, 0, 1, 1, 0, // counts
|
||||||
mapped_count); // parameter
|
mapped_count); // parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
const Operator* SimplifiedOperatorBuilder::Allocate(Type* type,
|
const Operator* SimplifiedOperatorBuilder::Allocate(Type* type,
|
||||||
|
@ -450,11 +450,8 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
|
|||||||
const Operator* ArgumentsLength(int formal_parameter_count,
|
const Operator* ArgumentsLength(int formal_parameter_count,
|
||||||
bool is_rest_length);
|
bool is_rest_length);
|
||||||
|
|
||||||
// new-mapped-arguments-elements arguments-frame, arguments-length
|
// new-arguments-elements arguments-frame, arguments-length
|
||||||
const Operator* NewMappedArgumentsElements(int mapped_count);
|
const Operator* NewArgumentsElements(int mapped_count);
|
||||||
|
|
||||||
// new-unmapped-arguments-elements arguments-frame, arguments-length
|
|
||||||
const Operator* NewUnmappedArgumentsElements();
|
|
||||||
|
|
||||||
// array-buffer-was-neutered buffer
|
// array-buffer-was-neutered buffer
|
||||||
const Operator* ArrayBufferWasNeutered();
|
const Operator* ArrayBufferWasNeutered();
|
||||||
|
@ -2004,11 +2004,7 @@ Type* Typer::Visitor::TypeArgumentsFrame(Node* node) {
|
|||||||
return Type::ExternalPointer();
|
return Type::ExternalPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
Type* Typer::Visitor::TypeNewMappedArgumentsElements(Node* node) {
|
Type* Typer::Visitor::TypeNewArgumentsElements(Node* node) {
|
||||||
return Type::OtherInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
Type* Typer::Visitor::TypeNewUnmappedArgumentsElements(Node* node) {
|
|
||||||
return Type::OtherInternal();
|
return Type::OtherInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1032,8 +1032,7 @@ void Verifier::Visitor::Check(Node* node) {
|
|||||||
case IrOpcode::kArgumentsFrame:
|
case IrOpcode::kArgumentsFrame:
|
||||||
CheckTypeIs(node, Type::ExternalPointer());
|
CheckTypeIs(node, Type::ExternalPointer());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kNewMappedArgumentsElements:
|
case IrOpcode::kNewArgumentsElements:
|
||||||
case IrOpcode::kNewUnmappedArgumentsElements:
|
|
||||||
CheckValueInputIs(node, 0, Type::ExternalPointer());
|
CheckValueInputIs(node, 0, Type::ExternalPointer());
|
||||||
CheckValueInputIs(node, 1, Type::Range(-Code::kMaxArguments,
|
CheckValueInputIs(node, 1, Type::Range(-Code::kMaxArguments,
|
||||||
Code::kMaxArguments, zone));
|
Code::kMaxArguments, zone));
|
||||||
|
@ -2121,15 +2121,14 @@ void Translation::BeginInterpretedFrame(BailoutId bytecode_offset,
|
|||||||
buffer_->Add(height);
|
buffer_->Add(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Translation::ArgumentsElements(CreateArgumentsType type) {
|
||||||
void Translation::ArgumentsElements(bool is_rest) {
|
|
||||||
buffer_->Add(ARGUMENTS_ELEMENTS);
|
buffer_->Add(ARGUMENTS_ELEMENTS);
|
||||||
buffer_->Add(is_rest);
|
buffer_->Add(static_cast<uint8_t>(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Translation::ArgumentsLength(bool is_rest) {
|
void Translation::ArgumentsLength(CreateArgumentsType type) {
|
||||||
buffer_->Add(ARGUMENTS_LENGTH);
|
buffer_->Add(ARGUMENTS_LENGTH);
|
||||||
buffer_->Add(is_rest);
|
buffer_->Add(static_cast<uint8_t>(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Translation::BeginCapturedObject(int length) {
|
void Translation::BeginCapturedObject(int length) {
|
||||||
@ -2229,6 +2228,8 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
|
|||||||
case GETTER_STUB_FRAME:
|
case GETTER_STUB_FRAME:
|
||||||
case SETTER_STUB_FRAME:
|
case SETTER_STUB_FRAME:
|
||||||
case DUPLICATED_OBJECT:
|
case DUPLICATED_OBJECT:
|
||||||
|
case ARGUMENTS_ELEMENTS:
|
||||||
|
case ARGUMENTS_LENGTH:
|
||||||
case CAPTURED_OBJECT:
|
case CAPTURED_OBJECT:
|
||||||
case REGISTER:
|
case REGISTER:
|
||||||
case INT32_REGISTER:
|
case INT32_REGISTER:
|
||||||
@ -2252,9 +2253,6 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
|
|||||||
case BUILTIN_CONTINUATION_FRAME:
|
case BUILTIN_CONTINUATION_FRAME:
|
||||||
case JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME:
|
case JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME:
|
||||||
return 3;
|
return 3;
|
||||||
case ARGUMENTS_ELEMENTS:
|
|
||||||
case ARGUMENTS_LENGTH:
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
FATAL("Unexpected translation type");
|
FATAL("Unexpected translation type");
|
||||||
return -1;
|
return -1;
|
||||||
@ -3014,7 +3012,8 @@ void TranslatedFrame::AdvanceIterator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Address TranslatedState::ComputeArgumentsPosition(Address input_frame_pointer,
|
Address TranslatedState::ComputeArgumentsPosition(Address input_frame_pointer,
|
||||||
bool is_rest, int* length) {
|
CreateArgumentsType type,
|
||||||
|
int* length) {
|
||||||
Address parent_frame_pointer = *reinterpret_cast<Address*>(
|
Address parent_frame_pointer = *reinterpret_cast<Address*>(
|
||||||
input_frame_pointer + StandardFrameConstants::kCallerFPOffset);
|
input_frame_pointer + StandardFrameConstants::kCallerFPOffset);
|
||||||
intptr_t parent_frame_type = Memory::intptr_at(
|
intptr_t parent_frame_type = Memory::intptr_at(
|
||||||
@ -3034,7 +3033,7 @@ Address TranslatedState::ComputeArgumentsPosition(Address input_frame_pointer,
|
|||||||
arguments_frame = input_frame_pointer;
|
arguments_frame = input_frame_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_rest) {
|
if (type == CreateArgumentsType::kRestParameter) {
|
||||||
// If the actual number of arguments is less than the number of formal
|
// If the actual number of arguments is less than the number of formal
|
||||||
// parameters, we have zero rest parameters.
|
// parameters, we have zero rest parameters.
|
||||||
if (length) *length = std::max(0, *length - formal_parameter_count_);
|
if (length) *length = std::max(0, *length - formal_parameter_count_);
|
||||||
@ -3044,24 +3043,23 @@ Address TranslatedState::ComputeArgumentsPosition(Address input_frame_pointer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Creates translated values for an arguments backing store, or the backing
|
// Creates translated values for an arguments backing store, or the backing
|
||||||
// store for the rest parameters if {is_rest} is true. The TranslatedValue
|
// store for rest parameters depending on the given {type}. The TranslatedValue
|
||||||
// objects for the fields are not read from the TranslationIterator, but instead
|
// objects for the fields are not read from the TranslationIterator, but instead
|
||||||
// created on-the-fly based on dynamic information in the optimized frame.
|
// created on-the-fly based on dynamic information in the optimized frame.
|
||||||
void TranslatedState::CreateArgumentsElementsTranslatedValues(
|
void TranslatedState::CreateArgumentsElementsTranslatedValues(
|
||||||
int frame_index, Address input_frame_pointer, bool is_rest,
|
int frame_index, Address input_frame_pointer, CreateArgumentsType type,
|
||||||
FILE* trace_file) {
|
FILE* trace_file) {
|
||||||
TranslatedFrame& frame = frames_[frame_index];
|
TranslatedFrame& frame = frames_[frame_index];
|
||||||
|
|
||||||
int length;
|
int length;
|
||||||
Address arguments_frame =
|
Address arguments_frame =
|
||||||
ComputeArgumentsPosition(input_frame_pointer, is_rest, &length);
|
ComputeArgumentsPosition(input_frame_pointer, type, &length);
|
||||||
|
|
||||||
int object_index = static_cast<int>(object_positions_.size());
|
int object_index = static_cast<int>(object_positions_.size());
|
||||||
int value_index = static_cast<int>(frame.values_.size());
|
int value_index = static_cast<int>(frame.values_.size());
|
||||||
if (trace_file != nullptr) {
|
if (trace_file != nullptr) {
|
||||||
PrintF(trace_file,
|
PrintF(trace_file, "arguments elements object #%d (type = %d, length = %d)",
|
||||||
"arguments elements object #%d (is_rest = %d, length = %d)",
|
object_index, static_cast<uint8_t>(type), length);
|
||||||
object_index, is_rest, length);
|
|
||||||
}
|
}
|
||||||
object_positions_.push_back({frame_index, value_index});
|
object_positions_.push_back({frame_index, value_index});
|
||||||
frame.Add(TranslatedValue::NewDeferredObject(
|
frame.Add(TranslatedValue::NewDeferredObject(
|
||||||
@ -3071,7 +3069,17 @@ void TranslatedState::CreateArgumentsElementsTranslatedValues(
|
|||||||
TranslatedValue::NewTagged(this, isolate_->heap()->fixed_array_map()));
|
TranslatedValue::NewTagged(this, isolate_->heap()->fixed_array_map()));
|
||||||
frame.Add(TranslatedValue::NewInt32(this, length));
|
frame.Add(TranslatedValue::NewInt32(this, length));
|
||||||
|
|
||||||
for (int i = length - 1; i >= 0; --i) {
|
int number_of_holes = 0;
|
||||||
|
if (type == CreateArgumentsType::kMappedArguments) {
|
||||||
|
// If the actual number of arguments is less than the number of formal
|
||||||
|
// parameters, we have fewer holes to fill to not overshoot the length.
|
||||||
|
number_of_holes = Min(formal_parameter_count_, length);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < number_of_holes; ++i) {
|
||||||
|
frame.Add(
|
||||||
|
TranslatedValue::NewTagged(this, isolate_->heap()->the_hole_value()));
|
||||||
|
}
|
||||||
|
for (int i = length - number_of_holes - 1; i >= 0; --i) {
|
||||||
Address argument_slot = arguments_frame +
|
Address argument_slot = arguments_frame +
|
||||||
CommonFrameConstants::kFixedFrameSizeAboveFp +
|
CommonFrameConstants::kFixedFrameSizeAboveFp +
|
||||||
i * kPointerSize;
|
i * kPointerSize;
|
||||||
@ -3124,19 +3132,21 @@ int TranslatedState::CreateNextTranslatedValue(
|
|||||||
}
|
}
|
||||||
|
|
||||||
case Translation::ARGUMENTS_ELEMENTS: {
|
case Translation::ARGUMENTS_ELEMENTS: {
|
||||||
bool is_rest = iterator->Next();
|
CreateArgumentsType arguments_type =
|
||||||
CreateArgumentsElementsTranslatedValues(frame_index, fp, is_rest,
|
static_cast<CreateArgumentsType>(iterator->Next());
|
||||||
|
CreateArgumentsElementsTranslatedValues(frame_index, fp, arguments_type,
|
||||||
trace_file);
|
trace_file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Translation::ARGUMENTS_LENGTH: {
|
case Translation::ARGUMENTS_LENGTH: {
|
||||||
bool is_rest = iterator->Next();
|
CreateArgumentsType arguments_type =
|
||||||
|
static_cast<CreateArgumentsType>(iterator->Next());
|
||||||
int length;
|
int length;
|
||||||
ComputeArgumentsPosition(fp, is_rest, &length);
|
ComputeArgumentsPosition(fp, arguments_type, &length);
|
||||||
if (trace_file != nullptr) {
|
if (trace_file != nullptr) {
|
||||||
PrintF(trace_file, "arguments length field (is_rest = %d, length = %d)",
|
PrintF(trace_file, "arguments length field (type = %d, length = %d)",
|
||||||
is_rest, length);
|
static_cast<uint8_t>(arguments_type), length);
|
||||||
}
|
}
|
||||||
frame.Add(TranslatedValue::NewInt32(this, length));
|
frame.Add(TranslatedValue::NewInt32(this, length));
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -281,11 +281,12 @@ class TranslatedState {
|
|||||||
int CreateNextTranslatedValue(int frame_index, TranslationIterator* iterator,
|
int CreateNextTranslatedValue(int frame_index, TranslationIterator* iterator,
|
||||||
FixedArray* literal_array, Address fp,
|
FixedArray* literal_array, Address fp,
|
||||||
RegisterValues* registers, FILE* trace_file);
|
RegisterValues* registers, FILE* trace_file);
|
||||||
Address ComputeArgumentsPosition(Address input_frame_pointer, bool is_rest,
|
Address ComputeArgumentsPosition(Address input_frame_pointer,
|
||||||
int* length);
|
CreateArgumentsType type, int* length);
|
||||||
void CreateArgumentsElementsTranslatedValues(int frame_index,
|
void CreateArgumentsElementsTranslatedValues(int frame_index,
|
||||||
Address input_frame_pointer,
|
Address input_frame_pointer,
|
||||||
bool is_rest, FILE* trace_file);
|
CreateArgumentsType type,
|
||||||
|
FILE* trace_file);
|
||||||
|
|
||||||
void UpdateFromPreviouslyMaterializedObjects();
|
void UpdateFromPreviouslyMaterializedObjects();
|
||||||
Handle<Object> MaterializeAt(int frame_index, int* value_index);
|
Handle<Object> MaterializeAt(int frame_index, int* value_index);
|
||||||
@ -906,8 +907,8 @@ class Translation BASE_EMBEDDED {
|
|||||||
int literal_id, unsigned height);
|
int literal_id, unsigned height);
|
||||||
void BeginGetterStubFrame(int literal_id);
|
void BeginGetterStubFrame(int literal_id);
|
||||||
void BeginSetterStubFrame(int literal_id);
|
void BeginSetterStubFrame(int literal_id);
|
||||||
void ArgumentsElements(bool is_rest);
|
void ArgumentsElements(CreateArgumentsType type);
|
||||||
void ArgumentsLength(bool is_rest);
|
void ArgumentsLength(CreateArgumentsType type);
|
||||||
void BeginCapturedObject(int length);
|
void BeginCapturedObject(int length);
|
||||||
void DuplicateObject(int object_index);
|
void DuplicateObject(int object_index);
|
||||||
void StoreRegister(Register reg);
|
void StoreRegister(Register reg);
|
||||||
|
@ -14460,8 +14460,9 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(
|
|||||||
|
|
||||||
case Translation::ARGUMENTS_ELEMENTS:
|
case Translation::ARGUMENTS_ELEMENTS:
|
||||||
case Translation::ARGUMENTS_LENGTH: {
|
case Translation::ARGUMENTS_LENGTH: {
|
||||||
bool is_rest = iterator.Next();
|
CreateArgumentsType arguments_type =
|
||||||
os << "{is_rest=" << (is_rest ? "true" : "false") << "}";
|
static_cast<CreateArgumentsType>(iterator.Next());
|
||||||
|
os << "{arguments_type=" << arguments_type << "}";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user