aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-06-14 10:12:20 +0200
committerLars Knoll <lars.knoll@qt.io>2018-06-21 19:43:32 +0000
commit99d8808bc5b85d54e8e735953a27a0c0c788f10e (patch)
tree9d4ea0fb0bcaee583c7b8510ca92d4b6c744a70c /src/qml
parent6969aa5932f0eb7171dea2b4da39c21d1c09cc60 (diff)
Add support for function calls with spread
Function calls with thread are modelled by pushing an empty value in front of every argument that requires spreading. The runtime methods callWithSpread and constructWithSpread then take care of spreading out the arguments. Change-Id: Ie877c59d3d9d08fc5f20d7befb7153c7b716bf30 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/compiler/qv4bytecodehandler.cpp12
-rw-r--r--src/qml/compiler/qv4codegen.cpp88
-rw-r--r--src/qml/compiler/qv4codegen_p.h4
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp16
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h8
-rw-r--r--src/qml/jit/qv4baselinejit.cpp51
-rw-r--r--src/qml/jit/qv4baselinejit_p.h4
-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
10 files changed, 235 insertions, 42 deletions
diff --git a/src/qml/compiler/qv4bytecodehandler.cpp b/src/qml/compiler/qv4bytecodehandler.cpp
index 3e4844a1ac..8d1ac0bfd9 100644
--- a/src/qml/compiler/qv4bytecodehandler.cpp
+++ b/src/qml/compiler/qv4bytecodehandler.cpp
@@ -263,6 +263,15 @@ std::vector<int> ByteCodeHandler::collectLabelsInBytecode(const char *code, uint
COLLECTOR_BEGIN_INSTR(CallContextObjectProperty)
COLLECTOR_END_INSTR(CallContextObjectProperty)
+ COLLECTOR_BEGIN_INSTR(CallWithSpread)
+ COLLECTOR_END_INSTR(CallWithSpread)
+
+ COLLECTOR_BEGIN_INSTR(Construct)
+ COLLECTOR_END_INSTR(Construct)
+
+ COLLECTOR_BEGIN_INSTR(ConstructWithSpread)
+ COLLECTOR_END_INSTR(ConstructWithSpread)
+
COLLECTOR_BEGIN_INSTR(SetUnwindHandler)
addLabel(code - start + offset);
COLLECTOR_END_INSTR(SetUnwindHandler)
@@ -355,9 +364,6 @@ std::vector<int> ByteCodeHandler::collectLabelsInBytecode(const char *code, uint
COLLECTOR_BEGIN_INSTR(ToObject)
COLLECTOR_END_INSTR(ToObject)
- COLLECTOR_BEGIN_INSTR(Construct)
- COLLECTOR_END_INSTR(Construct)
-
COLLECTOR_BEGIN_INSTR(Jump)
addLabel(code - start + offset);
COLLECTOR_END_INSTR(Jump)
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 6682f604de..fc2fb86666 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1610,6 +1610,7 @@ bool Codegen::visit(CallExpression *ast)
RegisterScope scope(this);
Reference base = expression(ast->base);
+
if (hasError)
return false;
switch (base.type) {
@@ -1626,10 +1627,36 @@ bool Codegen::visit(CallExpression *ast)
break;
}
+ int thisObject = bytecodeGenerator->newRegister();
+ int functionObject = bytecodeGenerator->newRegister();
+
auto calldata = pushArgs(ast->arguments);
if (hasError)
return false;
+ if (calldata.hasSpread) {
+ Reference baseObject = base.baseObject();
+ if (!baseObject.isStackSlot()) {
+ baseObject.storeOnStack(thisObject);
+ baseObject = Reference::fromStackSlot(this, thisObject);
+ }
+ if (!base.isStackSlot()) {
+ base.storeOnStack(functionObject);
+ base = Reference::fromStackSlot(this, functionObject);
+ }
+
+ Instruction::CallWithSpread call;
+ call.func = base.stackSlot();
+ call.thisObject = baseObject.stackSlot();
+ call.argc = calldata.argc;
+ call.argv = calldata.argv;
+ bytecodeGenerator->addInstruction(call);
+
+ _expr.setResult(Reference::fromAccumulator(this));
+ return false;
+
+ }
+
handleCall(base, calldata);
return false;
}
@@ -1707,36 +1734,41 @@ void Codegen::handleCall(Reference &base, Arguments calldata)
Codegen::Arguments Codegen::pushArgs(ArgumentList *args)
{
+ bool hasSpread = false;
int argc = 0;
for (ArgumentList *it = args; it; it = it->next) {
if (it->isSpreadElement) {
- throwSyntaxError(it->firstSourceLocation(), QLatin1String("'...' in argument lists is unimplemented."));
- return { 0, 0 };
+ hasSpread = true;
+ ++argc;
}
++argc;
}
if (!argc)
- return { 0, 0 };
+ return { 0, 0, false };
int calldata = bytecodeGenerator->newRegisterArray(argc);
argc = 0;
for (ArgumentList *it = args; it; it = it->next) {
+ if (it->isSpreadElement) {
+ Reference::fromConst(this, Primitive::emptyValue().asReturnedValue()).storeOnStack(calldata + argc);
+ ++argc;
+ }
RegisterScope scope(this);
Reference e = expression(it->expression);
if (hasError)
break;
- if (!argc && !it->next) {
+ if (!argc && !it->next && !hasSpread) {
// avoid copy for functions taking a single argument
if (e.isStackSlot())
- return { 1, e.stackSlot() };
+ return { 1, e.stackSlot(), hasSpread };
}
(void) e.storeOnStack(calldata + argc);
++argc;
}
- return { argc, calldata };
+ return { argc, calldata, hasSpread };
}
Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args)
@@ -1746,7 +1778,7 @@ Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args)
++argc;
if (!argc)
- return { 0, 0 };
+ return { 0, 0, false };
int calldata = bytecodeGenerator->newRegisterArray(argc);
@@ -1760,7 +1792,7 @@ Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args)
++argc;
}
- return { argc, calldata };
+ return { argc, calldata, false };
}
bool Codegen::visit(ConditionalExpression *ast)
@@ -2096,11 +2128,19 @@ bool Codegen::visit(NewMemberExpression *ast)
if (hasError)
return false;
- Instruction::Construct create;
- create.func = base.stackSlot();
- create.argc = calldata.argc;
- create.argv = calldata.argv;
- bytecodeGenerator->addInstruction(create);
+ if (calldata.hasSpread) {
+ Instruction::ConstructWithSpread create;
+ create.func = base.stackSlot();
+ create.argc = calldata.argc;
+ create.argv = calldata.argv;
+ bytecodeGenerator->addInstruction(create);
+ } else {
+ Instruction::Construct create;
+ create.func = base.stackSlot();
+ create.argc = calldata.argc;
+ create.argv = calldata.argv;
+ bytecodeGenerator->addInstruction(create);
+ }
_expr.setResult(Reference::fromAccumulator(this));
return false;
}
@@ -3640,6 +3680,28 @@ Codegen::Reference Codegen::Reference::storeConsumeAccumulator() const
return Reference();
}
+Codegen::Reference Codegen::Reference::baseObject() const
+{
+ if (type == Reference::QmlScopeObject || type == Reference::QmlContextObject) {
+ return Reference::fromStackSlot(codegen, qmlBase.stackSlot());
+ } else if (type == Reference::Member) {
+ RValue rval = propertyBase;
+ if (!rval.isValid())
+ return Reference::fromConst(codegen, Encode::undefined());
+ if (rval.isAccumulator())
+ return Reference::fromAccumulator(codegen);
+ if (rval.isStackSlot())
+ Reference::fromStackSlot(codegen, rval.stackSlot());
+ if (rval.isConst())
+ return Reference::fromConst(codegen, rval.constantValue());
+ Q_UNREACHABLE();
+ } else if (type == Reference::Subscript) {
+ return Reference::fromStackSlot(codegen, elementBase.stackSlot());
+ } else {
+ return Reference::fromConst(codegen, Encode::undefined());
+ }
+}
+
Codegen::Reference Codegen::Reference::storeOnStack() const
{ return doStoreOnStack(-1); }
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 3750811eaf..83b8731179 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -325,6 +325,8 @@ public:
Q_REQUIRED_RESULT Reference storeRetainAccumulator() const;
Reference storeConsumeAccumulator() const;
+ Q_REQUIRED_RESULT Reference baseObject() const;
+
bool storeWipesAccumulator() const;
void loadInAccumulator() const;
@@ -637,7 +639,7 @@ public:
Reference binopHelper(QSOperator::Op oper, Reference &left, Reference &right);
Reference jumpBinop(QSOperator::Op oper, Reference &left, Reference &right);
- struct Arguments { int argc; int argv; };
+ struct Arguments { int argc; int argv; bool hasSpread; };
Arguments pushArgs(AST::ArgumentList *args);
void handleCall(Reference &base, Arguments calldata);
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index 6f603f9488..df5dd5610c 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -376,6 +376,18 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << dumpRegister(base, nFormals) << "." << name << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallContextObjectProperty)
+ MOTH_BEGIN_INSTR(CallWithSpread)
+ d << "new" << dumpRegister(func, nFormals) << dumpRegister(thisObject, nFormals) << dumpArguments(argc, argv, nFormals);
+ MOTH_END_INSTR(CallWithSpread)
+
+ MOTH_BEGIN_INSTR(Construct)
+ d << "new" << dumpRegister(func, nFormals) << dumpArguments(argc, argv, nFormals);
+ MOTH_END_INSTR(Construct)
+
+ MOTH_BEGIN_INSTR(ConstructWithSpread)
+ d << "new" << dumpRegister(func, nFormals) << dumpArguments(argc, argv, nFormals);
+ MOTH_END_INSTR(ConstructWithSpread)
+
MOTH_BEGIN_INSTR(SetUnwindHandler)
if (offset)
d << ABSOLUTE_OFFSET();
@@ -486,10 +498,6 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_BEGIN_INSTR(ToObject)
MOTH_END_INSTR(ToObject)
- MOTH_BEGIN_INSTR(Construct)
- d << "new" << dumpRegister(func, nFormals) << dumpArguments(argc, argv, nFormals);
- MOTH_END_INSTR(Construct)
-
MOTH_BEGIN_INSTR(Jump)
d << ABSOLUTE_OFFSET();
MOTH_END_INSTR(Jump)
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index d4d630dfaf..85b30507a1 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -109,6 +109,9 @@ QT_BEGIN_NAMESPACE
#define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 3, index, argc, argv)
#define INSTR_CallScopeObjectProperty(op) INSTRUCTION(op, CallScopeObjectProperty, 4, name, base, argc, argv)
#define INSTR_CallContextObjectProperty(op) INSTRUCTION(op, CallContextObjectProperty, 4, name, base, argc, argv)
+#define INSTR_CallWithSpread(op) INSTRUCTION(op, CallWithSpread, 4, func, thisObject, argc, argv)
+#define INSTR_Construct(op) INSTRUCTION(op, Construct, 3, func, argc, argv)
+#define INSTR_ConstructWithSpread(op) INSTRUCTION(op, ConstructWithSpread, 3, func, argc, argv)
#define INSTR_SetUnwindHandler(op) INSTRUCTION(op, SetUnwindHandler, 1, offset)
#define INSTR_UnwindDispatch(op) INSTRUCTION(op, UnwindDispatch, 0)
#define INSTR_UnwindToLabel(op) INSTRUCTION(op, UnwindToLabel, 2, level, offset)
@@ -139,7 +142,6 @@ QT_BEGIN_NAMESPACE
#define INSTR_CreateRestParameter(op) INSTRUCTION(op, CreateRestParameter, 1, argIndex)
#define INSTR_ConvertThisToObject(op) INSTRUCTION(op, ConvertThisToObject, 0)
#define INSTR_ToObject(op) INSTRUCTION(op, ToObject, 0)
-#define INSTR_Construct(op) INSTRUCTION(op, Construct, 3, func, argc, argv)
#define INSTR_Jump(op) INSTRUCTION(op, Jump, 1, offset)
#define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 1, offset)
#define INSTR_JumpFalse(op) INSTRUCTION(op, JumpFalse, 1, offset)
@@ -235,6 +237,9 @@ QT_BEGIN_NAMESPACE
F(CallGlobalLookup) \
F(CallScopeObjectProperty) \
F(CallContextObjectProperty) \
+ F(CallWithSpread) \
+ F(Construct) \
+ F(ConstructWithSpread) \
F(SetUnwindHandler) \
F(UnwindDispatch) \
F(UnwindToLabel) \
@@ -265,7 +270,6 @@ QT_BEGIN_NAMESPACE
F(CreateRestParameter) \
F(ConvertThisToObject) \
F(ToObject) \
- F(Construct) \
F(Jump) \
F(JumpTrue) \
F(JumpFalse) \
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index 7f9674c57f..c813ff7f2d 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -532,6 +532,45 @@ void BaselineJIT::generate_CallContextObjectProperty(int propIdx, int base, int
as->checkException();
}
+
+void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, int argv)
+{
+ STORE_IP();
+ as->prepareCallWithArgCount(5);
+ as->passInt32AsArg(argc, 4);
+ as->passRegAsArg(argv, 3);
+ as->passRegAsArg(thisObject, 2);
+ as->passRegAsArg(func, 1);
+ as->passEngineAsArg(0);
+ JIT_GENERATE_RUNTIME_CALL(Runtime::method_callWithSpread, Assembler::ResultInAccumulator);
+ as->checkException();
+}
+
+
+void BaselineJIT::generate_Construct(int func, int argc, int argv)
+{
+ STORE_IP();
+ as->prepareCallWithArgCount(4);
+ as->passInt32AsArg(argc, 3);
+ as->passRegAsArg(argv, 2);
+ as->passRegAsArg(func, 1);
+ as->passEngineAsArg(0);
+ JIT_GENERATE_RUNTIME_CALL(Runtime::method_construct, Assembler::ResultInAccumulator);
+ as->checkException();
+}
+
+void BaselineJIT::generate_ConstructWithSpread(int func, int argc, int argv)
+{
+ STORE_IP();
+ as->prepareCallWithArgCount(4);
+ as->passInt32AsArg(argc, 3);
+ as->passRegAsArg(argv, 2);
+ as->passRegAsArg(func, 1);
+ as->passEngineAsArg(0);
+ JIT_GENERATE_RUNTIME_CALL(Runtime::method_constructWithSpread, Assembler::ResultInAccumulator);
+ as->checkException();
+}
+
void BaselineJIT::generate_SetUnwindHandler(int offset)
{
if (offset)
@@ -841,18 +880,6 @@ void BaselineJIT::generate_ToObject()
}
-void BaselineJIT::generate_Construct(int func, int argc, int argv)
-{
- STORE_IP();
- as->prepareCallWithArgCount(4);
- as->passInt32AsArg(argc, 3);
- as->passRegAsArg(argv, 2);
- as->passRegAsArg(func, 1);
- as->passEngineAsArg(0);
- JIT_GENERATE_RUNTIME_CALL(Runtime::method_construct, Assembler::ResultInAccumulator);
- as->checkException();
-}
-
void BaselineJIT::generate_Jump(int offset) { as->jump(instructionOffset() + offset); }
void BaselineJIT::generate_JumpTrue(int offset) { as->jumpTrue(instructionOffset() + offset); }
void BaselineJIT::generate_JumpFalse(int offset) { as->jumpFalse(instructionOffset() + offset); }
diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h
index b09efb1680..11548219af 100644
--- a/src/qml/jit/qv4baselinejit_p.h
+++ b/src/qml/jit/qv4baselinejit_p.h
@@ -126,6 +126,9 @@ public:
void generate_CallGlobalLookup(int index, int argc, int argv) override;
void generate_CallScopeObjectProperty(int propIdx, int base, int argc, int argv) override;
void generate_CallContextObjectProperty(int propIdx, int base, int argc, int argv) override;
+ void generate_CallWithSpread(int func, int thisObject, int argc, int argv) override;
+ void generate_Construct(int func, int argc, int argv) override;
+ void generate_ConstructWithSpread(int func, int argc, int argv) override;
void generate_SetUnwindHandler(int offset) override;
void generate_UnwindDispatch() override;
void generate_UnwindToLabel(int level, int offset) override;
@@ -156,7 +159,6 @@ public:
void generate_CreateRestParameter(int argIndex) override;
void generate_ConvertThisToObject() override;
void generate_ToObject() override;
- void generate_Construct(int func, int argc, int argv) override;
void generate_Jump(int offset) override;
void generate_JumpTrue(int offset) override;
void generate_JumpFalse(int offset) override;
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)