aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/compiler/qv4bytecodegenerator_p.h2
-rw-r--r--src/qml/compiler/qv4codegen.cpp115
-rw-r--r--src/qml/compiler/qv4compilercontrolflow_p.h2
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp6
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h6
-rw-r--r--src/qml/jit/qv4baselinejit.cpp12
-rw-r--r--src/qml/jit/qv4baselinejit_p.h6
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp11
-rw-r--r--src/qml/jsruntime/qv4mapobject.cpp3
-rw-r--r--src/qml/jsruntime/qv4promiseobject.cpp24
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp32
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h6
-rw-r--r--src/qml/jsruntime/qv4setobject.cpp6
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp11
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp10
-rw-r--r--src/qmlcompiler/qqmljscodegenerator.cpp10
-rw-r--r--src/qmlcompiler/qqmljscodegenerator_p.h6
-rw-r--r--src/qmlcompiler/qqmljscompilepass_p.h4
-rw-r--r--src/qmlcompiler/qqmljstypepropagator.cpp10
-rw-r--r--src/qmlcompiler/qqmljstypepropagator_p.h6
20 files changed, 159 insertions, 129 deletions
diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h
index 35e539fb5e..fa14754f85 100644
--- a/src/qml/compiler/qv4bytecodegenerator_p.h
+++ b/src/qml/compiler/qv4bytecodegenerator_p.h
@@ -58,7 +58,7 @@ public:
link();
}
- void link() {
+ void link() const {
Q_ASSERT(index >= 0);
Q_ASSERT(generator->labels[index] == -1);
generator->labels[index] = generator->instructions.size();
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index aba071580b..1fca7bd75a 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -713,9 +713,8 @@ void Codegen::destructureElementList(const Codegen::Reference &array, PatternEle
RegisterScope scope(this);
Reference iterator = Reference::fromStackSlot(this);
- Reference iteratorValue = Reference::fromStackSlot(this);
- Reference iteratorDone = Reference::fromStackSlot(this);
- Reference::storeConstOnStack(this, Encode(false), iteratorDone.stackSlot());
+ QVarLengthArray<Reference> iteratorValues;
+ Reference ignored;
array.loadInAccumulator();
Instruction::GetIterator iteratorObjInstr;
@@ -723,45 +722,76 @@ void Codegen::destructureElementList(const Codegen::Reference &array, PatternEle
bytecodeGenerator->addInstruction(iteratorObjInstr);
iterator.storeConsumeAccumulator();
+ BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
+ Reference needsClose = Reference::storeConstOnStack(this, Encode(false));
+
+ for (PatternElementList *p = bindingList; p; p = p->next) {
+ PatternElement *e = p->element;
+ for (Elision *elision = p->elision; elision; elision = elision->next) {
+ iterator.loadInAccumulator();
+ Instruction::IteratorNext next;
+ if (!ignored.isValid())
+ ignored = Reference::fromStackSlot(this);
+ next.value = ignored.stackSlot();
+ bytecodeGenerator->addJumpInstruction(next).link(done);
+ }
+
+ if (!e)
+ continue;
+
+ if (e->type != PatternElement::RestElement) {
+ iterator.loadInAccumulator();
+ Instruction::IteratorNext next;
+ iteratorValues.push_back(Reference::fromStackSlot(this));
+ next.value = iteratorValues.back().stackSlot();
+ bytecodeGenerator->addJumpInstruction(next).link(done);
+ }
+ }
+
+ // If we've iterated through all the patterns without exhausing the iterator, it needs
+ // to be closed. But we don't close it here because:
+ // a, closing might throw an exception and we want to assign the values before we handle that
+ // b, there might be a rest element that could still continue iterating
+ Reference::fromConst(this, Encode(true)).storeOnStack(needsClose.stackSlot());
+
+ done.link();
+ bytecodeGenerator->checkException();
+
{
- auto cleanup = [this, iterator, iteratorDone]() {
+ ControlFlowUnwindCleanup flow(this, [&]() {
+ BytecodeGenerator::Label skipClose = bytecodeGenerator->newLabel();
+ needsClose.loadInAccumulator();
+ bytecodeGenerator->jumpFalse().link(skipClose);
iterator.loadInAccumulator();
Instruction::IteratorClose close;
- close.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(close);
- };
-
- ControlFlowUnwindCleanup flow(this, cleanup);
+ skipClose.link();
+ });
+ auto it = iteratorValues.constBegin();
for (PatternElementList *p = bindingList; p; p = p->next) {
PatternElement *e = p->element;
- for (Elision *elision = p->elision; elision; elision = elision->next) {
- iterator.loadInAccumulator();
- Instruction::IteratorNext next;
- next.value = iteratorValue.stackSlot();
- next.done = iteratorDone.stackSlot();
- bytecodeGenerator->addInstruction(next);
- }
if (!e)
continue;
- RegisterScope scope(this);
- iterator.loadInAccumulator();
-
if (e->type == PatternElement::RestElement) {
- Reference::fromConst(this, Encode(true)).storeOnStack(iteratorDone.stackSlot());
+ Q_ASSERT(it == iteratorValues.constEnd());
+
+ // The rest element is guaranteed to exhaust the iterator
+ Reference::fromConst(this, Encode(false)).storeOnStack(needsClose.stackSlot());
+
+ iterator.loadInAccumulator();
bytecodeGenerator->addInstruction(Instruction::DestructureRestElement());
- initializeAndDestructureBindingElement(e, Reference::fromAccumulator(this), isDefinition);
+ initializeAndDestructureBindingElement(
+ e, Reference::fromAccumulator(this), isDefinition);
} else {
- Instruction::IteratorNext next;
- next.value = iteratorValue.stackSlot();
- next.done = iteratorDone.stackSlot();
- bytecodeGenerator->addInstruction(next);
- initializeAndDestructureBindingElement(e, iteratorValue, isDefinition);
- if (hasError())
- return;
+ Q_ASSERT(it != iteratorValues.constEnd());
+ initializeAndDestructureBindingElement(e, *it++, isDefinition);
}
+
+ if (hasError())
+ return;
}
}
}
@@ -1167,7 +1197,6 @@ bool Codegen::visit(ArrayPattern *ast)
RegisterScope scope(this);
Reference iterator = Reference::fromStackSlot(this);
- Reference iteratorDone = Reference::fromConst(this, Encode(false)).storeOnStack();
Reference lhsValue = Reference::fromStackSlot(this);
// There should be a temporal block, so that variables declared in lhs shadow outside vars.
@@ -1187,24 +1216,23 @@ bool Codegen::visit(ArrayPattern *ast)
BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
+ BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
{
- auto cleanup = [this, iterator, iteratorDone]() {
+ auto cleanup = [this, iterator, done]() {
iterator.loadInAccumulator();
Instruction::IteratorClose close;
- close.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(close);
+ done.link();
};
- ControlFlowLoop flow(this, &end, &in, cleanup);
+ ControlFlowLoop flow(this, &end, &in, std::move(cleanup));
in.link();
bytecodeGenerator->addLoopStart(in);
iterator.loadInAccumulator();
Instruction::IteratorNext next;
next.value = lhsValue.stackSlot();
- next.done = iteratorDone.stackSlot();
- bytecodeGenerator->addInstruction(next);
- bytecodeGenerator->addJumpInstruction(Instruction::JumpTrue()).link(end);
+ bytecodeGenerator->addJumpInstruction(next).link(done);
lhsValue.loadInAccumulator();
pushAccumulator();
@@ -3220,15 +3248,15 @@ bool Codegen::visit(YieldExpression *ast)
Instruction::IteratorNextForYieldStar next;
next.object = lhsValue.stackSlot();
next.iterator = iterator.stackSlot();
- bytecodeGenerator->addInstruction(next);
-
- BytecodeGenerator::Jump done = bytecodeGenerator->jumpTrue();
+ BytecodeGenerator::Jump done = bytecodeGenerator->addJumpInstruction(next);
bytecodeGenerator->jumpNotUndefined().link(loop);
+
lhsValue.loadInAccumulator();
emitReturn(acc);
done.link();
+ bytecodeGenerator->checkException();
lhsValue.loadInAccumulator();
setExprResult(acc);
@@ -3572,7 +3600,6 @@ bool Codegen::visit(ForEachStatement *ast)
TailCallBlocker blockTailCalls(this);
Reference iterator = Reference::fromStackSlot(this);
- Reference iteratorDone = Reference::fromConst(this, Encode(false)).storeOnStack();
Reference lhsValue = Reference::fromStackSlot(this);
// There should be a temporal block, so that variables declared in lhs shadow outside vars.
@@ -3593,16 +3620,20 @@ bool Codegen::visit(ForEachStatement *ast)
BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
+ BytecodeGenerator::Label done;
{
std::function<void()> cleanup;
if (ast->type == ForEachType::Of) {
- cleanup = [iterator, iteratorDone, this]() {
+ done = bytecodeGenerator->newLabel();
+ cleanup = [iterator, this, done]() {
iterator.loadInAccumulator();
Instruction::IteratorClose close;
- close.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(close);
+ done.link();
};
+ } else {
+ done = end;
}
ControlFlowLoop flow(this, &end, &in, std::move(cleanup));
bytecodeGenerator->addLoopStart(in);
@@ -3610,9 +3641,7 @@ bool Codegen::visit(ForEachStatement *ast)
iterator.loadInAccumulator();
Instruction::IteratorNext next;
next.value = lhsValue.stackSlot();
- next.done = iteratorDone.stackSlot();
- bytecodeGenerator->addInstruction(next);
- bytecodeGenerator->addJumpInstruction(Instruction::JumpTrue()).link(end);
+ bytecodeGenerator->addJumpInstruction(next).link(done);
// each iteration gets it's own context, as per spec
{
diff --git a/src/qml/compiler/qv4compilercontrolflow_p.h b/src/qml/compiler/qv4compilercontrolflow_p.h
index 070a1390ce..b190b77410 100644
--- a/src/qml/compiler/qv4compilercontrolflow_p.h
+++ b/src/qml/compiler/qv4compilercontrolflow_p.h
@@ -167,8 +167,8 @@ struct ControlFlowUnwindCleanup : public ControlFlowUnwind
~ControlFlowUnwindCleanup() {
if (cleanup) {
unwindLabel.link();
- generator()->setUnwindHandler(parentUnwindHandler());
cleanup();
+ generator()->setUnwindHandler(parentUnwindHandler());
emitUnwindHandler();
}
}
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index 4fda5b1b19..2f6f12437d 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -405,15 +405,15 @@ QString dumpBytecode(
MOTH_END_INSTR(GetIterator)
MOTH_BEGIN_INSTR(IteratorNext)
- s << dumpRegister(value, nFormals) << ", " << dumpRegister(done, nFormals);
+ s << dumpRegister(value, nFormals) << ", " << ABSOLUTE_OFFSET();
MOTH_END_INSTR(IteratorNext)
MOTH_BEGIN_INSTR(IteratorNextForYieldStar)
- s << dumpRegister(iterator, nFormals) << ", " << dumpRegister(object, nFormals);
+ s << dumpRegister(iterator, nFormals) << ", " << dumpRegister(object, nFormals)
+ << ABSOLUTE_OFFSET();
MOTH_END_INSTR(IteratorNextForYieldStar)
MOTH_BEGIN_INSTR(IteratorClose)
- s << dumpRegister(done, nFormals);
MOTH_END_INSTR(IteratorClose)
MOTH_BEGIN_INSTR(DestructureRestElement)
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 7ebf849f3e..70e9f9e7a2 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE
#define INSTR_Yield(op) INSTRUCTION(op, Yield, 0)
#define INSTR_YieldStar(op) INSTRUCTION(op, YieldStar, 0)
#define INSTR_Resume(op) INSTRUCTION(op, Resume, 1, offset)
-#define INSTR_IteratorNextForYieldStar(op) INSTRUCTION(op, IteratorNextForYieldStar, 2, iterator, object)
+#define INSTR_IteratorNextForYieldStar(op) INSTRUCTION(op, IteratorNextForYieldStar, 3, iterator, object, offset)
#define INSTR_StoreProperty(op) INSTRUCTION(op, StoreProperty, 2, name, base)
#define INSTR_SetLookup(op) INSTRUCTION(op, SetLookup, 2, index, base)
#define INSTR_LoadSuperProperty(op) INSTRUCTION(op, LoadSuperProperty, 1, property)
@@ -94,8 +94,8 @@ QT_BEGIN_NAMESPACE
#define INSTR_PopScriptContext(op) INSTRUCTION(op, PopScriptContext, 0)
#define INSTR_PopContext(op) INSTRUCTION(op, PopContext, 0)
#define INSTR_GetIterator(op) INSTRUCTION(op, GetIterator, 1, iterator)
-#define INSTR_IteratorNext(op) INSTRUCTION(op, IteratorNext, 2, value, done)
-#define INSTR_IteratorClose(op) INSTRUCTION(op, IteratorClose, 1, done)
+#define INSTR_IteratorNext(op) INSTRUCTION(op, IteratorNext, 2, value, offset)
+#define INSTR_IteratorClose(op) INSTRUCTION(op, IteratorClose, 0)
#define INSTR_DestructureRestElement(op) INSTRUCTION(op, DestructureRestElement, 0)
#define INSTR_DeleteProperty(op) INSTRUCTION(op, DeleteProperty, 2, base, index)
#define INSTR_DeleteName(op) INSTRUCTION(op, DeleteName, 1, name)
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index d2895e8bf2..bd2e331cbc 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -586,7 +586,7 @@ void BaselineJIT::generate_GetIterator(int iterator)
BASELINEJIT_GENERATE_RUNTIME_CALL(GetIterator, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_IteratorNext(int value, int done)
+void BaselineJIT::generate_IteratorNext(int value, int offset)
{
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(3);
@@ -594,10 +594,10 @@ void BaselineJIT::generate_IteratorNext(int value, int done)
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(IteratorNext, CallResultDestination::InAccumulator);
- as->storeReg(done);
+ labels.insert(as->jumpTrue(absoluteOffset(offset)));
}
-void BaselineJIT::generate_IteratorNextForYieldStar(int iterator, int object)
+void BaselineJIT::generate_IteratorNextForYieldStar(int iterator, int object, int offset)
{
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(4);
@@ -606,13 +606,13 @@ void BaselineJIT::generate_IteratorNextForYieldStar(int iterator, int object)
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(IteratorNextForYieldStar, CallResultDestination::InAccumulator);
+ labels.insert(as->jumpTrue(absoluteOffset(offset)));
}
-void BaselineJIT::generate_IteratorClose(int done)
+void BaselineJIT::generate_IteratorClose()
{
as->saveAccumulatorInFrame();
- as->prepareCallWithArgCount(3);
- as->passJSSlotAsArg(done, 2);
+ as->prepareCallWithArgCount(2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(IteratorClose, CallResultDestination::InAccumulator);
diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h
index c502e4d405..40138ea700 100644
--- a/src/qml/jit/qv4baselinejit_p.h
+++ b/src/qml/jit/qv4baselinejit_p.h
@@ -106,9 +106,9 @@ public:
void generate_PopScriptContext() override;
void generate_PopContext() override;
void generate_GetIterator(int iterator) override;
- void generate_IteratorNext(int value, int done) override;
- void generate_IteratorNextForYieldStar(int iterator, int object) override;
- void generate_IteratorClose(int done) override;
+ void generate_IteratorNext(int value, int offset) override;
+ void generate_IteratorNextForYieldStar(int iterator, int object, int offset) override;
+ void generate_IteratorClose() override;
void generate_DestructureRestElement() override;
void generate_DeleteProperty(int base, int index) override;
void generate_DeleteName(int name) override;
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 05e73d0295..a32017210a 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -194,9 +194,8 @@ ReturnedValue ArrayPrototype::method_from(const FunctionObject *builtin, const V
// sets them into the created array.
forever {
if (k > (static_cast<qint64>(1) << 53) - 1) {
- ScopedValue falsey(scope, Encode(false));
ScopedValue error(scope, scope.engine->throwTypeError());
- return Runtime::IteratorClose::call(scope.engine, iterator, falsey);
+ return Runtime::IteratorClose::call(scope.engine, iterator);
}
// Retrieve the next value. If the iteration ends, we're done here.
@@ -218,7 +217,7 @@ ReturnedValue ArrayPrototype::method_from(const FunctionObject *builtin, const V
mapArguments[1] = Value::fromDouble(k);
mappedValue = mapfn->call(thisArg, mapArguments, 2);
if (scope.hasException())
- return Runtime::IteratorClose::call(scope.engine, iterator, Value::fromBoolean(false));
+ return Runtime::IteratorClose::call(scope.engine, iterator);
} else {
mappedValue = *nextValue;
}
@@ -230,10 +229,8 @@ ReturnedValue ArrayPrototype::method_from(const FunctionObject *builtin, const V
scope.engine->throwTypeError(QString::fromLatin1("Cannot redefine property: %1").arg(k));
}
- if (scope.hasException()) {
- ScopedValue falsey(scope, Encode(false));
- return Runtime::IteratorClose::call(scope.engine, iterator, falsey);
- }
+ if (scope.hasException())
+ return Runtime::IteratorClose::call(scope.engine, iterator);
k++;
}
diff --git a/src/qml/jsruntime/qv4mapobject.cpp b/src/qml/jsruntime/qv4mapobject.cpp
index 72e66e0e76..4bb9617b93 100644
--- a/src/qml/jsruntime/qv4mapobject.cpp
+++ b/src/qml/jsruntime/qv4mapobject.cpp
@@ -74,8 +74,7 @@ ReturnedValue WeakMapCtor::construct(const FunctionObject *f, const Value *argv,
if (scope.hasException())
break;
}
- ScopedValue falsey(scope, Encode(false));
- return Runtime::IteratorClose::call(scope.engine, iter, falsey);
+ return Runtime::IteratorClose::call(scope.engine, iter);
}
}
return a->asReturnedValue();
diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp
index 5424545e79..16cffea124 100644
--- a/src/qml/jsruntime/qv4promiseobject.cpp
+++ b/src/qml/jsruntime/qv4promiseobject.cpp
@@ -575,7 +575,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
}
if (!doneValue->toBoolean())
- completion = Runtime::IteratorClose::call(e, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(e, iteratorObject);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
@@ -583,7 +583,9 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1)));
if (scope.hasException() || !nextPromise) {
- ScopedValue completion(scope, Runtime::IteratorClose::call(e, iteratorObject, doneValue));
+ ScopedValue completion(scope, doneValue->toBoolean()
+ ? Encode::undefined()
+ : Runtime::IteratorClose::call(e, iteratorObject));
if (scope.hasException()) {
completion = e->exceptionValue->asReturnedValue();
dropException(e);
@@ -605,7 +607,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
}
if (!doneValue->toBoolean())
- completion = Runtime::IteratorClose::call(scope.engine, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(scope.engine, iteratorObject);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
@@ -624,7 +626,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
dropException(e);
if (!doneValue->toBoolean())
- completion = Runtime::IteratorClose::call(scope.engine, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(scope.engine, iteratorObject);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
@@ -686,7 +688,9 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
doneValue = Value::fromReturnedValue(Runtime::IteratorNext::call(e, iteratorObject, nextValue));
if (scope.hasException()) {
- ScopedValue completion(scope, Runtime::IteratorClose::call(e, iteratorObject, doneValue));
+ ScopedValue completion(scope, doneValue->toBoolean()
+ ? Encode::undefined()
+ : Runtime::IteratorClose::call(e, iteratorObject));
if (scope.hasException()) {
completion = e->exceptionValue->asReturnedValue();
dropException(e);
@@ -721,7 +725,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
}
if (!doneValue->toBoolean())
- completion = Runtime::IteratorClose::call(e, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(e, iteratorObject);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
@@ -729,7 +733,9 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1)));
if (scope.hasException() || !nextPromise) {
- ScopedValue completion(scope, Runtime::IteratorClose::call(e, iteratorObject, doneValue));
+ ScopedValue completion(scope, doneValue->toBoolean()
+ ? Encode::undefined()
+ : Runtime::IteratorClose::call(e, iteratorObject));
if (scope.hasException()) {
completion = e->exceptionValue->asReturnedValue();
dropException(e);
@@ -749,7 +755,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
}
if (!doneValue->toBoolean())
- completion = Runtime::IteratorClose::call(e, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(e, iteratorObject);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
@@ -768,7 +774,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
dropException(e);
if (!doneValue->toBoolean())
- completion = Runtime::IteratorClose::call(e, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(e, iteratorObject);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index f5b88f662b..01a378406a 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -862,6 +862,8 @@ ReturnedValue Runtime::IteratorNextForYieldStar::call(ExecutionEngine *engine, c
engine->hasException = false;
ScopedValue ret(scope, static_cast<const Object &>(iterator).get(engine->id_return()));
+ if (engine->hasException)
+ return Encode(true);
if (ret->isUndefined()) {
// propagate return()
return Encode::undefined();
@@ -876,14 +878,13 @@ ReturnedValue Runtime::IteratorNextForYieldStar::call(ExecutionEngine *engine, c
ScopedValue t(scope, static_cast<const Object &>(iterator).get(engine->id_throw()));
if (engine->hasException)
- return Encode::undefined();
+ return Encode(true);
if (t->isUndefined()) {
// no throw method on the iterator
- ScopedValue done(scope, Encode(false));
- IteratorClose::call(engine, iterator, done);
- if (engine->hasException)
- return Encode::undefined();
- return engine->throwTypeError();
+ IteratorClose::call(engine, iterator);
+ if (!engine->hasException)
+ engine->throwTypeError();
+ return Encode(true);
}
f = t->as<FunctionObject>();
arg = exceptionValue;
@@ -894,14 +895,18 @@ ReturnedValue Runtime::IteratorNextForYieldStar::call(ExecutionEngine *engine, c
f = next->as<FunctionObject>();
}
- if (!f)
- return engine->throwTypeError();
+ if (!f) {
+ engine->throwTypeError();
+ return Encode(true);
+ }
ScopedObject o(scope, f->call(&iterator, arg, 1));
if (scope.hasException())
return Encode(true);
- if (!o)
- return engine->throwTypeError();
+ if (!o) {
+ engine->throwTypeError();
+ return Encode(true);
+ }
ScopedValue d(scope, o->get(engine->id_done()));
if (scope.hasException())
@@ -909,18 +914,15 @@ ReturnedValue Runtime::IteratorNextForYieldStar::call(ExecutionEngine *engine, c
bool done = d->toBoolean();
if (done) {
*object = o->get(engine->id_value());
- return returnCalled ? Encode::undefined() : Encode(true);
+ return (returnCalled && !engine->hasException) ? Encode::undefined() : Encode(true);
}
*object = o;
return Encode(false);
}
-ReturnedValue Runtime::IteratorClose::call(ExecutionEngine *engine, const Value &iterator, const Value &done)
+ReturnedValue Runtime::IteratorClose::call(ExecutionEngine *engine, const Value &iterator)
{
Q_ASSERT(iterator.isObject());
- Q_ASSERT(done.isBoolean());
- if (done.booleanValue())
- return Encode::undefined();
Scope scope(engine);
ScopedValue e(scope);
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index 5e11d15495..797de7e13f 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -43,7 +43,7 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
static constexpr bool lastArgumentIsOutputValue = out == LastArgumentIsOutputValue::Yes;
};
using PureMethod = Method<Throws::No, ChangesContext::No, Pure::Yes>;
- using IteratorMethod = Method<Throws::Yes, ChangesContext::No, Pure::No,
+ using IteratorMethod = Method<Throws::No, ChangesContext::No, Pure::No,
LastArgumentIsOutputValue::Yes>;
/* call */
@@ -285,9 +285,9 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
{
static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value *);
};
- struct Q_QML_PRIVATE_EXPORT IteratorClose : Method<Throws::Yes>
+ struct Q_QML_PRIVATE_EXPORT IteratorClose : Method<Throws::No>
{
- static ReturnedValue call(ExecutionEngine *, const Value &, const Value &);
+ static ReturnedValue call(ExecutionEngine *, const Value &);
};
struct Q_QML_PRIVATE_EXPORT DestructureRestElement : Method<Throws::Yes>
{
diff --git a/src/qml/jsruntime/qv4setobject.cpp b/src/qml/jsruntime/qv4setobject.cpp
index 2a4cdc1944..01fc62a4d4 100644
--- a/src/qml/jsruntime/qv4setobject.cpp
+++ b/src/qml/jsruntime/qv4setobject.cpp
@@ -54,10 +54,8 @@ ReturnedValue WeakSetCtor::construct(const FunctionObject *f, const Value *argv,
return a.asReturnedValue();
adder->call(a, nextValue, 1);
- if (scope.hasException()) {
- ScopedValue falsey(scope, Encode(false));
- return Runtime::IteratorClose::call(scope.engine, iter, falsey);
- }
+ if (scope.hasException())
+ return Runtime::IteratorClose::call(scope.engine, iter);
}
}
}
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index 43dc0fae4f..6c72eaba5f 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -1680,14 +1680,13 @@ ReturnedValue IntrinsicTypedArrayCtor::method_from(const FunctionObject *f, cons
forever {
// Here we calculate the length of the iterable range.
if (iterableLength > (static_cast<qint64>(1) << 53) - 1) {
- ScopedValue falsey(scope, Encode(false));
ScopedValue error(scope, scope.engine->throwTypeError());
- return Runtime::IteratorClose::call(scope.engine, lengthIterator, falsey);
+ return Runtime::IteratorClose::call(scope.engine, lengthIterator);
}
// Retrieve the next value. If the iteration ends, we're done here.
done = Value::fromReturnedValue(Runtime::IteratorNext::call(scope.engine, lengthIterator, nextValue));
if (scope.hasException())
- return Runtime::IteratorClose::call(scope.engine, lengthIterator, Value::fromBoolean(false));
+ return Runtime::IteratorClose::call(scope.engine, lengthIterator);
if (done->toBoolean()) {
break;
}
@@ -1720,21 +1719,21 @@ ReturnedValue IntrinsicTypedArrayCtor::method_from(const FunctionObject *f, cons
for (qint64 k = 0; k < iterableLength; ++k) {
done = Value::fromReturnedValue(Runtime::IteratorNext::call(scope.engine, iterator, nextValue));
if (scope.hasException())
- return Runtime::IteratorClose::call(scope.engine, iterator, Value::fromBoolean(false));
+ return Runtime::IteratorClose::call(scope.engine, iterator);
if (mapfn) {
mapArguments[0] = *nextValue;
mapArguments[1] = Value::fromDouble(k);
mappedValue = mapfn->call(thisArg, mapArguments, 2);
if (scope.hasException())
- return Runtime::IteratorClose::call(scope.engine, iterator, Value::fromBoolean(false));
+ return Runtime::IteratorClose::call(scope.engine, iterator);
} else {
mappedValue = *nextValue;
}
a->put(k, mappedValue);
if (scope.hasException())
- return Runtime::IteratorClose::call(scope.engine, iterator, Value::fromBoolean(false));
+ return Runtime::IteratorClose::call(scope.engine, iterator);
}
return a.asReturnedValue();
} else {
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 0d4ba41fee..55f2261b4d 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -844,7 +844,8 @@ QV4::ReturnedValue VME::interpret(JSTypesStackFrame *frame, ExecutionEngine *eng
MOTH_BEGIN_INSTR(IteratorNextForYieldStar)
STORE_ACC();
acc = Runtime::IteratorNextForYieldStar::call(engine, accumulator, STACK_VALUE(iterator), &STACK_VALUE(object));
- CHECK_EXCEPTION;
+ if (ACC.toBoolean())
+ code += offset;
MOTH_END_INSTR(IteratorNextForYieldStar)
MOTH_BEGIN_INSTR(CallValue)
@@ -1054,15 +1055,14 @@ QV4::ReturnedValue VME::interpret(JSTypesStackFrame *frame, ExecutionEngine *eng
STORE_IP();
STORE_ACC();
acc = Runtime::IteratorNext::call(engine, accumulator, &STACK_VALUE(value));
- STACK_VALUE(done) = acc;
- CHECK_EXCEPTION;
+ if (ACC.toBoolean())
+ code += offset;
MOTH_END_INSTR(IteratorNext)
MOTH_BEGIN_INSTR(IteratorClose)
STORE_IP();
STORE_ACC();
- acc = Runtime::IteratorClose::call(engine, accumulator, STACK_VALUE(done));
- CHECK_EXCEPTION;
+ acc = Runtime::IteratorClose::call(engine, accumulator);
MOTH_END_INSTR(IteratorClose)
MOTH_BEGIN_INSTR(DestructureRestElement)
diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp
index c33b915441..d62e899dbc 100644
--- a/src/qmlcompiler/qqmljscodegenerator.cpp
+++ b/src/qmlcompiler/qqmljscodegenerator.cpp
@@ -2299,23 +2299,23 @@ void QQmlJSCodeGenerator::generate_GetIterator(int iterator)
BYTECODE_UNIMPLEMENTED();
}
-void QQmlJSCodeGenerator::generate_IteratorNext(int value, int done)
+void QQmlJSCodeGenerator::generate_IteratorNext(int value, int offset)
{
Q_UNUSED(value)
- Q_UNUSED(done)
+ Q_UNUSED(offset)
BYTECODE_UNIMPLEMENTED();
}
-void QQmlJSCodeGenerator::generate_IteratorNextForYieldStar(int iterator, int object)
+void QQmlJSCodeGenerator::generate_IteratorNextForYieldStar(int iterator, int object, int offset)
{
Q_UNUSED(iterator)
Q_UNUSED(object)
+ Q_UNUSED(offset)
BYTECODE_UNIMPLEMENTED();
}
-void QQmlJSCodeGenerator::generate_IteratorClose(int done)
+void QQmlJSCodeGenerator::generate_IteratorClose()
{
- Q_UNUSED(done)
BYTECODE_UNIMPLEMENTED();
}
diff --git a/src/qmlcompiler/qqmljscodegenerator_p.h b/src/qmlcompiler/qqmljscodegenerator_p.h
index 0a743127f9..b6ffd5ac7f 100644
--- a/src/qmlcompiler/qqmljscodegenerator_p.h
+++ b/src/qmlcompiler/qqmljscodegenerator_p.h
@@ -133,9 +133,9 @@ protected:
void generate_PopScriptContext() override;
void generate_PopContext() override;
void generate_GetIterator(int iterator) override;
- void generate_IteratorNext(int value, int done) override;
- void generate_IteratorNextForYieldStar(int iterator, int object) override;
- void generate_IteratorClose(int done) override;
+ void generate_IteratorNext(int value, int offset) override;
+ void generate_IteratorNextForYieldStar(int iterator, int object, int offset) override;
+ void generate_IteratorClose() override;
void generate_DestructureRestElement() override;
void generate_DeleteProperty(int base, int index) override;
void generate_DeleteName(int name) override;
diff --git a/src/qmlcompiler/qqmljscompilepass_p.h b/src/qmlcompiler/qqmljscompilepass_p.h
index ea73169538..05f0816aa7 100644
--- a/src/qmlcompiler/qqmljscompilepass_p.h
+++ b/src/qmlcompiler/qqmljscompilepass_p.h
@@ -411,9 +411,9 @@ protected:
void generate_GetTemplateObject(int) override {}
void generate_Increment() override {}
void generate_InitializeBlockDeadTemporalZone(int, int) override {}
- void generate_IteratorClose(int) override {}
+ void generate_IteratorClose() override {}
void generate_IteratorNext(int, int) override {}
- void generate_IteratorNextForYieldStar(int, int) override {}
+ void generate_IteratorNextForYieldStar(int, int, int) override {}
void generate_Jump(int) override {}
void generate_JumpFalse(int) override {}
void generate_JumpNoException(int) override {}
diff --git a/src/qmlcompiler/qqmljstypepropagator.cpp b/src/qmlcompiler/qqmljstypepropagator.cpp
index 4bddaf470e..3a02cd7714 100644
--- a/src/qmlcompiler/qqmljstypepropagator.cpp
+++ b/src/qmlcompiler/qqmljstypepropagator.cpp
@@ -1897,23 +1897,23 @@ void QQmlJSTypePropagator::generate_GetIterator(int iterator)
INSTR_PROLOGUE_NOT_IMPLEMENTED();
}
-void QQmlJSTypePropagator::generate_IteratorNext(int value, int done)
+void QQmlJSTypePropagator::generate_IteratorNext(int value, int offset)
{
Q_UNUSED(value)
- Q_UNUSED(done)
+ Q_UNUSED(offset)
INSTR_PROLOGUE_NOT_IMPLEMENTED();
}
-void QQmlJSTypePropagator::generate_IteratorNextForYieldStar(int iterator, int object)
+void QQmlJSTypePropagator::generate_IteratorNextForYieldStar(int iterator, int object, int offset)
{
Q_UNUSED(iterator)
Q_UNUSED(object)
+ Q_UNUSED(offset)
INSTR_PROLOGUE_NOT_IMPLEMENTED();
}
-void QQmlJSTypePropagator::generate_IteratorClose(int done)
+void QQmlJSTypePropagator::generate_IteratorClose()
{
- Q_UNUSED(done)
INSTR_PROLOGUE_NOT_IMPLEMENTED();
}
diff --git a/src/qmlcompiler/qqmljstypepropagator_p.h b/src/qmlcompiler/qqmljstypepropagator_p.h
index 6e9ac5e16a..282e3dad35 100644
--- a/src/qmlcompiler/qqmljstypepropagator_p.h
+++ b/src/qmlcompiler/qqmljstypepropagator_p.h
@@ -101,9 +101,9 @@ struct Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSTypePropagator : public QQmlJSCompileP
void generate_PopScriptContext() override;
void generate_PopContext() override;
void generate_GetIterator(int iterator) override;
- void generate_IteratorNext(int value, int done) override;
- void generate_IteratorNextForYieldStar(int iterator, int object) override;
- void generate_IteratorClose(int done) override;
+ void generate_IteratorNext(int value, int offset) override;
+ void generate_IteratorNextForYieldStar(int iterator, int object, int offset) override;
+ void generate_IteratorClose() override;
void generate_DestructureRestElement() override;
void generate_DeleteProperty(int base, int index) override;
void generate_DeleteName(int name) override;