Chromium Code Reviews| 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 /// Enables debugging of fast/slow objects using V8-specific primitives. | 7 /// Enables debugging of fast/slow objects using V8-specific primitives. |
| 8 const DEBUG_FAST_OBJECTS = false; | 8 const DEBUG_FAST_OBJECTS = false; |
| 9 | 9 |
| 10 /** | 10 /** |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 83 typedef void FunctionTypeTestEmitter(FunctionType functionType); | 83 typedef void FunctionTypeTestEmitter(FunctionType functionType); |
| 84 typedef void SubstitutionEmitter(Element element, {bool emitNull}); | 84 typedef void SubstitutionEmitter(Element element, {bool emitNull}); |
| 85 | 85 |
| 86 /** | 86 /** |
| 87 * Generates the code for all used classes in the program. Static fields (even | 87 * Generates the code for all used classes in the program. Static fields (even |
| 88 * in classes) are ignored, since they can be treated as non-class elements. | 88 * in classes) are ignored, since they can be treated as non-class elements. |
| 89 * | 89 * |
| 90 * The code for the containing (used) methods must exist in the [:universe:]. | 90 * The code for the containing (used) methods must exist in the [:universe:]. |
| 91 */ | 91 */ |
| 92 class CodeEmitterTask extends CompilerTask { | 92 class CodeEmitterTask extends CompilerTask { |
| 93 bool needsInheritFunction = false; | |
| 94 bool needsDefineClass = false; | 93 bool needsDefineClass = false; |
| 95 bool needsMixinSupport = false; | 94 bool needsMixinSupport = false; |
| 96 bool needsLazyInitializer = false; | 95 bool needsLazyInitializer = false; |
| 97 final Namer namer; | 96 final Namer namer; |
| 98 ConstantEmitter constantEmitter; | 97 ConstantEmitter constantEmitter; |
| 99 NativeEmitter nativeEmitter; | 98 NativeEmitter nativeEmitter; |
| 100 CodeBuffer mainBuffer; | 99 CodeBuffer mainBuffer; |
| 101 final CodeBuffer deferredLibraries = new CodeBuffer(); | 100 final CodeBuffer deferredLibraries = new CodeBuffer(); |
| 102 final CodeBuffer deferredConstants = new CodeBuffer(); | 101 final CodeBuffer deferredConstants = new CodeBuffer(); |
| 103 /** Shorter access to [isolatePropertiesName]. Both here in the code, as | 102 /** Shorter access to [isolatePropertiesName]. Both here in the code, as |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 161 */ | 160 */ |
| 162 Set<FunctionType> checkedFunctionTypes; | 161 Set<FunctionType> checkedFunctionTypes; |
| 163 | 162 |
| 164 Map<ClassElement, Set<FunctionType>> checkedGenericFunctionTypes = | 163 Map<ClassElement, Set<FunctionType>> checkedGenericFunctionTypes = |
| 165 new Map<ClassElement, Set<FunctionType>>(); | 164 new Map<ClassElement, Set<FunctionType>>(); |
| 166 | 165 |
| 167 Set<FunctionType> checkedNonGenericFunctionTypes = | 166 Set<FunctionType> checkedNonGenericFunctionTypes = |
| 168 new Set<FunctionType>(); | 167 new Set<FunctionType>(); |
| 169 | 168 |
| 170 /** | 169 /** |
| 170 * List of expressions and statements that will be included in the | |
| 171 * precompiled function. | |
| 172 * | |
| 173 * To save space, dart2js normally generates constructors and accessors | |
| 174 * dynamically. This doesn't work in CSP mode, and may impact startup time | |
| 175 * negatively. So dart2js will emit these functions to a separate file that | |
| 176 * can be optionally included to support CSP mode or for faster startup. | |
| 177 */ | |
| 178 List<jsAst.Node> precompiledFunction = <jsAst.Node>[]; | |
| 179 | |
| 180 List<jsAst.Expression> precompiledConstructorNames = <jsAst.Expression>[]; | |
| 181 | |
| 182 // True if Isolate.makeConstantList is needed. | |
| 183 bool hasMakeConstantList = false; | |
| 184 | |
| 185 /** | |
| 171 * For classes and libraries, record code for static/top-level members. | 186 * For classes and libraries, record code for static/top-level members. |
| 172 * Later, this code is emitted when the class or library is emitted. | 187 * Later, this code is emitted when the class or library is emitted. |
| 173 * See [bufferForElement]. | 188 * See [bufferForElement]. |
| 174 */ | 189 */ |
| 175 // TODO(ahe): Generate statics with their class, and store only libraries in | 190 // TODO(ahe): Generate statics with their class, and store only libraries in |
| 176 // this map. | 191 // this map. |
| 177 final Map<Element, List<CodeBuffer>> elementBuffers = | 192 final Map<Element, List<CodeBuffer>> elementBuffers = |
| 178 new Map<Element, List<CodeBuffer>>(); | 193 new Map<Element, List<CodeBuffer>>(); |
| 179 | 194 |
| 180 void registerDynamicFunctionTypeCheck(FunctionType functionType) { | 195 void registerDynamicFunctionTypeCheck(FunctionType functionType) { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 256 String get generateAccessorHolder | 271 String get generateAccessorHolder |
| 257 => '$isolatePropertiesName.\$generateAccessor'; | 272 => '$isolatePropertiesName.\$generateAccessor'; |
| 258 String get finishClassesProperty | 273 String get finishClassesProperty |
| 259 => r'$finishClasses'; | 274 => r'$finishClasses'; |
| 260 String get finishClassesName | 275 String get finishClassesName |
| 261 => '${namer.isolateName}.$finishClassesProperty'; | 276 => '${namer.isolateName}.$finishClassesProperty'; |
| 262 String get finishIsolateConstructorName | 277 String get finishIsolateConstructorName |
| 263 => '${namer.isolateName}.\$finishIsolateConstructor'; | 278 => '${namer.isolateName}.\$finishIsolateConstructor'; |
| 264 String get isolatePropertiesName | 279 String get isolatePropertiesName |
| 265 => '${namer.isolateName}.${namer.isolatePropertiesName}'; | 280 => '${namer.isolateName}.${namer.isolatePropertiesName}'; |
| 266 String get supportsProtoName | |
| 267 => 'supportsProto'; | |
| 268 String get lazyInitializerName | 281 String get lazyInitializerName |
| 269 => '${namer.isolateName}.\$lazy'; | 282 => '${namer.isolateName}.\$lazy'; |
| 270 | 283 |
| 271 // Compact field specifications. The format of the field specification is | 284 // Compact field specifications. The format of the field specification is |
| 272 // <accessorName>:<fieldName><suffix> where the suffix and accessor name | 285 // <accessorName>:<fieldName><suffix> where the suffix and accessor name |
| 273 // prefix are optional. The suffix directs the generation of getter and | 286 // prefix are optional. The suffix directs the generation of getter and |
| 274 // setter methods. Each of the getter and setter has two bits to determine | 287 // setter methods. Each of the getter and setter has two bits to determine |
| 275 // the calling convention. Setter listed below, getter is similar. | 288 // the calling convention. Setter listed below, getter is similar. |
| 276 // | 289 // |
| 277 // 00: no setter | 290 // 00: no setter |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 420 // Declare a function called "generateAccessor". This is used in | 433 // Declare a function called "generateAccessor". This is used in |
| 421 // defineClassFunction (it's a local declaration in init()). | 434 // defineClassFunction (it's a local declaration in init()). |
| 422 return [ | 435 return [ |
| 423 generateAccessorFunction, | 436 generateAccessorFunction, |
| 424 js('$generateAccessorHolder = generateAccessor'), | 437 js('$generateAccessorHolder = generateAccessor'), |
| 425 new jsAst.FunctionDeclaration( | 438 new jsAst.FunctionDeclaration( |
| 426 new jsAst.VariableDeclaration('defineClass'), defineClass) ]; | 439 new jsAst.VariableDeclaration('defineClass'), defineClass) ]; |
| 427 } | 440 } |
| 428 | 441 |
| 429 /** Needs defineClass to be defined. */ | 442 /** Needs defineClass to be defined. */ |
| 430 List buildProtoSupportCheck() { | 443 List buildInheritFrom() { |
| 431 // On Firefox and Webkit browsers we can manipulate the __proto__ | |
| 432 // directly. Opera claims to have __proto__ support, but it is buggy. | |
| 433 // So we have to do more checks. | |
| 434 // Opera bug was filed as DSK-370158, and fixed as CORE-47615 | |
| 435 // (http://my.opera.com/desktopteam/blog/2012/07/20/more-12-01-fixes). | |
| 436 // If the browser does not support __proto__ we need to instantiate an | |
| 437 // object with the correct (internal) prototype set up correctly, and then | |
| 438 // copy the members. | |
| 439 // TODO(8541): Remove this work around. | |
| 440 | |
| 441 return [ | 444 return [ |
| 442 js('var $supportsProtoName = false'), | 445 js('var inheritFrom = #', |
| 443 // js('var tmp = defineClass("c", "c", ["f<"], {}).prototype'), | 446 js.fun([], [ |
| 444 // | 447 new jsAst.FunctionDeclaration( |
| 445 // js.if_(js('tmp.__proto__'), [ | 448 new jsAst.VariableDeclaration('tmp'), js.fun([], [])), |
| 446 // js('tmp.__proto__ = {}'), | 449 js('var hasOwnProperty = Object.prototype.hasOwnProperty'), |
| 447 // js.if_(js(r'typeof tmp.get$f != "undefined"'), | 450 js.return_(js.fun(['constructor', 'superConstructor'], [ |
| 448 // js('$supportsProtoName = true')) | 451 js('tmp.prototype = superConstructor.prototype'), |
| 449 // ]) | 452 js('var object = new tmp()'), |
| 450 ]; | 453 js('var properties = constructor.prototype'), |
| 454 js.forIn('member', 'properties', | |
| 455 js.if_('hasOwnProperty.call(properties, member)', | |
| 456 js('object[member] = properties[member]'))), | |
| 457 js('object.constructor = constructor'), | |
| 458 js('constructor.prototype = object'), | |
| 459 js.return_('object') | |
| 460 ]))])())]; | |
| 451 } | 461 } |
| 452 | 462 |
| 453 static const MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING = 4; | 463 static const MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING = 4; |
| 454 | 464 |
| 455 // If we need fewer than this many noSuchMethod handlers we can save space by | 465 // If we need fewer than this many noSuchMethod handlers we can save space by |
| 456 // just emitting them in JS, rather than emitting the JS needed to generate | 466 // just emitting them in JS, rather than emitting the JS needed to generate |
| 457 // them at run time. | 467 // them at run time. |
| 458 static const VERY_FEW_NO_SUCH_METHOD_HANDLERS = 10; | 468 static const VERY_FEW_NO_SUCH_METHOD_HANDLERS = 10; |
| 459 | 469 |
| 460 /** | 470 /** |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 695 // For engines where we have access to the '__proto__' we can manipulate | 705 // For engines where we have access to the '__proto__' we can manipulate |
| 696 // the object literal directly. For other engines we have to create a new | 706 // the object literal directly. For other engines we have to create a new |
| 697 // object and copy over the members. | 707 // object and copy over the members. |
| 698 | 708 |
| 699 String reflectableField = namer.reflectableField; | 709 String reflectableField = namer.reflectableField; |
| 700 List<jsAst.Node> statements = [ | 710 List<jsAst.Node> statements = [ |
| 701 js('var pendingClasses = {}'), | 711 js('var pendingClasses = {}'), |
| 702 js.if_('!init.allClasses', js('init.allClasses = {}')), | 712 js.if_('!init.allClasses', js('init.allClasses = {}')), |
| 703 js('var allClasses = init.allClasses'), | 713 js('var allClasses = init.allClasses'), |
| 704 | 714 |
| 705 js('var hasOwnProperty = Object.prototype.hasOwnProperty'), | |
| 706 js('var combinedConstructorFunction = ' | |
| 707 '"function \$reflectable(fn){fn.$reflectableField=1;return fn};\\n"' | |
| 708 '+ "var \$desc;\\n"'), | |
| 709 js('var constructorsList = []'), | |
| 710 | |
| 711 optional( | 715 optional( |
| 712 DEBUG_FAST_OBJECTS, | 716 DEBUG_FAST_OBJECTS, |
| 713 js('print("Number of classes: "' | 717 js('print("Number of classes: "' |
| 714 r' + Object.getOwnPropertyNames($$).length)')), | 718 r' + Object.getOwnPropertyNames($$).length)')), |
| 715 | 719 |
| 720 js('var hasOwnProperty = Object.prototype.hasOwnProperty'), | |
| 721 | |
| 722 js.if_('typeof dart_precompiled == "function"', | |
| 723 [js('var constructors = dart_precompiled(collectedClasses)')], | |
| 724 | |
| 725 [js('var combinedConstructorFunction = "function \$reflectable(fn){' | |
| 726 'fn.$reflectableField=1;return fn};\\n"+ "var \$desc;\\n"'), | |
| 727 js('var constructorsList = []')]), | |
| 716 js.forIn('cls', 'collectedClasses', [ | 728 js.forIn('cls', 'collectedClasses', [ |
| 717 js.if_('hasOwnProperty.call(collectedClasses, cls)', [ | 729 js.if_('hasOwnProperty.call(collectedClasses, cls)', [ |
| 718 js('var desc = collectedClasses[cls]'), | 730 js('var desc = collectedClasses[cls]'), |
| 719 js.if_('desc instanceof Array', js('desc = desc[1]')), | 731 js.if_('desc instanceof Array', js('desc = desc[1]')), |
| 720 | 732 |
| 721 /* The 'fields' are either a constructor function or a | 733 /* The 'fields' are either a constructor function or a |
| 722 * string encoding fields, constructor and superclass. Get | 734 * string encoding fields, constructor and superclass. Get |
| 723 * the superclass and the fields in the format | 735 * the superclass and the fields in the format |
| 724 * '[name/]Super;field1,field2' | 736 * '[name/]Super;field1,field2' |
| 725 * from the null-string property on the descriptor. | 737 * from the null-string property on the descriptor. |
| 726 * The 'name/' is optional and contains the name that should be used | 738 * The 'name/' is optional and contains the name that should be used |
| 727 * when printing the runtime type string. It is used, for example, to | 739 * when printing the runtime type string. It is used, for example, to |
| 728 * print the runtime type JSInt as 'int'. | 740 * print the runtime type JSInt as 'int'. |
| 729 */ | 741 */ |
| 730 js('var classData = desc[""], supr, name = cls, fields = classData'), | 742 js('var classData = desc[""], supr, name = cls, fields = classData'), |
| 731 optional( | 743 optional( |
| 732 backend.hasRetainedMetadata, | 744 backend.hasRetainedMetadata, |
| 733 js.if_('typeof classData == "object" && ' | 745 js.if_('typeof classData == "object" && ' |
| 734 'classData instanceof Array', | 746 'classData instanceof Array', |
| 735 [js('classData = fields = classData[0]')])), | 747 [js('classData = fields = classData[0]')])), |
| 736 | 748 |
| 737 js.if_('typeof classData == "string"', [ | 749 js.if_('typeof classData == "string"', [ |
| 738 js('var split = classData.split("/")'), | 750 js('var split = classData.split("/")'), |
| 739 js.if_('split.length == 2', [ | 751 js.if_('split.length == 2', [ |
| 740 js('name = split[0]'), | 752 js('name = split[0]'), |
| 741 js('fields = split[1]') | 753 js('fields = split[1]') |
| 742 ]) | 754 ]) |
| 743 ]), | 755 ]), |
| 744 | 756 |
| 745 js.if_('typeof fields == "string"', [ | 757 js('var s = fields.split(";")'), |
| 746 js('var s = fields.split(";")'), | 758 js('fields = s[1] == "" ? [] : s[1].split(",")'), |
| 747 js('fields = s[1] == "" ? [] : s[1].split(",")'), | 759 js('supr = s[0]'), |
| 748 js('supr = s[0]'), | |
| 749 ], /* else */ [ | |
| 750 js('supr = desc.super'), | |
| 751 js.if_(r'!!desc.$name', js(r'name = desc.$name')) | |
| 752 ]), | |
| 753 | 760 |
| 754 optional(needsMixinSupport, js.if_('supr && supr.indexOf("+") > 0', [ | 761 optional(needsMixinSupport, js.if_('supr && supr.indexOf("+") > 0', [ |
| 755 js('s = supr.split("+")'), | 762 js('s = supr.split("+")'), |
| 756 js('supr = s[0]'), | 763 js('supr = s[0]'), |
| 757 js('var mixin = collectedClasses[s[1]]'), | 764 js('var mixin = collectedClasses[s[1]]'), |
| 758 js.if_('mixin instanceof Array', js('mixin = mixin[1]')), | 765 js.if_('mixin instanceof Array', js('mixin = mixin[1]')), |
| 759 js.forIn('d', 'mixin', [ | 766 js.forIn('d', 'mixin', [ |
| 760 js.if_('hasOwnProperty.call(mixin, d)' | 767 js.if_('hasOwnProperty.call(mixin, d)' |
| 761 '&& !hasOwnProperty.call(desc, d)', | 768 '&& !hasOwnProperty.call(desc, d)', |
| 762 js('desc[d] = mixin[d]')) | 769 js('desc[d] = mixin[d]')) |
| 763 ]), | 770 ]), |
| 764 ])), | 771 ])), |
| 765 | 772 |
| 766 js('combinedConstructorFunction += defineClass(name, cls, fields)'), | 773 js.if_('typeof dart_precompiled != "function"', |
| 767 js('constructorsList.push(cls)'), | 774 [js('combinedConstructorFunction +=' |
| 775 ' defineClass(name, cls, fields)'), | |
| 776 js('constructorsList.push(cls)')]), | |
| 768 js.if_('supr', js('pendingClasses[cls] = supr')) | 777 js.if_('supr', js('pendingClasses[cls] = supr')) |
| 769 ]) | 778 ]) |
| 770 ]), | 779 ]), |
| 771 js('combinedConstructorFunction +=' | 780 js.if_('typeof dart_precompiled != "function"', |
| 772 ' "return [\\n " + constructorsList.join(",\\n ") + "\\n]"'), | 781 [js('combinedConstructorFunction +=' |
| 773 js('var constructors =' | 782 ' "return [\\n " + constructorsList.join(",\\n ") + "\\n]"'), |
| 774 ' new Function("\$collectedClasses", combinedConstructorFunction)' | 783 js('var constructors =' |
| 775 '(collectedClasses)'), | 784 ' new Function("\$collectedClasses", combinedConstructorFunction)' |
| 776 js('combinedConstructorFunction = null'), | 785 '(collectedClasses)'), |
| 786 js('combinedConstructorFunction = null')]), | |
| 777 js.for_('var i = 0', 'i < constructors.length', 'i++', [ | 787 js.for_('var i = 0', 'i < constructors.length', 'i++', [ |
| 778 js('var constructor = constructors[i]'), | 788 js('var constructor = constructors[i]'), |
| 779 js('var cls = constructor.name'), | 789 js('var cls = constructor.name'), |
| 780 js('var desc = collectedClasses[cls]'), | 790 js('var desc = collectedClasses[cls]'), |
| 781 js('var globalObject = isolateProperties'), | 791 js('var globalObject = isolateProperties'), |
| 782 js.if_('desc instanceof Array', [ | 792 js.if_('desc instanceof Array', [ |
| 783 js('globalObject = desc[0] || isolateProperties'), | 793 js('globalObject = desc[0] || isolateProperties'), |
| 784 js('desc = desc[1]') | 794 js('desc = desc[1]') |
| 785 ]), | 795 ]), |
| 786 optional(backend.isTreeShakingDisabled, | 796 optional(backend.isTreeShakingDisabled, |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 834 // we have a string. | 844 // we have a string. |
| 835 js.if_('!superclass || typeof superclass != "string"', js.return_()), | 845 js.if_('!superclass || typeof superclass != "string"', js.return_()), |
| 836 js('finishClass(superclass)'), | 846 js('finishClass(superclass)'), |
| 837 js('var constructor = allClasses[cls]'), | 847 js('var constructor = allClasses[cls]'), |
| 838 js('var superConstructor = allClasses[superclass]'), | 848 js('var superConstructor = allClasses[superclass]'), |
| 839 | 849 |
| 840 js.if_(js('!superConstructor'), | 850 js.if_(js('!superConstructor'), |
| 841 js('superConstructor =' | 851 js('superConstructor =' |
| 842 'existingIsolateProperties[superclass]')), | 852 'existingIsolateProperties[superclass]')), |
| 843 | 853 |
| 844 js('var prototype = constructor.prototype'), | 854 js('prototype = inheritFrom(constructor, superConstructor)'), |
| 845 | |
| 846 // if ($supportsProtoName) { | |
| 847 js.if_(supportsProtoName, [ | |
| 848 js('prototype.__proto__ = superConstructor.prototype'), | |
| 849 js('prototype.constructor = constructor'), | |
| 850 | |
| 851 ], /* else */ [ | |
| 852 // function tmp() {}; | |
| 853 new jsAst.FunctionDeclaration( | |
| 854 new jsAst.VariableDeclaration('tmp'), | |
| 855 js.fun([], [])), | |
| 856 | |
| 857 js('tmp.prototype = superConstructor.prototype'), | |
| 858 js('var newPrototype = new tmp()'), | |
| 859 | |
| 860 js('constructor.prototype = newPrototype'), | |
| 861 js('newPrototype.constructor = constructor'), | |
| 862 | |
| 863 // for (var member in prototype) { | |
| 864 js.forIn('member', 'prototype', [ | |
| 865 /* Short version of: if (member == '') */ | |
| 866 // if (!member) continue; | |
| 867 js.if_('!member', new jsAst.Continue(null)), | |
| 868 | |
| 869 // if (hasOwnProperty.call(prototype, member)) { | |
| 870 js.if_('hasOwnProperty.call(prototype, member)', [ | |
| 871 js('newPrototype[member] = prototype[member]') | |
| 872 ]) | |
| 873 ]) | |
| 874 | |
| 875 ]) | |
| 876 ]); | 855 ]); |
| 877 | 856 |
| 878 return new jsAst.FunctionDeclaration( | 857 return new jsAst.FunctionDeclaration( |
| 879 new jsAst.VariableDeclaration('finishClass'), | 858 new jsAst.VariableDeclaration('finishClass'), |
| 880 fun); | 859 fun); |
| 881 } | 860 } |
| 882 | 861 |
| 883 jsAst.Fun get finishIsolateConstructorFunction { | 862 jsAst.Fun get finishIsolateConstructorFunction_NO_CSP { |
|
ngeoffray
2013/09/24 08:15:29
Is that dead code?
ahe
2013/09/24 14:05:09
Yes, removed in https://codereview.chromium.org/24
| |
| 884 String isolate = namer.isolateName; | 863 String isolate = namer.isolateName; |
| 885 // We replace the old Isolate function with a new one that initializes | 864 // We replace the old Isolate function with a new one that initializes |
| 886 // all its field with the initial (and often final) value of all globals. | 865 // all its field with the initial (and often final) value of all globals. |
| 887 // This has two advantages: | 866 // This has two advantages: |
| 888 // 1. the properties are in the object itself (thus avoiding to go through | 867 // 1. the properties are in the object itself (thus avoiding to go through |
| 889 // the prototype when looking up globals. | 868 // the prototype when looking up globals. |
| 890 // 2. a new isolate goes through a (usually well optimized) constructor | 869 // 2. a new isolate goes through a (usually well optimized) constructor |
| 891 // function of the form: "function() { this.x = ...; this.y = ...; }". | 870 // function of the form: "function() { this.x = ...; this.y = ...; }". |
| 892 // | 871 // |
| 893 // Example: If [isolateProperties] is an object containing: x = 3 and | 872 // Example: If [isolateProperties] is an object containing: x = 3 and |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 937 // TODO(ahe): Only copy makeConstantList when it is used. | 916 // TODO(ahe): Only copy makeConstantList when it is used. |
| 938 js('newIsolate.makeConstantList = oldIsolate.makeConstantList'), | 917 js('newIsolate.makeConstantList = oldIsolate.makeConstantList'), |
| 939 ]..addAll(copyFinishClasses) | 918 ]..addAll(copyFinishClasses) |
| 940 ..addAll([ | 919 ..addAll([ |
| 941 | 920 |
| 942 // return newIsolate; | 921 // return newIsolate; |
| 943 js.return_('newIsolate') | 922 js.return_('newIsolate') |
| 944 ])); | 923 ])); |
| 945 } | 924 } |
| 946 | 925 |
| 926 jsAst.Fun get finishIsolateConstructorFunction { | |
| 927 // We replace the old Isolate function with a new one that initializes | |
| 928 // all its fields with the initial (and often final) value of all globals. | |
| 929 // | |
| 930 // We also copy over old values like the prototype, and the | |
| 931 // isolateProperties themselves. | |
| 932 return js.fun('oldIsolate', [ | |
| 933 js('var isolateProperties = oldIsolate.${namer.isolatePropertiesName}'), | |
| 934 new jsAst.FunctionDeclaration( | |
| 935 new jsAst.VariableDeclaration('Isolate'), | |
| 936 js.fun([], [ | |
| 937 js('var hasOwnProperty = Object.prototype.hasOwnProperty'), | |
| 938 js.forIn('staticName', 'isolateProperties', | |
| 939 js.if_('hasOwnProperty.call(isolateProperties, staticName)', | |
| 940 js('this[staticName] = isolateProperties[staticName]'))), | |
| 941 // Use the newly created object as prototype. In Chrome, | |
| 942 // this creates a hidden class for the object and makes | |
| 943 // sure it is fast to access. | |
| 944 new jsAst.FunctionDeclaration( | |
| 945 new jsAst.VariableDeclaration('ForceEfficientMap'), | |
| 946 js.fun([], [])), | |
| 947 js('ForceEfficientMap.prototype = this'), | |
| 948 js('new ForceEfficientMap()')])), | |
| 949 js('Isolate.prototype = oldIsolate.prototype'), | |
| 950 js('Isolate.prototype.constructor = Isolate'), | |
| 951 js('Isolate.${namer.isolatePropertiesName} = isolateProperties'), | |
| 952 optional(needsDefineClass, | |
| 953 js('Isolate.$finishClassesProperty =' | |
| 954 ' oldIsolate.$finishClassesProperty')), | |
| 955 optional(hasMakeConstantList, | |
| 956 js('Isolate.makeConstantList = oldIsolate.makeConstantList')), | |
| 957 js.return_('Isolate')]); | |
| 958 } | |
| 959 | |
| 947 jsAst.Fun get lazyInitializerFunction { | 960 jsAst.Fun get lazyInitializerFunction { |
| 948 // function(prototype, staticName, fieldName, getterName, lazyValue) { | 961 // function(prototype, staticName, fieldName, getterName, lazyValue) { |
| 949 var parameters = <String>['prototype', 'staticName', 'fieldName', | 962 var parameters = <String>['prototype', 'staticName', 'fieldName', |
| 950 'getterName', 'lazyValue']; | 963 'getterName', 'lazyValue']; |
| 951 return js.fun(parameters, [ | 964 return js.fun(parameters, addLazyInitializerLogic()); |
| 952 js('var getter = new Function("{ return this." + fieldName + ";}")'), | |
| 953 ]..addAll(addLazyInitializerLogic()) | |
| 954 ); | |
| 955 } | 965 } |
| 956 | 966 |
| 957 List addLazyInitializerLogic() { | 967 List addLazyInitializerLogic() { |
| 958 String isolate = namer.CURRENT_ISOLATE; | 968 String isolate = namer.CURRENT_ISOLATE; |
| 959 String cyclicThrow = namer.isolateAccess(backend.getCyclicThrowHelper()); | 969 String cyclicThrow = namer.isolateAccess(backend.getCyclicThrowHelper()); |
| 960 var lazies = []; | 970 var lazies = []; |
| 961 if (backend.rememberLazies) { | 971 if (backend.rememberLazies) { |
| 962 lazies = [ | 972 lazies = [ |
| 963 js.if_('!init.lazies', js('init.lazies = {}')), | 973 js.if_('!init.lazies', js('init.lazies = {}')), |
| 964 js('init.lazies[fieldName] = getterName')]; | 974 js('init.lazies[fieldName] = getterName')]; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 997 ], /* else */ [ | 1007 ], /* else */ [ |
| 998 js.if_('result === sentinelInProgress', | 1008 js.if_('result === sentinelInProgress', |
| 999 js('$cyclicThrow(staticName)') | 1009 js('$cyclicThrow(staticName)') |
| 1000 ) | 1010 ) |
| 1001 ]), | 1011 ]), |
| 1002 | 1012 |
| 1003 // return result; | 1013 // return result; |
| 1004 js.return_('result') | 1014 js.return_('result') |
| 1005 | 1015 |
| 1006 ], finallyPart: [ | 1016 ], finallyPart: [ |
| 1007 js('$isolate[getterName] = getter') | 1017 js('$isolate[getterName] = #', |
| 1018 js.fun([], [js.return_('this[fieldName]')])) | |
| 1008 ]) | 1019 ]) |
| 1009 ])) | 1020 ])) |
| 1010 ]); | 1021 ]); |
| 1011 } | 1022 } |
| 1012 | 1023 |
| 1013 List buildDefineClassAndFinishClassFunctionsIfNecessary() { | 1024 List buildDefineClassAndFinishClassFunctionsIfNecessary() { |
| 1014 if (!needsDefineClass) return []; | 1025 if (!needsDefineClass) return []; |
| 1015 return defineClassFunction | 1026 return defineClassFunction |
| 1016 ..addAll(buildProtoSupportCheck()) | 1027 ..addAll(buildInheritFrom()) |
| 1017 ..addAll([ | 1028 ..addAll([ |
| 1018 js('$finishClassesName = #', finishClassesFunction) | 1029 js('$finishClassesName = #', finishClassesFunction) |
| 1019 ]); | 1030 ]); |
| 1020 } | 1031 } |
| 1021 | 1032 |
| 1022 List buildLazyInitializerFunctionIfNecessary() { | 1033 List buildLazyInitializerFunctionIfNecessary() { |
| 1023 if (!needsLazyInitializer) return []; | 1034 if (!needsLazyInitializer) return []; |
| 1024 | 1035 |
| 1025 return [js('$lazyInitializerName = #', lazyInitializerFunction)]; | 1036 return [js('$lazyInitializerName = #', lazyInitializerFunction)]; |
| 1026 } | 1037 } |
| (...skipping 675 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1702 if (reflectionName != null) { | 1713 if (reflectionName != null) { |
| 1703 var reflectable = | 1714 var reflectable = |
| 1704 js(backend.isAccessibleByReflection(member) ? '1' : '0'); | 1715 js(backend.isAccessibleByReflection(member) ? '1' : '0'); |
| 1705 builder.addProperty('+$reflectionName', reflectable); | 1716 builder.addProperty('+$reflectionName', reflectable); |
| 1706 } | 1717 } |
| 1707 } | 1718 } |
| 1708 | 1719 |
| 1709 void generateGetter(Element member, String fieldName, String accessorName, | 1720 void generateGetter(Element member, String fieldName, String accessorName, |
| 1710 ClassBuilder builder) { | 1721 ClassBuilder builder) { |
| 1711 String getterName = namer.getterNameFromAccessorName(accessorName); | 1722 String getterName = namer.getterNameFromAccessorName(accessorName); |
| 1712 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) | 1723 ClassElement cls = member.getEnclosingClass(); |
| 1713 ? 'receiver' : 'this'; | 1724 String className = namer.getNameOfClass(cls); |
| 1714 List<String> args = backend.isInterceptedMethod(member) | 1725 String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this'; |
| 1715 ? ['receiver'] | 1726 List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : []; |
| 1716 : []; | 1727 precompiledFunction.add( |
| 1717 builder.addProperty(getterName, | 1728 js('$className.prototype.$getterName = #', |
| 1718 js.fun(args, js.return_(js('$receiver.$fieldName')))); | 1729 js.fun(args, js.return_(js('$receiver.$fieldName'))))); |
| 1719 generateReflectionDataForFieldGetterOrSetter( | 1730 if (backend.isNeededForReflection(member)) { |
| 1720 member, getterName, builder, isGetter: true); | 1731 precompiledFunction.add( |
| 1732 js('$className.prototype.$getterName.${namer.reflectableField} = 1')); | |
| 1733 } | |
| 1721 } | 1734 } |
| 1722 | 1735 |
| 1723 void generateSetter(Element member, String fieldName, String accessorName, | 1736 void generateSetter(Element member, String fieldName, String accessorName, |
| 1724 ClassBuilder builder) { | 1737 ClassBuilder builder) { |
| 1725 String setterName = namer.setterNameFromAccessorName(accessorName); | 1738 String setterName = namer.setterNameFromAccessorName(accessorName); |
| 1726 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) | 1739 ClassElement cls = member.getEnclosingClass(); |
| 1727 ? 'receiver' : 'this'; | 1740 String className = namer.getNameOfClass(cls); |
| 1728 List<String> args = backend.isInterceptedMethod(member) | 1741 String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this'; |
| 1729 ? ['receiver', 'v'] | 1742 List<String> args = |
| 1730 : ['v']; | 1743 backend.isInterceptedMethod(member) ? ['receiver', 'v'] : ['v']; |
| 1731 builder.addProperty(setterName, | 1744 precompiledFunction.add( |
| 1732 js.fun(args, js('$receiver.$fieldName = v'))); | 1745 js('$className.prototype.$setterName = #', |
| 1733 generateReflectionDataForFieldGetterOrSetter( | 1746 js.fun(args, js.return_(js('$receiver.$fieldName = v'))))); |
| 1734 member, setterName, builder, isGetter: false); | 1747 if (backend.isNeededForReflection(member)) { |
| 1748 precompiledFunction.add( | |
| 1749 js('$className.prototype.$setterName.${namer.reflectableField} = 1')); | |
| 1750 } | |
| 1735 } | 1751 } |
| 1736 | 1752 |
| 1737 bool canGenerateCheckedSetter(VariableElement field) { | 1753 bool canGenerateCheckedSetter(VariableElement field) { |
| 1738 // We never generate accessors for top-level/static fields. | 1754 // We never generate accessors for top-level/static fields. |
| 1739 if (!field.isInstanceMember()) return false; | 1755 if (!field.isInstanceMember()) return false; |
| 1740 DartType type = field.computeType(compiler).unalias(compiler); | 1756 DartType type = field.computeType(compiler).unalias(compiler); |
| 1741 if (type.element.isTypeVariable() || | 1757 if (type.element.isTypeVariable() || |
| 1742 (type is FunctionType && type.containsTypeVariables) || | 1758 (type is FunctionType && type.containsTypeVariables) || |
| 1743 type.treatAsDynamic || | 1759 type.treatAsDynamic || |
| 1744 type.element == compiler.objectClass) { | 1760 type.element == compiler.objectClass) { |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 1774 List<String> args = backend.isInterceptedMethod(member) | 1790 List<String> args = backend.isInterceptedMethod(member) |
| 1775 ? ['receiver', 'v'] | 1791 ? ['receiver', 'v'] |
| 1776 : ['v']; | 1792 : ['v']; |
| 1777 builder.addProperty(setterName, | 1793 builder.addProperty(setterName, |
| 1778 js.fun(args, | 1794 js.fun(args, |
| 1779 js('$receiver.$fieldName = #', js(helperName)(arguments)))); | 1795 js('$receiver.$fieldName = #', js(helperName)(arguments)))); |
| 1780 generateReflectionDataForFieldGetterOrSetter( | 1796 generateReflectionDataForFieldGetterOrSetter( |
| 1781 member, setterName, builder, isGetter: false); | 1797 member, setterName, builder, isGetter: false); |
| 1782 } | 1798 } |
| 1783 | 1799 |
| 1784 void emitClassConstructor(ClassElement classElement, ClassBuilder builder) { | 1800 void emitClassConstructor(ClassElement classElement, |
| 1785 /* Do nothing. */ | 1801 ClassBuilder builder, |
| 1802 String runtimeName) { | |
| 1803 List<String> fields = <String>[]; | |
| 1804 if (!classElement.isNative()) { | |
| 1805 visitFields(classElement, false, | |
| 1806 (Element member, | |
| 1807 String name, | |
| 1808 String accessorName, | |
| 1809 bool needsGetter, | |
| 1810 bool needsSetter, | |
| 1811 bool needsCheckedSetter) { | |
| 1812 fields.add(name); | |
| 1813 }); | |
| 1814 } | |
| 1815 String constructorName = namer.getNameOfClass(classElement); | |
| 1816 precompiledFunction.add(new jsAst.FunctionDeclaration( | |
| 1817 new jsAst.VariableDeclaration(constructorName), | |
| 1818 js.fun(fields, fields.map( | |
| 1819 (name) => js('this.$name = $name')).toList()))); | |
| 1820 if (runtimeName == null) { | |
| 1821 runtimeName = constructorName; | |
| 1822 } | |
| 1823 precompiledFunction.addAll([ | |
| 1824 js('$constructorName.builtin\$cls = "$runtimeName"'), | |
| 1825 js.if_('!"name" in $constructorName', | |
| 1826 js('$constructorName.name = "$constructorName"')), | |
| 1827 js('\$desc=\$collectedClasses.$constructorName'), | |
| 1828 js.if_('\$desc instanceof Array', js('\$desc = \$desc[1]')), | |
| 1829 js('$constructorName.prototype = \$desc'), | |
| 1830 ]); | |
| 1831 | |
| 1832 precompiledConstructorNames.add(js(constructorName)); | |
| 1833 } | |
| 1834 | |
| 1835 jsAst.FunctionDeclaration buildPrecompiledFunction() { | |
| 1836 // TODO(ahe): Compute a hash code. | |
| 1837 String name = 'dart_precompiled'; | |
| 1838 | |
| 1839 precompiledFunction.add( | |
| 1840 js.return_( | |
| 1841 new jsAst.ArrayInitializer.from(precompiledConstructorNames))); | |
| 1842 precompiledFunction.insert(0, js(r'var $desc')); | |
| 1843 return new jsAst.FunctionDeclaration( | |
| 1844 new jsAst.VariableDeclaration(name), | |
| 1845 js.fun([r'$collectedClasses'], precompiledFunction)); | |
| 1786 } | 1846 } |
| 1787 | 1847 |
| 1788 void emitSuper(String superName, ClassBuilder builder) { | 1848 void emitSuper(String superName, ClassBuilder builder) { |
| 1789 /* Do nothing. */ | 1849 /* Do nothing. */ |
| 1790 } | 1850 } |
| 1791 | 1851 |
| 1792 void emitRuntimeName(String runtimeName, ClassBuilder builder) { | 1852 void emitRuntimeName(String runtimeName, ClassBuilder builder) { |
| 1793 /* Do nothing. */ | 1853 /* Do nothing. */ |
| 1794 } | 1854 } |
| 1795 | 1855 |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1959 String name, | 2019 String name, |
| 1960 String accessorName, | 2020 String accessorName, |
| 1961 bool needsGetter, | 2021 bool needsGetter, |
| 1962 bool needsSetter, | 2022 bool needsSetter, |
| 1963 bool needsCheckedSetter) { | 2023 bool needsCheckedSetter) { |
| 1964 compiler.withCurrentElement(member, () { | 2024 compiler.withCurrentElement(member, () { |
| 1965 if (needsCheckedSetter) { | 2025 if (needsCheckedSetter) { |
| 1966 assert(!needsSetter); | 2026 assert(!needsSetter); |
| 1967 generateCheckedSetter(member, name, accessorName, builder); | 2027 generateCheckedSetter(member, name, accessorName, builder); |
| 1968 } | 2028 } |
| 1969 if (!getterAndSetterCanBeImplementedByFieldSpec) { | 2029 if (needsGetter) { |
| 1970 if (needsGetter) { | 2030 generateGetter(member, name, accessorName, builder); |
| 1971 generateGetter(member, name, accessorName, builder); | 2031 } |
| 1972 } | 2032 if (needsSetter) { |
| 1973 if (needsSetter) { | 2033 generateSetter(member, name, accessorName, builder); |
| 1974 generateSetter(member, name, accessorName, builder); | |
| 1975 } | |
| 1976 } | 2034 } |
| 1977 }); | 2035 }); |
| 1978 }); | 2036 }); |
| 1979 } | 2037 } |
| 1980 | 2038 |
| 1981 /** | 2039 /** |
| 1982 * Documentation wanted -- johnniwinther | 2040 * Documentation wanted -- johnniwinther |
| 1983 * | 2041 * |
| 1984 * Invariant: [classElement] must be a declaration element. | 2042 * Invariant: [classElement] must be a declaration element. |
| 1985 */ | 2043 */ |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 2000 String runtimeName = | 2058 String runtimeName = |
| 2001 namer.getPrimitiveInterceptorRuntimeName(classElement); | 2059 namer.getPrimitiveInterceptorRuntimeName(classElement); |
| 2002 | 2060 |
| 2003 if (classElement.isMixinApplication) { | 2061 if (classElement.isMixinApplication) { |
| 2004 String mixinName = namer.getNameOfClass(computeMixinClass(classElement)); | 2062 String mixinName = namer.getNameOfClass(computeMixinClass(classElement)); |
| 2005 superName = '$superName+$mixinName'; | 2063 superName = '$superName+$mixinName'; |
| 2006 needsMixinSupport = true; | 2064 needsMixinSupport = true; |
| 2007 } | 2065 } |
| 2008 | 2066 |
| 2009 ClassBuilder builder = new ClassBuilder(); | 2067 ClassBuilder builder = new ClassBuilder(); |
| 2010 emitClassConstructor(classElement, builder); | 2068 emitClassConstructor(classElement, builder, runtimeName); |
| 2011 emitSuper(superName, builder); | 2069 emitSuper(superName, builder); |
| 2012 emitRuntimeName(runtimeName, builder); | 2070 emitRuntimeName(runtimeName, builder); |
| 2013 emitFields(classElement, builder, superName, onlyForRti: onlyForRti); | 2071 emitFields(classElement, builder, superName, onlyForRti: onlyForRti); |
| 2014 emitClassGettersSetters(classElement, builder); | 2072 emitClassGettersSetters(classElement, builder); |
| 2015 if (!classElement.isMixinApplication) { | 2073 if (!classElement.isMixinApplication) { |
| 2016 emitInstanceMembers(classElement, builder); | 2074 emitInstanceMembers(classElement, builder); |
| 2017 } | 2075 } |
| 2018 emitIsTests(classElement, builder); | 2076 emitIsTests(classElement, builder); |
| 2019 | 2077 |
| 2020 emitClassBuilderWithReflectionData( | 2078 emitClassBuilderWithReflectionData( |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2068 String reflectionName = getReflectionName(classElement, className); | 2126 String reflectionName = getReflectionName(classElement, className); |
| 2069 if (reflectionName != null) { | 2127 if (reflectionName != null) { |
| 2070 List<int> interfaces = <int>[]; | 2128 List<int> interfaces = <int>[]; |
| 2071 for (DartType interface in classElement.interfaces) { | 2129 for (DartType interface in classElement.interfaces) { |
| 2072 interfaces.add(reifyType(interface)); | 2130 interfaces.add(reifyType(interface)); |
| 2073 } | 2131 } |
| 2074 buffer.write(',$n$n"+$reflectionName": $interfaces'); | 2132 buffer.write(',$n$n"+$reflectionName": $interfaces'); |
| 2075 } | 2133 } |
| 2076 } | 2134 } |
| 2077 | 2135 |
| 2078 bool get getterAndSetterCanBeImplementedByFieldSpec => true; | |
| 2079 | |
| 2080 /// If this is true then we can generate the noSuchMethod handlers at startup | 2136 /// If this is true then we can generate the noSuchMethod handlers at startup |
| 2081 /// time, instead of them being emitted as part of the Object class. | 2137 /// time, instead of them being emitted as part of the Object class. |
| 2082 bool get generateTrivialNsmHandlers => true; | 2138 bool get generateTrivialNsmHandlers => true; |
| 2083 | 2139 |
| 2084 int _selectorRank(Selector selector) { | 2140 int _selectorRank(Selector selector) { |
| 2085 int arity = selector.argumentCount * 3; | 2141 int arity = selector.argumentCount * 3; |
| 2086 if (selector.isGetter()) return arity + 2; | 2142 if (selector.isGetter()) return arity + 2; |
| 2087 if (selector.isSetter()) return arity + 1; | 2143 if (selector.isSetter()) return arity + 1; |
| 2088 return arity; | 2144 return arity; |
| 2089 } | 2145 } |
| (...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2486 emitFunctionTypeSignature, emitIsFunctionTypeTest); | 2542 emitFunctionTypeSignature, emitIsFunctionTypeTest); |
| 2487 } | 2543 } |
| 2488 } | 2544 } |
| 2489 | 2545 |
| 2490 void emitClosureClassHeader(String mangledName, | 2546 void emitClosureClassHeader(String mangledName, |
| 2491 String superName, | 2547 String superName, |
| 2492 List<String> fieldNames, | 2548 List<String> fieldNames, |
| 2493 ClassBuilder builder) { | 2549 ClassBuilder builder) { |
| 2494 builder.addProperty('', | 2550 builder.addProperty('', |
| 2495 js.string("$superName;${fieldNames.join(',')}")); | 2551 js.string("$superName;${fieldNames.join(',')}")); |
| 2552 | |
| 2553 List<String> fields = fieldNames; | |
| 2554 String constructorName = mangledName; | |
| 2555 precompiledFunction.add(new jsAst.FunctionDeclaration( | |
| 2556 new jsAst.VariableDeclaration(constructorName), | |
| 2557 js.fun(fields, fields.map( | |
| 2558 (name) => js('this.$name = $name')).toList()))); | |
| 2559 precompiledFunction.addAll([ | |
| 2560 js('$constructorName.builtin\$cls = "$constructorName"'), | |
| 2561 js('\$desc=\$collectedClasses.$constructorName'), | |
| 2562 js.if_('\$desc instanceof Array', js('\$desc = \$desc[1]')), | |
| 2563 js('$constructorName.prototype = \$desc'), | |
| 2564 ]); | |
| 2565 | |
| 2566 precompiledConstructorNames.add(js(constructorName)); | |
| 2496 } | 2567 } |
| 2497 | 2568 |
| 2498 /** | 2569 /** |
| 2499 * Documentation wanted -- johnniwinther | 2570 * Documentation wanted -- johnniwinther |
| 2500 * | 2571 * |
| 2501 * Invariant: [member] must be a declaration element. | 2572 * Invariant: [member] must be a declaration element. |
| 2502 */ | 2573 */ |
| 2503 void emitDynamicFunctionGetter(FunctionElement member, | 2574 void emitDynamicFunctionGetter(FunctionElement member, |
| 2504 DefineStubFunction defineStub) { | 2575 DefineStubFunction defineStub) { |
| 2505 assert(invariant(member, member.isDeclaration)); | 2576 assert(invariant(member, member.isDeclaration)); |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2785 | 2856 |
| 2786 jsAst.Expression buildLazyInitializedGetter(VariableElement element) { | 2857 jsAst.Expression buildLazyInitializedGetter(VariableElement element) { |
| 2787 // Nothing to do, the 'lazy' function will create the getter. | 2858 // Nothing to do, the 'lazy' function will create the getter. |
| 2788 return null; | 2859 return null; |
| 2789 } | 2860 } |
| 2790 | 2861 |
| 2791 void emitCompileTimeConstants(CodeBuffer eagerBuffer) { | 2862 void emitCompileTimeConstants(CodeBuffer eagerBuffer) { |
| 2792 ConstantHandler handler = compiler.constantHandler; | 2863 ConstantHandler handler = compiler.constantHandler; |
| 2793 List<Constant> constants = handler.getConstantsForEmission( | 2864 List<Constant> constants = handler.getConstantsForEmission( |
| 2794 compareConstants); | 2865 compareConstants); |
| 2795 bool addedMakeConstantList = false; | |
| 2796 for (Constant constant in constants) { | 2866 for (Constant constant in constants) { |
| 2797 if (isConstantInlinedOrAlreadyEmitted(constant)) continue; | 2867 if (isConstantInlinedOrAlreadyEmitted(constant)) continue; |
| 2798 String name = namer.constantName(constant); | 2868 String name = namer.constantName(constant); |
| 2799 if (!addedMakeConstantList && constant.isList()) { | 2869 if (constant.isList()) emitMakeConstantListIfNotEmitted(eagerBuffer); |
| 2800 addedMakeConstantList = true; | |
| 2801 emitMakeConstantList(eagerBuffer); | |
| 2802 } | |
| 2803 CodeBuffer buffer = bufferForConstant(constant, eagerBuffer); | 2870 CodeBuffer buffer = bufferForConstant(constant, eagerBuffer); |
| 2804 jsAst.Expression init = js( | 2871 jsAst.Expression init = js( |
| 2805 '${namer.globalObjectForConstant(constant)}.$name = #', | 2872 '${namer.globalObjectForConstant(constant)}.$name = #', |
| 2806 constantInitializerExpression(constant)); | 2873 constantInitializerExpression(constant)); |
| 2807 buffer.write(jsAst.prettyPrint(init, compiler)); | 2874 buffer.write(jsAst.prettyPrint(init, compiler)); |
| 2808 buffer.write('$N'); | 2875 buffer.write('$N'); |
| 2809 } | 2876 } |
| 2810 } | 2877 } |
| 2811 | 2878 |
| 2812 bool isConstantInlinedOrAlreadyEmitted(Constant constant) { | 2879 bool isConstantInlinedOrAlreadyEmitted(Constant constant) { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 2827 if (cmp1 + cmp2 < 2) return cmp1 - cmp2; | 2894 if (cmp1 + cmp2 < 2) return cmp1 - cmp2; |
| 2828 // Sorting by the long name clusters constants with the same constructor | 2895 // Sorting by the long name clusters constants with the same constructor |
| 2829 // which compresses a tiny bit better. | 2896 // which compresses a tiny bit better. |
| 2830 int r = namer.constantLongName(a).compareTo(namer.constantLongName(b)); | 2897 int r = namer.constantLongName(a).compareTo(namer.constantLongName(b)); |
| 2831 if (r != 0) return r; | 2898 if (r != 0) return r; |
| 2832 // Resolve collisions in the long name by using the constant name (i.e. JS | 2899 // Resolve collisions in the long name by using the constant name (i.e. JS |
| 2833 // name) which is unique. | 2900 // name) which is unique. |
| 2834 return namer.constantName(a).compareTo(namer.constantName(b)); | 2901 return namer.constantName(a).compareTo(namer.constantName(b)); |
| 2835 } | 2902 } |
| 2836 | 2903 |
| 2837 void emitMakeConstantList(CodeBuffer buffer) { | 2904 void emitMakeConstantListIfNotEmitted(CodeBuffer buffer) { |
| 2838 buffer.write(namer.isolateName); | 2905 if (hasMakeConstantList) return; |
| 2839 buffer.write(r'''.makeConstantList = function(list) { | 2906 hasMakeConstantList = true; |
| 2907 buffer | |
| 2908 ..write(namer.isolateName) | |
| 2909 ..write(r'''.makeConstantList = function(list) { | |
| 2840 list.immutable$list = true; | 2910 list.immutable$list = true; |
| 2841 list.fixed$length = true; | 2911 list.fixed$length = true; |
| 2842 return list; | 2912 return list; |
| 2843 }; | 2913 }; |
| 2844 '''); | 2914 '''); |
| 2845 } | 2915 } |
| 2846 | 2916 |
| 2847 /** | 2917 /** |
| 2848 * Documentation wanted -- johnniwinther | 2918 * Documentation wanted -- johnniwinther |
| 2849 * | 2919 * |
| (...skipping 900 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3750 buffer.write(metadata); | 3820 buffer.write(metadata); |
| 3751 } | 3821 } |
| 3752 } else { | 3822 } else { |
| 3753 throw 'Unexpected value in metadata: ${Error.safeToString(metadata)}'; | 3823 throw 'Unexpected value in metadata: ${Error.safeToString(metadata)}'; |
| 3754 } | 3824 } |
| 3755 buffer.write(',$n'); | 3825 buffer.write(',$n'); |
| 3756 } | 3826 } |
| 3757 buffer.write('];$n'); | 3827 buffer.write('];$n'); |
| 3758 } | 3828 } |
| 3759 | 3829 |
| 3760 void emitConvertToFastObjectFunction() { | 3830 void emitConvertToFastObjectFunction_NO_CSP() { |
|
ngeoffray
2013/09/24 08:15:29
Ditto
| |
| 3761 mainBuffer.add(r''' | 3831 mainBuffer.add(r''' |
| 3762 function convertToFastObject(properties) { | 3832 function convertToFastObject(properties) { |
| 3763 function makeConstructor() { | 3833 function makeConstructor() { |
| 3764 var str = "{\n"; | 3834 var str = "{\n"; |
| 3765 var hasOwnProperty = Object.prototype.hasOwnProperty; | 3835 var hasOwnProperty = Object.prototype.hasOwnProperty; |
| 3766 for (var property in properties) { | 3836 for (var property in properties) { |
| 3767 if (hasOwnProperty.call(properties, property)) { | 3837 if (hasOwnProperty.call(properties, property)) { |
| 3768 str += "this." + property + "= properties." + property + ";\n"; | 3838 str += "this." + property + "= properties." + property + ";\n"; |
| 3769 } | 3839 } |
| 3770 } | 3840 } |
| 3771 str += "}\n"; | 3841 str += "}\n"; |
| 3772 return new Function("properties", str); | 3842 return new Function("properties", str); |
| 3773 }; | 3843 }; |
| 3774 var constructor = makeConstructor(); | 3844 var constructor = makeConstructor(); |
| 3775 return makeConstructor.prototype = new constructor(properties); | 3845 return makeConstructor.prototype = new constructor(properties); |
| 3776 } | 3846 } |
| 3777 '''); | 3847 '''); |
| 3778 } | 3848 } |
| 3779 | 3849 |
| 3850 void emitConvertToFastObjectFunction() { | |
| 3851 // Create an instance that uses 'properties' as prototype. This should make | |
| 3852 // 'properties' a fast object. | |
| 3853 mainBuffer.add(r'''function convertToFastObject(properties) { | |
| 3854 function MyClass() {}; | |
| 3855 MyClass.prototype = properties; | |
| 3856 new MyClass(); | |
| 3857 '''); | |
| 3858 if (DEBUG_FAST_OBJECTS) { | |
| 3859 ClassElement primitives = | |
| 3860 compiler.findHelper(const SourceString('Primitives')); | |
| 3861 FunctionElement printHelper = | |
| 3862 compiler.lookupElementIn( | |
| 3863 primitives, const SourceString('printString')); | |
| 3864 String printHelperName = namer.isolateAccess(printHelper); | |
| 3865 mainBuffer.add(''' | |
| 3866 // The following only works on V8 when run with option "--allow-natives-syntax". | |
| 3867 if (typeof $printHelperName === "function") { | |
| 3868 $printHelperName("Size of global object: " | |
| 3869 + String(Object.getOwnPropertyNames(properties).length) | |
| 3870 + ", fast properties " + %HasFastProperties(properties)); | |
| 3871 } | |
| 3872 '''); | |
| 3873 } | |
| 3874 mainBuffer.add(r''' | |
| 3875 return properties; | |
| 3876 } | |
| 3877 '''); | |
| 3878 } | |
| 3879 | |
| 3880 | |
| 3780 String assembleProgram() { | 3881 String assembleProgram() { |
| 3781 measure(() { | 3882 measure(() { |
| 3782 // Compute the required type checks to know which classes need a | 3883 // Compute the required type checks to know which classes need a |
| 3783 // 'is$' method. | 3884 // 'is$' method. |
| 3784 computeRequiredTypeChecks(); | 3885 computeRequiredTypeChecks(); |
| 3785 | 3886 |
| 3786 computeNeededClasses(); | 3887 computeNeededClasses(); |
| 3787 | 3888 |
| 3788 mainBuffer.add(buildGeneratedBy()); | 3889 mainBuffer.add(buildGeneratedBy()); |
| 3789 addComment(HOOKS_API_USAGE, mainBuffer); | 3890 addComment(HOOKS_API_USAGE, mainBuffer); |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4067 if (typeof $printHelperName === "function") { | 4168 if (typeof $printHelperName === "function") { |
| 4068 $printHelperName("Size of $object: " | 4169 $printHelperName("Size of $object: " |
| 4069 + String(Object.getOwnPropertyNames($object).length) | 4170 + String(Object.getOwnPropertyNames($object).length) |
| 4070 + ", fast properties " + %HasFastProperties($object)); | 4171 + ", fast properties " + %HasFastProperties($object)); |
| 4071 } | 4172 } |
| 4072 '''); | 4173 '''); |
| 4073 } | 4174 } |
| 4074 } | 4175 } |
| 4075 | 4176 |
| 4076 emitMain(mainBuffer); | 4177 emitMain(mainBuffer); |
| 4178 jsAst.FunctionDeclaration precompiledFunctionAst = | |
| 4179 buildPrecompiledFunction(); | |
| 4077 emitInitFunction(mainBuffer); | 4180 emitInitFunction(mainBuffer); |
| 4078 if (!areAnyElementsDeferred) { | 4181 if (!areAnyElementsDeferred) { |
| 4079 mainBuffer.add('})()$n'); | 4182 mainBuffer.add('})()$n'); |
| 4080 } | 4183 } |
| 4081 compiler.assembledCode = mainBuffer.getText(); | 4184 compiler.assembledCode = mainBuffer.getText(); |
| 4082 outputSourceMap(compiler.assembledCode, ''); | 4185 outputSourceMap(compiler.assembledCode, ''); |
| 4083 | 4186 |
| 4187 mainBuffer.write( | |
| 4188 jsAst.prettyPrint(precompiledFunctionAst, compiler).getText()); | |
| 4189 | |
| 4190 compiler.outputProvider('precompiled', 'js') | |
| 4191 ..add(mainBuffer.getText()) | |
| 4192 ..close(); | |
| 4193 | |
| 4084 emitDeferredCode(); | 4194 emitDeferredCode(); |
| 4085 | 4195 |
| 4086 }); | 4196 }); |
| 4087 return compiler.assembledCode; | 4197 return compiler.assembledCode; |
| 4088 } | 4198 } |
| 4089 | 4199 |
| 4090 CodeBuffer bufferForElement(Element element, CodeBuffer eagerBuffer) { | 4200 CodeBuffer bufferForElement(Element element, CodeBuffer eagerBuffer) { |
| 4091 Element owner = element.getLibrary(); | 4201 Element owner = element.getLibrary(); |
| 4092 if (!element.isTopLevel() && !element.isNative()) { | 4202 if (!element.isTopLevel() && !element.isNative()) { |
| 4093 // For static (not top level) elements, record their code in a buffer | 4203 // For static (not top level) elements, record their code in a buffer |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4327 | 4437 |
| 4328 const String HOOKS_API_USAGE = """ | 4438 const String HOOKS_API_USAGE = """ |
| 4329 // The code supports the following hooks: | 4439 // The code supports the following hooks: |
| 4330 // dartPrint(message) - if this function is defined it is called | 4440 // dartPrint(message) - if this function is defined it is called |
| 4331 // instead of the Dart [print] method. | 4441 // instead of the Dart [print] method. |
| 4332 // dartMainRunner(main) - if this function is defined, the Dart [main] | 4442 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 4333 // method will not be invoked directly. | 4443 // method will not be invoked directly. |
| 4334 // Instead, a closure that will invoke [main] is | 4444 // Instead, a closure that will invoke [main] is |
| 4335 // passed to [dartMainRunner]. | 4445 // passed to [dartMainRunner]. |
| 4336 """; | 4446 """; |
| OLD | NEW |