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 |