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

Side by Side Diff: pkg/compiler/lib/src/js_emitter/metadata_collector.dart

Issue 1153243003: dart2js: Use frequency of occurence to sort metadata indices. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 6 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
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart2js.js_emitter; 5 part of dart2js.js_emitter;
6 6
7 abstract class _MetadataEntry extends jsAst.TokenNumber implements Comparable {
8 jsAst.Expression get entry;
9 int get value;
10 int get _rc;
karlklose 2015/05/28 09:39:53 Could you add comments for this class and _rc?
herhut 2015/06/01 12:09:42 Done.
11
12 markSeen();
13 }
14
15 class _BoundMetadataEntry extends _MetadataEntry {
16 int _value = -1;
17 int _rc = 0;
18 final jsAst.Expression entry;
19
20 _BoundMetadataEntry(this.entry);
21
22 bool get isFinalized => _value != -1;
23
24 finalize(int value) {
25 assert(!isFinalized);
26 _value = value;
27 }
28
29 int get value {
30 if (!isFinalized) print ("OHA! I have no value!");
karlklose 2015/05/28 09:39:53 Remove/replace debug print.
herhut 2015/06/01 12:09:42 Done.
31 assert(isFinalized);
32 return _value;
33 }
34
35 markSeen() => _rc++;
36
37 int compareTo(_MetadataEntry other) => other._rc - this._rc;
38 }
39
40 abstract class Placeholder implements jsAst.TokenNumber {
41 bind(_MetadataEntry entry);
42 }
43
44 class _ForwardingMetadataEntry extends _MetadataEntry implements Placeholder {
45 _MetadataEntry _forwardTo;
46 var debugData;
47 var trace;
48
49 bool get isBound => _forwardTo != null;
50
51 _ForwardingMetadataEntry([this.debugData, this.trace]);
52
53 _MetadataEntry get forwardTo {
54 assert(isBound);
55 return _forwardTo;
56 }
57
58 jsAst.Expression get entry {
59 if (isBound) return forwardTo.entry;
60 return new jsAst.LiteralString('"BOGUS: $debugData"');
karlklose 2015/05/28 09:39:53 assert(isBound) or throw?
herhut 2015/06/01 12:09:42 Done.
61 }
62
63 int get value {
64 if (isBound) return forwardTo.value;
65 return -336699;
sra1 2015/05/27 19:38:51 Should this be assert(isBound); ?
herhut 2015/06/01 12:09:42 Done.
66 }
67
68 int get _rc => forwardTo._rc;
69 markSeen() {
70 if (isBound) forwardTo.markSeen();
71 }
72 int compareTo(other) => forwardTo.compareTo(other);
73
74 bind(_MetadataEntry entry) {
75 assert(!isBound);
76 _forwardTo = entry;
77 }
78 }
79
80 class _MetadataList extends jsAst.TokenExpression {
81 jsAst.Expression _value;
82
83 void setExpression(jsAst.Expression value) {
84 assert(_value == null);
85 _value = value;
86 }
87
88 jsAst.Expression get value {
89 assert(_value != null);
90 return _value;
91 }
92 }
93
7 class MetadataCollector { 94 class MetadataCollector {
8 final Compiler _compiler; 95 final Compiler _compiler;
9 final Emitter _emitter; 96 final Emitter _emitter;
10 97
11 /// A list of JS expressions that represent metadata, parameter names and 98 /// A token for a list of expressions that represent metadata, parameter names
12 /// type variable types. 99 /// and type variable types.
13 final List<jsAst.Expression> globalMetadata = <jsAst.Expression>[]; 100 final _MetadataList _globalMetadata = new _MetadataList();
101
102 jsAst.Expression get globalMetadata => _globalMetadata;
103
104 final jsAst.Expression _globalMetadataToken = new _MetadataList();
14 105
15 /// A map used to canonicalize the entries of globalMetadata. 106 /// A map used to canonicalize the entries of globalMetadata.
16 final Map<String, int> _globalMetadataMap = <String, int>{}; 107 Map<String, _BoundMetadataEntry> _globalMetadataMap;
17 108
18 /// A map with lists of JS expressions, one list for each output unit. The 109 /// A map with a token for a lists of JS expressions, one token for each
19 /// entries represent types including function types and typedefs. 110 /// output unit. Once finalized, the entries represent types including
20 final Map<OutputUnit, List<jsAst.Expression>> types = 111 /// function types and typedefs.
21 <OutputUnit, List<jsAst.Expression>>{}; 112 Map<OutputUnit, _MetadataList> _typesTokens =
113 new Map<OutputUnit, _MetadataList>();
114
115 jsAst.Expression getTypesForOutputUnit(OutputUnit outputUnit) {
116 return _typesTokens.putIfAbsent(outputUnit, () => new _MetadataList());
117 }
22 118
23 /// A map used to canonicalize the entries of types. 119 /// A map used to canonicalize the entries of types.
24 final Map<OutputUnit, Map<String, int>> _typesMap = 120 Map<OutputUnit, Map<DartType, _BoundMetadataEntry>> _typesMap =
25 <OutputUnit, Map<String, int>>{}; 121 <OutputUnit, Map<DartType, _BoundMetadataEntry>>{};
26 122
27 MetadataCollector(this._compiler, this._emitter); 123 MetadataCollector(this._compiler, this._emitter) {
124 _globalMetadataMap = new Map<String, _BoundMetadataEntry>();
125 }
28 126
29 JavaScriptBackend get _backend => _compiler.backend; 127 JavaScriptBackend get _backend => _compiler.backend;
30 TypeVariableHandler get _typeVariableHandler => _backend.typeVariableHandler; 128 TypeVariableHandler get _typeVariableHandler => _backend.typeVariableHandler;
31 129
32 bool _mustEmitMetadataFor(Element element) { 130 bool _mustEmitMetadataFor(Element element) {
33 return _backend.mustRetainMetadata && 131 return _backend.mustRetainMetadata &&
34 _backend.referencedFromMirrorSystem(element); 132 _backend.referencedFromMirrorSystem(element);
35 } 133 }
36 134
37 /// The metadata function returns the metadata associated with 135 /// The metadata function returns the metadata associated with
(...skipping 19 matching lines...) Expand all
57 metadata.add(_emitter.constantReference(constant.value)); 155 metadata.add(_emitter.constantReference(constant.value));
58 } 156 }
59 } 157 }
60 } 158 }
61 if (metadata.isEmpty) return null; 159 if (metadata.isEmpty) return null;
62 return js('function() { return # }', 160 return js('function() { return # }',
63 new jsAst.ArrayInitializer(metadata)); 161 new jsAst.ArrayInitializer(metadata));
64 }); 162 });
65 } 163 }
66 164
67 List<int> reifyDefaultArguments(FunctionElement function) { 165 List<jsAst.TokenNumber> reifyDefaultArguments(FunctionElement function) {
68 FunctionSignature signature = function.functionSignature; 166 FunctionSignature signature = function.functionSignature;
69 if (signature.optionalParameterCount == 0) return const []; 167 if (signature.optionalParameterCount == 0) return const [];
70 List<int> defaultValues = <int>[]; 168 List<jsAst.TokenNumber> defaultValues = <jsAst.TokenNumber>[];
71 for (ParameterElement element in signature.optionalParameters) { 169 for (ParameterElement element in signature.optionalParameters) {
72 ConstantExpression constant = 170 ConstantExpression constant =
73 _backend.constants.getConstantForVariable(element); 171 _backend.constants.getConstantForVariable(element);
74 jsAst.Expression expression = (constant == null) 172 jsAst.Expression representation = (constant == null)
75 ? null 173 ? new jsAst.LiteralNull()
76 : _emitter.constantReference(constant.value); 174 : _emitter.constantReference(constant.value);;
77 defaultValues.add(addGlobalMetadata(expression)); 175 defaultValues.add(_addGlobalMetadata(representation));
78 } 176 }
79 return defaultValues; 177 return defaultValues;
80 } 178 }
81 179
82 int reifyMetadata(MetadataAnnotation annotation) { 180 jsAst.Expression reifyMetadata(MetadataAnnotation annotation) {
83 ConstantExpression constant = 181 ConstantExpression constant =
84 _backend.constants.getConstantForMetadata(annotation); 182 _backend.constants.getConstantForMetadata(annotation);
85 if (constant == null) { 183 if (constant == null) {
86 _compiler.internalError(annotation, 'Annotation value is null.'); 184 _compiler.internalError(annotation, 'Annotation value is null.');
87 return -1; 185 return null;
88 } 186 }
89 return addGlobalMetadata(_emitter.constantReference(constant.value)); 187 return _addGlobalMetadata(_emitter.constantReference(constant.value));
90 } 188 }
91 189
92 int reifyType(DartType type, {bool ignoreTypeVariables: false}) { 190 jsAst.Expression reifyType(DartType type, {ignoreTypeVariables: false}) {
93 return reifyTypeForOutputUnit(type, 191 return reifyTypeForOutputUnit(type,
94 _compiler.deferredLoadTask.mainOutputUnit, 192 _compiler.deferredLoadTask.mainOutputUnit,
95 ignoreTypeVariables: ignoreTypeVariables); 193 ignoreTypeVariables: ignoreTypeVariables);
96 } 194 }
97 195
98 int reifyTypeForOutputUnit(DartType type, OutputUnit outputUnit, 196 jsAst.Expression reifyTypeForOutputUnit(DartType type,
99 {bool ignoreTypeVariables: false}) { 197 OutputUnit outputUnit,
100 jsAst.Expression representation = 198 {ignoreTypeVariables: false}) {
101 _backend.rti.getTypeRepresentation( 199 return addTypeInOutputUnit(type, outputUnit,
102 type, 200 ignoreTypeVariables: ignoreTypeVariables);
103 (variable) { 201 }
104 if (ignoreTypeVariables) return new jsAst.LiteralNull(); 202
105 return js.number( 203 jsAst.Expression reifyName(String name) {
106 _typeVariableHandler.reifyTypeVariable( 204 return _addGlobalMetadata(js.string(name));
107 variable.element)); 205 }
108 }, 206
109 (TypedefType typedef) { 207 jsAst.Expression reifyExpression(jsAst.Expression expression) {
110 return _backend.isAccessibleByReflection(typedef.element); 208 return _addGlobalMetadata(expression);
111 }); 209 }
210
211 Placeholder getMetadataPlaceholder([debug]) => new _ForwardingMetadataEntry(de bug);
sra1 2015/05/27 19:38:50 line length
herhut 2015/06/01 12:09:41 Done.
212
213 _MetadataEntry _addGlobalMetadata(jsAst.Node node) {
214 String printed = jsAst.prettyPrint(node, _compiler).getText();
215 return _globalMetadataMap.putIfAbsent(printed, () {
216 return new _BoundMetadataEntry(node);
217 });
218 }
219
220 jsAst.Expression _computeTypeRepresentation(DartType type,
221 {ignoreTypeVariables: false}) {
222 jsAst.Expression representation = _backend.rti.getTypeRepresentation(
223 type,
224 (variable) {
225 if (ignoreTypeVariables) return new jsAst.LiteralNull();
226 return _typeVariableHandler.reifyTypeVariable(variable.element);
227 },
228 (TypedefType typedef) {
229 return _backend.isAccessibleByReflection(typedef.element);
230 });
112 231
113 if (representation is jsAst.LiteralString) { 232 if (representation is jsAst.LiteralString) {
114 // We don't want the representation to be a string, since we use 233 // We don't want the representation to be a string, since we use
115 // strings as indicator for non-initialized types in the lazy emitter. 234 // strings as indicator for non-initialized types in the lazy emitter.
116 _compiler.internalError( 235 _compiler.internalError(
117 NO_LOCATION_SPANNABLE, 'reified types should not be strings.'); 236 NO_LOCATION_SPANNABLE, 'reified types should not be strings.');
118 } 237 }
119 238
120 return addTypeInOutputUnit(representation, outputUnit); 239 return representation;
240
121 } 241 }
122 242
123 int reifyName(String name) { 243 jsAst.Expression addTypeInOutputUnit(DartType type,
124 return addGlobalMetadata(js('"$name"')); 244 OutputUnit outputUnit,
125 } 245 {ignoreTypeVariables: false}) {
126 246 if (_typesMap[outputUnit] == null) {
127 int addGlobalMetadata(jsAst.Expression expression) { 247 _typesMap[outputUnit] = new Map<DartType, _BoundMetadataEntry>();
128 // TODO(sigmund): consider adding an effient way to compare expressions 248 }
129 String string = jsAst.prettyPrint(expression, _compiler).getText(); 249 return _typesMap[outputUnit].putIfAbsent(type, () {
130 return _globalMetadataMap.putIfAbsent(string, () { 250 return new _BoundMetadataEntry(
131 globalMetadata.add(expression); 251 _computeTypeRepresentation(type,
132 return globalMetadata.length - 1; 252 ignoreTypeVariables: ignoreTypeVariables));
133 }); 253 });
134 } 254 }
135 255
136 int addTypeInOutputUnit(jsAst.Expression type, OutputUnit outputUnit) { 256 List<jsAst.TokenNumber> computeMetadata(FunctionElement element) {
137 String string = jsAst.prettyPrint(type, _compiler).getText();
138 if (_typesMap[outputUnit] == null) {
139 _typesMap[outputUnit] = <String, int>{};
140 }
141 return _typesMap[outputUnit].putIfAbsent(string, () {
142
143 if (types[outputUnit] == null) {
144 types[outputUnit] = <jsAst.Expression>[];
145 }
146
147 types[outputUnit].add(type);
148 return types[outputUnit].length - 1;
149 });
150 }
151
152 List<int> computeMetadata(FunctionElement element) {
153 return _compiler.withCurrentElement(element, () { 257 return _compiler.withCurrentElement(element, () {
154 if (!_mustEmitMetadataFor(element)) return const <int>[]; 258 if (!_mustEmitMetadataFor(element)) return const <jsAst.TokenNumber>[];
155 List<int> metadata = <int>[]; 259 List<jsAst.TokenNumber> metadata = <jsAst.TokenNumber>[];
156 Link link = element.metadata; 260 Link link = element.metadata;
157 // TODO(ahe): Why is metadata sometimes null? 261 // TODO(ahe): Why is metadata sometimes null?
158 if (link != null) { 262 if (link != null) {
159 for (; !link.isEmpty; link = link.tail) { 263 for (; !link.isEmpty; link = link.tail) {
160 metadata.add(reifyMetadata(link.head)); 264 metadata.add(reifyMetadata(link.head));
161 } 265 }
162 } 266 }
163 return metadata; 267 return metadata;
164 }); 268 });
165 } 269 }
270
271 void countTokensInProgram(jsAst.Program program) {
272 TokenCounter visitor = new TokenCounter();
273 visitor.countTokens(program);
274 }
275
276 void finalizeTokens() {
277 void checkTokensInTypes(OutputUnit outputUnit, entries) {
278 UnBoundDebugger debugger = new UnBoundDebugger(outputUnit);
279 for (_BoundMetadataEntry entry in entries) {
280 if (entry._rc == 0) {
karlklose 2015/05/28 09:39:53 Add/use helper in _BoundMetadataEntry?
herhut 2015/06/01 12:09:42 Done.
281 print("UNUSED ${entry.hashCode}");
karlklose 2015/05/28 09:39:53 Remove debug print?
herhut 2015/06/01 12:09:41 Done.
282 continue;
283 }
284 debugger.findUnboundPlaceholders(entry.entry);
285 }
286 }
287 void countTokensInTypes(Iterable<_BoundMetadataEntry> entries) {
288 TokenCounter counter = new TokenCounter();
289 entries.where((_BoundMetadataEntry e) => e._rc > 0)
290 .map((_BoundMetadataEntry e) => e.entry)
291 .forEach(counter.countTokens);
292 }
293
294 jsAst.ArrayInitializer finalizeMap(Map<dynamic, _BoundMetadataEntry> map) {
sra1 2015/05/27 19:38:50 Indentation
herhut 2015/06/01 12:09:42 Done.
295 bool isUsed(_BoundMetadataEntry entry) => entry._rc > 0;
karlklose 2015/05/28 09:39:53 Move this helper to _BoundMetaDataEntry?
herhut 2015/06/01 12:09:42 Done.
296 List<_BoundMetadataEntry> entries = map.values.where(isUsed).toList();
297 entries.sort();
sra1 2015/05/27 19:38:50 Sort is not stable. Equivalence classes by referen
herhut 2015/06/01 12:09:41 True but this is not a regression. The original im
298
299 int count = 0;
300 for (_BoundMetadataEntry entry in entries) {
301 entry.finalize(count++);
302 }
sra1 2015/05/27 20:30:15 Longer term I think we need to be more sophisticat
herhut 2015/06/01 12:09:42 Acknowledged.
303
304 List<jsAst.Node> values =
305 entries.map((_BoundMetadataEntry e) => e.entry).toList();
306
307 return new jsAst.ArrayInitializer(values);
308 }
309
310 _globalMetadata.setExpression(finalizeMap(_globalMetadataMap));
311
312 _typesTokens.forEach((OutputUnit outputUnit, _MetadataList token) {
313 Map typesMap = _typesMap[outputUnit];
314 if (typesMap != null) {
315 checkTokensInTypes(outputUnit, typesMap.values);
316 countTokensInTypes(typesMap.values);
317 token.setExpression(finalizeMap(typesMap));
318 } else {
319 token.setExpression(new jsAst.ArrayInitializer([]));
320 }
321 });
322 }
166 } 323 }
324
325 class TokenCounter extends jsAst.BaseVisitor {
326 visitTokenNumber(jsAst.TokenNumber token) {
327 if (token is _MetadataEntry) {
328 token.markSeen();
329 }
330 }
331
332 void countTokens(jsAst.Node node) => node.accept(this);
333 }
334
335 class UnBoundDebugger extends jsAst.BaseVisitor {
336 OutputUnit outputUnit;
337
338 UnBoundDebugger(this.outputUnit);
339
340 visitTokenNumber(jsAst.TokenNumber token) {
341 if (token is _ForwardingMetadataEntry && !token.isBound) {
342 print("UNBOUND ${outputUnit.name} ${token.debugData} ${token.debugData.has hCode}");
karlklose 2015/05/28 09:39:53 Remove debug print.
herhut 2015/06/01 12:09:41 Turned the entire thing into an assertion.
343 }
344 }
345
346 void findUnboundPlaceholders(jsAst.Node node) => node.accept(this);
347 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698