Index: src/mips/builtins-mips.cc |
diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc |
index f8c112605c96f4e0bc1f0685e9e59ecabc57a5cc..de62d59fe798d16a220e394cb3674da5e9fde1af 100644 |
--- a/src/mips/builtins-mips.cc |
+++ b/src/mips/builtins-mips.cc |
@@ -1351,49 +1351,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. |
+ __ Subu(a2, sp, a2); |
+ // Check if the arguments will overflow the stack. |
+ __ sll(t3, v0, kPointerSizeLog2 - kSmiTagSize); |
+ // Signed comparison. |
+ __ Branch(&okay, gt, a2, Operand(t3)); |
+ |
+ // Out of stack space. |
+ __ lw(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; |
+ __ lw(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); |
+ __ lw(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. |
+ __ lw(a0, MemOperand(fp, indexOffset)); |
+ __ Addu(a0, a0, Operand(1 << kSmiTagSize)); |
+ __ sw(a0, MemOperand(fp, indexOffset)); |
+ |
+ // Test if the copy loop has finished copying all the elements from the |
+ // arguments object. |
+ __ bind(&entry); |
+ __ lw(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; |
+ |
__ lw(a0, MemOperand(fp, kFunctionOffset)); // Get the function. |
__ push(a0); |
- __ lw(a0, MemOperand(fp, kArgsOffset)); // Get the args array. |
+ __ lw(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. |
- __ subu(a2, sp, a2); |
- // Check if the arguments will overflow the stack. |
- __ sll(t3, v0, kPointerSizeLog2 - kSmiTagSize); |
- __ Branch(&okay, gt, a2, Operand(t3)); // Signed comparison. |
- |
- // Out of stack space. |
- __ lw(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. |
- __ lw(a0, MemOperand(fp, kRecvOffset)); |
+ __ lw(a0, MemOperand(fp, kReceiverOffset)); |
// Check that the function is a JS function (otherwise it must be a proxy). |
Label push_receiver; |
@@ -1449,36 +1499,12 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
__ push(a0); |
// Copy all arguments from the array to the stack. |
- Label entry, loop; |
- __ lw(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); |
- __ lw(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. |
- __ lw(a0, MemOperand(fp, kIndexOffset)); |
- __ Addu(a0, a0, Operand(1 << kSmiTagSize)); |
- __ sw(a0, MemOperand(fp, kIndexOffset)); |
- |
- // Test if the copy loop has finished copying all the elements from the |
- // arguments object. |
- __ bind(&entry); |
- __ lw(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); |
- __ sra(a0, a0, kSmiTagSize); |
__ lw(a1, MemOperand(fp, kFunctionOffset)); |
__ GetObjectType(a1, a2, a2); |
__ Branch(&call_proxy, ne, a2, Operand(JS_FUNCTION_TYPE)); |
@@ -1487,7 +1513,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
frame_scope.GenerateLeaveFrame(); |
__ Ret(USE_DELAY_SLOT); |
- __ Addu(sp, sp, Operand(3 * kPointerSize)); // In delay slot. |
+ __ Addu(sp, sp, Operand(kStackSize * kPointerSize)); // In delay slot. |
// Call the function proxy. |
__ bind(&call_proxy); |
@@ -1501,7 +1527,87 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
} |
__ Ret(USE_DELAY_SLOT); |
- __ Addu(sp, sp, Operand(3 * kPointerSize)); // In delay slot. |
+ __ Addu(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; |
+ __ lw(a0, MemOperand(fp, kNewTargetOffset)); |
+ __ LoadRoot(at, Heap::kUndefinedValueRootIndex); |
+ __ Branch(&validate_arguments, ne, a0, Operand(at)); |
+ __ lw(a0, MemOperand(fp, kFunctionOffset)); |
+ __ sw(a0, MemOperand(fp, kNewTargetOffset)); |
+ |
+ // Validate arguments |
+ __ bind(&validate_arguments); |
+ __ lw(a0, MemOperand(fp, kFunctionOffset)); // get the function |
+ __ push(a0); |
+ __ lw(a0, MemOperand(fp, kArgumentsOffset)); // get the args array |
+ __ push(a0); |
+ __ lw(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 |
+ __ lw(a0, MemOperand(fp, kNewTargetOffset)); |
+ __ push(a0); |
+ __ lw(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); |
+ __ lw(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. |
+ } |
+ __ Addu(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); |
} |