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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/compiler.dart

Issue 692513002: Remove old dart2js code. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, 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 part of dart2js;
6
7 /**
8 * If true, print a warning for each method that was resolved, but not
9 * compiled.
10 */
11 const bool REPORT_EXCESS_RESOLUTION = false;
12
13 /**
14 * Contains backend-specific data that is used throughout the compilation of
15 * one work item.
16 */
17 class ItemCompilationContext {
18 }
19
20 abstract class WorkItem {
21 final ItemCompilationContext compilationContext;
22 /**
23 * Documentation wanted -- johnniwinther
24 *
25 * Invariant: [element] must be a declaration element.
26 */
27 final AstElement element;
28 TreeElements get resolutionTree;
29
30 WorkItem(this.element, this.compilationContext) {
31 assert(invariant(element, element.isDeclaration));
32 }
33
34 void run(Compiler compiler, Enqueuer world);
35 }
36
37 /// [WorkItem] used exclusively by the [ResolutionEnqueuer].
38 class ResolutionWorkItem extends WorkItem {
39 TreeElements resolutionTree;
40
41 ResolutionWorkItem(AstElement element,
42 ItemCompilationContext compilationContext)
43 : super(element, compilationContext);
44
45 void run(Compiler compiler, ResolutionEnqueuer world) {
46 compiler.analyze(this, world);
47 resolutionTree = element.resolvedAst.elements;
48 }
49
50 bool isAnalyzed() => resolutionTree != null;
51 }
52
53 // TODO(johnniwinther): Split this class into interface and implementation.
54 // TODO(johnniwinther): Move this implementation to the JS backend.
55 class CodegenRegistry extends Registry {
56 final Compiler compiler;
57 final TreeElements treeElements;
58
59 CodegenRegistry(this.compiler, this.treeElements);
60
61 bool get isForResolution => false;
62
63 Element get currentElement => treeElements.analyzedElement;
64
65 // TODO(johnniwinther): Remove this getter when [Registry] creates a
66 // dependency node.
67 Setlet<Element> get otherDependencies => treeElements.otherDependencies;
68
69 CodegenEnqueuer get world => compiler.enqueuer.codegen;
70 js_backend.JavaScriptBackend get backend => compiler.backend;
71
72 void registerDependency(Element element) {
73 treeElements.registerDependency(element);
74 }
75
76 void registerInlining(Element inlinedElement, Element context) {
77 if (compiler.dumpInfo) {
78 compiler.dumpInfoTask.registerInlined(inlinedElement, context);
79 }
80 }
81
82 void registerInstantiatedClass(ClassElement element) {
83 world.registerInstantiatedClass(element, this);
84 }
85
86 void registerInstantiatedType(InterfaceType type) {
87 world.registerInstantiatedType(type, this);
88 }
89
90 void registerStaticUse(Element element) {
91 world.registerStaticUse(element);
92 }
93
94 void registerDynamicInvocation(Selector selector) {
95 world.registerDynamicInvocation(selector);
96 compiler.dumpInfoTask.elementUsesSelector(currentElement, selector);
97 }
98
99 void registerDynamicSetter(Selector selector) {
100 world.registerDynamicSetter(selector);
101 compiler.dumpInfoTask.elementUsesSelector(currentElement, selector);
102 }
103
104 void registerDynamicGetter(Selector selector) {
105 world.registerDynamicGetter(selector);
106 compiler.dumpInfoTask.elementUsesSelector(currentElement, selector);
107 }
108
109 void registerGetterForSuperMethod(Element element) {
110 world.registerGetterForSuperMethod(element);
111 }
112
113 void registerFieldGetter(Element element) {
114 world.registerFieldGetter(element);
115 }
116
117 void registerFieldSetter(Element element) {
118 world.registerFieldSetter(element);
119 }
120
121 void registerIsCheck(DartType type) {
122 world.registerIsCheck(type, this);
123 backend.registerIsCheckForCodegen(type, world, this);
124 }
125
126 void registerCompileTimeConstant(ConstantValue constant) {
127 backend.registerCompileTimeConstant(constant, this);
128 backend.constants.addCompileTimeConstantForEmission(constant);
129 }
130
131 void registerTypeVariableBoundsSubtypeCheck(DartType subtype,
132 DartType supertype) {
133 backend.registerTypeVariableBoundsSubtypeCheck(subtype, supertype);
134 }
135
136 void registerClosureWithFreeTypeVariables(FunctionElement element) {
137 backend.registerClosureWithFreeTypeVariables(element, world, this);
138 }
139
140 void registerGetOfStaticFunction(FunctionElement element) {
141 world.registerGetOfStaticFunction(element);
142 }
143
144 void registerSelectorUse(Selector selector) {
145 world.registerSelectorUse(selector);
146 }
147
148 void registerFactoryWithTypeArguments() {
149 world.registerFactoryWithTypeArguments(this);
150 }
151
152 void registerConstSymbol(String name) {
153 backend.registerConstSymbol(name, this);
154 }
155
156 void registerSpecializedGetInterceptor(Set<ClassElement> classes) {
157 backend.registerSpecializedGetInterceptor(classes);
158 }
159
160 void registerUseInterceptor() {
161 backend.registerUseInterceptor(world);
162 }
163
164 void registerTypeConstant(ClassElement element) {
165 backend.customElementsAnalysis.registerTypeConstant(element, world);
166 }
167
168 void registerStaticInvocation(Element element) {
169 world.registerStaticUse(element);
170 }
171
172 void registerInstantiation(InterfaceType type) {
173 world.registerInstantiatedType(type, this);
174 }
175 }
176
177 /// [WorkItem] used exclusively by the [CodegenEnqueuer].
178 class CodegenWorkItem extends WorkItem {
179 Registry registry;
180 final TreeElements resolutionTree;
181
182 CodegenWorkItem(AstElement element,
183 ItemCompilationContext compilationContext)
184 : this.resolutionTree = element.resolvedAst.elements,
185 super(element, compilationContext) {
186 assert(invariant(element, resolutionTree != null,
187 message: 'Resolution tree is null for $element in codegen work item'));
188 }
189
190 void run(Compiler compiler, CodegenEnqueuer world) {
191 if (world.isProcessed(element)) return;
192
193 registry = new CodegenRegistry(compiler, resolutionTree);
194 compiler.codegen(this, world);
195 }
196 }
197
198 typedef void DeferredAction();
199
200 class DeferredTask {
201 final Element element;
202 final DeferredAction action;
203
204 DeferredTask(this.element, this.action);
205 }
206
207 /// Interface for registration of element dependencies.
208 abstract class Registry {
209 // TODO(johnniwinther): Remove this getter when [Registry] creates a
210 // dependency node.
211 Iterable<Element> get otherDependencies;
212
213 void registerDependency(Element element);
214
215 bool get isForResolution;
216
217 void registerStaticInvocation(Element element);
218
219 void registerInstantiation(InterfaceType type);
220
221 void registerGetOfStaticFunction(FunctionElement element);
222 }
223
224 abstract class Backend {
225 final Compiler compiler;
226
227 Backend(this.compiler);
228
229 /// The [ConstantSystem] used to interpret compile-time constants for this
230 /// backend.
231 ConstantSystem get constantSystem;
232
233 /// The constant environment for the backend interpretation of compile-time
234 /// constants.
235 BackendConstantEnvironment get constants;
236
237 /// The compiler task responsible for the compilation of constants for both
238 /// the frontend and the backend.
239 ConstantCompilerTask get constantCompilerTask;
240
241 /// Backend callback methods for the resolution phase.
242 ResolutionCallbacks get resolutionCallbacks;
243
244 /// Set of classes that need to be considered for reflection although not
245 /// otherwise visible during resolution.
246 Iterable<ClassElement> classesRequiredForReflection = const [];
247
248 // Given a [FunctionElement], return a buffer with the code generated for it
249 // or null if no code was generated.
250 CodeBuffer codeOf(Element element) => null;
251
252 void initializeHelperClasses() {}
253
254 void enqueueHelpers(ResolutionEnqueuer world, Registry registry);
255 void codegen(CodegenWorkItem work);
256
257 // The backend determines the native resolution enqueuer, with a no-op
258 // default, so tools like dart2dart can ignore the native classes.
259 native.NativeEnqueuer nativeResolutionEnqueuer(world) {
260 return new native.NativeEnqueuer();
261 }
262 native.NativeEnqueuer nativeCodegenEnqueuer(world) {
263 return new native.NativeEnqueuer();
264 }
265
266 void assembleProgram();
267 List<CompilerTask> get tasks;
268
269 void onResolutionComplete() {}
270
271 ItemCompilationContext createItemCompilationContext() {
272 return new ItemCompilationContext();
273 }
274
275 bool classNeedsRti(ClassElement cls);
276 bool methodNeedsRti(FunctionElement function);
277
278 /// Called during codegen when [constant] has been used.
279 void registerCompileTimeConstant(ConstantValue constant, Registry registry) {}
280
281 /// Called during resolution when a constant value for [metadata] on
282 /// [annotatedElement] has been evaluated.
283 void registerMetadataConstant(MetadataAnnotation metadata,
284 Element annotatedElement,
285 Registry registry) {}
286
287 /// Called during resolution to notify to the backend that a class is
288 /// being instantiated.
289 void registerInstantiatedClass(ClassElement cls,
290 Enqueuer enqueuer,
291 Registry registry) {}
292
293 /// Register an is check to the backend.
294 void registerIsCheckForCodegen(DartType type,
295 Enqueuer enqueuer,
296 Registry registry) {}
297
298 /// Register a runtime type variable bound tests between [typeArgument] and
299 /// [bound].
300 void registerTypeVariableBoundsSubtypeCheck(DartType typeArgument,
301 DartType bound) {}
302
303 /// Returns `true` if [element] represent the assert function.
304 bool isAssertMethod(Element element) => false;
305
306 /**
307 * Call this to register that an instantiated generic class has a call
308 * method.
309 */
310 void registerCallMethodWithFreeTypeVariables(
311 Element callMethod,
312 Enqueuer enqueuer,
313 Registry registry) {}
314
315 /**
316 * Call this to register that a getter exists for a function on an
317 * instantiated generic class.
318 */
319 void registerClosureWithFreeTypeVariables(
320 Element closure,
321 Enqueuer enqueuer,
322 Registry registry) {}
323
324 /// Call this to register that a member has been closurized.
325 void registerBoundClosure(Enqueuer enqueuer) {}
326
327 /// Call this to register that a static function has been closurized.
328 void registerGetOfStaticFunction(Enqueuer enqueuer) {}
329
330 /**
331 * Call this to register that the [:runtimeType:] property has been accessed.
332 */
333 void registerRuntimeType(Enqueuer enqueuer, Registry registry) {}
334
335 /**
336 * Call this method to enable [noSuchMethod] handling in the
337 * backend.
338 */
339 void enableNoSuchMethod(Element context, Enqueuer enqueuer) {
340 enqueuer.registerInvocation(compiler.noSuchMethodSelector);
341 }
342
343 /// Call this method to enable support for isolates.
344 void enableIsolateSupport(Enqueuer enqueuer) {}
345
346 void registerRequiredType(DartType type, Element enclosingElement) {}
347 void registerClassUsingVariableExpression(ClassElement cls) {}
348
349 void registerConstSymbol(String name, Registry registry) {}
350 void registerNewSymbol(Registry registry) {}
351
352 bool isNullImplementation(ClassElement cls) {
353 return cls == compiler.nullClass;
354 }
355
356 ClassElement get intImplementation => compiler.intClass;
357 ClassElement get doubleImplementation => compiler.doubleClass;
358 ClassElement get numImplementation => compiler.numClass;
359 ClassElement get stringImplementation => compiler.stringClass;
360 ClassElement get listImplementation => compiler.listClass;
361 ClassElement get growableListImplementation => compiler.listClass;
362 ClassElement get fixedListImplementation => compiler.listClass;
363 ClassElement get constListImplementation => compiler.listClass;
364 ClassElement get mapImplementation => compiler.mapClass;
365 ClassElement get constMapImplementation => compiler.mapClass;
366 ClassElement get functionImplementation => compiler.functionClass;
367 ClassElement get typeImplementation => compiler.typeClass;
368 ClassElement get boolImplementation => compiler.boolClass;
369 ClassElement get nullImplementation => compiler.nullClass;
370 ClassElement get uint32Implementation => compiler.intClass;
371 ClassElement get uint31Implementation => compiler.intClass;
372 ClassElement get positiveIntImplementation => compiler.intClass;
373
374 ClassElement defaultSuperclass(ClassElement element) => compiler.objectClass;
375
376 bool isDefaultNoSuchMethodImplementation(Element element) {
377 assert(element.name == Compiler.NO_SUCH_METHOD);
378 ClassElement classElement = element.enclosingClass;
379 return classElement == compiler.objectClass;
380 }
381
382 bool isInterceptorClass(ClassElement element) => false;
383
384 /// Returns `true` if [element] is a foreign element, that is, that the
385 /// backend has specialized handling for the element.
386 bool isForeign(Element element) => false;
387
388 /// Returns `true` if [library] is a backend specific library whose members
389 /// have special treatment, such as being allowed to extends blacklisted
390 /// classes or member being eagerly resolved.
391 bool isBackendLibrary(LibraryElement library) {
392 // TODO(johnnwinther): Remove this when patching is only done by the
393 // JavaScript backend.
394 Uri canonicalUri = library.canonicalUri;
395 if (canonicalUri == js_backend.JavaScriptBackend.DART_JS_HELPER ||
396 canonicalUri == js_backend.JavaScriptBackend.DART_INTERCEPTORS) {
397 return true;
398 }
399 return false;
400 }
401
402 void registerStaticUse(Element element, Enqueuer enqueuer) {}
403
404 /// This method is called immediately after the [LibraryElement] [library] has
405 /// been created.
406 void onLibraryCreated(LibraryElement library) {}
407
408 /// This method is called immediately after the [library] and its parts have
409 /// been scanned.
410 Future onLibraryScanned(LibraryElement library, LibraryLoader loader) {
411 if (library.isPlatformLibrary && !library.isPatched) {
412 // Apply patch, if any.
413 Uri patchUri = compiler.resolvePatchUri(library.canonicalUri.path);
414 if (patchUri != null) {
415 return compiler.patchParser.patchLibrary(loader, patchUri, library);
416 }
417 }
418 if (library.canUseNative) {
419 library.forEachLocalMember((Element element) {
420 if (element.isClass) {
421 checkNativeAnnotation(compiler, element);
422 }
423 });
424 }
425 return new Future.value();
426 }
427
428 /// This method is called when all new libraries loaded through
429 /// [LibraryLoader.loadLibrary] has been loaded and their imports/exports
430 /// have been computed.
431 Future onLibrariesLoaded(Map<Uri, LibraryElement> loadedLibraries) {
432 return new Future.value();
433 }
434
435 /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed
436 /// annotations. The arguments corresponds to the unions of the corresponding
437 /// fields of the annotations.
438 void registerMirrorUsage(Set<String> symbols,
439 Set<Element> targets,
440 Set<Element> metaTargets) {}
441
442 /// Returns true if this element needs reflection information at runtime.
443 bool isAccessibleByReflection(Element element) => true;
444
445 /// Returns true if this element is covered by a mirrorsUsed annotation.
446 ///
447 /// Note that it might still be ok to tree shake the element away if no
448 /// reflection is used in the program (and thus [isTreeShakingDisabled] is
449 /// still false). Therefore _do not_ use this predicate to decide inclusion
450 /// in the tree, use [requiredByMirrorSystem] instead.
451 bool referencedFromMirrorSystem(Element element, [recursive]) => false;
452
453 /// Returns true if this element has to be enqueued due to
454 /// mirror usage. Might be a subset of [referencedFromMirrorSystem] if
455 /// normal tree shaking is still active ([isTreeShakingDisabled] is false).
456 bool requiredByMirrorSystem(Element element) => false;
457
458 /// Returns true if global optimizations such as type inferencing
459 /// can apply to this element. One category of elements that do not
460 /// apply is runtime helpers that the backend calls, but the
461 /// optimizations don't see those calls.
462 bool canBeUsedForGlobalOptimizations(Element element) => true;
463
464 /// Called when [enqueuer]'s queue is empty, but before it is closed.
465 /// This is used, for example, by the JS backend to enqueue additional
466 /// elements needed for reflection. [recentClasses] is a collection of
467 /// all classes seen for the first time by the [enqueuer] since the last call
468 /// to [onQueueEmpty].
469 ///
470 /// A return value of [:true:] indicates that [recentClasses] has been
471 /// processed and its elements do not need to be seen in the next round. When
472 /// [:false:] is returned, [onQueueEmpty] will be called again once the
473 /// resolution queue has drained and [recentClasses] will be a superset of the
474 /// current value.
475 ///
476 /// There is no guarantee that a class is only present once in
477 /// [recentClasses], but every class seen by the [enqueuer] will be present in
478 /// [recentClasses] at least once.
479 bool onQueueEmpty(Enqueuer enqueuer, Iterable<ClassElement> recentClasses) {
480 return true;
481 }
482
483 /// Called after [element] has been resolved.
484 // TODO(johnniwinther): Change [TreeElements] to [Registry] or a dependency
485 // node. [elements] is currently unused by the implementation.
486 void onElementResolved(Element element, TreeElements elements) {}
487
488 // Does this element belong in the output
489 bool shouldOutput(Element element) => true;
490
491 FunctionElement helperForBadMain() => null;
492
493 FunctionElement helperForMissingMain() => null;
494
495 FunctionElement helperForMainArity() => null;
496
497 void forgetElement(Element element) {}
498
499 void registerMainHasArguments(Enqueuer enqueuer) {}
500 }
501
502 /// Backend callbacks function specific to the resolution phase.
503 class ResolutionCallbacks {
504 /// Register that [node] is a call to `assert`.
505 void onAssert(Send node, Registry registry) {}
506
507 /// Called during resolution to notify to the backend that the
508 /// program uses string interpolation.
509 void onStringInterpolation(Registry registry) {}
510
511 /// Called during resolution to notify to the backend that the
512 /// program has a catch statement.
513 void onCatchStatement(Registry registry) {}
514
515 /// Called during resolution to notify to the backend that the
516 /// program explicitly throws an exception.
517 void onThrowExpression(Registry registry) {}
518
519 /// Called during resolution to notify to the backend that the
520 /// program has a global variable with a lazy initializer.
521 void onLazyField(Registry registry) {}
522
523 /// Called during resolution to notify to the backend that the
524 /// program uses a type variable as an expression.
525 void onTypeVariableExpression(Registry registry) {}
526
527 /// Called during resolution to notify to the backend that the
528 /// program uses a type literal.
529 void onTypeLiteral(DartType type, Registry registry) {}
530
531 /// Called during resolution to notify to the backend that the
532 /// program has a catch statement with a stack trace.
533 void onStackTraceInCatch(Registry registry) {}
534
535 /// Register an is check to the backend.
536 void onIsCheck(DartType type, Registry registry) {}
537
538 /// Register an as check to the backend.
539 void onAsCheck(DartType type, Registry registry) {}
540
541 /// Registers that a type variable bounds check might occur at runtime.
542 void onTypeVariableBoundCheck(Registry registry) {}
543
544 /// Register that the application may throw a [NoSuchMethodError].
545 void onThrowNoSuchMethod(Registry registry) {}
546
547 /// Register that the application may throw a [RuntimeError].
548 void onThrowRuntimeError(Registry registry) {}
549
550 /// Register that the application may throw an
551 /// [AbstractClassInstantiationError].
552 void onAbstractClassInstantiation(Registry registry) {}
553
554 /// Register that the application may throw a [FallThroughError].
555 void onFallThroughError(Registry registry) {}
556
557 /// Register that a super call will end up calling
558 /// [: super.noSuchMethod :].
559 void onSuperNoSuchMethod(Registry registry) {}
560
561 /// Register that the application creates a constant map.
562 void onConstantMap(Registry registry) {}
563
564 /// Called when resolving the `Symbol` constructor.
565 void onSymbolConstructor(Registry registry) {}
566 }
567
568 /**
569 * Key class used in [TokenMap] in which the hash code for a token is based
570 * on the [charOffset].
571 */
572 class TokenKey {
573 final Token token;
574 TokenKey(this.token);
575 int get hashCode => token.charOffset;
576 operator==(other) => other is TokenKey && token == other.token;
577 }
578
579 /// Map of tokens and the first associated comment.
580 /*
581 * This implementation was chosen among several candidates for its space/time
582 * efficiency by empirical tests of running dartdoc on dartdoc itself. Time
583 * measurements for the use of [Compiler.commentMap]:
584 *
585 * 1) Using [TokenKey] as key (this class): ~80 msec
586 * 2) Using [TokenKey] as key + storing a separate map in each script: ~120 msec
587 * 3) Using [Token] as key in a [Map]: ~38000 msec
588 * 4) Storing comments is new field in [Token]: ~20 msec
589 * (Abandoned due to the increased memory usage)
590 * 5) Storing comments in an [Expando]: ~14000 msec
591 * 6) Storing token/comments pairs in a linked list: ~5400 msec
592 */
593 class TokenMap {
594 Map<TokenKey,Token> comments = new Map<TokenKey,Token>();
595
596 Token operator[] (Token key) {
597 if (key == null) return null;
598 return comments[new TokenKey(key)];
599 }
600
601 void operator[]= (Token key, Token value) {
602 if (key == null) return;
603 comments[new TokenKey(key)] = value;
604 }
605 }
606
607 abstract class Compiler implements DiagnosticListener {
608 static final Uri DART_CORE = new Uri(scheme: 'dart', path: 'core');
609 static final Uri DART_MIRRORS = new Uri(scheme: 'dart', path: 'mirrors');
610 static final Uri DART_NATIVE_TYPED_DATA =
611 new Uri(scheme: 'dart', path: '_native_typed_data');
612 static final Uri DART_INTERNAL = new Uri(scheme: 'dart', path: '_internal');
613 static final Uri DART_ASYNC = new Uri(scheme: 'dart', path: 'async');
614
615 final Stopwatch totalCompileTime = new Stopwatch();
616 int nextFreeClassId = 0;
617 World world;
618 String assembledCode;
619 Types types;
620
621 final CacheStrategy cacheStrategy;
622
623 /**
624 * Map from token to the first preceeding comment token.
625 */
626 final TokenMap commentMap = new TokenMap();
627
628 /**
629 * Records global dependencies, that is, dependencies that don't
630 * correspond to a particular element.
631 *
632 * We should get rid of this and ensure that all dependencies are
633 * associated with a particular element.
634 */
635 Registry globalDependencies;
636
637 /**
638 * Dependencies that are only included due to mirrors.
639 *
640 * We should get rid of this and ensure that all dependencies are
641 * associated with a particular element.
642 */
643 // TODO(johnniwinther): This should not be a [ResolutionRegistry].
644 final Registry mirrorDependencies =
645 new ResolutionRegistry.internal(null, new TreeElementMapping(null));
646
647 final bool enableMinification;
648
649 /// When `true` emits URIs in the reflection metadata.
650 final bool preserveUris;
651
652 final bool enableTypeAssertions;
653 final bool enableUserAssertions;
654 final bool trustTypeAnnotations;
655 final bool enableConcreteTypeInference;
656 final bool disableTypeInferenceFlag;
657 final bool dumpInfo;
658 final bool useContentSecurityPolicy;
659
660 /**
661 * The maximum size of a concrete type before it widens to dynamic during
662 * concrete type inference.
663 */
664 final int maxConcreteTypeSize;
665 final bool analyzeAllFlag;
666 final bool analyzeOnly;
667
668 /// If true, disable tree-shaking for the main script.
669 final bool analyzeMain;
670
671 /**
672 * If true, skip analysis of method bodies and field initializers. Implies
673 * [analyzeOnly].
674 */
675 final bool analyzeSignaturesOnly;
676 final bool enableNativeLiveTypeAnalysis;
677
678 /**
679 * If true, stop compilation after type inference is complete. Used for
680 * debugging and testing purposes only.
681 */
682 bool stopAfterTypeInference = false;
683
684 /**
685 * If [:true:], comment tokens are collected in [commentMap] during scanning.
686 */
687 final bool preserveComments;
688
689 /**
690 * Is the compiler in verbose mode.
691 */
692 final bool verbose;
693
694 /**
695 * URI of the main source map if the compiler is generating source
696 * maps.
697 */
698 final Uri sourceMapUri;
699
700 /**
701 * URI of the main output if the compiler is generating source maps.
702 */
703 final Uri outputUri;
704
705 /// Emit terse diagnostics without howToFix.
706 final bool terseDiagnostics;
707
708 /// If `true`, warnings and hints not from user code are reported.
709 final bool showPackageWarnings;
710
711 /// `true` if the last diagnostic was filtered, in which case the
712 /// accompanying info message should be filtered as well.
713 bool lastDiagnosticWasFiltered = false;
714
715 /// Map containing information about the warnings and hints that have been
716 /// suppressed for each library.
717 Map<Uri, SuppressionInfo> suppressedWarnings = <Uri, SuppressionInfo>{};
718
719 final bool suppressWarnings;
720
721 /// If `true`, some values are cached for reuse in incremental compilation.
722 /// Incremental compilation is basically calling [run] more than once.
723 final bool hasIncrementalSupport;
724
725 api.CompilerOutputProvider outputProvider;
726
727 bool disableInlining = false;
728
729 /// True if compilation was aborted with a [CompilerCancelledException]. Only
730 /// set after Future retuned by [run] has completed.
731 bool compilerWasCancelled = false;
732
733 List<Uri> librariesToAnalyzeWhenRun;
734
735 Tracer tracer;
736
737 CompilerTask measuredTask;
738 Element _currentElement;
739 LibraryElement coreLibrary;
740
741 LibraryElement mainApp;
742 FunctionElement mainFunction;
743
744 /// Initialized when dart:mirrors is loaded.
745 LibraryElement mirrorsLibrary;
746
747 /// Initialized when dart:typed_data is loaded.
748 LibraryElement typedDataLibrary;
749
750 ClassElement objectClass;
751 ClassElement boolClass;
752 ClassElement numClass;
753 ClassElement intClass;
754 ClassElement doubleClass;
755 ClassElement stringClass;
756 ClassElement functionClass;
757 ClassElement nullClass;
758 ClassElement listClass;
759 ClassElement typeClass;
760 ClassElement mapClass;
761 ClassElement symbolClass;
762 ClassElement stackTraceClass;
763 ClassElement typedDataClass;
764
765 /// The constant for the [proxy] variable defined in dart:core.
766 ConstantValue proxyConstant;
767
768 // TODO(johnniwinther): Move this to the JavaScriptBackend.
769 /// The constant for the [patch] variable defined in dart:_js_helper.
770 ConstantValue patchConstant;
771
772 // TODO(johnniwinther): Move this to the JavaScriptBackend.
773 ClassElement nativeAnnotationClass;
774
775 // Initialized after symbolClass has been resolved.
776 FunctionElement symbolConstructor;
777
778 // Initialized when dart:mirrors is loaded.
779 ClassElement mirrorSystemClass;
780
781 // Initialized when dart:mirrors is loaded.
782 ClassElement mirrorsUsedClass;
783
784 // Initialized after mirrorSystemClass has been resolved.
785 FunctionElement mirrorSystemGetNameFunction;
786
787 // Initialized when dart:_internal is loaded.
788 ClassElement symbolImplementationClass;
789
790 // Initialized when symbolImplementationClass has been resolved.
791 FunctionElement symbolValidatedConstructor;
792
793 // Initialized when mirrorsUsedClass has been resolved.
794 FunctionElement mirrorsUsedConstructor;
795
796 // Initialized when dart:mirrors is loaded.
797 ClassElement deferredLibraryClass;
798
799 /// Document class from dart:mirrors.
800 ClassElement documentClass;
801 Element identicalFunction;
802 Element loadLibraryFunction;
803 Element functionApplyMethod;
804 Element intEnvironment;
805 Element boolEnvironment;
806 Element stringEnvironment;
807
808 fromEnvironment(String name) => null;
809
810 Element get currentElement => _currentElement;
811
812 String tryToString(object) {
813 try {
814 return object.toString();
815 } catch (_) {
816 return '<exception in toString()>';
817 }
818 }
819
820 /**
821 * Perform an operation, [f], returning the return value from [f]. If an
822 * error occurs then report it as having occurred during compilation of
823 * [element]. Can be nested.
824 */
825 withCurrentElement(Element element, f()) {
826 Element old = currentElement;
827 _currentElement = element;
828 try {
829 return f();
830 } on SpannableAssertionFailure catch (ex) {
831 if (!hasCrashed) {
832 reportAssertionFailure(ex);
833 pleaseReportCrash();
834 }
835 hasCrashed = true;
836 rethrow;
837 } on CompilerCancelledException catch (ex) {
838 rethrow;
839 } on StackOverflowError catch (ex) {
840 // We cannot report anything useful in this case, because we
841 // do not have enough stack space.
842 rethrow;
843 } catch (ex) {
844 if (hasCrashed) rethrow;
845 try {
846 unhandledExceptionOnElement(element);
847 } catch (doubleFault) {
848 // Ignoring exceptions in exception handling.
849 }
850 rethrow;
851 } finally {
852 _currentElement = old;
853 }
854 }
855
856 List<CompilerTask> tasks;
857 ScannerTask scanner;
858 DietParserTask dietParser;
859 ParserTask parser;
860 PatchParserTask patchParser;
861 LibraryLoaderTask libraryLoader;
862 ResolverTask resolver;
863 closureMapping.ClosureTask closureToClassMapper;
864 TypeCheckerTask checker;
865 IrBuilderTask irBuilder;
866 ti.TypesTask typesTask;
867 Backend backend;
868
869 GenericTask reuseLibraryTask;
870
871 /// The constant environment for the frontend interpretation of compile-time
872 /// constants.
873 ConstantEnvironment constants;
874
875 EnqueueTask enqueuer;
876 DeferredLoadTask deferredLoadTask;
877 MirrorUsageAnalyzerTask mirrorUsageAnalyzerTask;
878 DumpInfoTask dumpInfoTask;
879 String buildId;
880
881 /// A customizable filter that is applied to enqueued work items.
882 QueueFilter enqueuerFilter = new QueueFilter();
883
884 static const String MAIN = 'main';
885 static const String CALL_OPERATOR_NAME = 'call';
886 static const String NO_SUCH_METHOD = 'noSuchMethod';
887 static const int NO_SUCH_METHOD_ARG_COUNT = 1;
888 static const String CREATE_INVOCATION_MIRROR =
889 'createInvocationMirror';
890
891 static const String RUNTIME_TYPE = 'runtimeType';
892
893 static const String UNDETERMINED_BUILD_ID =
894 "build number could not be determined";
895
896 final Selector iteratorSelector =
897 new Selector.getter('iterator', null);
898 final Selector currentSelector =
899 new Selector.getter('current', null);
900 final Selector moveNextSelector =
901 new Selector.call('moveNext', null, 0);
902 final Selector noSuchMethodSelector = new Selector.call(
903 Compiler.NO_SUCH_METHOD, null, Compiler.NO_SUCH_METHOD_ARG_COUNT);
904 final Selector symbolValidatedConstructorSelector = new Selector.call(
905 'validated', null, 1);
906 final Selector fromEnvironmentSelector = new Selector.callConstructor(
907 'fromEnvironment', null, 2);
908
909 bool enabledNoSuchMethod = false;
910 bool enabledRuntimeType = false;
911 bool enabledFunctionApply = false;
912 bool enabledInvokeOn = false;
913 bool hasIsolateSupport = false;
914
915 Stopwatch progress;
916
917 bool get shouldPrintProgress {
918 return verbose && progress.elapsedMilliseconds > 500;
919 }
920
921 static const int PHASE_SCANNING = 0;
922 static const int PHASE_RESOLVING = 1;
923 static const int PHASE_DONE_RESOLVING = 2;
924 static const int PHASE_COMPILING = 3;
925 int phase;
926
927 bool compilationFailed = false;
928
929 bool hasCrashed = false;
930
931 /// Set by the backend if real reflection is detected in use of dart:mirrors.
932 bool disableTypeInferenceForMirrors = false;
933
934 Compiler({this.enableTypeAssertions: false,
935 this.enableUserAssertions: false,
936 this.trustTypeAnnotations: false,
937 this.enableConcreteTypeInference: false,
938 bool disableTypeInferenceFlag: false,
939 this.maxConcreteTypeSize: 5,
940 this.enableMinification: false,
941 this.preserveUris: false,
942 this.enableNativeLiveTypeAnalysis: false,
943 bool emitJavaScript: true,
944 bool dart2dartMultiFile: false,
945 bool generateSourceMap: true,
946 bool analyzeAllFlag: false,
947 bool analyzeOnly: false,
948 this.analyzeMain: false,
949 bool analyzeSignaturesOnly: false,
950 this.preserveComments: false,
951 this.verbose: false,
952 this.sourceMapUri: null,
953 this.outputUri: null,
954 this.buildId: UNDETERMINED_BUILD_ID,
955 this.terseDiagnostics: false,
956 this.dumpInfo: false,
957 this.showPackageWarnings: false,
958 this.useContentSecurityPolicy: false,
959 this.suppressWarnings: false,
960 bool hasIncrementalSupport: false,
961 api.CompilerOutputProvider outputProvider,
962 List<String> strips: const []})
963 : this.disableTypeInferenceFlag =
964 disableTypeInferenceFlag || !emitJavaScript,
965 this.analyzeOnly =
966 analyzeOnly || analyzeSignaturesOnly || analyzeAllFlag,
967 this.analyzeSignaturesOnly = analyzeSignaturesOnly,
968 this.analyzeAllFlag = analyzeAllFlag,
969 this.hasIncrementalSupport = hasIncrementalSupport,
970 cacheStrategy = new CacheStrategy(hasIncrementalSupport),
971 this.outputProvider = (outputProvider == null)
972 ? NullSink.outputProvider
973 : outputProvider {
974 if (hasIncrementalSupport) {
975 // TODO(ahe): This is too much. Any method from platform and package
976 // libraries can be inlined.
977 disableInlining = true;
978 }
979 world = new World(this);
980 types = new Types(this);
981 tracer = new Tracer(this, this.outputProvider);
982
983 if (verbose) {
984 progress = new Stopwatch()..start();
985 }
986
987 // TODO(johnniwinther): Separate the dependency tracking from the enqueueing
988 // for global dependencies.
989 globalDependencies =
990 new CodegenRegistry(this, new TreeElementMapping(null));
991
992 closureMapping.ClosureNamer closureNamer;
993 if (emitJavaScript) {
994 js_backend.JavaScriptBackend jsBackend =
995 new js_backend.JavaScriptBackend(this, generateSourceMap);
996 closureNamer = jsBackend.namer;
997 backend = jsBackend;
998 } else {
999 closureNamer = new closureMapping.ClosureNamer();
1000 backend = new dart_backend.DartBackend(this, strips,
1001 multiFile: dart2dartMultiFile);
1002 }
1003
1004 tasks = [
1005 libraryLoader = new LibraryLoaderTask(this),
1006 scanner = new ScannerTask(this),
1007 dietParser = new DietParserTask(this),
1008 parser = new ParserTask(this),
1009 patchParser = new PatchParserTask(this),
1010 resolver = new ResolverTask(this, backend.constantCompilerTask),
1011 closureToClassMapper = new closureMapping.ClosureTask(this, closureNamer),
1012 checker = new TypeCheckerTask(this),
1013 irBuilder = new IrBuilderTask(this),
1014 typesTask = new ti.TypesTask(this),
1015 constants = backend.constantCompilerTask,
1016 deferredLoadTask = new DeferredLoadTask(this),
1017 mirrorUsageAnalyzerTask = new MirrorUsageAnalyzerTask(this),
1018 enqueuer = new EnqueueTask(this),
1019 dumpInfoTask = new DumpInfoTask(this),
1020 reuseLibraryTask = new GenericTask('Reuse library', this),
1021 ];
1022
1023 tasks.addAll(backend.tasks);
1024 }
1025
1026 Universe get resolverWorld => enqueuer.resolution.universe;
1027 Universe get codegenWorld => enqueuer.codegen.universe;
1028
1029 bool get hasBuildId => buildId != UNDETERMINED_BUILD_ID;
1030
1031 bool get analyzeAll => analyzeAllFlag || compileAll;
1032
1033 bool get compileAll => false;
1034
1035 bool get disableTypeInference => disableTypeInferenceFlag;
1036
1037 int getNextFreeClassId() => nextFreeClassId++;
1038
1039 void unimplemented(Spannable spannable, String methodName) {
1040 internalError(spannable, "$methodName not implemented.");
1041 }
1042
1043 void internalError(Spannable node, reason) {
1044 assembledCode = null; // Compilation failed. Make sure that we
1045 // don't return a bogus result.
1046 String message = tryToString(reason);
1047 reportDiagnosticInternal(
1048 node, MessageKind.GENERIC, {'text': message}, api.Diagnostic.CRASH);
1049 throw 'Internal Error: $message';
1050 }
1051
1052 void unhandledExceptionOnElement(Element element) {
1053 if (hasCrashed) return;
1054 hasCrashed = true;
1055 reportDiagnostic(element,
1056 MessageKind.COMPILER_CRASHED.message(),
1057 api.Diagnostic.CRASH);
1058 pleaseReportCrash();
1059 }
1060
1061 void pleaseReportCrash() {
1062 print(MessageKind.PLEASE_REPORT_THE_CRASH.message({'buildId': buildId}));
1063 }
1064
1065 SourceSpan spanFromSpannable(Spannable node) {
1066 // TODO(johnniwinther): Disallow `node == null` ?
1067 if (node == null) return null;
1068 if (node == CURRENT_ELEMENT_SPANNABLE) {
1069 node = currentElement;
1070 } else if (node == NO_LOCATION_SPANNABLE) {
1071 if (currentElement == null) return null;
1072 node = currentElement;
1073 }
1074 if (node is SourceSpan) {
1075 return node;
1076 } else if (node is Node) {
1077 return spanFromNode(node);
1078 } else if (node is Token) {
1079 return spanFromTokens(node, node);
1080 } else if (node is HInstruction) {
1081 return spanFromHInstruction(node);
1082 } else if (node is Element) {
1083 return spanFromElement(node);
1084 } else if (node is MetadataAnnotation) {
1085 Uri uri = node.annotatedElement.compilationUnit.script.readableUri;
1086 return spanFromTokens(node.beginToken, node.endToken, uri);
1087 } else if (node is Local) {
1088 Local local = node;
1089 return spanFromElement(local.executableContext);
1090 } else {
1091 throw 'No error location.';
1092 }
1093 }
1094
1095 Element _elementFromHInstruction(HInstruction instruction) {
1096 return instruction.sourceElement is Element
1097 ? instruction.sourceElement : null;
1098 }
1099
1100 /// Finds the approximate [Element] for [node]. [currentElement] is used as
1101 /// the default value.
1102 Element elementFromSpannable(Spannable node) {
1103 Element element;
1104 if (node is Element) {
1105 element = node;
1106 } else if (node is HInstruction) {
1107 element = _elementFromHInstruction(node);
1108 } else if (node is MetadataAnnotation) {
1109 element = node.annotatedElement;
1110 }
1111 return element != null ? element : currentElement;
1112 }
1113
1114 void log(message) {
1115 reportDiagnostic(null,
1116 MessageKind.GENERIC.message({'text': '$message'}),
1117 api.Diagnostic.VERBOSE_INFO);
1118 }
1119
1120 Future<bool> run(Uri uri) {
1121 totalCompileTime.start();
1122
1123 return new Future.sync(() => runCompiler(uri)).catchError((error) {
1124 if (error is CompilerCancelledException) {
1125 compilerWasCancelled = true;
1126 log('Error: $error');
1127 return false;
1128 }
1129
1130 try {
1131 if (!hasCrashed) {
1132 hasCrashed = true;
1133 if (error is SpannableAssertionFailure) {
1134 reportAssertionFailure(error);
1135 } else {
1136 reportDiagnostic(new SourceSpan(uri, 0, 0),
1137 MessageKind.COMPILER_CRASHED.message(),
1138 api.Diagnostic.CRASH);
1139 }
1140 pleaseReportCrash();
1141 }
1142 } catch (doubleFault) {
1143 // Ignoring exceptions in exception handling.
1144 }
1145 throw error;
1146 }).whenComplete(() {
1147 tracer.close();
1148 totalCompileTime.stop();
1149 }).then((_) {
1150 return !compilationFailed;
1151 });
1152 }
1153
1154 /// This method is called immediately after the [LibraryElement] [library] has
1155 /// been created.
1156 ///
1157 /// Use this callback method to store references to specific libraries.
1158 /// Note that [library] has not been scanned yet, nor has its imports/exports
1159 /// been resolved.
1160 void onLibraryCreated(LibraryElement library) {
1161 Uri uri = library.canonicalUri;
1162 if (uri == DART_CORE) {
1163 coreLibrary = library;
1164 } else if (uri == DART_NATIVE_TYPED_DATA) {
1165 typedDataLibrary = library;
1166 } else if (uri == DART_MIRRORS) {
1167 mirrorsLibrary = library;
1168 }
1169 backend.onLibraryCreated(library);
1170 }
1171
1172 /// This method is called immediately after the [library] and its parts have
1173 /// been scanned.
1174 ///
1175 /// Use this callback method to store references to specific member declared
1176 /// in certain libraries. Note that [library] has not been patched yet, nor
1177 /// has its imports/exports been resolved.
1178 ///
1179 /// Use [loader] to register the creation and scanning of a patch library
1180 /// for [library].
1181 Future onLibraryScanned(LibraryElement library, LibraryLoader loader) {
1182 Uri uri = library.canonicalUri;
1183 if (uri == DART_CORE) {
1184 initializeCoreClasses();
1185 identicalFunction = coreLibrary.find('identical');
1186 } else if (uri == DART_INTERNAL) {
1187 symbolImplementationClass = findRequiredElement(library, 'Symbol');
1188 } else if (uri == DART_MIRRORS) {
1189 mirrorSystemClass = findRequiredElement(library, 'MirrorSystem');
1190 mirrorsUsedClass = findRequiredElement(library, 'MirrorsUsed');
1191 } else if (uri == DART_ASYNC) {
1192 deferredLibraryClass = findRequiredElement(library, 'DeferredLibrary');
1193 } else if (uri == DART_NATIVE_TYPED_DATA) {
1194 typedDataClass = findRequiredElement(library, 'NativeTypedData');
1195 } else if (uri == js_backend.JavaScriptBackend.DART_JS_HELPER) {
1196 nativeAnnotationClass = findRequiredElement(library, 'Native');
1197 }
1198 return backend.onLibraryScanned(library, loader);
1199 }
1200
1201 /// This method is called when all new libraries loaded through
1202 /// [LibraryLoader.loadLibrary] has been loaded and their imports/exports
1203 /// have been computed.
1204 ///
1205 /// [loadedLibraries] contains the newly loaded libraries.
1206 ///
1207 /// The method returns a [Future] allowing for the loading of additional
1208 /// libraries.
1209 Future onLibrariesLoaded(Map<Uri, LibraryElement> loadedLibraries) {
1210 return new Future.sync(() {
1211 if (!loadedLibraries.containsKey(DART_CORE)) return new Future.value();
1212
1213 functionClass.ensureResolved(this);
1214 functionApplyMethod = functionClass.lookupLocalMember('apply');
1215
1216 proxyConstant =
1217 resolver.constantCompiler.compileConstant(
1218 coreLibrary.find('proxy')).value;
1219
1220 // TODO(johnniwinther): Move this to the JavaScript backend.
1221 LibraryElement jsHelperLibrary =
1222 loadedLibraries[js_backend.JavaScriptBackend.DART_JS_HELPER];
1223 if (jsHelperLibrary != null) {
1224 patchConstant = resolver.constantCompiler.compileConstant(
1225 jsHelperLibrary.find('patch')).value;
1226 }
1227
1228 if (preserveComments) {
1229 return libraryLoader.loadLibrary(DART_MIRRORS)
1230 .then((LibraryElement libraryElement) {
1231 documentClass = libraryElement.find('Comment');
1232 });
1233 }
1234 }).then((_) => backend.onLibrariesLoaded(loadedLibraries));
1235 }
1236
1237 Element findRequiredElement(LibraryElement library, String name) {
1238 var element = library.find(name);
1239 if (element == null) {
1240 internalError(library,
1241 "The library '${library.canonicalUri}' does not contain required "
1242 "element: '$name'.");
1243 }
1244 return element;
1245 }
1246
1247 void onClassResolved(ClassElement cls) {
1248 if (mirrorSystemClass == cls) {
1249 mirrorSystemGetNameFunction =
1250 cls.lookupLocalMember('getName');
1251 } else if (symbolClass == cls) {
1252 symbolConstructor = cls.constructors.head;
1253 } else if (symbolImplementationClass == cls) {
1254 symbolValidatedConstructor = symbolImplementationClass.lookupConstructor(
1255 symbolValidatedConstructorSelector);
1256 } else if (mirrorsUsedClass == cls) {
1257 mirrorsUsedConstructor = cls.constructors.head;
1258 } else if (intClass == cls) {
1259 intEnvironment = intClass.lookupConstructor(fromEnvironmentSelector);
1260 } else if (stringClass == cls) {
1261 stringEnvironment =
1262 stringClass.lookupConstructor(fromEnvironmentSelector);
1263 } else if (boolClass == cls) {
1264 boolEnvironment = boolClass.lookupConstructor(fromEnvironmentSelector);
1265 }
1266 }
1267
1268 void initializeCoreClasses() {
1269 final List missingCoreClasses = [];
1270 ClassElement lookupCoreClass(String name) {
1271 ClassElement result = coreLibrary.find(name);
1272 if (result == null) {
1273 missingCoreClasses.add(name);
1274 }
1275 return result;
1276 }
1277 objectClass = lookupCoreClass('Object');
1278 boolClass = lookupCoreClass('bool');
1279 numClass = lookupCoreClass('num');
1280 intClass = lookupCoreClass('int');
1281 doubleClass = lookupCoreClass('double');
1282 stringClass = lookupCoreClass('String');
1283 functionClass = lookupCoreClass('Function');
1284 listClass = lookupCoreClass('List');
1285 typeClass = lookupCoreClass('Type');
1286 mapClass = lookupCoreClass('Map');
1287 nullClass = lookupCoreClass('Null');
1288 stackTraceClass = lookupCoreClass('StackTrace');
1289 symbolClass = lookupCoreClass('Symbol');
1290 if (!missingCoreClasses.isEmpty) {
1291 internalError(coreLibrary,
1292 'dart:core library does not contain required classes: '
1293 '$missingCoreClasses');
1294 }
1295 }
1296
1297 Element _unnamedListConstructor;
1298 Element get unnamedListConstructor {
1299 if (_unnamedListConstructor != null) return _unnamedListConstructor;
1300 Selector callConstructor = new Selector.callConstructor(
1301 "", listClass.library);
1302 return _unnamedListConstructor =
1303 listClass.lookupConstructor(callConstructor);
1304 }
1305
1306 Element _filledListConstructor;
1307 Element get filledListConstructor {
1308 if (_filledListConstructor != null) return _filledListConstructor;
1309 Selector callConstructor = new Selector.callConstructor(
1310 "filled", listClass.library);
1311 return _filledListConstructor =
1312 listClass.lookupConstructor(callConstructor);
1313 }
1314
1315 /**
1316 * Get an [Uri] pointing to a patch for the dart: library with
1317 * the given path. Returns null if there is no patch.
1318 */
1319 Uri resolvePatchUri(String dartLibraryPath);
1320
1321 Future runCompiler(Uri uri) {
1322 // TODO(ahe): This prevents memory leaks when invoking the compiler
1323 // multiple times. Implement a better mechanism where we can store
1324 // such caches in the compiler and get access to them through a
1325 // suitably maintained static reference to the current compiler.
1326 StringToken.canonicalizedSubstrings.clear();
1327 Selector.canonicalizedValues.clear();
1328 TypedSelector.canonicalizedValues.clear();
1329
1330 assert(uri != null || analyzeOnly || hasIncrementalSupport);
1331 return new Future.sync(() {
1332 if (librariesToAnalyzeWhenRun != null) {
1333 return Future.forEach(librariesToAnalyzeWhenRun, (libraryUri) {
1334 log('Analyzing $libraryUri ($buildId)');
1335 return libraryLoader.loadLibrary(libraryUri);
1336 });
1337 }
1338 }).then((_) {
1339 if (uri != null) {
1340 if (analyzeOnly) {
1341 log('Analyzing $uri ($buildId)');
1342 } else {
1343 log('Compiling $uri ($buildId)');
1344 }
1345 return libraryLoader.loadLibrary(uri).then((LibraryElement library) {
1346 mainApp = library;
1347 });
1348 }
1349 }).then((_) {
1350 if (!compilationFailed) {
1351 // TODO(johnniwinther): Reenable analysis of programs with load failures
1352 // when these are handled as erroneous libraries/compilation units.
1353 compileLoadedLibraries();
1354 }
1355 });
1356 }
1357
1358 void computeMain() {
1359 if (mainApp == null) return;
1360
1361 Element main = mainApp.findExported(MAIN);
1362 ErroneousElement errorElement = null;
1363 if (main == null) {
1364 if (analyzeOnly) {
1365 if (!analyzeAll) {
1366 errorElement = new ErroneousElementX(
1367 MessageKind.CONSIDER_ANALYZE_ALL, {'main': MAIN}, MAIN, mainApp);
1368 }
1369 } else {
1370 // Compilation requires a main method.
1371 errorElement = new ErroneousElementX(
1372 MessageKind.MISSING_MAIN, {'main': MAIN}, MAIN, mainApp);
1373 }
1374 mainFunction = backend.helperForMissingMain();
1375 } else if (main.isErroneous && main.isSynthesized) {
1376 if (main is ErroneousElement) {
1377 errorElement = main;
1378 } else {
1379 internalError(main, 'Problem with $MAIN.');
1380 }
1381 mainFunction = backend.helperForBadMain();
1382 } else if (!main.isFunction) {
1383 errorElement = new ErroneousElementX(
1384 MessageKind.MAIN_NOT_A_FUNCTION, {'main': MAIN}, MAIN, main);
1385 mainFunction = backend.helperForBadMain();
1386 } else {
1387 mainFunction = main;
1388 FunctionSignature parameters = mainFunction.computeSignature(this);
1389 if (parameters.requiredParameterCount > 2) {
1390 int index = 0;
1391 parameters.orderedForEachParameter((Element parameter) {
1392 if (index++ < 2) return;
1393 errorElement = new ErroneousElementX(
1394 MessageKind.MAIN_WITH_EXTRA_PARAMETER, {'main': MAIN}, MAIN,
1395 parameter);
1396 mainFunction = backend.helperForMainArity();
1397 // Don't warn about main not being used:
1398 enqueuer.resolution.registerStaticUse(main);
1399 });
1400 }
1401 }
1402 if (mainFunction == null) {
1403 if (errorElement == null && !analyzeOnly && !analyzeAll) {
1404 internalError(mainApp, "Problem with '$MAIN'.");
1405 } else {
1406 mainFunction = errorElement;
1407 }
1408 }
1409 if (errorElement != null && errorElement.isSynthesized) {
1410 reportWarning(
1411 errorElement, errorElement.messageKind,
1412 errorElement.messageArguments);
1413 }
1414 }
1415
1416 /// Performs the compilation when all libraries have been loaded.
1417 void compileLoadedLibraries() {
1418 computeMain();
1419
1420 mirrorUsageAnalyzerTask.analyzeUsage(mainApp);
1421
1422 // In order to see if a library is deferred, we must compute the
1423 // compile-time constants that are metadata. This means adding
1424 // something to the resolution queue. So we cannot wait with
1425 // this until after the resolution queue is processed.
1426 deferredLoadTask.ensureMetadataResolved(this);
1427
1428 phase = PHASE_RESOLVING;
1429 if (analyzeAll) {
1430 libraryLoader.libraries.forEach((LibraryElement library) {
1431 log('Enqueuing ${library.canonicalUri}');
1432 fullyEnqueueLibrary(library, enqueuer.resolution);
1433 });
1434 } else if (analyzeMain && mainApp != null) {
1435 fullyEnqueueLibrary(mainApp, enqueuer.resolution);
1436 }
1437 // Elements required by enqueueHelpers are global dependencies
1438 // that are not pulled in by a particular element.
1439 backend.enqueueHelpers(enqueuer.resolution, globalDependencies);
1440 resolveLibraryMetadata();
1441 log('Resolving...');
1442 processQueue(enqueuer.resolution, mainFunction);
1443 enqueuer.resolution.logSummary(log);
1444
1445 if (compilationFailed) return;
1446 if (!showPackageWarnings && !suppressWarnings) {
1447 suppressedWarnings.forEach((Uri uri, SuppressionInfo info) {
1448 MessageKind kind = MessageKind.HIDDEN_WARNINGS_HINTS;
1449 if (info.warnings == 0) {
1450 kind = MessageKind.HIDDEN_HINTS;
1451 } else if (info.hints == 0) {
1452 kind = MessageKind.HIDDEN_WARNINGS;
1453 }
1454 reportDiagnostic(null,
1455 kind.message({'warnings': info.warnings,
1456 'hints': info.hints,
1457 'uri': uri},
1458 terseDiagnostics),
1459 api.Diagnostic.HINT);
1460 });
1461 }
1462 if (analyzeOnly) {
1463 if (!analyzeAll) {
1464 // No point in reporting unused code when [analyzeAll] is true: all
1465 // code is artificially used.
1466 reportUnusedCode();
1467 }
1468 return;
1469 }
1470 assert(mainFunction != null);
1471 phase = PHASE_DONE_RESOLVING;
1472
1473 world.populate();
1474 // Compute whole-program-knowledge that the backend needs. (This might
1475 // require the information computed in [world.populate].)
1476 backend.onResolutionComplete();
1477
1478 deferredLoadTask.onResolutionComplete(mainFunction);
1479
1480 log('Building IR...');
1481 irBuilder.buildNodes();
1482
1483 log('Inferring types...');
1484 typesTask.onResolutionComplete(mainFunction);
1485
1486 if (stopAfterTypeInference) return;
1487
1488 log('Compiling...');
1489 phase = PHASE_COMPILING;
1490 // TODO(johnniwinther): Move these to [CodegenEnqueuer].
1491 if (hasIsolateSupport) {
1492 backend.enableIsolateSupport(enqueuer.codegen);
1493 }
1494 if (enabledNoSuchMethod) {
1495 backend.enableNoSuchMethod(null, enqueuer.codegen);
1496 }
1497 if (compileAll) {
1498 libraryLoader.libraries.forEach((LibraryElement library) {
1499 fullyEnqueueLibrary(library, enqueuer.codegen);
1500 });
1501 }
1502 processQueue(enqueuer.codegen, mainFunction);
1503 enqueuer.codegen.logSummary(log);
1504
1505 if (compilationFailed) return;
1506
1507 backend.assembleProgram();
1508
1509 if (dumpInfo) {
1510 dumpInfoTask.dumpInfo();
1511 }
1512
1513 checkQueues();
1514
1515 if (compilationFailed) {
1516 assembledCode = null; // Signals failure.
1517 }
1518 }
1519
1520 void fullyEnqueueLibrary(LibraryElement library, Enqueuer world) {
1521 void enqueueAll(Element element) {
1522 fullyEnqueueTopLevelElement(element, world);
1523 }
1524 library.implementation.forEachLocalMember(enqueueAll);
1525 }
1526
1527 void fullyEnqueueTopLevelElement(Element element, Enqueuer world) {
1528 if (element.isClass) {
1529 ClassElement cls = element;
1530 cls.ensureResolved(this);
1531 cls.forEachLocalMember(enqueuer.resolution.addToWorkList);
1532 world.registerInstantiatedClass(element, globalDependencies);
1533 } else {
1534 world.addToWorkList(element);
1535 }
1536 }
1537
1538 // Resolves metadata on library elements. This is necessary in order to
1539 // resolve metadata classes referenced only from metadata on library tags.
1540 // TODO(ahe): Figure out how to do this lazily.
1541 void resolveLibraryMetadata() {
1542 for (LibraryElement library in libraryLoader.libraries) {
1543 if (library.metadata != null) {
1544 for (MetadataAnnotation metadata in library.metadata) {
1545 metadata.ensureResolved(this);
1546 }
1547 }
1548 }
1549 }
1550
1551 void processQueue(Enqueuer world, Element main) {
1552 world.nativeEnqueuer.processNativeClasses(libraryLoader.libraries);
1553 if (main != null && !main.isErroneous) {
1554 FunctionElement mainMethod = main;
1555 if (mainMethod.computeSignature(this).parameterCount != 0) {
1556 // The first argument could be a list of strings.
1557 world.registerInstantiatedClass(
1558 backend.listImplementation, globalDependencies);
1559 world.registerInstantiatedClass(
1560 backend.stringImplementation, globalDependencies);
1561
1562 backend.registerMainHasArguments(world);
1563 }
1564 world.addToWorkList(main);
1565 }
1566 if (verbose) {
1567 progress.reset();
1568 }
1569 world.forEach((WorkItem work) {
1570 withCurrentElement(work.element, () => work.run(this, world));
1571 });
1572 world.queueIsClosed = true;
1573 if (compilationFailed) return;
1574 assert(world.checkNoEnqueuedInvokedInstanceMethods());
1575 }
1576
1577 /**
1578 * Perform various checks of the queues. This includes checking that
1579 * the queues are empty (nothing was added after we stopped
1580 * processing the queues). Also compute the number of methods that
1581 * were resolved, but not compiled (aka excess resolution).
1582 */
1583 checkQueues() {
1584 for (Enqueuer world in [enqueuer.resolution, enqueuer.codegen]) {
1585 world.forEach((WorkItem work) {
1586 internalError(work.element, "Work list is not empty.");
1587 });
1588 }
1589 if (!REPORT_EXCESS_RESOLUTION) return;
1590 var resolved = new Set.from(enqueuer.resolution.resolvedElements);
1591 for (Element e in enqueuer.codegen.generatedCode.keys) {
1592 resolved.remove(e);
1593 }
1594 for (Element e in new Set.from(resolved)) {
1595 if (e.isClass ||
1596 e.isField ||
1597 e.isTypeVariable ||
1598 e.isTypedef ||
1599 identical(e.kind, ElementKind.ABSTRACT_FIELD)) {
1600 resolved.remove(e);
1601 }
1602 if (identical(e.kind, ElementKind.GENERATIVE_CONSTRUCTOR)) {
1603 ClassElement enclosingClass = e.enclosingClass;
1604 resolved.remove(e);
1605
1606 }
1607 if (backend.isBackendLibrary(e.library)) {
1608 resolved.remove(e);
1609 }
1610 }
1611 log('Excess resolution work: ${resolved.length}.');
1612 for (Element e in resolved) {
1613 reportWarning(e,
1614 MessageKind.GENERIC,
1615 {'text': 'Warning: $e resolved but not compiled.'});
1616 }
1617 }
1618
1619 void analyzeElement(Element element) {
1620 assert(invariant(element,
1621 element.impliesType ||
1622 element.isField ||
1623 element.isFunction ||
1624 element.isGenerativeConstructor ||
1625 element.isGetter ||
1626 element.isSetter,
1627 message: 'Unexpected element kind: ${element.kind}'));
1628 assert(invariant(element, element is AnalyzableElement,
1629 message: 'Element $element is not analyzable.'));
1630 assert(invariant(element, element.isDeclaration));
1631 ResolutionEnqueuer world = enqueuer.resolution;
1632 if (world.hasBeenResolved(element)) return;
1633 assert(parser != null);
1634 Node tree = parser.parse(element);
1635 assert(invariant(element, !element.isSynthesized || tree == null));
1636 TreeElements elements = resolver.resolve(element);
1637 if (elements != null) {
1638 if (tree != null && !analyzeSignaturesOnly &&
1639 !suppressWarnings) {
1640 // Only analyze nodes with a corresponding [TreeElements].
1641 checker.check(elements);
1642 }
1643 world.registerResolvedElement(element);
1644 }
1645 }
1646
1647 void analyze(ResolutionWorkItem work, ResolutionEnqueuer world) {
1648 assert(invariant(work.element, identical(world, enqueuer.resolution)));
1649 assert(invariant(work.element, !work.isAnalyzed(),
1650 message: 'Element ${work.element} has already been analyzed'));
1651 if (shouldPrintProgress) {
1652 // TODO(ahe): Add structured diagnostics to the compiler API and
1653 // use it to separate this from the --verbose option.
1654 if (phase == PHASE_RESOLVING) {
1655 log('Resolved ${enqueuer.resolution.resolvedElements.length} '
1656 'elements.');
1657 progress.reset();
1658 }
1659 }
1660 AstElement element = work.element;
1661 if (world.hasBeenResolved(element)) return;
1662 analyzeElement(element);
1663 backend.onElementResolved(element, element.resolvedAst.elements);
1664 }
1665
1666 void codegen(CodegenWorkItem work, CodegenEnqueuer world) {
1667 assert(invariant(work.element, identical(world, enqueuer.codegen)));
1668 if (shouldPrintProgress) {
1669 // TODO(ahe): Add structured diagnostics to the compiler API and
1670 // use it to separate this from the --verbose option.
1671 log('Compiled ${enqueuer.codegen.generatedCode.length} methods.');
1672 progress.reset();
1673 }
1674 backend.codegen(work);
1675 }
1676
1677 void reportError(Spannable node,
1678 MessageKind messageKind,
1679 [Map arguments = const {}]) {
1680 reportDiagnosticInternal(
1681 node, messageKind, arguments, api.Diagnostic.ERROR);
1682 }
1683
1684 /**
1685 * Reports an error and then aborts the compiler. Avoid using this method.
1686 *
1687 * In order to support incremental compilation, it is preferable to use
1688 * [reportError]. However, care must be taken to leave the compiler in a
1689 * consistent state, for example, by creating synthetic erroneous objects.
1690 *
1691 * If there's absolutely no way to leave the compiler in a consistent state,
1692 * calling this method is preferred as it will set [compilerWasCancelled] to
1693 * true which alerts the incremental compiler to discard all state and start
1694 * a new compiler. Throwing an exception is also better, as this will set
1695 * [hasCrashed] which the incremental compiler also listens too (but don't
1696 * throw exceptions, it creates a really bad user experience).
1697 *
1698 * In any case, calling this method is a last resort, as it essentially
1699 * breaks the user experience of the incremental compiler. The purpose of the
1700 * incremental compiler is to improve developer productivity. Developers
1701 * frequently make mistakes, so syntax errors and spelling errors are
1702 * considered normal to the incremental compiler.
1703 */
1704 void reportFatalError(Spannable node, MessageKind messageKind,
1705 [Map arguments = const {}]) {
1706 reportError(node, messageKind, arguments);
1707 // TODO(ahe): Make this only abort the current method.
1708 throw new CompilerCancelledException(
1709 'Error: Cannot continue due to previous error.');
1710 }
1711
1712 void reportWarning(Spannable node, MessageKind messageKind,
1713 [Map arguments = const {}]) {
1714 reportDiagnosticInternal(
1715 node, messageKind, arguments, api.Diagnostic.WARNING);
1716 }
1717
1718 void reportInfo(Spannable node, MessageKind messageKind,
1719 [Map arguments = const {}]) {
1720 reportDiagnosticInternal(node, messageKind, arguments, api.Diagnostic.INFO);
1721 }
1722
1723 void reportHint(Spannable node, MessageKind messageKind,
1724 [Map arguments = const {}]) {
1725 reportDiagnosticInternal(node, messageKind, arguments, api.Diagnostic.HINT);
1726 }
1727
1728 void reportDiagnosticInternal(Spannable node,
1729 MessageKind messageKind,
1730 Map arguments,
1731 api.Diagnostic kind) {
1732 if (!showPackageWarnings && node != NO_LOCATION_SPANNABLE) {
1733 switch (kind) {
1734 case api.Diagnostic.WARNING:
1735 case api.Diagnostic.HINT:
1736 Element element = elementFromSpannable(node);
1737 if (!inUserCode(element, assumeInUserCode: true)) {
1738 Uri uri = getCanonicalUri(element);
1739 SuppressionInfo info =
1740 suppressedWarnings.putIfAbsent(uri, () => new SuppressionInfo());
1741 if (kind == api.Diagnostic.WARNING) {
1742 info.warnings++;
1743 } else {
1744 info.hints++;
1745 }
1746 lastDiagnosticWasFiltered = true;
1747 return;
1748 }
1749 break;
1750 case api.Diagnostic.INFO:
1751 if (lastDiagnosticWasFiltered) {
1752 return;
1753 }
1754 break;
1755 }
1756 }
1757 lastDiagnosticWasFiltered = false;
1758 reportDiagnostic(
1759 node, messageKind.message(arguments, terseDiagnostics), kind);
1760 }
1761
1762 void reportDiagnostic(Spannable span,
1763 Message message,
1764 api.Diagnostic kind);
1765
1766 void reportAssertionFailure(SpannableAssertionFailure ex) {
1767 String message = (ex.message != null) ? tryToString(ex.message)
1768 : tryToString(ex);
1769 SourceSpan span = spanFromSpannable(ex.node);
1770 reportDiagnosticInternal(
1771 ex.node, MessageKind.GENERIC, {'text': message}, api.Diagnostic.CRASH);
1772 }
1773
1774 SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) {
1775 if (begin == null || end == null) {
1776 // TODO(ahe): We can almost always do better. Often it is only
1777 // end that is null. Otherwise, we probably know the current
1778 // URI.
1779 throw 'Cannot find tokens to produce error message.';
1780 }
1781 if (uri == null && currentElement != null) {
1782 uri = currentElement.compilationUnit.script.readableUri;
1783 }
1784 return SourceSpan.withCharacterOffsets(begin, end,
1785 (beginOffset, endOffset) => new SourceSpan(uri, beginOffset, endOffset));
1786 }
1787
1788 SourceSpan spanFromNode(Node node) {
1789 return spanFromTokens(node.getBeginToken(), node.getEndToken());
1790 }
1791
1792 SourceSpan spanFromElement(Element element) {
1793 while (element != null && element.isSynthesized) {
1794 element = element.enclosingElement;
1795 }
1796 if (element != null &&
1797 element.position == null &&
1798 !element.isLibrary &&
1799 !element.isCompilationUnit) {
1800 // Sometimes, the backend fakes up elements that have no
1801 // position. So we use the enclosing element instead. It is
1802 // not a good error location, but cancel really is "internal
1803 // error" or "not implemented yet", so the vicinity is good
1804 // enough for now.
1805 element = element.enclosingElement;
1806 // TODO(ahe): I plan to overhaul this infrastructure anyways.
1807 }
1808 if (element == null) {
1809 element = currentElement;
1810 }
1811 Token position = element.position;
1812 Uri uri = element.compilationUnit.script.readableUri;
1813 return (position == null)
1814 ? new SourceSpan(uri, 0, 0)
1815 : spanFromTokens(position, position, uri);
1816 }
1817
1818 SourceSpan spanFromHInstruction(HInstruction instruction) {
1819 Element element = _elementFromHInstruction(instruction);
1820 if (element == null) element = currentElement;
1821 var position = instruction.sourcePosition;
1822 if (position == null) return spanFromElement(element);
1823 Token token = position.token;
1824 if (token == null) return spanFromElement(element);
1825 Uri uri = element.compilationUnit.script.readableUri;
1826 return spanFromTokens(token, token, uri);
1827 }
1828
1829 /**
1830 * Translates the [resolvedUri] into a readable URI.
1831 *
1832 * The [importingLibrary] holds the library importing [resolvedUri] or
1833 * [:null:] if [resolvedUri] is loaded as the main library. The
1834 * [importingLibrary] is used to grant access to internal libraries from
1835 * platform libraries and patch libraries.
1836 *
1837 * If the [resolvedUri] is not accessible from [importingLibrary], this method
1838 * is responsible for reporting errors.
1839 *
1840 * See [LibraryLoader] for terminology on URIs.
1841 */
1842 Uri translateResolvedUri(LibraryElement importingLibrary,
1843 Uri resolvedUri, Node node) {
1844 unimplemented(importingLibrary, 'Compiler.translateResolvedUri');
1845 return null;
1846 }
1847
1848 /**
1849 * Reads the script specified by the [readableUri].
1850 *
1851 * See [LibraryLoader] for terminology on URIs.
1852 */
1853 Future<Script> readScript(Spannable node, Uri readableUri) {
1854 unimplemented(node, 'Compiler.readScript');
1855 return null;
1856 }
1857
1858 Element lookupElementIn(ScopeContainerElement container, String name) {
1859 Element element = container.localLookup(name);
1860 if (element == null) {
1861 throw 'Could not find $name in $container';
1862 }
1863 return element;
1864 }
1865
1866 bool get isMockCompilation => false;
1867
1868 Token processAndStripComments(Token currentToken) {
1869 Token firstToken = currentToken;
1870 Token prevToken;
1871 while (currentToken.kind != EOF_TOKEN) {
1872 if (identical(currentToken.kind, COMMENT_TOKEN)) {
1873 Token firstCommentToken = currentToken;
1874 while (identical(currentToken.kind, COMMENT_TOKEN)) {
1875 currentToken = currentToken.next;
1876 }
1877 commentMap[currentToken] = firstCommentToken;
1878 if (prevToken == null) {
1879 firstToken = currentToken;
1880 } else {
1881 prevToken.next = currentToken;
1882 }
1883 }
1884 prevToken = currentToken;
1885 currentToken = currentToken.next;
1886 }
1887 return firstToken;
1888 }
1889
1890 void reportUnusedCode() {
1891 void checkLive(member) {
1892 if (member.isFunction) {
1893 if (!enqueuer.resolution.hasBeenResolved(member)) {
1894 reportHint(member, MessageKind.UNUSED_METHOD,
1895 {'name': member.name});
1896 }
1897 } else if (member.isClass) {
1898 if (!member.isResolved) {
1899 reportHint(member, MessageKind.UNUSED_CLASS,
1900 {'name': member.name});
1901 } else {
1902 member.forEachLocalMember(checkLive);
1903 }
1904 } else if (member.isTypedef) {
1905 if (!member.isResolved) {
1906 reportHint(member, MessageKind.UNUSED_TYPEDEF,
1907 {'name': member.name});
1908 }
1909 }
1910 }
1911 libraryLoader.libraries.forEach((LibraryElement library) {
1912 // TODO(ahe): Implement better heuristics to discover entry points of
1913 // packages and use that to discover unused implementation details in
1914 // packages.
1915 if (library.isPlatformLibrary || library.isPackageLibrary) return;
1916 library.compilationUnits.forEach((unit) {
1917 unit.forEachLocalMember(checkLive);
1918 });
1919 });
1920 }
1921
1922 /// Helper for determining whether the current element is declared within
1923 /// 'user code'.
1924 ///
1925 /// See [inUserCode] for what defines 'user code'.
1926 bool currentlyInUserCode() {
1927 return inUserCode(currentElement);
1928 }
1929
1930 /// Helper for determining whether [element] is declared within 'user code'.
1931 ///
1932 /// What constitutes 'user code' is defined by the URI(s) provided by the
1933 /// entry point(s) of compilation or analysis:
1934 ///
1935 /// If an entrypoint URI uses the 'package' scheme then every library from
1936 /// that same package is considered to be in user code. For instance, if
1937 /// an entry point URI is 'package:foo/bar.dart' then every library whose
1938 /// canonical URI starts with 'package:foo/' is in user code.
1939 ///
1940 /// If an entrypoint URI uses another scheme than 'package' then every library
1941 /// with that scheme is in user code. For instance, an entry point URI is
1942 /// 'file:///foo.dart' then every library whose canonical URI scheme is
1943 /// 'file' is in user code.
1944 ///
1945 /// If [assumeInUserCode] is `true`, [element] is assumed to be in user code
1946 /// if no entrypoints have been set.
1947 bool inUserCode(Element element, {bool assumeInUserCode: false}) {
1948 List<Uri> entrypoints = <Uri>[];
1949 if (mainApp != null) {
1950 entrypoints.add(mainApp.canonicalUri);
1951 }
1952 if (librariesToAnalyzeWhenRun != null) {
1953 entrypoints.addAll(librariesToAnalyzeWhenRun);
1954 }
1955 if (entrypoints.isEmpty && assumeInUserCode) {
1956 // Assume in user code since [mainApp] has not been set yet.
1957 return true;
1958 }
1959 if (element == null) return false;
1960 Uri libraryUri = element.library.canonicalUri;
1961 if (libraryUri.scheme == 'package') {
1962 for (Uri uri in entrypoints) {
1963 if (uri.scheme != 'package') continue;
1964 int slashPos = libraryUri.path.indexOf('/');
1965 if (slashPos != -1) {
1966 String packageName = libraryUri.path.substring(0, slashPos + 1);
1967 if (uri.path.startsWith(packageName)) {
1968 return true;
1969 }
1970 } else {
1971 if (libraryUri.path == uri.path) {
1972 return true;
1973 }
1974 }
1975 }
1976 } else {
1977 for (Uri uri in entrypoints) {
1978 if (libraryUri.scheme == uri.scheme) return true;
1979 }
1980 }
1981 return false;
1982 }
1983
1984 /// Return a canonical URI for the source of [element].
1985 ///
1986 /// For a package library with canonical URI 'package:foo/bar/baz.dart' the
1987 /// return URI is 'package:foo'. For non-package libraries the returned URI is
1988 /// the canonical URI of the library itself.
1989 Uri getCanonicalUri(Element element) {
1990 if (element == null) return null;
1991 Uri libraryUri = element.library.canonicalUri;
1992 if (libraryUri.scheme == 'package') {
1993 int slashPos = libraryUri.path.indexOf('/');
1994 if (slashPos != -1) {
1995 String packageName = libraryUri.path.substring(0, slashPos);
1996 return new Uri(scheme: 'package', path: packageName);
1997 }
1998 }
1999 return libraryUri;
2000 }
2001
2002 void diagnoseCrashInUserCode(String message, exception, stackTrace) {
2003 // Overridden by Compiler in apiimpl.dart.
2004 }
2005
2006 void forgetElement(Element element) {
2007 enqueuer.forgetElement(element);
2008 if (element is MemberElement) {
2009 for (Element closure in element.nestedClosures) {
2010 // TODO(ahe): It would be nice to reuse names of nested closures.
2011 closureToClassMapper.forgetElement(closure);
2012 }
2013 }
2014 backend.forgetElement(element);
2015 }
2016 }
2017
2018 class CompilerTask {
2019 final Compiler compiler;
2020 final Stopwatch watch;
2021 UserTag profilerTag;
2022
2023 CompilerTask(Compiler compiler)
2024 : this.compiler = compiler,
2025 watch = (compiler.verbose) ? new Stopwatch() : null;
2026
2027 String get name => 'Unknown task';
2028 int get timing => (watch != null) ? watch.elapsedMilliseconds : 0;
2029
2030 int get timingMicroseconds => (watch != null) ? watch.elapsedMicroseconds : 0;
2031
2032 UserTag getProfilerTag() {
2033 if (profilerTag == null) profilerTag = new UserTag(name);
2034 return profilerTag;
2035 }
2036
2037 measure(action()) {
2038 // In verbose mode when watch != null.
2039 if (watch == null) return action();
2040 CompilerTask previous = compiler.measuredTask;
2041 if (identical(this, previous)) return action();
2042 compiler.measuredTask = this;
2043 if (previous != null) previous.watch.stop();
2044 watch.start();
2045 UserTag oldTag = getProfilerTag().makeCurrent();
2046 try {
2047 return action();
2048 } finally {
2049 watch.stop();
2050 oldTag.makeCurrent();
2051 if (previous != null) previous.watch.start();
2052 compiler.measuredTask = previous;
2053 }
2054 }
2055
2056 measureElement(Element element, action()) {
2057 compiler.withCurrentElement(element, () => measure(action));
2058 }
2059 }
2060
2061 class CompilerCancelledException implements Exception {
2062 final String reason;
2063 CompilerCancelledException(this.reason);
2064
2065 String toString() {
2066 String banner = 'compiler cancelled';
2067 return (reason != null) ? '$banner: $reason' : '$banner';
2068 }
2069 }
2070
2071 class SourceSpan implements Spannable {
2072 final Uri uri;
2073 final int begin;
2074 final int end;
2075
2076 const SourceSpan(this.uri, this.begin, this.end);
2077
2078 static withCharacterOffsets(Token begin, Token end,
2079 f(int beginOffset, int endOffset)) {
2080 final beginOffset = begin.charOffset;
2081 final endOffset = end.charOffset + end.charCount;
2082
2083 // [begin] and [end] might be the same for the same empty token. This
2084 // happens for instance when scanning '$$'.
2085 assert(endOffset >= beginOffset);
2086 return f(beginOffset, endOffset);
2087 }
2088
2089 String toString() => 'SourceSpan($uri, $begin, $end)';
2090 }
2091
2092 /// Flag that can be used in assertions to assert that a code path is only
2093 /// executed as part of development.
2094 ///
2095 /// This flag is automatically set to true if helper methods like, [debugPrint],
2096 /// [debugWrapPrint], [trace], and [reportHere] are called.
2097 bool DEBUG_MODE = false;
2098
2099 /// Assert that [DEBUG_MODE] is `true` and provide [message] as part of the
2100 /// error message.
2101 assertDebugMode(String message) {
2102 assert(invariant(NO_LOCATION_SPANNABLE, DEBUG_MODE,
2103 message: 'Debug mode is not enabled: $message'));
2104 }
2105
2106 /**
2107 * Throws a [SpannableAssertionFailure] if [condition] is
2108 * [:false:]. [condition] must be either a [:bool:] or a no-arg
2109 * function returning a [:bool:].
2110 *
2111 * Use this method to provide better information for assertion by calling
2112 * [invariant] as the argument to an [:assert:] statement:
2113 *
2114 * assert(invariant(position, isValid));
2115 *
2116 * [spannable] must be non-null and will be used to provide positional
2117 * information in the generated error message.
2118 */
2119 bool invariant(Spannable spannable, var condition, {var message: null}) {
2120 // TODO(johnniwinther): Use [spannable] and [message] to provide better
2121 // information on assertion errors.
2122 if (spannable == null) {
2123 throw new SpannableAssertionFailure(CURRENT_ELEMENT_SPANNABLE,
2124 "Spannable was null for invariant. Use CURRENT_ELEMENT_SPANNABLE.");
2125 }
2126 if (condition is Function){
2127 condition = condition();
2128 }
2129 if (!condition) {
2130 if (message is Function) {
2131 message = message();
2132 }
2133 throw new SpannableAssertionFailure(spannable, message);
2134 }
2135 return true;
2136 }
2137
2138 /// Returns `true` when [s] is private if used as an identifier.
2139 bool isPrivateName(String s) => !s.isEmpty && s.codeUnitAt(0) == $_;
2140
2141 /// A sink that drains into /dev/null.
2142 class NullSink implements EventSink<String> {
2143 final String name;
2144
2145 NullSink(this.name);
2146
2147 add(String value) {}
2148
2149 void addError(Object error, [StackTrace stackTrace]) {}
2150
2151 void close() {}
2152
2153 toString() => name;
2154
2155 /// Convenience method for getting an [api.CompilerOutputProvider].
2156 static NullSink outputProvider(String name, String extension) {
2157 return new NullSink('$name.$extension');
2158 }
2159 }
2160
2161 /// Information about suppressed warnings and hints for a given library.
2162 class SuppressionInfo {
2163 int warnings = 0;
2164 int hints = 0;
2165 }
2166
2167 class GenericTask extends CompilerTask {
2168 final String name;
2169
2170 GenericTask(this.name, Compiler compiler)
2171 : super(compiler);
2172 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698