Index: src/compiler/js-typed-lowering.cc |
diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc |
index 3b487eefc229f9b70ff8b3aa177f041ca25bf105..7dbb1814cb94dc03de7a65831cc2d0dbbdac331f 100644 |
--- a/src/compiler/js-typed-lowering.cc |
+++ b/src/compiler/js-typed-lowering.cc |
@@ -1514,115 +1514,171 @@ Reduction JSTypedLowering::ReduceJSCreateArguments(Node* node) { |
// Use the ArgumentsAccessStub for materializing both mapped and unmapped |
// arguments object, but only for non-inlined (i.e. outermost) frames. |
- if (p.type() != CreateArgumentsParameters::kRestArray && |
- outer_state->opcode() != IrOpcode::kFrameState) { |
+ if (outer_state->opcode() != IrOpcode::kFrameState) { |
Handle<SharedFunctionInfo> shared; |
Isolate* isolate = jsgraph()->isolate(); |
if (!state_info.shared_info().ToHandle(&shared)) return NoChange(); |
- bool unmapped = p.type() == CreateArgumentsParameters::kUnmappedArguments; |
- Callable callable = CodeFactory::ArgumentsAccess( |
- isolate, unmapped, shared->has_duplicate_parameters()); |
- CallDescriptor* desc = Linkage::GetStubCallDescriptor( |
- isolate, graph()->zone(), callable.descriptor(), 0, |
- CallDescriptor::kNeedsFrameState); |
- const Operator* new_op = common()->Call(desc); |
+ |
int parameter_count = state_info.parameter_count() - 1; |
int parameter_offset = parameter_count * kPointerSize; |
int offset = StandardFrameConstants::kCallerSPOffset + parameter_offset; |
- Node* stub_code = jsgraph()->HeapConstant(callable.code()); |
Node* parameter_pointer = graph()->NewNode( |
machine()->IntAdd(), graph()->NewNode(machine()->LoadFramePointer()), |
jsgraph()->IntPtrConstant(offset)); |
- node->InsertInput(graph()->zone(), 0, stub_code); |
- node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(parameter_count)); |
- node->InsertInput(graph()->zone(), 3, parameter_pointer); |
- NodeProperties::ChangeOp(node, new_op); |
- 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); |
- Node* allocate_effect = |
- elements->op()->EffectOutputCount() > 0 ? elements : effect; |
- // Load the arguments object map from the current native context. |
- Node* const load_native_context = graph()->NewNode( |
- javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), |
- context, context, effect); |
- 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(), allocate_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 && |
- outer_state->opcode() == IrOpcode::kFrameState) { |
- Node* const effect = NodeProperties::GetEffectInput(node); |
- Node* const control = NodeProperties::GetControlInput(node); |
- Node* const context = NodeProperties::GetContextInput(node); |
- // 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. |
- Node* const elements = AllocateArguments(effect, control, args_state); |
- Node* allocate_effect = |
- elements->op()->EffectOutputCount() > 0 ? elements : effect; |
- // Load the arguments object map from the current native context. |
- Node* const load_native_context = graph()->NewNode( |
- javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), |
- context, context, effect); |
- 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(), allocate_effect, control); |
- Node* properties = jsgraph()->EmptyFixedArrayConstant(); |
- 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); |
+ if (p.type() != CreateArgumentsParameters::kRestArray) { |
+ bool unmapped = p.type() == CreateArgumentsParameters::kUnmappedArguments; |
+ Callable callable = CodeFactory::ArgumentsAccess( |
+ isolate, unmapped, shared->has_duplicate_parameters()); |
+ CallDescriptor* desc = Linkage::GetStubCallDescriptor( |
+ isolate, graph()->zone(), callable.descriptor(), 0, |
+ CallDescriptor::kNeedsFrameState); |
+ const Operator* new_op = common()->Call(desc); |
+ Node* stub_code = jsgraph()->HeapConstant(callable.code()); |
+ node->InsertInput(graph()->zone(), 0, stub_code); |
+ node->InsertInput(graph()->zone(), 2, |
+ jsgraph()->Constant(parameter_count)); |
+ node->InsertInput(graph()->zone(), 3, parameter_pointer); |
+ NodeProperties::ChangeOp(node, new_op); |
+ return Changed(node); |
+ } else { |
+ Callable callable = CodeFactory::RestArgumentsAccess(isolate); |
+ CallDescriptor* desc = Linkage::GetStubCallDescriptor( |
+ isolate, graph()->zone(), callable.descriptor(), 0, |
+ CallDescriptor::kNeedsFrameState); |
+ const Operator* new_op = common()->Call(desc); |
+ Node* stub_code = jsgraph()->HeapConstant(callable.code()); |
+ node->InsertInput(graph()->zone(), 0, stub_code); |
+ node->ReplaceInput(1, jsgraph()->Constant(parameter_count)); |
+ node->InsertInput(graph()->zone(), 2, parameter_pointer); |
+ node->InsertInput(graph()->zone(), 3, |
+ jsgraph()->Constant(p.start_index())); |
+ node->InsertInput(graph()->zone(), 4, |
+ jsgraph()->Constant(shared->language_mode())); |
+ NodeProperties::ChangeOp(node, new_op); |
+ return Changed(node); |
+ } |
+ } else if (outer_state->opcode() == IrOpcode::kFrameState) { |
+ // 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) { |
+ Handle<SharedFunctionInfo> shared; |
+ if (!state_info.shared_info().ToHandle(&shared)) return NoChange(); |
+ Node* const callee = NodeProperties::GetValueInput(node, 0); |
+ Node* const control = NodeProperties::GetControlInput(node); |
+ Node* const context = NodeProperties::GetContextInput(node); |
+ Node* effect = NodeProperties::GetEffectInput(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); |
+ effect = elements->op()->EffectOutputCount() > 0 ? elements : effect; |
+ // Load the arguments object map from the current native context. |
+ Node* const load_native_context = effect = graph()->NewNode( |
+ javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), |
+ context, context, effect); |
+ Node* const load_arguments_map = effect = 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); |
+ } else if (p.type() == CreateArgumentsParameters::kUnmappedArguments) { |
+ // Use inline allocation for all unmapped arguments objects within inlined |
+ // (i.e. non-outermost) frames, independent of the object size. |
+ Node* const control = NodeProperties::GetControlInput(node); |
+ Node* const context = NodeProperties::GetContextInput(node); |
+ Node* effect = NodeProperties::GetEffectInput(node); |
+ // 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. |
+ Node* const elements = AllocateArguments(effect, control, args_state); |
+ effect = elements->op()->EffectOutputCount() > 0 ? elements : effect; |
+ // Load the arguments object map from the current native context. |
+ Node* const load_native_context = effect = graph()->NewNode( |
+ javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), |
+ context, context, effect); |
+ Node* const load_arguments_map = effect = 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); |
+ Node* properties = jsgraph()->EmptyFixedArrayConstant(); |
+ 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); |
+ } else if (p.type() == CreateArgumentsParameters::kRestArray) { |
+ // Use inline allocation for all unmapped arguments objects within inlined |
+ // (i.e. non-outermost) frames, independent of the object size. |
+ Node* const control = NodeProperties::GetControlInput(node); |
+ Node* const context = NodeProperties::GetContextInput(node); |
+ Node* effect = NodeProperties::GetEffectInput(node); |
+ // 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 the rest array. |
+ Node* const elements = |
+ AllocateRestArguments(effect, control, args_state, p.start_index()); |
+ effect = elements->op()->EffectOutputCount() > 0 ? elements : effect; |
+ // Load the JSArray object map from the current native context. |
+ Node* const load_native_context = effect = graph()->NewNode( |
+ javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), |
+ context, context, effect); |
+ Node* const load_jsarray_map = effect = graph()->NewNode( |
+ simplified()->LoadField(AccessBuilder::ForContextSlot( |
+ Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX)), |
+ load_native_context, effect, control); |
+ // Actually allocate and initialize the jsarray. |
+ AllocationBuilder a(jsgraph(), effect, control); |
+ Node* properties = jsgraph()->EmptyFixedArrayConstant(); |
+ |
+ // -1 to minus receiver |
+ int argument_count = args_state_info.parameter_count() - 1; |
+ int length = std::max(0, argument_count - p.start_index()); |
+ STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); |
+ a.Allocate(JSArray::kSize); |
+ a.Store(AccessBuilder::ForMap(), load_jsarray_map); |
+ a.Store(AccessBuilder::ForJSObjectProperties(), properties); |
+ a.Store(AccessBuilder::ForJSObjectElements(), elements); |
+ a.Store(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS), |
+ jsgraph()->Constant(length)); |
+ RelaxControls(node); |
+ a.FinishAndChange(node); |
+ return Changed(node); |
+ } |
} |
return NoChange(); |
@@ -2648,13 +2704,43 @@ Node* JSTypedLowering::AllocateArguments(Node* effect, Node* control, |
// 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(); |
+ auto parameters_it = ++parameters_access.begin(); |
// Actually allocate the backing store. |
AllocationBuilder a(jsgraph(), effect, control); |
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); |
+ for (int i = 0; i < argument_count; ++i, ++parameters_it) { |
+ a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node); |
+ } |
+ return a.Finish(); |
+} |
+ |
+ |
+// Helper that allocates a FixedArray holding argument values recorded in the |
+// given {frame_state}. Serves as backing store for JSCreateArguments nodes. |
+Node* JSTypedLowering::AllocateRestArguments(Node* effect, Node* control, |
+ Node* frame_state, |
+ int start_index) { |
+ FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); |
+ int argument_count = state_info.parameter_count() - 1; // Minus receiver. |
+ int num_elements = std::max(0, argument_count - start_index); |
+ if (num_elements == 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 parameters_it = ++parameters_access.begin(); |
+ |
+ // Skip unused arguments. |
+ for (int i = 0; i < start_index; i++) { |
+ ++parameters_it; |
+ } |
+ |
+ // Actually allocate the backing store. |
+ AllocationBuilder a(jsgraph(), effect, control); |
+ a.AllocateArray(num_elements, factory()->fixed_array_map()); |
+ for (int i = 0; i < num_elements; ++i, ++parameters_it) { |
+ a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node); |
} |
return a.Finish(); |
} |