Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-109221

Inconsistencies regarding list and value type property manipulations

    XMLWordPrintable

Details

    • ec58c0ddb (dev), 20374ccf7 (6.5), 3d924d59d (dev), 09003edcc (6.5), 4634b6bf5 (dev), a401d523f (6.5), b4cf8c1f1 (dev)

    Description

      If you read from and write to the same value type list property in a QML function, the interpreter will probably update any "references" to the list as soon as it's written to, but the compiler will create a true copy of the list, that doesn't get updated.

      This may be the same for any value type. We may need to invalidate any possible references whenever an operation with potential side effects takes place.

      This produces NaN when interpreted and a number when aot-compiled.

          property list<double> numbers: {
              var result = [];
              for (var i = 0; i < Categorizer.Length; ++i)
                  result[i] = randomNumber();
              return result;
          }
      
          function evil() : double {
              var numbers = root.numbers;
              var a = 0;
              for (var j = 0; j < Categorizer.Length; ++j) {
                  a += numbers[j];
                  root.numbers = [a, a, a]
              }
              return a;
          }
      

      Furthermore we cannot currently change any value type or list from generated code because we'd have to implement the complicated write back logic in order to do so. This is infeasible because we cannot track the origin of a value across function calls.

      The ValueTypeBehavior pragma can be set to make value types behave one way or another in both contexts, but since that doesn't change the default behavior, it's not a good solution. Everything new feature about value types in compiled code creates new inconsistencies. So, let's fix the default behavior.

      Observe:

      1. We can read and write value types and lists retrieved from properties in generated code as much as we like if we can prove that nothing between their retrieval and their manipulation can have had side effects that invalidate our (potentially non-existing) reference. Writing back value types and lists is not implemented yet, but within these constraints it would be possible.
      2. We can read from value types and lists passed as arguments to functions as much as we like if there hasn't been any side effect in the function before the read operation.
      3. We can analyze JavaScript functions for side effects ("being const") on import by just looking at their instructions. JavaScript functions could be scanned in two passes: first local constness for each function, then calls to other functions that may or may not be locally const. We need to scan the whole import set rather than each document individually, but that should be possible. This technique doesn't perform dead code elimination and may mark some obscure functions as having side effects even though they don't, but I think that's acceptable.

      If we go down this route we cannot write to value types and lists passed as arguments, but that's kind of bad style anyway. And we cannot do anything with value types and lists in bindings or functions after any side effects. However, you should avoid side effects anyway as far as possible. When you have to invoke a side effect, all your value type and list references are invalid afterwards. You can make this explicit by re-loading them from their properties.

      The following steps need to be taken to get there:

      1. Make the type propagator track whether any value can be affected by side effects. This is a matter of marking all live values as affected by side effect whenever an instruction that causes a side effect is processed.
      2. Prevent reading from value types and lists affected by side effects. At this point we have the minimum functionality to reach consistency.
      3. Analyze all functions for constness and mark them accordingly. We may need multiple levels of constness: pure functions without any side effects, side effects on arguments, side effects on other objects than the "this" object, side effects on everything. We can then selectively mark values as affected by side effects.
      4. Implement write back and allow it when writing to value types or lists not affected by side effects.
      5. Deprecate the ValueTypeBehavior and FunctionSignatureBehavior pragmas if everything works like it should.

      Attachments

        Issue Links

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

          Activity

            People

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

              Dates

                Created:
                Updated:
                Resolved:

                Gerrit Reviews