-
Notifications
You must be signed in to change notification settings - Fork 112
Description
Some of the examples in our initial prototype track the use of classes, instance members, and static calls by tracking the const-instances in annotations.
Some examples:
@RecordUse('do_something')
void doSomething() {
print('a');
}
@RecordUse()
class MethodUse {
final String nativeResource;
const MethodUse(this.nativeResource);
}
// const instance `MyClass(42)` not tree-shaken if `doSomething` is not tree-shaken.@ClassUse('org.my_org.foo.A')
class A {}
@RecordUse()
class ClassUse {
final String name;
const ClassUse(this.name);
}
// const instance `MyClass(42)` not tree-shaken if `class A` is not tree-shaken.While looking at #2893, I realized that this behavior heavily relies on the VM compiler. The VM frontend does not remove annotations, it preserves them in the kernel format and passes them to the backend. The dart2js compiler removes all annotations. (Dart2js only keeps pragmas, and does so in its own format.) Dart2js does not use the kernel format in its later stages but another format. In this format there is a constant pool, but annotation consts do not occur in this constant pool. Implementing the VM-compiler behavior in the JS-compiler is a non-trivial task.
This leads to the observation that there is no semantics specified for annotations in the Dart language spec once you start compiling. Dart compilers may do as they please.
Also, the goal of the two examples above is to track method use and class use. The fields of the const instance would contain some information of the resource being used that is a connection between the Dart definition and the native definition (a C symbol or a Java class). This mapping could be saved in some other location accessible in the link hook.
Since the semantics aren't specified, behavior of this feature would be unpredictable:
- If you put the annotation on an instance method. And the compiler figures out only subtypes of the class ever exist in the program and every subtype overrides the method, and none of the overrides call the super method. It could delete the method, and so the annotation
- If you put the annotation on a class, but the whole-world optimization figures out only subtypes are used not the class itself, and it can throw the class out of the hierarchy without changing the Dart semantics, then the annotation would disappear.
Instead of tracking annotations on things, we should track the use of those things itself. Then for each of those things, we can define a precise semantics.
- Class use: also track all subclasses? Track each individual constructor call? Track each const instance in code. ([record_use] Completeness: const constructors static "calls" #2911, [record_use] Completeness: non-const Constructors calls #2907)
And what about users in other packages adding subtypes. - Instance member use: also track all dynamic calls? also track all overrides? And what about users in other packages adding subtypes with overrides? (So far for these reasons we've avoided adding support for instance calls.)
Metadata
Metadata
Assignees
Labels
Type
Projects
Status