Kernel mixin transformation desugars mixin applications into normal
classes. Mixed-in type is pulled into interfaces list.
However, dart:mirrors needs to know the original mixed-in type of
a mixin application.
This change solves this problem by propagating a 'isTransformedMixinApplication'
attribute of a class through kernel AST, kernel binary and VM objects
into dart:mirrors implementation.
Fixes: https://github.com/dart-lang/sdk/issues/33240
Change-Id: I98ca69294e1ad445402a5ca91d90c30447aabcb2
Reviewed-on: https://dart-review.googlesource.com/56721
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
Reviewed-by: Kevin Millikin <kmillikin@google.com>
This CL turns the ClassHierarchy incremental and use that in two places:
* When compiling incrementally
* When performing the second ClassHierarchy computation after adding
forwarding stubs.
Change-Id: I7046d6be9d7673dc0783a98789b5a25183b44799
Reviewed-on: https://dart-review.googlesource.com/53804
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
This CL:
* Removes unused functions in the ClassHierarchy
* Turns the data structures used in the ClassHierarchy upside down
(nodes have a lists of supers instead of lists of subs)
* Factors some things that needs the original list-of-subs into another
class that the user can ask the ClassHierarchy to compute if needed.
It appears that it isn't generally.
This is step #1 in turning the ClassHierarchy into an incremental
ClassHierarchy.
Change-Id: I48c5731c01c1b0e8bf1fcd4ddba7f2bf7ce3b9c9
Reviewed-on: https://dart-review.googlesource.com/53662
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
When incrementally compiling, we can have builders for things that aren't
included anymore. Such builders should not introduce errors.
Change-Id: Ia0487d84819028913d54f6b55a2882e620009bd9
Reviewed-on: https://dart-review.googlesource.com/47223
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Peter von der Ahé <ahe@google.com>
The class hierarchy analysis maintains, for each class, a map from raw
supertypes to actual, parameterized supertypes. As an optimization, it
can share these maps between a class and one of its subclasses.
However, the sharing/copying mechanism sometimes ends up with entries
in the map that should not have been there.
This commit removes the optimization and always uses a separate map
for each class.
Closes https://github.com/dart-lang/sdk/issues/31996
Change-Id: I4c641d9c7d15706035791dd2b586a24045afceaa
Reviewed-on: https://dart-review.googlesource.com/39765
Commit-Queue: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Kevin Millikin <kmillikin@google.com>
Implemented more efficient way to iterate ClassSet in class_hierarchy.dart,
ClassSet becomes Iterable<Class>. This considerably improves speed of
ClosedWorldClassHierarchy.getSingleTargetForInterfaceInvocation() and
CHA-based devirtualization.
Time of CHA-based devirtualization on Flutter Gallery reduced
from ~13.4s to ~1.2s.
Also, ClassHierarchy used in devirtualization is configured to ignore
ambiguous supertypes to avoid crashes on Flutter Gallery.
Change-Id: Iaca251ca268aad3d8bb652247650096f19c25839
Reviewed-on: https://dart-review.googlesource.com/38960
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
This method is no longer needed, since the front end iterates through
members directly to find cross overrides.
Change-Id: Ibc5180962a097c4d6194dbf4cbd1a0dea15050c2
Reviewed-on: https://dart-review.googlesource.com/13582
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
This will be necessary when we try to integrate type inference with
the creation of forwarding nodes, because getter types can be inferred
from inherited setters and vice versa.
We accomplish this by producing two separate lists (getters and
setters), then merging them together. This results in a list where
correspondingly-named getters and setters are grouped together, with
getters appearing before setters.
Change-Id: I549f0b4354370753a6aa7a15285d778980fb4841
Reviewed-on: https://dart-review.googlesource.com/12900
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
This CL adds the ability to create a list of "forwarding nodes" for a
source class. A forwarding node is a data structure that will later
be resolved to either an explicitly declared member in the class or a
superclass, or to a forwarding stub. The idea is that we will create
the forwarding nodes at the time of outline building, and later,
during type inference, we will resolve each forwarding node as it is
encountered.
The reason we need to defer resolution of the forwarding nodes until
inference is because we may need to use the results of type inference
to determine which member a given forwarding node resolves to. For
example:
num f() => 1;
class A {
final x = 1; // Inferred type: int
}
class B {
final x = f(); // Inferred type: num
}
abstract class C implements A, B {}
We cannot determine at the time of building the outline for C whether
it inherits its x from A or B, because we need the results of type
inference to determine which of the two x's has a more specific type.
Note that some refactoring of ClassHierarchy was necessary in order to
allow the front end to maintain member lists in the same order used
internally by ClassHierarchy. This will let us avoid unnecessary
redundant sorting of methods.
Change-Id: Iee754957e0ad3b16c4b60608e17a4a7b0006dfb4
Reviewed-on: https://dart-review.googlesource.com/7851
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This CL adds a new target for kernel front-end, vm_precompiler. This is
an experimental target for new Dart VM precompiler pipeline which
will fully exploit strong mode type system and perform whole-program
optimizations.
As an example of such whole-program optimization, this CL adds
draft implementation of devirtualization of method invocations, which
uses single target computed by closed-world class hierarchy analysis.
Corresponding null checks (required for correctness) are not generated
yet.
Issue: https://github.com/dart-lang/sdk/issues/30480
Change-Id: I704cd16843a08f036a188b1188c80ee4dfbeab3b
Reviewed-on: https://dart-review.googlesource.com/3402
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This reverts commit e81deebfd8.
My reasoning in the above commit was wrong. Consider the following code:
class A {
void foo() {}
}
abstract class B extends A {
void foo([x]);
}
class C extends B {}
main() {
B b = new C();
b.foo(42); // BAD: A.foo can't accept arguments.
}
To ensure soundness, this code needs to be disallowed, and the current
mechanism for doing that is to use forEachOverridePair. Note that
forEachOverridePair is a bit of a misnomer; in addition to yielding
all pairs of methods (M1, M2) for which M1 overrides M2, it also
yields pairs of methods (M1, M2) for which the target class inherits
the concrete implementation M1, and M2 is part of the interface.
Technically this latter case is not an "override" but rather an
"implementation" (thanks to Lasse for pointing out this distinction).
However in both cases we need to do the same compile-time check to
ensure soundness: we need to check that the type of M1 is a subtype of
M2 (unless the check is suppressed by a "covariant" keyword). Hence
it makes sense for forEachOverridePair to cover both cases.
To ensure that the above example is properly rejected, it is crucial
that some invocation of forEachOverridePair yield the pair (A.foo,
B.foo). Prior to e81deebfd8,
forEachOverridePair(B) would not yield this pair, but
forEachOverridePair(C) would. After
e81deebfd8, both calls yield this pair.
When I made e81deebfd8, I failed to
notice that forEachOverridePair(C) would yield the pair, so I thought
there was a problem. So my "fix" was unnecessary. And it created a
fresh problem: it meant that the following code would be disallowed:
class A {
void foo() {}
}
abstract class B extends A {
void foo([x]);
}
class C extends B {
void foo([x]) {}
}
main() {
B b = new C();
b.foo(42); // OK: C.foo can accept an argument.
}
There is no a priori soundness reason for rejecting this code, and
according to Lasse, it has not yet been decided whether Dart 2.0 will
allow it.
This CL restores the old behavior. Rather than remove the test case
in e81deebfd8, it modifies it to
demonstrate why the old behavior was correct.
R=scheglov@google.com
Review-Url: https://codereview.chromium.org/3004023002 .
ClassHierarchy.forEachOverridePair contains special logic for unusual
cases like this one:
class A {
void foo() {}
}
class B extends A {
void foo();
}
main() {
B b = new B();
b.foo();
}
In this case, A.foo is considered to override B.foo (contrary to the
usual situation where the derived class method overrides the
superclass method). The reasoning is that calling foo on a concrete
instance of B will cause A.foo to be executed (as illustrated in
main); therefore A.foo is callable via the interface of B.foo, thus in
a sense A.foo "overrides" B.foo.
The code contained a questionable optimization, however; it only
executed this special logic if the derived class was concrete.
Presuambly the reasoning was that if B were abstract, then a concrete
instance of B could never be created, so this situation could never
arise.
However, there is nothing to stop a concrete class from being derived
from B, e.g.:
class A {
void foo() {}
}
abstract class B extends A {
void foo();
}
class C extends B {}
main() {
B b = new C();
b.foo();
}
Now, calling foo on a concrete instance of C will cause A.foo to be
executed (as illustrated in main); therefore A.foo is callable via the
interface of B.foo, as before. So we still need to report this as an
override pair even though B is abstract.
R=ahe@google.com, scheglov@google.com
Review-Url: https://codereview.chromium.org/2998383002 .
The front end will need to use this method to iterate through the
interface of a class in order to determine when to create forwarding
stubs.
The functionality already exists; this CL merely exposes it and adds
tests.
R=scheglov@google.com
Review-Url: https://codereview.chromium.org/3003913002 .
Normally getters and setters are considered distinct and unrelated by
the type inference algorithm. However, if a getter has no declared
type and doesn't override anything, then we fall back on inferring its
type from an inherited setter, and vice versa.
R=sigmund@google.com
Review-Url: https://codereview.chromium.org/2946733003 .
- Use strong-mode types for more precise tree shaking.
- Bail out nicely if dart:mirrors is used.
- Run the tree shaker in the VM target.
The initial tree-shaking pass could be combined with the type checking
pass (inserting implicit down casts) but for now they remain separate.
R=kmillikin@google.com
Review-Url: https://codereview.chromium.org/2627723003 .
"Covariance checks" are checks on certain parameters, necessary due to
the unsafe covariant subtyping rule for interface types.
The new pass generates a checked entry point for each method with
covariance checks. This entry point checks the parameters whose type
cannot be trusted, and then calls the actual method implementation.
Every typed call is then redirected to the checked entry point if the
interface taget declares any parameters with unsafe types, unless the
receiver is 'this'.
Dynamic calls and covariant overrides are not addressed by this CL,
these are still unchecked.
BUG=
R=kmillikin@google.com
Review-Url: https://codereview.chromium.org/2618393002 .
This is the result of:
- taking the diff of the branch closure_conversion to master in the kernel
repository
- updating the file paths
- applying the diff to the Dart SDK
- fixing conflicts between the changes to pkg/kernel in the Dart SDK and the master branch in the kernel repository
R=asgerf@google.com
Review-Url: https://codereview.chromium.org/2561723003 .
Type annotations in the supertype clauses of a class are now Supertypes
instead of InterfaceTypes. In the current version, the two classes
contain the same information, but they are about to diverge in the
following ways:
- An InterfaceType may be nullable, whereas a supertype cannot.
- An InterfaceType may represent the exact class, a subclass, or
a subtype of the given class.
- The type arguments to an interface type represent bounds, whereas
the arguments to a supertype are always exact.
We also introduce a class Substitution that represents an operator
that replaces type parameters with types, depending on the variance
of their use site.
A substitution can be applied to a DartType or a Supertype, and can
be generated independently of how it will be applied.
BUG=
R=kmillikin@google.com
Review URL: https://codereview.chromium.org/2439043002 .
When a class inherits two abstract members with the same name from
different supertypes, both members are now present the list returned
by ClassHierarchy.getInterfaceMembers. Previously, only one of the
member would be present.
This ensures that all override pairs can be detected, which in turn
is necessary for inserting covariance checks in strong mode.
Another change in this CL is that interface members are built
eagerly instead of on-demand. This makes the ClassHierarchy more
reliable when used for transformation, and easier to benchmark.
BUG=
R=kmillikin@google.com
Review URL: https://chromereviews.googleplex.com/520907013 .
Fields getters and setters should be implicit whenever possible
to ensure JS compilers can easily control how they are generated.
However, it is still useful to be able to take control of the getter
or setter in the IR. We should just refrain from doing so for common
cases, where it can have significant code size impact in JS.
We can use this to insert checked setters for fields that override
a setter with an incompatible type, or whose type references a type
variable.
There are two changes to facilitate this:
- Fields have two flags indicating if the implicit getter and/or
setter should be generated. If not set, there can be an explicit
getter/setter for it in the same class.
- Interface targets that reference a field now go through one
level of indirection. This lets us update interface targets in
the IR, which is necessary for redirecting calls to an explicit
getter or setter.
BUG=
R=kmillikin@google.com
Review URL: https://chromereviews.googleplex.com/504357013 .
We need the ability to efficiently transform a mixin application class
into a regular class, and the separation was obstructing it. It also
simplifies the IR a bit, although it no longer enforces the invariant
that mixin applications cannot contain fields and procedures.
The binary format is unchanged, so the separation still shows up in
there. This ensures the CL can land without any changes to the SDK.
BUG=
R=vegorov@google.com
Review URL: https://chromereviews.googleplex.com/488407013 .