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 |