diff options
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 68 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtimeapi_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 24 |
3 files changed, 88 insertions, 6 deletions
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 4c2477ded2..4e782fea00 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1256,6 +1256,60 @@ ReturnedValue Runtime::method_callQmlContextObjectProperty(ExecutionEngine *engi return fo->call(qmlContextValue, argv, argc); } +struct CallArgs { + Value *argv; + int argc; +}; + +static CallArgs createSpreadArguments(Scope &scope, Value *argv, int argc) +{ + ScopedValue it(scope); + ScopedValue done(scope); + + int argCount = 0; + + Value *v = scope.alloc<Scope::Uninitialized>(); + Value *arguments = v; + for (int i = 0; i < argc; ++i) { + if (!argv[i].isEmpty()) { + *v = argv[i]; + ++argCount; + v = scope.alloc<Scope::Uninitialized>(); + continue; + } + // spread element + ++i; + it = Runtime::method_getIterator(scope.engine, argv[i], /* ForInIterator */ 1); + if (scope.engine->hasException) + return { nullptr, 0 }; + while (1) { + done = Runtime::method_iteratorNext(scope.engine, it, v); + if (scope.engine->hasException) + return { nullptr, 0 }; + Q_ASSERT(done->isBoolean()); + if (done->booleanValue()) + break; + ++argCount; + v = scope.alloc<Scope::Uninitialized>(); + } + } + return { arguments, argCount }; +} + +ReturnedValue Runtime::method_callWithSpread(ExecutionEngine *engine, const Value &function, const Value &thisObject, Value *argv, int argc) +{ + Q_ASSERT(argc >= 1); + if (!function.isFunctionObject()) + return engine->throwTypeError(); + + Scope scope(engine); + CallArgs arguments = createSpreadArguments(scope, argv, argc); + if (engine->hasException) + return Encode::undefined(); + + return static_cast<const FunctionObject &>(function).call(&thisObject, arguments.argv, arguments.argc); +} + ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &function, Value *argv, int argc) { if (!function.isFunctionObject()) @@ -1264,6 +1318,20 @@ ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &fu return static_cast<const FunctionObject &>(function).callAsConstructor(argv, argc); } +ReturnedValue Runtime::method_constructWithSpread(ExecutionEngine *engine, const Value &function, Value *argv, int argc) +{ + Q_UNIMPLEMENTED(); + if (!function.isFunctionObject()) + return engine->throwTypeError(); + + Scope scope(engine); + CallArgs arguments = createSpreadArguments(scope, argv, argc); + if (engine->hasException) + return Encode::undefined(); + + return static_cast<const FunctionObject &>(function).callAsConstructor(arguments.argv, arguments.argc); +} + void Runtime::method_throwException(ExecutionEngine *engine, const Value &value) { if (!value.isEmpty()) diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index 63f4f426aa..09f6a65dde 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -99,9 +99,11 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> { F(ReturnedValue, callElement, (ExecutionEngine *engine, Value *base, const Value &index, Value *argv, int argc)) \ F(ReturnedValue, callValue, (ExecutionEngine *engine, const Value &func, Value *argv, int argc)) \ F(ReturnedValue, callPossiblyDirectEval, (ExecutionEngine *engine, Value *argv, int argc)) \ + F(ReturnedValue, callWithSpread, (ExecutionEngine *engine, const Value &func, const Value &thisObject, Value *argv, int argc)) \ \ /* construct */ \ F(ReturnedValue, construct, (ExecutionEngine *engine, const Value &func, Value *argv, int argc)) \ + F(ReturnedValue, constructWithSpread, (ExecutionEngine *engine, const Value &func, Value *argv, int argc)) \ \ /* load & store */ \ F(void, storeNameStrict, (ExecutionEngine *engine, int nameIndex, const Value &value)) \ diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 73a28557c2..9bd19cbe6b 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -877,6 +877,24 @@ QV4::ReturnedValue VME::interpret(CppStackFrame &frame, const char *code) CHECK_EXCEPTION; MOTH_END_INSTR(CallContextObjectProperty) + MOTH_BEGIN_INSTR(CallWithSpread) + STORE_IP(); + acc = Runtime::method_callWithSpread(engine, STACK_VALUE(func), STACK_VALUE(thisObject), stack + argv, argc); + CHECK_EXCEPTION; + MOTH_END_INSTR(CallWithSpread) + + MOTH_BEGIN_INSTR(Construct) + STORE_IP(); + acc = Runtime::method_construct(engine, STACK_VALUE(func), stack + argv, argc); + CHECK_EXCEPTION; + MOTH_END_INSTR(Construct) + + MOTH_BEGIN_INSTR(ConstructWithSpread) + STORE_IP(); + acc = Runtime::method_constructWithSpread(engine, STACK_VALUE(func), stack + argv, argc); + CHECK_EXCEPTION; + MOTH_END_INSTR(ConstructWithSpread) + MOTH_BEGIN_INSTR(SetUnwindHandler) frame.unwindHandler = offset ? code + offset : nullptr; MOTH_END_INSTR(SetUnwindHandler) @@ -1062,12 +1080,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame &frame, const char *code) CHECK_EXCEPTION; MOTH_END_INSTR(ToObject) - MOTH_BEGIN_INSTR(Construct) - STORE_IP(); - acc = Runtime::method_construct(engine, STACK_VALUE(func), stack + argv, argc); - CHECK_EXCEPTION; - MOTH_END_INSTR(Construct) - MOTH_BEGIN_INSTR(Jump) code += offset; MOTH_END_INSTR(Jump) |