diff options
author | Ulf Hermann <[email protected]> | 2023-08-25 15:40:37 +0200 |
---|---|---|
committer | Ulf Hermann <[email protected]> | 2023-09-08 20:27:58 +0000 |
commit | e7eb542a553c75cdb917450915addb3b9e20c0db (patch) | |
tree | 099ec4a22877b2f0eab679f805d817fffc055af4 /src/qml/jsruntime/qv4mapobject.cpp | |
parent | 1bd18723f72b451d3c5abf4560b4dd31394e5243 (diff) |
V4: Eliminate "done" from iterators
Instead of dragging another stack value around to mark if the iterator
was done, rather pass it an offset it should jump to if so. It can then
jump over any IteratorClose instruction while the ExceptionHandler can
still point to the IteratorClose instruction.
For this to work, we also have to refrain from checking for exceptions
as part of IteratorNext or IteratorClose. If IteratorNext generates an
exception, it also jumps to the "done" label, after which we dispatch
the exception. We don't want to jump to the exception handler for other
instructions in between as that would close the iterator. The iterator
should _not_ be closed if it has just thrown an exception, though. The
same holds for IteratorClose: If it throws an exception, we don't want
to jump back to the beginning of the loop's exception handler, since
that would produce an infinite loop. We also don't want to reset the
exception handler before IteratorClose because it needs to also be reset
if the iterator does not need to be closed.
This saves quite a few instructions and stack variables on actual
iteration.
For destructuring, we have to change the execution flow a bit. We need
to first perform the iteration for non-rest parameters, saving the
results in separate stack slots. This way we can apply our new "jump if
done" behavior if the iterator runs out or produces an exception itself.
We then save the "done" state in a separate stack slot, as before.
During the assignment of the iteration results to the actual variables,
we install an exception handler, so that we can still close the iterator
if one of the initializers throws an exception. This produces a few more
instructions than before:
1. We need to set and read the "needsClose" variable explicitly rather
than having IteratorNext and IteratorDone do it implicitly.
2. We need an additional CheckException after the iteration.
3. We need an additional conditional Jump over the IteratorDone.
Everything considered, the savings we get for regular iteration and the
more consistent semantics of the instructions involved are well worth
the few extra instructions on destructuring, especially since everything
those extra instructions do was done implicitly by the iterator
instructions before.
For consistency, the IteratorNextForYieldStar instruction is refactored
to work the same way as IteratorNext: In case of either an exception or
"done" it jumps to an offset, and we refrain from individually
exception-checking each IteratorNextForYieldStart instruction.
Task-number: QTBUG-116725
Change-Id: I9e2ad4319495aecabafdbbd3dd0cbf3c6191f942
Reviewed-by: Olivier De Cannière <[email protected]>
Reviewed-by: Sami Shalayel <[email protected]>
Diffstat (limited to 'src/qml/jsruntime/qv4mapobject.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4mapobject.cpp | 3 |
1 files changed, 1 insertions, 2 deletions
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(); |