aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jit
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2023-08-25 15:40:37 +0200
committerUlf Hermann <ulf.hermann@qt.io>2023-09-08 20:27:58 +0000
commite7eb542a553c75cdb917450915addb3b9e20c0db (patch)
tree099ec4a22877b2f0eab679f805d817fffc055af4 /src/qml/jit
parent1bd18723f72b451d3c5abf4560b4dd31394e5243 (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 <olivier.decanniere@qt.io> Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
Diffstat (limited to 'src/qml/jit')
-rw-r--r--src/qml/jit/qv4baselinejit.cpp12
-rw-r--r--src/qml/jit/qv4baselinejit_p.h6
2 files changed, 9 insertions, 9 deletions
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;