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

Side by Side Diff: pkg/dev_compiler/lib/src/compiler/element_loader.dart

Issue 2797443007: fix #29182, generate top level const fields lazily (Closed)
Patch Set: fix Created 3 years, 8 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) 2015, 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 import 'dart:collection' show HashMap;
6
7 import 'package:analyzer/dart/ast/ast.dart';
8 import 'package:analyzer/dart/element/element.dart';
9 import 'package:func/func.dart';
10 import '../js_ast/js_ast.dart' as JS;
11
12 /// Helper that tracks order of elements visited by the compiler, detecting
13 /// if the top level item can be loaded eagerly or not.
14 class ElementLoader {
15 final HashMap<Element, AstNode> _declarationNodes;
16
17 /// The stack of currently emitting elements, if generating top-level code
18 /// for them. This is not used when inside method bodies, because order does
19 /// not matter for those.
20 final _topLevelElements = new List<Element>();
21
22 /// The current element being loaded.
23 /// We can use this to determine if we're loading top-level code or not:
24 ///
25 /// _currentElements.last == _topLevelElements.last
26 final _currentElements = new List<Element>();
27
28 bool _checkReferences;
29
30 ElementLoader(this._declarationNodes) {
31 assert(!_declarationNodes.containsKey(null));
32 }
33
34 Element get currentElement => _currentElements.last;
35
36 bool isLoaded(Element e) => !_declarationNodes.containsKey(e);
37
38 /// True if the element is currently being loaded.
39 bool _isLoading(Element e) => _currentElements.contains(e);
40
41 /// Start generating top-level code for the element [e].
42 ///
43 /// Subsequent [emitDeclaration] calls will cause those elements to be
44 /// generated before this one, until [finishTopLevel] is called.
45 void startTopLevel(Element e) {
46 assert(identical(e, currentElement));
47 _topLevelElements.add(e);
48 }
49
50 /// Finishes the top-level code for the element [e].
51 void finishTopLevel(Element e) {
52 var last = _topLevelElements.removeLast();
53 assert(identical(e, last));
54 }
55
56 /// Starts recording calls to [declareBeforeUse], until
57 /// [finishCheckingReferences] is called.
58 void startCheckingReferences() {
59 // This function should not be reentrant, and we should not current be
60 // emitting top-level code.
61 assert(_checkReferences == null);
62 assert(_topLevelElements.isEmpty ||
63 !identical(currentElement, _topLevelElements.last));
64 // Assume true until proven otherwise
65 _checkReferences = true;
66 }
67
68 /// Finishes recording references, and returns `true` if all referenced
69 /// items were loaded (or if no items were referenced).
70 bool finishCheckingReferences() {
71 var result = _checkReferences;
72 _checkReferences = null;
73 return result;
74 }
75
76 /// Ensures a top-level declaration is generated, and returns `true` if it
77 /// is part of the current module.
78 /*=T*/ emitDeclaration/*<T extends JS.Node>*/(
79 Element e, Func1<AstNode, JS.Node/*=T*/ > visit) {
80 var node = _declarationNodes.remove(e);
81 if (node == null) return null; // not from this module or already loaded.
82
83 _currentElements.add(e);
84
85 var result = visit(node);
86
87 var last = _currentElements.removeLast();
88 assert(identical(e, last));
89
90 return result;
91 }
92
93 /// To emit top-level module items, we sometimes need to reorder them.
94 ///
95 /// This function takes care of that, and also detects cases where reordering
96 /// failed, and we need to resort to lazy loading, by marking the element as
97 /// lazy. All elements need to be aware of this possibility and generate code
98 /// accordingly.
99 ///
100 /// If we are not emitting top-level code, this does nothing, because all
101 /// declarations are assumed to be available before we start execution.
102 /// See [startTopLevel].
103 void declareBeforeUse(Element e, VoidFunc1<Element> emit) {
104 if (e == null) return;
105
106 if (_checkReferences != null) {
107 _checkReferences = _checkReferences && isLoaded(e) && !_isLoading(e);
108 return;
109 }
110
111 var topLevel = _topLevelElements;
112 if (topLevel.isNotEmpty && identical(currentElement, topLevel.last)) {
113 // If the item is from our library, try to emit it now.
114 emit(e);
115 }
116 }
117 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698