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

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

Issue 246633006: Revert "JS templates" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 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 | Annotate | Revision Log
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 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
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 56
57 // Set flag used by generateMethod helper below. If we have very few 57 // Set flag used by generateMethod helper below. If we have very few
58 // handlers we use addProperty for them all, rather than try to generate 58 // handlers we use addProperty for them all, rather than try to generate
59 // them at runtime. 59 // them at runtime.
60 bool haveVeryFewNoSuchMemberHandlers = 60 bool haveVeryFewNoSuchMemberHandlers =
61 (addedJsNames.length < VERY_FEW_NO_SUCH_METHOD_HANDLERS); 61 (addedJsNames.length < VERY_FEW_NO_SUCH_METHOD_HANDLERS);
62 62
63 jsAst.Expression generateMethod(String jsName, Selector selector) { 63 jsAst.Expression generateMethod(String jsName, Selector selector) {
64 // Values match JSInvocationMirror in js-helper library. 64 // Values match JSInvocationMirror in js-helper library.
65 int type = selector.invocationMirrorKind; 65 int type = selector.invocationMirrorKind;
66 List<String> parameterNames = 66 List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
67 new List.generate(selector.argumentCount, (i) => '\$$i'); 67 for (int i = 0; i < selector.argumentCount; i++) {
68 parameters.add(new jsAst.Parameter('\$$i'));
69 }
68 70
69 List<jsAst.Expression> argNames = 71 List<jsAst.Expression> argNames =
70 selector.getOrderedNamedArguments().map((String name) => 72 selector.getOrderedNamedArguments().map((String name) =>
71 js.string(name)).toList(); 73 js.string(name)).toList();
72 74
73 String methodName = selector.invocationMirrorMemberName; 75 String methodName = selector.invocationMirrorMemberName;
74 String internalName = namer.invocationMirrorInternalName(selector); 76 String internalName = namer.invocationMirrorInternalName(selector);
75 String reflectionName = task.getReflectionName(selector, internalName); 77 String reflectionName = task.getReflectionName(selector, internalName);
76 if (!haveVeryFewNoSuchMemberHandlers && 78 if (!haveVeryFewNoSuchMemberHandlers &&
77 isTrivialNsmHandler(type, argNames, selector, internalName) && 79 isTrivialNsmHandler(type, argNames, selector, internalName) &&
78 reflectionName == null) { 80 reflectionName == null) {
79 trivialNsmHandlers.add(selector); 81 trivialNsmHandlers.add(selector);
80 return null; 82 return null;
81 } 83 }
82 84
83 assert(backend.isInterceptedName(Compiler.NO_SUCH_METHOD)); 85 assert(backend.isInterceptedName(Compiler.NO_SUCH_METHOD));
84 jsAst.Expression expression = js('this.#(this, #(#, #, #, #, #))', [ 86 jsAst.Expression expression = js('this.$noSuchMethodName')(
85 noSuchMethodName, 87 [js('this'),
86 namer.elementAccess(backend.getCreateInvocationMirror()), 88 namer.elementAccess(backend.getCreateInvocationMirror())([
87 js.string(compiler.enableMinification ? 89 js.string(compiler.enableMinification ?
88 internalName : methodName), 90 internalName : methodName),
89 js.string(internalName), 91 js.string(internalName),
90 js.number(type), 92 type,
91 new jsAst.ArrayInitializer.from(parameterNames.map(js)), 93 new jsAst.ArrayInitializer.from(
92 new jsAst.ArrayInitializer.from(argNames)]); 94 parameters.map((param) => js(param.name)).toList()),
93 95 new jsAst.ArrayInitializer.from(argNames)])]);
94 if (backend.isInterceptedName(selector.name)) { 96 parameters = backend.isInterceptedName(selector.name)
95 return js(r'function($receiver, #) { return # }', 97 ? ([new jsAst.Parameter('\$receiver')]..addAll(parameters))
96 [parameterNames, expression]); 98 : parameters;
97 } else { 99 return js.fun(parameters, js.return_(expression));
98 return js(r'function(#) { return # }', [parameterNames, expression]);
99 }
100 } 100 }
101 101
102 for (String jsName in addedJsNames.keys.toList()..sort()) { 102 for (String jsName in addedJsNames.keys.toList()..sort()) {
103 Selector selector = addedJsNames[jsName]; 103 Selector selector = addedJsNames[jsName];
104 jsAst.Expression method = generateMethod(jsName, selector); 104 jsAst.Expression method = generateMethod(jsName, selector);
105 if (method != null) { 105 if (method != null) {
106 addProperty(jsName, method); 106 addProperty(jsName, method);
107 String reflectionName = task.getReflectionName(selector, jsName); 107 String reflectionName = task.getReflectionName(selector, jsName);
108 if (reflectionName != null) { 108 if (reflectionName != null) {
109 bool accessible = compiler.world.allFunctions.filter(selector).any( 109 bool accessible = compiler.world.allFunctions.filter(selector).any(
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 * as base 88 numbers. The difference is 2, which is "c" in lower-case- 169 * as base 88 numbers. The difference is 2, which is "c" in lower-case-
170 * terminated base 26. 170 * terminated base 26.
171 * 171 *
172 * The reason we don't encode long minified names with this method is that 172 * The reason we don't encode long minified names with this method is that
173 * decoding the base 88 numbers would overflow JavaScript's puny integers. 173 * decoding the base 88 numbers would overflow JavaScript's puny integers.
174 * 174 *
175 * There are some selectors that have a special calling convention (because 175 * There are some selectors that have a special calling convention (because
176 * they are called with the receiver as the first argument). They need a 176 * they are called with the receiver as the first argument). They need a
177 * slightly different noSuchMethod handler, so we handle these first. 177 * slightly different noSuchMethod handler, so we handle these first.
178 */ 178 */
179 List<jsAst.Statement> buildTrivialNsmHandlers() { 179 void addTrivialNsmHandlers(List<jsAst.Node> statements) {
180 List<jsAst.Statement> statements = <jsAst.Statement>[]; 180 if (trivialNsmHandlers.length == 0) return;
181 if (trivialNsmHandlers.length == 0) return statements;
182 // Sort by calling convention, JS name length and by JS name. 181 // Sort by calling convention, JS name length and by JS name.
183 trivialNsmHandlers.sort((a, b) { 182 trivialNsmHandlers.sort((a, b) {
184 bool aIsIntercepted = backend.isInterceptedName(a.name); 183 bool aIsIntercepted = backend.isInterceptedName(a.name);
185 bool bIsIntercepted = backend.isInterceptedName(b.name); 184 bool bIsIntercepted = backend.isInterceptedName(b.name);
186 if (aIsIntercepted != bIsIntercepted) return aIsIntercepted ? -1 : 1; 185 if (aIsIntercepted != bIsIntercepted) return aIsIntercepted ? -1 : 1;
187 String aName = namer.invocationMirrorInternalName(a); 186 String aName = namer.invocationMirrorInternalName(a);
188 String bName = namer.invocationMirrorInternalName(b); 187 String bName = namer.invocationMirrorInternalName(b);
189 if (aName.length != bName.length) return aName.length - bName.length; 188 if (aName.length != bName.length) return aName.length - bName.length;
190 return aName.compareTo(bName); 189 return aName.compareTo(bName);
191 }); 190 });
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 diffEncoding.write(","); 261 diffEncoding.write(",");
263 } 262 }
264 diffEncoding.write(short); 263 diffEncoding.write(short);
265 } 264 }
266 nameCounter++; 265 nameCounter++;
267 } 266 }
268 267
269 // Startup code that loops over the method names and puts handlers on the 268 // Startup code that loops over the method names and puts handlers on the
270 // Object class to catch noSuchMethod invocations. 269 // Object class to catch noSuchMethod invocations.
271 ClassElement objectClass = compiler.objectClass; 270 ClassElement objectClass = compiler.objectClass;
272 jsAst.Expression createInvocationMirror = namer.elementAccess( 271 String createInvocationMirror = namer.isolateAccess(
273 backend.getCreateInvocationMirror()); 272 backend.getCreateInvocationMirror());
274 String noSuchMethodName = namer.publicInstanceMethodNameByArity( 273 String noSuchMethodName = namer.publicInstanceMethodNameByArity(
275 Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT); 274 Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT);
276 var type = 0; 275 var type = 0;
277 if (useDiffEncoding) { 276 if (useDiffEncoding) {
278 statements.add(js.statement('''{ 277 statements.addAll([
279 var objectClassObject = 278 js('var objectClassObject = '
280 collectedClasses[#], // # is name of class Object. 279 ' collectedClasses["${namer.getNameOfClass(objectClass)}"],'
281 shortNames = #.split(","), // # is diffEncoding. 280 ' shortNames = "$diffEncoding".split(","),'
282 nameNumber = 0, 281 ' nameNumber = 0,'
283 diffEncodedString = shortNames[0], 282 ' diffEncodedString = shortNames[0],'
284 calculatedShortNames = [0, 1]; // 0, 1 are args for splice. 283 ' calculatedShortNames = [0, 1]'), // 0, 1 are args for splice.
285 // If we are loading a deferred library the object class will not be i n 284 // If we are loading a deferred library the object class will not be in
286 // the collectedClasses so objectClassObject is undefined, and we skip 285 // the collectedClasses so objectClassObject is undefined, and we skip
287 // setting up the names. 286 // setting up the names.
288 287 js.if_('objectClassObject', [
289 if (objectClassObject) { 288 js.if_('objectClassObject instanceof Array',
290 if (objectClassObject instanceof Array) 289 js('objectClassObject = objectClassObject[1]')),
291 objectClassObject = objectClassObject[1]; 290 js.for_('var i = 0', 'i < diffEncodedString.length', 'i++', [
292 for (var i = 0; i < diffEncodedString.length; i++) { 291 js('var codes = [],'
293 var codes = [], 292 ' diff = 0,'
294 diff = 0, 293 ' digit = diffEncodedString.charCodeAt(i)'),
295 digit = diffEncodedString.charCodeAt(i); 294 js.if_('digit == ${$PERIOD}', [
296 if (digit == ${$PERIOD}) { 295 js('nameNumber = 0'),
297 nameNumber = 0; 296 js('digit = diffEncodedString.charCodeAt(++i)')
298 digit = diffEncodedString.charCodeAt(++i); 297 ]),
299 } 298 js.while_('digit <= ${$Z}', [
300 for (; digit <= ${$Z};) { 299 js('diff *= 26'),
301 diff *= 26; 300 js('diff += (digit - ${$A})'),
302 diff += (digit - ${$A}); 301 js('digit = diffEncodedString.charCodeAt(++i)')
303 digit = diffEncodedString.charCodeAt(++i); 302 ]),
304 } 303 js('diff *= 26'),
305 diff *= 26; 304 js('diff += (digit - ${$a})'),
306 diff += (digit - ${$a}); 305 js('nameNumber += diff'),
307 nameNumber += diff; 306 js.for_('var remaining = nameNumber',
308 for (var remaining = nameNumber; 307 'remaining > 0',
309 remaining > 0; 308 'remaining = (remaining / 88) | 0', [
310 remaining = (remaining / 88) | 0) { 309 js('codes.unshift(${$HASH} + remaining % 88)')
311 codes.unshift(${$HASH} + remaining % 88); 310 ]),
312 } 311 js('calculatedShortNames.push('
313 calculatedShortNames.push( 312 ' String.fromCharCode.apply(String, codes))')
314 String.fromCharCode.apply(String, codes)); 313 ]),
315 } 314 js('shortNames.splice.apply(shortNames, calculatedShortNames)')])
316 shortNames.splice.apply(shortNames, calculatedShortNames); 315 ]);
317 }
318 }''', [
319 js.string(namer.getNameOfClass(objectClass)),
320 js.string('$diffEncoding')]));
321 } else { 316 } else {
322 // No useDiffEncoding version. 317 // No useDiffEncoding version.
323 Iterable<String> longs = trivialNsmHandlers.map((selector) => 318 Iterable<String> longs = trivialNsmHandlers.map((selector) =>
324 selector.invocationMirrorMemberName); 319 selector.invocationMirrorMemberName);
325 statements.add(js.statement( 320 String longNamesConstant = minify ? "" :
326 'var objectClassObject = collectedClasses[#],' 321 ',longNames = "${longs.join(",")}".split(",")';
327 ' shortNames = #.split(",")', [ 322 statements.add(
328 js.string(namer.getNameOfClass(objectClass)), 323 js('var objectClassObject = '
329 js.string('$diffEncoding')])); 324 ' collectedClasses["${namer.getNameOfClass(objectClass)}"],'
330 if (!minify) { 325 ' shortNames = "$diffEncoding".split(",")'
331 statements.add(js.statement('var longNames = #.split(",")', 326 ' $longNamesConstant'));
332 js.string(longs.join(',')))); 327 statements.add(
333 } 328 js.if_('objectClassObject instanceof Array',
334 statements.add(js.statement( 329 js('objectClassObject = objectClassObject[1]')));
335 'if (objectClassObject instanceof Array)'
336 ' objectClassObject = objectClassObject[1];'));
337 } 330 }
338 331
339 // TODO(9631): This is no longer valid for native methods. 332 String sliceOffset = ', (j < $firstNormalSelector) ? 1 : 0';
333 if (firstNormalSelector == 0) sliceOffset = '';
334 if (firstNormalSelector == shorts.length) sliceOffset = ', 1';
335
340 String whatToPatch = task.nativeEmitter.handleNoSuchMethod ? 336 String whatToPatch = task.nativeEmitter.handleNoSuchMethod ?
341 "Object.prototype" : 337 "Object.prototype" :
342 "objectClassObject"; 338 "objectClassObject";
343 339
344 List<jsAst.Expression> sliceOffsetArguments = 340 var params = ['name', 'short', 'type'];
345 firstNormalSelector == 0 341 var sliceOffsetParam = '';
346 ? [] 342 var slice = 'Array.prototype.slice.call';
347 : (firstNormalSelector == shorts.length 343 if (!sliceOffset.isEmpty) {
348 ? [js.number(1)] 344 sliceOffsetParam = ', sliceOffset';
349 : [js('(j < #) ? 1 : 0', js.number(firstNormalSelector))]); 345 params.add('sliceOffset');
350 346 }
351 var sliceOffsetParams = sliceOffsetArguments.isEmpty ? [] : ['sliceOffset']; 347 statements.addAll([
352
353 statements.add(js.statement('''
354 // If we are loading a deferred library the object class will not be in 348 // If we are loading a deferred library the object class will not be in
355 // the collectedClasses so objectClassObject is undefined, and we skip 349 // the collectedClasses so objectClassObject is undefined, and we skip
356 // setting up the names. 350 // setting up the names.
357 if (objectClassObject) { 351 js.if_('objectClassObject', [
358 for (var j = 0; j < shortNames.length; j++) { 352 js.for_('var j = 0', 'j < shortNames.length', 'j++', [
359 var type = 0; 353 js('var type = 0'),
360 var short = shortNames[j]; 354 js('var short = shortNames[j]'),
361 if (short[0] == "${namer.getterPrefix[0]}") type = 1; 355 js.if_('short[0] == "${namer.getterPrefix[0]}"', js('type = 1')),
362 if (short[0] == "${namer.setterPrefix[0]}") type = 2; 356 js.if_('short[0] == "${namer.setterPrefix[0]}"', js('type = 2')),
363 // Generate call to: 357 // Generate call to:
364 // 358 // createInvocationMirror(String name, internalName, type, arguments,
365 // createInvocationMirror(String name, internalName, type, 359 // argumentNames)
366 // arguments, argumentNames) 360 js('$whatToPatch[short] = #(${minify ? "shortNames" : "longNames"}[j], '
367 // 361 'short, type$sliceOffset)',
368 $whatToPatch[short] = (function(name, short, type, #) { 362 js.fun(params, [js.return_(js.fun([],
369 return function() { 363 [js.return_(js(
370 return this.#(this, 364 'this.$noSuchMethodName('
371 #(name, short, type, 365 'this, '
372 Array.prototype.slice.call(arguments, #), 366 '$createInvocationMirror('
373 [])); 367 'name, short, type, '
374 } 368 '$slice(arguments$sliceOffsetParam), []))'))]))]))
375 })(#[j], short, type, #); 369 ])
376 } 370 ])
377 }''', [ 371 ]);
378 sliceOffsetParams, // parameter
379 noSuchMethodName,
380 createInvocationMirror,
381 sliceOffsetParams, // argument to slice
382 minify ? 'shortNames' : 'longNames',
383 sliceOffsetArguments
384 ]));
385
386 return statements;
387 } 372 }
388 } 373 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698