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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart

Issue 13704004: dart2js: Use js('source') instead of js['source'] to invoke JS mini-parser (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 js_backend; 5 part of js_backend;
6 6
7 /** 7 /**
8 * A function element that represents a closure call. The signature is copied 8 * A function element that represents a closure call. The signature is copied
9 * from the given element. 9 * from the given element.
10 */ 10 */
(...skipping 19 matching lines...) Expand all
30 typedef void DefineStubFunction(String invocationName, jsAst.Expression value); 30 typedef void DefineStubFunction(String invocationName, jsAst.Expression value);
31 31
32 /** 32 /**
33 * A data structure for collecting fragments of a class definition. 33 * A data structure for collecting fragments of a class definition.
34 */ 34 */
35 class ClassBuilder { 35 class ClassBuilder {
36 final List<jsAst.Property> properties = <jsAst.Property>[]; 36 final List<jsAst.Property> properties = <jsAst.Property>[];
37 37
38 // Has the same signature as [DefineStubFunction]. 38 // Has the same signature as [DefineStubFunction].
39 void addProperty(String name, jsAst.Expression value) { 39 void addProperty(String name, jsAst.Expression value) {
40 properties.add(new jsAst.Property(js.string(name), value)); 40 properties.add(new jsAst.Property(jsBuilder.string(name), value));
41 } 41 }
42 42
43 jsAst.Expression toObjectInitializer() { 43 jsAst.Expression toObjectInitializer() {
44 return new jsAst.ObjectInitializer(properties); 44 return new jsAst.ObjectInitializer(properties);
45 } 45 }
46 } 46 }
47 47
48 /** 48 /**
49 * Generates the code for all used classes in the program. Static fields (even 49 * Generates the code for all used classes in the program. Static fields (even
50 * in classes) are ignored, since they can be treated as non-class elements. 50 * in classes) are ignored, since they can be treated as non-class elements.
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 : mainBuffer = new CodeBuffer(), 129 : mainBuffer = new CodeBuffer(),
130 this.namer = namer, 130 this.namer = namer,
131 boundClosureCache = new Map<int, String>(), 131 boundClosureCache = new Map<int, String>(),
132 interceptorClosureCache = new Map<int, String>(), 132 interceptorClosureCache = new Map<int, String>(),
133 constantEmitter = new ConstantEmitter(compiler, namer), 133 constantEmitter = new ConstantEmitter(compiler, namer),
134 super(compiler) { 134 super(compiler) {
135 nativeEmitter = new NativeEmitter(this); 135 nativeEmitter = new NativeEmitter(this);
136 } 136 }
137 137
138 void addComment(String comment, CodeBuffer buffer) { 138 void addComment(String comment, CodeBuffer buffer) {
139 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler)); 139 buffer.write(jsAst.prettyPrint(jsBuilder.comment(comment), compiler));
140 } 140 }
141 141
142 void computeRequiredTypeChecks() { 142 void computeRequiredTypeChecks() {
143 assert(checkedClasses == null && checkedTypedefs == null); 143 assert(checkedClasses == null && checkedTypedefs == null);
144 144
145 compiler.codegenWorld.addImplicitChecks(classesUsingTypeVariableTests); 145 compiler.codegenWorld.addImplicitChecks(classesUsingTypeVariableTests);
146 146
147 checkedClasses = new Set<ClassElement>(); 147 checkedClasses = new Set<ClassElement>();
148 checkedTypedefs = new Set<TypedefElement>(); 148 checkedTypedefs = new Set<TypedefElement>();
149 compiler.codegenWorld.isChecks.forEach((DartType t) { 149 compiler.codegenWorld.isChecks.forEach((DartType t) {
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 const RANGE2_SIZE = RANGE2_LAST - RANGE2_FIRST + 1; 210 const RANGE2_SIZE = RANGE2_LAST - RANGE2_FIRST + 1;
211 const RANGE1_ADJUST = - (FIRST_FIELD_CODE - RANGE1_FIRST); 211 const RANGE1_ADJUST = - (FIRST_FIELD_CODE - RANGE1_FIRST);
212 const RANGE2_ADJUST = - (FIRST_FIELD_CODE + RANGE1_SIZE - RANGE2_FIRST); 212 const RANGE2_ADJUST = - (FIRST_FIELD_CODE + RANGE1_SIZE - RANGE2_FIRST);
213 const RANGE3_ADJUST = 213 const RANGE3_ADJUST =
214 - (FIRST_FIELD_CODE + RANGE1_SIZE + RANGE2_SIZE - RANGE3_FIRST); 214 - (FIRST_FIELD_CODE + RANGE1_SIZE + RANGE2_SIZE - RANGE3_FIRST);
215 215
216 String receiverParamName = compiler.enableMinification ? "r" : "receiver"; 216 String receiverParamName = compiler.enableMinification ? "r" : "receiver";
217 String valueParamName = compiler.enableMinification ? "v" : "value"; 217 String valueParamName = compiler.enableMinification ? "v" : "value";
218 218
219 // function generateAccessor(field, prototype) { 219 // function generateAccessor(field, prototype) {
220 jsAst.Fun fun = js.fun(['field', 'prototype'], [ 220 jsAst.Fun fun = jsBuilder.fun(['field', 'prototype'], [
221 js['var len = field.length'], 221 js('var len = field.length'),
222 js['var code = field.charCodeAt(len - 1)'], 222 js('var code = field.charCodeAt(len - 1)'),
223 js['code = ((code >= $RANGE1_FIRST) && (code <= $RANGE1_LAST))' 223 js('code = ((code >= $RANGE1_FIRST) && (code <= $RANGE1_LAST))'
224 ' ? code - $RANGE1_ADJUST' 224 ' ? code - $RANGE1_ADJUST'
225 ' : ((code >= $RANGE2_FIRST) && (code <= $RANGE2_LAST))' 225 ' : ((code >= $RANGE2_FIRST) && (code <= $RANGE2_LAST))'
226 ' ? code - $RANGE2_ADJUST' 226 ' ? code - $RANGE2_ADJUST'
227 ' : ((code >= $RANGE3_FIRST) && (code <= $RANGE3_LAST))' 227 ' : ((code >= $RANGE3_FIRST) && (code <= $RANGE3_LAST))'
228 ' ? code - $RANGE3_ADJUST' 228 ' ? code - $RANGE3_ADJUST'
229 ' : $NO_FIELD_CODE'], 229 ' : $NO_FIELD_CODE'),
230 230
231 // if (needsAccessor) { 231 // if (needsAccessor) {
232 js.if_('code', [ 232 jsBuilder.if_('code', [
233 js['var getterCode = code & 3'], 233 js('var getterCode = code & 3'),
234 js['var setterCode = code >> 2'], 234 js('var setterCode = code >> 2'),
235 js['var accessorName = field = field.substring(0, len - 1)'], 235 js('var accessorName = field = field.substring(0, len - 1)'),
236 236
237 js['var divider = field.indexOf(":")'], 237 js('var divider = field.indexOf(":")'),
238 js.if_('divider > 0', [ // Colon never in first position. 238 jsBuilder.if_('divider > 0', [ // Colon never in first position.
239 js['accessorName = field.substring(0, divider)'], 239 js('accessorName = field.substring(0, divider)'),
240 js['field = field.substring(divider + 1)'] 240 js('field = field.substring(divider + 1)')
241 ]), 241 ]),
242 242
243 // if (needsGetter) { 243 // if (needsGetter) {
244 js.if_('getterCode', [ 244 jsBuilder.if_('getterCode', [
245 js['var args = (getterCode & 2) ? "$receiverParamName" : ""'], 245 js('var args = (getterCode & 2) ? "$receiverParamName" : ""'),
246 js['var receiver = (getterCode & 1) ? "this" : "$receiverParamName"'], 246 js('var receiver = (getterCode & 1) ? "this" : "$receiverParamName"'),
247 js['var body = "return " + receiver + "." + field'], 247 js('var body = "return " + receiver + "." + field'),
248 js['prototype["${namer.getterPrefix}" + accessorName] = ' 248 js('prototype["${namer.getterPrefix}" + accessorName] = '
249 'new Function(args, body)'] 249 'new Function(args, body)')
250 ]), 250 ]),
251 251
252 // if (needsSetter) { 252 // if (needsSetter) {
253 js.if_('setterCode', [ 253 jsBuilder.if_('setterCode', [
254 js['var args = (setterCode & 2)' 254 js('var args = (setterCode & 2)'
255 ' ? "$receiverParamName,${_}$valueParamName"' 255 ' ? "$receiverParamName,${_}$valueParamName"'
256 ' : "$valueParamName"'], 256 ' : "$valueParamName"'),
257 js['var receiver = (setterCode & 1) ? "this" : "$receiverParamName"'], 257 js('var receiver = (setterCode & 1) ? "this" : "$receiverParamName"'),
258 js['var body = receiver + "." + field + "$_=$_$valueParamName"'], 258 js('var body = receiver + "." + field + "$_=$_$valueParamName"'),
259 js['prototype["${namer.setterPrefix}" + accessorName] = ' 259 js('prototype["${namer.setterPrefix}" + accessorName] = '
260 'new Function(args, body)'] 260 'new Function(args, body)')
261 ]), 261 ]),
262 262
263 ]), 263 ]),
264 264
265 // return field; 265 // return field;
266 js.return_('field') 266 jsBuilder.return_('field')
267 ]); 267 ]);
268 268
269 return new jsAst.FunctionDeclaration( 269 return new jsAst.FunctionDeclaration(
270 new jsAst.VariableDeclaration('generateAccessor'), 270 new jsAst.VariableDeclaration('generateAccessor'),
271 fun); 271 fun);
272 } 272 }
273 273
274 List get defineClassFunction { 274 List get defineClassFunction {
275 // First the class name, then the field names in an array and the members 275 // First the class name, then the field names in an array and the members
276 // (inside an Object literal). 276 // (inside an Object literal).
277 // The caller can also pass in the constructor as a function if needed. 277 // The caller can also pass in the constructor as a function if needed.
278 // 278 //
279 // Example: 279 // Example:
280 // defineClass("A", ["x", "y"], { 280 // defineClass("A", ["x", "y"], {
281 // foo$1: function(y) { 281 // foo$1: function(y) {
282 // print(this.x + y); 282 // print(this.x + y);
283 // }, 283 // },
284 // bar$2: function(t, v) { 284 // bar$2: function(t, v) {
285 // this.x = t - v; 285 // this.x = t - v;
286 // }, 286 // },
287 // }); 287 // });
288 288
289 // function(cls, fields, prototype) { 289 // function(cls, fields, prototype) {
290 var defineClass = js.fun(['cls', 'fields', 'prototype'], [ 290 var defineClass = jsBuilder.fun(['cls', 'fields', 'prototype'], [
291 js['var constructor'], 291 js('var constructor'),
292 292
293 // if (typeof fields == "function") { 293 // if (typeof fields == "function") {
294 js.if_(js['typeof fields == "function"'], [ 294 jsBuilder.if_(js('typeof fields == "function"'), [
295 js['constructor = fields'] 295 js('constructor = fields')
296 ], /* else */ [ 296 ], /* else */ [
297 js['var str = "function " + cls + "("'], 297 js('var str = "function " + cls + "("'),
298 js['var body = ""'], 298 js('var body = ""'),
299 299
300 // for (var i = 0; i < fields.length; i++) { 300 // for (var i = 0; i < fields.length; i++) {
301 js.for_('var i = 0', 'i < fields.length', 'i++', [ 301 jsBuilder.for_('var i = 0', 'i < fields.length', 'i++', [
302 // if (i != 0) str += ", "; 302 // if (i != 0) str += ", ";
303 js.if_('i != 0', js['str += ", "']), 303 jsBuilder.if_('i != 0', js('str += ", "')),
304 304
305 js['var field = fields[i]'], 305 js('var field = fields[i]'),
306 js['field = generateAccessor(field, prototype)'], 306 js('field = generateAccessor(field, prototype)'),
307 js['str += field'], 307 js('str += field'),
308 js['body += ("this." + field + " = " + field + ";\\n")'] 308 js('body += ("this." + field + " = " + field + ";\\n")')
309 ]), 309 ]),
310 310
311 js['str += (") {" + body + "}\\nreturn " + cls)'], 311 js('str += (") {" + body + "}\\nreturn " + cls)'),
312 312
313 js['constructor = (new Function(str))()'] 313 js('constructor = (new Function(str))()')
314 ]), 314 ]),
315 315
316 js['constructor.prototype = prototype'], 316 js('constructor.prototype = prototype'),
317 js['constructor.builtin\$cls = cls'], 317 js('constructor.builtin\$cls = cls'),
318 318
319 // return constructor; 319 // return constructor;
320 js.return_('constructor') 320 jsBuilder.return_('constructor')
321 ]); 321 ]);
322 // Declare a function called "generateAccessor". This is used in 322 // Declare a function called "generateAccessor". This is used in
323 // defineClassFunction (it's a local declaration in init()). 323 // defineClassFunction (it's a local declaration in init()).
324 return [ 324 return [
325 generateAccessorFunction, 325 generateAccessorFunction,
326 js['$generateAccessorHolder = generateAccessor'], 326 js('$generateAccessorHolder = generateAccessor'),
327 new jsAst.FunctionDeclaration( 327 new jsAst.FunctionDeclaration(
328 new jsAst.VariableDeclaration('defineClass'), defineClass) ]; 328 new jsAst.VariableDeclaration('defineClass'), defineClass) ];
329 } 329 }
330 330
331 /** Needs defineClass to be defined. */ 331 /** Needs defineClass to be defined. */
332 List buildProtoSupportCheck() { 332 List buildProtoSupportCheck() {
333 // On Firefox and Webkit browsers we can manipulate the __proto__ 333 // On Firefox and Webkit browsers we can manipulate the __proto__
334 // directly. Opera claims to have __proto__ support, but it is buggy. 334 // directly. Opera claims to have __proto__ support, but it is buggy.
335 // So we have to do more checks. 335 // So we have to do more checks.
336 // Opera bug was filed as DSK-370158, and fixed as CORE-47615 336 // Opera bug was filed as DSK-370158, and fixed as CORE-47615
337 // (http://my.opera.com/desktopteam/blog/2012/07/20/more-12-01-fixes). 337 // (http://my.opera.com/desktopteam/blog/2012/07/20/more-12-01-fixes).
338 // If the browser does not support __proto__ we need to instantiate an 338 // If the browser does not support __proto__ we need to instantiate an
339 // object with the correct (internal) prototype set up correctly, and then 339 // object with the correct (internal) prototype set up correctly, and then
340 // copy the members. 340 // copy the members.
341 // TODO(8541): Remove this work around. 341 // TODO(8541): Remove this work around.
342 342
343 return [ 343 return [
344 js['var $supportsProtoName = false'], 344 js('var $supportsProtoName = false'),
345 js['var tmp = (defineClass("c", ["f?"], {})).prototype'], 345 js('var tmp = (defineClass("c", ["f?"], {})).prototype'),
346 346
347 js.if_(js['tmp.__proto__'], [ 347 jsBuilder.if_(js('tmp.__proto__'), [
348 js['tmp.__proto__ = {}'], 348 js('tmp.__proto__ = {}'),
349 js.if_(js[r'typeof tmp.get$f != "undefined"'], 349 jsBuilder.if_(js(r'typeof tmp.get$f != "undefined"'),
350 js['$supportsProtoName = true']) 350 js('$supportsProtoName = true'))
351 351
352 ]) 352 ])
353 ]; 353 ];
354 } 354 }
355 355
356 const MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING = 4; 356 const MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING = 4;
357 357
358 // If we need fewer than this many noSuchMethod handlers we can save space by 358 // If we need fewer than this many noSuchMethod handlers we can save space by
359 // just emitting them in JS, rather than emitting the JS needed to generate 359 // just emitting them in JS, rather than emitting the JS needed to generate
360 // them at run time. 360 // them at run time.
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 // Startup code that loops over the method names and puts handlers on the 491 // Startup code that loops over the method names and puts handlers on the
492 // Object class to catch noSuchMethod invocations. 492 // Object class to catch noSuchMethod invocations.
493 ClassElement objectClass = compiler.objectClass; 493 ClassElement objectClass = compiler.objectClass;
494 String createInvocationMirror = namer.getName( 494 String createInvocationMirror = namer.getName(
495 compiler.createInvocationMirrorElement); 495 compiler.createInvocationMirrorElement);
496 String noSuchMethodName = namer.publicInstanceMethodNameByArity( 496 String noSuchMethodName = namer.publicInstanceMethodNameByArity(
497 Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT); 497 Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT);
498 var type = 0; 498 var type = 0;
499 if (useDiffEncoding) { 499 if (useDiffEncoding) {
500 statements.addAll([ 500 statements.addAll([
501 js['var objectClassObject = ' 501 js('var objectClassObject = '
502 ' collectedClasses["${namer.getName(objectClass)}"],' 502 ' collectedClasses["${namer.getName(objectClass)}"],'
503 ' shortNames = "$diffEncoding".split(","),' 503 ' shortNames = "$diffEncoding".split(","),'
504 ' nameNumber = 0,' 504 ' nameNumber = 0,'
505 ' diffEncodedString = shortNames[0],' 505 ' diffEncodedString = shortNames[0],'
506 ' calculatedShortNames = [0, 1]'], // 0, 1 are args for splice. 506 ' calculatedShortNames = [0, 1]'), // 0, 1 are args for splice.
507 js.for_('var i = 0', 'i < diffEncodedString.length', 'i++', [ 507 jsBuilder.for_('var i = 0', 'i < diffEncodedString.length', 'i++', [
508 js['var codes = [],' 508 js('var codes = [],'
509 ' diff = 0,' 509 ' diff = 0,'
510 ' digit = diffEncodedString.charCodeAt(i)'], 510 ' digit = diffEncodedString.charCodeAt(i)'),
511 js.if_('digit == ${$PERIOD}', [ 511 jsBuilder.if_('digit == ${$PERIOD}', [
512 js['nameNumber = 0'], 512 js('nameNumber = 0'),
513 js['digit = diffEncodedString.charCodeAt(++i)'] 513 js('digit = diffEncodedString.charCodeAt(++i)')
514 ]), 514 ]),
515 js.while_('digit <= ${$Z}', [ 515 jsBuilder.while_('digit <= ${$Z}', [
516 js['diff *= 26'], 516 js('diff *= 26'),
517 js['diff += (digit - ${$A})'], 517 js('diff += (digit - ${$A})'),
518 js['digit = diffEncodedString.charCodeAt(++i)'] 518 js('digit = diffEncodedString.charCodeAt(++i)')
519 ]), 519 ]),
520 js['diff *= 26'], 520 js('diff *= 26'),
521 js['diff += (digit - ${$a})'], 521 js('diff += (digit - ${$a})'),
522 js['nameNumber += diff'], 522 js('nameNumber += diff'),
523 js.for_('var remaining = nameNumber', 523 jsBuilder.for_('var remaining = nameNumber',
524 'remaining > 0', 524 'remaining > 0',
525 'remaining = ((remaining / 88) | 0)', [ 525 'remaining = ((remaining / 88) | 0)', [
526 js['codes.unshift(${$HASH} + (remaining % 88))'] 526 js('codes.unshift(${$HASH} + (remaining % 88))')
527 ]), 527 ]),
528 js['calculatedShortNames.push(' 528 js('calculatedShortNames.push('
529 ' String.fromCharCode.apply(String, codes))'] 529 ' String.fromCharCode.apply(String, codes))')
530 ]), 530 ]),
531 js['shortNames.splice.apply(shortNames, calculatedShortNames)'] 531 js('shortNames.splice.apply(shortNames, calculatedShortNames)')
532 ]); 532 ]);
533 } else { 533 } else {
534 // No useDiffEncoding version. 534 // No useDiffEncoding version.
535 Iterable<String> longs = trivialNsmHandlers.map((selector) => 535 Iterable<String> longs = trivialNsmHandlers.map((selector) =>
536 selector.invocationMirrorMemberName); 536 selector.invocationMirrorMemberName);
537 String longNamesConstant = minify ? "" : 537 String longNamesConstant = minify ? "" :
538 ',longNames = "${longs.join(",")}".split(",")'; 538 ',longNames = "${longs.join(",")}".split(",")';
539 statements.add( 539 statements.add(
540 js['var objectClassObject = ' 540 js('var objectClassObject = '
541 ' collectedClasses["${namer.getName(objectClass)}"],' 541 ' collectedClasses["${namer.getName(objectClass)}"],'
542 ' shortNames = "$diffEncoding".split(",")' 542 ' shortNames = "$diffEncoding".split(",")'
543 ' $longNamesConstant']); 543 ' $longNamesConstant'));
544 } 544 }
545 545
546 String sliceOffset = '," + (j < $firstNormalSelector ? 1 : 0)'; 546 String sliceOffset = '," + (j < $firstNormalSelector ? 1 : 0)';
547 if (firstNormalSelector == 0) sliceOffset = '"'; 547 if (firstNormalSelector == 0) sliceOffset = '"';
548 if (firstNormalSelector == shorts.length) sliceOffset = ', 1"'; 548 if (firstNormalSelector == shorts.length) sliceOffset = ', 1"';
549 549
550 String whatToPatch = nativeEmitter.handleNoSuchMethod ? 550 String whatToPatch = nativeEmitter.handleNoSuchMethod ?
551 "Object.prototype" : 551 "Object.prototype" :
552 "objectClassObject"; 552 "objectClassObject";
553 553
554 statements.addAll([ 554 statements.addAll([
555 js.for_('var j = 0', 'j < shortNames.length', 'j++', [ 555 jsBuilder.for_('var j = 0', 'j < shortNames.length', 'j++', [
556 js['var type = 0'], 556 js('var type = 0'),
557 js['var short = shortNames[j]'], 557 js('var short = shortNames[j]'),
558 js.if_('short[0] == "${namer.getterPrefix[0]}"', js['type = 1']), 558 jsBuilder.if_('short[0] == "${namer.getterPrefix[0]}"', js('type = 1')),
559 js.if_('short[0] == "${namer.setterPrefix[0]}"', js['type = 2']), 559 jsBuilder.if_('short[0] == "${namer.setterPrefix[0]}"', js('type = 2')),
560 js['$whatToPatch[short] = Function("' 560 js('$whatToPatch[short] = Function("'
561 'return this.$noSuchMethodName(' 561 'return this.$noSuchMethodName('
562 'this,' 562 'this,'
563 '${namer.CURRENT_ISOLATE}.$createInvocationMirror(\'"' 563 '${namer.CURRENT_ISOLATE}.$createInvocationMirror(\'"'
564 ' + ${minify ? "shortNames" : "longNames"}[j]' 564 ' + ${minify ? "shortNames" : "longNames"}[j]'
565 ' + "\',\'" + short + "\',"' 565 ' + "\',\'" + short + "\',"'
566 ' + type' 566 ' + type'
567 ' + ",Array.prototype.slice.call(arguments' 567 ' + ",Array.prototype.slice.call(arguments'
568 '$sliceOffset' 568 '$sliceOffset'
569 ' + "),[]))")'] 569 ' + "),[]))")')
570 ]) 570 ])
571 ]); 571 ]);
572 } 572 }
573 573
574 jsAst.Fun get finishClassesFunction { 574 jsAst.Fun get finishClassesFunction {
575 // Class descriptions are collected in a JS object. 575 // Class descriptions are collected in a JS object.
576 // 'finishClasses' takes all collected descriptions and sets up 576 // 'finishClasses' takes all collected descriptions and sets up
577 // the prototype. 577 // the prototype.
578 // Once set up, the constructors prototype field satisfy: 578 // Once set up, the constructors prototype field satisfy:
579 // - it contains all (local) members. 579 // - it contains all (local) members.
580 // - its internal prototype (__proto__) points to the superclass' 580 // - its internal prototype (__proto__) points to the superclass'
581 // prototype field. 581 // prototype field.
582 // - the prototype's constructor field points to the JavaScript 582 // - the prototype's constructor field points to the JavaScript
583 // constructor. 583 // constructor.
584 // For engines where we have access to the '__proto__' we can manipulate 584 // For engines where we have access to the '__proto__' we can manipulate
585 // the object literal directly. For other engines we have to create a new 585 // the object literal directly. For other engines we have to create a new
586 // object and copy over the members. 586 // object and copy over the members.
587 587
588 List<jsAst.Node> statements = [ 588 List<jsAst.Node> statements = [
589 js['var pendingClasses = {}'], 589 js('var pendingClasses = {}'),
590 590
591 js['var hasOwnProperty = Object.prototype.hasOwnProperty'], 591 js('var hasOwnProperty = Object.prototype.hasOwnProperty'),
592 592
593 // for (var cls in collectedClasses) { 593 // for (var cls in collectedClasses) {
594 js.forIn('cls', 'collectedClasses', [ 594 jsBuilder.forIn('cls', 'collectedClasses', [
595 // if (hasOwnProperty.call(collectedClasses, cls)) { 595 // if (hasOwnProperty.call(collectedClasses, cls)) {
596 js.if_('hasOwnProperty.call(collectedClasses, cls)', [ 596 jsBuilder.if_('hasOwnProperty.call(collectedClasses, cls)', [
597 js['var desc = collectedClasses[cls]'], 597 js('var desc = collectedClasses[cls]'),
598 598
599 /* The 'fields' are either a constructor function or a 599 /* The 'fields' are either a constructor function or a
600 * string encoding fields, constructor and superclass. Get 600 * string encoding fields, constructor and superclass. Get
601 * the superclass and the fields in the format 601 * the superclass and the fields in the format
602 * Super;field1,field2 from the null-string property on the 602 * Super;field1,field2 from the null-string property on the
603 * descriptor. 603 * descriptor.
604 */ 604 */
605 // var fields = desc[""], supr; 605 // var fields = desc[""], supr;
606 js['var fields = desc[""], supr'], 606 js('var fields = desc[""], supr'),
607 607
608 js.if_('typeof fields == "string"', [ 608 jsBuilder.if_('typeof fields == "string"', [
609 js['var s = fields.split(";")'], 609 js('var s = fields.split(";")'),
610 js['supr = s[0]'], 610 js('supr = s[0]'),
611 js['fields = s[1] == "" ? [] : s[1].split(",")'], 611 js('fields = s[1] == "" ? [] : s[1].split(",")'),
612 ], /* else */ [ 612 ], /* else */ [
613 js['supr = desc.super'] 613 js('supr = desc.super')
614 ]), 614 ]),
615 615
616 js['isolateProperties[cls] = defineClass(cls, fields, desc)'], 616 js('isolateProperties[cls] = defineClass(cls, fields, desc)'),
617 617
618 // if (supr) pendingClasses[cls] = supr; 618 // if (supr) pendingClasses[cls] = supr;
619 js.if_('supr', js['pendingClasses[cls] = supr']) 619 jsBuilder.if_('supr', js('pendingClasses[cls] = supr'))
620 ]) 620 ])
621 ]), 621 ]),
622 622
623 js['var finishedClasses = {}'], 623 js('var finishedClasses = {}'),
624 624
625 // function finishClass(cls) { ... } 625 // function finishClass(cls) { ... }
626 buildFinishClass(), 626 buildFinishClass(),
627 ]; 627 ];
628 628
629 addTrivialNsmHandlers(statements); 629 addTrivialNsmHandlers(statements);
630 630
631 statements.add( 631 statements.add(
632 // for (var cls in pendingClasses) finishClass(cls); 632 // for (var cls in pendingClasses) finishClass(cls);
633 js.forIn('cls', 'pendingClasses', js['finishClass(cls)']) 633 jsBuilder.forIn('cls', 'pendingClasses', js('finishClass(cls)'))
634 ); 634 );
635 // function(collectedClasses, 635 // function(collectedClasses,
636 // isolateProperties, 636 // isolateProperties,
637 // existingIsolateProperties) { 637 // existingIsolateProperties) {
638 return js.fun(['collectedClasses', 'isolateProperties', 638 return jsBuilder.fun(['collectedClasses', 'isolateProperties',
639 'existingIsolateProperties'], statements); 639 'existingIsolateProperties'], statements);
640 } 640 }
641 641
642 jsAst.FunctionDeclaration buildFinishClass() { 642 jsAst.FunctionDeclaration buildFinishClass() {
643 // function finishClass(cls) { 643 // function finishClass(cls) {
644 jsAst.Fun fun = js.fun(['cls'], [ 644 jsAst.Fun fun = jsBuilder.fun(['cls'], [
645 645
646 // TODO(8540): Remove this work around. 646 // TODO(8540): Remove this work around.
647 /* Opera does not support 'getOwnPropertyNames'. Therefore we use 647 /* Opera does not support 'getOwnPropertyNames'. Therefore we use
648 hasOwnProperty instead. */ 648 hasOwnProperty instead. */
649 js['var hasOwnProperty = Object.prototype.hasOwnProperty'], 649 js('var hasOwnProperty = Object.prototype.hasOwnProperty'),
650 650
651 // if (hasOwnProperty.call(finishedClasses, cls)) return; 651 // if (hasOwnProperty.call(finishedClasses, cls)) return;
652 js.if_('hasOwnProperty.call(finishedClasses, cls)', 652 jsBuilder.if_('hasOwnProperty.call(finishedClasses, cls)',
653 js.return_()), 653 jsBuilder.return_()),
654 654
655 js['finishedClasses[cls] = true'], 655 js('finishedClasses[cls] = true'),
656 656
657 js['var superclass = pendingClasses[cls]'], 657 js('var superclass = pendingClasses[cls]'),
658 658
659 // The superclass is only false (empty string) for Dart's Object class. 659 // The superclass is only false (empty string) for Dart's Object class.
660 // The minifier together with noSuchMethod can put methods on the 660 // The minifier together with noSuchMethod can put methods on the
661 // Object.prototype object, and they show through here, so we check that 661 // Object.prototype object, and they show through here, so we check that
662 // we have a string. 662 // we have a string.
663 js.if_('!superclass || typeof superclass != "string"', js.return_()), 663 jsBuilder.if_('!superclass || typeof superclass != "string"',
664 js['finishClass(superclass)'], 664 jsBuilder.return_()),
665 js['var constructor = isolateProperties[cls]'], 665 js('finishClass(superclass)'),
666 js['var superConstructor = isolateProperties[superclass]'], 666 js('var constructor = isolateProperties[cls]'),
667 js('var superConstructor = isolateProperties[superclass]'),
667 668
668 // if (!superConstructor) 669 // if (!superConstructor)
669 // superConstructor = existingIsolateProperties[superclass]; 670 // superConstructor = existingIsolateProperties[superclass];
670 js.if_(js['superConstructor'].not, 671 jsBuilder.if_(js('superConstructor').not,
671 js['superConstructor'].assign( 672 js('superConstructor').assign(
672 js['existingIsolateProperties'][js['superclass']])), 673 js('existingIsolateProperties')[js('superclass')])),
673 674
674 js['var prototype = constructor.prototype'], 675 js('var prototype = constructor.prototype'),
675 676
676 // if ($supportsProtoName) { 677 // if ($supportsProtoName) {
677 js.if_(supportsProtoName, [ 678 jsBuilder.if_(supportsProtoName, [
678 js['prototype.__proto__ = superConstructor.prototype'], 679 js('prototype.__proto__ = superConstructor.prototype'),
679 js['prototype.constructor = constructor'], 680 js('prototype.constructor = constructor'),
680 681
681 ], /* else */ [ 682 ], /* else */ [
682 // function tmp() {}; 683 // function tmp() {};
683 new jsAst.FunctionDeclaration( 684 new jsAst.FunctionDeclaration(
684 new jsAst.VariableDeclaration('tmp'), 685 new jsAst.VariableDeclaration('tmp'),
685 js.fun([], [])), 686 jsBuilder.fun([], [])),
686 687
687 js['tmp.prototype = superConstructor.prototype'], 688 js('tmp.prototype = superConstructor.prototype'),
688 js['var newPrototype = new tmp()'], 689 js('var newPrototype = new tmp()'),
689 690
690 js['constructor.prototype = newPrototype'], 691 js('constructor.prototype = newPrototype'),
691 js['newPrototype.constructor = constructor'], 692 js('newPrototype.constructor = constructor'),
692 693
693 // for (var member in prototype) { 694 // for (var member in prototype) {
694 js.forIn('member', 'prototype', [ 695 jsBuilder.forIn('member', 'prototype', [
695 /* Short version of: if (member == '') */ 696 /* Short version of: if (member == '') */
696 // if (!member) continue; 697 // if (!member) continue;
697 js.if_('!member', new jsAst.Continue(null)), 698 jsBuilder.if_('!member', new jsAst.Continue(null)),
698 699
699 // if (hasOwnProperty.call(prototype, member)) { 700 // if (hasOwnProperty.call(prototype, member)) {
700 js.if_('hasOwnProperty.call(prototype, member)', [ 701 jsBuilder.if_('hasOwnProperty.call(prototype, member)', [
701 js['newPrototype[member] = prototype[member]'] 702 js('newPrototype[member] = prototype[member]')
702 ]) 703 ])
703 ]) 704 ])
704 705
705 ]) 706 ])
706 ]); 707 ]);
707 708
708 return new jsAst.FunctionDeclaration( 709 return new jsAst.FunctionDeclaration(
709 new jsAst.VariableDeclaration('finishClass'), 710 new jsAst.VariableDeclaration('finishClass'),
710 fun); 711 fun);
711 } 712 }
(...skipping 18 matching lines...) Expand all
730 // which is then dynamically evaluated: 731 // which is then dynamically evaluated:
731 // var newIsolate = new Function(str); 732 // var newIsolate = new Function(str);
732 // 733 //
733 // We also copy over old values like the prototype, and the 734 // We also copy over old values like the prototype, and the
734 // isolateProperties themselves. 735 // isolateProperties themselves.
735 736
736 List copyFinishClasses = []; 737 List copyFinishClasses = [];
737 if (needsDefineClass) { 738 if (needsDefineClass) {
738 copyFinishClasses.add( 739 copyFinishClasses.add(
739 // newIsolate.$finishClasses = oldIsolate.$finishClasses; 740 // newIsolate.$finishClasses = oldIsolate.$finishClasses;
740 js['newIsolate'][finishClassesProperty].assign( 741 js('newIsolate')[finishClassesProperty].assign(
741 js['oldIsolate'][finishClassesProperty])); 742 js('oldIsolate')[finishClassesProperty]));
742 } 743 }
743 744
744 // function(oldIsolate) { 745 // function(oldIsolate) {
745 return js.fun('oldIsolate', [ 746 return jsBuilder.fun('oldIsolate', [
746 js['var isolateProperties = oldIsolate.${namer.isolatePropertiesName}'], 747 js('var isolateProperties = oldIsolate.${namer.isolatePropertiesName}'),
747 748
748 js[r'isolateProperties.$currentScript =' 749 js(r'isolateProperties.$currentScript ='
749 'typeof document == "object" ?' 750 'typeof document == "object" ?'
750 '(document.currentScript ||' 751 '(document.currentScript ||'
751 'document.scripts[document.scripts.length - 1]) :' 752 'document.scripts[document.scripts.length - 1]) :'
752 'null'], 753 'null'),
753 754
754 js['var isolatePrototype = oldIsolate.prototype'], 755 js('var isolatePrototype = oldIsolate.prototype'),
755 js['var str = "{\\n"'], 756 js('var str = "{\\n"'),
756 js['str += ' 757 js('str += '
757 '"var properties = $isolate.${namer.isolatePropertiesName};\\n"'], 758 '"var properties = $isolate.${namer.isolatePropertiesName};\\n"'),
758 js['var hasOwnProperty = Object.prototype.hasOwnProperty'], 759 js('var hasOwnProperty = Object.prototype.hasOwnProperty'),
759 760
760 // for (var staticName in isolateProperties) { 761 // for (var staticName in isolateProperties) {
761 js.forIn('staticName', 'isolateProperties', [ 762 jsBuilder.forIn('staticName', 'isolateProperties', [
762 js.if_('hasOwnProperty.call(isolateProperties, staticName)', [ 763 jsBuilder.if_('hasOwnProperty.call(isolateProperties, staticName)', [
763 js['str += ("this." + staticName + "= properties." + staticName + ' 764 js('str += ("this." + staticName + "= properties." + staticName + '
764 '";\\n")'] 765 '";\\n")')
765 ]) 766 ])
766 ]), 767 ]),
767 768
768 js['str += "}\\n"'], 769 js('str += "}\\n"'),
769 770
770 js['var newIsolate = new Function(str)'], 771 js('var newIsolate = new Function(str)'),
771 js['newIsolate.prototype = isolatePrototype'], 772 js('newIsolate.prototype = isolatePrototype'),
772 js['isolatePrototype.constructor = newIsolate'], 773 js('isolatePrototype.constructor = newIsolate'),
773 js['newIsolate.${namer.isolatePropertiesName} = isolateProperties'], 774 js('newIsolate.${namer.isolatePropertiesName} = isolateProperties'),
774 ]..addAll(copyFinishClasses) 775 ]..addAll(copyFinishClasses)
775 ..addAll([ 776 ..addAll([
776 777
777 // return newIsolate; 778 // return newIsolate;
778 js.return_('newIsolate') 779 jsBuilder.return_('newIsolate')
779 ])); 780 ]));
780 } 781 }
781 782
782 jsAst.Fun get lazyInitializerFunction { 783 jsAst.Fun get lazyInitializerFunction {
783 String isolate = namer.CURRENT_ISOLATE; 784 String isolate = namer.CURRENT_ISOLATE;
784 785
785 // function(prototype, staticName, fieldName, getterName, lazyValue) { 786 // function(prototype, staticName, fieldName, getterName, lazyValue) {
786 var parameters = <String>['prototype', 'staticName', 'fieldName', 787 var parameters = <String>['prototype', 'staticName', 'fieldName',
787 'getterName', 'lazyValue']; 788 'getterName', 'lazyValue'];
788 return js.fun(parameters, [ 789 return jsBuilder.fun(parameters, [
789 js['var getter = new Function("{ return $isolate." + fieldName + ";}")'], 790 js('var getter = new Function("{ return $isolate." + fieldName + ";}")'),
790 ]..addAll(addLazyInitializerLogic()) 791 ]..addAll(addLazyInitializerLogic())
791 ); 792 );
792 } 793 }
793 794
794 List addLazyInitializerLogic() { 795 List addLazyInitializerLogic() {
795 String isolate = namer.CURRENT_ISOLATE; 796 String isolate = namer.CURRENT_ISOLATE;
796 String cyclicThrow = namer.isolateAccess(backend.getCyclicThrowHelper()); 797 String cyclicThrow = namer.isolateAccess(backend.getCyclicThrowHelper());
797 798
798 return [ 799 return [
799 js['var sentinelUndefined = {}'], 800 js('var sentinelUndefined = {}'),
800 js['var sentinelInProgress = {}'], 801 js('var sentinelInProgress = {}'),
801 js['prototype[fieldName] = sentinelUndefined'], 802 js('prototype[fieldName] = sentinelUndefined'),
802 803
803 // prototype[getterName] = function() { 804 // prototype[getterName] = function() {
804 js['prototype'][js['getterName']].assign(js.fun([], [ 805 js('prototype')[js('getterName')].assign(jsBuilder.fun([], [
805 js['var result = $isolate[fieldName]'], 806 js('var result = $isolate[fieldName]'),
806 807
807 // try { 808 // try {
808 js.try_([ 809 jsBuilder.try_([
809 js.if_('result === sentinelUndefined', [ 810 jsBuilder.if_('result === sentinelUndefined', [
810 js['$isolate[fieldName] = sentinelInProgress'], 811 js('$isolate[fieldName] = sentinelInProgress'),
811 812
812 // try { 813 // try {
813 js.try_([ 814 jsBuilder.try_([
814 js['result = $isolate[fieldName] = lazyValue()'], 815 js('result = $isolate[fieldName] = lazyValue()'),
815 816
816 ], finallyPart: [ 817 ], finallyPart: [
817 // Use try-finally, not try-catch/throw as it destroys the 818 // Use try-finally, not try-catch/throw as it destroys the
818 // stack trace. 819 // stack trace.
819 820
820 // if (result === sentinelUndefined) { 821 // if (result === sentinelUndefined) {
821 js.if_('result === sentinelUndefined', [ 822 jsBuilder.if_('result === sentinelUndefined', [
822 // if ($isolate[fieldName] === sentinelInProgress) { 823 // if ($isolate[fieldName] === sentinelInProgress) {
823 js.if_('$isolate[fieldName] === sentinelInProgress', [ 824 jsBuilder.if_('$isolate[fieldName] === sentinelInProgress', [
824 js['$isolate[fieldName] = null'], 825 js('$isolate[fieldName] = null'),
825 ]) 826 ])
826 ]) 827 ])
827 ]) 828 ])
828 ], /* else */ [ 829 ], /* else */ [
829 js.if_('result === sentinelInProgress', 830 jsBuilder.if_('result === sentinelInProgress',
830 js['$cyclicThrow(staticName)'] 831 js('$cyclicThrow(staticName)')
831 ) 832 )
832 ]), 833 ]),
833 834
834 // return result; 835 // return result;
835 js.return_('result') 836 jsBuilder.return_('result')
836 837
837 ], finallyPart: [ 838 ], finallyPart: [
838 js['$isolate[getterName] = getter'] 839 js('$isolate[getterName] = getter')
839 ]) 840 ])
840 ])) 841 ]))
841 ]; 842 ];
842 } 843 }
843 844
844 List buildDefineClassAndFinishClassFunctionsIfNecessary() { 845 List buildDefineClassAndFinishClassFunctionsIfNecessary() {
845 if (!needsDefineClass) return []; 846 if (!needsDefineClass) return [];
846 return defineClassFunction 847 return defineClassFunction
847 ..addAll(buildProtoSupportCheck()) 848 ..addAll(buildProtoSupportCheck())
848 ..addAll([ 849 ..addAll([
849 js[finishClassesName].assign(finishClassesFunction) 850 js(finishClassesName).assign(finishClassesFunction)
850 ]); 851 ]);
851 } 852 }
852 853
853 List buildLazyInitializerFunctionIfNecessary() { 854 List buildLazyInitializerFunctionIfNecessary() {
854 if (!needsLazyInitializer) return []; 855 if (!needsLazyInitializer) return [];
855 856
856 // $lazyInitializerName = $lazyInitializerFunction 857 // $lazyInitializerName = $lazyInitializerFunction
857 return [js[lazyInitializerName].assign(lazyInitializerFunction)]; 858 return [js(lazyInitializerName).assign(lazyInitializerFunction)];
858 } 859 }
859 860
860 List buildFinishIsolateConstructor() { 861 List buildFinishIsolateConstructor() {
861 return [ 862 return [
862 // $finishIsolateConstructorName = $finishIsolateConstructorFunction 863 // $finishIsolateConstructorName = $finishIsolateConstructorFunction
863 js[finishIsolateConstructorName].assign(finishIsolateConstructorFunction) 864 js(finishIsolateConstructorName).assign(finishIsolateConstructorFunction)
864 ]; 865 ];
865 } 866 }
866 867
867 void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) { 868 void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) {
868 String isolate = namer.isolateName; 869 String isolate = namer.isolateName;
869 buffer.write("$isolate = $finishIsolateConstructorName($isolate)$N"); 870 buffer.write("$isolate = $finishIsolateConstructorName($isolate)$N");
870 } 871 }
871 872
872 /** 873 /**
873 * Generate stubs to handle invocation of methods with optional 874 * Generate stubs to handle invocation of methods with optional
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
915 new List<jsAst.Parameter>(selector.argumentCount + extraArgumentCount); 916 new List<jsAst.Parameter>(selector.argumentCount + extraArgumentCount);
916 // The arguments that will be passed to the real method. 917 // The arguments that will be passed to the real method.
917 List<jsAst.Expression> argumentsBuffer = 918 List<jsAst.Expression> argumentsBuffer =
918 new List<jsAst.Expression>( 919 new List<jsAst.Expression>(
919 parameters.parameterCount + extraArgumentCount); 920 parameters.parameterCount + extraArgumentCount);
920 921
921 int count = 0; 922 int count = 0;
922 if (isInterceptedMethod) { 923 if (isInterceptedMethod) {
923 count++; 924 count++;
924 parametersBuffer[0] = new jsAst.Parameter(receiverArgumentName); 925 parametersBuffer[0] = new jsAst.Parameter(receiverArgumentName);
925 argumentsBuffer[0] = js[receiverArgumentName]; 926 argumentsBuffer[0] = js(receiverArgumentName);
926 } 927 }
927 928
928 int optionalParameterStart = positionalArgumentCount + extraArgumentCount; 929 int optionalParameterStart = positionalArgumentCount + extraArgumentCount;
929 // Includes extra receiver argument when using interceptor convention 930 // Includes extra receiver argument when using interceptor convention
930 int indexOfLastOptionalArgumentInParameters = optionalParameterStart - 1; 931 int indexOfLastOptionalArgumentInParameters = optionalParameterStart - 1;
931 932
932 TreeElements elements = 933 TreeElements elements =
933 compiler.enqueuer.resolution.getCachedElements(member); 934 compiler.enqueuer.resolution.getCachedElements(member);
934 935
935 parameters.orderedForEachParameter((Element element) { 936 parameters.orderedForEachParameter((Element element) {
936 String jsName = backend.namer.safeName(element.name.slowToString()); 937 String jsName = backend.namer.safeName(element.name.slowToString());
937 assert(jsName != receiverArgumentName); 938 assert(jsName != receiverArgumentName);
938 if (count < optionalParameterStart) { 939 if (count < optionalParameterStart) {
939 parametersBuffer[count] = new jsAst.Parameter(jsName); 940 parametersBuffer[count] = new jsAst.Parameter(jsName);
940 argumentsBuffer[count] = js[jsName]; 941 argumentsBuffer[count] = js(jsName);
941 } else { 942 } else {
942 int index = names.indexOf(element.name); 943 int index = names.indexOf(element.name);
943 if (index != -1) { 944 if (index != -1) {
944 indexOfLastOptionalArgumentInParameters = count; 945 indexOfLastOptionalArgumentInParameters = count;
945 // The order of the named arguments is not the same as the 946 // The order of the named arguments is not the same as the
946 // one in the real method (which is in Dart source order). 947 // one in the real method (which is in Dart source order).
947 argumentsBuffer[count] = js[jsName]; 948 argumentsBuffer[count] = js(jsName);
948 parametersBuffer[optionalParameterStart + index] = 949 parametersBuffer[optionalParameterStart + index] =
949 new jsAst.Parameter(jsName); 950 new jsAst.Parameter(jsName);
950 // Note that [elements] may be null for a synthesized [member]. 951 // Note that [elements] may be null for a synthesized [member].
951 } else if (elements != null && elements.isParameterChecked(element)) { 952 } else if (elements != null && elements.isParameterChecked(element)) {
952 argumentsBuffer[count] = constantReference(SentinelConstant.SENTINEL); 953 argumentsBuffer[count] = constantReference(SentinelConstant.SENTINEL);
953 } else { 954 } else {
954 Constant value = handler.initialVariableValues[element]; 955 Constant value = handler.initialVariableValues[element];
955 if (value == null) { 956 if (value == null) {
956 argumentsBuffer[count] = constantReference(new NullConstant()); 957 argumentsBuffer[count] = constantReference(new NullConstant());
957 } else { 958 } else {
958 if (!value.isNull()) { 959 if (!value.isNull()) {
959 // If the value is the null constant, we should not pass it 960 // If the value is the null constant, we should not pass it
960 // down to the native method. 961 // down to the native method.
961 indexOfLastOptionalArgumentInParameters = count; 962 indexOfLastOptionalArgumentInParameters = count;
962 } 963 }
963 argumentsBuffer[count] = constantReference(value); 964 argumentsBuffer[count] = constantReference(value);
964 } 965 }
965 } 966 }
966 } 967 }
967 count++; 968 count++;
968 }); 969 });
969 970
970 List body; 971 List body;
971 if (member.hasFixedBackendName()) { 972 if (member.hasFixedBackendName()) {
972 body = nativeEmitter.generateParameterStubStatements( 973 body = nativeEmitter.generateParameterStubStatements(
973 member, isInterceptedMethod, invocationName, 974 member, isInterceptedMethod, invocationName,
974 parametersBuffer, argumentsBuffer, 975 parametersBuffer, argumentsBuffer,
975 indexOfLastOptionalArgumentInParameters); 976 indexOfLastOptionalArgumentInParameters);
976 } else { 977 } else {
977 body = [js.return_(js['this'][namer.getName(member)](argumentsBuffer))]; 978 String name = namer.getName(member);
979 body = [jsBuilder.return_(js('this')[name](argumentsBuffer))];
978 } 980 }
979 981
980 jsAst.Fun function = js.fun(parametersBuffer, body); 982 jsAst.Fun function = jsBuilder.fun(parametersBuffer, body);
981 983
982 defineStub(invocationName, function); 984 defineStub(invocationName, function);
983 } 985 }
984 986
985 void addParameterStubs(FunctionElement member, 987 void addParameterStubs(FunctionElement member,
986 DefineStubFunction defineStub) { 988 DefineStubFunction defineStub) {
987 // We fill the lists depending on the selector. For example, 989 // We fill the lists depending on the selector. For example,
988 // take method foo: 990 // take method foo:
989 // foo(a, b, {c, d}); 991 // foo(a, b, {c, d});
990 // 992 //
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
1190 includeBackendMembers: true, 1192 includeBackendMembers: true,
1191 includeSuperMembers: false); 1193 includeSuperMembers: false);
1192 1194
1193 void generateIsTest(Element other) { 1195 void generateIsTest(Element other) {
1194 jsAst.Expression code; 1196 jsAst.Expression code;
1195 if (other == compiler.objectClass && other != classElement) { 1197 if (other == compiler.objectClass && other != classElement) {
1196 // Avoid emitting [:$isObject:] on all classes but [Object]. 1198 // Avoid emitting [:$isObject:] on all classes but [Object].
1197 return; 1199 return;
1198 } 1200 }
1199 if (nativeEmitter.requiresNativeIsCheck(other)) { 1201 if (nativeEmitter.requiresNativeIsCheck(other)) {
1200 code = js.fun([], [js.return_(true)]); 1202 code = jsBuilder.fun([], [jsBuilder.return_(true)]);
1201 } else { 1203 } else {
1202 code = new jsAst.LiteralBool(true); 1204 code = new jsAst.LiteralBool(true);
1203 } 1205 }
1204 builder.addProperty(namer.operatorIs(other), code); 1206 builder.addProperty(namer.operatorIs(other), code);
1205 } 1207 }
1206 1208
1207 void generateSubstitution(Element other, {bool emitNull: false}) { 1209 void generateSubstitution(Element other, {bool emitNull: false}) {
1208 RuntimeTypes rti = backend.rti; 1210 RuntimeTypes rti = backend.rti;
1209 // TODO(karlklose): support typedefs with variables. 1211 // TODO(karlklose): support typedefs with variables.
1210 jsAst.Expression expression; 1212 jsAst.Expression expression;
1211 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other); 1213 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other);
1212 if (other.kind == ElementKind.CLASS) { 1214 if (other.kind == ElementKind.CLASS) {
1213 String substitution = rti.getSupertypeSubstitution(classElement, other, 1215 String substitution = rti.getSupertypeSubstitution(classElement, other,
1214 alwaysGenerateFunction: true); 1216 alwaysGenerateFunction: true);
1215 if (substitution != null) { 1217 if (substitution != null) {
1216 expression = new jsAst.LiteralExpression(substitution); 1218 expression = new jsAst.LiteralExpression(substitution);
1217 } else if (emitNull || needsNativeCheck) { 1219 } else if (emitNull || needsNativeCheck) {
1218 expression = new jsAst.LiteralNull(); 1220 expression = new jsAst.LiteralNull();
1219 } 1221 }
1220 } 1222 }
1221 if (expression != null) { 1223 if (expression != null) {
1222 if (needsNativeCheck) { 1224 if (needsNativeCheck) {
1223 expression = js.fun([], js.return_(expression)); 1225 expression = jsBuilder.fun([], jsBuilder.return_(expression));
1224 } 1226 }
1225 builder.addProperty(namer.substitutionName(other), expression); 1227 builder.addProperty(namer.substitutionName(other), expression);
1226 } 1228 }
1227 } 1229 }
1228 1230
1229 generateIsTestsOn(classElement, generateIsTest, generateSubstitution); 1231 generateIsTestsOn(classElement, generateIsTest, generateSubstitution);
1230 1232
1231 if (identical(classElement, compiler.objectClass) 1233 if (identical(classElement, compiler.objectClass)
1232 && compiler.enabledNoSuchMethod) { 1234 && compiler.enabledNoSuchMethod) {
1233 // Emit the noSuchMethod handlers on the Object prototype now, 1235 // Emit the noSuchMethod handlers on the Object prototype now,
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
1282 } 1284 }
1283 1285
1284 // Add checks to the constructors of instantiated classes or to the created 1286 // Add checks to the constructors of instantiated classes or to the created
1285 // holder object. 1287 // holder object.
1286 for (ClassElement cls in typeChecks) { 1288 for (ClassElement cls in typeChecks) {
1287 String holder = namer.isolateAccess(cls); 1289 String holder = namer.isolateAccess(cls);
1288 for (ClassElement check in typeChecks[cls]) { 1290 for (ClassElement check in typeChecks[cls]) {
1289 buffer.write('$holder.${namer.operatorIs(check)}$_=${_}true$N'); 1291 buffer.write('$holder.${namer.operatorIs(check)}$_=${_}true$N');
1290 String body = rti.getSupertypeSubstitution(cls, check); 1292 String body = rti.getSupertypeSubstitution(cls, check);
1291 if (body != null) { 1293 if (body != null) {
1292 buffer.write('$holder.${namer.substitutionName(check)}$_=${_}$body$N') ; 1294 buffer.write(
1295 '$holder.${namer.substitutionName(check)}$_=${_}$body$N');
1293 } 1296 }
1294 }; 1297 };
1295 } 1298 }
1296 } 1299 }
1297 1300
1298 void visitNativeMixins(ClassElement classElement, 1301 void visitNativeMixins(ClassElement classElement,
1299 void visit(MixinApplicationElement mixinApplication)) { 1302 void visit(MixinApplicationElement mixinApplication)) {
1300 if (!classElement.isNative()) return; 1303 if (!classElement.isNative()) return;
1301 // Use recursion to make sure to visit the superclasses before the 1304 // Use recursion to make sure to visit the superclasses before the
1302 // subclasses. Once we start keeping track of the emitted fields 1305 // subclasses. Once we start keeping track of the emitted fields
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
1409 1412
1410 void generateGetter(Element member, String fieldName, String accessorName, 1413 void generateGetter(Element member, String fieldName, String accessorName,
1411 ClassBuilder builder) { 1414 ClassBuilder builder) {
1412 String getterName = namer.getterNameFromAccessorName(accessorName); 1415 String getterName = namer.getterNameFromAccessorName(accessorName);
1413 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) 1416 String receiver = backend.isInterceptorClass(member.getEnclosingClass())
1414 ? 'receiver' : 'this'; 1417 ? 'receiver' : 'this';
1415 List<String> args = backend.isInterceptedMethod(member) 1418 List<String> args = backend.isInterceptedMethod(member)
1416 ? ['receiver'] 1419 ? ['receiver']
1417 : []; 1420 : [];
1418 builder.addProperty(getterName, 1421 builder.addProperty(getterName,
1419 js.fun(args, js.return_(js['$receiver.$fieldName']))); 1422 jsBuilder.fun(args, jsBuilder.return_(js('$receiver.$fieldName'))));
1420 } 1423 }
1421 1424
1422 void generateSetter(Element member, String fieldName, String accessorName, 1425 void generateSetter(Element member, String fieldName, String accessorName,
1423 ClassBuilder builder) { 1426 ClassBuilder builder) {
1424 String setterName = namer.setterNameFromAccessorName(accessorName); 1427 String setterName = namer.setterNameFromAccessorName(accessorName);
1425 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) 1428 String receiver = backend.isInterceptorClass(member.getEnclosingClass())
1426 ? 'receiver' : 'this'; 1429 ? 'receiver' : 'this';
1427 List<String> args = backend.isInterceptedMethod(member) 1430 List<String> args = backend.isInterceptedMethod(member)
1428 ? ['receiver', 'v'] 1431 ? ['receiver', 'v']
1429 : ['v']; 1432 : ['v'];
1430 builder.addProperty(setterName, 1433 builder.addProperty(setterName,
1431 js.fun(args, js[receiver][fieldName].assign('v'))); 1434 jsBuilder.fun(args, js(receiver)[fieldName].assign('v')));
1432 } 1435 }
1433 1436
1434 bool canGenerateCheckedSetter(Element member) { 1437 bool canGenerateCheckedSetter(Element member) {
1435 DartType type = member.computeType(compiler); 1438 DartType type = member.computeType(compiler);
1436 if (type.element.isTypeVariable() 1439 if (type.element.isTypeVariable()
1437 || type.element == compiler.dynamicClass 1440 || type.element == compiler.dynamicClass
1438 || type.element == compiler.objectClass) { 1441 || type.element == compiler.objectClass) {
1439 // TODO(ngeoffray): Support type checks on type parameters. 1442 // TODO(ngeoffray): Support type checks on type parameters.
1440 return false; 1443 return false;
1441 } 1444 }
1442 return true; 1445 return true;
1443 } 1446 }
1444 1447
1445 void generateCheckedSetter(Element member, 1448 void generateCheckedSetter(Element member,
1446 String fieldName, 1449 String fieldName,
1447 String accessorName, 1450 String accessorName,
1448 ClassBuilder builder) { 1451 ClassBuilder builder) {
1449 assert(canGenerateCheckedSetter(member)); 1452 assert(canGenerateCheckedSetter(member));
1450 DartType type = member.computeType(compiler); 1453 DartType type = member.computeType(compiler);
1451 // TODO(ahe): Generate a dynamic type error here. 1454 // TODO(ahe): Generate a dynamic type error here.
1452 if (type.element.isErroneous()) return; 1455 if (type.element.isErroneous()) return;
1453 FunctionElement helperElement 1456 FunctionElement helperElement
1454 = backend.getCheckedModeHelper(type, typeCast: false); 1457 = backend.getCheckedModeHelper(type, typeCast: false);
1455 String helperName = namer.isolateAccess(helperElement); 1458 String helperName = namer.isolateAccess(helperElement);
1456 List<jsAst.Expression> arguments = <jsAst.Expression>[js['v']]; 1459 List<jsAst.Expression> arguments = <jsAst.Expression>[js('v')];
1457 if (helperElement.computeSignature(compiler).parameterCount != 1) { 1460 if (helperElement.computeSignature(compiler).parameterCount != 1) {
1458 arguments.add(js.string(namer.operatorIs(type.element))); 1461 arguments.add(jsBuilder.string(namer.operatorIs(type.element)));
1459 } 1462 }
1460 1463
1461 String setterName = namer.setterNameFromAccessorName(accessorName); 1464 String setterName = namer.setterNameFromAccessorName(accessorName);
1462 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) 1465 String receiver = backend.isInterceptorClass(member.getEnclosingClass())
1463 ? 'receiver' : 'this'; 1466 ? 'receiver' : 'this';
1464 List<String> args = backend.isInterceptedMethod(member) 1467 List<String> args = backend.isInterceptedMethod(member)
1465 ? ['receiver', 'v'] 1468 ? ['receiver', 'v']
1466 : ['v']; 1469 : ['v'];
1467 builder.addProperty(setterName, 1470 builder.addProperty(setterName,
1468 js.fun(args, 1471 jsBuilder.fun(
1469 js[receiver][fieldName].assign(js[helperName](arguments)))); 1472 args, js(receiver)[fieldName].assign(js(helperName)(arguments))));
1470 } 1473 }
1471 1474
1472 void emitClassConstructor(ClassElement classElement, ClassBuilder builder) { 1475 void emitClassConstructor(ClassElement classElement, ClassBuilder builder) {
1473 /* Do nothing. */ 1476 /* Do nothing. */
1474 } 1477 }
1475 1478
1476 void emitSuper(String superName, ClassBuilder builder) { 1479 void emitSuper(String superName, ClassBuilder builder) {
1477 /* Do nothing. */ 1480 /* Do nothing. */
1478 } 1481 }
1479 1482
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
1540 assert(setterCode != 0); 1543 assert(setterCode != 0);
1541 } 1544 }
1542 int code = getterCode + (setterCode << 2); 1545 int code = getterCode + (setterCode << 2);
1543 buffer.write(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]); 1546 buffer.write(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]);
1544 } 1547 }
1545 } 1548 }
1546 }); 1549 });
1547 1550
1548 bool fieldsAdded = buffer.length > bufferClassLength; 1551 bool fieldsAdded = buffer.length > bufferClassLength;
1549 String compactClassData = buffer.toString(); 1552 String compactClassData = buffer.toString();
1550 builder.addProperty('', js.string(compactClassData)); 1553 builder.addProperty('', jsBuilder.string(compactClassData));
1551 return fieldsAdded; 1554 return fieldsAdded;
1552 } 1555 }
1553 1556
1554 void emitClassGettersSetters(ClassElement classElement, 1557 void emitClassGettersSetters(ClassElement classElement,
1555 ClassBuilder builder) { 1558 ClassBuilder builder) {
1556 1559
1557 visitClassFields(classElement, (Element member, 1560 visitClassFields(classElement, (Element member,
1558 String name, 1561 String name,
1559 String accessorName, 1562 String accessorName,
1560 bool needsGetter, 1563 bool needsGetter,
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1603 ClassBuilder builder = new ClassBuilder(); 1606 ClassBuilder builder = new ClassBuilder();
1604 1607
1605 emitClassConstructor(classElement, builder); 1608 emitClassConstructor(classElement, builder);
1606 emitSuper(superName, builder); 1609 emitSuper(superName, builder);
1607 emitClassFields(classElement, builder, 1610 emitClassFields(classElement, builder,
1608 superClass: superName, classIsNative: false); 1611 superClass: superName, classIsNative: false);
1609 emitClassGettersSetters(classElement, builder); 1612 emitClassGettersSetters(classElement, builder);
1610 emitInstanceMembers(classElement, builder); 1613 emitInstanceMembers(classElement, builder);
1611 1614
1612 jsAst.Expression init = 1615 jsAst.Expression init =
1613 js[classesCollector][className].assign(builder.toObjectInitializer()); 1616 js(classesCollector)[className].assign(builder.toObjectInitializer());
1614 buffer.write(jsAst.prettyPrint(init, compiler)); 1617 buffer.write(jsAst.prettyPrint(init, compiler));
1615 buffer.write('$N$n'); 1618 buffer.write('$N$n');
1616 } 1619 }
1617 1620
1618 bool get getterAndSetterCanBeImplementedByFieldSpec => true; 1621 bool get getterAndSetterCanBeImplementedByFieldSpec => true;
1619 1622
1620 /// If this is true then we can generate the noSuchMethod handlers at startup 1623 /// If this is true then we can generate the noSuchMethod handlers at startup
1621 /// time, instead of them being emitted as part of the Object class. 1624 /// time, instead of them being emitted as part of the Object class.
1622 bool get generateTrivialNsmHandlers => true; 1625 bool get generateTrivialNsmHandlers => true;
1623 1626
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
1826 1829
1827 // Reset the map. 1830 // Reset the map.
1828 buffer.write("$classesCollector$_=${_}null$N$n"); 1831 buffer.write("$classesCollector$_=${_}null$N$n");
1829 } 1832 }
1830 } 1833 }
1831 1834
1832 void emitStaticFunction(CodeBuffer buffer, 1835 void emitStaticFunction(CodeBuffer buffer,
1833 String name, 1836 String name,
1834 jsAst.Expression functionExpression) { 1837 jsAst.Expression functionExpression) {
1835 jsAst.Expression assignment = 1838 jsAst.Expression assignment =
1836 js[isolateProperties][name].assign(functionExpression); 1839 js(isolateProperties)[name].assign(functionExpression);
1837 buffer.write(jsAst.prettyPrint(assignment, compiler)); 1840 buffer.write(jsAst.prettyPrint(assignment, compiler));
1838 buffer.write('$N$n'); 1841 buffer.write('$N$n');
1839 } 1842 }
1840 1843
1841 void emitStaticFunctions(CodeBuffer eagerBuffer) { 1844 void emitStaticFunctions(CodeBuffer eagerBuffer) {
1842 bool isStaticFunction(Element element) => 1845 bool isStaticFunction(Element element) =>
1843 !element.isInstanceMember() && !element.isField(); 1846 !element.isInstanceMember() && !element.isField();
1844 1847
1845 Iterable<Element> elements = 1848 Iterable<Element> elements =
1846 backend.generatedCode.keys.where(isStaticFunction); 1849 backend.generatedCode.keys.where(isStaticFunction);
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1883 FunctionElement callElement = 1886 FunctionElement callElement =
1884 new ClosureInvocationElement(namer.closureInvocationSelectorName, 1887 new ClosureInvocationElement(namer.closureInvocationSelectorName,
1885 element); 1888 element);
1886 String staticName = namer.getName(element); 1889 String staticName = namer.getName(element);
1887 String invocationName = namer.instanceMethodName(callElement); 1890 String invocationName = namer.instanceMethodName(callElement);
1888 String fieldAccess = '$isolateProperties.$staticName'; 1891 String fieldAccess = '$isolateProperties.$staticName';
1889 buffer.write("$fieldAccess.$invocationName$_=$_$fieldAccess$N"); 1892 buffer.write("$fieldAccess.$invocationName$_=$_$fieldAccess$N");
1890 1893
1891 addParameterStubs(callElement, (String name, jsAst.Expression value) { 1894 addParameterStubs(callElement, (String name, jsAst.Expression value) {
1892 jsAst.Expression assignment = 1895 jsAst.Expression assignment =
1893 js[isolateProperties][staticName][name].assign(value); 1896 js(isolateProperties)[staticName][name].assign(value);
1894 buffer.write(jsAst.prettyPrint(assignment.toStatement(), compiler)); 1897 buffer.write(jsAst.prettyPrint(assignment.toStatement(), compiler));
1895 buffer.write('$N'); 1898 buffer.write('$N');
1896 }); 1899 });
1897 1900
1898 // If a static function is used as a closure we need to add its name 1901 // If a static function is used as a closure we need to add its name
1899 // in case it is used in spawnFunction. 1902 // in case it is used in spawnFunction.
1900 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; 1903 String fieldName = namer.STATIC_CLOSURE_NAME_NAME;
1901 buffer.write('$fieldAccess.$fieldName$_=$_"$staticName"$N'); 1904 buffer.write('$fieldAccess.$fieldName$_=$_"$staticName"$N');
1902 getTypedefChecksOn(element.computeType(compiler)).forEach( 1905 getTypedefChecksOn(element.computeType(compiler)).forEach(
1903 (Element typedef) { 1906 (Element typedef) {
1904 String operator = namer.operatorIs(typedef); 1907 String operator = namer.operatorIs(typedef);
1905 buffer.write('$fieldAccess.$operator$_=${_}true$N'); 1908 buffer.write('$fieldAccess.$operator$_=${_}true$N');
1906 } 1909 }
1907 ); 1910 );
1908 } 1911 }
1909 } 1912 }
1910 1913
1911 void emitBoundClosureClassHeader(String mangledName, 1914 void emitBoundClosureClassHeader(String mangledName,
1912 String superName, 1915 String superName,
1913 List<String> fieldNames, 1916 List<String> fieldNames,
1914 ClassBuilder builder) { 1917 ClassBuilder builder) {
1915 builder.addProperty('', 1918 builder.addProperty('',
1916 js.string("$superName;${fieldNames.join(',')}")); 1919 jsBuilder.string("$superName;${fieldNames.join(',')}"));
1917 } 1920 }
1918 1921
1919 /** 1922 /**
1920 * Documentation wanted -- johnniwinther 1923 * Documentation wanted -- johnniwinther
1921 * 1924 *
1922 * Invariant: [member] must be a declaration element. 1925 * Invariant: [member] must be a declaration element.
1923 */ 1926 */
1924 void emitDynamicFunctionGetter(FunctionElement member, 1927 void emitDynamicFunctionGetter(FunctionElement member,
1925 DefineStubFunction defineStub) { 1928 DefineStubFunction defineStub) {
1926 assert(invariant(member, member.isDeclaration)); 1929 assert(invariant(member, member.isDeclaration));
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
2005 // Note: the callElement will not have any enclosingElement. 2008 // Note: the callElement will not have any enclosingElement.
2006 FunctionElement callElement = 2009 FunctionElement callElement =
2007 new ClosureInvocationElement(namer.closureInvocationSelectorName, 2010 new ClosureInvocationElement(namer.closureInvocationSelectorName,
2008 member); 2011 member);
2009 2012
2010 String invocationName = namer.instanceMethodName(callElement); 2013 String invocationName = namer.instanceMethodName(callElement);
2011 2014
2012 List<String> parameters = <String>[]; 2015 List<String> parameters = <String>[];
2013 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 2016 List<jsAst.Expression> arguments = <jsAst.Expression>[];
2014 if (inInterceptor) { 2017 if (inInterceptor) {
2015 arguments.add(js['this'][fieldNames[2]]); 2018 arguments.add(js('this')[fieldNames[2]]);
2016 } 2019 }
2017 for (int i = 0; i < parameterCount; i++) { 2020 for (int i = 0; i < parameterCount; i++) {
2018 String name = 'p$i'; 2021 String name = 'p$i';
2019 parameters.add(name); 2022 parameters.add(name);
2020 arguments.add(js[name]); 2023 arguments.add(js(name));
2021 } 2024 }
2022 2025
2023 jsAst.Expression fun = js.fun( 2026 jsAst.Expression fun = jsBuilder.fun(
2024 parameters, 2027 parameters,
2025 js.return_( 2028 jsBuilder.return_(
2026 js['this'][fieldNames[0]][js['this'][fieldNames[1]]](arguments))); 2029 js('this')[fieldNames[0]][js('this')[fieldNames[1]]](arguments)));
2027 boundClosureBuilder.addProperty(invocationName, fun); 2030 boundClosureBuilder.addProperty(invocationName, fun);
2028 2031
2029 addParameterStubs(callElement, boundClosureBuilder.addProperty); 2032 addParameterStubs(callElement, boundClosureBuilder.addProperty);
2030 typedefChecks.forEach((Element typedef) { 2033 typedefChecks.forEach((Element typedef) {
2031 String operator = namer.operatorIs(typedef); 2034 String operator = namer.operatorIs(typedef);
2032 boundClosureBuilder.addProperty(operator, new jsAst.LiteralBool(true)); 2035 boundClosureBuilder.addProperty(operator, new jsAst.LiteralBool(true));
2033 }); 2036 });
2034 2037
2035 boundClosures.add( 2038 boundClosures.add(
2036 js[classesCollector][mangledName].assign( 2039 js(classesCollector)[mangledName].assign(
2037 boundClosureBuilder.toObjectInitializer())); 2040 boundClosureBuilder.toObjectInitializer()));
2038 2041
2039 closureClass = namer.isolateAccess(closureClassElement); 2042 closureClass = namer.isolateAccess(closureClassElement);
2040 2043
2041 // Cache it. 2044 // Cache it.
2042 if (canBeShared) { 2045 if (canBeShared) {
2043 cache[parameterCount] = closureClass; 2046 cache[parameterCount] = closureClass;
2044 } 2047 }
2045 } 2048 }
2046 2049
2047 // And finally the getter. 2050 // And finally the getter.
2048 String getterName = namer.getterName(member); 2051 String getterName = namer.getterName(member);
2049 String targetName = namer.instanceMethodName(member); 2052 String targetName = namer.instanceMethodName(member);
2050 2053
2051 List<String> parameters = <String>[]; 2054 List<String> parameters = <String>[];
2052 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 2055 List<jsAst.Expression> arguments = <jsAst.Expression>[];
2053 arguments.add(js['this']); 2056 arguments.add(js('this'));
2054 arguments.add(js.string(targetName)); 2057 arguments.add(jsBuilder.string(targetName));
2055 if (inInterceptor) { 2058 if (inInterceptor) {
2056 parameters.add(extraArg); 2059 parameters.add(extraArg);
2057 arguments.add(js[extraArg]); 2060 arguments.add(js(extraArg));
2058 } 2061 }
2059 2062
2060 jsAst.Expression getterFunction = js.fun( 2063 jsAst.Expression getterFunction = jsBuilder.fun(
2061 parameters, 2064 parameters,
2062 js.return_(js[closureClass].newWith(arguments))); 2065 jsBuilder.return_(js(closureClass).newWith(arguments)));
2063 2066
2064 defineStub(getterName, getterFunction); 2067 defineStub(getterName, getterFunction);
2065 } 2068 }
2066 2069
2067 /** 2070 /**
2068 * Documentation wanted -- johnniwinther 2071 * Documentation wanted -- johnniwinther
2069 * 2072 *
2070 * Invariant: [member] must be a declaration element. 2073 * Invariant: [member] must be a declaration element.
2071 */ 2074 */
2072 void emitCallStubForGetter(Element member, 2075 void emitCallStubForGetter(Element member,
2073 Set<Selector> selectors, 2076 Set<Selector> selectors,
2074 DefineStubFunction defineStub) { 2077 DefineStubFunction defineStub) {
2075 assert(invariant(member, member.isDeclaration)); 2078 assert(invariant(member, member.isDeclaration));
2076 LibraryElement memberLibrary = member.getLibrary(); 2079 LibraryElement memberLibrary = member.getLibrary();
2077 // If the method is intercepted, the stub gets the 2080 // If the method is intercepted, the stub gets the
2078 // receiver explicitely and we need to pass it to the getter call. 2081 // receiver explicitely and we need to pass it to the getter call.
2079 bool isInterceptedMethod = backend.isInterceptedMethod(member); 2082 bool isInterceptedMethod = backend.isInterceptedMethod(member);
2080 2083
2081 const String receiverArgumentName = r'$receiver'; 2084 const String receiverArgumentName = r'$receiver';
2082 2085
2083 jsAst.Expression buildGetter() { 2086 jsAst.Expression buildGetter() {
2084 if (member.isGetter()) { 2087 if (member.isGetter()) {
2085 String getterName = namer.getterName(member); 2088 String getterName = namer.getterName(member);
2086 return js['this'][getterName]( 2089 return js('this')[getterName](
2087 isInterceptedMethod 2090 isInterceptedMethod
2088 ? <jsAst.Expression>[js[receiverArgumentName]] 2091 ? <jsAst.Expression>[js(receiverArgumentName)]
2089 : <jsAst.Expression>[]); 2092 : <jsAst.Expression>[]);
2090 } else { 2093 } else {
2091 String fieldName = member.hasFixedBackendName() 2094 String fieldName = member.hasFixedBackendName()
2092 ? member.fixedBackendName() 2095 ? member.fixedBackendName()
2093 : namer.instanceFieldName(member); 2096 : namer.instanceFieldName(member);
2094 return js['this'][fieldName]; 2097 return js('this')[fieldName];
2095 } 2098 }
2096 } 2099 }
2097 2100
2098 // Two selectors may match but differ only in type. To avoid generating 2101 // Two selectors may match but differ only in type. To avoid generating
2099 // identical stubs for each we track untyped selectors which already have 2102 // identical stubs for each we track untyped selectors which already have
2100 // stubs. 2103 // stubs.
2101 Set<Selector> generatedSelectors = new Set<Selector>(); 2104 Set<Selector> generatedSelectors = new Set<Selector>();
2102 2105
2103 for (Selector selector in selectors) { 2106 for (Selector selector in selectors) {
2104 if (selector.applies(member, compiler)) { 2107 if (selector.applies(member, compiler)) {
2105 selector = selector.asUntyped; 2108 selector = selector.asUntyped;
2106 if (generatedSelectors.contains(selector)) continue; 2109 if (generatedSelectors.contains(selector)) continue;
2107 generatedSelectors.add(selector); 2110 generatedSelectors.add(selector);
2108 2111
2109 String invocationName = namer.invocationName(selector); 2112 String invocationName = namer.invocationName(selector);
2110 Selector callSelector = new Selector.callClosureFrom(selector); 2113 Selector callSelector = new Selector.callClosureFrom(selector);
2111 String closureCallName = namer.invocationName(callSelector); 2114 String closureCallName = namer.invocationName(callSelector);
2112 2115
2113 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; 2116 List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
2114 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 2117 List<jsAst.Expression> arguments = <jsAst.Expression>[];
2115 if (isInterceptedMethod) { 2118 if (isInterceptedMethod) {
2116 parameters.add(new jsAst.Parameter(receiverArgumentName)); 2119 parameters.add(new jsAst.Parameter(receiverArgumentName));
2117 } 2120 }
2118 2121
2119 for (int i = 0; i < selector.argumentCount; i++) { 2122 for (int i = 0; i < selector.argumentCount; i++) {
2120 String name = 'arg$i'; 2123 String name = 'arg$i';
2121 parameters.add(new jsAst.Parameter(name)); 2124 parameters.add(new jsAst.Parameter(name));
2122 arguments.add(js[name]); 2125 arguments.add(js(name));
2123 } 2126 }
2124 2127
2125 jsAst.Fun function = js.fun( 2128 jsAst.Fun function = jsBuilder.fun(
2126 parameters, 2129 parameters,
2127 js.return_(buildGetter()[closureCallName](arguments))); 2130 jsBuilder.return_(buildGetter()[closureCallName](arguments)));
2128 2131
2129 defineStub(invocationName, function); 2132 defineStub(invocationName, function);
2130 } 2133 }
2131 } 2134 }
2132 } 2135 }
2133 2136
2134 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) { 2137 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) {
2135 ConstantHandler handler = compiler.constantHandler; 2138 ConstantHandler handler = compiler.constantHandler;
2136 Iterable<VariableElement> staticNonFinalFields = 2139 Iterable<VariableElement> staticNonFinalFields =
2137 handler.getStaticNonFinalFieldsForEmission(); 2140 handler.getStaticNonFinalFieldsForEmission();
2138 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { 2141 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) {
2139 // [:interceptedNames:] is handled in [emitInterceptedNames]. 2142 // [:interceptedNames:] is handled in [emitInterceptedNames].
2140 if (element == backend.interceptedNames) continue; 2143 if (element == backend.interceptedNames) continue;
2141 compiler.withCurrentElement(element, () { 2144 compiler.withCurrentElement(element, () {
2142 Constant initialValue = handler.getInitialValueFor(element); 2145 Constant initialValue = handler.getInitialValueFor(element);
2143 jsAst.Expression init = 2146 jsAst.Expression init =
2144 js[isolateProperties][namer.getName(element)].assign( 2147 js(isolateProperties)[namer.getName(element)].assign(
2145 constantEmitter.referenceInInitializationContext(initialValue)); 2148 constantEmitter.referenceInInitializationContext(initialValue));
2146 buffer.write(jsAst.prettyPrint(init, compiler)); 2149 buffer.write(jsAst.prettyPrint(init, compiler));
2147 buffer.write('$N'); 2150 buffer.write('$N');
2148 }); 2151 });
2149 } 2152 }
2150 } 2153 }
2151 2154
2152 void emitLazilyInitializedStaticFields(CodeBuffer buffer) { 2155 void emitLazilyInitializedStaticFields(CodeBuffer buffer) {
2153 ConstantHandler handler = compiler.constantHandler; 2156 ConstantHandler handler = compiler.constantHandler;
2154 List<VariableElement> lazyFields = 2157 List<VariableElement> lazyFields =
2155 handler.getLazilyInitializedFieldsForEmission(); 2158 handler.getLazilyInitializedFieldsForEmission();
2156 if (!lazyFields.isEmpty) { 2159 if (!lazyFields.isEmpty) {
2157 needsLazyInitializer = true; 2160 needsLazyInitializer = true;
2158 for (VariableElement element in Elements.sortedByPosition(lazyFields)) { 2161 for (VariableElement element in Elements.sortedByPosition(lazyFields)) {
2159 assert(backend.generatedBailoutCode[element] == null); 2162 assert(backend.generatedBailoutCode[element] == null);
2160 jsAst.Expression code = backend.generatedCode[element]; 2163 jsAst.Expression code = backend.generatedCode[element];
2161 // The code is null if we ended up not needing the lazily 2164 // The code is null if we ended up not needing the lazily
2162 // initialized field after all because of constant folding 2165 // initialized field after all because of constant folding
2163 // before code generation. 2166 // before code generation.
2164 if (code == null) continue; 2167 if (code == null) continue;
2165 // The code only computes the initial value. We build the lazy-check 2168 // The code only computes the initial value. We build the lazy-check
2166 // here: 2169 // here:
2167 // lazyInitializer(prototype, 'name', fieldName, getterName, initial); 2170 // lazyInitializer(prototype, 'name', fieldName, getterName, initial);
2168 // The name is used for error reporting. The 'initial' must be a 2171 // The name is used for error reporting. The 'initial' must be a
2169 // closure that constructs the initial value. 2172 // closure that constructs the initial value.
2170 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 2173 List<jsAst.Expression> arguments = <jsAst.Expression>[];
2171 arguments.add(js[isolateProperties]); 2174 arguments.add(js(isolateProperties));
2172 arguments.add(js.string(element.name.slowToString())); 2175 arguments.add(jsBuilder.string(element.name.slowToString()));
2173 arguments.add(js.string(namer.getName(element))); 2176 arguments.add(jsBuilder.string(namer.getName(element)));
2174 arguments.add(js.string(namer.getLazyInitializerName(element))); 2177 arguments.add(jsBuilder.string(namer.getLazyInitializerName(element)));
2175 arguments.add(code); 2178 arguments.add(code);
2176 jsAst.Expression getter = buildLazyInitializedGetter(element); 2179 jsAst.Expression getter = buildLazyInitializedGetter(element);
2177 if (getter != null) { 2180 if (getter != null) {
2178 arguments.add(getter); 2181 arguments.add(getter);
2179 } 2182 }
2180 jsAst.Expression init = js[lazyInitializerName](arguments); 2183 jsAst.Expression init = js(lazyInitializerName)(arguments);
2181 buffer.write(jsAst.prettyPrint(init, compiler)); 2184 buffer.write(jsAst.prettyPrint(init, compiler));
2182 buffer.write("$N"); 2185 buffer.write("$N");
2183 } 2186 }
2184 } 2187 }
2185 } 2188 }
2186 2189
2187 jsAst.Expression buildLazyInitializedGetter(VariableElement element) { 2190 jsAst.Expression buildLazyInitializedGetter(VariableElement element) {
2188 // Nothing to do, the 'lazy' function will create the getter. 2191 // Nothing to do, the 'lazy' function will create the getter.
2189 return null; 2192 return null;
2190 } 2193 }
(...skipping 12 matching lines...) Expand all
2203 // The name is null when the constant is already a JS constant. 2206 // The name is null when the constant is already a JS constant.
2204 // TODO(floitsch): every constant should be registered, so that we can 2207 // TODO(floitsch): every constant should be registered, so that we can
2205 // share the ones that take up too much space (like some strings). 2208 // share the ones that take up too much space (like some strings).
2206 if (name == null) continue; 2209 if (name == null) continue;
2207 if (!addedMakeConstantList && constant.isList()) { 2210 if (!addedMakeConstantList && constant.isList()) {
2208 addedMakeConstantList = true; 2211 addedMakeConstantList = true;
2209 emitMakeConstantList(eagerBuffer); 2212 emitMakeConstantList(eagerBuffer);
2210 } 2213 }
2211 CodeBuffer buffer = 2214 CodeBuffer buffer =
2212 bufferForElement(constant.computeType(compiler).element, eagerBuffer); 2215 bufferForElement(constant.computeType(compiler).element, eagerBuffer);
2213 jsAst.Expression init = js[isolateProperties][name].assign( 2216 jsAst.Expression init = js(isolateProperties)[name].assign(
2214 constantInitializerExpression(constant)); 2217 constantInitializerExpression(constant));
2215 buffer.write(jsAst.prettyPrint(init, compiler)); 2218 buffer.write(jsAst.prettyPrint(init, compiler));
2216 buffer.write('$N'); 2219 buffer.write('$N');
2217 } 2220 }
2218 } 2221 }
2219 2222
2220 void emitMakeConstantList(CodeBuffer buffer) { 2223 void emitMakeConstantList(CodeBuffer buffer) {
2221 buffer.write(namer.isolateName); 2224 buffer.write(namer.isolateName);
2222 buffer.write(r'''.makeConstantList = function(list) { 2225 buffer.write(r'''.makeConstantList = function(list) {
2223 list.immutable$list = true; 2226 list.immutable$list = true;
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
2380 // Values match JSInvocationMirror in js-helper library. 2383 // Values match JSInvocationMirror in js-helper library.
2381 int type = selector.invocationMirrorKind; 2384 int type = selector.invocationMirrorKind;
2382 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; 2385 List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
2383 CodeBuffer args = new CodeBuffer(); 2386 CodeBuffer args = new CodeBuffer();
2384 for (int i = 0; i < selector.argumentCount; i++) { 2387 for (int i = 0; i < selector.argumentCount; i++) {
2385 parameters.add(new jsAst.Parameter('\$$i')); 2388 parameters.add(new jsAst.Parameter('\$$i'));
2386 } 2389 }
2387 2390
2388 List<jsAst.Expression> argNames = 2391 List<jsAst.Expression> argNames =
2389 selector.getOrderedNamedArguments().map((SourceString name) => 2392 selector.getOrderedNamedArguments().map((SourceString name) =>
2390 js.string(name.slowToString())).toList(); 2393 jsBuilder.string(name.slowToString())).toList();
2391 2394
2392 String methodName = selector.invocationMirrorMemberName; 2395 String methodName = selector.invocationMirrorMemberName;
2393 String internalName = namer.invocationMirrorInternalName(selector); 2396 String internalName = namer.invocationMirrorInternalName(selector);
2394 if (!haveVeryFewNoSuchMemberHandlers && 2397 if (!haveVeryFewNoSuchMemberHandlers &&
2395 isTrivialNsmHandler(type, argNames, selector, internalName)) { 2398 isTrivialNsmHandler(type, argNames, selector, internalName)) {
2396 trivialNsmHandlers.add(selector); 2399 trivialNsmHandlers.add(selector);
2397 return null; 2400 return null;
2398 } 2401 }
2399 2402
2400 String createInvocationMirror = namer.getName( 2403 String createInvocationMirror = namer.getName(
2401 compiler.createInvocationMirrorElement); 2404 compiler.createInvocationMirrorElement);
2402 2405
2403 assert(backend.isInterceptedName(Compiler.NO_SUCH_METHOD)); 2406 assert(backend.isInterceptedName(Compiler.NO_SUCH_METHOD));
2404 jsAst.Expression expression = js['this.$noSuchMethodName']( 2407 jsAst.Expression expression = js('this.$noSuchMethodName')(
2405 [js['this'], 2408 [js('this'),
2406 js[namer.CURRENT_ISOLATE][createInvocationMirror]([ 2409 js(namer.CURRENT_ISOLATE)[createInvocationMirror]([
2407 js.string(compiler.enableMinification ? 2410 jsBuilder.string(compiler.enableMinification ?
2408 internalName : methodName), 2411 internalName : methodName),
2409 js.string(internalName), 2412 jsBuilder.string(internalName),
2410 type, 2413 type,
2411 new jsAst.ArrayInitializer.from( 2414 new jsAst.ArrayInitializer.from(
2412 parameters.map((param) => js[param.name]).toList()), 2415 parameters.map((param) => js(param.name)).toList()),
2413 new jsAst.ArrayInitializer.from(argNames)])]); 2416 new jsAst.ArrayInitializer.from(argNames)])]);
2414 parameters = backend.isInterceptedName(selector.name) 2417 parameters = backend.isInterceptedName(selector.name)
2415 ? ([new jsAst.Parameter('\$receiver')]..addAll(parameters)) 2418 ? ([new jsAst.Parameter('\$receiver')]..addAll(parameters))
2416 : parameters; 2419 : parameters;
2417 return js.fun(parameters, js.return_(expression)); 2420 return jsBuilder.fun(parameters, jsBuilder.return_(expression));
2418 } 2421 }
2419 2422
2420 for (String jsName in addedJsNames.keys.toList()..sort()) { 2423 for (String jsName in addedJsNames.keys.toList()..sort()) {
2421 Selector selector = addedJsNames[jsName]; 2424 Selector selector = addedJsNames[jsName];
2422 jsAst.Expression method = generateMethod(jsName, selector); 2425 jsAst.Expression method = generateMethod(jsName, selector);
2423 if (method != null) defineStub(jsName, method); 2426 if (method != null) defineStub(jsName, method);
2424 } 2427 }
2425 } 2428 }
2426 2429
2427 String buildIsolateSetup(CodeBuffer buffer, 2430 String buildIsolateSetup(CodeBuffer buffer,
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
2470 } 2473 }
2471 } 2474 }
2472 """); 2475 """);
2473 addComment('END invoke [main].', buffer); 2476 addComment('END invoke [main].', buffer);
2474 } 2477 }
2475 2478
2476 void emitGetInterceptorMethod(CodeBuffer buffer, 2479 void emitGetInterceptorMethod(CodeBuffer buffer,
2477 String key, 2480 String key,
2478 Collection<ClassElement> classes) { 2481 Collection<ClassElement> classes) {
2479 jsAst.Statement buildReturnInterceptor(ClassElement cls) { 2482 jsAst.Statement buildReturnInterceptor(ClassElement cls) {
2480 return js.return_(js[namer.isolateAccess(cls)]['prototype']); 2483 return jsBuilder.return_(js(namer.isolateAccess(cls))['prototype']);
2481 } 2484 }
2482 2485
2483 /** 2486 /**
2484 * Build a JavaScrit AST node for doing a type check on 2487 * Build a JavaScrit AST node for doing a type check on
2485 * [cls]. [cls] must be an interceptor class. 2488 * [cls]. [cls] must be an interceptor class.
2486 */ 2489 */
2487 jsAst.Statement buildInterceptorCheck(ClassElement cls) { 2490 jsAst.Statement buildInterceptorCheck(ClassElement cls) {
2488 jsAst.Expression condition; 2491 jsAst.Expression condition;
2489 assert(backend.isInterceptorClass(cls)); 2492 assert(backend.isInterceptorClass(cls));
2490 if (cls == backend.jsBoolClass) { 2493 if (cls == backend.jsBoolClass) {
2491 condition = js['(typeof receiver) == "boolean"']; 2494 condition = js('(typeof receiver) == "boolean"');
2492 } else if (cls == backend.jsIntClass || 2495 } else if (cls == backend.jsIntClass ||
2493 cls == backend.jsDoubleClass || 2496 cls == backend.jsDoubleClass ||
2494 cls == backend.jsNumberClass) { 2497 cls == backend.jsNumberClass) {
2495 throw 'internal error'; 2498 throw 'internal error';
2496 } else if (cls == backend.jsArrayClass || 2499 } else if (cls == backend.jsArrayClass ||
2497 cls == backend.jsMutableArrayClass || 2500 cls == backend.jsMutableArrayClass ||
2498 cls == backend.jsFixedArrayClass || 2501 cls == backend.jsFixedArrayClass ||
2499 cls == backend.jsExtendableArrayClass) { 2502 cls == backend.jsExtendableArrayClass) {
2500 condition = js['receiver.constructor == Array']; 2503 condition = js('receiver.constructor == Array');
2501 } else if (cls == backend.jsStringClass) { 2504 } else if (cls == backend.jsStringClass) {
2502 condition = js['(typeof receiver) == "string"']; 2505 condition = js('(typeof receiver) == "string"');
2503 } else if (cls == backend.jsNullClass) { 2506 } else if (cls == backend.jsNullClass) {
2504 condition = js['receiver == null']; 2507 condition = js('receiver == null');
2505 } else if (cls == backend.jsFunctionClass) { 2508 } else if (cls == backend.jsFunctionClass) {
2506 condition = js['(typeof receiver) == "function"']; 2509 condition = js('(typeof receiver) == "function"');
2507 } else { 2510 } else {
2508 throw 'internal error'; 2511 throw 'internal error';
2509 } 2512 }
2510 return js.if_(condition, buildReturnInterceptor(cls)); 2513 return jsBuilder.if_(condition, buildReturnInterceptor(cls));
2511 } 2514 }
2512 2515
2513 bool hasArray = false; 2516 bool hasArray = false;
2514 bool hasBool = false; 2517 bool hasBool = false;
2515 bool hasDouble = false; 2518 bool hasDouble = false;
2516 bool hasFunction = false; 2519 bool hasFunction = false;
2517 bool hasInt = false; 2520 bool hasInt = false;
2518 bool hasNull = false; 2521 bool hasNull = false;
2519 bool hasNumber = false; 2522 bool hasNumber = false;
2520 bool hasString = false; 2523 bool hasString = false;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
2556 jsAst.Statement whenNumber; 2559 jsAst.Statement whenNumber;
2557 2560
2558 /// Note: there are two number classes in play: Dart's [num], 2561 /// Note: there are two number classes in play: Dart's [num],
2559 /// and JavaScript's Number (typeof receiver == 'number'). This 2562 /// and JavaScript's Number (typeof receiver == 'number'). This
2560 /// is the fallback used when we have determined that receiver 2563 /// is the fallback used when we have determined that receiver
2561 /// is a JavaScript Number. 2564 /// is a JavaScript Number.
2562 jsAst.Return returnNumberClass = buildReturnInterceptor( 2565 jsAst.Return returnNumberClass = buildReturnInterceptor(
2563 hasDouble ? backend.jsDoubleClass : backend.jsNumberClass); 2566 hasDouble ? backend.jsDoubleClass : backend.jsNumberClass);
2564 2567
2565 if (hasInt) { 2568 if (hasInt) {
2566 jsAst.Expression isInt = js['Math.floor(receiver) == receiver']; 2569 jsAst.Expression isInt = js('Math.floor(receiver) == receiver');
2567 whenNumber = js.block([ 2570 whenNumber = jsBuilder.block([
2568 js.if_(isInt, buildReturnInterceptor(backend.jsIntClass)), 2571 jsBuilder.if_(isInt, buildReturnInterceptor(backend.jsIntClass)),
2569 returnNumberClass]); 2572 returnNumberClass]);
2570 } else { 2573 } else {
2571 whenNumber = returnNumberClass; 2574 whenNumber = returnNumberClass;
2572 } 2575 }
2573 block.statements.add( 2576 block.statements.add(
2574 js.if_('(typeof receiver) == "number"', 2577 jsBuilder.if_('(typeof receiver) == "number"',
2575 whenNumber)); 2578 whenNumber));
2576 } 2579 }
2577 2580
2578 if (hasString) { 2581 if (hasString) {
2579 block.statements.add(buildInterceptorCheck(backend.jsStringClass)); 2582 block.statements.add(buildInterceptorCheck(backend.jsStringClass));
2580 } 2583 }
2581 if (hasNull) { 2584 if (hasNull) {
2582 block.statements.add(buildInterceptorCheck(backend.jsNullClass)); 2585 block.statements.add(buildInterceptorCheck(backend.jsNullClass));
2583 } else { 2586 } else {
2584 // Returning "undefined" or "null" here will provoke a JavaScript 2587 // Returning "undefined" or "null" here will provoke a JavaScript
2585 // TypeError which is later identified as a null-error by 2588 // TypeError which is later identified as a null-error by
2586 // [unwrapException] in js_helper.dart. 2589 // [unwrapException] in js_helper.dart.
2587 block.statements.add(js.if_('receiver == null', 2590 block.statements.add(jsBuilder.if_('receiver == null',
2588 js.return_(js['receiver']))); 2591 jsBuilder.return_(js('receiver'))));
2589 } 2592 }
2590 if (hasFunction) { 2593 if (hasFunction) {
2591 block.statements.add(buildInterceptorCheck(backend.jsFunctionClass)); 2594 block.statements.add(buildInterceptorCheck(backend.jsFunctionClass));
2592 } 2595 }
2593 if (hasBool) { 2596 if (hasBool) {
2594 block.statements.add(buildInterceptorCheck(backend.jsBoolClass)); 2597 block.statements.add(buildInterceptorCheck(backend.jsBoolClass));
2595 } 2598 }
2596 // TODO(ahe): It might be faster to check for Array before 2599 // TODO(ahe): It might be faster to check for Array before
2597 // function and bool. 2600 // function and bool.
2598 if (hasArray) { 2601 if (hasArray) {
2599 block.statements.add(buildInterceptorCheck(backend.jsArrayClass)); 2602 block.statements.add(buildInterceptorCheck(backend.jsArrayClass));
2600 } 2603 }
2601 2604
2602 if (hasNative) { 2605 if (hasNative) {
2603 block.statements.add( 2606 block.statements.add(
2604 js.if_( 2607 jsBuilder.if_(
2605 js['(typeof receiver) != "object"'], 2608 js('(typeof receiver) != "object"'),
2606 js.return_(js['receiver']))); 2609 jsBuilder.return_(js('receiver'))));
2607 2610
2608 // if (receiver instanceof $.Object) return receiver; 2611 // if (receiver instanceof $.Object) return receiver;
2609 // return $.getNativeInterceptor(receiver); 2612 // return $.getNativeInterceptor(receiver);
2610 block.statements.add( 2613 block.statements.add(
2611 js.if_( 2614 jsBuilder.if_(
2612 new jsAst.Binary( 2615 new jsAst.Binary(
2613 "instanceof", 2616 "instanceof",
2614 js['receiver'], 2617 js('receiver'),
2615 js[namer.isolateAccess(compiler.objectClass)]), 2618 js(namer.isolateAccess(compiler.objectClass))),
2616 js.return_(js['receiver']))); 2619 jsBuilder.return_(js('receiver'))));
2617 2620
2618 // TODO(sra): Fold this 'Object' check into the `getNativeInterceptor` 2621 // TODO(sra): Fold this 'Object' check into the `getNativeInterceptor`
2619 // check by patching `Object.prototype` with a special hook function. 2622 // check by patching `Object.prototype` with a special hook function.
2620 // TODO(9556): This test is needed in plain non-browser code because 2623 // TODO(9556): This test is needed in plain non-browser code because
2621 // 'holders' are not Dart classes. 2624 // 'holders' are not Dart classes.
2622 block.statements.add( 2625 block.statements.add(
2623 js.if_( 2626 jsBuilder.if_(
2624 js['Object.getPrototypeOf(receiver) === Object.prototype'], 2627 js('Object.getPrototypeOf(receiver) === Object.prototype'),
2625 buildReturnInterceptor(backend.jsInterceptorClass))); 2628 buildReturnInterceptor(backend.jsInterceptorClass)));
2626 2629
2627 block.statements.add( 2630 block.statements.add(
2628 js.return_( 2631 jsBuilder.return_(
2629 js[namer.isolateAccess(backend.getNativeInterceptorMethod)]( 2632 js(namer.isolateAccess(backend.getNativeInterceptorMethod))(
2630 ['receiver']))); 2633 ['receiver'])));
2631 2634
2632 } else { 2635 } else {
2633 block.statements.add(js.return_(js['receiver'])); 2636 block.statements.add(jsBuilder.return_(js('receiver')));
2634 } 2637 }
2635 2638
2636 buffer.write(jsAst.prettyPrint( 2639 buffer.write(jsAst.prettyPrint(
2637 js[isolateProperties][key].assign(js.fun(['receiver'], block)), 2640 js(isolateProperties)[key].assign(jsBuilder.fun(['receiver'], block)),
2638 compiler)); 2641 compiler));
2639 buffer.write(N); 2642 buffer.write(N);
2640 } 2643 }
2641 2644
2642 /** 2645 /**
2643 * Emit all versions of the [:getInterceptor:] method. 2646 * Emit all versions of the [:getInterceptor:] method.
2644 */ 2647 */
2645 void emitGetInterceptorMethods(CodeBuffer buffer) { 2648 void emitGetInterceptorMethods(CodeBuffer buffer) {
2646 var specializedGetInterceptors = backend.specializedGetInterceptors; 2649 var specializedGetInterceptors = backend.specializedGetInterceptors;
2647 for (String name in specializedGetInterceptors.keys.toList()..sort()) { 2650 for (String name in specializedGetInterceptors.keys.toList()..sort()) {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
2701 } else { 2704 } else {
2702 regularClasses.add(element); 2705 regularClasses.add(element);
2703 } 2706 }
2704 } 2707 }
2705 } 2708 }
2706 2709
2707 // Optimize performance critical one shot interceptors. 2710 // Optimize performance critical one shot interceptors.
2708 jsAst.Statement tryOptimizeOneShotInterceptor(Selector selector, 2711 jsAst.Statement tryOptimizeOneShotInterceptor(Selector selector,
2709 Set<ClassElement> classes) { 2712 Set<ClassElement> classes) {
2710 jsAst.Expression isNumber(String variable) { 2713 jsAst.Expression isNumber(String variable) {
2711 return js[variable].typeof.equals(js.string('number')); 2714 return js(variable).typeof.equals(jsBuilder.string('number'));
2712 } 2715 }
2713 2716
2714 jsAst.Expression isNotObject(String variable) { 2717 jsAst.Expression isNotObject(String variable) {
2715 return js[variable].typeof.equals(js.string('object')).not; 2718 return js(variable).typeof.equals(jsBuilder.string('object')).not;
2716 } 2719 }
2717 2720
2718 jsAst.Expression isInt(String variable) { 2721 jsAst.Expression isInt(String variable) {
2719 jsAst.Expression receiver = js[variable]; 2722 jsAst.Expression receiver = js(variable);
2720 return isNumber(variable).binary('&&', 2723 return isNumber(variable).binary('&&',
2721 js['Math']['floor'](receiver).equals(receiver)); 2724 js('Math')['floor'](receiver).equals(receiver));
2722 } 2725 }
2723 2726
2724 jsAst.Expression tripleShiftZero(jsAst.Expression receiver) { 2727 jsAst.Expression tripleShiftZero(jsAst.Expression receiver) {
2725 return receiver.binary('>>>', js.toExpression(0)); 2728 return receiver.binary('>>>', jsBuilder.toExpression(0));
2726 } 2729 }
2727 2730
2728 if (selector.isOperator()) { 2731 if (selector.isOperator()) {
2729 String name = selector.name.stringValue; 2732 String name = selector.name.stringValue;
2730 if (name == '==') { 2733 if (name == '==') {
2731 // Unfolds to: 2734 // Unfolds to:
2732 // [: if (receiver == null) return a0 == null; 2735 // [: if (receiver == null) return a0 == null;
2733 // if (typeof receiver != 'object') { 2736 // if (typeof receiver != 'object') {
2734 // return a0 != null && receiver === a0; 2737 // return a0 != null && receiver === a0;
2735 // } 2738 // }
2736 // :]. 2739 // :].
2737 List<jsAst.Statement> body = <jsAst.Statement>[]; 2740 List<jsAst.Statement> body = <jsAst.Statement>[];
2738 body.add(js.if_('receiver == null', 2741 body.add(jsBuilder.if_(
2739 js.return_(js['a0'].equals(new jsAst.LiteralNull())))); 2742 'receiver == null',
2740 body.add(js.if_( 2743 jsBuilder.return_(js('a0').equals(new jsAst.LiteralNull()))));
2744 body.add(jsBuilder.if_(
2741 isNotObject('receiver'), 2745 isNotObject('receiver'),
2742 js.return_(js['a0'].equals(new jsAst.LiteralNull()).not.binary( 2746 jsBuilder.return_(js('a0')
2743 '&&', js['receiver'].strictEquals(js['a0']))))); 2747 .equals(new jsAst.LiteralNull())
2748 .not
2749 .binary('&&', js('receiver').strictEquals(js('a0'))))));
2744 return new jsAst.Block(body); 2750 return new jsAst.Block(body);
2745 } 2751 }
2746 if (!classes.contains(backend.jsIntClass) 2752 if (!classes.contains(backend.jsIntClass)
2747 && !classes.contains(backend.jsNumberClass) 2753 && !classes.contains(backend.jsNumberClass)
2748 && !classes.contains(backend.jsDoubleClass)) { 2754 && !classes.contains(backend.jsDoubleClass)) {
2749 return null; 2755 return null;
2750 } 2756 }
2751 if (selector.argumentCount == 1) { 2757 if (selector.argumentCount == 1) {
2752 // The following operators do not map to a JavaScript 2758 // The following operators do not map to a JavaScript
2753 // operator. 2759 // operator.
2754 if (name != '~/' && name != '<<' && name != '%' && name != '>>') { 2760 if (name != '~/' && name != '<<' && name != '%' && name != '>>') {
2755 jsAst.Expression result = js['receiver'].binary(name, js['a0']); 2761 jsAst.Expression result = js('receiver').binary(name, js('a0'));
2756 if (name == '&' || name == '|' || name == '^') { 2762 if (name == '&' || name == '|' || name == '^') {
2757 result = tripleShiftZero(result); 2763 result = tripleShiftZero(result);
2758 } 2764 }
2759 // Unfolds to: 2765 // Unfolds to:
2760 // [: if (typeof receiver == "number" && typeof a0 == "number") 2766 // [: if (typeof receiver == "number" && typeof a0 == "number")
2761 // return receiver op a0; 2767 // return receiver op a0;
2762 // :]. 2768 // :].
2763 return js.if_( 2769 return jsBuilder.if_(
2764 isNumber('receiver').binary('&&', isNumber('a0')), 2770 isNumber('receiver').binary('&&', isNumber('a0')),
2765 js.return_(result)); 2771 jsBuilder.return_(result));
2766 } 2772 }
2767 } else if (name == 'unary-') { 2773 } else if (name == 'unary-') {
2768 // operator~ does not map to a JavaScript operator. 2774 // operator~ does not map to a JavaScript operator.
2769 // Unfolds to: 2775 // Unfolds to:
2770 // [: if (typeof receiver == "number") return -receiver:]. 2776 // [: if (typeof receiver == "number") return -receiver:].
2771 return js.if_( 2777 return jsBuilder.if_(
2772 isNumber('receiver'), 2778 isNumber('receiver'),
2773 js.return_(new jsAst.Prefix('-', js['receiver']))); 2779 jsBuilder.return_(new jsAst.Prefix('-', js('receiver'))));
2774 } else { 2780 } else {
2775 assert(name == '~'); 2781 assert(name == '~');
2776 return js.if_( 2782 return jsBuilder.if_(
2777 isInt('receiver'), 2783 isInt('receiver'),
2778 js.return_( 2784 jsBuilder.return_(
2779 tripleShiftZero(new jsAst.Prefix(name, js['receiver'])))); 2785 tripleShiftZero(new jsAst.Prefix(name, js('receiver')))));
2780 } 2786 }
2781 } else if (selector.isIndex() || selector.isIndexSet()) { 2787 } else if (selector.isIndex() || selector.isIndexSet()) {
2782 // For an index operation, this code generates: 2788 // For an index operation, this code generates:
2783 // 2789 //
2784 // [: if (receiver.constructor == Array || typeof receiver == "string") { 2790 // [: if (receiver.constructor == Array || typeof receiver == "string") {
2785 // if (a0 >>> 0 === a0 && a0 < receiver.length) { 2791 // if (a0 >>> 0 === a0 && a0 < receiver.length) {
2786 // return receiver[a0]; 2792 // return receiver[a0];
2787 // } 2793 // }
2788 // } 2794 // }
2789 // :] 2795 // :]
(...skipping 11 matching lines...) Expand all
2801 // The index set operator requires a check on its set value in 2807 // The index set operator requires a check on its set value in
2802 // checked mode, so we don't optimize the interceptor if the 2808 // checked mode, so we don't optimize the interceptor if the
2803 // compiler has type assertions enabled. 2809 // compiler has type assertions enabled.
2804 if (selector.isIndexSet() 2810 if (selector.isIndexSet()
2805 && (compiler.enableTypeAssertions || !containsArray)) { 2811 && (compiler.enableTypeAssertions || !containsArray)) {
2806 return null; 2812 return null;
2807 } 2813 }
2808 if (!containsArray && !containsString) { 2814 if (!containsArray && !containsString) {
2809 return null; 2815 return null;
2810 } 2816 }
2811 jsAst.Expression receiver = js['receiver']; 2817 jsAst.Expression receiver = js('receiver');
2812 jsAst.Expression arg0 = js['a0']; 2818 jsAst.Expression arg0 = js('a0');
2813 jsAst.Expression isIntAndAboveZero = 2819 jsAst.Expression isIntAndAboveZero =
2814 arg0.binary('>>>', js.toExpression(0)).strictEquals(arg0); 2820 arg0.binary('>>>', jsBuilder.toExpression(0)).strictEquals(arg0);
2815 jsAst.Expression belowLength = arg0.binary('<', receiver['length']); 2821 jsAst.Expression belowLength = arg0.binary('<', receiver['length']);
2816 jsAst.Expression arrayCheck = receiver['constructor'].equals('Array'); 2822 jsAst.Expression arrayCheck = receiver['constructor'].equals('Array');
2817 2823
2818 if (selector.isIndex()) { 2824 if (selector.isIndex()) {
2819 jsAst.Expression stringCheck = 2825 jsAst.Expression stringCheck =
2820 receiver.typeof.equals(js.string('string')); 2826 receiver.typeof.equals(jsBuilder.string('string'));
2821 jsAst.Expression typeCheck; 2827 jsAst.Expression typeCheck;
2822 if (containsArray) { 2828 if (containsArray) {
2823 if (containsString) { 2829 if (containsString) {
2824 typeCheck = arrayCheck.binary('||', stringCheck); 2830 typeCheck = arrayCheck.binary('||', stringCheck);
2825 } else { 2831 } else {
2826 typeCheck = arrayCheck; 2832 typeCheck = arrayCheck;
2827 } 2833 }
2828 } else { 2834 } else {
2829 assert(containsString); 2835 assert(containsString);
2830 typeCheck = stringCheck; 2836 typeCheck = stringCheck;
2831 } 2837 }
2832 2838
2833 return js.if_(typeCheck, 2839 return jsBuilder.if_(
2834 js.if_(isIntAndAboveZero.binary('&&', belowLength), 2840 typeCheck,
2835 js.return_(receiver[arg0]))); 2841 jsBuilder.if_(isIntAndAboveZero.binary('&&', belowLength),
2842 jsBuilder.return_(receiver[arg0])));
2836 } else { 2843 } else {
2837 jsAst.Expression isImmutableArray = arrayCheck.binary( 2844 jsAst.Expression isImmutableArray = arrayCheck.binary(
2838 '&&', receiver[r'immutable$list'].not); 2845 '&&', receiver[r'immutable$list'].not);
2839 return js.if_(isImmutableArray.binary( 2846 return jsBuilder.if_(isImmutableArray.binary(
2840 '&&', isIntAndAboveZero.binary('&&', belowLength)), 2847 '&&', isIntAndAboveZero.binary('&&', belowLength)),
2841 js.return_(receiver[arg0].assign(js['a1']))); 2848 jsBuilder.return_(receiver[arg0].assign(js('a1'))));
2842 } 2849 }
2843 } 2850 }
2844 return null; 2851 return null;
2845 } 2852 }
2846 2853
2847 void emitOneShotInterceptors(CodeBuffer buffer) { 2854 void emitOneShotInterceptors(CodeBuffer buffer) {
2848 List<String> names = backend.oneShotInterceptors.keys.toList(); 2855 List<String> names = backend.oneShotInterceptors.keys.toList();
2849 names.sort(); 2856 names.sort();
2850 for (String name in names) { 2857 for (String name in names) {
2851 Selector selector = backend.oneShotInterceptors[name]; 2858 Selector selector = backend.oneShotInterceptors[name];
2852 Set<ClassElement> classes = 2859 Set<ClassElement> classes =
2853 backend.getInterceptedClassesOn(selector.name); 2860 backend.getInterceptedClassesOn(selector.name);
2854 String getInterceptorName = 2861 String getInterceptorName =
2855 namer.getInterceptorName(backend.getInterceptorMethod, classes); 2862 namer.getInterceptorName(backend.getInterceptorMethod, classes);
2856 2863
2857 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; 2864 List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
2858 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 2865 List<jsAst.Expression> arguments = <jsAst.Expression>[];
2859 parameters.add(new jsAst.Parameter('receiver')); 2866 parameters.add(new jsAst.Parameter('receiver'));
2860 arguments.add(js['receiver']); 2867 arguments.add(js('receiver'));
2861 2868
2862 if (selector.isSetter()) { 2869 if (selector.isSetter()) {
2863 parameters.add(new jsAst.Parameter('value')); 2870 parameters.add(new jsAst.Parameter('value'));
2864 arguments.add(js['value']); 2871 arguments.add(js('value'));
2865 } else { 2872 } else {
2866 for (int i = 0; i < selector.argumentCount; i++) { 2873 for (int i = 0; i < selector.argumentCount; i++) {
2867 String argName = 'a$i'; 2874 String argName = 'a$i';
2868 parameters.add(new jsAst.Parameter(argName)); 2875 parameters.add(new jsAst.Parameter(argName));
2869 arguments.add(js[argName]); 2876 arguments.add(js(argName));
2870 } 2877 }
2871 } 2878 }
2872 2879
2873 List<jsAst.Statement> body = <jsAst.Statement>[]; 2880 List<jsAst.Statement> body = <jsAst.Statement>[];
2874 jsAst.Statement optimizedPath = 2881 jsAst.Statement optimizedPath =
2875 tryOptimizeOneShotInterceptor(selector, classes); 2882 tryOptimizeOneShotInterceptor(selector, classes);
2876 if (optimizedPath != null) { 2883 if (optimizedPath != null) {
2877 body.add(optimizedPath); 2884 body.add(optimizedPath);
2878 } 2885 }
2879 2886
2880 String invocationName = backend.namer.invocationName(selector); 2887 String invocationName = backend.namer.invocationName(selector);
2881 body.add(js.return_( 2888 body.add(jsBuilder.return_(
2882 js[isolateProperties][getInterceptorName]('receiver')[invocationName]( 2889 js(isolateProperties)[getInterceptorName]('receiver')[invocationName](
2883 arguments))); 2890 arguments)));
2884 2891
2885 jsAst.Fun function = js.fun(parameters, body); 2892 jsAst.Fun function = jsBuilder.fun(parameters, body);
2886 2893
2887 jsAst.PropertyAccess property = 2894 jsAst.PropertyAccess property =
2888 js[isolateProperties][name]; 2895 js(isolateProperties)[name];
2889 2896
2890 buffer.write(jsAst.prettyPrint(property.assign(function), compiler)); 2897 buffer.write(jsAst.prettyPrint(property.assign(function), compiler));
2891 buffer.write(N); 2898 buffer.write(N);
2892 } 2899 }
2893 } 2900 }
2894 2901
2895 /** 2902 /**
2896 * If [:invokeOn:] has been compiled, emit all the possible selector names 2903 * If [:invokeOn:] has been compiled, emit all the possible selector names
2897 * that are intercepted into the [:interceptedNames:] top-level 2904 * that are intercepted into the [:interceptedNames:] top-level
2898 * variable. The implementation of [:invokeOn:] will use it to 2905 * variable. The implementation of [:invokeOn:] will use it to
2899 * determine whether it should call the method with an extra 2906 * determine whether it should call the method with an extra
2900 * parameter. 2907 * parameter.
2901 */ 2908 */
2902 void emitInterceptedNames(CodeBuffer buffer) { 2909 void emitInterceptedNames(CodeBuffer buffer) {
2903 if (!compiler.enabledInvokeOn) return; 2910 if (!compiler.enabledInvokeOn) return;
2904 String name = backend.namer.getName(backend.interceptedNames); 2911 String name = backend.namer.getName(backend.interceptedNames);
2905 jsAst.PropertyAccess property = js[isolateProperties][name]; 2912 jsAst.PropertyAccess property = js(isolateProperties)[name];
2906 2913
2907 int index = 0; 2914 int index = 0;
2908 List<jsAst.ArrayElement> elements = backend.usedInterceptors.map( 2915 List<jsAst.ArrayElement> elements = backend.usedInterceptors.map(
2909 (Selector selector) { 2916 (Selector selector) {
2910 jsAst.Literal str = js.string(namer.invocationName(selector)); 2917 jsAst.Literal str = jsBuilder.string(namer.invocationName(selector));
2911 return new jsAst.ArrayElement(index++, str); 2918 return new jsAst.ArrayElement(index++, str);
2912 }).toList(); 2919 }).toList();
2913 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer( 2920 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer(
2914 backend.usedInterceptors.length, 2921 backend.usedInterceptors.length,
2915 elements); 2922 elements);
2916 2923
2917 buffer.write(jsAst.prettyPrint(property.assign(array), compiler)); 2924 buffer.write(jsAst.prettyPrint(property.assign(array), compiler));
2918 buffer.write(N); 2925 buffer.write(N);
2919 } 2926 }
2920 2927
2921 void emitInitFunction(CodeBuffer buffer) { 2928 void emitInitFunction(CodeBuffer buffer) {
2922 jsAst.Fun fun = js.fun([], [ 2929 jsAst.Fun fun = jsBuilder.fun([], [
2923 js['$isolateProperties = {}'], 2930 js('$isolateProperties = {}'),
2924 ] 2931 ]
2925 ..addAll(buildDefineClassAndFinishClassFunctionsIfNecessary()) 2932 ..addAll(buildDefineClassAndFinishClassFunctionsIfNecessary())
2926 ..addAll(buildLazyInitializerFunctionIfNecessary()) 2933 ..addAll(buildLazyInitializerFunctionIfNecessary())
2927 ..addAll(buildFinishIsolateConstructor()) 2934 ..addAll(buildFinishIsolateConstructor())
2928 ); 2935 );
2929 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration( 2936 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration(
2930 new jsAst.VariableDeclaration('init'), fun); 2937 new jsAst.VariableDeclaration('init'), fun);
2931 buffer.write(jsAst.prettyPrint(decl, compiler).getText()); 2938 buffer.write(jsAst.prettyPrint(decl, compiler).getText());
2932 } 2939 }
2933 2940
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
3119 """; 3126 """;
3120 const String HOOKS_API_USAGE = """ 3127 const String HOOKS_API_USAGE = """
3121 // The code supports the following hooks: 3128 // The code supports the following hooks:
3122 // dartPrint(message) - if this function is defined it is called 3129 // dartPrint(message) - if this function is defined it is called
3123 // instead of the Dart [print] method. 3130 // instead of the Dart [print] method.
3124 // dartMainRunner(main) - if this function is defined, the Dart [main] 3131 // dartMainRunner(main) - if this function is defined, the Dart [main]
3125 // method will not be invoked directly. 3132 // method will not be invoked directly.
3126 // Instead, a closure that will invoke [main] is 3133 // Instead, a closure that will invoke [main] is
3127 // passed to [dartMainRunner]. 3134 // passed to [dartMainRunner].
3128 """; 3135 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698