aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp68
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h2
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp24
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)