Index: src/builtins/builtins-internal.cc |
diff --git a/src/builtins/builtins-internal.cc b/src/builtins/builtins-internal.cc |
index a8c98bf0c15e4fff203754b8f6d7cefbc2da771c..39b1ca77695a6342bbbf6dd513054556312dc774 100644 |
--- a/src/builtins/builtins-internal.cc |
+++ b/src/builtins/builtins-internal.cc |
@@ -141,5 +141,175 @@ void Builtins::Generate_GrowFastSmiOrObjectElements( |
assembler.TailCallRuntime(Runtime::kGrowArrayElements, context, object, key); |
} |
+namespace { |
+ |
+void Generate_NewArgumentsElements(CodeStubAssembler* assembler, |
+ compiler::Node* frame, |
+ compiler::Node* length) { |
+ typedef CodeStubAssembler::Label Label; |
+ typedef CodeStubAssembler::Variable Variable; |
+ typedef compiler::Node Node; |
+ |
+ // Check if we can allocate in new space. |
+ ElementsKind kind = FAST_ELEMENTS; |
+ int max_elements = FixedArray::GetMaxLengthForNewSpaceAllocation(kind); |
+ Label if_newspace(assembler), if_oldspace(assembler, Label::kDeferred); |
+ assembler->Branch(assembler->IntPtrLessThan( |
+ length, assembler->IntPtrConstant(max_elements)), |
+ &if_newspace, &if_oldspace); |
+ |
+ assembler->Bind(&if_newspace); |
+ { |
+ // Prefer EmptyFixedArray in case of non-positive {length} (the {length} |
+ // can be negative here for rest parameters). |
+ Label if_empty(assembler), if_notempty(assembler); |
+ assembler->Branch( |
+ assembler->IntPtrLessThanOrEqual(length, assembler->IntPtrConstant(0)), |
+ &if_empty, &if_notempty); |
+ |
+ assembler->Bind(&if_empty); |
+ assembler->Return(assembler->EmptyFixedArrayConstant()); |
+ |
+ assembler->Bind(&if_notempty); |
+ { |
+ // Allocate a FixedArray in new space. |
+ Node* result = assembler->AllocateFixedArray( |
+ kind, length, CodeStubAssembler::INTPTR_PARAMETERS); |
+ |
+ // Compute the effective {offset} into the {frame}. |
+ Node* offset = assembler->IntPtrAdd(length, assembler->IntPtrConstant(1)); |
+ |
+ // Copy the parameters from {frame} (starting at {offset}) to {result}. |
+ Variable var_index(assembler, MachineType::PointerRepresentation()); |
+ Label loop(assembler, &var_index), done_loop(assembler); |
+ var_index.Bind(assembler->IntPtrConstant(0)); |
+ assembler->Goto(&loop); |
+ assembler->Bind(&loop); |
+ { |
+ // Load the current {index}. |
+ Node* index = var_index.value(); |
+ |
+ // Check if we are done. |
+ assembler->GotoIf(assembler->WordEqual(index, length), &done_loop); |
+ |
+ // Load the parameter at the given {index}. |
+ Node* value = assembler->Load( |
+ MachineType::AnyTagged(), frame, |
+ assembler->WordShl(assembler->IntPtrSub(offset, index), |
+ assembler->IntPtrConstant(kPointerSizeLog2))); |
+ |
+ // Store the {value} into the {result}. |
+ assembler->StoreFixedArrayElement(result, index, value, |
+ SKIP_WRITE_BARRIER, 0, |
+ CodeStubAssembler::INTPTR_PARAMETERS); |
+ |
+ // Continue with next {index}. |
+ var_index.Bind( |
+ assembler->IntPtrAdd(index, assembler->IntPtrConstant(1))); |
+ assembler->Goto(&loop); |
+ } |
+ |
+ assembler->Bind(&done_loop); |
+ assembler->Return(result); |
+ } |
+ } |
+ |
+ assembler->Bind(&if_oldspace); |
+ { |
+ // Allocate in old space (or large object space). |
+ assembler->TailCallRuntime( |
+ Runtime::kNewArgumentsElements, assembler->NoContextConstant(), |
+ assembler->BitcastWordToTagged(frame), assembler->SmiFromWord(length)); |
+ } |
+} |
+ |
+} // namespace |
+ |
+void Builtins::Generate_NewUnmappedArgumentsElements( |
+ compiler::CodeAssemblerState* state) { |
+ typedef CodeStubAssembler::Label Label; |
+ typedef CodeStubAssembler::Variable Variable; |
+ typedef compiler::Node Node; |
+ typedef NewArgumentsElementsDescriptor Descriptor; |
+ CodeStubAssembler assembler(state); |
+ |
+ Node* formal_parameter_count = |
+ assembler.Parameter(Descriptor::kFormalParameterCount); |
+ |
+ // Determine the frame that holds the parameters. |
+ Label done(&assembler); |
+ Variable var_frame(&assembler, MachineType::PointerRepresentation()), |
+ var_length(&assembler, MachineType::PointerRepresentation()); |
+ var_frame.Bind(assembler.LoadParentFramePointer()); |
+ var_length.Bind(formal_parameter_count); |
+ Node* parent_frame = assembler.Load( |
+ MachineType::Pointer(), var_frame.value(), |
+ assembler.IntPtrConstant(StandardFrameConstants::kCallerFPOffset)); |
+ Node* parent_frame_type = |
+ assembler.Load(MachineType::AnyTagged(), parent_frame, |
+ assembler.IntPtrConstant( |
+ CommonFrameConstants::kContextOrFrameTypeOffset)); |
+ assembler.GotoUnless( |
+ assembler.WordEqual( |
+ parent_frame_type, |
+ assembler.SmiConstant(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))), |
+ &done); |
+ { |
+ // Determine the length from the ArgumentsAdaptorFrame. |
+ Node* length = assembler.LoadAndUntagSmi( |
+ parent_frame, ArgumentsAdaptorFrameConstants::kLengthOffset); |
+ |
+ // Take the arguments from the ArgumentsAdaptorFrame. |
+ var_frame.Bind(parent_frame); |
+ var_length.Bind(length); |
+ } |
+ assembler.Goto(&done); |
+ |
+ // Allocate the actual FixedArray for the elements. |
+ assembler.Bind(&done); |
+ Generate_NewArgumentsElements(&assembler, var_frame.value(), |
+ var_length.value()); |
+} |
+ |
+void Builtins::Generate_NewRestParameterElements( |
+ compiler::CodeAssemblerState* state) { |
+ typedef CodeStubAssembler::Label Label; |
+ typedef compiler::Node Node; |
+ typedef NewArgumentsElementsDescriptor Descriptor; |
+ CodeStubAssembler assembler(state); |
+ |
+ Node* formal_parameter_count = |
+ assembler.Parameter(Descriptor::kFormalParameterCount); |
+ |
+ // Check if we have an ArgumentsAdaptorFrame, as we will only have rest |
+ // parameters in that case. |
+ Label if_empty(&assembler); |
+ Node* frame = assembler.Load( |
+ MachineType::Pointer(), assembler.LoadParentFramePointer(), |
+ assembler.IntPtrConstant(StandardFrameConstants::kCallerFPOffset)); |
+ Node* frame_type = |
+ assembler.Load(MachineType::AnyTagged(), frame, |
+ assembler.IntPtrConstant( |
+ CommonFrameConstants::kContextOrFrameTypeOffset)); |
+ assembler.GotoUnless( |
+ assembler.WordEqual(frame_type, assembler.SmiConstant(Smi::FromInt( |
+ StackFrame::ARGUMENTS_ADAPTOR))), |
+ &if_empty); |
+ |
+ // Determine the length from the ArgumentsAdaptorFrame. |
+ Node* frame_length = assembler.LoadAndUntagSmi( |
+ frame, ArgumentsAdaptorFrameConstants::kLengthOffset); |
+ |
+ // Compute the actual rest parameter length (may be negative). |
+ Node* length = assembler.IntPtrSub(frame_length, formal_parameter_count); |
+ |
+ // Allocate the actual FixedArray for the elements. |
+ Generate_NewArgumentsElements(&assembler, frame, length); |
+ |
+ // No rest parameters, return an empty FixedArray. |
+ assembler.Bind(&if_empty); |
+ assembler.Return(assembler.EmptyFixedArrayConstant()); |
+} |
+ |
} // namespace internal |
} // namespace v8 |