XMLWordPrintable

Details

    • 6eff3465b5 (qt/qtdeclarative/dev) 6eff3465b5 (qt/tqtc-qtdeclarative/dev)

    Description

      In order to support the construction of lists in a sensible way, we need to make sure we construct the right kind of list right away when we hit the JavaScript array syntax. Unfortunately, there is no way to know the type of the elements at that point. The required type is only determined later, when we assign or return the list.

      This is the same problem we are facing in a number of other places where we produce a register of a type given by whatever the operation at hand does most "naturally", only to convert it to a different type later. If we could just produce the right type in the first place, we could skip the conversion.

      So, how do we get there?

      1. We need to move the basic block analysis out of the code generator, into a separate pass. It needs to be a higher level affair. Splitting each instruction into multiple sections is too fiddly. We should rather allow each section to write multiple values and refer to the registers by index and type, rather than by name. This allows us to use the instruction offsets as delimiters of basic blocks.
      2. Realize that expectedTargetTypesBeforeJump is a virtual write at the jump target, and a virtual read of the same type at the jump source.
      3. Do the dead store analysis on this structure, before generating any code.
      4. For each basic block, iterate the instructions backwards and collect reads. Merge them up via QQmlJSTypeResolver::merge(). When we hit a write, determine if the merged up type is "better" than the one currently provided. If so, change it.
      5. Types provided by expectedTargetTypesBeforeJump are propagated into the basic blocks they originate from, and those have to be analyzed again, then.
      6. Loop over this until nothing changes anymore (or some maximum number of iterations).
      7. In the code generator, provide specializations of instructions to generate specific types.

      Where does this matter?

      1. Lists, obviously.
      2. Any place where we return QVariant, we can just generate the return value into QVariant::data() rather than storing it on the stack first. This might make a difference with lookups, but not so much with arithmetics.
      3. Any place where we lookup into a QVariant::data() and then convert to a QJSPrimitiveValue, we could rather lookup into the QJSPrimitiveValue right away? Or produce undefined if the type is not a primitive.
      4. If a function call returns something, but we ignore the returned value, our dead store elimination currently doesn't catch it because the already generated call code has the assumption of the return value built in.

      Attachments

        For Gerrit Dashboard: QTBUG-100157
        # Subject Branch Project Status CR V

        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