We may find it useful later to add a more verbose stringification that
writes out the properties expressed by the powerset. For now, just
printing the int value is sufficient to debug e.g. test failures, and
it's relatively straightforward to manually convert an int to a set of
properties by looking at the definitions of the powerset domains.
Change-Id: I2397ffd83a6e86830f67c7f1ef811e33c0b7ff3c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/405567
Reviewed-by: Nate Biggs <natebiggs@google.com>
The `ClassRelation` concept is no longer needed as we are only using the CFE static type. All creations of "exact" and "this" types were already removed in an earlier CL so we are already always following the 'subtype' path.
Change-Id: Iccc3d61737c5b64b3b4217f7f20b34b181cc7db2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/348463
Reviewed-by: Mayank Patke <fishythefish@google.com>
I suspect that when the list of type preserving selectors was created the first/last setters either didn't exist or were just overlooked. Any dynamic List could have its inferred type changed by these operations.
Due to Dart2js's type representation this bug affects more than just dynamic lists. We track some simple values as part of the type system. So an operation that modifies a value can technically modify the type, as Dart2js represents it, even if the "real" type is preserved.
In the added test we would represent the list literal's type as "List(length: 2, elementType: Bool(true))". Notice the type states the elementType is specifically true, not just bool. Thus the first/last operations are modifying that type. But since we aren't registering this type change, SSA optimizes away the call/index and inlines the element itself.
Interestingly, this primarily manifested for bools due to a check in SSA:
https://github.com/dart-lang/sdk/blob/main/pkg/compiler/lib/src/ssa/optimize.dart#L475
In that code we are inlining constant-like expressions for the arguments of static invocations (such as the argument to a Expect.isTrue call). However, a few lines earlier you will see we only inline bool constants:
https://github.com/dart-lang/sdk/blob/main/pkg/compiler/lib/src/ssa/optimize.dart#L467
So when the list element type is anything other than a bool, this inlining does not trigger thus avoiding the bug.
Bug: https://github.com/dart-lang/sdk/issues/53944
Change-Id: I4e893903f335fc99b13cf526736c27bb066a4bad
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/334420
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
Currently _narrowType for TypeInformation nodes has logic to process DartTypes. This logic is a simplified version of the logic in createFromStaticType. We can consolidate the two and just use createFromStaticType directly.
And since the static type is only ever used for this type narrowing (and its immutable) we can create the AbstractValue up front and store that instead of the DartType.
There was no difference in the emitted JS when tested on 2 large programs.
Change-Id: I432279684580edf64ff52254653bd26501d461b7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/304160
Reviewed-by: Mayank Patke <fishythefish@google.com>
Type inference is not tracking the type of 'local' correctly through the switch statement into the inner return. The same code without the for loop does work correctly though.
Change-Id: I0b1b4741e4ff17c22dec3383defb412f5fff0836
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/298980
Reviewed-by: Stephen Adams <sra@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
This CL replaces https://dart-review.googlesource.com/c/sdk/+/296900
The `List` constructor is removed in Dart 3.0.
Some of the `@patch` implementations were not removed.
This is *high priority*. It seems the left-over `@patch factory List` constructor did not cause any errors, instead it *added* a constructor to `List` that can be used in web compiled code. Even if `List` doesn't have such a constructor in the SDK code proper.
The VM and analyzer will say the invocation is an error, but dart2js happily compiles it and runs.
(It used to be that patches couldn't add public members, that security seems to have been removed.)
Also removes code which tries to detect "the unnamed List constructor",
which is no longer a thing, and a number of invocations of the constructor, where it's not clear that the test is aware that the constructor no longer exists, and is not marked as `@dart=2.x` with x < 12.
TEST=ci
Change-Id: I4ffaf3ae2c4e75ca06e7ba0bf19187b6376f3888
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/297100
Reviewed-by: Brian Quinlan <bquinlan@google.com>
Reviewed-by: Nate Bosch <nbosch@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
Inference runtime metrics on a large program:
-----Before-----
Duration - Mean: 182.303 Median: 174.500 Max: 292.0
Memory - Mean: 5857.426 Median: 5752.639 Max: 6167.91
-----After-----
Duration - Mean: 144.525 Median: 133.500 Max: 242.0
Memory - Mean: 5867.756 Median: 5727.506 Max: 6262.414
This shows ~20% improvement in runtime and virtually no change in memory usage. Previously we saw a memory regression due to this change. But thanks to improvements in the representation of TypeInformation nodes that memory regression no longer exists.
Code size for this program is also very similar before and after this change.
Before: 43258484 bytes JS
After: 43258444 bytes JS
Change-Id: I6512637f16d83f3127fd1c060bb770ae56405b88
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/295460
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
- For parameters of closurized members make sure to mark the virtual parameter as closurized where appropriate. Closurized parameters are treated as dynamic and this needs to propagate to all the virtual target's overrides. Previously only the concrete target was getting marked as closurized.
- For mixins defining an abstract member, foo, implementations of foo (either directly on the mixin target or superclasses of it) should propagate their types to the abstract foo as they are effectively overriding it. Calls to foo within the body of the mixin can only target the abstract foo with a virtual call. So that virtual target needs to reflect the types of all its overrides.
Tests have been added that capture both of these cases. The values here reflect the non-linearized algorithm but prior to these fixes the linearized algorithms showed a diff for both tests. After these changes there is no diff.
This fixes all failures referenced in b/277876666.
Change-Id: Icaca99cb6902c54f481eebdbb65cbd7cf81aa2c2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/294960
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
This reverts commit 9aa00f6c75.
Reason for revert: breaks google3 (b/277876666)
Original change's description:
> [dart2js] Patch experimental inferrer (with linearized algorithm) into main inferrer.
>
> After this change for a large program we see:
> - 20% reduction in runtime (254s -> 202s)
> - 2% decrease in memory usage (7671.029MB -> 7524.901MB)
> - Code size decrease of <1% (214,788,150 bytes -> 214,757,445 bytes).
> - The k-limit of 6 refines imposed on the global inference algorithm is no longer hit for converging types. All but 15 types converge, down from 777 types that were hitting the k-limit before. This means we are likely generating better types/code for all 762 of those types.
> - More resilience to dynamic calls with lots of potential targets.
>
> Change-Id: I53d4ade51559f3366f076b6f2b485c5bdc50c6e8
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/271480
> Reviewed-by: Sigmund Cherem <sigmund@google.com>
> Commit-Queue: Nate Biggs <natebiggs@google.com>
Change-Id: Ia6e038e8e077813e589a54d2242bd2820bd22036
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/294741
Reviewed-by: Alexander Thomas <athom@google.com>
Commit-Queue: Emmanuel Pellereau <emmanuelp@google.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
After this change for a large program we see:
- 20% reduction in runtime (254s -> 202s)
- 2% decrease in memory usage (7671.029MB -> 7524.901MB)
- Code size decrease of <1% (214,788,150 bytes -> 214,757,445 bytes).
- The k-limit of 6 refines imposed on the global inference algorithm is no longer hit for converging types. All but 15 types converge, down from 777 types that were hitting the k-limit before. This means we are likely generating better types/code for all 762 of those types.
- More resilience to dynamic calls with lots of potential targets.
Change-Id: I53d4ade51559f3366f076b6f2b485c5bdc50c6e8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/271480
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
We now attempt to evaluate
- final local variables with initializers
- final statics with initializers
- static or local function invocations if they just return an expression
by attempting to const-evaluate the initializer/returned expression.
Change-Id: I976863d950ba1609c5d8e6a21884ca56af0d2b4b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/275145
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Mayank Patke <fishythefish@google.com>
Suppose we have code like
if (isDevMode) {
// do foo
} else {
// do bar
}
where isDevMode is const (or can be evaluated as const). In particular,
isDevMode can be controlled by compile-time options, like
bool.fromEnvironment.
We currently eliminate the dead branch during SSA, but that means we do
the work of compiling dead code in the previous phases. Instead, we can
recognize that the condition is const (or effectively const) and
eliminate the dead AST subtree directly.
Change-Id: Ia91da5ebc7fa496a1b963308c6e02d572cab936e
Bug: b/254543452
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/270281
Reviewed-by: Sigmund Cherem <sigmund@google.com>
These are scattered changes to get to type inferrence.
- Add some impact tracking for used record types
- Add RecordTypeInformation and FieldInRecordTypeInformation
- Add a simple test to show inference is currently very conservative.
Change-Id: Icb81033b11588c1bddd01c8c5fcf69950fdb77e9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/275161
Reviewed-by: Nate Biggs <natebiggs@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
The type bounds in each case statement can diverge when a break is hit in a conditional control flow block. Previously the switch statement was just merging the end state after visiting each case block. Instead we need to merge all possible termination states for each case.
This is trivial when the switch only contains breaks. The termination states are just those when we reach each break (or the end of the switch if there's a default).
When there are switch-continue statements we must reconcile the states that flow into each targeted switch before reconciling the types of those targeted switches themselves. We achieve that by making two passes over the cases, the first to gather the continue states and the second to update the switches affected by those states. Similar to before this is done repeatedly until a fixed point is reached.
Fixed: 46770
Change-Id: I5795748a4591e6a1dc283f2a54129e09a20d13d8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/250200
Reviewed-by: Mayank Patke <fishythefish@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
Late fields start out holding a sentinel value and after they are initialized or assigned, never hold a sentinel value again.
This CL implements some removal of checks and loads based on this monotonic behaviour.
On two large Dart Angular apps, this reduces the number of late-instance-field checks by ~25%.
One app is 0.44% smaller, the other is 0.98% smaller.
The optimization_test.dart no longer forces `--disable-inlining` because that prevents the inlining that exposes the optimization opportunities.
Most tests already use `@pragma('dart2js:noInline')` to prevent inlining where relevant.
Change-Id: I2327a96e69191313ed6c07eabe94aa2962fb2648
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/246881
Reviewed-by: Joshua Litt <joshualitt@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
A bug in global inference made the analysis accidentally carry over
the state of a nested condition in a subexpression and conclude
that it was part of the state of the outer condition.
This was due to the fact that we didn't clear the state when
popping out of the context and reentering the conition state.
Fixes https://github.com/dart-lang/sdk/issues/48571
Change-Id: I4e8294bb1a05bb3b910b6aec374357d75acb67cb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/240321
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Sigmund Cherem <sigmund@google.com>
Global type inference incorrectly handles conditions nested within
subexpressions and accidentally carries information from those
in the context of outer conditions.
Change-Id: I99e0af3da65590acb9429771b318b7da8f3b7f14
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/240320
Reviewed-by: Stephen Adams <sra@google.com>