Commit e61ff991 authored by tebbi's avatar tebbi Committed by Commit bot

[turbofan] compute arguments length in deoptimizer

Following the design of https://codereview.chromium.org/2692753004, also compute the arguments length in the deoptimizer sucht that it does not have to be computed in optimized code.

R=bmeurer@chromium.org

Review-Url: https://codereview.chromium.org/2729163002
Cr-Commit-Position: refs/heads/master@{#43587}
parent b7944a5c
...@@ -702,6 +702,10 @@ void CodeGenerator::TranslateStateValueDescriptor( ...@@ -702,6 +702,10 @@ void CodeGenerator::TranslateStateValueDescriptor(
if (translation != nullptr) { if (translation != nullptr) {
translation->ArgumentsElements(desc->is_rest()); translation->ArgumentsElements(desc->is_rest());
} }
} else if (desc->IsArgumentsLength()) {
if (translation != nullptr) {
translation->ArgumentsLength(desc->is_rest());
}
} else if (desc->IsDuplicate()) { } else if (desc->IsDuplicate()) {
if (translation != nullptr) { if (translation != nullptr) {
translation->DuplicateObject(static_cast<int>(desc->id())); translation->DuplicateObject(static_cast<int>(desc->id()));
......
...@@ -1239,8 +1239,16 @@ const Operator* CommonOperatorBuilder::ArgumentsElementsState(bool is_rest) { ...@@ -1239,8 +1239,16 @@ const Operator* CommonOperatorBuilder::ArgumentsElementsState(bool is_rest) {
0, 0, 0, 1, 0, 0, is_rest); // counts 0, 0, 0, 1, 0, 0, is_rest); // counts
} }
const Operator* CommonOperatorBuilder::ArgumentsLengthState(bool is_rest) {
return new (zone()) Operator1<bool>( // --
IrOpcode::kArgumentsLengthState, Operator::kPure, // opcode
"ArgumentsLengthState", // name
0, 0, 0, 1, 0, 0, is_rest); // counts
}
bool IsRestOf(Operator const* op) { bool IsRestOf(Operator const* op) {
DCHECK(op->opcode() == IrOpcode::kArgumentsElementsState); DCHECK(op->opcode() == IrOpcode::kArgumentsElementsState ||
op->opcode() == IrOpcode::kArgumentsLengthState);
return OpParameter<bool>(op); return OpParameter<bool>(op);
} }
......
...@@ -297,9 +297,9 @@ SparseInputMask SparseInputMaskOf(Operator const*); ...@@ -297,9 +297,9 @@ SparseInputMask SparseInputMaskOf(Operator const*);
ZoneVector<MachineType> const* MachineTypesOf(Operator const*) ZoneVector<MachineType> const* MachineTypesOf(Operator const*)
WARN_UNUSED_RESULT; WARN_UNUSED_RESULT;
// The ArgumentsElementsState can either describe an unmapped arguments backing // The ArgumentsElementsState and ArgumentsLengthState can either describe an
// store or the backing store of the rest parameters. IsRestOf(op) is true in // unmapped arguments backing store or the backing store of the rest parameters.
// the second case. // IsRestOf(op) is true in the second case.
bool IsRestOf(Operator const*); bool IsRestOf(Operator const*);
// Interface for building common operators that can be used at any level of IR, // Interface for building common operators that can be used at any level of IR,
...@@ -368,6 +368,7 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final ...@@ -368,6 +368,7 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
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(bool is_rest);
const Operator* ArgumentsLengthState(bool is_rest);
const Operator* ObjectState(int pointer_slots); const Operator* ObjectState(int pointer_slots);
const Operator* TypedObjectState(const ZoneVector<MachineType>* types); const Operator* TypedObjectState(const ZoneVector<MachineType>* types);
const Operator* FrameState(BailoutId bailout_id, const Operator* FrameState(BailoutId bailout_id,
......
...@@ -411,6 +411,28 @@ void EscapeAnalysisReducer::Finalize() { ...@@ -411,6 +411,28 @@ void EscapeAnalysisReducer::Finalize() {
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;
Node* arguments_length_state = nullptr;
for (Edge edge : arguments_length->use_edges()) {
Node* use = edge.from();
switch (use->opcode()) {
case IrOpcode::kObjectState:
case IrOpcode::kTypedObjectState:
case IrOpcode::kStateValues:
case IrOpcode::kTypedStateValues:
if (!arguments_length_state) {
arguments_length_state = jsgraph()->graph()->NewNode(
jsgraph()->common()->ArgumentsLengthState(
IsRestLengthOf(arguments_length->op())));
NodeProperties::SetType(arguments_length_state,
Type::OtherInternal());
}
edge.UpdateTo(arguments_length_state);
break;
default:
break;
}
}
bool escaping_use = false; bool escaping_use = false;
ZoneVector<Node*> loads(zone()); ZoneVector<Node*> loads(zone());
for (Edge edge : node->use_edges()) { for (Edge edge : node->use_edges()) {
......
...@@ -454,6 +454,7 @@ InstructionOperand OperandForDeopt(Isolate* isolate, OperandGenerator* g, ...@@ -454,6 +454,7 @@ InstructionOperand OperandForDeopt(Isolate* isolate, OperandGenerator* g,
return g->UseImmediate(input); return g->UseImmediate(input);
} }
case IrOpcode::kArgumentsElementsState: case IrOpcode::kArgumentsElementsState:
case IrOpcode::kArgumentsLengthState:
case IrOpcode::kObjectState: case IrOpcode::kObjectState:
case IrOpcode::kTypedObjectState: case IrOpcode::kTypedObjectState:
UNREACHABLE(); UNREACHABLE();
...@@ -513,6 +514,10 @@ size_t InstructionSelector::AddOperandToStateValueDescriptor( ...@@ -513,6 +514,10 @@ size_t InstructionSelector::AddOperandToStateValueDescriptor(
values->PushArgumentsElements(IsRestOf(input->op())); values->PushArgumentsElements(IsRestOf(input->op()));
return 0; return 0;
} }
case IrOpcode::kArgumentsLengthState: {
values->PushArgumentsLength(IsRestOf(input->op()));
return 0;
}
case IrOpcode::kObjectState: { case IrOpcode::kObjectState: {
UNREACHABLE(); UNREACHABLE();
return 0; return 0;
......
...@@ -1126,6 +1126,7 @@ class FrameStateDescriptor; ...@@ -1126,6 +1126,7 @@ class FrameStateDescriptor;
enum class StateValueKind : uint8_t { enum class StateValueKind : uint8_t {
kArgumentsElements, kArgumentsElements,
kArgumentsLength,
kPlain, kPlain,
kOptimizedOut, kOptimizedOut,
kNested, kNested,
...@@ -1143,6 +1144,12 @@ class StateValueDescriptor { ...@@ -1143,6 +1144,12 @@ class StateValueDescriptor {
descr.is_rest_ = is_rest; descr.is_rest_ = is_rest;
return descr; return descr;
} }
static StateValueDescriptor ArgumentsLength(bool is_rest) {
StateValueDescriptor descr(StateValueKind::kArgumentsLength,
MachineType::AnyTagged());
descr.is_rest_ = is_rest;
return descr;
}
static StateValueDescriptor Plain(MachineType type) { static StateValueDescriptor Plain(MachineType type) {
return StateValueDescriptor(StateValueKind::kPlain, type); return StateValueDescriptor(StateValueKind::kPlain, type);
} }
...@@ -1166,6 +1173,9 @@ class StateValueDescriptor { ...@@ -1166,6 +1173,9 @@ class StateValueDescriptor {
bool IsArgumentsElements() const { bool IsArgumentsElements() const {
return kind_ == StateValueKind::kArgumentsElements; return kind_ == StateValueKind::kArgumentsElements;
} }
bool IsArgumentsLength() const {
return kind_ == StateValueKind::kArgumentsLength;
}
bool IsPlain() const { return kind_ == StateValueKind::kPlain; } bool IsPlain() const { return kind_ == StateValueKind::kPlain; }
bool IsOptimizedOut() const { return kind_ == StateValueKind::kOptimizedOut; } bool IsOptimizedOut() const { return kind_ == StateValueKind::kOptimizedOut; }
bool IsNested() const { return kind_ == StateValueKind::kNested; } bool IsNested() const { return kind_ == StateValueKind::kNested; }
...@@ -1177,7 +1187,8 @@ class StateValueDescriptor { ...@@ -1177,7 +1187,8 @@ class StateValueDescriptor {
return id_; return id_;
} }
int is_rest() const { int is_rest() const {
DCHECK(kind_ == StateValueKind::kArgumentsElements); DCHECK(kind_ == StateValueKind::kArgumentsElements ||
kind_ == StateValueKind::kArgumentsLength);
return is_rest_; return is_rest_;
} }
...@@ -1252,6 +1263,9 @@ class StateValueList { ...@@ -1252,6 +1263,9 @@ class StateValueList {
void PushArgumentsElements(bool is_rest) { void PushArgumentsElements(bool is_rest) {
fields_.push_back(StateValueDescriptor::ArgumentsElements(is_rest)); fields_.push_back(StateValueDescriptor::ArgumentsElements(is_rest));
} }
void PushArgumentsLength(bool is_rest) {
fields_.push_back(StateValueDescriptor::ArgumentsLength(is_rest));
}
void PushDuplicate(size_t id) { void PushDuplicate(size_t id) {
fields_.push_back(StateValueDescriptor::Duplicate(id)); fields_.push_back(StateValueDescriptor::Duplicate(id));
} }
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
V(StateValues) \ V(StateValues) \
V(TypedStateValues) \ V(TypedStateValues) \
V(ArgumentsElementsState) \ V(ArgumentsElementsState) \
V(ArgumentsLengthState) \
V(ObjectState) \ V(ObjectState) \
V(TypedObjectState) \ V(TypedObjectState) \
V(Call) \ V(Call) \
......
...@@ -2725,6 +2725,7 @@ class RepresentationSelector { ...@@ -2725,6 +2725,7 @@ class RepresentationSelector {
case IrOpcode::kProjection: case IrOpcode::kProjection:
case IrOpcode::kOsrValue: case IrOpcode::kOsrValue:
case IrOpcode::kArgumentsElementsState: case IrOpcode::kArgumentsElementsState:
case IrOpcode::kArgumentsLengthState:
// All JavaScript operators except JSToNumber have uniform handling. // All JavaScript operators except JSToNumber have uniform handling.
#define OPCODE_CASE(name) case IrOpcode::k##name: #define OPCODE_CASE(name) case IrOpcode::k##name:
JS_SIMPLE_BINOP_LIST(OPCODE_CASE) JS_SIMPLE_BINOP_LIST(OPCODE_CASE)
......
...@@ -848,6 +848,10 @@ Type* Typer::Visitor::TypeArgumentsElementsState(Node* node) { ...@@ -848,6 +848,10 @@ Type* Typer::Visitor::TypeArgumentsElementsState(Node* node) {
return Type::Internal(); return Type::Internal();
} }
Type* Typer::Visitor::TypeArgumentsLengthState(Node* node) {
return Type::Internal();
}
Type* Typer::Visitor::TypeObjectState(Node* node) { return Type::Internal(); } Type* Typer::Visitor::TypeObjectState(Node* node) { return Type::Internal(); }
Type* Typer::Visitor::TypeTypedObjectState(Node* node) { Type* Typer::Visitor::TypeTypedObjectState(Node* node) {
......
...@@ -498,6 +498,7 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -498,6 +498,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kStateValues: case IrOpcode::kStateValues:
case IrOpcode::kTypedStateValues: case IrOpcode::kTypedStateValues:
case IrOpcode::kArgumentsElementsState: case IrOpcode::kArgumentsElementsState:
case IrOpcode::kArgumentsLengthState:
case IrOpcode::kObjectState: case IrOpcode::kObjectState:
case IrOpcode::kTypedObjectState: case IrOpcode::kTypedObjectState:
// TODO(jarin): what are the constraints on these? // TODO(jarin): what are the constraints on these?
......
...@@ -2407,6 +2407,11 @@ void Translation::ArgumentsElements(bool is_rest) { ...@@ -2407,6 +2407,11 @@ void Translation::ArgumentsElements(bool is_rest) {
buffer_->Add(is_rest); buffer_->Add(is_rest);
} }
void Translation::ArgumentsLength(bool is_rest) {
buffer_->Add(ARGUMENTS_LENGTH);
buffer_->Add(is_rest);
}
void Translation::BeginCapturedObject(int length) { void Translation::BeginCapturedObject(int length) {
buffer_->Add(CAPTURED_OBJECT); buffer_->Add(CAPTURED_OBJECT);
buffer_->Add(length); buffer_->Add(length);
...@@ -2540,6 +2545,7 @@ int Translation::NumberOfOperandsFor(Opcode opcode) { ...@@ -2540,6 +2545,7 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
case CONSTRUCT_STUB_FRAME: case CONSTRUCT_STUB_FRAME:
return 3; return 3;
case ARGUMENTS_ELEMENTS: case ARGUMENTS_ELEMENTS:
case ARGUMENTS_LENGTH:
return 1; return 1;
} }
FATAL("Unexpected translation type"); FATAL("Unexpected translation type");
...@@ -3309,6 +3315,7 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame( ...@@ -3309,6 +3315,7 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
case Translation::DUPLICATED_OBJECT: case Translation::DUPLICATED_OBJECT:
case Translation::ARGUMENTS_OBJECT: case Translation::ARGUMENTS_OBJECT:
case Translation::ARGUMENTS_ELEMENTS: case Translation::ARGUMENTS_ELEMENTS:
case Translation::ARGUMENTS_LENGTH:
case Translation::CAPTURED_OBJECT: case Translation::CAPTURED_OBJECT:
case Translation::REGISTER: case Translation::REGISTER:
case Translation::INT32_REGISTER: case Translation::INT32_REGISTER:
...@@ -3344,38 +3351,48 @@ void TranslatedFrame::AdvanceIterator( ...@@ -3344,38 +3351,48 @@ void TranslatedFrame::AdvanceIterator(
} }
} }
// Creates translated values for an arguments backing store, or the backing Address TranslatedState::ComputeArgumentsPosition(Address input_frame_pointer,
// store for the rest parameters if {is_rest} is true. The TranslatedValue bool is_rest, int* length) {
// 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) {
TranslatedFrame& frame = frames_[frame_index];
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(
parent_frame_pointer + CommonFrameConstants::kContextOrFrameTypeOffset); parent_frame_pointer + CommonFrameConstants::kContextOrFrameTypeOffset);
int length;
Address arguments_frame; Address arguments_frame;
if (parent_frame_type == if (parent_frame_type ==
StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)) { StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)) {
length = Smi::cast(*reinterpret_cast<Object**>( if (length)
parent_frame_pointer + *length = Smi::cast(*reinterpret_cast<Object**>(
ArgumentsAdaptorFrameConstants::kLengthOffset)) parent_frame_pointer +
->value(); ArgumentsAdaptorFrameConstants::kLengthOffset))
->value();
arguments_frame = parent_frame_pointer; arguments_frame = parent_frame_pointer;
} else { } else {
length = formal_parameter_count_; if (length) *length = formal_parameter_count_;
arguments_frame = input_frame_pointer; arguments_frame = input_frame_pointer;
} }
if (is_rest) { if (is_rest) {
// 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.
length = std::max(0, length - formal_parameter_count_); if (length) *length = std::max(0, *length - formal_parameter_count_);
} }
return arguments_frame;
}
// Creates translated values for an arguments backing store, or the backing
// store for the rest parameters if {is_rest} is true. 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) {
TranslatedFrame& frame = frames_[frame_index];
int length;
Address arguments_frame =
ComputeArgumentsPosition(input_frame_pointer, is_rest, &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());
object_positions_.push_back({frame_index, value_index}); object_positions_.push_back({frame_index, value_index});
...@@ -3459,6 +3476,14 @@ int TranslatedState::CreateNextTranslatedValue( ...@@ -3459,6 +3476,14 @@ int TranslatedState::CreateNextTranslatedValue(
return 0; return 0;
} }
case Translation::ARGUMENTS_LENGTH: {
bool is_rest = iterator->Next();
int length;
ComputeArgumentsPosition(fp, is_rest, &length);
frame.Add(TranslatedValue::NewInt32(this, length));
return 0;
}
case Translation::CAPTURED_OBJECT: { case Translation::CAPTURED_OBJECT: {
int field_count = iterator->Next(); int field_count = iterator->Next();
int object_index = static_cast<int>(object_positions_.size()); int object_index = static_cast<int>(object_positions_.size());
......
...@@ -318,6 +318,8 @@ class TranslatedState { ...@@ -318,6 +318,8 @@ 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,
int* length);
void CreateArgumentsElementsTranslatedValues(int frame_index, void CreateArgumentsElementsTranslatedValues(int frame_index,
Address input_frame_pointer, Address input_frame_pointer,
bool is_rest); bool is_rest);
...@@ -935,6 +937,7 @@ class TranslationIterator BASE_EMBEDDED { ...@@ -935,6 +937,7 @@ class TranslationIterator BASE_EMBEDDED {
V(DUPLICATED_OBJECT) \ V(DUPLICATED_OBJECT) \
V(ARGUMENTS_OBJECT) \ V(ARGUMENTS_OBJECT) \
V(ARGUMENTS_ELEMENTS) \ V(ARGUMENTS_ELEMENTS) \
V(ARGUMENTS_LENGTH) \
V(CAPTURED_OBJECT) \ V(CAPTURED_OBJECT) \
V(REGISTER) \ V(REGISTER) \
V(INT32_REGISTER) \ V(INT32_REGISTER) \
...@@ -984,6 +987,7 @@ class Translation BASE_EMBEDDED { ...@@ -984,6 +987,7 @@ class Translation BASE_EMBEDDED {
void BeginSetterStubFrame(int literal_id); void BeginSetterStubFrame(int literal_id);
void BeginArgumentsObject(int args_length); void BeginArgumentsObject(int args_length);
void ArgumentsElements(bool is_rest); void ArgumentsElements(bool is_rest);
void ArgumentsLength(bool is_rest);
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);
......
...@@ -14479,7 +14479,8 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint( ...@@ -14479,7 +14479,8 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(
break; break;
} }
case Translation::ARGUMENTS_ELEMENTS: { case Translation::ARGUMENTS_ELEMENTS:
case Translation::ARGUMENTS_LENGTH: {
bool is_rest = iterator.Next(); bool is_rest = iterator.Next();
os << "{is_rest=" << (is_rest ? "true" : "false") << "}"; os << "{is_rest=" << (is_rest ? "true" : "false") << "}";
break; break;
......
...@@ -96,8 +96,8 @@ ...@@ -96,8 +96,8 @@
var rest = arguments; var rest = arguments;
for (var i = 0; i < rest.length; ++i) { for (var i = 0; i < rest.length; ++i) {
var j = i; var j = i;
if (rest.length % 15 == 0 && i == 10) j += rest.length; if (rest.length % 15 == 0 && i == 10) j += 10000;
sum += rest[j] || rest[j-rest.length]; sum += rest[j] || i+1;
} }
return sum; return sum;
}; };
...@@ -113,11 +113,10 @@ ...@@ -113,11 +113,10 @@
(function ArgumentsAccessSloppy () { (function ArgumentsAccessSloppy () {
function sum2(a,b,c) { function sum2(a,b,c) {
var sum = 0; var sum = 0;
var rest = arguments; for (var i = 0; i < arguments.length; ++i) {
for (var i = 0; i < rest.length; ++i) {
var j = i; var j = i;
if (rest.length % 15 == 0 && i == 10) j += rest.length; if (arguments.length % 15 == 0 && i == 10) j += 10000;
sum += rest[j] || rest[j-rest.length]; sum += arguments[j] || i+1;
} }
return sum; return sum;
}; };
...@@ -135,8 +134,8 @@ ...@@ -135,8 +134,8 @@
var sum = 0; var sum = 0;
for (var i = 0; i < rest.length; ++i) { for (var i = 0; i < rest.length; ++i) {
var j = i; var j = i;
if (rest.length % 15 == 0 && i == 10) j += rest.length; if (rest.length % 15 == 0 && i == 10) j += 10000;
sum += rest[j] || rest[j-rest.length]; sum += rest[j] || i+1;
} }
return sum; return sum;
}; };
...@@ -154,8 +153,8 @@ ...@@ -154,8 +153,8 @@
var sum = 0; var sum = 0;
for (var i = 0; i < rest.length; ++i) { for (var i = 0; i < rest.length; ++i) {
var j = i; var j = i;
if (rest.length % 15 == 0 && i == 10) j += rest.length; if (rest.length % 15 == 0 && i == 10) j += 10000;
sum += rest[j] || rest[j-rest.length]; sum += rest[j] || i+2;
} }
return sum; return sum;
}; };
...@@ -167,3 +166,18 @@ ...@@ -167,3 +166,18 @@
assertEquals(i*(i+1)/2-1, sum4(...args)); assertEquals(i*(i+1)/2-1, sum4(...args));
} }
})(); })();
(function ReadArguments () {
function read() {
if (arguments.length % 10 == 5) %DeoptimizeNow();
return arguments[arguments.length-1];
};
var args = []
for (var i = 1; i < 30; ++i) {
args.push(i);
if (i%10 == 0) %OptimizeFunctionOnNextCall(read);
assertEquals(i, read(...args));
}
})();
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