OLD | NEW |
---|---|
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library dart2js.new_js_emitter.model_emitter; | 5 library dart2js.new_js_emitter.model_emitter; |
6 | 6 |
7 import '../../constants/values.dart' show ConstantValue, FunctionConstantValue; | 7 import '../../constants/values.dart' show ConstantValue, FunctionConstantValue; |
8 import '../../dart2jslib.dart' show Compiler; | 8 import '../../dart2jslib.dart' show Compiler; |
9 import '../../dart_types.dart' show DartType; | 9 import '../../dart_types.dart' show DartType; |
10 import '../../elements/elements.dart' show ClassElement, FunctionElement; | 10 import '../../elements/elements.dart' show ClassElement, FunctionElement; |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
110 if (value.isFunction) { | 110 if (value.isFunction) { |
111 FunctionConstantValue functionConstant = value; | 111 FunctionConstantValue functionConstant = value; |
112 return generateStaticClosureAccess(functionConstant.element); | 112 return generateStaticClosureAccess(functionConstant.element); |
113 } | 113 } |
114 | 114 |
115 // We are only interested in the "isInlined" part, but it does not hurt to | 115 // We are only interested in the "isInlined" part, but it does not hurt to |
116 // test for the other predicates. | 116 // test for the other predicates. |
117 if (isConstantInlinedOrAlreadyEmitted(value)) { | 117 if (isConstantInlinedOrAlreadyEmitted(value)) { |
118 return constantEmitter.generate(value); | 118 return constantEmitter.generate(value); |
119 } | 119 } |
120 return js.js('#.#', [namer.globalObjectForConstant(value), | 120 return js.js('#.#()', [namer.globalObjectForConstant(value), |
121 namer.constantName(value)]); | 121 namer.constantName(value)]); |
122 } | 122 } |
123 | 123 |
124 int emitProgram(Program program) { | 124 int emitProgram(Program program) { |
125 List<Fragment> fragments = program.fragments; | 125 List<Fragment> fragments = program.fragments; |
126 MainFragment mainFragment = fragments.first; | 126 MainFragment mainFragment = fragments.first; |
127 | 127 |
128 int totalSize = 0; | 128 int totalSize = 0; |
129 | 129 |
130 // We have to emit the deferred fragments first, since we need their | 130 // We have to emit the deferred fragments first, since we need their |
131 // deferred hash (which depends on the output) when emitting the main | 131 // deferred hash (which depends on the output) when emitting the main |
(...skipping 14 matching lines...) Expand all Loading... | |
146 ..add(mainCode) | 146 ..add(mainCode) |
147 ..close(); | 147 ..close(); |
148 totalSize += mainCode.length; | 148 totalSize += mainCode.length; |
149 | 149 |
150 return totalSize; | 150 return totalSize; |
151 } | 151 } |
152 | 152 |
153 js.LiteralString unparse(Compiler compiler, js.Node value) { | 153 js.LiteralString unparse(Compiler compiler, js.Node value) { |
154 String text = js.prettyPrint(value, compiler).getText(); | 154 String text = js.prettyPrint(value, compiler).getText(); |
155 if (value is js.Fun) text = '($text)'; | 155 if (value is js.Fun) text = '($text)'; |
156 if (value is js.LiteralExpression && | |
floitsch
2015/03/06 19:30:26
This captures the JS_CONST cases that had a litera
| |
157 (value.template.startsWith("function ") || | |
158 value.template.startsWith("{"))) { | |
159 text = '($text)'; | |
160 } | |
156 return js.js.escapedString(text); | 161 return js.js.escapedString(text); |
157 } | 162 } |
158 | 163 |
159 String buildGeneratedBy(compiler) { | 164 String buildGeneratedBy(compiler) { |
160 var suffix = ''; | 165 var suffix = ''; |
161 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}'; | 166 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}'; |
162 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n'; | 167 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n'; |
163 } | 168 } |
164 | 169 |
165 js.Statement emitMainFragment(Program program) { | 170 js.Statement emitMainFragment(Program program) { |
166 MainFragment fragment = program.fragments.first; | 171 MainFragment fragment = program.fragments.first; |
167 List<js.Expression> elements = fragment.libraries.map(emitLibrary).toList(); | 172 List<js.Expression> elements = fragment.libraries.map(emitLibrary).toList(); |
168 elements.add( | 173 elements.add( |
169 emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields)); | 174 emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields)); |
175 elements.add(emitConstants(fragment.constants)); | |
176 | |
170 | 177 |
171 js.Expression code = new js.ArrayInitializer(elements); | 178 js.Expression code = new js.ArrayInitializer(elements); |
172 | 179 |
173 Map<String, dynamic> holes = | 180 Map<String, dynamic> holes = |
174 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), | 181 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), |
175 'holders': emitHolders(program.holders), | 182 'holders': emitHolders(program.holders), |
176 'tearOff': buildTearOffCode(backend), | 183 'tearOff': buildTearOffCode(backend), |
177 'parseFunctionDescriptor': | 184 'parseFunctionDescriptor': |
178 js.js.statement(parseFunctionDescriptorBoilerplate, | 185 js.js.statement(parseFunctionDescriptorBoilerplate, |
179 {'argumentCount': js.string(namer.requiredParameterField), | 186 {'argumentCount': js.string(namer.requiredParameterField), |
180 'defaultArgumentValues': js.string(namer.defaultValuesField), | 187 'defaultArgumentValues': js.string(namer.defaultValuesField), |
181 'callName': js.string(namer.callNameField)}), | 188 'callName': js.string(namer.callNameField)}), |
182 | 189 |
183 'cyclicThrow': | 190 'cyclicThrow': |
184 backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), | 191 backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), |
185 'outputContainsConstantList': program.outputContainsConstantList, | 192 'outputContainsConstantList': program.outputContainsConstantList, |
186 'embeddedGlobals': emitEmbeddedGlobals(program), | 193 'embeddedGlobals': emitEmbeddedGlobals(program), |
187 'constants': emitConstants(fragment.constants), | |
188 'staticNonFinals': | 194 'staticNonFinals': |
189 emitStaticNonFinalFields(fragment.staticNonFinalFields), | 195 emitStaticNonFinalFields(fragment.staticNonFinalFields), |
190 'operatorIsPrefix': js.string(namer.operatorIsPrefix), | 196 'operatorIsPrefix': js.string(namer.operatorIsPrefix), |
191 'callName': js.string(namer.callNameField), | 197 'callName': js.string(namer.callNameField), |
192 'argumentCount': js.string(namer.requiredParameterField), | 198 'argumentCount': js.string(namer.requiredParameterField), |
193 'defaultArgumentValues': js.string(namer.defaultValuesField), | 199 'defaultArgumentValues': js.string(namer.defaultValuesField), |
194 'eagerClasses': emitEagerClassInitializations(fragment.libraries), | 200 'eagerClasses': emitEagerClassInitializations(fragment.libraries), |
195 'invokeMain': fragment.invokeMain, | 201 'invokeMain': fragment.invokeMain, |
196 'code': code}; | 202 'code': code}; |
197 | 203 |
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
414 // TODO(floitsch): initialize eager classes. | 420 // TODO(floitsch): initialize eager classes. |
415 // TODO(floitsch): the hash must depend on the output. | 421 // TODO(floitsch): the hash must depend on the output. |
416 int hash = fragment.hashCode; | 422 int hash = fragment.hashCode; |
417 | 423 |
418 List<js.Expression> deferredCode = | 424 List<js.Expression> deferredCode = |
419 fragment.libraries.map(emitLibrary).toList(); | 425 fragment.libraries.map(emitLibrary).toList(); |
420 | 426 |
421 deferredCode.add( | 427 deferredCode.add( |
422 emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields)); | 428 emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields)); |
423 | 429 |
430 deferredCode.add(emitConstants(fragment.constants)); | |
floitsch
2015/03/06 19:30:26
This line was missing.
| |
431 | |
424 js.ArrayInitializer deferredArray = new js.ArrayInitializer(deferredCode); | 432 js.ArrayInitializer deferredArray = new js.ArrayInitializer(deferredCode); |
425 | 433 |
426 // This is the code that must be evaluated after all deferred classes have | 434 // This is the code that must be evaluated after all deferred classes have |
427 // been setup. | 435 // been setup. |
428 js.Statement immediateCode = js.js.statement('''{ | 436 js.Statement immediateCode = |
429 #constants; | 437 emitEagerClassInitializations(fragment.libraries); |
430 #eagerClasses; | |
431 }''', | |
432 {'constants': emitConstants(fragment.constants), | |
433 'eagerClasses': emitEagerClassInitializations(fragment.libraries)}); | |
434 | 438 |
435 js.LiteralString immediateString = unparse(compiler, immediateCode); | 439 js.LiteralString immediateString = unparse(compiler, immediateCode); |
436 js.ArrayInitializer hunk = | 440 js.ArrayInitializer hunk = |
437 new js.ArrayInitializer([deferredArray, immediateString]); | 441 new js.ArrayInitializer([deferredArray, immediateString]); |
438 | 442 |
439 return js.js("$deferredInitializersGlobal[$hash] = #", hunk); | 443 return js.js("$deferredInitializersGlobal[$hash] = #", hunk); |
440 } | 444 } |
441 | 445 |
442 js.Block emitConstants(List<Constant> constants) { | 446 // This string should be referenced wherever JavaScript code makes assumptions |
443 Iterable<js.Statement> statements = constants.map((Constant constant) { | 447 // on the constants format. |
444 js.Expression code = constantEmitter.generate(constant.value); | 448 static final String constantsDescription = |
445 return js.js.statement("#.# = #;", | 449 "The constants are encoded as a follows:" |
446 [constant.holder.name, constant.name, code]); | 450 " [constantsHolderIndex, name, code, name2, code2, ...]." |
447 }); | 451 "The array is completely empty if there is no constant at all."; |
448 return new js.Block(statements.toList()); | 452 |
453 js.ArrayInitializer emitConstants(List<Constant> constants) { | |
454 List<js.Expression> data = <js.Expression>[]; | |
455 if (constants.isNotEmpty) { | |
456 int holderIndex = constants.first.holder.index; | |
457 data.add(js.number(holderIndex)); | |
458 data.addAll(constants.expand((Constant constant) { | |
459 assert(constant.holder.index == holderIndex); | |
460 js.Expression code = constantEmitter.generate(constant.value); | |
461 return [js.string(constant.name), unparse(compiler, code)]; | |
462 })); | |
463 } | |
464 return new js.ArrayInitializer(data); | |
449 } | 465 } |
450 | 466 |
451 js.Block emitStaticNonFinalFields(List<StaticField> fields) { | 467 js.Block emitStaticNonFinalFields(List<StaticField> fields) { |
452 Iterable<js.Statement> statements = fields.map((StaticField field) { | 468 Iterable<js.Statement> statements = fields.map((StaticField field) { |
453 return js.js.statement("#.# = #;", | 469 return js.js.statement("#.# = #;", |
454 [field.holder.name, field.name, field.code]); | 470 [field.holder.name, field.name, field.code]); |
455 }); | 471 }); |
456 return new js.Block(statements.toList()); | 472 return new js.Block(statements.toList()); |
457 } | 473 } |
458 | 474 |
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
807 | 823 |
808 !function(start, program) { | 824 !function(start, program) { |
809 // Initialize holder objects. | 825 // Initialize holder objects. |
810 #holders; | 826 #holders; |
811 var nativeInfos = Object.create(null); | 827 var nativeInfos = Object.create(null); |
812 | 828 |
813 // Counter to generate unique names for tear offs. | 829 // Counter to generate unique names for tear offs. |
814 var functionCounter = 0; | 830 var functionCounter = 0; |
815 | 831 |
816 function $setupProgramName(program) { | 832 function $setupProgramName(program) { |
817 for (var i = 0; i < program.length - 1; i++) { | 833 for (var i = 0; i < program.length - 2; i++) { |
818 setupLibrary(program[i]); | 834 setupLibrary(program[i]); |
819 } | 835 } |
820 setupLazyStatics(program[i]); | 836 setupLazyStatics(program[i]); |
837 setupConstants(program[i + 1]); | |
821 } | 838 } |
822 | 839 |
823 function setupLibrary(library) { | 840 function setupLibrary(library) { |
824 var statics = library[0]; | 841 var statics = library[0]; |
825 for (var i = 0; i < statics.length; i += 3) { | 842 for (var i = 0; i < statics.length; i += 3) { |
826 var holderIndex = statics[i + 1]; | 843 var holderIndex = statics[i + 1]; |
827 setupStatic(statics[i], holders[holderIndex], statics[i + 2]); | 844 setupStatic(statics[i], holders[holderIndex], statics[i + 2]); |
828 } | 845 } |
829 | 846 |
830 var classes = library[1]; | 847 var classes = library[1]; |
(...skipping 25 matching lines...) Expand all Loading... | |
856 function setupLazyStatics(statics) { | 873 function setupLazyStatics(statics) { |
857 for (var i = 0; i < statics.length; i += 4) { | 874 for (var i = 0; i < statics.length; i += 4) { |
858 var name = statics[i]; | 875 var name = statics[i]; |
859 var getterName = statics[i + 1]; | 876 var getterName = statics[i + 1]; |
860 var holderIndex = statics[i + 2]; | 877 var holderIndex = statics[i + 2]; |
861 var initializer = statics[i + 3]; | 878 var initializer = statics[i + 3]; |
862 setupLazyStatic(name, getterName, holders[holderIndex], initializer); | 879 setupLazyStatic(name, getterName, holders[holderIndex], initializer); |
863 } | 880 } |
864 } | 881 } |
865 | 882 |
883 function setupConstants(constants) { | |
884 // $constantsDescription. | |
885 if (constants.length == 0) return; | |
886 // We assume that all constants are in the same holder. | |
887 var holder = holders[constants[0]]; | |
888 for (var i = 1; i < constants.length; i += 2) { | |
889 var name = constants[i]; | |
890 var initializer = constants[i + 1]; | |
891 setupConstant(name, holder, initializer); | |
892 } | |
893 } | |
894 | |
866 function setupStatic(name, holder, descriptor) { | 895 function setupStatic(name, holder, descriptor) { |
867 if (typeof descriptor == 'string') { | 896 if (typeof descriptor == 'string') { |
868 holder[name] = function() { | 897 holder[name] = function() { |
869 var method = compile(name, descriptor); | 898 var method = compile(name, descriptor); |
870 holder[name] = method; | 899 holder[name] = method; |
871 return method.apply(this, arguments); | 900 return method.apply(this, arguments); |
872 }; | 901 }; |
873 } else { | 902 } else { |
874 // Parse the tear off information and generate compile handlers. | 903 // Parse the tear off information and generate compile handlers. |
875 // TODO(herhut): Share parser with instance methods. | 904 // TODO(herhut): Share parser with instance methods. |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
928 result = holder[name] = sentinelInProgress; | 957 result = holder[name] = sentinelInProgress; |
929 result = holder[name] = initializer(); | 958 result = holder[name] = initializer(); |
930 } finally { | 959 } finally { |
931 // Use try-finally, not try-catch/throw as it destroys the stack trace. | 960 // Use try-finally, not try-catch/throw as it destroys the stack trace. |
932 if (result === sentinelInProgress) { | 961 if (result === sentinelInProgress) { |
933 // The lazy static (holder[name]) might have been set to a different | 962 // The lazy static (holder[name]) might have been set to a different |
934 // value. According to spec we still have to reset it to null, if the | 963 // value. According to spec we still have to reset it to null, if the |
935 // initialization failed. | 964 // initialization failed. |
936 holder[name] = null; | 965 holder[name] = null; |
937 } | 966 } |
967 // TODO(floitsch): the function should probably be unique for each | |
968 // static. | |
938 holder[getterName] = function() { return this[name]; }; | 969 holder[getterName] = function() { return this[name]; }; |
939 } | 970 } |
940 return result; | 971 return result; |
941 }; | 972 }; |
942 } | 973 } |
943 | 974 |
975 function setupConstant(name, holder, descriptor) { | |
976 var c; | |
977 holder[name] = function() { | |
978 if (descriptor !== null) { | |
979 c = compile(name, descriptor); | |
980 name = null; | |
981 descriptor = null; | |
982 } | |
983 return c; | |
984 }; | |
985 } | |
986 | |
944 function setupClass(name, holder, descriptor) { | 987 function setupClass(name, holder, descriptor) { |
945 var patch = function() { | 988 var patch = function() { |
946 var constructor = compileConstructor(name, descriptor); | 989 var constructor = compileConstructor(name, descriptor); |
947 holder[name] = constructor; | 990 holder[name] = constructor; |
948 constructor.ensureResolved = function() { return this; }; | 991 constructor.ensureResolved = function() { return this; }; |
949 if (this === patch) return constructor; // Was used as "ensureResolved". | 992 if (this === patch) return constructor; // Was used as "ensureResolved". |
950 var object = new constructor(); | 993 var object = new constructor(); |
951 constructor.apply(object, arguments); | 994 constructor.apply(object, arguments); |
952 return object; | 995 return object; |
953 }; | 996 }; |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1044 for (var nativeClass in nativeInfos) { | 1087 for (var nativeClass in nativeInfos) { |
1045 var constructor = holdersMap[nativeClass][nativeClass].ensureResolved(); | 1088 var constructor = holdersMap[nativeClass][nativeClass].ensureResolved(); |
1046 var nativeInfo = nativeInfos[nativeClass]; | 1089 var nativeInfo = nativeInfos[nativeClass]; |
1047 #nativeInfoHandler; | 1090 #nativeInfoHandler; |
1048 } | 1091 } |
1049 } | 1092 } |
1050 } | 1093 } |
1051 | 1094 |
1052 $setupProgramName(program); | 1095 $setupProgramName(program); |
1053 | 1096 |
1054 // Initialize constants. | |
1055 #constants; | |
1056 | |
1057 // Initialize globals. | 1097 // Initialize globals. |
1058 #embeddedGlobals; | 1098 #embeddedGlobals; |
1059 | 1099 |
1060 // TODO(floitsch): this order means that native classes may not be | 1100 // TODO(floitsch): this order means that native classes may not be |
1061 // referenced from constants. I'm mostly afraid of things like using them as | 1101 // referenced from constants. I'm mostly afraid of things like using them as |
1062 // generic arguments (which should be fine, but maybe there are other | 1102 // generic arguments (which should be fine, but maybe there are other |
1063 // similar things). | 1103 // similar things). |
1064 // Initialize natives. | 1104 // Initialize natives. |
1065 if (#needsNativeSupport) handleNativeClassInfos(); | 1105 if (#needsNativeSupport) handleNativeClassInfos(); |
1066 | 1106 |
1067 // Initialize static non-final fields. | 1107 // Initialize static non-final fields. |
1068 #staticNonFinals; | 1108 #staticNonFinals; |
1069 | 1109 |
1070 // Add native boilerplate code. | 1110 // Add native boilerplate code. |
1071 #nativeIsolateAffinityTagInitialization; | 1111 #nativeIsolateAffinityTagInitialization; |
1072 | 1112 |
1073 // Initialize eager classes. | 1113 // Initialize eager classes. |
1074 #eagerClasses; | 1114 #eagerClasses; |
1075 | 1115 |
1076 var end = Date.now(); | 1116 var end = Date.now(); |
1077 // print('Setup: ' + (end - start) + ' ms.'); | 1117 // print('Setup: ' + (end - start) + ' ms.'); |
1078 | 1118 |
1079 #invokeMain; // Start main. | 1119 #invokeMain; // Start main. |
1080 | 1120 |
1081 }(Date.now(), #code) | 1121 }(Date.now(), #code) |
1082 }"""; | 1122 }"""; |
1083 | 1123 |
1084 } | 1124 } |
OLD | NEW |