Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: pkg/front_end/lib/src/fasta/kernel/kernel_outline_shaker.dart

Issue 2893493004: First step for modular output in fasta. (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 /// A transformation to create a self-contained modular kernel without
6 /// unnecessary references to other libraries.
7 library fasta.kernel.kernel_outline_shaker;
8
9 import 'package:kernel/ast.dart';
10 import 'package:kernel/core_types.dart';
11
12 import '../errors.dart' show internalError;
13
14 /// Removes from [program] unnecessary libraries, classes, and members.
ahe 2017/05/22 12:04:24 Removes unnecessary libraries, classes, and member
15 ///
16 /// This applies a simple "tree-shaking" technique: the full body of libraries
17 /// whose URI match [isIncluded] are preserved, and so is the outline of the
18 /// members and classes which are referred to transitively from these included
19 /// libraries.
20 ///
21 /// The intent is that the resulting program has the entire code that is meant
22 /// to be included and the minimum required to prevent dangling references and
23 /// allow modular program transformations.
24 ///
25 /// Note that the resulting program may include libraries not in [isIncluded],
26 /// but those will be marked as external. There should be no method bodies for
27 /// any members of those libraries.
28 ///
29 /// When [retainClassMembers] is true, all members of retained classes will be
30 /// retained as well.
31 void trimProgram(Program program, bool isIncluded(Uri uri),
32 {bool retainClassMembers: true}) {
33 var result = new _Analysis(program, isIncluded, retainClassMembers).run();
34 new _Shaker(result, isIncluded).transform(program);
35 }
36
37 /// Result of analyzing a program before tree-shaking it.
38 abstract class _AnalysisResult {
39 /// Whether a library should be preserved and mark as external.
40 bool isLibraryUsed(Library library);
41
42 /// Whether a class should be preserved. If a class is preserved, its
43 /// supertypes will be preserved too, but some of it members may not be
44 /// included.
45 bool isClassUsed(Class cls);
46
47 /// Whether a member should be preserved. If so, its enclosing class/library
48 /// will be preserved too.
49 bool isMemberUsed(Member member);
50 }
51
52 /// Visitor used by [trimProgram] to collects which libraries, classes, and
53 /// members should be preserved.
54 class _Analysis extends RecursiveVisitor implements _AnalysisResult {
55 /// The program being analyzed.
56 final Program program;
57
58 /// Helper to fetch classes and members of the core libraries.
59 final CoreTypes coreTypes;
60
61 /// Filter to determine libraries that should be analyzed.
62 final Filter isIncluded;
63
64 /// When retaining a class, whether to retain all of its members.
65 // TODO(sigmund): delete this option once we figure out the long term plan. Do
66 // we need to do this? Today it seems necessary because some transformations
67 // require it, but maybe we don't need them all (e.g. only constructors and
68 // members whose inferenceTarget is referred do in the sources?) Do we need a
69 // different retention policy for including the type hierarchy with and
70 // without members?
71 final bool retainClassMembers;
72
73 /// Libraries that contained code that is transitively reachable from the
74 /// included libraries.
75 final Set<Library> _libraries = new Set<Library>();
76
77 /// Classes that are transitively reachable from the included libraries.
78 final Set<Class> _classes = new Set<Class>();
79
80 /// Members that are transitively reachable from the included libraries.
81 final Set<Member> _members = new Set<Member>();
82
83 @override
84 bool isLibraryUsed(Library library) => _libraries.contains(library);
85
86 @override
87 bool isClassUsed(Class cls) => _classes.contains(cls);
88
89 @override
90 bool isMemberUsed(Member m) => _members.contains(m);
91
92 _Analysis(this.program, this.isIncluded, this.retainClassMembers)
93 : coreTypes = new CoreTypes(program);
94
95 _AnalysisResult run() {
96 _markRequired();
97 _markMember(program.mainMethod);
98 for (var library in program.libraries) {
99 if (isIncluded(library.importUri)) {
100 library.accept(this);
101 }
102 }
103 return this;
104 }
105
106 /// Marks classes and members that are assumed to exist by fasta or by
107 /// transformers.
108 void _markRequired() {
109 coreTypes.objectClass.members.forEach(_markMember);
110
111 // These are assumed to be available by fasta:
112 _markClass(coreTypes.objectClass);
113 _markClass(coreTypes.nullClass);
114 _markClass(coreTypes.boolClass);
115 _markClass(coreTypes.intClass);
116 _markClass(coreTypes.numClass);
117 _markClass(coreTypes.doubleClass);
118 _markClass(coreTypes.stringClass);
119 _markClass(coreTypes.listClass);
120 _markClass(coreTypes.mapClass);
121 _markClass(coreTypes.iterableClass);
122 _markClass(coreTypes.iteratorClass);
123 _markClass(coreTypes.futureClass);
124 _markClass(coreTypes.streamClass);
125 _markClass(coreTypes.symbolClass);
126 _markClass(coreTypes.internalSymbolClass);
127 _markClass(coreTypes.typeClass);
128 _markClass(coreTypes.functionClass);
129 _markClass(coreTypes.invocationClass);
130 _markMember(coreTypes.getMember("dart:_internal", "ExternalName", ""));
131
132 // These are needed by the continuation (async/await) transformer:
133 _markClass(coreTypes.getClass('dart:core', 'Iterator'));
134 _markClass(coreTypes.getClass('dart:async', 'Future'));
135 _markClass(coreTypes.getClass('dart:async', 'FutureOr'));
136 _markClass(coreTypes.getClass('dart:async', 'Completer'));
137 _markMember(coreTypes.getMember('dart:async', 'Completer', 'sync'));
138 _markMember(coreTypes.getMember('dart:core', '_SyncIterable', ''));
139 _markMember(coreTypes.getMember('dart:async', '_StreamIterator', ''));
140 _markMember(coreTypes.getMember('dart:async', 'Future', 'microtask'));
141 _markMember(
142 coreTypes.getMember('dart:async', '_AsyncStarStreamController', ''));
143 _markMember(coreTypes.getTopLevelMember('dart:core', 'print'));
144 _markMember(
145 coreTypes.getTopLevelMember('dart:async', '_asyncThenWrapperHelper'));
146 _markMember(
147 coreTypes.getTopLevelMember('dart:async', '_asyncErrorWrapperHelper'));
148 _markMember(coreTypes.getTopLevelMember('dart:async', '_awaitHelper'));
149
150 // These are needed by the mixin transformer
151 _markMember(coreTypes.getMember('dart:core', '_InvocationMirror', ''));
152 _markMember(coreTypes.getMember('dart:core', 'List', 'from'));
153 }
154
155 /// Mark a library as used.
156 _markLibrary(Library lib) {
157 if (!_libraries.add(lib)) return;
158 }
159
160 /// Mark a class and it's supertypes as used.
161 void _markClass(Class cls) {
162 if (cls == null || !_classes.add(cls)) return;
163 _markLibrary(cls.parent);
164 visitList(cls.annotations, this);
165 cls.supertype?.accept(this);
166 cls.mixedInType?.accept(this);
167 visitList(cls.implementedTypes, this);
168 visitList(cls.typeParameters, this);
169
170 if (retainClassMembers) cls.members.forEach(_markMember);
171 }
172
173 _markMember(Member m) {
174 if (m == null || !_members.add(m)) return;
175 _markMemberInterface(m);
176 var parent = m.parent;
177 if (parent is Library) {
178 _markLibrary(parent);
179 } else if (parent is Class) {
180 _markClass(parent);
181 }
182 }
183
184 void _markMemberInterface(Member node) {
185 if (node is Field) {
186 node.type.accept(this);
187 } else if (node is Procedure) {
188 _markFunctionInterface(node.function);
189 }
190 }
191
192 _markFunctionInterface(FunctionNode node) {
193 for (var parameter in node.typeParameters) {
194 parameter.bound.accept(this);
195 }
196 for (var parameter in node.positionalParameters) {
197 parameter.type.accept(this);
198 }
199 for (var parameter in node.namedParameters) {
200 parameter.type.accept(this);
201 }
202 node.returnType.accept(this);
203 }
204
205 @override
206 visitFunctionNode(FunctionNode node) {
207 switch (node.asyncMarker) {
208 case AsyncMarker.Sync:
209 break;
210 case AsyncMarker.SyncStar:
211 _markClass(coreTypes.iterableClass);
scheglov 2017/05/18 15:54:08 These classes are already included in _markRequire
Siggi Cherem (dart-lang) 2017/05/19 04:37:32 good point. I removed them from here. Also - now t
212 break;
213 case AsyncMarker.Async:
214 _markClass(coreTypes.futureClass);
215 break;
216 case AsyncMarker.AsyncStar:
217 _markClass(coreTypes.streamClass);
218 break;
219 case AsyncMarker.SyncYielding:
220 break;
221 }
222 node.visitChildren(this);
223 }
224
225 @override
226 visitSuperInitializer(SuperInitializer node) {
227 _markMember(node.target);
228 node.visitChildren(this);
229 }
230
231 @override
232 visitRedirectingInitializer(RedirectingInitializer node) {
233 _markMember(node.target);
234 node.visitChildren(this);
235 }
236
237 @override
238 visitConstructorInvocation(ConstructorInvocation node) {
239 _markMember(node.target);
240 node.visitChildren(this);
241 }
242
243 @override
244 visitStaticInvocation(StaticInvocation node) {
245 _markMember(node.target);
246 node.visitChildren(this);
247 }
248
249 @override
250 visitDirectMethodInvocation(DirectMethodInvocation node) {
251 if (node.receiver is! ThisExpression) {
252 return internalError('Direct calls are only supported on "this"');
253 }
254 _markMember(node.target);
255 node.visitChildren(this);
256 }
257
258 @override
259 visitMethodInvocation(MethodInvocation node) {
260 _markMember(node.interfaceTarget);
261 node.visitChildren(this);
262 }
263
264 @override
265 visitStaticGet(StaticGet node) {
266 _markMember(node.target);
267 node.visitChildren(this);
268 }
269
270 @override
271 visitStaticSet(StaticSet node) {
272 _markMember(node.target);
273 node.visitChildren(this);
274 }
275
276 @override
277 visitDirectPropertyGet(DirectPropertyGet node) {
278 _markMember(node.target);
279 node.visitChildren(this);
280 }
281
282 @override
283 visitDirectPropertySet(DirectPropertySet node) {
284 _markMember(node.target);
285 node.visitChildren(this);
286 }
287
288 @override
289 visitSuperPropertyGet(SuperPropertyGet node) {
290 _markMember(node.interfaceTarget);
291 node.visitChildren(this);
292 }
293
294 @override
295 visitSuperPropertySet(SuperPropertySet node) {
296 _markMember(node.interfaceTarget);
297 node.visitChildren(this);
298 }
299
300 @override
301 visitPropertyGet(PropertyGet node) {
302 _markMember(node.interfaceTarget);
303 node.visitChildren(this);
304 }
305
306 @override
307 visitPropertySet(PropertySet node) {
308 _markMember(node.interfaceTarget);
309 node.visitChildren(this);
310 }
311
312 @override
313 visitListLiteral(ListLiteral node) {
314 _markClass(coreTypes.listClass);
315 node.visitChildren(this);
316 }
317
318 @override
319 visitMapLiteral(MapLiteral node) {
320 _markClass(coreTypes.mapClass);
321 node.visitChildren(this);
322 }
323
324 @override
325 visitStringConcatenation(StringConcatenation node) {
326 node.visitChildren(this);
327 }
328
329 @override
330 visitInterfaceType(InterfaceType node) {
331 _markClass(node.classNode);
332 node.visitChildren(this);
333 }
334
335 @override
336 visitSupertype(Supertype node) {
337 _markClass(node.classNode);
338 node.visitChildren(this);
339 }
340
341 @override
342 visitDoubleLiteral(DoubleLiteral node) {
343 _markClass(coreTypes.doubleClass);
344 }
345
346 @override
347 visitSymbolLiteral(SymbolLiteral node) {
348 _markClass(coreTypes.symbolClass);
349 }
350
351 @override
352 visitTypeLiteral(TypeLiteral node) {
353 _markClass(coreTypes.typeClass);
354 node.visitChildren(this);
355 }
356
357 @override
358 visitTypedefReference(Typedef node) {
359 return internalError('not implemented');
360 }
361 }
362
363 /// Transformer that trims everything in the excluded libraries that is not
364 /// marked as preserved by the [_Analysis] above. For every member in these
365 /// excluded libraries, this transformer also removes function bodies and
366 /// initializers.
367 class _Shaker extends Transformer {
368 final _AnalysisResult result;
369 final Filter isIncluded;
370
371 _Shaker(this.result, this.isIncluded);
372
373 void transform(Program program) {
374 var toRemove = new Set<Library>();
375 for (var library in program.libraries) {
376 if (!isIncluded(library.importUri)) {
377 if (!result.isLibraryUsed(library)) {
378 toRemove.add(library);
379 } else {
380 library.isExternal = true;
381 library.transformChildren(this);
382 }
383 }
384 }
385 program.libraries.removeWhere(toRemove.contains);
386 }
387
388 Class visitClass(Class node) {
389 if (!result.isClassUsed(node)) {
390 node.canonicalName?.unbind();
391 return null; // Remove the class.
392 } else {
393 node.transformChildren(this);
394 return node;
395 }
396 }
397
398 Member defaultMember(Member node) {
399 if (!result.isMemberUsed(node)) {
400 node.canonicalName?.unbind();
401 return null;
402 } else {
403 if (node is Procedure) {
404 _clearFunction(node.function);
405 } else if (node is Field) {
406 node.initializer = null;
407 } else if (node is Constructor) {
408 node.initializers.clear();
409 _clearFunction(node.function);
410 }
411 return node;
412 }
413 }
414
415 _clearFunction(FunctionNode function) {
416 function.body = null;
417 // TODO(sigmund): Fix directly the continuation transformer. The async/await
418 // continuation transformer fails if it finds a function with no body that
419 // it is marked with async/async*/sync*, we shouldn't be patching that here.
420 function.dartAsyncMarker = function.asyncMarker;
421 function.asyncMarker = AsyncMarker.Sync;
422 }
423
424 /// Types appear to be encoded directly, so we have no need to preserve
425 /// typedefs.
426 // TODO(sigmund): revisit if this is not the case, the `inputError` in the
427 // analysis step is meant to detect this.
428 Typedef visitTypedef(Typedef node) => null;
429
430 TreeNode defaultTreeNode(TreeNode node) => node;
431 }
432
433 typedef bool Filter(Uri uri);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698