dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.06k stars 1.56k forks source link

dart2js: Strength reduction of comparisons for enum-like classes #35236

Open rakudrama opened 5 years ago

rakudrama commented 5 years ago

Dart enums, protocol buffer enums and other enum-like classes usually have discriminating int-valued member (often called value). This means that we can replace identical comparisons of an enum value against a constructed constant with a comparison of the value field against the discriminating value:

    aggregationLevel == C.AggregationLevel_2_DAYS
-->
    aggregationLevel.value == 2

or in a switch statement:

      switch (aggregationLevel) {
        case C.AggregationLevel_1_HOURS:
          ...
        case C.AggregationLevel_2_DAYS:
          ...
        case C.AggregationLevel_3_WEEKS:
          ...
        case C.AggregationLevel_4_MONTHS:
          ...
        case C.AggregationLevel_5_QUARTERS:
          ...
        default:
          ...
      }

-->

      switch (aggregationLevel.value) {

(or, guarding nullable values and reducing to the smallest out-of-domain non-negative number)

      switch (aggregationLevel==null ? 6 : aggregationLevel.value)
        case 1:
          ...
        case 2:
          ...
        case 3:
          ...
        case 4:
          ...
        case 5:
          ...
        default:
          ...
      }

The benefits would be

A class is enum-like if we can determine that

sigmundch commented 5 years ago

I really like this idea. Especially because that it can be applied selectively in some parts of the program and not others, so it doesn't require global tracking of values or determining that there are no dynamic accesses on the enum-like values.

QQ:

There is an int-valued discriminating field that is different for each constant.

do we care that it is an int? maybe we just care that it is a primitive? or maybe we just care that there exists a single discriminating field (it is going to be constant based on the previous requirement, and if that field itself is enum-like, we could go deeper).

rakudrama commented 5 years ago

We care that it is an int since that allows a JavaScript implementation to detect a chain of integer comparisons and generate jump table or branch tree that is better than the implied linear scan.

rakudrama commented 2 years ago

A partial implementation was committed as e0846aa5c6ed3ecb07fbda2456cb38e62702504a. This handles the switch-label case for Dart enum classes. The improvement was 0.2% code size in Flutter Gallery, negligible in cm_shell.

I'm leaving this issue open, since it would have more impact if