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 /** | |
| 171 * For classes and libraries, record code for static/top-level members. | 183 * For classes and libraries, record code for static/top-level members. |
| 172 * Later, this code is emitted when the class or library is emitted. | 184 * Later, this code is emitted when the class or library is emitted. |
| 173 * See [bufferForElement]. | 185 * See [bufferForElement]. |
| 174 */ | 186 */ |
| 175 // TODO(ahe): Generate statics with their class, and store only libraries in | 187 // TODO(ahe): Generate statics with their class, and store only libraries in |
| 176 // this map. | 188 // this map. |
| 177 final Map<Element, List<CodeBuffer>> elementBuffers = | 189 final Map<Element, List<CodeBuffer>> elementBuffers = |
| 178 new Map<Element, List<CodeBuffer>>(); | 190 new Map<Element, List<CodeBuffer>>(); |
| 179 | 191 |
| 180 void registerDynamicFunctionTypeCheck(FunctionType functionType) { | 192 void registerDynamicFunctionTypeCheck(FunctionType functionType) { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 256 String get generateAccessorHolder | 268 String get generateAccessorHolder |
| 257 => '$isolatePropertiesName.\$generateAccessor'; | 269 => '$isolatePropertiesName.\$generateAccessor'; |
| 258 String get finishClassesProperty | 270 String get finishClassesProperty |
| 259 => r'$finishClasses'; | 271 => r'$finishClasses'; |
| 260 String get finishClassesName | 272 String get finishClassesName |
| 261 => '${namer.isolateName}.$finishClassesProperty'; | 273 => '${namer.isolateName}.$finishClassesProperty'; |
| 262 String get finishIsolateConstructorName | 274 String get finishIsolateConstructorName |
| 263 => '${namer.isolateName}.\$finishIsolateConstructor'; | 275 => '${namer.isolateName}.\$finishIsolateConstructor'; |
| 264 String get isolatePropertiesName | 276 String get isolatePropertiesName |
| 265 => '${namer.isolateName}.${namer.isolatePropertiesName}'; | 277 => '${namer.isolateName}.${namer.isolatePropertiesName}'; |
| 266 String get supportsProtoName | |
| 267 => 'supportsProto'; | |
| 268 String get lazyInitializerName | 278 String get lazyInitializerName |
| 269 => '${namer.isolateName}.\$lazy'; | 279 => '${namer.isolateName}.\$lazy'; |
| 270 | 280 |
| 271 // Compact field specifications. The format of the field specification is | 281 // Compact field specifications. The format of the field specification is |
| 272 // <accessorName>:<fieldName><suffix> where the suffix and accessor name | 282 // <accessorName>:<fieldName><suffix> where the suffix and accessor name |
| 273 // prefix are optional. The suffix directs the generation of getter and | 283 // 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 | 284 // setter methods. Each of the getter and setter has two bits to determine |
| 275 // the calling convention. Setter listed below, getter is similar. | 285 // the calling convention. Setter listed below, getter is similar. |
| 276 // | 286 // |
| 277 // 00: no setter | 287 // 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 | 430 // Declare a function called "generateAccessor". This is used in |
| 421 // defineClassFunction (it's a local declaration in init()). | 431 // defineClassFunction (it's a local declaration in init()). |
| 422 return [ | 432 return [ |
| 423 generateAccessorFunction, | 433 generateAccessorFunction, |
| 424 js('$generateAccessorHolder = generateAccessor'), | 434 js('$generateAccessorHolder = generateAccessor'), |
| 425 new jsAst.FunctionDeclaration( | 435 new jsAst.FunctionDeclaration( |
| 426 new jsAst.VariableDeclaration('defineClass'), defineClass) ]; | 436 new jsAst.VariableDeclaration('defineClass'), defineClass) ]; |
| 427 } | 437 } |
| 428 | 438 |
| 429 /** Needs defineClass to be defined. */ | 439 /** Needs defineClass to be defined. */ |
| 430 List buildProtoSupportCheck() { | 440 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 [ | 441 return [ |
| 442 js('var $supportsProtoName = false'), | 442 js('var inheritFrom = #', |
| 443 // js('var tmp = defineClass("c", "c", ["f<"], {}).prototype'), | 443 js.fun([], [ |
| 444 // | 444 new jsAst.FunctionDeclaration( |
| 445 // js.if_(js('tmp.__proto__'), [ | 445 new jsAst.VariableDeclaration('tmp'), js.fun([], [])), |
| 446 // js('tmp.__proto__ = {}'), | 446 js('var hasOwnProperty = Object.prototype.hasOwnProperty'), |
| 447 // js.if_(js(r'typeof tmp.get$f != "undefined"'), | 447 js.return_(js.fun(['constructor', 'superConstructor'], [ |
| 448 // js('$supportsProtoName = true')) | 448 js('tmp.prototype = superConstructor.prototype'), |
| 449 // ]) | 449 js('var object = new tmp()'), |
| 450 ]; | 450 js('var properties = constructor.prototype'), |
| 451 js.forIn('member', 'properties', | |
| 452 js.if_('hasOwnProperty.call(properties, member)', | |
| 453 js('object[member] = properties[member]'))), | |
| 454 js('object.constructor = constructor'), | |
| 455 js('constructor.prototype = object'), | |
| 456 js.return_('object') | |
| 457 ]))])())]; | |
| 451 } | 458 } |
| 452 | 459 |
| 453 static const MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING = 4; | 460 static const MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING = 4; |
| 454 | 461 |
| 455 // If we need fewer than this many noSuchMethod handlers we can save space by | 462 // 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 | 463 // just emitting them in JS, rather than emitting the JS needed to generate |
| 457 // them at run time. | 464 // them at run time. |
| 458 static const VERY_FEW_NO_SUCH_METHOD_HANDLERS = 10; | 465 static const VERY_FEW_NO_SUCH_METHOD_HANDLERS = 10; |
| 459 | 466 |
| 460 /** | 467 /** |
| (...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 | 702 // 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 | 703 // the object literal directly. For other engines we have to create a new |
| 697 // object and copy over the members. | 704 // object and copy over the members. |
| 698 | 705 |
| 699 String reflectableField = namer.reflectableField; | 706 String reflectableField = namer.reflectableField; |
| 700 List<jsAst.Node> statements = [ | 707 List<jsAst.Node> statements = [ |
| 701 js('var pendingClasses = {}'), | 708 js('var pendingClasses = {}'), |
| 702 js.if_('!init.allClasses', js('init.allClasses = {}')), | 709 js.if_('!init.allClasses', js('init.allClasses = {}')), |
| 703 js('var allClasses = init.allClasses'), | 710 js('var allClasses = init.allClasses'), |
| 704 | 711 |
| 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( | 712 optional( |
| 712 DEBUG_FAST_OBJECTS, | 713 DEBUG_FAST_OBJECTS, |
| 713 js('print("Number of classes: "' | 714 js('print("Number of classes: "' |
| 714 r' + Object.getOwnPropertyNames($$).length)')), | 715 r' + Object.getOwnPropertyNames($$).length)')), |
| 715 | 716 |
| 717 js('var hasOwnProperty = Object.prototype.hasOwnProperty'), | |
| 718 | |
| 719 js.if_('typeof dart_precompiled == "function"', | |
| 720 [js('var constructors = dart_precompiled(collectedClasses)')], | |
| 721 | |
| 722 [js('var combinedConstructorFunction = "function \$reflectable(fn){' | |
| 723 'fn.$reflectableField=1;return fn};\\n"+ "var \$desc;\\n"'), | |
| 724 js('var constructorsList = []')]), | |
| 716 js.forIn('cls', 'collectedClasses', [ | 725 js.forIn('cls', 'collectedClasses', [ |
| 717 js.if_('hasOwnProperty.call(collectedClasses, cls)', [ | 726 js.if_('hasOwnProperty.call(collectedClasses, cls)', [ |
| 718 js('var desc = collectedClasses[cls]'), | 727 js('var desc = collectedClasses[cls]'), |
| 719 js.if_('desc instanceof Array', js('desc = desc[1]')), | 728 js.if_('desc instanceof Array', js('desc = desc[1]')), |
| 720 | 729 |
| 721 /* The 'fields' are either a constructor function or a | 730 /* The 'fields' are either a constructor function or a |
| 722 * string encoding fields, constructor and superclass. Get | 731 * string encoding fields, constructor and superclass. Get |
| 723 * the superclass and the fields in the format | 732 * the superclass and the fields in the format |
| 724 * '[name/]Super;field1,field2' | 733 * '[name/]Super;field1,field2' |
| 725 * from the null-string property on the descriptor. | 734 * from the null-string property on the descriptor. |
| 726 * The 'name/' is optional and contains the name that should be used | 735 * 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 | 736 * when printing the runtime type string. It is used, for example, to |
| 728 * print the runtime type JSInt as 'int'. | 737 * print the runtime type JSInt as 'int'. |
| 729 */ | 738 */ |
| 730 js('var classData = desc[""], supr, name = cls, fields = classData'), | 739 js('var classData = desc[""], supr, name = cls, fields = classData'), |
| 731 optional( | 740 optional( |
| 732 backend.hasRetainedMetadata, | 741 backend.hasRetainedMetadata, |
| 733 js.if_('typeof classData == "object" && ' | 742 js.if_('typeof classData == "object" && ' |
| 734 'classData instanceof Array', | 743 'classData instanceof Array', |
| 735 [js('classData = fields = classData[0]')])), | 744 [js('classData = fields = classData[0]')])), |
| 736 | 745 |
| 737 js.if_('typeof classData == "string"', [ | 746 js.if_('typeof classData == "string"', [ |
| 738 js('var split = classData.split("/")'), | 747 js('var split = classData.split("/")'), |
| 739 js.if_('split.length == 2', [ | 748 js.if_('split.length == 2', [ |
| 740 js('name = split[0]'), | 749 js('name = split[0]'), |
| 741 js('fields = split[1]') | 750 js('fields = split[1]') |
| 742 ]) | 751 ]) |
| 743 ]), | 752 ]), |
| 744 | 753 |
| 745 js.if_('typeof fields == "string"', [ | 754 js('var s = fields.split(";")'), |
| 746 js('var s = fields.split(";")'), | 755 js('fields = s[1] == "" ? [] : s[1].split(",")'), |
| 747 js('fields = s[1] == "" ? [] : s[1].split(",")'), | 756 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 | 757 |
| 754 optional(needsMixinSupport, js.if_('supr && supr.indexOf("+") > 0', [ | 758 optional(needsMixinSupport, js.if_('supr && supr.indexOf("+") > 0', [ |
| 755 js('s = supr.split("+")'), | 759 js('s = supr.split("+")'), |
| 756 js('supr = s[0]'), | 760 js('supr = s[0]'), |
| 757 js('var mixin = collectedClasses[s[1]]'), | 761 js('var mixin = collectedClasses[s[1]]'), |
| 758 js.if_('mixin instanceof Array', js('mixin = mixin[1]')), | 762 js.if_('mixin instanceof Array', js('mixin = mixin[1]')), |
| 759 js.forIn('d', 'mixin', [ | 763 js.forIn('d', 'mixin', [ |
| 760 js.if_('hasOwnProperty.call(mixin, d)' | 764 js.if_('hasOwnProperty.call(mixin, d)' |
| 761 '&& !hasOwnProperty.call(desc, d)', | 765 '&& !hasOwnProperty.call(desc, d)', |
| 762 js('desc[d] = mixin[d]')) | 766 js('desc[d] = mixin[d]')) |
| 763 ]), | 767 ]), |
| 764 ])), | 768 ])), |
| 765 | 769 |
| 766 js('combinedConstructorFunction += defineClass(name, cls, fields)'), | 770 js.if_('typeof dart_precompiled != "function"', |
| 767 js('constructorsList.push(cls)'), | 771 [js('combinedConstructorFunction +=' |
| 772 ' defineClass(name, cls, fields)'), | |
| 773 js('constructorsList.push(cls)')]), | |
| 768 js.if_('supr', js('pendingClasses[cls] = supr')) | 774 js.if_('supr', js('pendingClasses[cls] = supr')) |
| 769 ]) | 775 ]) |
| 770 ]), | 776 ]), |
| 771 js('combinedConstructorFunction +=' | 777 js.if_('typeof dart_precompiled != "function"', |
| 772 ' "return [\\n " + constructorsList.join(",\\n ") + "\\n]"'), | 778 [js('combinedConstructorFunction +=' |
| 773 js('var constructors =' | 779 ' "return [\\n " + constructorsList.join(",\\n ") + "\\n]"'), |
| 774 ' new Function("\$collectedClasses", combinedConstructorFunction)' | 780 js('var constructors =' |
| 775 '(collectedClasses)'), | 781 ' new Function("\$collectedClasses", combinedConstructorFunction)' |
| 776 js('combinedConstructorFunction = null'), | 782 '(collectedClasses)'), |
| 783 js('combinedConstructorFunction = null')]), | |
| 777 js.for_('var i = 0', 'i < constructors.length', 'i++', [ | 784 js.for_('var i = 0', 'i < constructors.length', 'i++', [ |
| 778 js('var constructor = constructors[i]'), | 785 js('var constructor = constructors[i]'), |
| 779 js('var cls = constructor.name'), | 786 js('var cls = constructor.name'), |
| 780 js('var desc = collectedClasses[cls]'), | 787 js('var desc = collectedClasses[cls]'), |
| 781 js('var globalObject = isolateProperties'), | 788 js('var globalObject = isolateProperties'), |
| 782 js.if_('desc instanceof Array', [ | 789 js.if_('desc instanceof Array', [ |
| 783 js('globalObject = desc[0] || isolateProperties'), | 790 js('globalObject = desc[0] || isolateProperties'), |
| 784 js('desc = desc[1]') | 791 js('desc = desc[1]') |
| 785 ]), | 792 ]), |
| 786 optional(backend.isTreeShakingDisabled, | 793 optional(backend.isTreeShakingDisabled, |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 834 // we have a string. | 841 // we have a string. |
| 835 js.if_('!superclass || typeof superclass != "string"', js.return_()), | 842 js.if_('!superclass || typeof superclass != "string"', js.return_()), |
| 836 js('finishClass(superclass)'), | 843 js('finishClass(superclass)'), |
| 837 js('var constructor = allClasses[cls]'), | 844 js('var constructor = allClasses[cls]'), |
| 838 js('var superConstructor = allClasses[superclass]'), | 845 js('var superConstructor = allClasses[superclass]'), |
| 839 | 846 |
| 840 js.if_(js('!superConstructor'), | 847 js.if_(js('!superConstructor'), |
| 841 js('superConstructor =' | 848 js('superConstructor =' |
| 842 'existingIsolateProperties[superclass]')), | 849 'existingIsolateProperties[superclass]')), |
| 843 | 850 |
| 844 js('var prototype = constructor.prototype'), | 851 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 ]); | 852 ]); |
| 877 | 853 |
| 878 return new jsAst.FunctionDeclaration( | 854 return new jsAst.FunctionDeclaration( |
| 879 new jsAst.VariableDeclaration('finishClass'), | 855 new jsAst.VariableDeclaration('finishClass'), |
| 880 fun); | 856 fun); |
| 881 } | 857 } |
| 882 | 858 |
| 883 jsAst.Fun get finishIsolateConstructorFunction { | 859 jsAst.Fun get finishIsolateConstructorFunction_NO_CSP { |
| 884 String isolate = namer.isolateName; | 860 String isolate = namer.isolateName; |
| 885 // We replace the old Isolate function with a new one that initializes | 861 // 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. | 862 // all its field with the initial (and often final) value of all globals. |
| 887 // This has two advantages: | 863 // This has two advantages: |
| 888 // 1. the properties are in the object itself (thus avoiding to go through | 864 // 1. the properties are in the object itself (thus avoiding to go through |
| 889 // the prototype when looking up globals. | 865 // the prototype when looking up globals. |
| 890 // 2. a new isolate goes through a (usually well optimized) constructor | 866 // 2. a new isolate goes through a (usually well optimized) constructor |
| 891 // function of the form: "function() { this.x = ...; this.y = ...; }". | 867 // function of the form: "function() { this.x = ...; this.y = ...; }". |
| 892 // | 868 // |
| 893 // Example: If [isolateProperties] is an object containing: x = 3 and | 869 // 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. | 913 // TODO(ahe): Only copy makeConstantList when it is used. |
| 938 js('newIsolate.makeConstantList = oldIsolate.makeConstantList'), | 914 js('newIsolate.makeConstantList = oldIsolate.makeConstantList'), |
| 939 ]..addAll(copyFinishClasses) | 915 ]..addAll(copyFinishClasses) |
| 940 ..addAll([ | 916 ..addAll([ |
| 941 | 917 |
| 942 // return newIsolate; | 918 // return newIsolate; |
| 943 js.return_('newIsolate') | 919 js.return_('newIsolate') |
| 944 ])); | 920 ])); |
| 945 } | 921 } |
| 946 | 922 |
| 923 jsAst.Fun get finishIsolateConstructorFunction { | |
| 924 // We replace the old Isolate function with a new one that initializes | |
| 925 // all its fields with the initial (and often final) value of all globals. | |
| 926 // | |
| 927 // We also copy over old values like the prototype, and the | |
| 928 // isolateProperties themselves. | |
| 929 return js.fun('oldIsolate', [ | |
| 930 js('var isolateProperties = oldIsolate.${namer.isolatePropertiesName}'), | |
| 931 new jsAst.FunctionDeclaration( | |
| 932 new jsAst.VariableDeclaration('Isolate'), | |
| 933 js.fun([], [ | |
| 934 js('var hasOwnProperty = Object.prototype.hasOwnProperty'), | |
| 935 js.forIn('staticName', 'isolateProperties', | |
| 936 js.if_('hasOwnProperty.call(isolateProperties, staticName)', | |
| 937 js('this[staticName] = isolateProperties[staticName]'))), | |
| 938 // Use the newly created object as prototype. In Chrome, | |
| 939 // this creates a hidden class for the object and makes | |
| 940 // sure it is fast to access. | |
| 941 new jsAst.FunctionDeclaration( | |
|
kasperl
2013/09/20 13:04:47
Could you use the convertToFast helper?
| |
| 942 new jsAst.VariableDeclaration('ForceEfficientMap'), | |
| 943 js.fun([], [])), | |
| 944 js('ForceEfficientMap.prototype = this'), | |
| 945 js('new ForceEfficientMap()')])), | |
| 946 js('Isolate.prototype = oldIsolate.prototype'), | |
| 947 js('Isolate.prototype.constructor = Isolate'), | |
| 948 js('Isolate.${namer.isolatePropertiesName} = isolateProperties'), | |
| 949 optional(needsDefineClass, | |
| 950 js('Isolate.$finishClassesProperty =' | |
| 951 ' oldIsolate.$finishClassesProperty')), | |
| 952 js.return_('Isolate')]); | |
| 953 } | |
| 954 | |
| 955 | |
| 947 jsAst.Fun get lazyInitializerFunction { | 956 jsAst.Fun get lazyInitializerFunction { |
| 948 // function(prototype, staticName, fieldName, getterName, lazyValue) { | 957 // function(prototype, staticName, fieldName, getterName, lazyValue) { |
| 949 var parameters = <String>['prototype', 'staticName', 'fieldName', | 958 var parameters = <String>['prototype', 'staticName', 'fieldName', |
| 950 'getterName', 'lazyValue']; | 959 'getterName', 'lazyValue']; |
| 951 return js.fun(parameters, [ | 960 return js.fun(parameters, addLazyInitializerLogic()); |
| 952 js('var getter = new Function("{ return this." + fieldName + ";}")'), | |
| 953 ]..addAll(addLazyInitializerLogic()) | |
| 954 ); | |
| 955 } | 961 } |
| 956 | 962 |
| 957 List addLazyInitializerLogic() { | 963 List addLazyInitializerLogic() { |
| 958 String isolate = namer.CURRENT_ISOLATE; | 964 String isolate = namer.CURRENT_ISOLATE; |
| 959 String cyclicThrow = namer.isolateAccess(backend.getCyclicThrowHelper()); | 965 String cyclicThrow = namer.isolateAccess(backend.getCyclicThrowHelper()); |
| 960 var lazies = []; | 966 var lazies = []; |
| 961 if (backend.rememberLazies) { | 967 if (backend.rememberLazies) { |
| 962 lazies = [ | 968 lazies = [ |
| 963 js.if_('!init.lazies', js('init.lazies = {}')), | 969 js.if_('!init.lazies', js('init.lazies = {}')), |
| 964 js('init.lazies[fieldName] = getterName')]; | 970 js('init.lazies[fieldName] = getterName')]; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 997 ], /* else */ [ | 1003 ], /* else */ [ |
| 998 js.if_('result === sentinelInProgress', | 1004 js.if_('result === sentinelInProgress', |
| 999 js('$cyclicThrow(staticName)') | 1005 js('$cyclicThrow(staticName)') |
| 1000 ) | 1006 ) |
| 1001 ]), | 1007 ]), |
| 1002 | 1008 |
| 1003 // return result; | 1009 // return result; |
| 1004 js.return_('result') | 1010 js.return_('result') |
| 1005 | 1011 |
| 1006 ], finallyPart: [ | 1012 ], finallyPart: [ |
| 1007 js('$isolate[getterName] = getter') | 1013 js('$isolate[getterName] = #', |
| 1014 js.fun([], [js.return_('this[fieldName]')])) | |
|
kasperl
2013/09/20 13:04:47
It might be worth investigating how much this cost
| |
| 1008 ]) | 1015 ]) |
| 1009 ])) | 1016 ])) |
| 1010 ]); | 1017 ]); |
| 1011 } | 1018 } |
| 1012 | 1019 |
| 1013 List buildDefineClassAndFinishClassFunctionsIfNecessary() { | 1020 List buildDefineClassAndFinishClassFunctionsIfNecessary() { |
| 1014 if (!needsDefineClass) return []; | 1021 if (!needsDefineClass) return []; |
| 1015 return defineClassFunction | 1022 return defineClassFunction |
| 1016 ..addAll(buildProtoSupportCheck()) | 1023 ..addAll(buildInheritFrom()) |
| 1017 ..addAll([ | 1024 ..addAll([ |
| 1018 js('$finishClassesName = #', finishClassesFunction) | 1025 js('$finishClassesName = #', finishClassesFunction) |
| 1019 ]); | 1026 ]); |
| 1020 } | 1027 } |
| 1021 | 1028 |
| 1022 List buildLazyInitializerFunctionIfNecessary() { | 1029 List buildLazyInitializerFunctionIfNecessary() { |
| 1023 if (!needsLazyInitializer) return []; | 1030 if (!needsLazyInitializer) return []; |
| 1024 | 1031 |
| 1025 return [js('$lazyInitializerName = #', lazyInitializerFunction)]; | 1032 return [js('$lazyInitializerName = #', lazyInitializerFunction)]; |
| 1026 } | 1033 } |
| (...skipping 675 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1702 if (reflectionName != null) { | 1709 if (reflectionName != null) { |
| 1703 var reflectable = | 1710 var reflectable = |
| 1704 js(backend.isAccessibleByReflection(member) ? '1' : '0'); | 1711 js(backend.isAccessibleByReflection(member) ? '1' : '0'); |
| 1705 builder.addProperty('+$reflectionName', reflectable); | 1712 builder.addProperty('+$reflectionName', reflectable); |
| 1706 } | 1713 } |
| 1707 } | 1714 } |
| 1708 | 1715 |
| 1709 void generateGetter(Element member, String fieldName, String accessorName, | 1716 void generateGetter(Element member, String fieldName, String accessorName, |
| 1710 ClassBuilder builder) { | 1717 ClassBuilder builder) { |
| 1711 String getterName = namer.getterNameFromAccessorName(accessorName); | 1718 String getterName = namer.getterNameFromAccessorName(accessorName); |
| 1712 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) | 1719 ClassElement cls = member.getEnclosingClass(); |
| 1713 ? 'receiver' : 'this'; | 1720 String className = namer.getNameOfClass(cls); |
| 1714 List<String> args = backend.isInterceptedMethod(member) | 1721 String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this'; |
| 1715 ? ['receiver'] | 1722 List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : []; |
| 1716 : []; | 1723 precompiledFunction.add( |
| 1717 builder.addProperty(getterName, | 1724 js('$className.prototype.$getterName = #', |
| 1718 js.fun(args, js.return_(js('$receiver.$fieldName')))); | 1725 js.fun(args, js.return_(js('$receiver.$fieldName'))))); |
| 1719 generateReflectionDataForFieldGetterOrSetter( | 1726 if (backend.isNeededForReflection(member)) { |
| 1720 member, getterName, builder, isGetter: true); | 1727 precompiledFunction.add( |
| 1728 js('$className.prototype.$getterName.${namer.reflectableField} = 1')); | |
| 1729 } | |
| 1721 } | 1730 } |
| 1722 | 1731 |
| 1723 void generateSetter(Element member, String fieldName, String accessorName, | 1732 void generateSetter(Element member, String fieldName, String accessorName, |
| 1724 ClassBuilder builder) { | 1733 ClassBuilder builder) { |
| 1725 String setterName = namer.setterNameFromAccessorName(accessorName); | 1734 String setterName = namer.setterNameFromAccessorName(accessorName); |
| 1726 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) | 1735 ClassElement cls = member.getEnclosingClass(); |
| 1727 ? 'receiver' : 'this'; | 1736 String className = namer.getNameOfClass(cls); |
| 1728 List<String> args = backend.isInterceptedMethod(member) | 1737 String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this'; |
| 1729 ? ['receiver', 'v'] | 1738 List<String> args = |
| 1730 : ['v']; | 1739 backend.isInterceptedMethod(member) ? ['receiver', 'v'] : ['v']; |
| 1731 builder.addProperty(setterName, | 1740 precompiledFunction.add( |
| 1732 js.fun(args, js('$receiver.$fieldName = v'))); | 1741 js('$className.prototype.$setterName = #', |
| 1733 generateReflectionDataForFieldGetterOrSetter( | 1742 js.fun(args, js.return_(js('$receiver.$fieldName = v'))))); |
| 1734 member, setterName, builder, isGetter: false); | 1743 if (backend.isNeededForReflection(member)) { |
| 1744 precompiledFunction.add( | |
| 1745 js('$className.prototype.$setterName.${namer.reflectableField} = 1')); | |
| 1746 } | |
| 1735 } | 1747 } |
| 1736 | 1748 |
| 1737 bool canGenerateCheckedSetter(VariableElement field) { | 1749 bool canGenerateCheckedSetter(VariableElement field) { |
| 1738 // We never generate accessors for top-level/static fields. | 1750 // We never generate accessors for top-level/static fields. |
| 1739 if (!field.isInstanceMember()) return false; | 1751 if (!field.isInstanceMember()) return false; |
| 1740 DartType type = field.computeType(compiler).unalias(compiler); | 1752 DartType type = field.computeType(compiler).unalias(compiler); |
| 1741 if (type.element.isTypeVariable() || | 1753 if (type.element.isTypeVariable() || |
| 1742 (type is FunctionType && type.containsTypeVariables) || | 1754 (type is FunctionType && type.containsTypeVariables) || |
| 1743 type.treatAsDynamic || | 1755 type.treatAsDynamic || |
| 1744 type.element == compiler.objectClass) { | 1756 type.element == compiler.objectClass) { |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 1774 List<String> args = backend.isInterceptedMethod(member) | 1786 List<String> args = backend.isInterceptedMethod(member) |
| 1775 ? ['receiver', 'v'] | 1787 ? ['receiver', 'v'] |
| 1776 : ['v']; | 1788 : ['v']; |
| 1777 builder.addProperty(setterName, | 1789 builder.addProperty(setterName, |
| 1778 js.fun(args, | 1790 js.fun(args, |
| 1779 js('$receiver.$fieldName = #', js(helperName)(arguments)))); | 1791 js('$receiver.$fieldName = #', js(helperName)(arguments)))); |
| 1780 generateReflectionDataForFieldGetterOrSetter( | 1792 generateReflectionDataForFieldGetterOrSetter( |
| 1781 member, setterName, builder, isGetter: false); | 1793 member, setterName, builder, isGetter: false); |
| 1782 } | 1794 } |
| 1783 | 1795 |
| 1784 void emitClassConstructor(ClassElement classElement, ClassBuilder builder) { | 1796 void emitClassConstructor(ClassElement classElement, |
| 1785 /* Do nothing. */ | 1797 ClassBuilder builder, |
| 1798 String runtimeName) { | |
| 1799 List<String> fields = <String>[]; | |
| 1800 if (!classElement.isNative()) { | |
| 1801 visitFields(classElement, false, | |
| 1802 (Element member, | |
| 1803 String name, | |
| 1804 String accessorName, | |
| 1805 bool needsGetter, | |
| 1806 bool needsSetter, | |
| 1807 bool needsCheckedSetter) { | |
| 1808 fields.add(name); | |
| 1809 }); | |
| 1810 } | |
| 1811 String constructorName = namer.getNameOfClass(classElement); | |
| 1812 precompiledFunction.add(new jsAst.FunctionDeclaration( | |
| 1813 new jsAst.VariableDeclaration(constructorName), | |
| 1814 js.fun(fields, fields.map( | |
| 1815 (name) => js('this.$name = $name')).toList()))); | |
| 1816 if (runtimeName == null) { | |
| 1817 runtimeName = constructorName; | |
| 1818 } | |
| 1819 precompiledFunction.addAll([ | |
| 1820 js('$constructorName.builtin\$cls = "$runtimeName"'), | |
| 1821 js.if_('!"name" in $constructorName', | |
| 1822 js('$constructorName.name = "$constructorName"')), | |
| 1823 js('\$desc=\$collectedClasses.$constructorName'), | |
| 1824 js.if_('\$desc instanceof Array', js('\$desc = \$desc[1]')), | |
| 1825 js('$constructorName.prototype = \$desc'), | |
| 1826 ]); | |
| 1827 | |
| 1828 precompiledConstructorNames.add(js(constructorName)); | |
| 1829 } | |
| 1830 | |
| 1831 jsAst.FunctionDeclaration buildPrecompiledFunction() { | |
| 1832 // TODO(ahe): Compute a hash code. | |
|
kasperl
2013/09/20 13:04:47
Maybe elaborate on the TODO so others would unders
| |
| 1833 String name = 'dart_precompiled'; | |
|
kasperl
2013/09/20 13:04:47
Factor out this constant?
| |
| 1834 | |
| 1835 precompiledFunction.add( | |
| 1836 js.return_( | |
| 1837 new jsAst.ArrayInitializer.from(precompiledConstructorNames))); | |
| 1838 precompiledFunction.insert(0, js(r'var $desc')); | |
| 1839 return new jsAst.FunctionDeclaration( | |
| 1840 new jsAst.VariableDeclaration(name), | |
| 1841 js.fun([r'$collectedClasses'], precompiledFunction)); | |
| 1786 } | 1842 } |
| 1787 | 1843 |
| 1788 void emitSuper(String superName, ClassBuilder builder) { | 1844 void emitSuper(String superName, ClassBuilder builder) { |
| 1789 /* Do nothing. */ | 1845 /* Do nothing. */ |
| 1790 } | 1846 } |
| 1791 | 1847 |
| 1792 void emitRuntimeName(String runtimeName, ClassBuilder builder) { | 1848 void emitRuntimeName(String runtimeName, ClassBuilder builder) { |
| 1793 /* Do nothing. */ | 1849 /* Do nothing. */ |
| 1794 } | 1850 } |
| 1795 | 1851 |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1959 String name, | 2015 String name, |
| 1960 String accessorName, | 2016 String accessorName, |
| 1961 bool needsGetter, | 2017 bool needsGetter, |
| 1962 bool needsSetter, | 2018 bool needsSetter, |
| 1963 bool needsCheckedSetter) { | 2019 bool needsCheckedSetter) { |
| 1964 compiler.withCurrentElement(member, () { | 2020 compiler.withCurrentElement(member, () { |
| 1965 if (needsCheckedSetter) { | 2021 if (needsCheckedSetter) { |
| 1966 assert(!needsSetter); | 2022 assert(!needsSetter); |
| 1967 generateCheckedSetter(member, name, accessorName, builder); | 2023 generateCheckedSetter(member, name, accessorName, builder); |
| 1968 } | 2024 } |
| 1969 if (!getterAndSetterCanBeImplementedByFieldSpec) { | 2025 if (needsGetter) { |
| 1970 if (needsGetter) { | 2026 generateGetter(member, name, accessorName, builder); |
| 1971 generateGetter(member, name, accessorName, builder); | 2027 } |
| 1972 } | 2028 if (needsSetter) { |
| 1973 if (needsSetter) { | 2029 generateSetter(member, name, accessorName, builder); |
| 1974 generateSetter(member, name, accessorName, builder); | |
| 1975 } | |
| 1976 } | 2030 } |
| 1977 }); | 2031 }); |
| 1978 }); | 2032 }); |
| 1979 } | 2033 } |
| 1980 | 2034 |
| 1981 /** | 2035 /** |
| 1982 * Documentation wanted -- johnniwinther | 2036 * Documentation wanted -- johnniwinther |
| 1983 * | 2037 * |
| 1984 * Invariant: [classElement] must be a declaration element. | 2038 * Invariant: [classElement] must be a declaration element. |
| 1985 */ | 2039 */ |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 2000 String runtimeName = | 2054 String runtimeName = |
| 2001 namer.getPrimitiveInterceptorRuntimeName(classElement); | 2055 namer.getPrimitiveInterceptorRuntimeName(classElement); |
| 2002 | 2056 |
| 2003 if (classElement.isMixinApplication) { | 2057 if (classElement.isMixinApplication) { |
| 2004 String mixinName = namer.getNameOfClass(computeMixinClass(classElement)); | 2058 String mixinName = namer.getNameOfClass(computeMixinClass(classElement)); |
| 2005 superName = '$superName+$mixinName'; | 2059 superName = '$superName+$mixinName'; |
| 2006 needsMixinSupport = true; | 2060 needsMixinSupport = true; |
| 2007 } | 2061 } |
| 2008 | 2062 |
| 2009 ClassBuilder builder = new ClassBuilder(); | 2063 ClassBuilder builder = new ClassBuilder(); |
| 2010 emitClassConstructor(classElement, builder); | 2064 emitClassConstructor(classElement, builder, runtimeName); |
| 2011 emitSuper(superName, builder); | 2065 emitSuper(superName, builder); |
| 2012 emitRuntimeName(runtimeName, builder); | 2066 emitRuntimeName(runtimeName, builder); |
| 2013 emitFields(classElement, builder, superName, onlyForRti: onlyForRti); | 2067 emitFields(classElement, builder, superName, onlyForRti: onlyForRti); |
| 2014 emitClassGettersSetters(classElement, builder); | 2068 emitClassGettersSetters(classElement, builder); |
| 2015 if (!classElement.isMixinApplication) { | 2069 if (!classElement.isMixinApplication) { |
| 2016 emitInstanceMembers(classElement, builder); | 2070 emitInstanceMembers(classElement, builder); |
| 2017 } | 2071 } |
| 2018 emitIsTests(classElement, builder); | 2072 emitIsTests(classElement, builder); |
| 2019 | 2073 |
| 2020 emitClassBuilderWithReflectionData( | 2074 emitClassBuilderWithReflectionData( |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2068 String reflectionName = getReflectionName(classElement, className); | 2122 String reflectionName = getReflectionName(classElement, className); |
| 2069 if (reflectionName != null) { | 2123 if (reflectionName != null) { |
| 2070 List<int> interfaces = <int>[]; | 2124 List<int> interfaces = <int>[]; |
| 2071 for (DartType interface in classElement.interfaces) { | 2125 for (DartType interface in classElement.interfaces) { |
| 2072 interfaces.add(reifyType(interface)); | 2126 interfaces.add(reifyType(interface)); |
| 2073 } | 2127 } |
| 2074 buffer.write(',$n$n"+$reflectionName": $interfaces'); | 2128 buffer.write(',$n$n"+$reflectionName": $interfaces'); |
| 2075 } | 2129 } |
| 2076 } | 2130 } |
| 2077 | 2131 |
| 2078 bool get getterAndSetterCanBeImplementedByFieldSpec => true; | |
| 2079 | |
| 2080 /// If this is true then we can generate the noSuchMethod handlers at startup | 2132 /// 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. | 2133 /// time, instead of them being emitted as part of the Object class. |
| 2082 bool get generateTrivialNsmHandlers => true; | 2134 bool get generateTrivialNsmHandlers => true; |
| 2083 | 2135 |
| 2084 int _selectorRank(Selector selector) { | 2136 int _selectorRank(Selector selector) { |
| 2085 int arity = selector.argumentCount * 3; | 2137 int arity = selector.argumentCount * 3; |
| 2086 if (selector.isGetter()) return arity + 2; | 2138 if (selector.isGetter()) return arity + 2; |
| 2087 if (selector.isSetter()) return arity + 1; | 2139 if (selector.isSetter()) return arity + 1; |
| 2088 return arity; | 2140 return arity; |
| 2089 } | 2141 } |
| (...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2486 emitFunctionTypeSignature, emitIsFunctionTypeTest); | 2538 emitFunctionTypeSignature, emitIsFunctionTypeTest); |
| 2487 } | 2539 } |
| 2488 } | 2540 } |
| 2489 | 2541 |
| 2490 void emitClosureClassHeader(String mangledName, | 2542 void emitClosureClassHeader(String mangledName, |
| 2491 String superName, | 2543 String superName, |
| 2492 List<String> fieldNames, | 2544 List<String> fieldNames, |
| 2493 ClassBuilder builder) { | 2545 ClassBuilder builder) { |
| 2494 builder.addProperty('', | 2546 builder.addProperty('', |
| 2495 js.string("$superName;${fieldNames.join(',')}")); | 2547 js.string("$superName;${fieldNames.join(',')}")); |
| 2548 | |
| 2549 List<String> fields = fieldNames; | |
| 2550 String constructorName = mangledName; | |
| 2551 precompiledFunction.add(new jsAst.FunctionDeclaration( | |
| 2552 new jsAst.VariableDeclaration(constructorName), | |
| 2553 js.fun(fields, fields.map( | |
| 2554 (name) => js('this.$name = $name')).toList()))); | |
| 2555 precompiledFunction.addAll([ | |
| 2556 js('$constructorName.builtin\$cls = "$constructorName"'), | |
| 2557 js('\$desc=\$collectedClasses.$constructorName'), | |
| 2558 js.if_('\$desc instanceof Array', js('\$desc = \$desc[1]')), | |
| 2559 js('$constructorName.prototype = \$desc'), | |
| 2560 ]); | |
| 2561 | |
| 2562 precompiledConstructorNames.add(js(constructorName)); | |
| 2496 } | 2563 } |
| 2497 | 2564 |
| 2498 /** | 2565 /** |
| 2499 * Documentation wanted -- johnniwinther | 2566 * Documentation wanted -- johnniwinther |
| 2500 * | 2567 * |
| 2501 * Invariant: [member] must be a declaration element. | 2568 * Invariant: [member] must be a declaration element. |
| 2502 */ | 2569 */ |
| 2503 void emitDynamicFunctionGetter(FunctionElement member, | 2570 void emitDynamicFunctionGetter(FunctionElement member, |
| 2504 DefineStubFunction defineStub) { | 2571 DefineStubFunction defineStub) { |
| 2505 assert(invariant(member, member.isDeclaration)); | 2572 assert(invariant(member, member.isDeclaration)); |
| (...skipping 1244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3750 buffer.write(metadata); | 3817 buffer.write(metadata); |
| 3751 } | 3818 } |
| 3752 } else { | 3819 } else { |
| 3753 throw 'Unexpected value in metadata: ${Error.safeToString(metadata)}'; | 3820 throw 'Unexpected value in metadata: ${Error.safeToString(metadata)}'; |
| 3754 } | 3821 } |
| 3755 buffer.write(',$n'); | 3822 buffer.write(',$n'); |
| 3756 } | 3823 } |
| 3757 buffer.write('];$n'); | 3824 buffer.write('];$n'); |
| 3758 } | 3825 } |
| 3759 | 3826 |
| 3760 void emitConvertToFastObjectFunction() { | 3827 void emitConvertToFastObjectFunction_NO_CSP() { |
| 3761 mainBuffer.add(r''' | 3828 mainBuffer.add(r''' |
| 3762 function convertToFastObject(properties) { | 3829 function convertToFastObject(properties) { |
|
kasperl
2013/09/20 13:04:47
Could this go through js ASTs?
| |
| 3763 function makeConstructor() { | 3830 function makeConstructor() { |
| 3764 var str = "{\n"; | 3831 var str = "{\n"; |
| 3765 var hasOwnProperty = Object.prototype.hasOwnProperty; | 3832 var hasOwnProperty = Object.prototype.hasOwnProperty; |
| 3766 for (var property in properties) { | 3833 for (var property in properties) { |
| 3767 if (hasOwnProperty.call(properties, property)) { | 3834 if (hasOwnProperty.call(properties, property)) { |
| 3768 str += "this." + property + "= properties." + property + ";\n"; | 3835 str += "this." + property + "= properties." + property + ";\n"; |
| 3769 } | 3836 } |
| 3770 } | 3837 } |
| 3771 str += "}\n"; | 3838 str += "}\n"; |
| 3772 return new Function("properties", str); | 3839 return new Function("properties", str); |
| 3773 }; | 3840 }; |
| 3774 var constructor = makeConstructor(); | 3841 var constructor = makeConstructor(); |
| 3775 return makeConstructor.prototype = new constructor(properties); | 3842 return makeConstructor.prototype = new constructor(properties); |
| 3776 } | 3843 } |
| 3777 '''); | 3844 '''); |
| 3778 } | 3845 } |
| 3779 | 3846 |
| 3847 void emitConvertToFastObjectFunction() { | |
| 3848 // Create an instance that uses 'properties' as prototype. This should make | |
| 3849 // 'properties' a fast object. | |
| 3850 mainBuffer.add(r'''function convertToFastObject(properties) { | |
|
kasperl
2013/09/20 13:04:47
Could this go through js ASTs?
| |
| 3851 function MyClass() {}; | |
| 3852 MyClass.prototype = properties; | |
| 3853 new MyClass(); | |
| 3854 '''); | |
| 3855 if (DEBUG_FAST_OBJECTS) { | |
| 3856 ClassElement primitives = | |
| 3857 compiler.findHelper(const SourceString('Primitives')); | |
| 3858 FunctionElement printHelper = | |
| 3859 compiler.lookupElementIn( | |
| 3860 primitives, const SourceString('printString')); | |
| 3861 String printHelperName = namer.isolateAccess(printHelper); | |
| 3862 mainBuffer.add(''' | |
| 3863 // The following only works on V8 when run with option "--allow-natives-syntax". | |
| 3864 if (typeof $printHelperName === "function") { | |
| 3865 $printHelperName("Size of global object: " | |
| 3866 + String(Object.getOwnPropertyNames(properties).length) | |
| 3867 + ", fast properties " + %HasFastProperties(properties)); | |
| 3868 } | |
| 3869 '''); | |
| 3870 } | |
| 3871 mainBuffer.add(r''' | |
| 3872 return properties; | |
| 3873 } | |
| 3874 '''); | |
| 3875 } | |
| 3876 | |
| 3877 | |
| 3780 String assembleProgram() { | 3878 String assembleProgram() { |
| 3781 measure(() { | 3879 measure(() { |
| 3782 // Compute the required type checks to know which classes need a | 3880 // Compute the required type checks to know which classes need a |
| 3783 // 'is$' method. | 3881 // 'is$' method. |
| 3784 computeRequiredTypeChecks(); | 3882 computeRequiredTypeChecks(); |
| 3785 | 3883 |
| 3786 computeNeededClasses(); | 3884 computeNeededClasses(); |
| 3787 | 3885 |
| 3788 mainBuffer.add(buildGeneratedBy()); | 3886 mainBuffer.add(buildGeneratedBy()); |
| 3789 addComment(HOOKS_API_USAGE, mainBuffer); | 3887 addComment(HOOKS_API_USAGE, mainBuffer); |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4021 // The following code should not use the short-hand for the | 4119 // The following code should not use the short-hand for the |
| 4022 // initialStatics. | 4120 // initialStatics. |
| 4023 mainBuffer.add('${namer.CURRENT_ISOLATE}$_=${_}null$N'); | 4121 mainBuffer.add('${namer.CURRENT_ISOLATE}$_=${_}null$N'); |
| 4024 | 4122 |
| 4025 emitFinishIsolateConstructorInvocation(mainBuffer); | 4123 emitFinishIsolateConstructorInvocation(mainBuffer); |
| 4026 mainBuffer.add( | 4124 mainBuffer.add( |
| 4027 '${namer.CURRENT_ISOLATE}$_=${_}new ${namer.isolateName}()$N'); | 4125 '${namer.CURRENT_ISOLATE}$_=${_}new ${namer.isolateName}()$N'); |
| 4028 | 4126 |
| 4029 emitConvertToFastObjectFunction(); | 4127 emitConvertToFastObjectFunction(); |
| 4030 for (String globalObject in Namer.reservedGlobalObjectNames) { | 4128 for (String globalObject in Namer.reservedGlobalObjectNames) { |
| 4031 mainBuffer.add('$globalObject = convertToFastObject($globalObject)$N'); | 4129 mainBuffer.add('$globalObject = convertToFastObject($globalObject)$N'); |
|
kasperl
2013/09/20 13:04:47
Could this go through js AST?
| |
| 4032 } | 4130 } |
| 4033 if (DEBUG_FAST_OBJECTS) { | 4131 if (DEBUG_FAST_OBJECTS) { |
| 4034 ClassElement primitives = | 4132 ClassElement primitives = |
| 4035 compiler.findHelper(const SourceString('Primitives')); | 4133 compiler.findHelper(const SourceString('Primitives')); |
| 4036 FunctionElement printHelper = | 4134 FunctionElement printHelper = |
| 4037 compiler.lookupElementIn( | 4135 compiler.lookupElementIn( |
| 4038 primitives, const SourceString('printString')); | 4136 primitives, const SourceString('printString')); |
| 4039 String printHelperName = namer.isolateAccess(printHelper); | 4137 String printHelperName = namer.isolateAccess(printHelper); |
| 4040 | 4138 |
| 4041 mainBuffer.add(''' | 4139 mainBuffer.add(''' |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 4067 if (typeof $printHelperName === "function") { | 4165 if (typeof $printHelperName === "function") { |
| 4068 $printHelperName("Size of $object: " | 4166 $printHelperName("Size of $object: " |
| 4069 + String(Object.getOwnPropertyNames($object).length) | 4167 + String(Object.getOwnPropertyNames($object).length) |
| 4070 + ", fast properties " + %HasFastProperties($object)); | 4168 + ", fast properties " + %HasFastProperties($object)); |
| 4071 } | 4169 } |
| 4072 '''); | 4170 '''); |
| 4073 } | 4171 } |
| 4074 } | 4172 } |
| 4075 | 4173 |
| 4076 emitMain(mainBuffer); | 4174 emitMain(mainBuffer); |
| 4175 jsAst.FunctionDeclaration precompiledFunctionAst = | |
| 4176 buildPrecompiledFunction(); | |
| 4077 emitInitFunction(mainBuffer); | 4177 emitInitFunction(mainBuffer); |
| 4078 if (!areAnyElementsDeferred) { | 4178 if (!areAnyElementsDeferred) { |
| 4079 mainBuffer.add('})()$n'); | 4179 mainBuffer.add('})()$n'); |
| 4080 } | 4180 } |
| 4081 compiler.assembledCode = mainBuffer.getText(); | 4181 compiler.assembledCode = mainBuffer.getText(); |
| 4082 outputSourceMap(mainBuffer, compiler.assembledCode, ''); | 4182 outputSourceMap(mainBuffer, compiler.assembledCode, ''); |
| 4083 | 4183 |
| 4184 mainBuffer.write( | |
| 4185 jsAst.prettyPrint(precompiledFunctionAst, compiler).getText()); | |
| 4186 | |
| 4187 compiler.outputProvider('precompiled', 'js') | |
| 4188 ..add(mainBuffer.getText()) | |
| 4189 ..close(); | |
| 4190 | |
| 4084 emitDeferredCode(); | 4191 emitDeferredCode(); |
| 4085 | 4192 |
| 4086 }); | 4193 }); |
| 4087 return compiler.assembledCode; | 4194 return compiler.assembledCode; |
| 4088 } | 4195 } |
| 4089 | 4196 |
| 4090 CodeBuffer bufferForElement(Element element, CodeBuffer eagerBuffer) { | 4197 CodeBuffer bufferForElement(Element element, CodeBuffer eagerBuffer) { |
| 4091 Element owner = element.getLibrary(); | 4198 Element owner = element.getLibrary(); |
| 4092 if (!element.isTopLevel() && !element.isNative()) { | 4199 if (!element.isTopLevel() && !element.isNative()) { |
| 4093 // For static (not top level) elements, record their code in a buffer | 4200 // 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 | 4434 |
| 4328 const String HOOKS_API_USAGE = """ | 4435 const String HOOKS_API_USAGE = """ |
| 4329 // The code supports the following hooks: | 4436 // The code supports the following hooks: |
| 4330 // dartPrint(message) - if this function is defined it is called | 4437 // dartPrint(message) - if this function is defined it is called |
| 4331 // instead of the Dart [print] method. | 4438 // instead of the Dart [print] method. |
| 4332 // dartMainRunner(main) - if this function is defined, the Dart [main] | 4439 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 4333 // method will not be invoked directly. | 4440 // method will not be invoked directly. |
| 4334 // Instead, a closure that will invoke [main] is | 4441 // Instead, a closure that will invoke [main] is |
| 4335 // passed to [dartMainRunner]. | 4442 // passed to [dartMainRunner]. |
| 4336 """; | 4443 """; |
| OLD | NEW |