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

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

Issue 1859343004: dartfmt pkg/compiler (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 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
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.full_emitter; 5 part of dart2js.js_emitter.full_emitter;
6 6
7 class NsmEmitter extends CodeEmitterHelper { 7 class NsmEmitter extends CodeEmitterHelper {
8 final List<Selector> trivialNsmHandlers = <Selector>[]; 8 final List<Selector> trivialNsmHandlers = <Selector>[];
9 9
10 /// If this is true then we can generate the noSuchMethod handlers at startup 10 /// If this is true then we can generate the noSuchMethod handlers at startup
11 /// time, instead of them being emitted as part of the Object class. 11 /// time, instead of them being emitted as part of the Object class.
12 bool get generateTrivialNsmHandlers => true; 12 bool get generateTrivialNsmHandlers => true;
13 13
14 // If we need fewer than this many noSuchMethod handlers we can save space by 14 // If we need fewer than this many noSuchMethod handlers we can save space by
15 // just emitting them in JS, rather than emitting the JS needed to generate 15 // just emitting them in JS, rather than emitting the JS needed to generate
16 // them at run time. 16 // them at run time.
17 static const VERY_FEW_NO_SUCH_METHOD_HANDLERS = 10; 17 static const VERY_FEW_NO_SUCH_METHOD_HANDLERS = 10;
18 18
19 static const MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING = 4; 19 static const MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING = 4;
20 20
21 void emitNoSuchMethodHandlers(AddPropertyFunction addProperty) { 21 void emitNoSuchMethodHandlers(AddPropertyFunction addProperty) {
22
23 ClassStubGenerator generator = 22 ClassStubGenerator generator =
24 new ClassStubGenerator(compiler, namer, backend); 23 new ClassStubGenerator(compiler, namer, backend);
25 24
26 // Keep track of the JavaScript names we've already added so we 25 // Keep track of the JavaScript names we've already added so we
27 // do not introduce duplicates (bad for code size). 26 // do not introduce duplicates (bad for code size).
28 Map<jsAst.Name, Selector> addedJsNames 27 Map<jsAst.Name, Selector> addedJsNames =
29 = generator.computeSelectorsForNsmHandlers(); 28 generator.computeSelectorsForNsmHandlers();
30 29
31 // Set flag used by generateMethod helper below. If we have very few 30 // Set flag used by generateMethod helper below. If we have very few
32 // handlers we use addProperty for them all, rather than try to generate 31 // handlers we use addProperty for them all, rather than try to generate
33 // them at runtime. 32 // them at runtime.
34 bool haveVeryFewNoSuchMemberHandlers = 33 bool haveVeryFewNoSuchMemberHandlers =
35 (addedJsNames.length < VERY_FEW_NO_SUCH_METHOD_HANDLERS); 34 (addedJsNames.length < VERY_FEW_NO_SUCH_METHOD_HANDLERS);
36 List<jsAst.Name> names = addedJsNames.keys.toList() 35 List<jsAst.Name> names = addedJsNames.keys.toList()..sort();
37 ..sort();
38 for (jsAst.Name jsName in names) { 36 for (jsAst.Name jsName in names) {
39 Selector selector = addedJsNames[jsName]; 37 Selector selector = addedJsNames[jsName];
40 String reflectionName = emitter.getReflectionName(selector, jsName); 38 String reflectionName = emitter.getReflectionName(selector, jsName);
41 39
42 if (reflectionName != null) { 40 if (reflectionName != null) {
43 emitter.mangledFieldNames[jsName] = reflectionName; 41 emitter.mangledFieldNames[jsName] = reflectionName;
44 } 42 }
45 43
46 List<jsAst.Expression> argNames = 44 List<jsAst.Expression> argNames = selector.callStructure
47 selector.callStructure.getOrderedNamedArguments().map((String name) => 45 .getOrderedNamedArguments()
48 js.string(name)).toList(); 46 .map((String name) => js.string(name))
47 .toList();
49 int type = selector.invocationMirrorKind; 48 int type = selector.invocationMirrorKind;
50 if (!haveVeryFewNoSuchMemberHandlers && 49 if (!haveVeryFewNoSuchMemberHandlers &&
51 isTrivialNsmHandler(type, argNames, selector, jsName) && 50 isTrivialNsmHandler(type, argNames, selector, jsName) &&
52 reflectionName == null) { 51 reflectionName == null) {
53 trivialNsmHandlers.add(selector); 52 trivialNsmHandlers.add(selector);
54 } else { 53 } else {
55 StubMethod method = 54 StubMethod method =
56 generator.generateStubForNoSuchMethod(jsName, selector); 55 generator.generateStubForNoSuchMethod(jsName, selector);
57 addProperty(method.name, method.code); 56 addProperty(method.name, method.code);
58 if (reflectionName != null) { 57 if (reflectionName != null) {
59 bool accessible = 58 bool accessible = compiler.world.allFunctions
60 compiler.world.allFunctions.filter(selector, null).any( 59 .filter(selector, null)
61 (Element e) => backend.isAccessibleByReflection(e)); 60 .any((Element e) => backend.isAccessibleByReflection(e));
62 addProperty(namer.asName('+$reflectionName'), 61 addProperty(
63 js(accessible ? '2' : '0')); 62 namer.asName('+$reflectionName'), js(accessible ? '2' : '0'));
64 } 63 }
65 } 64 }
66 } 65 }
67 } 66 }
68 67
69 // Identify the noSuchMethod handlers that are so simple that we can 68 // Identify the noSuchMethod handlers that are so simple that we can
70 // generate them programatically. 69 // generate them programatically.
71 bool isTrivialNsmHandler( 70 bool isTrivialNsmHandler(
72 int type, List argNames, Selector selector, jsAst.Name internalName) { 71 int type, List argNames, Selector selector, jsAst.Name internalName) {
73 if (!generateTrivialNsmHandlers) return false; 72 if (!generateTrivialNsmHandlers) return false;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 */ 119 */
121 List<jsAst.Statement> buildTrivialNsmHandlers() { 120 List<jsAst.Statement> buildTrivialNsmHandlers() {
122 List<jsAst.Statement> statements = <jsAst.Statement>[]; 121 List<jsAst.Statement> statements = <jsAst.Statement>[];
123 if (trivialNsmHandlers.length == 0) return statements; 122 if (trivialNsmHandlers.length == 0) return statements;
124 123
125 bool minify = compiler.options.enableMinification; 124 bool minify = compiler.options.enableMinification;
126 bool useDiffEncoding = minify && trivialNsmHandlers.length > 30; 125 bool useDiffEncoding = minify && trivialNsmHandlers.length > 30;
127 126
128 // Find out how many selectors there are with the special calling 127 // Find out how many selectors there are with the special calling
129 // convention. 128 // convention.
130 Iterable<Selector> interceptedSelectors = trivialNsmHandlers.where( 129 Iterable<Selector> interceptedSelectors = trivialNsmHandlers
131 (Selector s) => backend.isInterceptedName(s.name)); 130 .where((Selector s) => backend.isInterceptedName(s.name));
132 Iterable<Selector> ordinarySelectors = trivialNsmHandlers.where( 131 Iterable<Selector> ordinarySelectors = trivialNsmHandlers
133 (Selector s) => !backend.isInterceptedName(s.name)); 132 .where((Selector s) => !backend.isInterceptedName(s.name));
134 133
135 // Get the short names (JS names, perhaps minified). 134 // Get the short names (JS names, perhaps minified).
136 Iterable<jsAst.Name> interceptedShorts = 135 Iterable<jsAst.Name> interceptedShorts =
137 interceptedSelectors.map(namer.invocationMirrorInternalName); 136 interceptedSelectors.map(namer.invocationMirrorInternalName);
138 Iterable<jsAst.Name> ordinaryShorts = 137 Iterable<jsAst.Name> ordinaryShorts =
139 ordinarySelectors.map(namer.invocationMirrorInternalName); 138 ordinarySelectors.map(namer.invocationMirrorInternalName);
140 139
141 jsAst.Expression sortedShorts; 140 jsAst.Expression sortedShorts;
142 Iterable<String> sortedLongs; 141 Iterable<String> sortedLongs;
143 if (useDiffEncoding) { 142 if (useDiffEncoding) {
144 assert(minify); 143 assert(minify);
145 sortedShorts = new _DiffEncodedListOfNames( 144 sortedShorts =
146 [interceptedShorts, ordinaryShorts]); 145 new _DiffEncodedListOfNames([interceptedShorts, ordinaryShorts]);
147 } else { 146 } else {
148 Iterable<Selector> sorted = 147 Iterable<Selector> sorted =
149 [interceptedSelectors, ordinarySelectors].expand((e) => (e)); 148 [interceptedSelectors, ordinarySelectors].expand((e) => (e));
150 sortedShorts = js.concatenateStrings( 149 sortedShorts = js.concatenateStrings(
151 js.joinLiterals( 150 js.joinLiterals(sorted.map(namer.invocationMirrorInternalName),
152 sorted.map(namer.invocationMirrorInternalName),
153 js.stringPart(",")), 151 js.stringPart(",")),
154 addQuotes: true); 152 addQuotes: true);
155 153
156 if (!minify) { 154 if (!minify) {
157 sortedLongs = sorted.map((selector) => 155 sortedLongs =
158 selector.invocationMirrorMemberName); 156 sorted.map((selector) => selector.invocationMirrorMemberName);
159 } 157 }
160 } 158 }
161 // Startup code that loops over the method names and puts handlers on the 159 // Startup code that loops over the method names and puts handlers on the
162 // Object class to catch noSuchMethod invocations. 160 // Object class to catch noSuchMethod invocations.
163 ClassElement objectClass = compiler.coreClasses.objectClass; 161 ClassElement objectClass = compiler.coreClasses.objectClass;
164 jsAst.Expression createInvocationMirror = backend.emitter 162 jsAst.Expression createInvocationMirror = backend.emitter
165 .staticFunctionAccess(backend.helpers.createInvocationMirror); 163 .staticFunctionAccess(backend.helpers.createInvocationMirror);
166 if (useDiffEncoding) { 164 if (useDiffEncoding) {
167 statements.add(js.statement('''{ 165 statements.add(js.statement(
166 '''{
168 var objectClassObject = processedClasses.collected[#objectClass], 167 var objectClassObject = processedClasses.collected[#objectClass],
169 nameSequences = #diffEncoding.split("."), 168 nameSequences = #diffEncoding.split("."),
170 shortNames = []; 169 shortNames = [];
171 if (objectClassObject instanceof Array) 170 if (objectClassObject instanceof Array)
172 objectClassObject = objectClassObject[1]; 171 objectClassObject = objectClassObject[1];
173 for (var j = 0; j < nameSequences.length; ++j) { 172 for (var j = 0; j < nameSequences.length; ++j) {
174 var sequence = nameSequences[j].split(","), 173 var sequence = nameSequences[j].split(","),
175 nameNumber = 0; 174 nameNumber = 0;
176 // If we are loading a deferred library the object class will not be 175 // If we are loading a deferred library the object class will not be
177 // in the collectedClasses so objectClassObject is undefined, and we 176 // in the collectedClasses so objectClassObject is undefined, and we
(...skipping 19 matching lines...) Expand all
197 remaining = (remaining / 88) | 0) { 196 remaining = (remaining / 88) | 0) {
198 codes.unshift(${$HASH} + remaining % 88); 197 codes.unshift(${$HASH} + remaining % 88);
199 } 198 }
200 shortNames.push( 199 shortNames.push(
201 String.fromCharCode.apply(String, codes)); 200 String.fromCharCode.apply(String, codes));
202 } 201 }
203 if (sequence.length > 1) { 202 if (sequence.length > 1) {
204 Array.prototype.push.apply(shortNames, sequence.shift()); 203 Array.prototype.push.apply(shortNames, sequence.shift());
205 } 204 }
206 } 205 }
207 }''', {'objectClass': js.quoteName(namer.className(objectClass)), 206 }''',
208 'diffEncoding': sortedShorts})); 207 {
208 'objectClass': js.quoteName(namer.className(objectClass)),
209 'diffEncoding': sortedShorts
210 }));
209 } else { 211 } else {
210 // No useDiffEncoding version. 212 // No useDiffEncoding version.
211 statements.add(js.statement( 213 statements.add(js.statement(
212 'var objectClassObject = processedClasses.collected[#objectClass],' 214 'var objectClassObject = processedClasses.collected[#objectClass],'
213 ' shortNames = #diffEncoding.split(",")', 215 ' shortNames = #diffEncoding.split(",")',
214 {'objectClass': js.quoteName(namer.className(objectClass)), 216 {
215 'diffEncoding': sortedShorts})); 217 'objectClass': js.quoteName(namer.className(objectClass)),
218 'diffEncoding': sortedShorts
219 }));
216 if (!minify) { 220 if (!minify) {
217 statements.add(js.statement('var longNames = #longs.split(",")', 221 statements.add(js.statement('var longNames = #longs.split(",")',
218 {'longs': js.string(sortedLongs.join(','))})); 222 {'longs': js.string(sortedLongs.join(','))}));
219 } 223 }
220 statements.add(js.statement( 224 statements.add(js.statement('if (objectClassObject instanceof Array)'
221 'if (objectClassObject instanceof Array)'
222 ' objectClassObject = objectClassObject[1];')); 225 ' objectClassObject = objectClassObject[1];'));
223 } 226 }
224 227
225 dynamic isIntercepted = // jsAst.Expression or bool. 228 dynamic isIntercepted = // jsAst.Expression or bool.
226 interceptedSelectors.isEmpty 229 interceptedSelectors.isEmpty
227 ? false 230 ? false
228 : ordinarySelectors.isEmpty 231 : ordinarySelectors.isEmpty
229 ? true 232 ? true
230 : js('j < #', js.number(interceptedSelectors.length)); 233 : js('j < #', js.number(interceptedSelectors.length));
231 234
232 statements.add(js.statement(''' 235 statements.add(js.statement(
236 '''
233 // If we are loading a deferred library the object class will not be in 237 // If we are loading a deferred library the object class will not be in
234 // the collectedClasses so objectClassObject is undefined, and we skip 238 // the collectedClasses so objectClassObject is undefined, and we skip
235 // setting up the names. 239 // setting up the names.
236 if (objectClassObject) { 240 if (objectClassObject) {
237 for (var j = 0; j < shortNames.length; j++) { 241 for (var j = 0; j < shortNames.length; j++) {
238 var type = 0; 242 var type = 0;
239 var shortName = shortNames[j]; 243 var shortName = shortNames[j];
240 if (shortName.indexOf("${namer.getterPrefix}") == 0) type = 1; 244 if (shortName.indexOf("${namer.getterPrefix}") == 0) type = 1;
241 if (shortName.indexOf("${namer.setterPrefix}") == 0) type = 2; 245 if (shortName.indexOf("${namer.setterPrefix}") == 0) type = 2;
242 // Generate call to: 246 // Generate call to:
(...skipping 26 matching lines...) Expand all
269 // argument. We could pass anything in place of [this]. 273 // argument. We could pass anything in place of [this].
270 this, 274 this,
271 #createInvocationMirror(name, shortName, type, 275 #createInvocationMirror(name, shortName, type,
272 // Create proper Array with all arguments. 276 // Create proper Array with all arguments.
273 Array.prototype.slice.call(arguments, 0), 277 Array.prototype.slice.call(arguments, 0),
274 [])); 278 []));
275 } 279 }
276 })(#names[j], shortName, type); 280 })(#names[j], shortName, type);
277 } 281 }
278 } 282 }
279 }''', { 283 }''',
284 {
280 'noSuchMethodName': namer.noSuchMethodName, 285 'noSuchMethodName': namer.noSuchMethodName,
281 'createInvocationMirror': createInvocationMirror, 286 'createInvocationMirror': createInvocationMirror,
282 'names': minify ? 'shortNames' : 'longNames', 287 'names': minify ? 'shortNames' : 'longNames',
283 'isIntercepted': isIntercepted})); 288 'isIntercepted': isIntercepted
289 }));
284 290
285 return statements; 291 return statements;
286 } 292 }
287 } 293 }
288 294
289 /// When pretty printed, this node computes a diff-encoded string for the list 295 /// When pretty printed, this node computes a diff-encoded string for the list
290 /// of given names. 296 /// of given names.
291 /// 297 ///
292 /// See [buildTrivialNsmHandlers]. 298 /// See [buildTrivialNsmHandlers].
293 class _DiffEncodedListOfNames extends jsAst.DeferredString 299 class _DiffEncodedListOfNames extends jsAst.DeferredString
294 implements jsAst.AstContainer { 300 implements jsAst.AstContainer {
295 String _cachedValue; 301 String _cachedValue;
296 List<jsAst.ArrayInitializer> ast; 302 List<jsAst.ArrayInitializer> ast;
297 303
298 Iterable<jsAst.Node> get containedNodes => ast; 304 Iterable<jsAst.Node> get containedNodes => ast;
299 305
300 _DiffEncodedListOfNames(Iterable<Iterable<jsAst.Name>> names) { 306 _DiffEncodedListOfNames(Iterable<Iterable<jsAst.Name>> names) {
301 // Store the names in ArrayInitializer nodes to make them discoverable 307 // Store the names in ArrayInitializer nodes to make them discoverable
302 // by traversals of the ast. 308 // by traversals of the ast.
303 ast = names.map((Iterable i) => new jsAst.ArrayInitializer(i.toList())) 309 ast = names
304 .toList(); 310 .map((Iterable i) => new jsAst.ArrayInitializer(i.toList()))
311 .toList();
305 } 312 }
306 313
307 void _computeDiffEncodingForList(Iterable<jsAst.Name> names, 314 void _computeDiffEncodingForList(
308 StringBuffer diffEncoding) { 315 Iterable<jsAst.Name> names, StringBuffer diffEncoding) {
309 // Treat string as a number in base 88 with digits in ASCII order from # to 316 // Treat string as a number in base 88 with digits in ASCII order from # to
310 // z. The short name sorting is based on length, and uses ASCII order for 317 // z. The short name sorting is based on length, and uses ASCII order for
311 // equal length strings so this means that names are ascending. The hash 318 // equal length strings so this means that names are ascending. The hash
312 // character, #, is never given as input, but we need it because it's the 319 // character, #, is never given as input, but we need it because it's the
313 // implicit leading zero (otherwise we could not code names with leading 320 // implicit leading zero (otherwise we could not code names with leading
314 // dollar signs). 321 // dollar signs).
315 int fromBase88(String x) { 322 int fromBase88(String x) {
316 int answer = 0; 323 int answer = 0;
317 for (int i = 0; i < x.length; i++) { 324 for (int i = 0; i < x.length; i++) {
318 int c = x.codeUnitAt(i); 325 int c = x.codeUnitAt(i);
(...skipping 18 matching lines...) Expand all
337 } 344 }
338 return new String.fromCharCodes(encodingChars.reversed.toList()); 345 return new String.fromCharCodes(encodingChars.reversed.toList());
339 } 346 }
340 347
341 // Sort by length, then lexicographic. 348 // Sort by length, then lexicographic.
342 int compare(String a, String b) { 349 int compare(String a, String b) {
343 if (a.length != b.length) return a.length - b.length; 350 if (a.length != b.length) return a.length - b.length;
344 return a.compareTo(b); 351 return a.compareTo(b);
345 } 352 }
346 353
347 List<String> shorts = 354 List<String> shorts = names.map((jsAst.Name name) => name.name).toList()
348 names.map((jsAst.Name name) => name.name) 355 ..sort(compare);
349 .toList()
350 ..sort(compare);
351 356
352 int previous = 0; 357 int previous = 0;
353 for (String short in shorts) { 358 for (String short in shorts) {
354 if (short.length <= NsmEmitter.MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING) { 359 if (short.length <= NsmEmitter.MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING) {
355 int base63 = fromBase88(short); 360 int base63 = fromBase88(short);
356 int diff = base63 - previous; 361 int diff = base63 - previous;
357 previous = base63; 362 previous = base63;
358 String base26Diff = toBase26(diff); 363 String base26Diff = toBase26(diff);
359 diffEncoding.write(base26Diff); 364 diffEncoding.write(base26Diff);
360 } else { 365 } else {
(...skipping 21 matching lines...) Expand all
382 } 387 }
383 388
384 String get value { 389 String get value {
385 if (_cachedValue == null) { 390 if (_cachedValue == null) {
386 _cachedValue = _computeDiffEncoding(); 391 _cachedValue = _computeDiffEncoding();
387 } 392 }
388 393
389 return _cachedValue; 394 return _cachedValue;
390 } 395 }
391 } 396 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698