Index: src/compiler/js-typed-lowering.cc |
diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc |
index 06d2902020fc6e8308e4c18e8b3510758c6f2517..ab5631ddafbeda4e9e55bd2db15e8bbf1b30bd73 100644 |
--- a/src/compiler/js-typed-lowering.cc |
+++ b/src/compiler/js-typed-lowering.cc |
@@ -1127,6 +1127,20 @@ Reduction JSTypedLowering::ReduceJSLoadDynamicContext(Node* node) { |
} |
+namespace { |
+ |
+// Retrieves the frame state holding actual argument values. |
+Node* GetArgumentsFrameState(Node* frame_state) { |
+ Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput); |
+ FrameStateInfo outer_state_info = OpParameter<FrameStateInfo>(outer_state); |
+ return outer_state_info.type() == FrameStateType::kArgumentsAdaptor |
+ ? outer_state |
+ : frame_state; |
+} |
+ |
+} // namespace |
+ |
+ |
Reduction JSTypedLowering::ReduceJSCreateArguments(Node* node) { |
DCHECK_EQ(IrOpcode::kJSCreateArguments, node->opcode()); |
CreateArgumentsParameters const& p = CreateArgumentsParametersOf(node->op()); |
@@ -1162,6 +1176,55 @@ Reduction JSTypedLowering::ReduceJSCreateArguments(Node* node) { |
return Changed(node); |
} |
+ // Use inline allocation for all mapped arguments objects within inlined |
+ // (i.e. non-outermost) frames, independent of the object size. |
+ if (p.type() == CreateArgumentsParameters::kMappedArguments && |
+ outer_state->opcode() == IrOpcode::kFrameState) { |
+ Handle<SharedFunctionInfo> shared; |
+ if (!state_info.shared_info().ToHandle(&shared)) return NoChange(); |
+ Node* const callee = NodeProperties::GetValueInput(node, 0); |
+ Node* const effect = NodeProperties::GetEffectInput(node); |
+ Node* const control = NodeProperties::GetControlInput(node); |
+ Node* const context = NodeProperties::GetContextInput(node); |
+ // TODO(mstarzinger): Duplicate parameters are not handled yet. |
+ if (shared->has_duplicate_parameters()) return NoChange(); |
+ // 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 = GetArgumentsFrameState(frame_state); |
+ FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state); |
+ // Prepare element backing store to be used by arguments object. |
+ bool has_aliased_arguments = false; |
+ Node* const elements = AllocateAliasedArguments( |
+ effect, control, args_state, context, shared, &has_aliased_arguments); |
+ // 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( |
+ has_aliased_arguments ? Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX |
+ : Context::SLOPPY_ARGUMENTS_MAP_INDEX)), |
+ load_native_context, effect, control); |
+ // Actually allocate and initialize the arguments object. |
+ AllocationBuilder a(jsgraph(), effect, control); |
+ Node* properties = jsgraph()->EmptyFixedArrayConstant(); |
+ int length = args_state_info.parameter_count() - 1; // Minus receiver. |
+ STATIC_ASSERT(Heap::kSloppyArgumentsObjectSize == 5 * kPointerSize); |
+ a.Allocate(Heap::kSloppyArgumentsObjectSize); |
+ a.Store(AccessBuilder::ForMap(), load_arguments_map); |
+ a.Store(AccessBuilder::ForJSObjectProperties(), properties); |
+ a.Store(AccessBuilder::ForJSObjectElements(), elements); |
+ a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length)); |
+ a.Store(AccessBuilder::ForArgumentsCallee(), callee); |
+ RelaxControls(node); |
+ a.FinishAndChange(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 && |
@@ -1169,13 +1232,9 @@ Reduction JSTypedLowering::ReduceJSCreateArguments(Node* node) { |
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; |
+ Node* const args_state = GetArgumentsFrameState(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); |
@@ -1193,7 +1252,7 @@ Reduction JSTypedLowering::ReduceJSCreateArguments(Node* node) { |
load_native_context, effect, control); |
// Actually allocate and initialize the arguments object. |
AllocationBuilder a(jsgraph(), effect, control); |
- Handle<Object> properties = factory()->empty_fixed_array(); |
+ Node* properties = jsgraph()->EmptyFixedArrayConstant(); |
int length = args_state_info.parameter_count() - 1; // Minus receiver. |
STATIC_ASSERT(Heap::kStrictArgumentsObjectSize == 4 * kPointerSize); |
a.Allocate(Heap::kStrictArgumentsObjectSize); |
@@ -1879,20 +1938,76 @@ Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { |
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()); |
+ int argument_count = state_info.parameter_count() - 1; // Minus receiver. |
+ if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant(); |
+ |
+ // Prepare an iterator over argument values recorded in the frame state. |
Node* const parameters = frame_state->InputAt(kFrameStateParametersInput); |
StateValuesAccess parameters_access(parameters); |
auto paratemers_it = ++parameters_access.begin(); |
+ |
+ // Actually allocate the backing store. |
AllocationBuilder a(jsgraph(), effect, control); |
- a.AllocateArray(length, factory()->fixed_array_map()); |
- for (int i = 0; i < length; ++i, ++paratemers_it) { |
+ a.AllocateArray(argument_count, factory()->fixed_array_map()); |
+ for (int i = 0; i < argument_count; ++i, ++paratemers_it) { |
a.Store(AccessBuilder::ForFixedArraySlot(i), (*paratemers_it).node); |
} |
return a.Finish(); |
} |
+// Helper that allocates a FixedArray serving as a parameter map for values |
+// recorded in the given {frame_state}. Some elements map to slots within the |
+// given {context}. Serves as backing store for JSCreateArguments nodes. |
+Node* JSTypedLowering::AllocateAliasedArguments( |
+ Node* effect, Node* control, Node* frame_state, Node* context, |
+ Handle<SharedFunctionInfo> shared, bool* has_aliased_arguments) { |
+ FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); |
+ int argument_count = state_info.parameter_count() - 1; // Minus receiver. |
+ if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant(); |
+ |
+ // If there is no aliasing, the arguments object elements are not special in |
+ // any way, we can just return an unmapped backing store instead. |
+ int parameter_count = shared->internal_formal_parameter_count(); |
+ if (parameter_count == 0) { |
+ return AllocateArguments(effect, control, frame_state); |
+ } |
+ |
+ // Calculate number of argument values being aliased/mapped. |
+ int mapped_count = Min(argument_count, parameter_count); |
+ *has_aliased_arguments = true; |
+ |
+ // Prepare an iterator over argument values recorded in the frame state. |
+ Node* const parameters = frame_state->InputAt(kFrameStateParametersInput); |
+ StateValuesAccess parameters_access(parameters); |
+ auto paratemers_it = ++parameters_access.begin(); |
+ |
+ // The unmapped argument values recorded in the frame state are stored yet |
+ // another indirection away and then linked into the parameter map below, |
+ // whereas mapped argument values are replaced with a hole instead. |
+ AllocationBuilder aa(jsgraph(), effect, control); |
+ aa.AllocateArray(argument_count, factory()->fixed_array_map()); |
+ for (int i = 0; i < mapped_count; ++i, ++paratemers_it) { |
+ aa.Store(AccessBuilder::ForFixedArraySlot(i), jsgraph()->TheHoleConstant()); |
+ } |
+ for (int i = mapped_count; i < argument_count; ++i, ++paratemers_it) { |
+ aa.Store(AccessBuilder::ForFixedArraySlot(i), (*paratemers_it).node); |
+ } |
+ Node* arguments = aa.Finish(); |
+ |
+ // Actually allocate the backing store. |
+ AllocationBuilder a(jsgraph(), effect, control); |
+ a.AllocateArray(mapped_count + 2, factory()->sloppy_arguments_elements_map()); |
+ a.Store(AccessBuilder::ForFixedArraySlot(0), context); |
+ a.Store(AccessBuilder::ForFixedArraySlot(1), arguments); |
+ for (int i = 0; i < mapped_count; ++i) { |
+ int idx = Context::MIN_CONTEXT_SLOTS + parameter_count - 1 - i; |
+ a.Store(AccessBuilder::ForFixedArraySlot(i + 2), jsgraph()->Constant(idx)); |
+ } |
+ return a.Finish(); |
+} |
+ |
+ |
Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); } |