| 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 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 // defineClassFunction (it's a local declaration in init()). | 263 // defineClassFunction (it's a local declaration in init()). |
| 264 return [ | 264 return [ |
| 265 generateAccessorFunction, | 265 generateAccessorFunction, |
| 266 js('$generateAccessorHolder = generateAccessor'), | 266 js('$generateAccessorHolder = generateAccessor'), |
| 267 new jsAst.FunctionDeclaration( | 267 new jsAst.FunctionDeclaration( |
| 268 new jsAst.VariableDeclaration('defineClass'), defineClass) ]; | 268 new jsAst.VariableDeclaration('defineClass'), defineClass) ]; |
| 269 } | 269 } |
| 270 | 270 |
| 271 /** Needs defineClass to be defined. */ | 271 /** Needs defineClass to be defined. */ |
| 272 List buildInheritFrom() { | 272 List buildInheritFrom() { |
| 273 return [ | 273 return [js(r''' |
| 274 js('var inheritFrom = #', | 274 var inheritFrom = function() { |
| 275 js.fun([], [ | 275 function tmp() {} |
| 276 new jsAst.FunctionDeclaration( | 276 var hasOwnProperty = Object.prototype.hasOwnProperty; |
| 277 new jsAst.VariableDeclaration('tmp'), js.fun([], [])), | 277 return function (constructor, superConstructor) { |
| 278 js('var hasOwnProperty = Object.prototype.hasOwnProperty'), | 278 tmp.prototype = superConstructor.prototype; |
| 279 js.return_(js.fun(['constructor', 'superConstructor'], [ | 279 var object = new tmp(); |
| 280 js('tmp.prototype = superConstructor.prototype'), | 280 var properties = constructor.prototype; |
| 281 js('var object = new tmp()'), | 281 for (var member in properties) |
| 282 js('var properties = constructor.prototype'), | 282 if (hasOwnProperty.call(properties, member)) |
| 283 js.forIn('member', 'properties', | 283 object[member] = properties[member]; |
| 284 js.if_('hasOwnProperty.call(properties, member)', | 284 object.constructor = constructor; |
| 285 js('object[member] = properties[member]'))), | 285 constructor.prototype = object; |
| 286 js('object.constructor = constructor'), | 286 return object; |
| 287 js('constructor.prototype = object'), | 287 }; |
| 288 js.return_('object') | 288 }() |
| 289 ]))])())]; | 289 ''')]; |
| 290 } | 290 } |
| 291 | 291 |
| 292 jsAst.Fun get finishClassesFunction { | 292 jsAst.Fun get finishClassesFunction { |
| 293 // Class descriptions are collected in a JS object. | 293 // Class descriptions are collected in a JS object. |
| 294 // 'finishClasses' takes all collected descriptions and sets up | 294 // 'finishClasses' takes all collected descriptions and sets up |
| 295 // the prototype. | 295 // the prototype. |
| 296 // Once set up, the constructors prototype field satisfy: | 296 // Once set up, the constructors prototype field satisfy: |
| 297 // - it contains all (local) members. | 297 // - it contains all (local) members. |
| 298 // - its internal prototype (__proto__) points to the superclass' | 298 // - its internal prototype (__proto__) points to the superclass' |
| 299 // prototype field. | 299 // prototype field. |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 378 ]), | 378 ]), |
| 379 ])), | 379 ])), |
| 380 | 380 |
| 381 js.if_('typeof dart_precompiled != "function"', | 381 js.if_('typeof dart_precompiled != "function"', |
| 382 [js('combinedConstructorFunction +=' | 382 [js('combinedConstructorFunction +=' |
| 383 ' defineClass(name, cls, fields)'), | 383 ' defineClass(name, cls, fields)'), |
| 384 js('constructorsList.push(cls)')]), | 384 js('constructorsList.push(cls)')]), |
| 385 js.if_('supr', js('pendingClasses[cls] = supr')) | 385 js.if_('supr', js('pendingClasses[cls] = supr')) |
| 386 ]) | 386 ]) |
| 387 ]), | 387 ]), |
| 388 js.if_('typeof dart_precompiled != "function"', | 388 js.statement(''' |
| 389 [js('combinedConstructorFunction +=' | 389 if (typeof dart_precompiled != "function") { |
| 390 ' "return [\\n " + constructorsList.join(",\\n ") + "\\n]"'), | 390 combinedConstructorFunction += |
| 391 js('var constructors =' | 391 "return [\\n " + constructorsList.join(",\\n ") + "\\n]"; |
| 392 ' new Function("\$collectedClasses", combinedConstructorFunction)' | 392 var constructors = |
| 393 '(collectedClasses)'), | 393 new Function("\$collectedClasses", combinedConstructorFunction) |
| 394 js('combinedConstructorFunction = null')]), | 394 (collectedClasses); |
| 395 combinedConstructorFunction = null; |
| 396 }'''), |
| 395 js.for_('var i = 0', 'i < constructors.length', 'i++', [ | 397 js.for_('var i = 0', 'i < constructors.length', 'i++', [ |
| 396 js('var constructor = constructors[i]'), | 398 js('var constructor = constructors[i]'), |
| 397 js('var cls = constructor.name'), | 399 js('var cls = constructor.name'), |
| 398 js('var desc = collectedClasses[cls]'), | 400 js('var desc = collectedClasses[cls]'), |
| 399 js('var globalObject = isolateProperties'), | 401 js('var globalObject = isolateProperties'), |
| 400 js.if_('desc instanceof Array', [ | 402 js.if_('desc instanceof Array', [ |
| 401 js('globalObject = desc[0] || isolateProperties'), | 403 js('globalObject = desc[0] || isolateProperties'), |
| 402 js('desc = desc[1]') | 404 js('desc = desc[1]') |
| 403 ]), | 405 ]), |
| 404 optional(backend.isTreeShakingDisabled, | 406 optional(backend.isTreeShakingDisabled, |
| 405 js('constructor["${namer.metadataField}"] = desc')), | 407 js('constructor["${namer.metadataField}"] = desc')), |
| 406 js('allClasses[cls] = constructor'), | 408 js('allClasses[cls] = constructor'), |
| 407 js('globalObject[cls] = constructor'), | 409 js('globalObject[cls] = constructor'), |
| 408 ]), | 410 ]), |
| 409 js('constructors = null'), | 411 js('constructors = null'), |
| 410 | 412 |
| 411 js('var finishedClasses = {}'), | 413 js('var finishedClasses = {}'), |
| 412 js('init.interceptorsByTag = Object.create(null)'), | 414 js('init.interceptorsByTag = Object.create(null)'), |
| 413 js('init.leafTags = {}'), | 415 js('init.leafTags = {}'), |
| 414 | 416 |
| 415 buildFinishClass(), | 417 buildFinishClass(), |
| 416 ]; | 418 ]; |
| 417 | 419 |
| 418 nsmEmitter.addTrivialNsmHandlers(statements); | 420 nsmEmitter.addTrivialNsmHandlers(statements); |
| 419 | 421 |
| 420 statements.add( | 422 statements.add( |
| 421 js.forIn('cls', 'pendingClasses', js('finishClass(cls)')) | 423 js.statement('for (var cls in pendingClasses) finishClass(cls);') |
| 422 ); | 424 ); |
| 425 |
| 423 // function(collectedClasses, | 426 // function(collectedClasses, |
| 424 // isolateProperties, | 427 // isolateProperties, |
| 425 // existingIsolateProperties) | 428 // existingIsolateProperties) |
| 426 return js.fun(['collectedClasses', 'isolateProperties', | 429 return js.fun(['collectedClasses', 'isolateProperties', |
| 427 'existingIsolateProperties'], statements); | 430 'existingIsolateProperties'], statements); |
| 428 } | 431 } |
| 429 | 432 |
| 430 jsAst.Node optional(bool condition, jsAst.Node node) { | 433 jsAst.Node optional(bool condition, jsAst.Node node) { |
| 431 return condition ? node : new jsAst.EmptyStatement(); | 434 return condition ? node : new jsAst.EmptyStatement(); |
| 432 } | 435 } |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 512 new jsAst.VariableDeclaration('finishClass'), | 515 new jsAst.VariableDeclaration('finishClass'), |
| 513 fun); | 516 fun); |
| 514 } | 517 } |
| 515 | 518 |
| 516 jsAst.Fun get finishIsolateConstructorFunction { | 519 jsAst.Fun get finishIsolateConstructorFunction { |
| 517 // 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 |
| 518 // 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. |
| 519 // | 522 // |
| 520 // We also copy over old values like the prototype, and the | 523 // We also copy over old values like the prototype, and the |
| 521 // isolateProperties themselves. | 524 // isolateProperties themselves. |
| 522 return js.fun('oldIsolate', [ | 525 return js(''' |
| 523 js('var isolateProperties = oldIsolate.${namer.isolatePropertiesName}'), | 526 function (oldIsolate) { |
| 524 new jsAst.FunctionDeclaration( | 527 var isolateProperties = oldIsolate.${namer.isolatePropertiesName}; |
| 525 new jsAst.VariableDeclaration('Isolate'), | 528 function Isolate() { |
| 526 js.fun([], [ | 529 var hasOwnProperty = Object.prototype.hasOwnProperty; |
| 527 js('var hasOwnProperty = Object.prototype.hasOwnProperty'), | 530 for (var staticName in isolateProperties) |
| 528 js.forIn('staticName', 'isolateProperties', | 531 if (hasOwnProperty.call(isolateProperties, staticName)) |
| 529 js.if_('hasOwnProperty.call(isolateProperties, staticName)', | 532 this[staticName] = isolateProperties[staticName]; |
| 530 js('this[staticName] = isolateProperties[staticName]'))), | 533 // Use the newly created object as prototype. In Chrome, |
| 531 // Use the newly created object as prototype. In Chrome, | 534 // this creates a hidden class for the object and makes |
| 532 // this creates a hidden class for the object and makes | 535 // sure it is fast to access. |
| 533 // sure it is fast to access. | 536 function ForceEfficientMap() {} |
| 534 new jsAst.FunctionDeclaration( | 537 ForceEfficientMap.prototype = this; |
| 535 new jsAst.VariableDeclaration('ForceEfficientMap'), | 538 new ForceEfficientMap(); |
| 536 js.fun([], [])), | 539 } |
| 537 js('ForceEfficientMap.prototype = this'), | 540 Isolate.prototype = oldIsolate.prototype; |
| 538 js('new ForceEfficientMap()')])), | 541 Isolate.prototype.constructor = Isolate; |
| 539 js('Isolate.prototype = oldIsolate.prototype'), | 542 Isolate.${namer.isolatePropertiesName} = isolateProperties; |
| 540 js('Isolate.prototype.constructor = Isolate'), | 543 # |
| 541 js('Isolate.${namer.isolatePropertiesName} = isolateProperties'), | 544 # |
| 542 optional(needsDefineClass, | 545 return Isolate; |
| 543 js('Isolate.$finishClassesProperty =' | 546 }''', |
| 544 ' oldIsolate.$finishClassesProperty')), | 547 [ optional(needsDefineClass, |
| 545 optional(hasMakeConstantList, | 548 js('Isolate.$finishClassesProperty =' |
| 546 js('Isolate.makeConstantList = oldIsolate.makeConstantList')), | 549 ' oldIsolate.$finishClassesProperty')), |
| 547 js.return_('Isolate')]); | 550 optional(hasMakeConstantList, |
| 551 js('Isolate.makeConstantList = oldIsolate.makeConstantList')) |
| 552 ]); |
| 548 } | 553 } |
| 549 | 554 |
| 550 jsAst.Fun get lazyInitializerFunction { | 555 jsAst.Fun get lazyInitializerFunction { |
| 551 // function(prototype, staticName, fieldName, getterName, lazyValue) { | 556 // function(prototype, staticName, fieldName, getterName, lazyValue) { |
| 552 var parameters = <String>['prototype', 'staticName', 'fieldName', | 557 var parameters = <String>['prototype', 'staticName', 'fieldName', |
| 553 'getterName', 'lazyValue']; | 558 'getterName', 'lazyValue']; |
| 554 return js.fun(parameters, addLazyInitializerLogic()); | 559 return js.fun(parameters, addLazyInitializerLogic()); |
| 555 } | 560 } |
| 556 | 561 |
| 557 List addLazyInitializerLogic() { | 562 List addLazyInitializerLogic() { |
| (...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 985 String mainAccess = "${namer.isolateStaticClosureAccess(appMain)}"; | 990 String mainAccess = "${namer.isolateStaticClosureAccess(appMain)}"; |
| 986 // Since we pass the closurized version of the main method to | 991 // Since we pass the closurized version of the main method to |
| 987 // the isolate method, we must make sure that it exists. | 992 // the isolate method, we must make sure that it exists. |
| 988 return "(function(a){${namer.isolateAccess(isolateMain)}($mainAccess,a)})"; | 993 return "(function(a){${namer.isolateAccess(isolateMain)}($mainAccess,a)})"; |
| 989 } | 994 } |
| 990 | 995 |
| 991 /** | 996 /** |
| 992 * Emits code that sets `init.isolateTag` to a unique string. | 997 * Emits code that sets `init.isolateTag` to a unique string. |
| 993 */ | 998 */ |
| 994 jsAst.Expression generateIsolateAffinityTagInitialization() { | 999 jsAst.Expression generateIsolateAffinityTagInitialization() { |
| 995 return js('!#', js.fun([], [ | 1000 return js(''' |
| 996 | 1001 !function() { |
| 997 // On V8, the 'intern' function converts a string to a symbol, which | 1002 // On V8, the 'intern' function converts a string to a symbol, which |
| 998 // makes property access much faster. | 1003 // makes property access much faster. |
| 999 new jsAst.FunctionDeclaration(new jsAst.VariableDeclaration('intern'), | 1004 function intern(s) { |
| 1000 js.fun(['s'], [ | 1005 var o = {}; |
| 1001 js('var o = {}'), | 1006 o[s] = 1; |
| 1002 js('o[s] = 1'), | 1007 return Object.keys(convertToFastObject(o))[0]; |
| 1003 js.return_(js('Object.keys(convertToFastObject(o))[0]'))])), | 1008 } |
| 1004 | 1009 |
| 1005 | 1010 init.getIsolateTag = function(name) { |
| 1006 js('init.getIsolateTag = #', | 1011 return intern("___dart_" + name + init.isolateTag); |
| 1007 js.fun(['name'], | 1012 }; |
| 1008 js.return_('intern("___dart_" + name + init.isolateTag)'))), | |
| 1009 | 1013 |
| 1010 // To ensure that different programs loaded into the same context (page) | 1014 // To ensure that different programs loaded into the same context (page) |
| 1011 // use distinct dispatch properies, we place an object on `Object` to | 1015 // use distinct dispatch properies, we place an object on `Object` to |
| 1012 // contain the names already in use. | 1016 // contain the names already in use. |
| 1013 js('var tableProperty = "___dart_isolate_tags_"'), | 1017 var tableProperty = "___dart_isolate_tags_"; |
| 1014 js('var usedProperties = Object[tableProperty] ||' | 1018 var usedProperties = Object[tableProperty] || |
| 1015 '(Object[tableProperty] = Object.create(null))'), | 1019 (Object[tableProperty] = Object.create(null)); |
| 1016 | 1020 |
| 1017 js('var rootProperty = "_${generateIsolateTagRoot()}"'), | 1021 var rootProperty = "_${generateIsolateTagRoot()}"; |
| 1018 js.for_('var i = 0', null, 'i++', [ | 1022 for (var i = 0; ; i++) { |
| 1019 js('var property = intern(rootProperty + "_" + i + "_")'), | 1023 var property = intern(rootProperty + "_" + i + "_"); |
| 1020 js.if_('!(property in usedProperties)', [ | 1024 if (!(property in usedProperties)) { |
| 1021 js('usedProperties[property] = 1'), | 1025 usedProperties[property] = 1; |
| 1022 js('init.isolateTag = property'), | 1026 init.isolateTag = property; |
| 1023 new jsAst.Break(null)])])]) | 1027 break; |
| 1024 ()); | 1028 } |
| 1025 | 1029 } |
| 1030 }() |
| 1031 '''); |
| 1026 } | 1032 } |
| 1027 | 1033 |
| 1028 jsAst.Expression generateDispatchPropertyNameInitialization() { | 1034 jsAst.Expression generateDispatchPropertyNameInitialization() { |
| 1029 return js( | 1035 return js( |
| 1030 'init.dispatchPropertyName = init.getIsolateTag("dispatch_record")'); | 1036 'init.dispatchPropertyName = init.getIsolateTag("dispatch_record")'); |
| 1031 } | 1037 } |
| 1032 | 1038 |
| 1033 String generateIsolateTagRoot() { | 1039 String generateIsolateTagRoot() { |
| 1034 // TODO(sra): MD5 of contributing source code or URIs? | 1040 // TODO(sra): MD5 of contributing source code or URIs? |
| 1035 return 'ZxYxX'; | 1041 return 'ZxYxX'; |
| (...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1399 var map = new jsAst.ObjectInitializer(properties); | 1405 var map = new jsAst.ObjectInitializer(properties); |
| 1400 mainBuffer.write( | 1406 mainBuffer.write( |
| 1401 jsAst.prettyPrint( | 1407 jsAst.prettyPrint( |
| 1402 js('init.mangledGlobalNames = #', map).toStatement(), | 1408 js('init.mangledGlobalNames = #', map).toStatement(), |
| 1403 compiler)); | 1409 compiler)); |
| 1404 if (compiler.enableMinification) { | 1410 if (compiler.enableMinification) { |
| 1405 mainBuffer.write(';'); | 1411 mainBuffer.write(';'); |
| 1406 } | 1412 } |
| 1407 } | 1413 } |
| 1408 mainBuffer | 1414 mainBuffer |
| 1409 ..write(getReflectionDataParser(classesCollector, backend)) | 1415 ..write('(') |
| 1416 ..write( |
| 1417 jsAst.prettyPrint( |
| 1418 getReflectionDataParser(classesCollector, backend), |
| 1419 compiler)) |
| 1420 ..write(')') |
| 1410 ..write('([$n'); | 1421 ..write('([$n'); |
| 1411 | 1422 |
| 1412 List<Element> sortedElements = | 1423 List<Element> sortedElements = |
| 1413 Elements.sortedByPosition(elementDescriptors.keys); | 1424 Elements.sortedByPosition(elementDescriptors.keys); |
| 1414 | 1425 |
| 1415 Iterable<Element> pendingStatics = sortedElements.where((element) { | 1426 Iterable<Element> pendingStatics = sortedElements.where((element) { |
| 1416 return !element.isLibrary() && | 1427 return !element.isLibrary() && |
| 1417 elementDescriptors[element].values.any((descriptor) => | 1428 elementDescriptors[element].values.any((descriptor) => |
| 1418 descriptor != null); | 1429 descriptor != null); |
| 1419 }); | 1430 }); |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1657 ..write('var old${namer.currentIsolate}$_=' | 1668 ..write('var old${namer.currentIsolate}$_=' |
| 1658 '$_${namer.currentIsolate}$N' | 1669 '$_${namer.currentIsolate}$N' |
| 1659 // TODO(ahe): This defines a lot of properties on the | 1670 // TODO(ahe): This defines a lot of properties on the |
| 1660 // Isolate.prototype object. We know this will turn it into a | 1671 // Isolate.prototype object. We know this will turn it into a |
| 1661 // slow object in V8, so instead we should do something similar | 1672 // slow object in V8, so instead we should do something similar |
| 1662 // to Isolate.$finishIsolateConstructor. | 1673 // to Isolate.$finishIsolateConstructor. |
| 1663 '${namer.currentIsolate}$_=' | 1674 '${namer.currentIsolate}$_=' |
| 1664 '$_${namer.isolateName}.prototype$N$n' | 1675 '$_${namer.isolateName}.prototype$N$n' |
| 1665 // The classesCollector object ($$). | 1676 // The classesCollector object ($$). |
| 1666 '$classesCollector$_=$_{};$n') | 1677 '$classesCollector$_=$_{};$n') |
| 1667 ..write(getReflectionDataParser(classesCollector, backend)) | 1678 ..write('(') |
| 1679 ..write( |
| 1680 jsAst.prettyPrint( |
| 1681 getReflectionDataParser(classesCollector, backend), |
| 1682 compiler)) |
| 1683 ..write(')') |
| 1668 ..write('([$n') | 1684 ..write('([$n') |
| 1669 ..addBuffer(outputBuffer) | 1685 ..addBuffer(outputBuffer) |
| 1670 ..write('])$N'); | 1686 ..write('])$N'); |
| 1671 | 1687 |
| 1672 if (outputClassLists.containsKey(outputUnit)) { | 1688 if (outputClassLists.containsKey(outputUnit)) { |
| 1673 buffer.write( | 1689 buffer.write( |
| 1674 '$finishClassesName($classesCollector,$_${namer.currentIsolate},' | 1690 '$finishClassesName($classesCollector,$_${namer.currentIsolate},' |
| 1675 '$_$isolatePropertiesName)$N'); | 1691 '$_$isolatePropertiesName)$N'); |
| 1676 } | 1692 } |
| 1677 | 1693 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1713 String sourceMap = sourceMapBuilder.build(); | 1729 String sourceMap = sourceMapBuilder.build(); |
| 1714 compiler.outputProvider(name, 'js.map') | 1730 compiler.outputProvider(name, 'js.map') |
| 1715 ..add(sourceMap) | 1731 ..add(sourceMap) |
| 1716 ..close(); | 1732 ..close(); |
| 1717 } | 1733 } |
| 1718 | 1734 |
| 1719 void registerReadTypeVariable(TypeVariableElement element) { | 1735 void registerReadTypeVariable(TypeVariableElement element) { |
| 1720 readTypeVariables.add(element); | 1736 readTypeVariables.add(element); |
| 1721 } | 1737 } |
| 1722 } | 1738 } |
| OLD | NEW |