| Index: src/mips64/builtins-mips64.cc
 | 
| diff --git a/src/mips64/builtins-mips64.cc b/src/mips64/builtins-mips64.cc
 | 
| index 53246335b7b73feb3f9863738ddce5235555105d..0fb0e6d3a54f7e06b6ae5388006709cd02d85d09 100644
 | 
| --- a/src/mips64/builtins-mips64.cc
 | 
| +++ b/src/mips64/builtins-mips64.cc
 | 
| @@ -1359,49 +1359,99 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
 | 
| -  const int kIndexOffset    =
 | 
| -      StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
 | 
| -  const int kLimitOffset    =
 | 
| -      StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
 | 
| -  const int kArgsOffset     = 2 * kPointerSize;
 | 
| -  const int kRecvOffset     = 3 * kPointerSize;
 | 
| -  const int kFunctionOffset = 4 * kPointerSize;
 | 
| +static void Generate_CheckStackOverflow(MacroAssembler* masm,
 | 
| +                                        const int calleeOffset) {
 | 
| +  // Check the stack for overflow. We are not trying to catch
 | 
| +  // interruptions (e.g. debug break and preemption) here, so the "real stack
 | 
| +  // limit" is checked.
 | 
| +  Label okay;
 | 
| +  __ LoadRoot(a2, Heap::kRealStackLimitRootIndex);
 | 
| +  // Make a2 the space we have left. The stack might already be overflowed
 | 
| +  // here which will cause a2 to become negative.
 | 
| +  __ dsubu(a2, sp, a2);
 | 
| +  // Check if the arguments will overflow the stack.
 | 
| +  __ SmiScale(a7, v0, kPointerSizeLog2);
 | 
| +  __ Branch(&okay, gt, a2, Operand(a7));  // Signed comparison.
 | 
| +
 | 
| +  // Out of stack space.
 | 
| +  __ ld(a1, MemOperand(fp, calleeOffset));
 | 
| +  __ Push(a1, v0);
 | 
| +  __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
 | 
| +
 | 
| +  __ bind(&okay);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +static void Generate_PushAppliedArguments(MacroAssembler* masm,
 | 
| +                                          const int argumentsOffset,
 | 
| +                                          const int indexOffset,
 | 
| +                                          const int limitOffset) {
 | 
| +  Label entry, loop;
 | 
| +  __ ld(a0, MemOperand(fp, indexOffset));
 | 
| +  __ Branch(&entry);
 | 
| +
 | 
| +  // Load the current argument from the arguments array and push it to the
 | 
| +  // stack.
 | 
| +  // a0: current argument index
 | 
| +  __ bind(&loop);
 | 
| +  __ ld(a1, MemOperand(fp, argumentsOffset));
 | 
| +  __ Push(a1, a0);
 | 
| +
 | 
| +  // Call the runtime to access the property in the arguments array.
 | 
| +  __ CallRuntime(Runtime::kGetProperty, 2);
 | 
| +  __ push(v0);
 | 
| +
 | 
| +  // Use inline caching to access the arguments.
 | 
| +  __ ld(a0, MemOperand(fp, indexOffset));
 | 
| +  __ Daddu(a0, a0, Operand(Smi::FromInt(1)));
 | 
| +  __ sd(a0, MemOperand(fp, indexOffset));
 | 
| +
 | 
| +  // Test if the copy loop has finished copying all the elements from the
 | 
| +  // arguments object.
 | 
| +  __ bind(&entry);
 | 
| +  __ ld(a1, MemOperand(fp, limitOffset));
 | 
| +  __ Branch(&loop, ne, a0, Operand(a1));
 | 
| +
 | 
| +  // On exit, the pushed arguments count is in a0, untagged
 | 
| +  __ SmiUntag(a0);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +// Used by FunctionApply and ReflectApply
 | 
| +static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
 | 
| +  const int kFormalParameters = targetIsArgument ? 3 : 2;
 | 
| +  const int kStackSize = kFormalParameters + 1;
 | 
|  
 | 
|    {
 | 
|      FrameScope frame_scope(masm, StackFrame::INTERNAL);
 | 
| +    const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize;
 | 
| +    const int kReceiverOffset = kArgumentsOffset + kPointerSize;
 | 
| +    const int kFunctionOffset = kReceiverOffset + kPointerSize;
 | 
| +
 | 
|      __ ld(a0, MemOperand(fp, kFunctionOffset));  // Get the function.
 | 
|      __ push(a0);
 | 
| -    __ ld(a0, MemOperand(fp, kArgsOffset));  // Get the args array.
 | 
| +    __ ld(a0, MemOperand(fp, kArgumentsOffset));  // Get the args array.
 | 
|      __ push(a0);
 | 
| +
 | 
|      // Returns (in v0) number of arguments to copy to stack as Smi.
 | 
| -    __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
 | 
| -
 | 
| -    // Check the stack for overflow. We are not trying to catch
 | 
| -    // interruptions (e.g. debug break and preemption) here, so the "real stack
 | 
| -    // limit" is checked.
 | 
| -    Label okay;
 | 
| -    __ LoadRoot(a2, Heap::kRealStackLimitRootIndex);
 | 
| -    // Make a2 the space we have left. The stack might already be overflowed
 | 
| -    // here which will cause a2 to become negative.
 | 
| -    __ dsubu(a2, sp, a2);
 | 
| -    // Check if the arguments will overflow the stack.
 | 
| -    __ SmiScale(a7, v0, kPointerSizeLog2);
 | 
| -    __ Branch(&okay, gt, a2, Operand(a7));  // Signed comparison.
 | 
| -
 | 
| -    // Out of stack space.
 | 
| -    __ ld(a1, MemOperand(fp, kFunctionOffset));
 | 
| -    __ Push(a1, v0);
 | 
| -    __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
 | 
| -    // End of stack check.
 | 
| +    if (targetIsArgument) {
 | 
| +      __ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION);
 | 
| +    } else {
 | 
| +      __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
 | 
| +    }
 | 
| +
 | 
| +    Generate_CheckStackOverflow(masm, kFunctionOffset);
 | 
|  
 | 
|      // Push current limit and index.
 | 
| -    __ bind(&okay);
 | 
| +    const int kIndexOffset =
 | 
| +        StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
 | 
| +    const int kLimitOffset =
 | 
| +        StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
 | 
|      __ mov(a1, zero_reg);
 | 
|      __ Push(v0, a1);  // Limit and initial index.
 | 
|  
 | 
|      // Get the receiver.
 | 
| -    __ ld(a0, MemOperand(fp, kRecvOffset));
 | 
| +    __ ld(a0, MemOperand(fp, kReceiverOffset));
 | 
|  
 | 
|      // Check that the function is a JS function (otherwise it must be a proxy).
 | 
|      Label push_receiver;
 | 
| @@ -1457,36 +1507,12 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
 | 
|      __ push(a0);
 | 
|  
 | 
|      // Copy all arguments from the array to the stack.
 | 
| -    Label entry, loop;
 | 
| -    __ ld(a0, MemOperand(fp, kIndexOffset));
 | 
| -    __ Branch(&entry);
 | 
| -
 | 
| -    // Load the current argument from the arguments array and push it to the
 | 
| -    // stack.
 | 
| -    // a0: current argument index
 | 
| -    __ bind(&loop);
 | 
| -    __ ld(a1, MemOperand(fp, kArgsOffset));
 | 
| -    __ Push(a1, a0);
 | 
| -
 | 
| -    // Call the runtime to access the property in the arguments array.
 | 
| -    __ CallRuntime(Runtime::kGetProperty, 2);
 | 
| -    __ push(v0);
 | 
| -
 | 
| -    // Use inline caching to access the arguments.
 | 
| -    __ ld(a0, MemOperand(fp, kIndexOffset));
 | 
| -    __ Daddu(a0, a0, Operand(Smi::FromInt(1)));
 | 
| -    __ sd(a0, MemOperand(fp, kIndexOffset));
 | 
| -
 | 
| -    // Test if the copy loop has finished copying all the elements from the
 | 
| -    // arguments object.
 | 
| -    __ bind(&entry);
 | 
| -    __ ld(a1, MemOperand(fp, kLimitOffset));
 | 
| -    __ Branch(&loop, ne, a0, Operand(a1));
 | 
| +    Generate_PushAppliedArguments(
 | 
| +        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
 | 
|  
 | 
|      // Call the function.
 | 
|      Label call_proxy;
 | 
|      ParameterCount actual(a0);
 | 
| -    __ SmiUntag(a0);
 | 
|      __ ld(a1, MemOperand(fp, kFunctionOffset));
 | 
|      __ GetObjectType(a1, a2, a2);
 | 
|      __ Branch(&call_proxy, ne, a2, Operand(JS_FUNCTION_TYPE));
 | 
| @@ -1495,7 +1521,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
 | 
|  
 | 
|      frame_scope.GenerateLeaveFrame();
 | 
|      __ Ret(USE_DELAY_SLOT);
 | 
| -    __ Daddu(sp, sp, Operand(3 * kPointerSize));  // In delay slot.
 | 
| +    __ Daddu(sp, sp, Operand(kStackSize * kPointerSize));  // In delay slot.
 | 
|  
 | 
|      // Call the function proxy.
 | 
|      __ bind(&call_proxy);
 | 
| @@ -1509,7 +1535,87 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
 | 
|    }
 | 
|  
 | 
|    __ Ret(USE_DELAY_SLOT);
 | 
| -  __ Daddu(sp, sp, Operand(3 * kPointerSize));  // In delay slot.
 | 
| +  __ Daddu(sp, sp, Operand(kStackSize * kPointerSize));  // In delay slot.
 | 
| +}
 | 
| +
 | 
| +
 | 
| +static void Generate_ConstructHelper(MacroAssembler* masm) {
 | 
| +  const int kFormalParameters = 3;
 | 
| +  const int kStackSize = kFormalParameters + 1;
 | 
| +
 | 
| +  {
 | 
| +    FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL);
 | 
| +    const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize;
 | 
| +    const int kArgumentsOffset = kNewTargetOffset + kPointerSize;
 | 
| +    const int kFunctionOffset = kArgumentsOffset + kPointerSize;
 | 
| +
 | 
| +    // If newTarget is not supplied, set it to constructor
 | 
| +    Label validate_arguments;
 | 
| +    __ ld(a0, MemOperand(fp, kNewTargetOffset));
 | 
| +    __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
 | 
| +    __ Branch(&validate_arguments, ne, a0, Operand(at));
 | 
| +    __ ld(a0, MemOperand(fp, kFunctionOffset));
 | 
| +    __ sd(a0, MemOperand(fp, kNewTargetOffset));
 | 
| +
 | 
| +    // Validate arguments
 | 
| +    __ bind(&validate_arguments);
 | 
| +    __ ld(a0, MemOperand(fp, kFunctionOffset));  // get the function
 | 
| +    __ push(a0);
 | 
| +    __ ld(a0, MemOperand(fp, kArgumentsOffset));  // get the args array
 | 
| +    __ push(a0);
 | 
| +    __ ld(a0, MemOperand(fp, kNewTargetOffset));  // get the new.target
 | 
| +    __ push(a0);
 | 
| +    __ InvokeBuiltin(Builtins::REFLECT_CONSTRUCT_PREPARE, CALL_FUNCTION);
 | 
| +
 | 
| +    Generate_CheckStackOverflow(masm, kFunctionOffset);
 | 
| +
 | 
| +    // Push current limit and index.
 | 
| +    const int kIndexOffset =
 | 
| +        StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
 | 
| +    const int kLimitOffset =
 | 
| +        StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
 | 
| +    __ push(v0);  // limit
 | 
| +    __ mov(a1, zero_reg);  // initial index
 | 
| +    __ push(a1);
 | 
| +    // Push newTarget and callee functions
 | 
| +    __ ld(a0, MemOperand(fp, kNewTargetOffset));
 | 
| +    __ push(a0);
 | 
| +    __ ld(a0, MemOperand(fp, kFunctionOffset));
 | 
| +    __ push(a0);
 | 
| +
 | 
| +    // Copy all arguments from the array to the stack.
 | 
| +    Generate_PushAppliedArguments(
 | 
| +        masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
 | 
| +
 | 
| +    // Use undefined feedback vector
 | 
| +    __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
 | 
| +    __ ld(a1, MemOperand(fp, kFunctionOffset));
 | 
| +
 | 
| +    // Call the function.
 | 
| +    CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
 | 
| +    __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
 | 
| +
 | 
| +    __ Drop(1);
 | 
| +
 | 
| +    // Leave internal frame.
 | 
| +  }
 | 
| +  __ Daddu(sp, sp, Operand(kStackSize * kPointerSize));
 | 
| +  __ Jump(ra);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
 | 
| +  Generate_ApplyHelper(masm, false);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
 | 
| +  Generate_ApplyHelper(masm, true);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
 | 
| +  Generate_ConstructHelper(masm);
 | 
|  }
 | 
|  
 | 
|  
 | 
| 
 |