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

Side by Side Diff: pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart

Issue 1249023002: dart2js: support isolates in the startup-emitter. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Fix typo. Created 5 years, 4 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
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 dart2js.js_emitter.startup_emitter.model_emitter; 5 part of dart2js.js_emitter.startup_emitter.model_emitter;
6 6
7 /// The name of the property that stores the tear-off getter on a static
8 /// function.
9 ///
10 /// This property is only used when isolates are used.
11 ///
12 /// When serializing static functions we transmit the
13 /// name of the static function, but not the name of the function's getter. We
14 /// store the getter-function on the static function itself, which allows us to
15 /// find it easily.
16 const String tearOffPropertyName = r'$tearOff';
17
18 /// The name of the property that stores the list of fields on a constructor.
19 ///
20 /// This property is only used when isolates are used.
21 ///
22 /// When serializing objects we extract all fields from any given object.
23 /// We extract the names of all fields from a fresh empty object. This list
24 /// is cached on the constructor in this property to to avoid too many
25 /// allocations.
26 const String cachedClassFieldNames = r'$cachedFieldNames';
27
7 /// The fast startup emitter's goal is to minimize the amount of work that the 28 /// The fast startup emitter's goal is to minimize the amount of work that the
8 /// JavaScript engine has to do before it can start running user code. 29 /// JavaScript engine has to do before it can start running user code.
9 /// 30 ///
10 /// Whenever possible, the emitter uses object literals instead of updating 31 /// Whenever possible, the emitter uses object literals instead of updating
11 /// objects. 32 /// objects.
12 /// 33 ///
13 /// Example: 34 /// Example:
14 /// 35 ///
15 /// // Holders are initialized directly with the classes and static 36 /// // Holders are initialized directly with the classes and static
16 /// // functions. 37 /// // functions.
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 // The argument [funsOrNames] is an array of strings or functions. If it is a 156 // The argument [funsOrNames] is an array of strings or functions. If it is a
136 // name, then the function should be fetched from the container. The first 157 // name, then the function should be fetched from the container. The first
137 // entry in that array *must* be a string. 158 // entry in that array *must* be a string.
138 // 159 //
139 // TODO(floitsch): Change tearOffCode to accept the data directly, or create a 160 // TODO(floitsch): Change tearOffCode to accept the data directly, or create a
140 // different tearOffCode? 161 // different tearOffCode?
141 function installTearOff(container, getterName, 162 function installTearOff(container, getterName,
142 isStatic, isIntercepted, requiredParameterCount, 163 isStatic, isIntercepted, requiredParameterCount,
143 optionalParameterDefaultValues, 164 optionalParameterDefaultValues,
144 callNames, funsOrNames, funType) { 165 callNames, funsOrNames, funType) {
166 // A function can have several stubs (for example to fill in optional
167 // arguments). We collect these functions in the `funs` array.
145 var funs = []; 168 var funs = [];
146 for (var i = 0; i < funsOrNames.length; i++) { 169 for (var i = 0; i < funsOrNames.length; i++) {
147 var fun = funsOrNames[i]; 170 var fun = funsOrNames[i];
148 if ((typeof fun) == 'string') fun = container[fun]; 171 if ((typeof fun) == 'string') fun = container[fun];
149 fun.#callName = callNames[i]; 172 fun.#callName = callNames[i];
150 funs.push(fun); 173 funs.push(fun);
151 } 174 }
152 175
153 funs[0][#argumentCount] = requiredParameterCount; 176 // The main function to which all stubs redirect.
154 funs[0][#defaultArgumentValues] = optionalParameterDefaultValues; 177 var fun = funs[0];
178
179 fun[#argumentCount] = requiredParameterCount;
180 fun[#defaultArgumentValues] = optionalParameterDefaultValues;
155 var reflectionInfo = funType; 181 var reflectionInfo = funType;
156 if (typeof reflectionInfo == "number") { 182 if (typeof reflectionInfo == "number") {
157 // The reflectionInfo can either be a function, or a pointer into the types 183 // The reflectionInfo can either be a function, or a pointer into the types
158 // table. If it points into the types-table we need to update the index, 184 // table. If it points into the types-table we need to update the index,
159 // in case the tear-off is part of a deferred hunk. 185 // in case the tear-off is part of a deferred hunk.
160 reflectionInfo = reflectionInfo + typesOffset; 186 reflectionInfo = reflectionInfo + typesOffset;
161 } 187 }
162 var name = funsOrNames[0]; 188 var name = funsOrNames[0];
163 container[getterName] = 189 var getterFunction =
164 tearOff(funs, reflectionInfo, isStatic, name, isIntercepted); 190 tearOff(funs, reflectionInfo, isStatic, name, isIntercepted);
191 container[getterName] = getterFunction;
192 if (isStatic) {
193 fun.$tearOffPropertyName = getterFunction;
194 }
165 } 195 }
166 196
167 // Instead of setting the interceptor tags directly we use this update 197 // Instead of setting the interceptor tags directly we use this update
168 // function. This makes it easier for deferred fragments to contribute to the 198 // function. This makes it easier for deferred fragments to contribute to the
169 // embedded global. 199 // embedded global.
170 function setOrUpdateInterceptorsByTag(newTags) { 200 function setOrUpdateInterceptorsByTag(newTags) {
171 var tags = #embeddedInterceptorTags; 201 var tags = #embeddedInterceptorTags;
172 if (!tags) { 202 if (!tags) {
173 #embeddedInterceptorTags = newTags; 203 #embeddedInterceptorTags = newTags;
174 return; 204 return;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 // Update the typesOffset for the next deferred library. 244 // Update the typesOffset for the next deferred library.
215 typesOffset = #embeddedTypes.length; 245 typesOffset = #embeddedTypes.length;
216 246
217 // TODO(floitsch): extend natives. 247 // TODO(floitsch): extend natives.
218 hunk(inherit, mixin, lazy, makeConstList, installTearOff, 248 hunk(inherit, mixin, lazy, makeConstList, installTearOff,
219 updateHolder, updateTypes, setOrUpdateInterceptorsByTag, 249 updateHolder, updateTypes, setOrUpdateInterceptorsByTag,
220 setOrUpdateLeafTags, 250 setOrUpdateLeafTags,
221 #embeddedGlobalsObject, #holdersList, #staticState); 251 #embeddedGlobalsObject, #holdersList, #staticState);
222 } 252 }
223 253
254 // Returns the global with the given [name].
255 function getGlobalFromName(name) {
256 // TODO(floitsch): we are running through all holders. Since negative
257 // lookups are expensive we might need to improve this.
258 // Relies on the fact that all names are unique across all holders.
259 for (var i = 0; i < holders.length; i++) {
260 // The constant holder reuses the same names. Therefore we must skip it.
261 if (holders[i] == #constantHolderReference) continue;
262 // Relies on the fact that all variables are unique.
263 if (holders[i][name]) return holders[i][name];
264 }
265 }
266
224 // Creates the holders. 267 // Creates the holders.
225 #holders; 268 #holders;
226 // TODO(floitsch): if name is not set (for example in IE), run through all 269 // TODO(floitsch): if name is not set (for example in IE), run through all
227 // functions and set the name. 270 // functions and set the name.
228 271
229 // TODO(floitsch): we should build this object as a literal. 272 // TODO(floitsch): we should build this object as a literal.
230 var #staticStateDeclaration = {}; 273 var #staticStateDeclaration = {};
231 274
232 // Sets the prototypes of classes. 275 // Sets the prototypes of classes.
233 #prototypes; 276 #prototypes;
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 'embeddedInterceptorTags': 386 'embeddedInterceptorTags':
344 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG), 387 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG),
345 'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS), 388 'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS),
346 'embeddedGlobalsObject': js.js("init"), 389 'embeddedGlobalsObject': js.js("init"),
347 'holdersList': new js.ArrayInitializer(program.holders.map((holder) { 390 'holdersList': new js.ArrayInitializer(program.holders.map((holder) {
348 return js.js("#", holder.name); 391 return js.js("#", holder.name);
349 }).toList()), 392 }).toList()),
350 'staticStateDeclaration': new js.VariableDeclaration( 393 'staticStateDeclaration': new js.VariableDeclaration(
351 namer.staticStateHolder, allowRename: false), 394 namer.staticStateHolder, allowRename: false),
352 'staticState': js.js('#', namer.staticStateHolder), 395 'staticState': js.js('#', namer.staticStateHolder),
396 'constantHolderReference': buildConstantHolderReference(program),
353 'holders': emitHolders(program.holders, fragment), 397 'holders': emitHolders(program.holders, fragment),
354 'callName': js.string(namer.callNameField), 398 'callName': js.string(namer.callNameField),
355 'argumentCount': js.string(namer.requiredParameterField), 399 'argumentCount': js.string(namer.requiredParameterField),
356 'defaultArgumentValues': js.string(namer.defaultValuesField), 400 'defaultArgumentValues': js.string(namer.defaultValuesField),
357 'prototypes': emitPrototypes(fragment), 401 'prototypes': emitPrototypes(fragment),
358 'inheritance': emitInheritance(fragment), 402 'inheritance': emitInheritance(fragment),
359 'aliases': emitInstanceMethodAliases(fragment), 403 'aliases': emitInstanceMethodAliases(fragment),
360 'tearOffs': emitInstallTearOffs(fragment), 404 'tearOffs': emitInstallTearOffs(fragment),
361 'constants': emitConstants(fragment), 405 'constants': emitConstants(fragment),
362 'staticNonFinalFields': emitStaticNonFinalFields(fragment), 406 'staticNonFinalFields': emitStaticNonFinalFields(fragment),
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
462 new js.VariableDeclarationList(holders 506 new js.VariableDeclarationList(holders
463 .map(emitHolderInitialization) 507 .map(emitHolderInitialization)
464 .toList())), 508 .toList())),
465 js.js.statement('var holders = #', new js.ArrayInitializer( 509 js.js.statement('var holders = #', new js.ArrayInitializer(
466 holders 510 holders
467 .map((holder) => new js.VariableUse(holder.name)) 511 .map((holder) => new js.VariableUse(holder.name))
468 .toList(growable: false)))]; 512 .toList(growable: false)))];
469 return new js.Block(statements); 513 return new js.Block(statements);
470 } 514 }
471 515
516 /// Returns a reference to the constant holder, or the JS-literal `null`.
517 js.Expression buildConstantHolderReference(Program program) {
518 Holder constantHolder = program.holders
519 .firstWhere((Holder holder) => holder.isConstantsHolder,
520 orElse: () => null);
521 if (constantHolder == null) return new js.LiteralNull();
522 return new js.VariableUse(constantHolder.name);
523 }
524
472 /// Emits the given [method]. 525 /// Emits the given [method].
473 /// 526 ///
474 /// A Dart method might result in several JavaScript functions, if it 527 /// A Dart method might result in several JavaScript functions, if it
475 /// requires stubs. The returned map contains the original method and all 528 /// requires stubs. The returned map contains the original method and all
476 /// the stubs it needs. 529 /// the stubs it needs.
477 Map<js.Name, js.Expression> emitStaticMethod(StaticMethod method) { 530 Map<js.Name, js.Expression> emitStaticMethod(StaticMethod method) {
478 Map<js.Name, js.Expression> jsMethods = <js.Name, js.Expression>{}; 531 Map<js.Name, js.Expression> jsMethods = <js.Name, js.Expression>{};
479 532
480 // We don't need to install stub-methods. They can only be used when there 533 // We don't need to install stub-methods. They can only be used when there
481 // are tear-offs, in which case they are emitted there. 534 // are tear-offs, in which case they are emitted there.
(...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after
948 1001
949 return new js.Property(js.string(MANGLED_GLOBAL_NAMES), 1002 return new js.Property(js.string(MANGLED_GLOBAL_NAMES),
950 new js.ObjectInitializer(names)); 1003 new js.ObjectInitializer(names));
951 } 1004 }
952 1005
953 /// Emits the [GET_TYPE_FROM_NAME] embedded global. 1006 /// Emits the [GET_TYPE_FROM_NAME] embedded global.
954 /// 1007 ///
955 /// This embedded global provides a way to go from a class name (which is 1008 /// This embedded global provides a way to go from a class name (which is
956 /// also the constructor's name) to the constructor itself. 1009 /// also the constructor's name) to the constructor itself.
957 js.Property emitGetTypeFromName() { 1010 js.Property emitGetTypeFromName() {
958 // TODO(floitsch): Fix getTypeFromName. It's too inefficient. 1011 js.Expression function = js.js("getGlobalFromName");
959 // The current implementation relies on the fact that the names in holders
960 // are unique across all holders.
961 // TODO(floitsch): constants and other globals may share the same name.
962 // If a global happens to have the same (minified) name this code breaks.
963 // A follow-up CL has a fix for this.
964 js.Expression function =
965 js.js( """function(name) {
966 for (var i = 0; i < holders.length; i++) {
967 // Relies on the fact that all variables are unique.
968 if (holders[i][name]) return holders[i][name];
969 }
970 }""");
971 return new js.Property(js.string(GET_TYPE_FROM_NAME), function); 1012 return new js.Property(js.string(GET_TYPE_FROM_NAME), function);
972 } 1013 }
973 1014
974 /// Emits the [METADATA] embedded global. 1015 /// Emits the [METADATA] embedded global.
975 /// 1016 ///
976 /// The metadata itself has already been computed earlier and is stored in 1017 /// The metadata itself has already been computed earlier and is stored in
977 /// the [program]. 1018 /// the [program].
978 List<js.Property> emitMetadata(Program program) { 1019 List<js.Property> emitMetadata(Program program) {
979 List<js.Property> metadataGlobals = <js.Property>[]; 1020 List<js.Property> metadataGlobals = <js.Property>[];
980 1021
(...skipping 26 matching lines...) Expand all
1007 } 1048 }
1008 1049
1009 if (program.hasIsolateSupport) { 1050 if (program.hasIsolateSupport) {
1010 String staticStateName = namer.staticStateHolder; 1051 String staticStateName = namer.staticStateHolder;
1011 // TODO(floitsch): this doesn't create a new isolate, but just reuses 1052 // TODO(floitsch): this doesn't create a new isolate, but just reuses
1012 // the current static state. Since we don't run multiple isolates in the 1053 // the current static state. Since we don't run multiple isolates in the
1013 // same JavaScript context (except for testing) this shouldn't have any 1054 // same JavaScript context (except for testing) this shouldn't have any
1014 // impact on real-world programs, though. 1055 // impact on real-world programs, though.
1015 globals.add( 1056 globals.add(
1016 new js.Property(js.string(CREATE_NEW_ISOLATE), 1057 new js.Property(js.string(CREATE_NEW_ISOLATE),
1017 js.js('function () { return $staticStateName; }'))); 1058 js.js('function () { return $staticStateName; }')));
1018 // TODO(floitsch): add remaining isolate functions. 1059
1060 js.Expression nameToClosureFunction = js.js('''
1061 // First fetch the static function. From there we can execute its
1062 // getter function which builds a Dart closure.
1063 function(name) {
1064 var staticFunction = getGlobalFromName(name);
1065 var getterFunction = staticFunction.$tearOffPropertyName;
1066 return getterFunction();
1067 }''');
1068 globals.add(new js.Property(js.string(STATIC_FUNCTION_NAME_TO_CLOSURE),
1069 nameToClosureFunction));
1070
1071 globals.add(
1072 new js.Property(js.string(CLASS_ID_EXTRACTOR),
1073 js.js('function(o) { return o.constructor.name; }')));
1074
1075 js.Expression extractFieldsFunction = js.js('''
1076 function(o) {
1077 var constructor = o.constructor;
1078 var fieldNames = constructor.$cachedClassFieldNames;
1079 if (!fieldNames) {
1080 // Extract the fields from an empty unmodified object.
1081 var empty = new constructor();
1082 // This gives us the keys that the constructor sets.
1083 fieldNames = constructor.$cachedClassFieldNames = Object.keys(empty);
1084 }
1085 var result = new Array(fieldNames.length);
1086 for (var i = 0; i < fieldNames.length; i++) {
1087 result[i] = o[fieldNames[i]];
1088 }
1089 return result;
1090 }''');
1091 globals.add(new js.Property(js.string(CLASS_FIELDS_EXTRACTOR),
1092 extractFieldsFunction));
1093
1094 js.Expression createInstanceFromClassIdFunction = js.js('''
1095 function(name) {
1096 var constructor = getGlobalFromName(name);
1097 return new constructor();
1098 }
1099 ''');
1100 globals.add(new js.Property(js.string(INSTANCE_FROM_CLASS_ID),
1101 createInstanceFromClassIdFunction));
1102
1103 js.Expression initializeEmptyInstanceFunction = js.js('''
1104 function(name, o, fields) {
1105 var constructor = o.constructor;
1106 // By construction the object `o` is an empty object with the same
1107 // keys as the one we used in the extract-fields function.
1108 var fieldNames = Object.keys(o);
1109 if (fieldNames.length != fields.length) {
1110 throw new Error("Mismatch during deserialization.");
1111 }
1112 for (var i = 0; i < fields.length; i++) {
1113 o[fieldNames[i]] = fields[i];
1114 }
1115 return o;
1116 }''');
1117 globals.add(new js.Property(js.string(INITIALIZE_EMPTY_INSTANCE),
1118 initializeEmptyInstanceFunction));
1019 } 1119 }
1020 1120
1021 globals.add(emitMangledGlobalNames()); 1121 globals.add(emitMangledGlobalNames());
1022 1122
1023 // The [MANGLED_NAMES] table is only relevant for reflection. 1123 // The [MANGLED_NAMES] table is only relevant for reflection.
1024 // TODO(floitsch): verify that this is correct. 1124 // TODO(floitsch): verify that this is correct.
1025 globals.add(new js.Property(js.string(MANGLED_NAMES), 1125 globals.add(new js.Property(js.string(MANGLED_NAMES),
1026 new js.ObjectInitializer([]))); 1126 new js.ObjectInitializer([])));
1027 1127
1028 globals.add(emitGetTypeFromName()); 1128 globals.add(emitGetTypeFromName());
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1099 } 1199 }
1100 } 1200 }
1101 statements.add(js.js.statement("setOrUpdateInterceptorsByTag(#);", 1201 statements.add(js.js.statement("setOrUpdateInterceptorsByTag(#);",
1102 js.objectLiteral(interceptorsByTag))); 1202 js.objectLiteral(interceptorsByTag)));
1103 statements.add(js.js.statement("setOrUpdateLeafTags(#);", 1203 statements.add(js.js.statement("setOrUpdateLeafTags(#);",
1104 js.objectLiteral(leafTags))); 1204 js.objectLiteral(leafTags)));
1105 statements.add(subclassAssignment); 1205 statements.add(subclassAssignment);
1106 1206
1107 return new js.Block(statements); 1207 return new js.Block(statements);
1108 } 1208 }
1109 } 1209 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698