Details

    • Technical task
    • Resolution: Fixed
    • P2: Important
    • 6.7
    • QML: Compiler
    • None
    • e7eb542a5 (dev), a173d50a9 (dev)

    Description

      Once we have iterators, we can compiler for...in, for...of, and destructuring patterns. This is certainly helpful for any real-world usage. Iterators will only work on typed lists. We will provide some special QJSIterator type in qjslist.h that handles the details. There is a caveat, though: The iterator instructions are the only ones that write not one but two registers. The compiler infrastructure cannot handle this. However, it doesn't need to. We can change the instructions to store the "done" state inside the iterator objects rather than on the JS stack. This will have the nice side effect of simplifying the byte code.

      In addition, for...of and destructuring needs unwind handling since they both register an unwind handler to close the iterator if the iteration terminates "abruptly".

      So, let's recap how this works:

      for...in loops

      for...in loops don't need to close their iterator. Therefore they neither need a "done" register, nor an unwind handler. We could easily encode the jump on done into the IteratorNext instruction itself.

      for...of loops

      for...of loops need to close their iterator if:

      1. A break has terminated the loop prematurely
      2. Something else in the loop body has thrown an exception

      They must not close their iterator if the next() method itself has thrown an exception. However, if it has, we still have to terminate the loop somehow. Right now we keep a "done" register around that tells us whether we still need to close the iterator. We also register an unwind handler. If any exception (from the iterator itself or from something else) is thrown, we enter the unwind handler, check the "done" register and possibly close the iterator. We also enter the unwind handler and do the same thing if a break has terminated the loop.

      Can we do this with a conditional jump encoded into the IteratorNext instruction? Possibly. In case of either "done" or an exception, IteratorNext would have to jump to a place after the unwind handler where the unwind handler is cleared (or reset to the parent unwind handler). IteratorDone would have to refrain from checking exceptions, relegating that to the UnwindDispatch that follows.

      destructuring

      The specialty of destructuring is that it can continue retrieving values after the iterator is already done, but it might not exhaust the iterator. This, combined with the possibility of exceptions from either the surrounding initialization code or the iterator, makes the whole affair quite complicated. When destructuring, we don't really want to jump out when done, but we do want to jump out on exception. We do, however, want to remember the "done" state for the case when the destructuring terminates normally or via an exception from surrounding initialization code. In that case we have to close the iterator only if it is not done, yet. This cannot be encoded into a simple "jump on done or exception", but it is possible to structure it like this:

      1. Set "done" register to true
      2. IteratorNext with jump over following instruction when done or exception
      3. Set "done" register to false
      4. check exception

      Unfortunately this requires 4 instructions where we previously needed only one.

       

      Attachments

        Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

              ulherman Ulf Hermann
              ulherman Ulf Hermann
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Gerrit Reviews

                  There are no open Gerrit changes