| 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 |