Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(401)

Side by Side Diff: pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart

Issue 952973004: dart2js: create constants lazily in the new emitter. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add constants to deferred libraries. Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698