OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 """; |
OLD | NEW |