Commit 66b0d031 authored by mvstanton's avatar mvstanton Committed by Commit bot

Basic TurboFan support for rest arguments.

TurboFan can accept them, it calls a runtime function to initialize
the rest object as a JSArray.

BUG=
R=bmeurer@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#33071}
parent 3d6f79bc
...@@ -585,6 +585,11 @@ bool AstNumberingVisitor::Renumber(FunctionLiteral* node) { ...@@ -585,6 +585,11 @@ bool AstNumberingVisitor::Renumber(FunctionLiteral* node) {
DisableCrankshaft(kContextAllocatedArguments); DisableCrankshaft(kContextAllocatedArguments);
} }
int rest_index;
if (scope->rest_parameter(&rest_index)) {
DisableCrankshaft(kRestParameter);
}
VisitDeclarations(scope->declarations()); VisitDeclarations(scope->declarations());
VisitStatements(node->body()); VisitStatements(node->body());
......
...@@ -3229,9 +3229,19 @@ Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) { ...@@ -3229,9 +3229,19 @@ Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) {
Node* AstGraphBuilder::BuildRestArgumentsArray(Variable* rest, int index) { Node* AstGraphBuilder::BuildRestArgumentsArray(Variable* rest, int index) {
if (rest == NULL) return NULL; if (rest == NULL) return NULL;
// TODO(mvstanton): Handle rest arguments. // Allocate and initialize a new arguments object.
SetStackOverflow(); CreateArgumentsParameters::Type type = CreateArgumentsParameters::kRestArray;
return jsgraph()->UndefinedConstant(); const Operator* op = javascript()->CreateArguments(type, index);
Node* object = NewNode(op, GetFunctionClosure());
PrepareFrameState(object, BailoutId::None());
// Assign the object to the {rest} variable. This should never lazy
// deopt, so it is fine to send invalid bailout id.
DCHECK(rest->IsContextSlot() || rest->IsStackAllocated());
FrameStateBeforeAndAfter states(this, BailoutId::None());
BuildVariableAssignment(rest, object, Token::ASSIGN, VectorSlotPair(),
BailoutId::None(), states);
return object;
} }
......
...@@ -463,7 +463,8 @@ void JSGenericLowering::LowerJSCreateArguments(Node* node) { ...@@ -463,7 +463,8 @@ void JSGenericLowering::LowerJSCreateArguments(Node* node) {
ReplaceWithRuntimeCall(node, Runtime::kNewStrictArguments_Generic); ReplaceWithRuntimeCall(node, Runtime::kNewStrictArguments_Generic);
break; break;
case CreateArgumentsParameters::kRestArray: case CreateArgumentsParameters::kRestArray:
UNIMPLEMENTED(); node->InsertInput(zone(), 1, jsgraph()->Constant(p.start_index()));
ReplaceWithRuntimeCall(node, Runtime::kNewRestArguments_Generic);
break; break;
} }
} }
......
...@@ -521,6 +521,26 @@ Handle<JSObject> NewStrictArguments(Isolate* isolate, Handle<JSFunction> callee, ...@@ -521,6 +521,26 @@ Handle<JSObject> NewStrictArguments(Isolate* isolate, Handle<JSFunction> callee,
} }
template <typename T>
Handle<JSObject> NewRestArguments(Isolate* isolate, Handle<JSFunction> callee,
T parameters, int argument_count,
int start_index) {
int num_elements = std::max(0, argument_count - start_index);
Handle<JSObject> result = isolate->factory()->NewJSArray(
FAST_ELEMENTS, num_elements, num_elements, Strength::WEAK,
DONT_INITIALIZE_ARRAY_ELEMENTS);
{
DisallowHeapAllocation no_gc;
FixedArray* elements = FixedArray::cast(result->elements());
WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
for (int i = 0; i < num_elements; i++) {
elements->set(i, parameters[i + start_index], mode);
}
}
return result;
}
class HandleArguments BASE_EMBEDDED { class HandleArguments BASE_EMBEDDED {
public: public:
explicit HandleArguments(Handle<Object>* array) : array_(array) {} explicit HandleArguments(Handle<Object>* array) : array_(array) {}
...@@ -571,6 +591,22 @@ RUNTIME_FUNCTION(Runtime_NewStrictArguments_Generic) { ...@@ -571,6 +591,22 @@ RUNTIME_FUNCTION(Runtime_NewStrictArguments_Generic) {
} }
RUNTIME_FUNCTION(Runtime_NewRestArguments_Generic) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0)
CONVERT_SMI_ARG_CHECKED(start_index, 1);
// This generic runtime function can also be used when the caller has been
// inlined, we use the slow but accurate {Runtime::GetCallerArguments}.
int argument_count = 0;
base::SmartArrayPointer<Handle<Object>> arguments =
Runtime::GetCallerArguments(isolate, 0, &argument_count);
HandleArguments argument_getter(arguments.get());
return *NewRestArguments(isolate, callee, argument_getter, argument_count,
start_index);
}
RUNTIME_FUNCTION(Runtime_NewSloppyArguments) { RUNTIME_FUNCTION(Runtime_NewSloppyArguments) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK(args.length() == 3); DCHECK(args.length() == 3);
......
...@@ -560,6 +560,7 @@ namespace internal { ...@@ -560,6 +560,7 @@ namespace internal {
F(InitializeLegacyConstLookupSlot, 3, 1) \ F(InitializeLegacyConstLookupSlot, 3, 1) \
F(NewSloppyArguments_Generic, 1, 1) \ F(NewSloppyArguments_Generic, 1, 1) \
F(NewStrictArguments_Generic, 1, 1) \ F(NewStrictArguments_Generic, 1, 1) \
F(NewRestArguments_Generic, 2, 1) \
F(NewSloppyArguments, 3, 1) \ F(NewSloppyArguments, 3, 1) \
F(NewStrictArguments, 3, 1) \ F(NewStrictArguments, 3, 1) \
F(NewRestParam, 4, 1) \ F(NewRestParam, 4, 1) \
......
...@@ -35,9 +35,6 @@ TEST(ArgumentsUnmapped) { ...@@ -35,9 +35,6 @@ TEST(ArgumentsUnmapped) {
TEST(ArgumentsRest) { TEST(ArgumentsRest) {
// TODO(mvstanton): restore this test when Turbofan again supports rest args.
// (soon).
return;
FunctionTester T("(function(a, ...args) { return args; })"); FunctionTester T("(function(a, ...args) { return args; })");
Handle<Object> arguments; Handle<Object> arguments;
......
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