Commit 0af58d24 authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[turbofan] Lower unmapped arguments objects in inline frame.

This lowers JSCreateArguments nodes within inline (i.e. non-outermost)
frames that create "unmapped arguments objects" to inline allocations.

The arguments count as well as each value is statically known and can be
directly stored into the arguments object. Note that the object is still
context-dependent and the map is loaded from the current context. The
object size is not taken into account for now, we might want to limit it
later though to keep code size bounded.

R=jarin@chromium.org

Review URL: https://codereview.chromium.org/1412113004

Cr-Commit-Position: refs/heads/master@{#31550}
parent 3109e4d1
...@@ -130,6 +130,14 @@ FieldAccess AccessBuilder::ForStringLength(Zone* zone) { ...@@ -130,6 +130,14 @@ FieldAccess AccessBuilder::ForStringLength(Zone* zone) {
} }
// static
FieldAccess AccessBuilder::ForGlobalObjectNativeContext() {
FieldAccess access = {kTaggedBase, GlobalObject::kNativeContextOffset,
Handle<Name>(), Type::Any(), kMachAnyTagged};
return access;
}
// static // static
FieldAccess AccessBuilder::ForValue() { FieldAccess AccessBuilder::ForValue() {
FieldAccess access = {kTaggedBase, JSValue::kValueOffset, Handle<Name>(), FieldAccess access = {kTaggedBase, JSValue::kValueOffset, Handle<Name>(),
...@@ -138,6 +146,25 @@ FieldAccess AccessBuilder::ForValue() { ...@@ -138,6 +146,25 @@ FieldAccess AccessBuilder::ForValue() {
} }
// static
FieldAccess AccessBuilder::ForArgumentsLength() {
int offset =
JSObject::kHeaderSize + Heap::kArgumentsLengthIndex * kPointerSize;
FieldAccess access = {kTaggedBase, offset, Handle<Name>(), Type::Any(),
kMachAnyTagged};
return access;
}
// static
FieldAccess AccessBuilder::ForFixedArraySlot(size_t index) {
int offset = FixedArray::OffsetOfElementAt(static_cast<int>(index));
FieldAccess access = {kTaggedBase, offset, Handle<Name>(), Type::Any(),
kMachAnyTagged};
return access;
}
// static // static
FieldAccess AccessBuilder::ForContextSlot(size_t index) { FieldAccess AccessBuilder::ForContextSlot(size_t index) {
int offset = Context::kHeaderSize + static_cast<int>(index) * kPointerSize; int offset = Context::kHeaderSize + static_cast<int>(index) * kPointerSize;
......
...@@ -61,10 +61,19 @@ class AccessBuilder final : public AllStatic { ...@@ -61,10 +61,19 @@ class AccessBuilder final : public AllStatic {
// Provides access to String::length() field. // Provides access to String::length() field.
static FieldAccess ForStringLength(Zone* zone); static FieldAccess ForStringLength(Zone* zone);
// Provides access to GlobalObject::native_context() field.
static FieldAccess ForGlobalObjectNativeContext();
// Provides access to JSValue::value() field. // Provides access to JSValue::value() field.
static FieldAccess ForValue(); static FieldAccess ForValue();
// Provides access Context slots. // Provides access to arguments objects fields.
static FieldAccess ForArgumentsLength();
// Provides access to FixedArray slots.
static FieldAccess ForFixedArraySlot(size_t index);
// Provides access to Context slots.
static FieldAccess ForContextSlot(size_t index); static FieldAccess ForContextSlot(size_t index);
// Provides access to PropertyCell::value() field. // Provides access to PropertyCell::value() field.
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "src/compiler/node-matchers.h" #include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h" #include "src/compiler/node-properties.h"
#include "src/compiler/operator-properties.h" #include "src/compiler/operator-properties.h"
#include "src/compiler/state-values-utils.h"
#include "src/types.h" #include "src/types.h"
namespace v8 { namespace v8 {
...@@ -36,17 +37,15 @@ JSTypedLowering::JSTypedLowering(Editor* editor, JSGraph* jsgraph, Zone* zone) ...@@ -36,17 +37,15 @@ JSTypedLowering::JSTypedLowering(Editor* editor, JSGraph* jsgraph, Zone* zone)
// allocated object and also provides helpers for commonly allocated objects. // allocated object and also provides helpers for commonly allocated objects.
class AllocationBuilder final { class AllocationBuilder final {
public: public:
AllocationBuilder(JSGraph* jsgraph, SimplifiedOperatorBuilder* simplified, AllocationBuilder(JSGraph* jsgraph, Node* effect, Node* control)
Node* effect, Node* control)
: jsgraph_(jsgraph), : jsgraph_(jsgraph),
simplified_(simplified),
allocation_(nullptr), allocation_(nullptr),
effect_(effect), effect_(effect),
control_(control) {} control_(control) {}
// Primitive allocation of static size. // Primitive allocation of static size.
void Allocate(int size) { void Allocate(int size) {
effect_ = graph()->NewNode(jsgraph()->common()->BeginRegion(), effect_); effect_ = graph()->NewNode(common()->BeginRegion(), effect_);
allocation_ = graph()->NewNode( allocation_ = graph()->NewNode(
simplified()->Allocate(), jsgraph()->Constant(size), effect_, control_); simplified()->Allocate(), jsgraph()->Constant(size), effect_, control_);
effect_ = allocation_; effect_ = allocation_;
...@@ -71,22 +70,26 @@ class AllocationBuilder final { ...@@ -71,22 +70,26 @@ class AllocationBuilder final {
Store(access, jsgraph()->Constant(value)); Store(access, jsgraph()->Constant(value));
} }
void Finish(Node* node) { void FinishAndChange(Node* node) {
NodeProperties::SetType(allocation_, NodeProperties::GetType(node)); NodeProperties::SetType(allocation_, NodeProperties::GetType(node));
node->ReplaceInput(0, allocation_); node->ReplaceInput(0, allocation_);
node->ReplaceInput(1, effect_); node->ReplaceInput(1, effect_);
node->TrimInputCount(2); node->TrimInputCount(2);
NodeProperties::ChangeOp(node, jsgraph()->common()->FinishRegion()); NodeProperties::ChangeOp(node, common()->FinishRegion());
}
Node* Finish() {
return graph()->NewNode(common()->FinishRegion(), allocation_, effect_);
} }
protected: protected:
JSGraph* jsgraph() { return jsgraph_; } JSGraph* jsgraph() { return jsgraph_; }
Graph* graph() { return jsgraph_->graph(); } Graph* graph() { return jsgraph_->graph(); }
SimplifiedOperatorBuilder* simplified() { return simplified_; } CommonOperatorBuilder* common() { return jsgraph_->common(); }
SimplifiedOperatorBuilder* simplified() { return jsgraph_->simplified(); }
private: private:
JSGraph* const jsgraph_; JSGraph* const jsgraph_;
SimplifiedOperatorBuilder* simplified_;
Node* allocation_; Node* allocation_;
Node* effect_; Node* effect_;
Node* control_; Node* control_;
...@@ -1159,6 +1162,50 @@ Reduction JSTypedLowering::ReduceJSCreateArguments(Node* node) { ...@@ -1159,6 +1162,50 @@ Reduction JSTypedLowering::ReduceJSCreateArguments(Node* node) {
return Changed(node); return Changed(node);
} }
// Use inline allocation for all unmapped arguments objects within inlined
// (i.e. non-outermost) frames, independent of the object size.
if (p.type() == CreateArgumentsParameters::kUnmappedArguments &&
outer_state->opcode() == IrOpcode::kFrameState) {
Node* const effect = NodeProperties::GetEffectInput(node);
Node* const control = NodeProperties::GetControlInput(node);
Node* const context = NodeProperties::GetContextInput(node);
FrameStateInfo outer_state_info = OpParameter<FrameStateInfo>(outer_state);
// Choose the correct frame state and frame state info depending on whether
// there conceptually is an arguments adaptor frame in the call chain.
Node* const args_state =
outer_state_info.type() == FrameStateType::kArgumentsAdaptor
? outer_state
: frame_state;
FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
// Prepare element backing store to be used by arguments object.
Node* const elements = AllocateArguments(effect, control, args_state);
// Load the arguments object map from the current native context.
Node* const load_global_object = graph()->NewNode(
simplified()->LoadField(
AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)),
context, effect, control);
Node* const load_native_context = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForGlobalObjectNativeContext()),
load_global_object, effect, control);
Node* const load_arguments_map = graph()->NewNode(
simplified()->LoadField(
AccessBuilder::ForContextSlot(Context::STRICT_ARGUMENTS_MAP_INDEX)),
load_native_context, effect, control);
// Actually allocate and initialize the arguments object.
AllocationBuilder a(jsgraph(), effect, control);
Handle<Object> properties = factory()->empty_fixed_array();
int length = args_state_info.parameter_count() - 1; // Minus receiver.
STATIC_ASSERT(Heap::kStrictArgumentsObjectSize == 4 * kPointerSize);
a.Allocate(Heap::kStrictArgumentsObjectSize);
a.Store(AccessBuilder::ForMap(), load_arguments_map);
a.Store(AccessBuilder::ForJSObjectProperties(), properties);
a.Store(AccessBuilder::ForJSObjectElements(), elements);
a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
RelaxControls(node);
a.FinishAndChange(node);
return Changed(node);
}
return NoChange(); return NoChange();
} }
...@@ -1270,7 +1317,7 @@ Reduction JSTypedLowering::ReduceJSCreateFunctionContext(Node* node) { ...@@ -1270,7 +1317,7 @@ Reduction JSTypedLowering::ReduceJSCreateFunctionContext(Node* node) {
simplified()->LoadField( simplified()->LoadField(
AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)), AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)),
context, effect, control); context, effect, control);
AllocationBuilder a(jsgraph(), simplified(), effect, control); AllocationBuilder a(jsgraph(), effect, control);
STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
int context_length = slot_count + Context::MIN_CONTEXT_SLOTS; int context_length = slot_count + Context::MIN_CONTEXT_SLOTS;
a.AllocateArray(context_length, factory()->function_context_map()); a.AllocateArray(context_length, factory()->function_context_map());
...@@ -1282,7 +1329,7 @@ Reduction JSTypedLowering::ReduceJSCreateFunctionContext(Node* node) { ...@@ -1282,7 +1329,7 @@ Reduction JSTypedLowering::ReduceJSCreateFunctionContext(Node* node) {
a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant()); a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
} }
RelaxControls(node); RelaxControls(node);
a.Finish(node); a.FinishAndChange(node);
return Changed(node); return Changed(node);
} }
...@@ -1325,7 +1372,7 @@ Reduction JSTypedLowering::ReduceJSCreateWithContext(Node* node) { ...@@ -1325,7 +1372,7 @@ Reduction JSTypedLowering::ReduceJSCreateWithContext(Node* node) {
simplified()->LoadField( simplified()->LoadField(
AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)), AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)),
context, effect, control); context, effect, control);
AllocationBuilder a(jsgraph(), simplified(), effect, control); AllocationBuilder a(jsgraph(), effect, control);
STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
a.AllocateArray(Context::MIN_CONTEXT_SLOTS, factory()->with_context_map()); a.AllocateArray(Context::MIN_CONTEXT_SLOTS, factory()->with_context_map());
a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure); a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
...@@ -1333,7 +1380,7 @@ Reduction JSTypedLowering::ReduceJSCreateWithContext(Node* node) { ...@@ -1333,7 +1380,7 @@ Reduction JSTypedLowering::ReduceJSCreateWithContext(Node* node) {
a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), input); a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), input);
a.Store(AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX), load); a.Store(AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX), load);
RelaxControls(node); RelaxControls(node);
a.Finish(node); a.FinishAndChange(node);
return Changed(node); return Changed(node);
} }
...@@ -1363,7 +1410,7 @@ Reduction JSTypedLowering::ReduceJSCreateBlockContext(Node* node) { ...@@ -1363,7 +1410,7 @@ Reduction JSTypedLowering::ReduceJSCreateBlockContext(Node* node) {
simplified()->LoadField( simplified()->LoadField(
AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)), AccessBuilder::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)),
context, effect, control); context, effect, control);
AllocationBuilder a(jsgraph(), simplified(), effect, control); AllocationBuilder a(jsgraph(), effect, control);
STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
a.AllocateArray(context_length, factory()->block_context_map()); a.AllocateArray(context_length, factory()->block_context_map());
a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure); a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
...@@ -1374,7 +1421,7 @@ Reduction JSTypedLowering::ReduceJSCreateBlockContext(Node* node) { ...@@ -1374,7 +1421,7 @@ Reduction JSTypedLowering::ReduceJSCreateBlockContext(Node* node) {
a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->TheHoleConstant()); a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->TheHoleConstant());
} }
RelaxControls(node); RelaxControls(node);
a.Finish(node); a.FinishAndChange(node);
return Changed(node); return Changed(node);
} }
...@@ -1813,6 +1860,25 @@ Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { ...@@ -1813,6 +1860,25 @@ Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) {
} }
// Helper that allocates a FixedArray holding argument values recorded in the
// given {frame_state}. Serves as backing store for JSCreateArguments nodes.
Node* JSTypedLowering::AllocateArguments(Node* effect, Node* control,
Node* frame_state) {
FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
int length = state_info.parameter_count() - 1; // Minus receiver argument.
if (length == 0) return jsgraph()->Constant(factory()->empty_fixed_array());
Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
StateValuesAccess parameters_access(parameters);
auto paratemers_it = ++parameters_access.begin();
AllocationBuilder a(jsgraph(), effect, control);
a.AllocateArray(length, factory()->fixed_array_map());
for (int i = 0; i < length; ++i, ++paratemers_it) {
a.Store(AccessBuilder::ForFixedArraySlot(i), (*paratemers_it).node);
}
return a.Finish();
}
Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); } Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
......
...@@ -74,6 +74,7 @@ class JSTypedLowering final : public AdvancedReducer { ...@@ -74,6 +74,7 @@ class JSTypedLowering final : public AdvancedReducer {
const Operator* shift_op); const Operator* shift_op);
Node* Word32Shl(Node* const lhs, int32_t const rhs); Node* Word32Shl(Node* const lhs, int32_t const rhs);
Node* AllocateArguments(Node* effect, Node* control, Node* frame_state);
Factory* factory() const; Factory* factory() const;
Graph* graph() const; Graph* graph() const;
......
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