diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-02-10 19:02:34 +0100 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-04-25 17:49:15 +0000 |
commit | 219485d898556368a833576f1c55e210c1cf7189 (patch) | |
tree | c6f8faf247711f4ba36eb3605e5fc89f84c6aff6 /src | |
parent | b59b727035c4c1a4d235432cc67e5d89d3a24cd3 (diff) |
Add support for ES6 rest parameters
function foo(a, b, ...c) {...} now works correctly.
Change-Id: Ie442a0e7cc5e9dc4156e56b348bba305cced8531
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 10 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth.cpp | 4 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 2 | ||||
-rw-r--r-- | src/qml/jit/qv4jit.cpp | 11 | ||||
-rw-r--r-- | src/qml/jit/qv4jit_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 10 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtimeapi_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 4 |
8 files changed, 41 insertions, 2 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index bc0c62e9be..52dd32dcc5 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -2339,10 +2339,15 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, bytecodeGenerator->addInstruction(convert); } + int argc = 0; while (formals) { if (formals->isRest) { - // #### implement me - throwSyntaxError(formals->firstSourceLocation(), QString::fromLatin1("Support for rest parameters not implemented!")); + Q_ASSERT(!formals->next); + Instruction::CreateRestParameter rest; + rest.argIndex = argc; + bytecodeGenerator->addInstruction(rest); + Reference f = referenceForName(formals->name.toString(), true); + f.storeConsumeAccumulator(); } if (formals->defaultExpression) { RegisterScope scope(this); @@ -2354,6 +2359,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, jump.link(); } formals = formals->next; + ++argc; } beginFunctionBodyHook(); diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp index 362bc40b31..3a9cecdae0 100644 --- a/src/qml/compiler/qv4instr_moth.cpp +++ b/src/qml/compiler/qv4instr_moth.cpp @@ -454,6 +454,10 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st MOTH_BEGIN_INSTR(CreateUnmappedArgumentsObject) MOTH_END_INSTR(CreateUnmappedArgumentsObject) + MOTH_BEGIN_INSTR(CreateRestParameter) + d << argIndex; + MOTH_END_INSTR(CreateRestParameter) + MOTH_BEGIN_INSTR(ConvertThisToObject) MOTH_END_INSTR(ConvertThisToObject) diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index df9be62672..8ce72f4942 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -128,6 +128,7 @@ QT_BEGIN_NAMESPACE #define INSTR_DefineObjectLiteral(op) INSTRUCTION(op, DefineObjectLiteral, 4, internalClassId, arrayValueCount, arrayGetterSetterCountAndFlags, args) #define INSTR_CreateMappedArgumentsObject(op) INSTRUCTION(op, CreateMappedArgumentsObject, 0) #define INSTR_CreateUnmappedArgumentsObject(op) INSTRUCTION(op, CreateUnmappedArgumentsObject, 0) +#define INSTR_CreateRestParameter(op) INSTRUCTION(op, CreateRestParameter, 1, argIndex) #define INSTR_ConvertThisToObject(op) INSTRUCTION(op, ConvertThisToObject, 0) #define INSTR_Construct(op) INSTRUCTION(op, Construct, 3, func, argc, argv) #define INSTR_Jump(op) INSTRUCTION(op, Jump, 1, offset) @@ -245,6 +246,7 @@ QT_BEGIN_NAMESPACE F(DefineObjectLiteral) \ F(CreateMappedArgumentsObject) \ F(CreateUnmappedArgumentsObject) \ + F(CreateRestParameter) \ F(ConvertThisToObject) \ F(Construct) \ F(Jump) \ diff --git a/src/qml/jit/qv4jit.cpp b/src/qml/jit/qv4jit.cpp index ec446b63ec..b2dde4fca2 100644 --- a/src/qml/jit/qv4jit.cpp +++ b/src/qml/jit/qv4jit.cpp @@ -781,6 +781,14 @@ void BaselineJIT::generate_CreateUnmappedArgumentsObject() Assembler::ResultInAccumulator); } +void BaselineJIT::generate_CreateRestParameter(int argIndex) +{ + as->prepareCallWithArgCount(2); + as->passInt32AsArg(argIndex, 1); + as->passEngineAsArg(0); + JIT_GENERATE_RUNTIME_CALL(Runtime::method_createRestParameter, Assembler::ResultInAccumulator); +} + static void convertThisToObjectHelper(ExecutionEngine *engine, Value *t) { if (!t->isObject()) { @@ -1173,6 +1181,9 @@ void BaselineJIT::collectLabelsInBytecode() MOTH_BEGIN_INSTR(CreateUnmappedArgumentsObject) MOTH_END_INSTR(CreateUnmappedArgumentsObject) + MOTH_BEGIN_INSTR(CreateRestParameter) + MOTH_END_INSTR(CreateRestParameter) + MOTH_BEGIN_INSTR(ConvertThisToObject) MOTH_END_INSTR(ConvertThisToObject) diff --git a/src/qml/jit/qv4jit_p.h b/src/qml/jit/qv4jit_p.h index 93fa7e7576..9ff2d99191 100644 --- a/src/qml/jit/qv4jit_p.h +++ b/src/qml/jit/qv4jit_p.h @@ -192,6 +192,7 @@ public: int args) override; void generate_CreateMappedArgumentsObject() override; void generate_CreateUnmappedArgumentsObject() override; + void generate_CreateRestParameter(int argIndex) override; void generate_ConvertThisToObject() override; void generate_Construct(int func, int argc, int argv) override; void generate_Jump(int offset) override; diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index c984a70a14..b14395b507 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1269,6 +1269,16 @@ QV4::ReturnedValue Runtime::method_createUnmappedArgumentsObject(ExecutionEngine return engine->memoryManager->allocObject<StrictArgumentsObject>(ic, engine->currentStackFrame)->asReturnedValue(); } +QV4::ReturnedValue Runtime::method_createRestParameter(ExecutionEngine *engine, int argIndex) +{ + const Value *values = engine->currentStackFrame->originalArguments + argIndex; + int nValues = engine->currentStackFrame->originalArgumentsCount - argIndex; + if (nValues <= 0) + return engine->newArrayObject(0)->asReturnedValue(); + return engine->newArrayObject(values, nValues)->asReturnedValue(); +} + + ReturnedValue Runtime::method_loadQmlContext(NoThrowEngine *engine) { Heap::QmlContext *ctx = engine->qmlContext(); diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index 91232256a9..9bdb41b19e 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -134,6 +134,7 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> { F(void, declareVar, (ExecutionEngine *engine, bool deletable, int nameIndex)) \ F(ReturnedValue, createMappedArgumentsObject, (ExecutionEngine *engine)) \ F(ReturnedValue, createUnmappedArgumentsObject, (ExecutionEngine *engine)) \ + F(ReturnedValue, createRestParameter, (ExecutionEngine *engine, int argIndex)) \ \ /* literals */ \ F(ReturnedValue, arrayLiteral, (ExecutionEngine *engine, Value *values, uint length)) \ diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 88d859eef5..fae917dbb5 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -981,6 +981,10 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const Value *thisObject, acc = Runtime::method_createUnmappedArgumentsObject(engine); MOTH_END_INSTR(CreateUnmappedArgumentsObject) + MOTH_BEGIN_INSTR(CreateRestParameter) + acc = Runtime::method_createRestParameter(engine, argIndex); + MOTH_END_INSTR(CreateRestParameter) + MOTH_BEGIN_INSTR(ConvertThisToObject) Value *t = &stack[CallData::This]; if (!t->isObject()) { |