| 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 dart2js.js_emitter; | 5 part of dart2js.js_emitter; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * Generates the code for all used classes in the program. Static fields (even | 8 * Generates the code for all used classes in the program. Static fields (even |
| 9 * in classes) are ignored, since they can be treated as non-class elements. | 9 * in classes) are ignored, since they can be treated as non-class elements. |
| 10 * | 10 * |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 const RANGE2_SIZE = RANGE2_LAST - RANGE2_FIRST + 1; | 141 const RANGE2_SIZE = RANGE2_LAST - RANGE2_FIRST + 1; |
| 142 const RANGE1_ADJUST = - (FIRST_FIELD_CODE - RANGE1_FIRST); | 142 const RANGE1_ADJUST = - (FIRST_FIELD_CODE - RANGE1_FIRST); |
| 143 const RANGE2_ADJUST = - (FIRST_FIELD_CODE + RANGE1_SIZE - RANGE2_FIRST); | 143 const RANGE2_ADJUST = - (FIRST_FIELD_CODE + RANGE1_SIZE - RANGE2_FIRST); |
| 144 const RANGE3_ADJUST = | 144 const RANGE3_ADJUST = |
| 145 - (FIRST_FIELD_CODE + RANGE1_SIZE + RANGE2_SIZE - RANGE3_FIRST); | 145 - (FIRST_FIELD_CODE + RANGE1_SIZE + RANGE2_SIZE - RANGE3_FIRST); |
| 146 | 146 |
| 147 String receiverParamName = compiler.enableMinification ? "r" : "receiver"; | 147 String receiverParamName = compiler.enableMinification ? "r" : "receiver"; |
| 148 String valueParamName = compiler.enableMinification ? "v" : "value"; | 148 String valueParamName = compiler.enableMinification ? "v" : "value"; |
| 149 String reflectableField = namer.reflectableField; | 149 String reflectableField = namer.reflectableField; |
| 150 | 150 |
| 151 return js.statement(''' | 151 // function generateAccessor(field, prototype, cls) { |
| 152 function generateAccessor(fieldDescriptor, accessors, cls) { | 152 jsAst.Fun fun = js.fun(['fieldDescriptor', 'accessors', 'cls'], [ |
| 153 var fieldInformation = fieldDescriptor.split("-"); | 153 js('var fieldInformation = fieldDescriptor.split("-")'), |
| 154 var field = fieldInformation[0]; | 154 js('var field = fieldInformation[0]'), |
| 155 var len = field.length; | 155 js('var len = field.length'), |
| 156 var code = field.charCodeAt(len - 1); | 156 js('var code = field.charCodeAt(len - 1)'), |
| 157 var reflectable; | 157 js('var reflectable'), |
| 158 if (fieldInformation.length > 1) reflectable = true; | 158 js.if_('fieldInformation.length > 1', js('reflectable = true'), |
| 159 else reflectable = false; | 159 js('reflectable = false')), |
| 160 code = ((code >= $RANGE1_FIRST) && (code <= $RANGE1_LAST)) | 160 js('code = ((code >= $RANGE1_FIRST) && (code <= $RANGE1_LAST))' |
| 161 ? code - $RANGE1_ADJUST | 161 ' ? code - $RANGE1_ADJUST' |
| 162 : ((code >= $RANGE2_FIRST) && (code <= $RANGE2_LAST)) | 162 ' : ((code >= $RANGE2_FIRST) && (code <= $RANGE2_LAST))' |
| 163 ? code - $RANGE2_ADJUST | 163 ' ? code - $RANGE2_ADJUST' |
| 164 : ((code >= $RANGE3_FIRST) && (code <= $RANGE3_LAST)) | 164 ' : ((code >= $RANGE3_FIRST) && (code <= $RANGE3_LAST))' |
| 165 ? code - $RANGE3_ADJUST | 165 ' ? code - $RANGE3_ADJUST' |
| 166 : $NO_FIELD_CODE; | 166 ' : $NO_FIELD_CODE'), |
| 167 | 167 |
| 168 if (code) { // needsAccessor | 168 // if (needsAccessor) { |
| 169 var getterCode = code & 3; | 169 js.if_('code', [ |
| 170 var setterCode = code >> 2; | 170 js('var getterCode = code & 3'), |
| 171 var accessorName = field = field.substring(0, len - 1); | 171 js('var setterCode = code >> 2'), |
| 172 js('var accessorName = field = field.substring(0, len - 1)'), |
| 172 | 173 |
| 173 var divider = field.indexOf(":"); | 174 js('var divider = field.indexOf(":")'), |
| 174 if (divider > 0) { // Colon never in first position. | 175 js.if_('divider > 0', [ // Colon never in first position. |
| 175 accessorName = field.substring(0, divider); | 176 js('accessorName = field.substring(0, divider)'), |
| 176 field = field.substring(divider + 1); | 177 js('field = field.substring(divider + 1)') |
| 177 } | 178 ]), |
| 178 | 179 |
| 179 if (getterCode) { // needsGetter | 180 // if (needsGetter) { |
| 180 var args = (getterCode & 2) ? "$receiverParamName" : ""; | 181 js.if_('getterCode', [ |
| 181 var receiver = (getterCode & 1) ? "this" : "$receiverParamName"; | 182 js('var args = (getterCode & 2) ? "$receiverParamName" : ""'), |
| 182 var body = "return " + receiver + "." + field; | 183 js('var receiver = (getterCode & 1) ? "this" : "$receiverParamName"'), |
| 183 var property = | 184 js('var body = "return " + receiver + "." + field'), |
| 184 cls + ".prototype.${namer.getterPrefix}" + accessorName + "="; | 185 js('var property =' |
| 185 var fn = "function(" + args + "){" + body + "}"; | 186 ' cls + ".prototype.${namer.getterPrefix}" + accessorName + "="'), |
| 186 if (reflectable) | 187 js('var fn = "function(" + args + "){" + body + "}"'), |
| 187 accessors.push(property + "\$reflectable(" + fn + ");\\n"); | 188 js.if_( |
| 188 else | 189 'reflectable', |
| 189 accessors.push(property + fn + ";\\n"); | 190 js('accessors.push(property + "\$reflectable(" + fn + ");\\n")'), |
| 190 } | 191 js('accessors.push(property + fn + ";\\n")')), |
| 192 ]), |
| 191 | 193 |
| 192 if (setterCode) { // needsSetter | 194 // if (needsSetter) { |
| 193 var args = (setterCode & 2) | 195 js.if_('setterCode', [ |
| 194 ? "$receiverParamName,${_}$valueParamName" | 196 js('var args = (setterCode & 2)' |
| 195 : "$valueParamName"; | 197 ' ? "$receiverParamName,${_}$valueParamName"' |
| 196 var receiver = (setterCode & 1) ? "this" : "$receiverParamName"; | 198 ' : "$valueParamName"'), |
| 197 var body = receiver + "." + field + "$_=$_$valueParamName"; | 199 js('var receiver = (setterCode & 1) ? "this" : "$receiverParamName"'), |
| 198 var property = | 200 js('var body = receiver + "." + field + "$_=$_$valueParamName"'), |
| 199 cls + ".prototype.${namer.setterPrefix}" + accessorName + "="; | 201 js('var property =' |
| 200 var fn = "function(" + args + "){" + body + "}"; | 202 ' cls + ".prototype.${namer.setterPrefix}" + accessorName + "="'), |
| 201 if (reflectable) | 203 js('var fn = "function(" + args + "){" + body + "}"'), |
| 202 accessors.push(property + "\$reflectable(" + fn + ");\\n"); | 204 js.if_( |
| 203 else | 205 'reflectable', |
| 204 accessors.push(property + fn + ";\\n"); | 206 js('accessors.push(property + "\$reflectable(" + fn + ");\\n")'), |
| 205 } | 207 js('accessors.push(property + fn + ";\\n")')), |
| 206 } | 208 ]), |
| 207 | 209 |
| 208 return field; | 210 ]), |
| 209 }'''); | 211 |
| 212 // return field; |
| 213 js.return_('field') |
| 214 ]); |
| 215 |
| 216 return new jsAst.FunctionDeclaration( |
| 217 new jsAst.VariableDeclaration('generateAccessor'), |
| 218 fun); |
| 210 } | 219 } |
| 211 | 220 |
| 212 List get defineClassFunction { | 221 List get defineClassFunction { |
| 213 // First the class name, then the field names in an array and the members | 222 // First the class name, then the field names in an array and the members |
| 214 // (inside an Object literal). | 223 // (inside an Object literal). |
| 215 // The caller can also pass in the constructor as a function if needed. | 224 // The caller can also pass in the constructor as a function if needed. |
| 216 // | 225 // |
| 217 // Example: | 226 // Example: |
| 218 // defineClass("A", ["x", "y"], { | 227 // defineClass("A", ["x", "y"], { |
| 219 // foo$1: function(y) { | 228 // foo$1: function(y) { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 // - it contains all (local) members. | 297 // - it contains all (local) members. |
| 289 // - its internal prototype (__proto__) points to the superclass' | 298 // - its internal prototype (__proto__) points to the superclass' |
| 290 // prototype field. | 299 // prototype field. |
| 291 // - the prototype's constructor field points to the JavaScript | 300 // - the prototype's constructor field points to the JavaScript |
| 292 // constructor. | 301 // constructor. |
| 293 // For engines where we have access to the '__proto__' we can manipulate | 302 // For engines where we have access to the '__proto__' we can manipulate |
| 294 // the object literal directly. For other engines we have to create a new | 303 // the object literal directly. For other engines we have to create a new |
| 295 // object and copy over the members. | 304 // object and copy over the members. |
| 296 | 305 |
| 297 String reflectableField = namer.reflectableField; | 306 String reflectableField = namer.reflectableField; |
| 307 List<jsAst.Node> statements = [ |
| 308 js('var pendingClasses = {}'), |
| 309 js.if_('!init.allClasses', js('init.allClasses = {}')), |
| 310 js('var allClasses = init.allClasses'), |
| 298 | 311 |
| 299 return js(''' | 312 optional( |
| 300 function(collectedClasses, isolateProperties, existingIsolateProperties) { | 313 DEBUG_FAST_OBJECTS, |
| 301 var pendingClasses = {}; | 314 js('print("Number of classes: "' |
| 302 if (!init.allClasses) init.allClasses = {}; | 315 r' + Object.getOwnPropertyNames($$).length)')), |
| 303 var allClasses = init.allClasses; | |
| 304 | 316 |
| 305 if (#) // DEBUG_FAST_OBJECTS | 317 js('var hasOwnProperty = Object.prototype.hasOwnProperty'), |
| 306 print("Number of classes: " + | |
| 307 Object.getOwnPropertyNames(\$\$).length); | |
| 308 | 318 |
| 309 var hasOwnProperty = Object.prototype.hasOwnProperty; | 319 js.if_('typeof dart_precompiled == "function"', |
| 320 [js('var constructors = dart_precompiled(collectedClasses)')], |
| 310 | 321 |
| 311 if (typeof dart_precompiled == "function") { | 322 [js('var combinedConstructorFunction = "function \$reflectable(fn){' |
| 312 var constructors = dart_precompiled(collectedClasses); | 323 'fn.$reflectableField=1;return fn};\\n"+ "var \$desc;\\n"'), |
| 313 } else { | 324 js('var constructorsList = []')]), |
| 314 var combinedConstructorFunction = | 325 js.forIn('cls', 'collectedClasses', [ |
| 315 "function \$reflectable(fn){fn.$reflectableField=1;return fn};\\n"+ | 326 js.if_('hasOwnProperty.call(collectedClasses, cls)', [ |
| 316 "var \$desc;\\n"; | 327 js('var desc = collectedClasses[cls]'), |
| 317 var constructorsList = []; | 328 js.if_('desc instanceof Array', js('desc = desc[1]')), |
| 318 } | |
| 319 | 329 |
| 320 for (var cls in collectedClasses) { | 330 /* The 'fields' are either a constructor function or a |
| 321 if (hasOwnProperty.call(collectedClasses, cls)) { | 331 * string encoding fields, constructor and superclass. Get |
| 322 var desc = collectedClasses[cls]; | 332 * the superclass and the fields in the format |
| 323 if (desc instanceof Array) desc = desc[1]; | 333 * '[name/]Super;field1,field2' |
| 334 * from the CLASS_DESCRIPTOR_PROPERTY property on the descriptor. |
| 335 * The 'name/' is optional and contains the name that should be used |
| 336 * when printing the runtime type string. It is used, for example, to |
| 337 * print the runtime type JSInt as 'int'. |
| 338 */ |
| 339 js('var classData = desc["${namer.classDescriptorProperty}"], ' |
| 340 'supr, name = cls, fields = classData'), |
| 341 optional( |
| 342 backend.hasRetainedMetadata, |
| 343 js.if_('typeof classData == "object" && ' |
| 344 'classData instanceof Array', |
| 345 [js('classData = fields = classData[0]')])), |
| 324 | 346 |
| 325 /* The 'fields' are either a constructor function or a | 347 js.if_('typeof classData == "string"', [ |
| 326 * string encoding fields, constructor and superclass. Get | 348 js('var split = classData.split("/")'), |
| 327 * the superclass and the fields in the format | 349 js.if_('split.length == 2', [ |
| 328 * '[name/]Super;field1,field2' | 350 js('name = split[0]'), |
| 329 * from the CLASS_DESCRIPTOR_PROPERTY property on the descriptor. | 351 js('fields = split[1]') |
| 330 * The 'name/' is optional and contains the name that should be used | 352 ]) |
| 331 * when printing the runtime type string. It is used, for example, | 353 ]), |
| 332 * to print the runtime type JSInt as 'int'. | |
| 333 */ | |
| 334 var classData = desc["${namer.classDescriptorProperty}"], | |
| 335 supr, name = cls, fields = classData; | |
| 336 if (#) // backend.hasRetainedMetadata | |
| 337 if (typeof classData == "object" && | |
| 338 classData instanceof Array) { | |
| 339 classData = fields = classData[0]; | |
| 340 } | |
| 341 if (typeof classData == "string") { | |
| 342 var split = classData.split("/"); | |
| 343 if (split.length == 2) { | |
| 344 name = split[0]; | |
| 345 fields = split[1]; | |
| 346 } | |
| 347 } | |
| 348 | 354 |
| 349 var s = fields.split(";"); | 355 js('var s = fields.split(";")'), |
| 350 fields = s[1] == "" ? [] : s[1].split(","); | 356 js('fields = s[1] == "" ? [] : s[1].split(",")'), |
| 351 supr = s[0]; | 357 js('supr = s[0]'), |
| 352 split = supr.split(":"); | 358 js('split = supr.split(":")'), |
| 353 if (split.length == 2) { | 359 js.if_('split.length == 2', [ |
| 354 supr = split[0]; | 360 js('supr = split[0]'), |
| 355 var functionSignature = split[1]; | 361 js('var functionSignature = split[1]'), |
| 356 if (functionSignature) | 362 js.if_('functionSignature', |
| 357 desc.\$signature = (function(s) { | 363 js('desc.\$signature = #', |
| 358 return function(){ return init.metadata[s]; }; | 364 js.fun('s', |
| 359 })(functionSignature); | 365 js.return_(js.fun([], js.return_('init.metadata[s]'))))( |
| 360 } | 366 js('functionSignature')))) |
| 367 ]), |
| 361 | 368 |
| 362 if (#) // needsMixinSupport | 369 optional(needsMixinSupport, js.if_('supr && supr.indexOf("+") > 0', [ |
| 363 if (supr && supr.indexOf("+") > 0) { | 370 js('s = supr.split("+")'), |
| 364 s = supr.split("+"); | 371 js('supr = s[0]'), |
| 365 supr = s[0]; | 372 js('var mixin = collectedClasses[s[1]]'), |
| 366 var mixin = collectedClasses[s[1]]; | 373 js.if_('mixin instanceof Array', js('mixin = mixin[1]')), |
| 367 if (mixin instanceof Array) mixin = mixin[1]; | 374 js.forIn('d', 'mixin', [ |
| 368 for(var d in mixin) { | 375 js.if_('hasOwnProperty.call(mixin, d)' |
| 369 if (hasOwnProperty.call(mixin, d) && | 376 '&& !hasOwnProperty.call(desc, d)', |
| 370 !hasOwnProperty.call(desc, d)) | 377 js('desc[d] = mixin[d]')) |
| 371 desc[d] = mixin[d]; | 378 ]), |
| 372 } | 379 ])), |
| 373 } | |
| 374 | 380 |
| 375 if (typeof dart_precompiled != "function") { | 381 js.if_('typeof dart_precompiled != "function"', |
| 376 combinedConstructorFunction += defineClass(name, cls, fields); | 382 [js('combinedConstructorFunction +=' |
| 377 constructorsList.push(cls); | 383 ' defineClass(name, cls, fields)'), |
| 378 } | 384 js('constructorsList.push(cls)')]), |
| 379 if (supr) pendingClasses[cls] = supr; | 385 js.if_('supr', js('pendingClasses[cls] = supr')) |
| 380 } | 386 ]) |
| 381 } | 387 ]), |
| 388 js.statement(''' |
| 389 if (typeof dart_precompiled != "function") { |
| 390 combinedConstructorFunction += |
| 391 "return [\\n " + constructorsList.join(",\\n ") + "\\n]"; |
| 392 var constructors = |
| 393 new Function("\$collectedClasses", combinedConstructorFunction) |
| 394 (collectedClasses); |
| 395 combinedConstructorFunction = null; |
| 396 }'''), |
| 397 js.for_('var i = 0', 'i < constructors.length', 'i++', [ |
| 398 js('var constructor = constructors[i]'), |
| 399 js('var cls = constructor.name'), |
| 400 js('var desc = collectedClasses[cls]'), |
| 401 js('var globalObject = isolateProperties'), |
| 402 js.if_('desc instanceof Array', [ |
| 403 js('globalObject = desc[0] || isolateProperties'), |
| 404 js('desc = desc[1]') |
| 405 ]), |
| 406 optional(backend.isTreeShakingDisabled, |
| 407 js('constructor["${namer.metadataField}"] = desc')), |
| 408 js('allClasses[cls] = constructor'), |
| 409 js('globalObject[cls] = constructor'), |
| 410 ]), |
| 411 js('constructors = null'), |
| 382 | 412 |
| 383 if (typeof dart_precompiled != "function") { | 413 js('var finishedClasses = {}'), |
| 384 combinedConstructorFunction += | 414 js('init.interceptorsByTag = Object.create(null)'), |
| 385 "return [\\n " + constructorsList.join(",\\n ") + "\\n]"; | 415 js('init.leafTags = {}'), |
| 386 var constructors = | |
| 387 new Function("\$collectedClasses", combinedConstructorFunction) | |
| 388 (collectedClasses); | |
| 389 combinedConstructorFunction = null; | |
| 390 } | |
| 391 | 416 |
| 392 for (var i = 0; i < constructors.length; i++) { | 417 buildFinishClass(), |
| 393 var constructor = constructors[i]; | 418 ]; |
| 394 var cls = constructor.name; | |
| 395 var desc = collectedClasses[cls]; | |
| 396 var globalObject = isolateProperties; | |
| 397 if (desc instanceof Array) { | |
| 398 globalObject = desc[0] || isolateProperties; | |
| 399 desc = desc[1]; | |
| 400 } | |
| 401 if (#) //backend.isTreeShakingDisabled, | |
| 402 constructor["${namer.metadataField}"] = desc; | |
| 403 allClasses[cls] = constructor; | |
| 404 globalObject[cls] = constructor; | |
| 405 } | |
| 406 | 419 |
| 407 constructors = null; | 420 nsmEmitter.addTrivialNsmHandlers(statements); |
| 408 | 421 |
| 409 var finishedClasses = {}; | 422 statements.add( |
| 410 init.interceptorsByTag = Object.create(null); | 423 js.statement('for (var cls in pendingClasses) finishClass(cls);') |
| 411 init.leafTags = {}; | 424 ); |
| 412 | 425 |
| 413 #; // buildFinishClass(), | 426 // function(collectedClasses, |
| 414 | 427 // isolateProperties, |
| 415 #; // buildTrivialNsmHandlers() | 428 // existingIsolateProperties) |
| 416 | 429 return js.fun(['collectedClasses', 'isolateProperties', |
| 417 for (var cls in pendingClasses) finishClass(cls); | 430 'existingIsolateProperties'], statements); |
| 418 }''', [ | |
| 419 DEBUG_FAST_OBJECTS, | |
| 420 backend.hasRetainedMetadata, | |
| 421 needsMixinSupport, | |
| 422 backend.isTreeShakingDisabled, | |
| 423 buildFinishClass(), | |
| 424 nsmEmitter.buildTrivialNsmHandlers()]); | |
| 425 | |
| 426 } | 431 } |
| 427 | 432 |
| 428 jsAst.Node optional(bool condition, jsAst.Node node) { | 433 jsAst.Node optional(bool condition, jsAst.Node node) { |
| 429 return condition ? node : new jsAst.EmptyStatement(); | 434 return condition ? node : new jsAst.EmptyStatement(); |
| 430 } | 435 } |
| 431 | 436 |
| 432 jsAst.FunctionDeclaration buildFinishClass() { | 437 jsAst.FunctionDeclaration buildFinishClass() { |
| 433 String specProperty = '"${namer.nativeSpecProperty}"'; // "%" | 438 String specProperty = '"${namer.nativeSpecProperty}"'; // "%" |
| 434 | 439 |
| 435 return js.statement(''' | 440 // function finishClass(cls) { |
| 436 function finishClass(cls) { | 441 jsAst.Fun fun = js.fun(['cls'], [ |
| 437 | 442 |
| 438 // TODO(8540): Remove this work around. | 443 // TODO(8540): Remove this work around. |
| 439 // Opera does not support 'getOwnPropertyNames'. Therefore we use | 444 /* Opera does not support 'getOwnPropertyNames'. Therefore we use |
| 440 // hasOwnProperty instead. | 445 hasOwnProperty instead. */ |
| 441 var hasOwnProperty = Object.prototype.hasOwnProperty; | 446 js('var hasOwnProperty = Object.prototype.hasOwnProperty'), |
| 442 | 447 |
| 443 if (hasOwnProperty.call(finishedClasses, cls)) return; | 448 // if (hasOwnProperty.call(finishedClasses, cls)) return; |
| 449 js.if_('hasOwnProperty.call(finishedClasses, cls)', |
| 450 js.return_()), |
| 444 | 451 |
| 445 finishedClasses[cls] = true; | 452 js('finishedClasses[cls] = true'), |
| 446 | 453 |
| 447 var superclass = pendingClasses[cls]; | 454 js('var superclass = pendingClasses[cls]'), |
| 448 | 455 |
| 449 // The superclass is only false (empty string) for the Dart Object | 456 // The superclass is only false (empty string) for Dart's Object class. |
| 450 // class. The minifier together with noSuchMethod can put methods on | 457 // The minifier together with noSuchMethod can put methods on the |
| 451 // the Object.prototype object, and they show through here, so we check | 458 // Object.prototype object, and they show through here, so we check that |
| 452 // that we have a string. | 459 // we have a string. |
| 453 if (!superclass || typeof superclass != "string") return; | 460 js.if_('!superclass || typeof superclass != "string"', js.return_()), |
| 454 finishClass(superclass); | 461 js('finishClass(superclass)'), |
| 455 var constructor = allClasses[cls]; | 462 js('var constructor = allClasses[cls]'), |
| 456 var superConstructor = allClasses[superclass]; | 463 js('var superConstructor = allClasses[superclass]'), |
| 457 | 464 |
| 458 if (!superConstructor) | 465 js.if_(js('!superConstructor'), |
| 459 superConstructor = existingIsolateProperties[superclass]; | 466 js('superConstructor =' |
| 467 'existingIsolateProperties[superclass]')), |
| 460 | 468 |
| 461 var prototype = inheritFrom(constructor, superConstructor); | 469 js('var prototype = inheritFrom(constructor, superConstructor)'), |
| 462 | 470 |
| 463 if (#) { // !nativeClasses.isEmpty, | 471 optional(!nativeClasses.isEmpty, |
| 464 // The property looks like this: | 472 // The property looks like this: |
| 465 // | 473 // |
| 466 // HtmlElement: { | 474 // HtmlElement: { |
| 467 // "%": "HTMLDivElement|HTMLAnchorElement;HTMLElement;FancyButton" | 475 // "%": "HTMLDivElement|HTMLAnchorElement;HTMLElement;FancyButton" |
| 468 // | 476 // |
| 469 // The first two semicolon-separated parts contain dispatch tags, the | 477 // The first two semicolon-separated parts contain dispatch tags, the |
| 470 // third contains the JavaScript names for classes. | 478 // third contains the JavaScript names for classes. |
| 471 // | 479 // |
| 472 // The tags indicate that JavaScript objects with the dispatch tags | 480 // The tags indicate that JavaScript objects with the dispatch tags |
| 473 // (usually constructor names) HTMLDivElement, HTMLAnchorElement and | 481 // (usually constructor names) HTMLDivElement, HTMLAnchorElement and |
| 474 // HTMLElement all map to the Dart native class named HtmlElement. | 482 // HTMLElement all map to the Dart native class named HtmlElement. |
| 475 // The first set is for effective leaf nodes in the hierarchy, the | 483 // The first set is for effective leaf nodes in the hierarchy, the |
| 476 // second set is non-leaf nodes. | 484 // second set is non-leaf nodes. |
| 477 // | 485 // |
| 478 // The third part contains the JavaScript names of Dart classes that | 486 // The third part contains the JavaScript names of Dart classes that |
| 479 // extend the native class. Here, FancyButton extends HtmlElement, so | 487 // extend the native class. Here, FancyButton extends HtmlElement, so |
| 480 // the runtime needs to know that window.HTMLElement.prototype is the | 488 // the runtime needs to know that window.HTMLElement.prototype is the |
| 481 // prototype that needs to be extended in creating the custom element. | 489 // prototype that needs to be extended in creating the custom element. |
| 482 // | 490 // |
| 483 // The information is used to build tables referenced by | 491 // The information is used to build tables referenced by |
| 484 // getNativeInterceptor and custom element support. | 492 // getNativeInterceptor and custom element support. |
| 485 if (hasOwnProperty.call(prototype, $specProperty)) { | 493 js.if_('hasOwnProperty.call(prototype, $specProperty)', [ |
| 486 var nativeSpec = prototype[$specProperty].split(";"); | 494 js('var nativeSpec = prototype[$specProperty].split(";")'), |
| 487 if (nativeSpec[0]) { | 495 js.if_('nativeSpec[0]', [ |
| 488 var tags = nativeSpec[0].split("|"); | 496 js('var tags = nativeSpec[0].split("|")'), |
| 489 for (var i = 0; i < tags.length; i++) { | 497 js.for_('var i = 0', 'i < tags.length', 'i++', [ |
| 490 init.interceptorsByTag[tags[i]] = constructor; | 498 js('init.interceptorsByTag[tags[i]] = constructor'), |
| 491 init.leafTags[tags[i]] = true; | 499 js('init.leafTags[tags[i]] = true')])]), |
| 492 } | 500 js.if_('nativeSpec[1]', [ |
| 493 } | 501 js('tags = nativeSpec[1].split("|")'), |
| 494 if (nativeSpec[1]) { | 502 optional(true, // User subclassing of native classes? |
| 495 tags = nativeSpec[1].split("|"); | 503 js.if_('nativeSpec[2]', [ |
| 496 if (#) { // User subclassing of native classes? | 504 js('var subclasses = nativeSpec[2].split("|")'), |
| 497 if (nativeSpec[2]) { | 505 js.for_('var i = 0', 'i < subclasses.length', 'i++', [ |
| 498 var subclasses = nativeSpec[2].split("|"); | 506 js('var subclass = allClasses[subclasses[i]]'), |
| 499 for (var i = 0; i < subclasses.length; i++) { | 507 js('subclass.\$nativeSuperclassTag = ' |
| 500 var subclass = allClasses[subclasses[i]]; | 508 'tags[0]')])])), |
| 501 subclass.\$nativeSuperclassTag = tags[0]; | 509 js.for_('i = 0', 'i < tags.length', 'i++', [ |
| 502 } | 510 js('init.interceptorsByTag[tags[i]] = constructor'), |
| 503 } | 511 js('init.leafTags[tags[i]] = false')])])])) |
| 504 for (i = 0; i < tags.length; i++) { | 512 ]); |
| 505 init.interceptorsByTag[tags[i]] = constructor; | 513 |
| 506 init.leafTags[tags[i]] = false; | 514 return new jsAst.FunctionDeclaration( |
| 507 } | 515 new jsAst.VariableDeclaration('finishClass'), |
| 508 } | 516 fun); |
| 509 } | |
| 510 } | |
| 511 } | |
| 512 }''', [!nativeClasses.isEmpty, true]); | |
| 513 } | 517 } |
| 514 | 518 |
| 515 jsAst.Fun get finishIsolateConstructorFunction { | 519 jsAst.Fun get finishIsolateConstructorFunction { |
| 516 // We replace the old Isolate function with a new one that initializes | 520 // We replace the old Isolate function with a new one that initializes |
| 517 // all its fields with the initial (and often final) value of all globals. | 521 // all its fields with the initial (and often final) value of all globals. |
| 518 // | 522 // |
| 519 // We also copy over old values like the prototype, and the | 523 // We also copy over old values like the prototype, and the |
| 520 // isolateProperties themselves. | 524 // isolateProperties themselves. |
| 521 return js(''' | 525 return js(''' |
| 522 function (oldIsolate) { | 526 function (oldIsolate) { |
| 523 var isolateProperties = oldIsolate.${namer.isolatePropertiesName}; | 527 var isolateProperties = oldIsolate.${namer.isolatePropertiesName}; |
| 524 function Isolate() { | 528 function Isolate() { |
| 525 var hasOwnProperty = Object.prototype.hasOwnProperty; | 529 var hasOwnProperty = Object.prototype.hasOwnProperty; |
| 526 for (var staticName in isolateProperties) | 530 for (var staticName in isolateProperties) |
| 527 if (hasOwnProperty.call(isolateProperties, staticName)) | 531 if (hasOwnProperty.call(isolateProperties, staticName)) |
| 528 this[staticName] = isolateProperties[staticName]; | 532 this[staticName] = isolateProperties[staticName]; |
| 529 // Use the newly created object as prototype. In Chrome, | 533 // Use the newly created object as prototype. In Chrome, |
| 530 // this creates a hidden class for the object and makes | 534 // this creates a hidden class for the object and makes |
| 531 // sure it is fast to access. | 535 // sure it is fast to access. |
| 532 function ForceEfficientMap() {} | 536 function ForceEfficientMap() {} |
| 533 ForceEfficientMap.prototype = this; | 537 ForceEfficientMap.prototype = this; |
| 534 new ForceEfficientMap(); | 538 new ForceEfficientMap(); |
| 535 } | 539 } |
| 536 Isolate.prototype = oldIsolate.prototype; | 540 Isolate.prototype = oldIsolate.prototype; |
| 537 Isolate.prototype.constructor = Isolate; | 541 Isolate.prototype.constructor = Isolate; |
| 538 Isolate.${namer.isolatePropertiesName} = isolateProperties; | 542 Isolate.${namer.isolatePropertiesName} = isolateProperties; |
| 539 if (#) | 543 # |
| 540 Isolate.$finishClassesProperty = oldIsolate.$finishClassesProperty; | 544 # |
| 541 if (#) | |
| 542 Isolate.makeConstantList = oldIsolate.makeConstantList; | |
| 543 return Isolate; | 545 return Isolate; |
| 544 }''', | 546 }''', |
| 545 [ needsDefineClass, hasMakeConstantList ]); | 547 [ optional(needsDefineClass, |
| 548 js('Isolate.$finishClassesProperty =' |
| 549 ' oldIsolate.$finishClassesProperty')), |
| 550 optional(hasMakeConstantList, |
| 551 js('Isolate.makeConstantList = oldIsolate.makeConstantList')) |
| 552 ]); |
| 546 } | 553 } |
| 547 | 554 |
| 548 jsAst.Fun get lazyInitializerFunction { | 555 jsAst.Fun get lazyInitializerFunction { |
| 556 // function(prototype, staticName, fieldName, getterName, lazyValue) { |
| 557 var parameters = <String>['prototype', 'staticName', 'fieldName', |
| 558 'getterName', 'lazyValue']; |
| 559 return js.fun(parameters, addLazyInitializerLogic()); |
| 560 } |
| 561 |
| 562 List addLazyInitializerLogic() { |
| 549 String isolate = namer.currentIsolate; | 563 String isolate = namer.currentIsolate; |
| 550 String cyclicThrow = namer.isolateAccess(backend.getCyclicThrowHelper()); | 564 String cyclicThrow = namer.isolateAccess(backend.getCyclicThrowHelper()); |
| 565 var lazies = []; |
| 566 if (backend.rememberLazies) { |
| 567 lazies = [ |
| 568 js.if_('!init.lazies', js('init.lazies = {}')), |
| 569 js('init.lazies[fieldName] = getterName')]; |
| 570 } |
| 551 | 571 |
| 552 return js(''' | 572 return lazies..addAll([ |
| 553 function (prototype, staticName, fieldName, getterName, lazyValue) { | 573 js('var sentinelUndefined = {}'), |
| 554 if (#) { | 574 js('var sentinelInProgress = {}'), |
| 555 if (!init.lazies) init.lazies = {}; | 575 js('prototype[fieldName] = sentinelUndefined'), |
| 556 init.lazies[fieldName] = getterName; | |
| 557 } | |
| 558 | 576 |
| 559 var sentinelUndefined = {}; | 577 // prototype[getterName] = function() |
| 560 var sentinelInProgress = {}; | 578 js('prototype[getterName] = #', js.fun([], [ |
| 561 prototype[fieldName] = sentinelUndefined; | 579 js('var result = $isolate[fieldName]'), |
| 562 | 580 |
| 563 prototype[getterName] = function () { | 581 // try |
| 564 var result = $isolate[fieldName]; | 582 js.try_([ |
| 565 try { | 583 js.if_('result === sentinelUndefined', [ |
| 566 if (result === sentinelUndefined) { | 584 js('$isolate[fieldName] = sentinelInProgress'), |
| 567 $isolate[fieldName] = sentinelInProgress; | |
| 568 | 585 |
| 569 try { | 586 // try |
| 570 result = $isolate[fieldName] = lazyValue(); | 587 js.try_([ |
| 571 } finally { | 588 js('result = $isolate[fieldName] = lazyValue()'), |
| 572 // Use try-finally, not try-catch/throw as it destroys the | |
| 573 // stack trace. | |
| 574 if (result === sentinelUndefined) | |
| 575 if ($isolate[fieldName] === sentinelInProgress) | |
| 576 $isolate[fieldName] = null; | |
| 577 } | |
| 578 } else { | |
| 579 if (result === sentinelInProgress) | |
| 580 $cyclicThrow(staticName); | |
| 581 } | |
| 582 | 589 |
| 583 return result; | 590 ], finallyPart: [ |
| 584 } finally { | 591 // Use try-finally, not try-catch/throw as it destroys the |
| 585 $isolate[getterName] = function() { return this[fieldName]; }; | 592 // stack trace. |
| 586 } | 593 |
| 587 } | 594 // if (result === sentinelUndefined) |
| 588 } | 595 js.if_('result === sentinelUndefined', [ |
| 589 ''', [backend.rememberLazies]); | 596 // if ($isolate[fieldName] === sentinelInProgress) |
| 597 js.if_('$isolate[fieldName] === sentinelInProgress', [ |
| 598 js('$isolate[fieldName] = null'), |
| 599 ]) |
| 600 ]) |
| 601 ]) |
| 602 ], /* else */ [ |
| 603 js.if_('result === sentinelInProgress', |
| 604 js('$cyclicThrow(staticName)') |
| 605 ) |
| 606 ]), |
| 607 |
| 608 // return result; |
| 609 js.return_('result') |
| 610 |
| 611 ], finallyPart: [ |
| 612 js('$isolate[getterName] = #', |
| 613 js.fun([], [js.return_('this[fieldName]')])) |
| 614 ]) |
| 615 ])) |
| 616 ]); |
| 590 } | 617 } |
| 591 | 618 |
| 592 List buildDefineClassAndFinishClassFunctionsIfNecessary() { | 619 List buildDefineClassAndFinishClassFunctionsIfNecessary() { |
| 593 if (!needsDefineClass) return []; | 620 if (!needsDefineClass) return []; |
| 594 return defineClassFunction | 621 return defineClassFunction |
| 595 ..addAll(buildInheritFrom()) | 622 ..addAll(buildInheritFrom()) |
| 596 ..addAll([ | 623 ..addAll([ |
| 597 js('$finishClassesName = #', finishClassesFunction) | 624 js('$finishClassesName = #', finishClassesFunction) |
| 598 ]); | 625 ]); |
| 599 } | 626 } |
| 600 | 627 |
| 601 List buildLazyInitializerFunctionIfNecessary() { | 628 List buildLazyInitializerFunctionIfNecessary() { |
| 602 if (!needsLazyInitializer) return []; | 629 if (!needsLazyInitializer) return []; |
| 603 | 630 |
| 604 return [js('# = #', [js(lazyInitializerName), lazyInitializerFunction])]; | 631 return [js('$lazyInitializerName = #', lazyInitializerFunction)]; |
| 605 } | 632 } |
| 606 | 633 |
| 607 List buildFinishIsolateConstructor() { | 634 List buildFinishIsolateConstructor() { |
| 608 return [ | 635 return [ |
| 609 js('$finishIsolateConstructorName = #', finishIsolateConstructorFunction) | 636 js('$finishIsolateConstructorName = #', finishIsolateConstructorFunction) |
| 610 ]; | 637 ]; |
| 611 } | 638 } |
| 612 | 639 |
| 613 void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) { | 640 void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) { |
| 614 String isolate = namer.isolateName; | 641 String isolate = namer.isolateName; |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 725 } | 752 } |
| 726 | 753 |
| 727 String namedParametersAsReflectionNames(Selector selector) { | 754 String namedParametersAsReflectionNames(Selector selector) { |
| 728 if (selector.getOrderedNamedArguments().isEmpty) return ''; | 755 if (selector.getOrderedNamedArguments().isEmpty) return ''; |
| 729 String names = selector.getOrderedNamedArguments().join(':'); | 756 String names = selector.getOrderedNamedArguments().join(':'); |
| 730 return ':$names'; | 757 return ':$names'; |
| 731 } | 758 } |
| 732 | 759 |
| 733 jsAst.FunctionDeclaration buildPrecompiledFunction() { | 760 jsAst.FunctionDeclaration buildPrecompiledFunction() { |
| 734 // TODO(ahe): Compute a hash code. | 761 // TODO(ahe): Compute a hash code. |
| 735 return js.statement(''' | 762 String name = 'dart_precompiled'; |
| 736 function dart_precompiled(\$collectedClasses) { | 763 |
| 737 var \$desc; | 764 precompiledFunction.add( |
| 738 #; | 765 js.return_( |
| 739 return #; | 766 new jsAst.ArrayInitializer.from(precompiledConstructorNames))); |
| 740 }''', [ | 767 precompiledFunction.insert(0, js(r'var $desc')); |
| 741 precompiledFunction, | 768 return new jsAst.FunctionDeclaration( |
| 742 new jsAst.ArrayInitializer.from(precompiledConstructorNames)]); | 769 new jsAst.VariableDeclaration(name), |
| 770 js.fun([r'$collectedClasses'], precompiledFunction)); |
| 743 } | 771 } |
| 744 | 772 |
| 745 void generateClass(ClassElement classElement, ClassBuilder properties) { | 773 void generateClass(ClassElement classElement, ClassBuilder properties) { |
| 746 compiler.withCurrentElement(classElement, () { | 774 compiler.withCurrentElement(classElement, () { |
| 747 classEmitter.generateClass( | 775 classEmitter.generateClass( |
| 748 classElement, properties, additionalProperties[classElement]); | 776 classElement, properties, additionalProperties[classElement]); |
| 749 }); | 777 }); |
| 750 } | 778 } |
| 751 | 779 |
| 752 /** | 780 /** |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 823 Iterable<VariableElement> staticNonFinalFields = | 851 Iterable<VariableElement> staticNonFinalFields = |
| 824 handler.getStaticNonFinalFieldsForEmission(); | 852 handler.getStaticNonFinalFieldsForEmission(); |
| 825 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { | 853 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { |
| 826 // [:interceptedNames:] is handled in [emitInterceptedNames]. | 854 // [:interceptedNames:] is handled in [emitInterceptedNames]. |
| 827 if (element == backend.interceptedNames) continue; | 855 if (element == backend.interceptedNames) continue; |
| 828 // `mapTypeToInterceptor` is handled in [emitMapTypeToInterceptor]. | 856 // `mapTypeToInterceptor` is handled in [emitMapTypeToInterceptor]. |
| 829 if (element == backend.mapTypeToInterceptor) continue; | 857 if (element == backend.mapTypeToInterceptor) continue; |
| 830 compiler.withCurrentElement(element, () { | 858 compiler.withCurrentElement(element, () { |
| 831 Constant initialValue = handler.getInitialValueFor(element); | 859 Constant initialValue = handler.getInitialValueFor(element); |
| 832 jsAst.Expression init = | 860 jsAst.Expression init = |
| 833 js('$isolateProperties.# = #', | 861 js('$isolateProperties.${namer.getNameOfGlobalField(element)} = #', |
| 834 [namer.getNameOfGlobalField(element), | 862 constantEmitter.referenceInInitializationContext(initialValue)); |
| 835 constantEmitter.referenceInInitializationContext(initialValue)]); | |
| 836 buffer.write(jsAst.prettyPrint(init, compiler)); | 863 buffer.write(jsAst.prettyPrint(init, compiler)); |
| 837 buffer.write('$N'); | 864 buffer.write('$N'); |
| 838 }); | 865 }); |
| 839 } | 866 } |
| 840 } | 867 } |
| 841 | 868 |
| 842 void emitLazilyInitializedStaticFields(CodeBuffer buffer) { | 869 void emitLazilyInitializedStaticFields(CodeBuffer buffer) { |
| 843 JavaScriptConstantCompiler handler = backend.constants; | 870 JavaScriptConstantCompiler handler = backend.constants; |
| 844 List<VariableElement> lazyFields = | 871 List<VariableElement> lazyFields = |
| 845 handler.getLazilyInitializedFieldsForEmission(); | 872 handler.getLazilyInitializedFieldsForEmission(); |
| 846 if (!lazyFields.isEmpty) { | 873 if (!lazyFields.isEmpty) { |
| 847 needsLazyInitializer = true; | 874 needsLazyInitializer = true; |
| 848 for (VariableElement element in Elements.sortedByPosition(lazyFields)) { | 875 for (VariableElement element in Elements.sortedByPosition(lazyFields)) { |
| 849 jsAst.Expression code = backend.generatedCode[element]; | 876 jsAst.Expression code = backend.generatedCode[element]; |
| 850 // The code is null if we ended up not needing the lazily | 877 // The code is null if we ended up not needing the lazily |
| 851 // initialized field after all because of constant folding | 878 // initialized field after all because of constant folding |
| 852 // before code generation. | 879 // before code generation. |
| 853 if (code == null) continue; | 880 if (code == null) continue; |
| 854 // The code only computes the initial value. We build the lazy-check | 881 // The code only computes the initial value. We build the lazy-check |
| 855 // here: | 882 // here: |
| 856 // lazyInitializer(prototype, 'name', fieldName, getterName, initial); | 883 // lazyInitializer(prototype, 'name', fieldName, getterName, initial); |
| 857 // The name is used for error reporting. The 'initial' must be a | 884 // The name is used for error reporting. The 'initial' must be a |
| 858 // closure that constructs the initial value. | 885 // closure that constructs the initial value. |
| 886 List<jsAst.Expression> arguments = <jsAst.Expression>[]; |
| 887 arguments.add(js(isolateProperties)); |
| 888 arguments.add(js.string(element.name)); |
| 889 arguments.add(js.string(namer.getNameX(element))); |
| 890 arguments.add(js.string(namer.getLazyInitializerName(element))); |
| 891 arguments.add(code); |
| 859 jsAst.Expression getter = buildLazyInitializedGetter(element); | 892 jsAst.Expression getter = buildLazyInitializedGetter(element); |
| 860 jsAst.Expression init = js('#(#,#,#,#,#,#)', | 893 if (getter != null) { |
| 861 [js(lazyInitializerName), | 894 arguments.add(getter); |
| 862 js(isolateProperties), | 895 } |
| 863 js.string(element.name), | 896 jsAst.Expression init = js(lazyInitializerName)(arguments); |
| 864 js.string(namer.getNameX(element)), | |
| 865 js.string(namer.getLazyInitializerName(element)), | |
| 866 code, | |
| 867 getter == null ? [] : [getter]]); | |
| 868 buffer.write(jsAst.prettyPrint(init, compiler)); | 897 buffer.write(jsAst.prettyPrint(init, compiler)); |
| 869 buffer.write("$N"); | 898 buffer.write("$N"); |
| 870 } | 899 } |
| 871 } | 900 } |
| 872 } | 901 } |
| 873 | 902 |
| 874 jsAst.Expression buildLazyInitializedGetter(VariableElement element) { | 903 jsAst.Expression buildLazyInitializedGetter(VariableElement element) { |
| 875 // Nothing to do, the 'lazy' function will create the getter. | 904 // Nothing to do, the 'lazy' function will create the getter. |
| 876 return null; | 905 return null; |
| 877 } | 906 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 892 && constantUnit == null) { | 921 && constantUnit == null) { |
| 893 // The back-end introduces some constants, like "InterceptorConstant" or | 922 // The back-end introduces some constants, like "InterceptorConstant" or |
| 894 // some list constants. They are emitted in the main output-unit, and | 923 // some list constants. They are emitted in the main output-unit, and |
| 895 // ignored otherwise. | 924 // ignored otherwise. |
| 896 // TODO(sigurdm): We should track those constants. | 925 // TODO(sigurdm): We should track those constants. |
| 897 continue; | 926 continue; |
| 898 } | 927 } |
| 899 | 928 |
| 900 String name = namer.constantName(constant); | 929 String name = namer.constantName(constant); |
| 901 if (constant.isList) emitMakeConstantListIfNotEmitted(buffer); | 930 if (constant.isList) emitMakeConstantListIfNotEmitted(buffer); |
| 902 jsAst.Expression init = js('#.# = #', | 931 jsAst.Expression init = js( |
| 903 [namer.globalObjectForConstant(constant), name, | 932 '${namer.globalObjectForConstant(constant)}.$name = #', |
| 904 constantInitializerExpression(constant)]); | 933 constantInitializerExpression(constant)); |
| 905 buffer.write(jsAst.prettyPrint(init, compiler)); | 934 buffer.write(jsAst.prettyPrint(init, compiler)); |
| 906 buffer.write('$N'); | 935 buffer.write('$N'); |
| 907 } | 936 } |
| 908 } | 937 } |
| 909 | 938 |
| 910 bool isConstantInlinedOrAlreadyEmitted(Constant constant) { | 939 bool isConstantInlinedOrAlreadyEmitted(Constant constant) { |
| 911 if (constant.isFunction) return true; // Already emitted. | 940 if (constant.isFunction) return true; // Already emitted. |
| 912 if (constant.isPrimitive) return true; // Inlined. | 941 if (constant.isPrimitive) return true; // Inlined. |
| 913 if (constant.isDummy) return true; // Inlined. | 942 if (constant.isDummy) return true; // Inlined. |
| 914 // The name is null when the constant is already a JS constant. | 943 // The name is null when the constant is already a JS constant. |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1158 } else { | 1187 } else { |
| 1159 outputClassLists.putIfAbsent( | 1188 outputClassLists.putIfAbsent( |
| 1160 compiler.deferredLoadTask.outputUnitForElement(element), | 1189 compiler.deferredLoadTask.outputUnitForElement(element), |
| 1161 () => new List<ClassElement>()) | 1190 () => new List<ClassElement>()) |
| 1162 .add(element); | 1191 .add(element); |
| 1163 } | 1192 } |
| 1164 } | 1193 } |
| 1165 } | 1194 } |
| 1166 | 1195 |
| 1167 void emitInitFunction(CodeBuffer buffer) { | 1196 void emitInitFunction(CodeBuffer buffer) { |
| 1168 jsAst.FunctionDeclaration decl = js.statement(''' | 1197 jsAst.Fun fun = js.fun([], [ |
| 1169 function init() { | 1198 js('$isolateProperties = {}'), |
| 1170 $isolateProperties = {}; | 1199 ] |
| 1171 #; #; #; | 1200 ..addAll(buildDefineClassAndFinishClassFunctionsIfNecessary()) |
| 1172 }''', [ | 1201 ..addAll(buildLazyInitializerFunctionIfNecessary()) |
| 1173 buildDefineClassAndFinishClassFunctionsIfNecessary(), | 1202 ..addAll(buildFinishIsolateConstructor()) |
| 1174 buildLazyInitializerFunctionIfNecessary(), | 1203 ); |
| 1175 buildFinishIsolateConstructor()]); | 1204 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration( |
| 1176 | 1205 new jsAst.VariableDeclaration('init'), fun); |
| 1177 buffer.write(jsAst.prettyPrint(decl, compiler).getText()); | 1206 buffer.write(jsAst.prettyPrint(decl, compiler).getText()); |
| 1178 if (compiler.enableMinification) buffer.write('\n'); | 1207 if (compiler.enableMinification) buffer.write('\n'); |
| 1179 } | 1208 } |
| 1180 | 1209 |
| 1181 void emitConvertToFastObjectFunction() { | 1210 void emitConvertToFastObjectFunction() { |
| 1182 // Create an instance that uses 'properties' as prototype. This should make | 1211 // Create an instance that uses 'properties' as prototype. This should make |
| 1183 // 'properties' a fast object. | 1212 // 'properties' a fast object. |
| 1184 mainBuffer.add(r'''function convertToFastObject(properties) { | 1213 mainBuffer.add(r'''function convertToFastObject(properties) { |
| 1185 function MyClass() {}; | 1214 function MyClass() {}; |
| 1186 MyClass.prototype = properties; | 1215 MyClass.prototype = properties; |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1353 var keys = mangledFieldNames.keys.toList(); | 1382 var keys = mangledFieldNames.keys.toList(); |
| 1354 keys.sort(); | 1383 keys.sort(); |
| 1355 var properties = []; | 1384 var properties = []; |
| 1356 for (String key in keys) { | 1385 for (String key in keys) { |
| 1357 var value = js.string('${mangledFieldNames[key]}'); | 1386 var value = js.string('${mangledFieldNames[key]}'); |
| 1358 properties.add(new jsAst.Property(js.string(key), value)); | 1387 properties.add(new jsAst.Property(js.string(key), value)); |
| 1359 } | 1388 } |
| 1360 var map = new jsAst.ObjectInitializer(properties); | 1389 var map = new jsAst.ObjectInitializer(properties); |
| 1361 mainBuffer.write( | 1390 mainBuffer.write( |
| 1362 jsAst.prettyPrint( | 1391 jsAst.prettyPrint( |
| 1363 js.statement('init.mangledNames = #', map), compiler)); | 1392 js('init.mangledNames = #', map).toStatement(), compiler)); |
| 1364 if (compiler.enableMinification) { | 1393 if (compiler.enableMinification) { |
| 1365 mainBuffer.write(';'); | 1394 mainBuffer.write(';'); |
| 1366 } | 1395 } |
| 1367 } | 1396 } |
| 1368 if (!mangledGlobalFieldNames.isEmpty) { | 1397 if (!mangledGlobalFieldNames.isEmpty) { |
| 1369 var keys = mangledGlobalFieldNames.keys.toList(); | 1398 var keys = mangledGlobalFieldNames.keys.toList(); |
| 1370 keys.sort(); | 1399 keys.sort(); |
| 1371 var properties = []; | 1400 var properties = []; |
| 1372 for (String key in keys) { | 1401 for (String key in keys) { |
| 1373 var value = js.string('${mangledGlobalFieldNames[key]}'); | 1402 var value = js.string('${mangledGlobalFieldNames[key]}'); |
| 1374 properties.add(new jsAst.Property(js.string(key), value)); | 1403 properties.add(new jsAst.Property(js.string(key), value)); |
| 1375 } | 1404 } |
| 1376 var map = new jsAst.ObjectInitializer(properties); | 1405 var map = new jsAst.ObjectInitializer(properties); |
| 1377 mainBuffer.write( | 1406 mainBuffer.write( |
| 1378 jsAst.prettyPrint( | 1407 jsAst.prettyPrint( |
| 1379 js.statement('init.mangledGlobalNames = #', map), | 1408 js('init.mangledGlobalNames = #', map).toStatement(), |
| 1380 compiler)); | 1409 compiler)); |
| 1381 if (compiler.enableMinification) { | 1410 if (compiler.enableMinification) { |
| 1382 mainBuffer.write(';'); | 1411 mainBuffer.write(';'); |
| 1383 } | 1412 } |
| 1384 } | 1413 } |
| 1385 mainBuffer | 1414 mainBuffer |
| 1386 ..write('(') | 1415 ..write('(') |
| 1387 ..write( | 1416 ..write( |
| 1388 jsAst.prettyPrint( | 1417 jsAst.prettyPrint( |
| 1389 getReflectionDataParser(classesCollector, backend), | 1418 getReflectionDataParser(classesCollector, backend), |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1700 String sourceMap = sourceMapBuilder.build(); | 1729 String sourceMap = sourceMapBuilder.build(); |
| 1701 compiler.outputProvider(name, 'js.map') | 1730 compiler.outputProvider(name, 'js.map') |
| 1702 ..add(sourceMap) | 1731 ..add(sourceMap) |
| 1703 ..close(); | 1732 ..close(); |
| 1704 } | 1733 } |
| 1705 | 1734 |
| 1706 void registerReadTypeVariable(TypeVariableElement element) { | 1735 void registerReadTypeVariable(TypeVariableElement element) { |
| 1707 readTypeVariables.add(element); | 1736 readTypeVariables.add(element); |
| 1708 } | 1737 } |
| 1709 } | 1738 } |
| OLD | NEW |