Commit 05fcaa37 authored by akos.palfi's avatar akos.palfi Committed by Commit bot

MIPS: [es6] implement Reflect.apply() & Reflect.construct()

Port d21fd154

Known issue: the mjsunit/harmony/reflect-construct test fails, it will be addressed in a follow-up CL.

BUG=

Review URL: https://codereview.chromium.org/1021863002

Cr-Commit-Position: refs/heads/master@{#27326}
parent 3c3ce1bc
...@@ -1351,49 +1351,99 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { ...@@ -1351,49 +1351,99 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
} }
void Builtins::Generate_FunctionApply(MacroAssembler* masm) { static void Generate_CheckStackOverflow(MacroAssembler* masm,
const int kIndexOffset = const int calleeOffset) {
StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize); // Check the stack for overflow. We are not trying to catch
const int kLimitOffset = // interruptions (e.g. debug break and preemption) here, so the "real stack
StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize); // limit" is checked.
const int kArgsOffset = 2 * kPointerSize; Label okay;
const int kRecvOffset = 3 * kPointerSize; __ LoadRoot(a2, Heap::kRealStackLimitRootIndex);
const int kFunctionOffset = 4 * kPointerSize; // 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); 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. __ lw(a0, MemOperand(fp, kFunctionOffset)); // Get the function.
__ push(a0); __ push(a0);
__ lw(a0, MemOperand(fp, kArgsOffset)); // Get the args array. __ lw(a0, MemOperand(fp, kArgumentsOffset)); // Get the args array.
__ push(a0); __ push(a0);
// Returns (in v0) number of arguments to copy to stack as Smi. // Returns (in v0) number of arguments to copy to stack as Smi.
__ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); if (targetIsArgument) {
__ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION);
// Check the stack for overflow. We are not trying to catch } else {
// interruptions (e.g. debug break and preemption) here, so the "real stack __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
// limit" is checked. }
Label okay;
__ LoadRoot(a2, Heap::kRealStackLimitRootIndex); Generate_CheckStackOverflow(masm, kFunctionOffset);
// 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.
// Push current limit and index. // 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); __ mov(a1, zero_reg);
__ Push(v0, a1); // Limit and initial index. __ Push(v0, a1); // Limit and initial index.
// Get the receiver. // 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). // Check that the function is a JS function (otherwise it must be a proxy).
Label push_receiver; Label push_receiver;
...@@ -1449,36 +1499,12 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { ...@@ -1449,36 +1499,12 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ push(a0); __ push(a0);
// Copy all arguments from the array to the stack. // Copy all arguments from the array to the stack.
Label entry, loop; Generate_PushAppliedArguments(
__ lw(a0, MemOperand(fp, kIndexOffset)); masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
__ 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));
// Call the function. // Call the function.
Label call_proxy; Label call_proxy;
ParameterCount actual(a0); ParameterCount actual(a0);
__ sra(a0, a0, kSmiTagSize);
__ lw(a1, MemOperand(fp, kFunctionOffset)); __ lw(a1, MemOperand(fp, kFunctionOffset));
__ GetObjectType(a1, a2, a2); __ GetObjectType(a1, a2, a2);
__ Branch(&call_proxy, ne, a2, Operand(JS_FUNCTION_TYPE)); __ Branch(&call_proxy, ne, a2, Operand(JS_FUNCTION_TYPE));
...@@ -1487,7 +1513,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { ...@@ -1487,7 +1513,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
frame_scope.GenerateLeaveFrame(); frame_scope.GenerateLeaveFrame();
__ Ret(USE_DELAY_SLOT); __ 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. // Call the function proxy.
__ bind(&call_proxy); __ bind(&call_proxy);
...@@ -1501,7 +1527,87 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { ...@@ -1501,7 +1527,87 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
} }
__ Ret(USE_DELAY_SLOT); __ 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);
} }
......
...@@ -1359,49 +1359,99 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { ...@@ -1359,49 +1359,99 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
} }
void Builtins::Generate_FunctionApply(MacroAssembler* masm) { static void Generate_CheckStackOverflow(MacroAssembler* masm,
const int kIndexOffset = const int calleeOffset) {
StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize); // Check the stack for overflow. We are not trying to catch
const int kLimitOffset = // interruptions (e.g. debug break and preemption) here, so the "real stack
StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize); // limit" is checked.
const int kArgsOffset = 2 * kPointerSize; Label okay;
const int kRecvOffset = 3 * kPointerSize; __ LoadRoot(a2, Heap::kRealStackLimitRootIndex);
const int kFunctionOffset = 4 * kPointerSize; // 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); 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. __ ld(a0, MemOperand(fp, kFunctionOffset)); // Get the function.
__ push(a0); __ push(a0);
__ ld(a0, MemOperand(fp, kArgsOffset)); // Get the args array. __ ld(a0, MemOperand(fp, kArgumentsOffset)); // Get the args array.
__ push(a0); __ push(a0);
// Returns (in v0) number of arguments to copy to stack as Smi. // Returns (in v0) number of arguments to copy to stack as Smi.
__ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); if (targetIsArgument) {
__ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION);
// Check the stack for overflow. We are not trying to catch } else {
// interruptions (e.g. debug break and preemption) here, so the "real stack __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
// limit" is checked. }
Label okay;
__ LoadRoot(a2, Heap::kRealStackLimitRootIndex); Generate_CheckStackOverflow(masm, kFunctionOffset);
// 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.
// Push current limit and index. // 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); __ mov(a1, zero_reg);
__ Push(v0, a1); // Limit and initial index. __ Push(v0, a1); // Limit and initial index.
// Get the receiver. // 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). // Check that the function is a JS function (otherwise it must be a proxy).
Label push_receiver; Label push_receiver;
...@@ -1457,36 +1507,12 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { ...@@ -1457,36 +1507,12 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ push(a0); __ push(a0);
// Copy all arguments from the array to the stack. // Copy all arguments from the array to the stack.
Label entry, loop; Generate_PushAppliedArguments(
__ ld(a0, MemOperand(fp, kIndexOffset)); masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
__ 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));
// Call the function. // Call the function.
Label call_proxy; Label call_proxy;
ParameterCount actual(a0); ParameterCount actual(a0);
__ SmiUntag(a0);
__ ld(a1, MemOperand(fp, kFunctionOffset)); __ ld(a1, MemOperand(fp, kFunctionOffset));
__ GetObjectType(a1, a2, a2); __ GetObjectType(a1, a2, a2);
__ Branch(&call_proxy, ne, a2, Operand(JS_FUNCTION_TYPE)); __ Branch(&call_proxy, ne, a2, Operand(JS_FUNCTION_TYPE));
...@@ -1495,7 +1521,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { ...@@ -1495,7 +1521,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
frame_scope.GenerateLeaveFrame(); frame_scope.GenerateLeaveFrame();
__ Ret(USE_DELAY_SLOT); __ 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. // Call the function proxy.
__ bind(&call_proxy); __ bind(&call_proxy);
...@@ -1509,7 +1535,87 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { ...@@ -1509,7 +1535,87 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
} }
__ Ret(USE_DELAY_SLOT); __ 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);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment