dart2js: define flags for a “production-mode”

Two problems:

  • Build systems automatically pass flags to dart2js to make it easy for developers to get the best of dart2js production capabilities out of the box without any configuration: this may include compiling with --minify and --omit-implicit-checks today. Our flags will change, and we want that change to be transparent and not a breaking change for build systems.
  • We want users to be aware of how safe/unsafe certain flags are. Documentation is not enough for this.

Ideas

--production flag:
To improve the build system integration and prevent having to change tools downstream on every change to our compiler, we were planning to add a new set of flags that will evolve in time. Because the main goal build systems have is to have a flag to build apps at production level, we could focus on a single flag for that, e.g. --production. The means of a production compile may vary as we implement more features. For example, once we implement our optimizations for Dart2, we can deprecate the behavior of omit-implicit-checks, but may introduce a new option to allow unsafe casts in certain framework’s code.
So initially --production would be equivalent to --minify --omit-implicit-checks, but later it will be equivalent to --minify --allow-unsafe-cast-operator or something else.

--unsafe-optimizations flag:

One suggestion to address the second problem is to purposely use a naming convention of flags that makes it easier for users to see how safe or unsafe the flag is. For example: it has been proposed to add --unsafe-optimizations and --safe-optimizations flags that take as arguments an optional list of optimizations.

  • Accepted unsafe optimizations: default, all, none, allow-unsafe-cast-operator, lax-runtime-type, omit-parameter-checks, omit-implicit-downcasts, trust-primitives
  • Accepted safe optimizations: default, all, none, minify, inlining, type-inference, rti, runtime-type (and in the future some SSA optimizer steps can be listed here).
  • The default safe optimizations are all but minify
  • The default unsafe optimizations may only include allow-unsafe-cast-operator initially.

Revised --production=value flag:

Another suggestion: allow values to --production:

  • --production=safe (like --safe-optimizations=all)
  • --production=almost-safe (unsafe-cast-operator, lax-runtime-type-to-string)
  • --production=unsafe (omit-implicit-checks)
  • --production=really-unsafe (trust-primitives)

and have --production (with no args) default to --production=safe or --production=almost-safe.

The idea is that we could also provide a warning if an underlying flag is used without using the production flag. For example:

dart2js --production=unsafe  # produces no warnings
dart2js --omit-implicit-checks  # produces a warning about how you should test your app.

I’m starting to like this last approach. Thoughts?

cc @rakudrama @johnniwinther @natebosch @vsmenon

Author: Fantashit

1 thought on “dart2js: define flags for a “production-mode”

  1. @vsm had an interesting suggestion on wording:

    O2/O3 Performs optimizations that assume the program doesn’t ever throw any subclass of Error.

    O2 for us is about TypeError, O3 includes ArgumentError, NoSuchMethodError on null, and RangeError produced from the corelibs.

    … Will anyone want to run with –omit-implicit-checks but not –trust-primitives, for example?

    I believe so, yes. Today only a handful of teams use the latter. Externally, we were inclined to enable omit-implicit-checks by default on package:build, but not trust-primitives.

    use primitives heavily or that use arrays heavily.
    I do not know if it is reasonable for developers to understand this. Every program is going to use primitives and arrays heavily. To me this reads like “be careful using Dart if you use this flag”.

    Thinking more about this, the reason I’m so hesitant on grouping implicit-checks and trust-primitives in the same bucket is that the latter is more susceptible to invalid user input. So when I think of testing for omit-implicit-checks, normally DDC unit tests, plus some integration tests for the RPC layer tends to be enough to ensure that the app will be fine. With trust-primitives, I believe developers need to be more cautious about how different user inputs may affect their code and think more about off-by-one errors and such.

    At the same time – once we implement #34003, I feel more comfortable grouping them together because it will be less likely for users to need to use omit-implicit-checks altogether.

    Trying to put together all suggestions thus far, here is an updated proposal:

    -O -O<0,1,2,3>
       Controls optimizations that can help reduce code-size and improve
       performance of the generated code for deployment. 
    
      -O0
        Disables all optimizations. Equivalent to calling dart2js with these extra flags:
          --disable-inlining
          --disable-type-inference
          --disable-rti-optimizations
    
      -O
      -O1
        Enables optimizations that respect the language semantics and are safe for all
        programs. It however changes the string representation of types, which will no
        longer be consistent with the Dart VM or DDC.
    
        Equivalent to calling dart2js with these extra flags:
          --minify
          --lax-runtime-type-to-string
    
      -O2
        Enables optimizations that respect the language semantics only on programs that
        don't ever throw any subtype of `Error`. To use this option, we recommend that
        you properly test your application first without it, and ensure that no subtype
        of `Error` (such as `TypeError`) is ever thrown.
    
        Equivalent to calling dart2js with these extra flags:
          -O1
          --allow-unsafe-cast
          --omit-implicit-checks // for now
    
      -O3
        Enables more aggressive optimizations than -O2, but with the same assumptions.
        These optimizations are on a separate group because they are more likely to be
        affected by variations in input data. To use this option we recommend to pay
        additional attention on testing of edge cases in user input.
    
        Equivalent to calling dart2js with these extra flags:
          -O2
          --trust-primitives
    

Comments are closed.