| Index: src/compiler/escape-analysis-reducer.cc
|
| diff --git a/src/compiler/escape-analysis-reducer.cc b/src/compiler/escape-analysis-reducer.cc
|
| index c05092e06ea95f71ef958c121990df06254834e6..59ad39bd4218c0ac492dbc93e74da2e078a65f5a 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 {
|
| @@ -84,6 +86,9 @@ Reduction EscapeAnalysisReducer::ReduceNode(Node* node) {
|
| }
|
| return NoChange();
|
| }
|
| + case IrOpcode::kNewUnmappedArgumentsElements:
|
| + arguments_elements_.insert(node);
|
| + break;
|
| default:
|
| // TODO(sigurds): Change this to GetFrameStateInputCount once
|
| // it is working. For now we use EffectInputCount > 0 to determine
|
| @@ -380,6 +385,98 @@ 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;
|
| + if (use->use_edges().empty()) {
|
| + // A node without uses is dead, so we don't have to care about it.
|
| + 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);
|
| + } else {
|
| + escaping_use = true;
|
| + }
|
| + break;
|
| + default:
|
| + // If the arguments elements node node is used by an unhandled node,
|
| + // then we cannot remove this allocation.
|
| + escaping_use = true;
|
| + break;
|
| + }
|
| + if (escaping_use) break;
|
| + }
|
| + if (!escaping_use) {
|
| + Node* arguments_elements_state = jsgraph()->graph()->NewNode(
|
| + jsgraph()->common()->ArgumentsElementsState(
|
| + IsRestLengthOf(arguments_length->op())));
|
| + 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
|
|
|