[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()) {
|
||||
if (translation != nullptr) {
|
||||
translation->ArgumentsElements(desc->is_rest());
|
||||
translation->ArgumentsElements(desc->arguments_type());
|
||||
}
|
||||
} else if (desc->IsArgumentsLength()) {
|
||||
if (translation != nullptr) {
|
||||
translation->ArgumentsLength(desc->is_rest());
|
||||
translation->ArgumentsLength(desc->arguments_type());
|
||||
}
|
||||
} else if (desc->IsDuplicate()) {
|
||||
if (translation != nullptr) {
|
||||
|
@ -1235,24 +1235,28 @@ const Operator* CommonOperatorBuilder::TypedStateValues(
|
||||
TypedStateValueInfo(types, bitmask)); // parameters
|
||||
}
|
||||
|
||||
const Operator* CommonOperatorBuilder::ArgumentsElementsState(bool is_rest) {
|
||||
return new (zone()) Operator1<bool>( // --
|
||||
const Operator* CommonOperatorBuilder::ArgumentsElementsState(
|
||||
ArgumentsStateType type) {
|
||||
return new (zone()) Operator1<ArgumentsStateType>( // --
|
||||
IrOpcode::kArgumentsElementsState, Operator::kPure, // opcode
|
||||
"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) {
|
||||
return new (zone()) Operator1<bool>( // --
|
||||
const Operator* CommonOperatorBuilder::ArgumentsLengthState(
|
||||
ArgumentsStateType type) {
|
||||
return new (zone()) Operator1<ArgumentsStateType>( // --
|
||||
IrOpcode::kArgumentsLengthState, Operator::kPure, // opcode
|
||||
"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 ||
|
||||
op->opcode() == IrOpcode::kArgumentsLengthState);
|
||||
return OpParameter<bool>(op);
|
||||
return OpParameter<ArgumentsStateType>(op);
|
||||
}
|
||||
|
||||
const Operator* CommonOperatorBuilder::ObjectState(int object_id,
|
||||
|
@ -311,10 +311,28 @@ SparseInputMask SparseInputMaskOf(Operator const*);
|
||||
ZoneVector<MachineType> const* MachineTypesOf(Operator const*)
|
||||
WARN_UNUSED_RESULT;
|
||||
|
||||
// The ArgumentsElementsState and ArgumentsLengthState can either describe an
|
||||
// unmapped arguments backing store or the backing store of the rest parameters.
|
||||
// IsRestOf(op) is true in the second case.
|
||||
bool IsRestOf(Operator const*);
|
||||
// The ArgumentsElementsState and ArgumentsLengthState can describe the layout
|
||||
// for backing stores of arguments objects of various types:
|
||||
//
|
||||
// +------------------------------------+
|
||||
// - 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*);
|
||||
|
||||
@ -383,8 +401,8 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
|
||||
const Operator* StateValues(int arguments, SparseInputMask bitmask);
|
||||
const Operator* TypedStateValues(const ZoneVector<MachineType>* types,
|
||||
SparseInputMask bitmask);
|
||||
const Operator* ArgumentsElementsState(bool is_rest);
|
||||
const Operator* ArgumentsLengthState(bool is_rest);
|
||||
const Operator* ArgumentsElementsState(ArgumentsStateType type);
|
||||
const Operator* ArgumentsLengthState(ArgumentsStateType type);
|
||||
const Operator* ObjectState(int object_id, int pointer_slots);
|
||||
const Operator* TypedObjectState(int object_id,
|
||||
const ZoneVector<MachineType>* types);
|
||||
|
@ -748,11 +748,8 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
|
||||
case IrOpcode::kArgumentsLength:
|
||||
result = LowerArgumentsLength(node);
|
||||
break;
|
||||
case IrOpcode::kNewMappedArgumentsElements:
|
||||
result = LowerNewMappedArgumentsElements(node);
|
||||
break;
|
||||
case IrOpcode::kNewUnmappedArgumentsElements:
|
||||
result = LowerNewUnmappedArgumentsElements(node);
|
||||
case IrOpcode::kNewArgumentsElements:
|
||||
result = LowerNewArgumentsElements(node);
|
||||
break;
|
||||
case IrOpcode::kArrayBufferWasNeutered:
|
||||
result = LowerArrayBufferWasNeutered(node);
|
||||
@ -2159,7 +2156,7 @@ Node* EffectControlLinearizer::LowerArgumentsFrame(Node* node) {
|
||||
return done.PhiAt(0);
|
||||
}
|
||||
|
||||
Node* EffectControlLinearizer::LowerNewMappedArgumentsElements(Node* node) {
|
||||
Node* EffectControlLinearizer::LowerNewArgumentsElements(Node* node) {
|
||||
Node* frame = NodeProperties::GetValueInput(node, 0);
|
||||
Node* length = NodeProperties::GetValueInput(node, 1);
|
||||
int mapped_count = OpParameter<int>(node);
|
||||
@ -2174,20 +2171,6 @@ Node* EffectControlLinearizer::LowerNewMappedArgumentsElements(Node* node) {
|
||||
__ 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* value = node->InputAt(0);
|
||||
|
||||
|
@ -96,8 +96,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
|
||||
Node* LowerObjectIsUndetectable(Node* node);
|
||||
Node* LowerArgumentsFrame(Node* node);
|
||||
Node* LowerArgumentsLength(Node* node);
|
||||
Node* LowerNewMappedArgumentsElements(Node* node);
|
||||
Node* LowerNewUnmappedArgumentsElements(Node* node);
|
||||
Node* LowerNewArgumentsElements(Node* node);
|
||||
Node* LowerArrayBufferWasNeutered(Node* node);
|
||||
Node* LowerStringCharAt(Node* node);
|
||||
Node* LowerStringCharCodeAt(Node* node);
|
||||
|
@ -97,7 +97,7 @@ Reduction EscapeAnalysisReducer::Reduce(Node* node) {
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
case IrOpcode::kNewUnmappedArgumentsElements:
|
||||
case IrOpcode::kNewArgumentsElements:
|
||||
arguments_elements_.insert(node);
|
||||
return NoChange();
|
||||
default: {
|
||||
@ -212,13 +212,27 @@ void EscapeAnalysisReducer::VerifyReplacement() const {
|
||||
|
||||
void EscapeAnalysisReducer::Finalize() {
|
||||
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);
|
||||
if (arguments_frame->opcode() != IrOpcode::kArgumentsFrame) continue;
|
||||
Node* arguments_length = NodeProperties::GetValueInput(node, 1);
|
||||
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;
|
||||
for (Edge edge : arguments_length->use_edges()) {
|
||||
Node* use = edge.from();
|
||||
@ -229,8 +243,7 @@ void EscapeAnalysisReducer::Finalize() {
|
||||
case IrOpcode::kTypedStateValues:
|
||||
if (!arguments_length_state) {
|
||||
arguments_length_state = jsgraph()->graph()->NewNode(
|
||||
jsgraph()->common()->ArgumentsLengthState(
|
||||
IsRestLengthOf(arguments_length->op())));
|
||||
jsgraph()->common()->ArgumentsLengthState(type));
|
||||
NodeProperties::SetType(arguments_length_state,
|
||||
Type::OtherInternal());
|
||||
}
|
||||
@ -257,7 +270,11 @@ void EscapeAnalysisReducer::Finalize() {
|
||||
case IrOpcode::kTypedObjectState:
|
||||
break;
|
||||
case IrOpcode::kLoadElement:
|
||||
loads.push_back(use);
|
||||
if (mapped_count == 0) {
|
||||
loads.push_back(use);
|
||||
} else {
|
||||
escaping_use = true;
|
||||
}
|
||||
break;
|
||||
case IrOpcode::kLoadField:
|
||||
if (FieldAccessOf(use->op()).offset == FixedArray::kLengthOffset) {
|
||||
@ -276,8 +293,7 @@ void EscapeAnalysisReducer::Finalize() {
|
||||
}
|
||||
if (!escaping_use) {
|
||||
Node* arguments_elements_state = jsgraph()->graph()->NewNode(
|
||||
jsgraph()->common()->ArgumentsElementsState(
|
||||
IsRestLengthOf(arguments_length->op())));
|
||||
jsgraph()->common()->ArgumentsElementsState(type));
|
||||
NodeProperties::SetType(arguments_elements_state, Type::OtherInternal());
|
||||
ReplaceWithValue(node, arguments_elements_state);
|
||||
|
||||
|
@ -530,7 +530,7 @@ size_t InstructionSelector::AddOperandToStateValueDescriptor(
|
||||
|
||||
switch (input->opcode()) {
|
||||
case IrOpcode::kArgumentsElementsState: {
|
||||
values->PushArgumentsElements(IsRestOf(input->op()));
|
||||
values->PushArgumentsElements(ArgumentsStateTypeOf(input->op()));
|
||||
// The elements backing store of an arguments object participates in the
|
||||
// duplicate object counting, but can itself never appear duplicated.
|
||||
DCHECK_EQ(StateObjectDeduplicator::kNotDuplicated,
|
||||
@ -539,7 +539,7 @@ size_t InstructionSelector::AddOperandToStateValueDescriptor(
|
||||
return 0;
|
||||
}
|
||||
case IrOpcode::kArgumentsLengthState: {
|
||||
values->PushArgumentsLength(IsRestOf(input->op()));
|
||||
values->PushArgumentsLength(ArgumentsStateTypeOf(input->op()));
|
||||
return 0;
|
||||
}
|
||||
case IrOpcode::kObjectState: {
|
||||
|
@ -1123,16 +1123,16 @@ class StateValueDescriptor {
|
||||
StateValueDescriptor()
|
||||
: kind_(StateValueKind::kPlain), type_(MachineType::AnyTagged()) {}
|
||||
|
||||
static StateValueDescriptor ArgumentsElements(bool is_rest) {
|
||||
static StateValueDescriptor ArgumentsElements(ArgumentsStateType type) {
|
||||
StateValueDescriptor descr(StateValueKind::kArgumentsElements,
|
||||
MachineType::AnyTagged());
|
||||
descr.is_rest_ = is_rest;
|
||||
descr.args_type_ = type;
|
||||
return descr;
|
||||
}
|
||||
static StateValueDescriptor ArgumentsLength(bool is_rest) {
|
||||
static StateValueDescriptor ArgumentsLength(ArgumentsStateType type) {
|
||||
StateValueDescriptor descr(StateValueKind::kArgumentsLength,
|
||||
MachineType::AnyTagged());
|
||||
descr.is_rest_ = is_rest;
|
||||
descr.args_type_ = type;
|
||||
return descr;
|
||||
}
|
||||
static StateValueDescriptor Plain(MachineType type) {
|
||||
@ -1171,10 +1171,10 @@ class StateValueDescriptor {
|
||||
kind_ == StateValueKind::kNested);
|
||||
return id_;
|
||||
}
|
||||
int is_rest() const {
|
||||
ArgumentsStateType arguments_type() const {
|
||||
DCHECK(kind_ == StateValueKind::kArgumentsElements ||
|
||||
kind_ == StateValueKind::kArgumentsLength);
|
||||
return is_rest_;
|
||||
return args_type_;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -1185,7 +1185,7 @@ class StateValueDescriptor {
|
||||
MachineType type_;
|
||||
union {
|
||||
size_t id_;
|
||||
bool is_rest_;
|
||||
ArgumentsStateType args_type_;
|
||||
};
|
||||
};
|
||||
|
||||
@ -1245,11 +1245,11 @@ class StateValueList {
|
||||
nested_.push_back(nested);
|
||||
return nested;
|
||||
}
|
||||
void PushArgumentsElements(bool is_rest) {
|
||||
fields_.push_back(StateValueDescriptor::ArgumentsElements(is_rest));
|
||||
void PushArgumentsElements(ArgumentsStateType type) {
|
||||
fields_.push_back(StateValueDescriptor::ArgumentsElements(type));
|
||||
}
|
||||
void PushArgumentsLength(bool is_rest) {
|
||||
fields_.push_back(StateValueDescriptor::ArgumentsLength(is_rest));
|
||||
void PushArgumentsLength(ArgumentsStateType type) {
|
||||
fields_.push_back(StateValueDescriptor::ArgumentsLength(type));
|
||||
}
|
||||
void PushDuplicate(size_t id) {
|
||||
fields_.push_back(StateValueDescriptor::Duplicate(id));
|
||||
|
@ -355,7 +355,7 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
|
||||
arguments_frame);
|
||||
// Allocate the elements backing store.
|
||||
Node* const elements = effect =
|
||||
graph()->NewNode(simplified()->NewUnmappedArgumentsElements(),
|
||||
graph()->NewNode(simplified()->NewArgumentsElements(0),
|
||||
arguments_frame, arguments_length, effect);
|
||||
// Load the arguments object map.
|
||||
Node* const arguments_map = jsgraph()->HeapConstant(
|
||||
@ -381,11 +381,11 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
|
||||
simplified()->ArgumentsLength(
|
||||
shared->internal_formal_parameter_count(), true),
|
||||
arguments_frame);
|
||||
// Allocate the elements backing store. Since
|
||||
// NewUnmappedArgumentsElements copies from the end of the arguments
|
||||
// adapter frame, this is a suffix of the actual arguments.
|
||||
// Allocate the elements backing store. Since NewArgumentsElements
|
||||
// copies from the end of the arguments adapter frame, this is a suffix
|
||||
// of the actual arguments.
|
||||
Node* const elements = effect =
|
||||
graph()->NewNode(simplified()->NewUnmappedArgumentsElements(),
|
||||
graph()->NewNode(simplified()->NewArgumentsElements(0),
|
||||
arguments_frame, rest_length, effect);
|
||||
// Load the JSArray object map.
|
||||
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.
|
||||
int parameter_count = shared->internal_formal_parameter_count();
|
||||
if (parameter_count == 0) {
|
||||
return graph()->NewNode(simplified()->NewUnmappedArgumentsElements(),
|
||||
return graph()->NewNode(simplified()->NewArgumentsElements(0),
|
||||
arguments_frame, arguments_length, effect);
|
||||
}
|
||||
|
||||
@ -1219,7 +1219,7 @@ 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 =
|
||||
graph()->NewNode(simplified()->NewMappedArgumentsElements(mapped_count),
|
||||
graph()->NewNode(simplified()->NewArgumentsElements(mapped_count),
|
||||
arguments_frame, arguments_length, effect);
|
||||
|
||||
// Actually allocate the backing store.
|
||||
|
@ -364,8 +364,7 @@
|
||||
V(ObjectIsUndetectable) \
|
||||
V(ArgumentsFrame) \
|
||||
V(ArgumentsLength) \
|
||||
V(NewMappedArgumentsElements) \
|
||||
V(NewUnmappedArgumentsElements) \
|
||||
V(NewArgumentsElements) \
|
||||
V(ArrayBufferWasNeutered) \
|
||||
V(EnsureWritableFastElements) \
|
||||
V(MaybeGrowFastElements) \
|
||||
|
@ -2739,8 +2739,7 @@ class RepresentationSelector {
|
||||
MachineRepresentation::kTaggedSigned);
|
||||
return;
|
||||
}
|
||||
case IrOpcode::kNewMappedArgumentsElements:
|
||||
case IrOpcode::kNewUnmappedArgumentsElements: {
|
||||
case IrOpcode::kNewArgumentsElements: {
|
||||
VisitBinop(node, UseInfo::PointerInt(), UseInfo::TaggedSigned(),
|
||||
MachineRepresentation::kTaggedPointer);
|
||||
return;
|
||||
|
@ -609,14 +609,6 @@ struct SimplifiedOperatorGlobalCache final {
|
||||
};
|
||||
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>
|
||||
struct ChangeFloat64ToTaggedOperator final
|
||||
: public Operator1<CheckForMinusZeroMode> {
|
||||
@ -789,7 +781,6 @@ GET_FROM_CACHE(ArgumentsFrame)
|
||||
GET_FROM_CACHE(LookupHashStorageIndex)
|
||||
GET_FROM_CACHE(LoadHashMapValue)
|
||||
GET_FROM_CACHE(LoadFieldByIndex)
|
||||
GET_FROM_CACHE(NewUnmappedArgumentsElements)
|
||||
#undef GET_FROM_CACHE
|
||||
|
||||
const Operator* SimplifiedOperatorBuilder::ChangeFloat64ToTagged(
|
||||
@ -976,14 +967,14 @@ bool IsRestLengthOf(const Operator* op) {
|
||||
return OpParameter<ArgumentsLengthParameters>(op).is_rest_length;
|
||||
}
|
||||
|
||||
const Operator* SimplifiedOperatorBuilder::NewMappedArgumentsElements(
|
||||
const Operator* SimplifiedOperatorBuilder::NewArgumentsElements(
|
||||
int mapped_count) {
|
||||
return new (zone()) Operator1<int>( // --
|
||||
IrOpcode::kNewMappedArgumentsElements, // opcode
|
||||
Operator::kEliminatable, // flags
|
||||
"NewMappedArgumentsElements", // name
|
||||
2, 1, 0, 1, 1, 0, // counts
|
||||
mapped_count); // parameter
|
||||
return new (zone()) Operator1<int>( // --
|
||||
IrOpcode::kNewArgumentsElements, // opcode
|
||||
Operator::kEliminatable, // flags
|
||||
"NewArgumentsElements", // name
|
||||
2, 1, 0, 1, 1, 0, // counts
|
||||
mapped_count); // parameter
|
||||
}
|
||||
|
||||
const Operator* SimplifiedOperatorBuilder::Allocate(Type* type,
|
||||
|
@ -450,11 +450,8 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
|
||||
const Operator* ArgumentsLength(int formal_parameter_count,
|
||||
bool is_rest_length);
|
||||
|
||||
// new-mapped-arguments-elements arguments-frame, arguments-length
|
||||
const Operator* NewMappedArgumentsElements(int mapped_count);
|
||||
|
||||
// new-unmapped-arguments-elements arguments-frame, arguments-length
|
||||
const Operator* NewUnmappedArgumentsElements();
|
||||
// new-arguments-elements arguments-frame, arguments-length
|
||||
const Operator* NewArgumentsElements(int mapped_count);
|
||||
|
||||
// array-buffer-was-neutered buffer
|
||||
const Operator* ArrayBufferWasNeutered();
|
||||
|
@ -2004,11 +2004,7 @@ Type* Typer::Visitor::TypeArgumentsFrame(Node* node) {
|
||||
return Type::ExternalPointer();
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::TypeNewMappedArgumentsElements(Node* node) {
|
||||
return Type::OtherInternal();
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::TypeNewUnmappedArgumentsElements(Node* node) {
|
||||
Type* Typer::Visitor::TypeNewArgumentsElements(Node* node) {
|
||||
return Type::OtherInternal();
|
||||
}
|
||||
|
||||
|
@ -1032,8 +1032,7 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
case IrOpcode::kArgumentsFrame:
|
||||
CheckTypeIs(node, Type::ExternalPointer());
|
||||
break;
|
||||
case IrOpcode::kNewMappedArgumentsElements:
|
||||
case IrOpcode::kNewUnmappedArgumentsElements:
|
||||
case IrOpcode::kNewArgumentsElements:
|
||||
CheckValueInputIs(node, 0, Type::ExternalPointer());
|
||||
CheckValueInputIs(node, 1, Type::Range(-Code::kMaxArguments,
|
||||
Code::kMaxArguments, zone));
|
||||
|
@ -2121,15 +2121,14 @@ void Translation::BeginInterpretedFrame(BailoutId bytecode_offset,
|
||||
buffer_->Add(height);
|
||||
}
|
||||
|
||||
|
||||
void Translation::ArgumentsElements(bool is_rest) {
|
||||
void Translation::ArgumentsElements(CreateArgumentsType type) {
|
||||
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(is_rest);
|
||||
buffer_->Add(static_cast<uint8_t>(type));
|
||||
}
|
||||
|
||||
void Translation::BeginCapturedObject(int length) {
|
||||
@ -2229,6 +2228,8 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
|
||||
case GETTER_STUB_FRAME:
|
||||
case SETTER_STUB_FRAME:
|
||||
case DUPLICATED_OBJECT:
|
||||
case ARGUMENTS_ELEMENTS:
|
||||
case ARGUMENTS_LENGTH:
|
||||
case CAPTURED_OBJECT:
|
||||
case REGISTER:
|
||||
case INT32_REGISTER:
|
||||
@ -2252,9 +2253,6 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
|
||||
case BUILTIN_CONTINUATION_FRAME:
|
||||
case JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME:
|
||||
return 3;
|
||||
case ARGUMENTS_ELEMENTS:
|
||||
case ARGUMENTS_LENGTH:
|
||||
return 1;
|
||||
}
|
||||
FATAL("Unexpected translation type");
|
||||
return -1;
|
||||
@ -3014,7 +3012,8 @@ void TranslatedFrame::AdvanceIterator(
|
||||
}
|
||||
|
||||
Address TranslatedState::ComputeArgumentsPosition(Address input_frame_pointer,
|
||||
bool is_rest, int* length) {
|
||||
CreateArgumentsType type,
|
||||
int* length) {
|
||||
Address parent_frame_pointer = *reinterpret_cast<Address*>(
|
||||
input_frame_pointer + StandardFrameConstants::kCallerFPOffset);
|
||||
intptr_t parent_frame_type = Memory::intptr_at(
|
||||
@ -3034,7 +3033,7 @@ Address TranslatedState::ComputeArgumentsPosition(Address 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
|
||||
// parameters, we have zero rest parameters.
|
||||
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
|
||||
// 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
|
||||
// created on-the-fly based on dynamic information in the optimized frame.
|
||||
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) {
|
||||
TranslatedFrame& frame = frames_[frame_index];
|
||||
|
||||
int length;
|
||||
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 value_index = static_cast<int>(frame.values_.size());
|
||||
if (trace_file != nullptr) {
|
||||
PrintF(trace_file,
|
||||
"arguments elements object #%d (is_rest = %d, length = %d)",
|
||||
object_index, is_rest, length);
|
||||
PrintF(trace_file, "arguments elements object #%d (type = %d, length = %d)",
|
||||
object_index, static_cast<uint8_t>(type), length);
|
||||
}
|
||||
object_positions_.push_back({frame_index, value_index});
|
||||
frame.Add(TranslatedValue::NewDeferredObject(
|
||||
@ -3071,7 +3069,17 @@ void TranslatedState::CreateArgumentsElementsTranslatedValues(
|
||||
TranslatedValue::NewTagged(this, isolate_->heap()->fixed_array_map()));
|
||||
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 +
|
||||
CommonFrameConstants::kFixedFrameSizeAboveFp +
|
||||
i * kPointerSize;
|
||||
@ -3124,19 +3132,21 @@ int TranslatedState::CreateNextTranslatedValue(
|
||||
}
|
||||
|
||||
case Translation::ARGUMENTS_ELEMENTS: {
|
||||
bool is_rest = iterator->Next();
|
||||
CreateArgumentsElementsTranslatedValues(frame_index, fp, is_rest,
|
||||
CreateArgumentsType arguments_type =
|
||||
static_cast<CreateArgumentsType>(iterator->Next());
|
||||
CreateArgumentsElementsTranslatedValues(frame_index, fp, arguments_type,
|
||||
trace_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case Translation::ARGUMENTS_LENGTH: {
|
||||
bool is_rest = iterator->Next();
|
||||
CreateArgumentsType arguments_type =
|
||||
static_cast<CreateArgumentsType>(iterator->Next());
|
||||
int length;
|
||||
ComputeArgumentsPosition(fp, is_rest, &length);
|
||||
ComputeArgumentsPosition(fp, arguments_type, &length);
|
||||
if (trace_file != nullptr) {
|
||||
PrintF(trace_file, "arguments length field (is_rest = %d, length = %d)",
|
||||
is_rest, length);
|
||||
PrintF(trace_file, "arguments length field (type = %d, length = %d)",
|
||||
static_cast<uint8_t>(arguments_type), length);
|
||||
}
|
||||
frame.Add(TranslatedValue::NewInt32(this, length));
|
||||
return 0;
|
||||
|
@ -281,11 +281,12 @@ class TranslatedState {
|
||||
int CreateNextTranslatedValue(int frame_index, TranslationIterator* iterator,
|
||||
FixedArray* literal_array, Address fp,
|
||||
RegisterValues* registers, FILE* trace_file);
|
||||
Address ComputeArgumentsPosition(Address input_frame_pointer, bool is_rest,
|
||||
int* length);
|
||||
Address ComputeArgumentsPosition(Address input_frame_pointer,
|
||||
CreateArgumentsType type, int* length);
|
||||
void CreateArgumentsElementsTranslatedValues(int frame_index,
|
||||
Address input_frame_pointer,
|
||||
bool is_rest, FILE* trace_file);
|
||||
CreateArgumentsType type,
|
||||
FILE* trace_file);
|
||||
|
||||
void UpdateFromPreviouslyMaterializedObjects();
|
||||
Handle<Object> MaterializeAt(int frame_index, int* value_index);
|
||||
@ -906,8 +907,8 @@ class Translation BASE_EMBEDDED {
|
||||
int literal_id, unsigned height);
|
||||
void BeginGetterStubFrame(int literal_id);
|
||||
void BeginSetterStubFrame(int literal_id);
|
||||
void ArgumentsElements(bool is_rest);
|
||||
void ArgumentsLength(bool is_rest);
|
||||
void ArgumentsElements(CreateArgumentsType type);
|
||||
void ArgumentsLength(CreateArgumentsType type);
|
||||
void BeginCapturedObject(int length);
|
||||
void DuplicateObject(int object_index);
|
||||
void StoreRegister(Register reg);
|
||||
|
@ -14460,8 +14460,9 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(
|
||||
|
||||
case Translation::ARGUMENTS_ELEMENTS:
|
||||
case Translation::ARGUMENTS_LENGTH: {
|
||||
bool is_rest = iterator.Next();
|
||||
os << "{is_rest=" << (is_rest ? "true" : "false") << "}";
|
||||
CreateArgumentsType arguments_type =
|
||||
static_cast<CreateArgumentsType>(iterator.Next());
|
||||
os << "{arguments_type=" << arguments_type << "}";
|
||||
break;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user