| Index: src/compiler/escape-analysis-reducer.cc
|
| diff --git a/src/compiler/escape-analysis-reducer.cc b/src/compiler/escape-analysis-reducer.cc
|
| index be772f4e7607796c58679f8064b060924278e5c6..7b6aeef1da131cba2e8c2923f7a7205519517441 100644
|
| --- a/src/compiler/escape-analysis-reducer.cc
|
| +++ b/src/compiler/escape-analysis-reducer.cc
|
| @@ -6,6 +6,8 @@
|
|
|
| #include "src/compiler/all-nodes.h"
|
| #include "src/compiler/js-graph.h"
|
| +#include "src/compiler/simplified-operator.h"
|
| +#include "src/compiler/type-cache.h"
|
| #include "src/counters.h"
|
|
|
| namespace v8 {
|
| @@ -86,6 +88,9 @@ Reduction EscapeAnalysisReducer::ReduceNode(Node* node) {
|
| }
|
| return NoChange();
|
| }
|
| + case IrOpcode::kNewUnmappedArgumentsElements:
|
| + arguments_elements_.insert(node);
|
| + // Fallthrough.
|
| default:
|
| // TODO(sigurds): Change this to GetFrameStateInputCount once
|
| // it is working. For now we use EffectInputCount > 0 to determine
|
| @@ -397,6 +402,96 @@ void EscapeAnalysisReducer::VerifyReplacement() const {
|
| #endif // DEBUG
|
| }
|
|
|
| +void EscapeAnalysisReducer::Finalize() {
|
| + for (Node* node : arguments_elements_) {
|
| + DCHECK(node->opcode() == IrOpcode::kNewUnmappedArgumentsElements);
|
| +
|
| + 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;
|
| +
|
| + bool escaping_use = false;
|
| + ZoneVector<Node*> loads(zone());
|
| + for (Edge edge : node->use_edges()) {
|
| + Node* use = edge.from();
|
| + if (!NodeProperties::IsValueEdge(edge)) continue;
|
| + switch (use->opcode()) {
|
| + case IrOpcode::kStateValues:
|
| + case IrOpcode::kTypedStateValues:
|
| + case IrOpcode::kObjectState:
|
| + case IrOpcode::kTypedObjectState:
|
| + break;
|
| + case IrOpcode::kLoadElement:
|
| + loads.push_back(use);
|
| + break;
|
| + case IrOpcode::kLoadField:
|
| + if (FieldAccessOf(use->op()).offset == FixedArray::kLengthOffset) {
|
| + loads.push_back(use);
|
| + break;
|
| + }
|
| + // Fallthrough.
|
| + default:
|
| + if (!use->use_edges().empty()) {
|
| + escaping_use = true;
|
| + break;
|
| + }
|
| + }
|
| + if (escaping_use) break;
|
| + }
|
| + if (!escaping_use) {
|
| + int formal_parameter_count =
|
| + FormalParameterCountOf(arguments_length->op());
|
| + int skipped_arguments =
|
| + IsRestLengthOf(arguments_length->op()) ? formal_parameter_count : 0;
|
| + Node* arguments_elements_state = jsgraph()->graph()->NewNode(
|
| + jsgraph()->common()->ArgumentsElementsState(skipped_arguments));
|
| + NodeProperties::SetType(arguments_elements_state, Type::OtherInternal());
|
| + ReplaceWithValue(node, arguments_elements_state);
|
| +
|
| + ElementAccess stack_access;
|
| + stack_access.base_is_tagged = BaseTaggedness::kUntaggedBase;
|
| + // Reduce base address by {kPointerSize} such that (length - index)
|
| + // resolves to the right position.
|
| + stack_access.header_size =
|
| + CommonFrameConstants::kFixedFrameSizeAboveFp - kPointerSize;
|
| + stack_access.type = Type::NonInternal();
|
| + stack_access.machine_type = MachineType::AnyTagged();
|
| + stack_access.write_barrier_kind = WriteBarrierKind::kNoWriteBarrier;
|
| + const Operator* load_stack_op =
|
| + jsgraph()->simplified()->LoadElement(stack_access);
|
| +
|
| + for (Node* load : loads) {
|
| + switch (load->opcode()) {
|
| + case IrOpcode::kLoadElement: {
|
| + Node* index = NodeProperties::GetValueInput(load, 1);
|
| + // {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);
|
| + NodeProperties::SetType(offset,
|
| + TypeCache::Get().kArgumentsLengthType);
|
| + NodeProperties::ReplaceValueInput(load, arguments_frame, 0);
|
| + NodeProperties::ReplaceValueInput(load, offset, 1);
|
| + NodeProperties::ChangeOp(load, load_stack_op);
|
| + break;
|
| + }
|
| + case IrOpcode::kLoadField: {
|
| + DCHECK_EQ(FieldAccessOf(load->op()).offset,
|
| + FixedArray::kLengthOffset);
|
| + Node* length = NodeProperties::GetValueInput(node, 1);
|
| + ReplaceWithValue(load, length);
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| } // namespace compiler
|
| } // namespace internal
|
| } // namespace v8
|
|
|