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

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: Addressed sra's comments 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 /// Represents an entry's position in one of the global metadata arrays.
8 ///
9 /// [_rc] is used to count the number of references of the token in the
10 /// ast for a program.
11 /// [value] is the actual position, once they have been finalized.
12 abstract class _MetadataEntry extends jsAst.DeferredNumber
13 implements Comparable {
14 jsAst.Expression get entry;
15 int get value;
16 int get _rc;
17
18 // Mark this entry as seen. On the first time this is seen, the visitor
19 // will be applied to the [entry] to also mark potential [_MetadataEntry]
20 // instances in the [entry] as seen.
21 markSeen(jsAst.BaseVisitor visitor);
22 }
23
24 class _BoundMetadataEntry extends _MetadataEntry {
25 int _value = -1;
26 int _rc = 0;
27 final jsAst.Expression entry;
28
29 _BoundMetadataEntry(this.entry);
30
31 bool get isFinalized => _value != -1;
32
33 finalize(int value) {
34 assert(!isFinalized);
35 _value = value;
36 }
37
38 int get value {
39 assert(isFinalized);
40 return _value;
41 }
42
43 bool get isUsed => _rc > 0;
44
45 markSeen(jsAst.BaseVisitor visitor) {
46 _rc++;
47 if (_rc == 1) entry.accept(visitor);
48 }
49
50 int compareTo(_MetadataEntry other) => other._rc - this._rc;
51 }
52
53 abstract class Placeholder implements jsAst.DeferredNumber {
54 bind(_MetadataEntry entry);
55 }
56
57 class _ForwardingMetadataEntry extends _MetadataEntry implements Placeholder {
58 _MetadataEntry _forwardTo;
59 var debug;
60
61 bool get isBound => _forwardTo != null;
62
63 _ForwardingMetadataEntry([this.debug]);
64
65 _MetadataEntry get forwardTo {
66 assert(isBound);
67 return _forwardTo;
68 }
69
70 jsAst.Expression get entry {
71 assert(isBound);
72 return forwardTo.entry;
73 }
74
75 int get value {
76 assert(isBound);
77 return forwardTo.value;
78 }
79
80 int get _rc => forwardTo._rc;
81
82 markSeen(jsAst.BaseVisitor visitor) => forwardTo.markSeen(visitor);
83
84 int compareTo(other) => forwardTo.compareTo(other);
85
86 bind(_MetadataEntry entry) {
87 assert(!isBound);
88 _forwardTo = entry;
89 }
90 }
91
92 class _MetadataList extends jsAst.DeferredExpression {
93 jsAst.Expression _value;
94
95 void setExpression(jsAst.Expression value) {
96 // TODO(herhut): Enable the below assertion once incremental mode is gone.
97 // assert(_value == null);
98 assert(value.precedenceLevel == this.precedenceLevel);
99 _value = value;
100 }
101
102 jsAst.Expression get value {
103 assert(_value != null);
104 return _value;
105 }
106
107 int get precedenceLevel => js_precedence.PRIMARY;
108 }
109
7 class MetadataCollector { 110 class MetadataCollector {
8 final Compiler _compiler; 111 final Compiler _compiler;
9 final Emitter _emitter; 112 final Emitter _emitter;
10 113
11 /// A list of JS expressions that represent metadata, parameter names and 114 /// A token for a list of expressions that represent metadata, parameter names
12 /// type variable types. 115 /// and type variable types.
13 final List<jsAst.Expression> globalMetadata = <jsAst.Expression>[]; 116 final _MetadataList _globalMetadata = new _MetadataList();
117 jsAst.Expression get globalMetadata => _globalMetadata;
14 118
15 /// A map used to canonicalize the entries of globalMetadata. 119 /// A map used to canonicalize the entries of globalMetadata.
16 final Map<String, int> _globalMetadataMap = <String, int>{}; 120 Map<String, _BoundMetadataEntry> _globalMetadataMap;
17 121
18 /// A map with lists of JS expressions, one list for each output unit. The 122 /// A map with a token for a lists of JS expressions, one token for each
19 /// entries represent types including function types and typedefs. 123 /// output unit. Once finalized, the entries represent types including
20 final Map<OutputUnit, List<jsAst.Expression>> types = 124 /// function types and typedefs.
21 <OutputUnit, List<jsAst.Expression>>{}; 125 Map<OutputUnit, _MetadataList> _typesTokens =
126 new Map<OutputUnit, _MetadataList>();
127
128 jsAst.Expression getTypesForOutputUnit(OutputUnit outputUnit) {
129 return _typesTokens.putIfAbsent(outputUnit, () => new _MetadataList());
130 }
22 131
23 /// A map used to canonicalize the entries of types. 132 /// A map used to canonicalize the entries of types.
24 final Map<OutputUnit, Map<String, int>> _typesMap = 133 Map<OutputUnit, Map<DartType, _BoundMetadataEntry>> _typesMap =
25 <OutputUnit, Map<String, int>>{}; 134 <OutputUnit, Map<DartType, _BoundMetadataEntry>>{};
26 135
27 MetadataCollector(this._compiler, this._emitter); 136 // To support incremental compilation, we have to be able to eagerly emit
137 // metadata and add metadata later on. We use the below two counters for
138 // this.
139 int _globalMetadataCounter = 0;
140 int _globalTypesCounter = 0;
141
142 MetadataCollector(this._compiler, this._emitter) {
143 _globalMetadataMap = new Map<String, _BoundMetadataEntry>();
144 }
28 145
29 JavaScriptBackend get _backend => _compiler.backend; 146 JavaScriptBackend get _backend => _compiler.backend;
30 TypeVariableHandler get _typeVariableHandler => _backend.typeVariableHandler; 147 TypeVariableHandler get _typeVariableHandler => _backend.typeVariableHandler;
31 148
32 bool _mustEmitMetadataFor(Element element) { 149 bool _mustEmitMetadataFor(Element element) {
33 return _backend.mustRetainMetadata && 150 return _backend.mustRetainMetadata &&
34 _backend.referencedFromMirrorSystem(element); 151 _backend.referencedFromMirrorSystem(element);
35 } 152 }
36 153
37 /// The metadata function returns the metadata associated with 154 /// The metadata function returns the metadata associated with
(...skipping 19 matching lines...) Expand all
57 metadata.add(_emitter.constantReference(constant)); 174 metadata.add(_emitter.constantReference(constant));
58 } 175 }
59 } 176 }
60 } 177 }
61 if (metadata.isEmpty) return null; 178 if (metadata.isEmpty) return null;
62 return js('function() { return # }', 179 return js('function() { return # }',
63 new jsAst.ArrayInitializer(metadata)); 180 new jsAst.ArrayInitializer(metadata));
64 }); 181 });
65 } 182 }
66 183
67 List<int> reifyDefaultArguments(FunctionElement function) { 184 List<jsAst.DeferredNumber> reifyDefaultArguments(FunctionElement function) {
68 FunctionSignature signature = function.functionSignature; 185 FunctionSignature signature = function.functionSignature;
69 if (signature.optionalParameterCount == 0) return const []; 186 if (signature.optionalParameterCount == 0) return const [];
70 List<int> defaultValues = <int>[]; 187 List<jsAst.DeferredNumber> defaultValues = <jsAst.DeferredNumber>[];
71 for (ParameterElement element in signature.optionalParameters) { 188 for (ParameterElement element in signature.optionalParameters) {
72 ConstantValue constant = 189 ConstantValue constant =
73 _backend.constants.getConstantValueForVariable(element); 190 _backend.constants.getConstantValueForVariable(element);
74 jsAst.Expression expression = (constant == null) 191 jsAst.Expression expression = (constant == null)
75 ? null 192 ? new jsAst.LiteralNull()
76 : _emitter.constantReference(constant); 193 : _emitter.constantReference(constant);
77 defaultValues.add(addGlobalMetadata(expression)); 194 defaultValues.add(_addGlobalMetadata(expression));
78 } 195 }
79 return defaultValues; 196 return defaultValues;
80 } 197 }
81 198
82 int reifyMetadata(MetadataAnnotation annotation) { 199 jsAst.Expression reifyMetadata(MetadataAnnotation annotation) {
83 ConstantValue constant = 200 ConstantValue constant =
84 _backend.constants.getConstantValueForMetadata(annotation); 201 _backend.constants.getConstantValueForMetadata(annotation);
85 if (constant == null) { 202 if (constant == null) {
86 _compiler.internalError(annotation, 'Annotation value is null.'); 203 _compiler.internalError(annotation, 'Annotation value is null.');
87 return -1; 204 return null;
88 } 205 }
89 return addGlobalMetadata(_emitter.constantReference(constant)); 206 return _addGlobalMetadata(_emitter.constantReference(constant));
90 } 207 }
91 208
92 int reifyType(DartType type, {bool ignoreTypeVariables: false}) { 209 jsAst.Expression reifyType(DartType type, {ignoreTypeVariables: false}) {
93 return reifyTypeForOutputUnit(type, 210 return reifyTypeForOutputUnit(type,
94 _compiler.deferredLoadTask.mainOutputUnit, 211 _compiler.deferredLoadTask.mainOutputUnit,
95 ignoreTypeVariables: ignoreTypeVariables); 212 ignoreTypeVariables: ignoreTypeVariables);
96 } 213 }
97 214
98 int reifyTypeForOutputUnit(DartType type, OutputUnit outputUnit, 215 jsAst.Expression reifyTypeForOutputUnit(DartType type,
99 {bool ignoreTypeVariables: false}) { 216 OutputUnit outputUnit,
100 jsAst.Expression representation = 217 {ignoreTypeVariables: false}) {
101 _backend.rti.getTypeRepresentation( 218 return addTypeInOutputUnit(type, outputUnit,
102 type, 219 ignoreTypeVariables: ignoreTypeVariables);
103 (variable) { 220 }
104 if (ignoreTypeVariables) return new jsAst.LiteralNull(); 221
105 return js.number( 222 jsAst.Expression reifyName(String name) {
106 _typeVariableHandler.reifyTypeVariable( 223 return _addGlobalMetadata(js.string(name));
107 variable.element)); 224 }
108 }, 225
109 (TypedefType typedef) { 226 jsAst.Expression reifyExpression(jsAst.Expression expression) {
110 return _backend.isAccessibleByReflection(typedef.element); 227 return _addGlobalMetadata(expression);
111 }); 228 }
229
230 Placeholder getMetadataPlaceholder([debug]) {
231 return new _ForwardingMetadataEntry(debug);
232 }
233
234 _MetadataEntry _addGlobalMetadata(jsAst.Node node) {
235 String printed = jsAst.prettyPrint(node, _compiler).getText();
236 return _globalMetadataMap.putIfAbsent(printed, () {
237 _BoundMetadataEntry result = new _BoundMetadataEntry(node);
238 if (_compiler.hasIncrementalSupport) {
239 result.finalize(_globalMetadataCounter++);
240 }
241 return result;
242 });
243 }
244
245 jsAst.Expression _computeTypeRepresentation(DartType type,
246 {ignoreTypeVariables: false}) {
247 jsAst.Expression representation = _backend.rti.getTypeRepresentation(
248 type,
249 (variable) {
250 if (ignoreTypeVariables) return new jsAst.LiteralNull();
251 return _typeVariableHandler.reifyTypeVariable(variable.element);
252 },
253 (TypedefType typedef) {
254 return _backend.isAccessibleByReflection(typedef.element);
255 });
112 256
113 if (representation is jsAst.LiteralString) { 257 if (representation is jsAst.LiteralString) {
114 // We don't want the representation to be a string, since we use 258 // 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. 259 // strings as indicator for non-initialized types in the lazy emitter.
116 _compiler.internalError( 260 _compiler.internalError(
117 NO_LOCATION_SPANNABLE, 'reified types should not be strings.'); 261 NO_LOCATION_SPANNABLE, 'reified types should not be strings.');
118 } 262 }
119 263
120 return addTypeInOutputUnit(representation, outputUnit); 264 return representation;
265
121 } 266 }
122 267
123 int reifyName(String name) { 268 jsAst.Expression addTypeInOutputUnit(DartType type,
124 return addGlobalMetadata(js('"$name"')); 269 OutputUnit outputUnit,
125 } 270 {ignoreTypeVariables: false}) {
126 271 if (_typesMap[outputUnit] == null) {
127 int addGlobalMetadata(jsAst.Expression expression) { 272 _typesMap[outputUnit] = new Map<DartType, _BoundMetadataEntry>();
128 // TODO(sigmund): consider adding an effient way to compare expressions 273 }
129 String string = jsAst.prettyPrint(expression, _compiler).getText(); 274 return _typesMap[outputUnit].putIfAbsent(type, () {
130 return _globalMetadataMap.putIfAbsent(string, () { 275 _BoundMetadataEntry result = new _BoundMetadataEntry(
131 globalMetadata.add(expression); 276 _computeTypeRepresentation(type,
132 return globalMetadata.length - 1; 277 ignoreTypeVariables: ignoreTypeVariables));
278 if (_compiler.hasIncrementalSupport) {
279 result.finalize(_globalTypesCounter++);
280 }
281 return result;
133 }); 282 });
134 } 283 }
135 284
136 int addTypeInOutputUnit(jsAst.Expression type, OutputUnit outputUnit) { 285 List<jsAst.DeferredNumber> 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, () { 286 return _compiler.withCurrentElement(element, () {
154 if (!_mustEmitMetadataFor(element)) return const <int>[]; 287 if (!_mustEmitMetadataFor(element)) return const <jsAst.DeferredNumber>[];
155 List<int> metadata = <int>[]; 288 List<jsAst.DeferredNumber> metadata = <jsAst.DeferredNumber>[];
156 Link link = element.metadata; 289 Link link = element.metadata;
157 // TODO(ahe): Why is metadata sometimes null? 290 // TODO(ahe): Why is metadata sometimes null?
158 if (link != null) { 291 if (link != null) {
159 for (; !link.isEmpty; link = link.tail) { 292 for (; !link.isEmpty; link = link.tail) {
160 metadata.add(reifyMetadata(link.head)); 293 metadata.add(reifyMetadata(link.head));
161 } 294 }
162 } 295 }
163 return metadata; 296 return metadata;
164 }); 297 });
165 } 298 }
299
300 void countTokensInProgram(jsAst.Program program) {
301 TokenCounter visitor = new TokenCounter();
302 visitor.countTokens(program);
303 }
304
305 void finalizeTokens() {
306 bool checkTokensInTypes(OutputUnit outputUnit, entries) {
307 UnBoundDebugger debugger = new UnBoundDebugger(outputUnit);
308 for (_BoundMetadataEntry entry in entries) {
309 if (!entry.isUsed) continue;
310 if (debugger.findUnboundPlaceholders(entry.entry)) {
311 return false;
312 }
313 }
314 return true;
315 }
316 void countTokensInTypes(Iterable<_BoundMetadataEntry> entries) {
317 TokenCounter counter = new TokenCounter();
318 entries.where((_BoundMetadataEntry e) => e._rc > 0)
319 .map((_BoundMetadataEntry e) => e.entry)
320 .forEach(counter.countTokens);
321 }
322
323 jsAst.ArrayInitializer finalizeMap(Map<dynamic, _BoundMetadataEntry> map) {
324 // When in incremental mode, we allocate entries eagerly.
325 if (_compiler.hasIncrementalSupport) {
326 return new jsAst.ArrayInitializer(map.values.toList());
327 }
328
329 bool isUsed(_BoundMetadataEntry entry) => entry.isUsed;
330 List<_BoundMetadataEntry> entries = map.values.where(isUsed).toList();
331 entries.sort();
332
333 // TODO(herhut): Bucket entries by index length and use a stable
334 // distribution within buckets.
335 int count = 0;
336 for (_BoundMetadataEntry entry in entries) {
337 entry.finalize(count++);
338 }
339
340 List<jsAst.Node> values =
341 entries.map((_BoundMetadataEntry e) => e.entry).toList();
342
343 return new jsAst.ArrayInitializer(values);
344 }
345
346 _globalMetadata.setExpression(finalizeMap(_globalMetadataMap));
347
348 _typesTokens.forEach((OutputUnit outputUnit, _MetadataList token) {
349 Map typesMap = _typesMap[outputUnit];
350 if (typesMap != null) {
351 assert(checkTokensInTypes(outputUnit, typesMap.values));
352 countTokensInTypes(typesMap.values);
353 token.setExpression(finalizeMap(typesMap));
354 } else {
355 token.setExpression(new jsAst.ArrayInitializer([]));
356 }
357 });
358 }
166 } 359 }
360
361 class TokenCounter extends jsAst.BaseVisitor {
362 @override
363 visitDeferredNumber(jsAst.DeferredNumber token) {
364 if (token is _MetadataEntry) {
365 token.markSeen(this);
366 }
367 }
368
369 void countTokens(jsAst.Node node) => node.accept(this);
370 }
371
372 class UnBoundDebugger extends jsAst.BaseVisitor {
373 OutputUnit outputUnit;
374 bool _foundUnboundToken = false;
375
376 UnBoundDebugger(this.outputUnit);
377
378 @override
379 visitDeferredNumber(jsAst.DeferredNumber token) {
380 if (token is _ForwardingMetadataEntry && !token.isBound) {
381 _foundUnboundToken = true;
382 }
383 }
384
385 bool findUnboundPlaceholders(jsAst.Node node) {
386 node.accept(this);
387 return _foundUnboundToken;
388 }
389 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_emitter/js_emitter.dart ('k') | pkg/compiler/lib/src/js_emitter/model.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698