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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_backend/backend.dart

Issue 16077015: Rip-off the backend type inferrer. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 6 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 | sdk/lib/_internal/compiler/implementation/ssa/builder.dart » ('j') | 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) 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 typedef void Recompile(Element element);
8
9 class ReturnInfo {
10 HType returnType;
11 List<Element> compiledFunctions;
12
13 ReturnInfo(HType this.returnType)
14 : compiledFunctions = new List<Element>();
15
16 ReturnInfo.unknownType() : this(null);
17
18 void update(HType type, Recompile recompile, Compiler compiler) {
19 HType newType =
20 returnType != null ? returnType.union(type, compiler) : type;
21 if (newType != returnType) {
22 if (returnType == null && identical(newType, HType.UNKNOWN)) {
23 // If the first actual piece of information is not providing any type
24 // information there is no need to recompile callers.
25 compiledFunctions.clear();
26 }
27 returnType = newType;
28 if (recompile != null) {
29 compiledFunctions.forEach(recompile);
30 }
31 compiledFunctions.clear();
32 }
33 }
34
35 // Note that lazy initializers are treated like functions (but are not
36 // of type [FunctionElement].
37 addCompiledFunction(Element function) => compiledFunctions.add(function);
38 }
39
40 class OptionalParameterTypes {
41 final List<SourceString> names;
42 final List<HType> types;
43
44 OptionalParameterTypes(int optionalArgumentsCount)
45 : names = new List<SourceString>(optionalArgumentsCount),
46 types = new List<HType>(optionalArgumentsCount);
47
48 int get length => names.length;
49 SourceString name(int index) => names[index];
50 HType type(int index) => types[index];
51 int indexOf(SourceString name) => names.indexOf(name);
52
53 HType typeFor(SourceString name) {
54 int index = indexOf(name);
55 if (index == -1) return null;
56 return type(index);
57 }
58
59 void update(int index, SourceString name, HType type) {
60 names[index] = name;
61 types[index] = type;
62 }
63
64 String toString() => "OptionalParameterTypes($names, $types)";
65 }
66
67 class HTypeList {
68 final List<HType> types;
69 final List<SourceString> namedArguments;
70
71 HTypeList(int length)
72 : types = new List<HType>(length),
73 namedArguments = null;
74 HTypeList.withNamedArguments(int length, this.namedArguments)
75 : types = new List<HType>(length);
76 const HTypeList.withAllUnknown()
77 : types = null,
78 namedArguments = null;
79
80 factory HTypeList.fromStaticInvocation(HInvokeStatic node) {
81 bool allUnknown = true;
82 for (int i = 0; i < node.inputs.length; i++) {
83 if (node.inputs[i].instructionType != HType.UNKNOWN) {
84 allUnknown = false;
85 break;
86 }
87 }
88 if (allUnknown) return HTypeList.ALL_UNKNOWN;
89
90 HTypeList result = new HTypeList(node.inputs.length);
91 for (int i = 0; i < result.types.length; i++) {
92 result.types[i] = node.inputs[i].instructionType;
93 }
94 return result;
95 }
96
97 factory HTypeList.fromDynamicInvocation(HInvoke node,
98 Selector selector) {
99 HTypeList result;
100 int argumentsCount = node.inputs.length - 1;
101 int startInvokeIndex = HInvoke.ARGUMENTS_OFFSET;
102
103 if (node.isInterceptedCall) {
104 argumentsCount--;
105 startInvokeIndex++;
106 }
107
108 if (selector.namedArgumentCount > 0) {
109 result =
110 new HTypeList.withNamedArguments(
111 argumentsCount, selector.namedArguments);
112 } else {
113 result = new HTypeList(argumentsCount);
114 }
115
116 for (int i = 0; i < result.types.length; i++) {
117 result.types[i] = node.inputs[i + startInvokeIndex].instructionType;
118 }
119 return result;
120 }
121
122 static const HTypeList ALL_UNKNOWN = const HTypeList.withAllUnknown();
123
124 bool get allUnknown => types == null;
125 bool get hasNamedArguments => namedArguments != null;
126 int get length => types.length;
127 HType operator[](int index) => types[index];
128 void operator[]=(int index, HType type) { types[index] = type; }
129
130 HTypeList union(HTypeList other, Compiler compiler) {
131 if (allUnknown) return this;
132 if (other.allUnknown) return other;
133 if (length != other.length) return HTypeList.ALL_UNKNOWN;
134 bool onlyUnknown = true;
135 HTypeList result = this;
136 for (int i = 0; i < length; i++) {
137 HType newType = this[i].union(other[i], compiler);
138 if (result == this && newType != this[i]) {
139 // Create a new argument types object with the matching types copied.
140 result = new HTypeList(length);
141 result.types.setRange(0, i, this.types);
142 }
143 if (result != this) {
144 result.types[i] = newType;
145 }
146 if (result[i] != HType.UNKNOWN) onlyUnknown = false;
147 }
148 return onlyUnknown ? HTypeList.ALL_UNKNOWN : result;
149 }
150
151 HTypeList unionWithOptionalParameters(
152 Selector selector,
153 FunctionSignature signature,
154 OptionalParameterTypes defaultValueTypes) {
155 assert(allUnknown || selector.argumentCount == this.length);
156 // Create a new HTypeList for holding types for all parameters.
157 HTypeList result = new HTypeList(signature.parameterCount);
158
159 // First fill in the type of the positional arguments.
160 int nextTypeIndex = -1;
161 if (allUnknown) {
162 for (int i = 0; i < selector.positionalArgumentCount; i++) {
163 result.types[i] = HType.UNKNOWN;
164 }
165 } else {
166 result.types.setRange(0, selector.positionalArgumentCount, this.types);
167 nextTypeIndex = selector.positionalArgumentCount;
168 }
169
170 // Next fill the type of the optional arguments.
171 // As the selector can pass optional arguments positionally some of the
172 // optional arguments might already have a type set. We only need to look
173 // at the optional arguments not passed positionally.
174 // The variable 'index' is counting the signatures optional arguments, the
175 // variable 'next' is set to the next optional arguments to look at and
176 // is used to skip some optional arguments.
177 int next = selector.positionalArgumentCount;
178 int index = signature.requiredParameterCount;
179 signature.forEachOptionalParameter((Element element) {
180 // If some optional parameters were passed positionally these have
181 // already been filled.
182 if (index == next) {
183 assert(result.types[index] == null);
184 HType type = null;
185 if (hasNamedArguments &&
186 selector.namedArguments.indexOf(element.name) >= 0) {
187 type = types[nextTypeIndex++];
188 } else {
189 type = defaultValueTypes.typeFor(element.name);
190 }
191 result.types[index] = type;
192 next++;
193 }
194 index++;
195 });
196 return result;
197 }
198
199 String toString() =>
200 allUnknown ? "HTypeList.ALL_UNKNOWN" : "HTypeList $types";
201 }
202
203 class FieldTypesRegistry {
204 final JavaScriptBackend backend;
205
206 /**
207 * For each class, [constructors] holds the set of constructors. If there is
208 * more than one constructor for a class it is currently not possible to
209 * infer the field types from construction, as the information collected does
210 * not correlate the generative constructors and generative constructor
211 * body/bodies.
212 */
213 final Map<ClassElement, Set<Element>> constructors;
214
215 /**
216 * The collected type information is stored in three maps. One for types
217 * assigned in the initializer list(s) [fieldInitializerTypeMap], one for
218 * types assigned in the constructor(s) [fieldConstructorTypeMap], and one
219 * for types assigned in the rest of the code, where the field can be
220 * resolved [fieldTypeMap].
221 *
222 * If a field has a type both from constructors and from the initializer
223 * list(s), then the type from the constructor(s) will owerride the one from
224 * the initializer list(s).
225 *
226 * Because the order in which generative constructors, generative constructor
227 * bodies and normal method/function bodies are compiled is undefined, and
228 * because they can all be recompiled, it is not possible to combine this
229 * information into one map at the moment.
230 */
231 final Map<Element, HType> fieldInitializerTypeMap;
232 final Map<Element, HType> fieldConstructorTypeMap;
233 final Map<Element, HType> fieldTypeMap;
234
235 /**
236 * The set of current names setter selectors used. If a named selector is
237 * used it is currently not possible to infer the type of the field.
238 */
239 final Set<SourceString> setterSelectorsUsed;
240
241 final Map<Element, Set<Element>> optimizedStaticFunctions;
242 final Map<Element, FunctionSet> optimizedFunctions;
243
244 FieldTypesRegistry(JavaScriptBackend backend)
245 : constructors = new Map<ClassElement, Set<Element>>(),
246 fieldInitializerTypeMap = new Map<Element, HType>(),
247 fieldConstructorTypeMap = new Map<Element, HType>(),
248 fieldTypeMap = new Map<Element, HType>(),
249 setterSelectorsUsed = new Set<SourceString>(),
250 optimizedStaticFunctions = new Map<Element, Set<Element>>(),
251 optimizedFunctions = new Map<Element, FunctionSet>(),
252 this.backend = backend;
253
254 Compiler get compiler => backend.compiler;
255
256 void scheduleRecompilation(Element field) {
257 Set optimizedStatics = optimizedStaticFunctions[field];
258 if (optimizedStatics != null) {
259 optimizedStatics.forEach(backend.scheduleForRecompilation);
260 optimizedStaticFunctions.remove(field);
261 }
262 FunctionSet optimized = optimizedFunctions[field];
263 if (optimized != null) {
264 optimized.forEach(backend.scheduleForRecompilation);
265 optimizedFunctions.remove(field);
266 }
267 }
268
269 int constructorCount(Element element) {
270 assert(element.isClass());
271 Set<Element> ctors = constructors[element];
272 return ctors == null ? 0 : ctors.length;
273 }
274
275 void registerFieldType(Map<Element, HType> typeMap,
276 Element field,
277 HType type) {
278 assert(field.isField());
279 HType before = optimisticFieldType(field);
280
281 HType oldType = typeMap[field];
282 HType newType;
283
284 if (oldType != null) {
285 newType = oldType.union(type, compiler);
286 } else {
287 newType = type;
288 }
289 typeMap[field] = newType;
290 if (oldType != newType) {
291 scheduleRecompilation(field);
292 }
293 }
294
295 void registerConstructor(Element element) {
296 assert(element.isGenerativeConstructor());
297 Element cls = element.getEnclosingClass();
298 constructors.putIfAbsent(cls, () => new Set<Element>());
299 Set<Element> ctors = constructors[cls];
300 if (ctors.contains(element)) return;
301 ctors.add(element);
302 // We cannot infer field types for classes with more than one constructor.
303 // When the second constructor is seen, recompile all functions relying on
304 // optimistic field types for that class.
305 // TODO(sgjesse): Handle field types for classes with more than one
306 // constructor.
307 if (ctors.length == 2) {
308 optimizedFunctions.keys.toList().forEach((Element field) {
309 if (identical(field.enclosingElement, cls)) {
310 scheduleRecompilation(field);
311 }
312 });
313 }
314 }
315
316 void registerFieldInitializer(Element field, HType type) {
317 registerFieldType(fieldInitializerTypeMap, field, type);
318 }
319
320 void registerFieldConstructor(Element field, HType type) {
321 registerFieldType(fieldConstructorTypeMap, field, type);
322 }
323
324 void registerFieldSetter(Element element, Element field, HType type) {
325 HType initializerType = fieldInitializerTypeMap[field];
326 HType constructorType = fieldConstructorTypeMap[field];
327 HType setterType = fieldTypeMap[field];
328 if (type == HType.UNKNOWN
329 && initializerType == null
330 && constructorType == null
331 && setterType == null) {
332 // Don't register UNKNOWN if there is currently no type information
333 // present for the field. Instead register the function holding the
334 // setter for recompilation if better type information for the field
335 // becomes available.
336 registerOptimizedFunction(element, field, type);
337 return;
338 }
339 registerFieldType(fieldTypeMap, field, type);
340 }
341
342 void addedDynamicSetter(Selector setter, HType type) {
343 // Field type optimizations are disabled for all fields matching a
344 // setter selector.
345 assert(setter.isSetter());
346 // TODO(sgjesse): Take the type of the setter into account.
347 if (setterSelectorsUsed.contains(setter.name)) return;
348 setterSelectorsUsed.add(setter.name);
349 optimizedStaticFunctions.keys.toList().forEach((Element field) {
350 if (field.name == setter.name) {
351 scheduleRecompilation(field);
352 }
353 });
354 optimizedFunctions.keys.toList().forEach((Element field) {
355 if (field.name == setter.name) {
356 scheduleRecompilation(field);
357 }
358 });
359 }
360
361 HType optimisticFieldType(Element field) {
362 assert(field.isField());
363 if (constructorCount(field.getEnclosingClass()) > 1) {
364 return HType.UNKNOWN;
365 }
366 if (setterSelectorsUsed.contains(field.name)) {
367 return HType.UNKNOWN;
368 }
369 HType initializerType = fieldInitializerTypeMap[field];
370 HType constructorType = fieldConstructorTypeMap[field];
371 if (initializerType == null && constructorType == null) {
372 // If there are no constructor type information return UNKNOWN. This
373 // ensures that the function will be recompiled if useful constructor
374 // type information becomes available.
375 return HType.UNKNOWN;
376 }
377 // A type set through the constructor overrides the type from the
378 // initializer list.
379 HType result = constructorType != null ? constructorType : initializerType;
380 HType type = fieldTypeMap[field];
381 if (type != null) result = result.union(type, compiler);
382 return result;
383 }
384
385 void registerOptimizedFunction(Element element,
386 Element field,
387 HType type) {
388 assert(field.isField());
389 if (Elements.isStaticOrTopLevel(element)) {
390 optimizedStaticFunctions.putIfAbsent(
391 field, () => new Set<Element>());
392 optimizedStaticFunctions[field].add(element);
393 } else {
394 optimizedFunctions.putIfAbsent(
395 field, () => new FunctionSet(backend.compiler));
396 optimizedFunctions[field].add(element);
397 }
398 }
399
400 void dump() {
401 Set<Element> allFields = new Set<Element>();
402 fieldInitializerTypeMap.keys.forEach(allFields.add);
403 fieldConstructorTypeMap.keys.forEach(allFields.add);
404 fieldTypeMap.keys.forEach(allFields.add);
405 allFields.forEach((Element field) {
406 print("Inferred $field has type ${optimisticFieldType(field)}");
407 });
408 }
409 }
410
411 class ArgumentTypesRegistry {
412 final JavaScriptBackend backend;
413
414 /**
415 * Documentation wanted -- johnniwinther
416 *
417 * Invariant: Keys must be declaration elements.
418 */
419 final Map<Element, HTypeList> staticTypeMap;
420
421 /**
422 * Documentation wanted -- johnniwinther
423 *
424 * Invariant: Elements must be declaration elements.
425 */
426 final Set<Element> optimizedStaticFunctions;
427 final SelectorMap<HTypeList> selectorTypeMap;
428 final FunctionSet optimizedFunctions;
429
430 /**
431 * Documentation wanted -- johnniwinther
432 *
433 * Invariant: Keys must be declaration elements.
434 */
435 final Map<Element, HTypeList> optimizedTypes;
436 final Map<Element, OptionalParameterTypes> optimizedDefaultValueTypes;
437
438 ArgumentTypesRegistry(JavaScriptBackend backend)
439 : staticTypeMap = new Map<Element, HTypeList>(),
440 optimizedStaticFunctions = new Set<Element>(),
441 selectorTypeMap = new SelectorMap<HTypeList>(backend.compiler),
442 optimizedFunctions = new FunctionSet(backend.compiler),
443 optimizedTypes = new Map<Element, HTypeList>(),
444 optimizedDefaultValueTypes =
445 new Map<Element, OptionalParameterTypes>(),
446 this.backend = backend;
447
448 Compiler get compiler => backend.compiler;
449
450 bool updateTypes(HTypeList oldTypes, HTypeList newTypes, var key, var map) {
451 if (oldTypes.allUnknown) return false;
452 newTypes = oldTypes.union(newTypes, backend.compiler);
453 if (identical(newTypes, oldTypes)) return false;
454 map[key] = newTypes;
455 return true;
456 }
457
458 void registerStaticInvocation(HInvokeStatic node) {
459 Element element = node.element;
460 assert(invariant(node, element.isDeclaration));
461 HTypeList oldTypes = staticTypeMap[element];
462 HTypeList newTypes = new HTypeList.fromStaticInvocation(node);
463 if (oldTypes == null) {
464 staticTypeMap[element] = newTypes;
465 } else if (updateTypes(oldTypes, newTypes, element, staticTypeMap)) {
466 if (optimizedStaticFunctions.contains(element)) {
467 backend.scheduleForRecompilation(element);
468 }
469 }
470 }
471
472 void registerNonCallStaticUse(HStatic node) {
473 // When a static is used for anything else than a call target we cannot
474 // infer anything about its parameter types.
475 Element element = node.element;
476 assert(invariant(node, element.isDeclaration));
477 if (optimizedStaticFunctions.contains(element)) {
478 backend.scheduleForRecompilation(element);
479 }
480 staticTypeMap[element] = HTypeList.ALL_UNKNOWN;
481 }
482
483 void registerDynamicInvocation(HTypeList providedTypes, Selector selector) {
484 if (selector.isClosureCall()) {
485 // We cannot use the current framework to do optimizations based
486 // on the 'call' selector because we are also generating closure
487 // calls during the emitter phase, which at this point, does not
488 // track parameter types, nor invalidates optimized methods.
489 return;
490 }
491 if (!selectorTypeMap.containsKey(selector)) {
492 selectorTypeMap[selector] = providedTypes;
493 } else {
494 HTypeList oldTypes = selectorTypeMap[selector];
495 updateTypes(oldTypes, providedTypes, selector, selectorTypeMap);
496 }
497
498 // If we're not compiling, we don't have to do anything.
499 if (compiler.phase != Compiler.PHASE_COMPILING) return;
500
501 // Run through all optimized functions and figure out if they need
502 // to be recompiled because of this new invocation.
503 for (Element element in optimizedFunctions.filter(selector)) {
504 // TODO(kasperl): Maybe check if the element is already marked for
505 // recompilation? Could be pretty cheap compared to computing
506 // union types.
507 HTypeList newTypes =
508 parameterTypes(element, optimizedDefaultValueTypes[element]);
509 bool recompile = false;
510 if (newTypes.allUnknown) {
511 recompile = true;
512 } else {
513 HTypeList oldTypes = optimizedTypes[element];
514 assert(newTypes.length == oldTypes.length);
515 for (int i = 0; i < oldTypes.length; i++) {
516 if (newTypes[i] != oldTypes[i]) {
517 recompile = true;
518 break;
519 }
520 }
521 }
522 if (recompile) backend.scheduleForRecompilation(element);
523 }
524 }
525
526 HTypeList parameterTypes(FunctionElement element,
527 OptionalParameterTypes defaultValueTypes) {
528 assert(invariant(element, element.isDeclaration));
529 // Handle static functions separately.
530 if (Elements.isStaticOrTopLevelFunction(element) ||
531 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
532 HTypeList types = staticTypeMap[element];
533 if (types != null) {
534 if (!optimizedStaticFunctions.contains(element)) {
535 optimizedStaticFunctions.add(element);
536 }
537 return types;
538 } else {
539 return HTypeList.ALL_UNKNOWN;
540 }
541 }
542
543 // Getters have no parameters.
544 if (element.isGetter()) return HTypeList.ALL_UNKNOWN;
545
546 // TODO(kasperl): What kind of non-members do we get here?
547 if (!element.isMember()) return HTypeList.ALL_UNKNOWN;
548
549 // If there are any getters for this method we cannot know anything about
550 // the types of the provided parameters. Use resolverWorld for now as that
551 // information does not change during compilation.
552 // TODO(ngeoffray): These checks should use the codegenWorld and keep track
553 // of changes to this information.
554 if (compiler.resolverWorld.hasInvokedGetter(element, compiler)) {
555 return HTypeList.ALL_UNKNOWN;
556 }
557
558 FunctionSignature signature = element.computeSignature(compiler);
559 HTypeList found = null;
560 selectorTypeMap.visitMatching(element,
561 (Selector selector, HTypeList types) {
562 if (selector.argumentCount != signature.parameterCount ||
563 selector.namedArgumentCount > 0) {
564 types = types.unionWithOptionalParameters(selector,
565 signature,
566 defaultValueTypes);
567 }
568 assert(types.allUnknown || types.length == signature.parameterCount);
569 found = (found == null) ? types : found.union(types, compiler);
570 return !found.allUnknown;
571 });
572 return found != null ? found : HTypeList.ALL_UNKNOWN;
573 }
574
575 void registerOptimizedFunction(Element element,
576 HTypeList parameterTypes,
577 OptionalParameterTypes defaultValueTypes) {
578 if (Elements.isStaticOrTopLevelFunction(element)) {
579 if (parameterTypes.allUnknown) {
580 optimizedStaticFunctions.remove(element);
581 } else {
582 optimizedStaticFunctions.add(element);
583 }
584 }
585
586 // TODO(kasperl): What kind of non-members do we get here?
587 if (!element.isInstanceMember()) return;
588
589 if (parameterTypes.allUnknown) {
590 optimizedFunctions.remove(element);
591 optimizedTypes.remove(element);
592 optimizedDefaultValueTypes.remove(element);
593 } else {
594 optimizedFunctions.add(element);
595 optimizedTypes[element] = parameterTypes;
596 optimizedDefaultValueTypes[element] = defaultValueTypes;
597 }
598 }
599
600 void dump() {
601 optimizedFunctions.forEach((Element element) {
602 HTypeList types = optimizedTypes[element];
603 print("Inferred $element has argument types ${types.types}");
604 });
605 }
606 }
607
608 class JavaScriptItemCompilationContext extends ItemCompilationContext { 7 class JavaScriptItemCompilationContext extends ItemCompilationContext {
609 final Set<HInstruction> boundsChecked; 8 final Set<HInstruction> boundsChecked;
610 9
611 JavaScriptItemCompilationContext() 10 JavaScriptItemCompilationContext()
612 : boundsChecked = new Set<HInstruction>(); 11 : boundsChecked = new Set<HInstruction>();
613 } 12 }
614 13
615 class JavaScriptBackend extends Backend { 14 class JavaScriptBackend extends Backend {
616 SsaBuilderTask builder; 15 SsaBuilderTask builder;
617 SsaOptimizerTask optimizer; 16 SsaOptimizerTask optimizer;
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
684 83
685 final Namer namer; 84 final Namer namer;
686 85
687 /** 86 /**
688 * Interface used to determine if an object has the JavaScript 87 * Interface used to determine if an object has the JavaScript
689 * indexing behavior. The interface is only visible to specific 88 * indexing behavior. The interface is only visible to specific
690 * libraries. 89 * libraries.
691 */ 90 */
692 ClassElement jsIndexingBehaviorInterface; 91 ClassElement jsIndexingBehaviorInterface;
693 92
694 final Map<Element, ReturnInfo> returnInfo;
695
696 /**
697 * Documentation wanted -- johnniwinther
698 *
699 * Invariant: Elements must be declaration elements.
700 */
701 final List<Element> invalidateAfterCodegen;
702 ArgumentTypesRegistry argumentTypes;
703 FieldTypesRegistry fieldTypes;
704
705 /** 93 /**
706 * A collection of selectors of intercepted method calls. The 94 * A collection of selectors of intercepted method calls. The
707 * emitter uses this set to generate the [:ObjectInterceptor:] class 95 * emitter uses this set to generate the [:ObjectInterceptor:] class
708 * whose members just forward the call to the intercepted receiver. 96 * whose members just forward the call to the intercepted receiver.
709 */ 97 */
710 final Set<Selector> usedInterceptors; 98 final Set<Selector> usedInterceptors;
711 99
712 /** 100 /**
713 * A collection of selectors that must have a one shot interceptor 101 * A collection of selectors that must have a one shot interceptor
714 * generated. 102 * generated.
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
755 final Set<ClassElement> specialOperatorEqClasses = new Set<ClassElement>(); 143 final Set<ClassElement> specialOperatorEqClasses = new Set<ClassElement>();
756 144
757 List<CompilerTask> get tasks { 145 List<CompilerTask> get tasks {
758 return <CompilerTask>[builder, optimizer, generator, emitter]; 146 return <CompilerTask>[builder, optimizer, generator, emitter];
759 } 147 }
760 148
761 final RuntimeTypes rti; 149 final RuntimeTypes rti;
762 150
763 JavaScriptBackend(Compiler compiler, bool generateSourceMap, bool disableEval) 151 JavaScriptBackend(Compiler compiler, bool generateSourceMap, bool disableEval)
764 : namer = determineNamer(compiler), 152 : namer = determineNamer(compiler),
765 returnInfo = new Map<Element, ReturnInfo>(),
766 invalidateAfterCodegen = new List<Element>(),
767 usedInterceptors = new Set<Selector>(), 153 usedInterceptors = new Set<Selector>(),
768 oneShotInterceptors = new Map<String, Selector>(), 154 oneShotInterceptors = new Map<String, Selector>(),
769 interceptedElements = new Map<SourceString, Set<Element>>(), 155 interceptedElements = new Map<SourceString, Set<Element>>(),
770 rti = new RuntimeTypes(compiler), 156 rti = new RuntimeTypes(compiler),
771 specializedGetInterceptors = new Map<String, Set<ClassElement>>(), 157 specializedGetInterceptors = new Map<String, Set<ClassElement>>(),
772 super(compiler, JAVA_SCRIPT_CONSTANT_SYSTEM) { 158 super(compiler, JAVA_SCRIPT_CONSTANT_SYSTEM) {
773 emitter = disableEval 159 emitter = disableEval
774 ? new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap) 160 ? new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap)
775 : new CodeEmitterTask(compiler, namer, generateSourceMap); 161 : new CodeEmitterTask(compiler, namer, generateSourceMap);
776 builder = new SsaBuilderTask(this); 162 builder = new SsaBuilderTask(this);
777 optimizer = new SsaOptimizerTask(this); 163 optimizer = new SsaOptimizerTask(this);
778 generator = new SsaCodeGeneratorTask(this); 164 generator = new SsaCodeGeneratorTask(this);
779 argumentTypes = new ArgumentTypesRegistry(this);
780 fieldTypes = new FieldTypesRegistry(this);
781 } 165 }
782 166
783 static Namer determineNamer(Compiler compiler) { 167 static Namer determineNamer(Compiler compiler) {
784 return compiler.enableMinification ? 168 return compiler.enableMinification ?
785 new MinifyNamer(compiler) : 169 new MinifyNamer(compiler) :
786 new Namer(compiler); 170 new Namer(compiler);
787 } 171 }
788 172
789 bool isInterceptorClass(ClassElement element) { 173 bool isInterceptorClass(ClassElement element) {
790 if (element == null) return false; 174 if (element == null) return false;
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after
1045 String name = namer.getInterceptorName(getInterceptorMethod, classes); 429 String name = namer.getInterceptorName(getInterceptorMethod, classes);
1046 if (classes.contains(jsInterceptorClass)) { 430 if (classes.contains(jsInterceptorClass)) {
1047 // We can't use a specialized [getInterceptorMethod], so we make 431 // We can't use a specialized [getInterceptorMethod], so we make
1048 // sure we emit the one with all checks. 432 // sure we emit the one with all checks.
1049 specializedGetInterceptors[name] = interceptedClasses; 433 specializedGetInterceptors[name] = interceptedClasses;
1050 } else { 434 } else {
1051 specializedGetInterceptors[name] = classes; 435 specializedGetInterceptors[name] = classes;
1052 } 436 }
1053 } 437 }
1054 438
1055 void initializeNoSuchMethod() {
1056 // In case the emitter generates noSuchMethod calls, we need to
1057 // make sure all [noSuchMethod] methods know they might take a
1058 // [JsInvocationMirror] as parameter.
1059 HTypeList types = new HTypeList(1);
1060 types[0] = new HType.nonNullExact(
1061 compiler.jsInvocationMirrorClass.computeType(compiler),
1062 compiler);
1063 argumentTypes.registerDynamicInvocation(
1064 types, compiler.noSuchMethodSelector);
1065 }
1066
1067 void registerInstantiatedClass(ClassElement cls, 439 void registerInstantiatedClass(ClassElement cls,
1068 Enqueuer enqueuer, 440 Enqueuer enqueuer,
1069 TreeElements elements) { 441 TreeElements elements) {
1070 if (!seenAnyClass) { 442 if (!seenAnyClass) {
1071 initializeNoSuchMethod();
1072 seenAnyClass = true; 443 seenAnyClass = true;
1073 if (enqueuer.isResolutionQueue) { 444 if (enqueuer.isResolutionQueue) {
1074 // TODO(9577): Make it so that these are not needed when there are no 445 // TODO(9577): Make it so that these are not needed when there are no
1075 // native classes. 446 // native classes.
1076 enqueuer.registerStaticUse(getNativeInterceptorMethod); 447 enqueuer.registerStaticUse(getNativeInterceptorMethod);
1077 enqueuer.registerStaticUse(defineNativeMethodsFinishMethod); 448 enqueuer.registerStaticUse(defineNativeMethodsFinishMethod);
1078 enqueuer.registerStaticUse(initializeDispatchPropertyMethod); 449 enqueuer.registerStaticUse(initializeDispatchPropertyMethod);
1079 enqueuer.registerInstantiatedClass(jsInterceptorClass, 450 enqueuer.registerInstantiatedClass(jsInterceptorClass,
1080 compiler.globalDependencies); 451 compiler.globalDependencies);
1081 } 452 }
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after
1404 optimizer.optimize(work, graph, false); 775 optimizer.optimize(work, graph, false);
1405 if (work.allowSpeculativeOptimization 776 if (work.allowSpeculativeOptimization
1406 && optimizer.trySpeculativeOptimizations(work, graph)) { 777 && optimizer.trySpeculativeOptimizations(work, graph)) {
1407 jsAst.Expression code = generator.generateBailoutMethod(work, graph); 778 jsAst.Expression code = generator.generateBailoutMethod(work, graph);
1408 generatedBailoutCode[element] = code; 779 generatedBailoutCode[element] = code;
1409 optimizer.prepareForSpeculativeOptimizations(work, graph); 780 optimizer.prepareForSpeculativeOptimizations(work, graph);
1410 optimizer.optimize(work, graph, true); 781 optimizer.optimize(work, graph, true);
1411 } 782 }
1412 jsAst.Expression code = generator.generateCode(work, graph); 783 jsAst.Expression code = generator.generateCode(work, graph);
1413 generatedCode[element] = code; 784 generatedCode[element] = code;
1414 invalidateAfterCodegen.forEach(eagerRecompile);
1415 invalidateAfterCodegen.clear();
1416 } 785 }
1417 786
1418 native.NativeEnqueuer nativeResolutionEnqueuer(Enqueuer world) { 787 native.NativeEnqueuer nativeResolutionEnqueuer(Enqueuer world) {
1419 return new native.NativeResolutionEnqueuer(world, compiler); 788 return new native.NativeResolutionEnqueuer(world, compiler);
1420 } 789 }
1421 790
1422 native.NativeEnqueuer nativeCodegenEnqueuer(Enqueuer world) { 791 native.NativeEnqueuer nativeCodegenEnqueuer(Enqueuer world) {
1423 return new native.NativeCodegenEnqueuer(world, compiler, emitter); 792 return new native.NativeCodegenEnqueuer(world, compiler, emitter);
1424 } 793 }
1425 794
1426 ClassElement defaultSuperclass(ClassElement element) { 795 ClassElement defaultSuperclass(ClassElement element) {
1427 // Native classes inherit from Interceptor. 796 // Native classes inherit from Interceptor.
1428 return element.isNative() ? jsInterceptorClass : compiler.objectClass; 797 return element.isNative() ? jsInterceptorClass : compiler.objectClass;
1429 } 798 }
1430 799
1431 /** 800 /**
1432 * Unit test hook that returns code of an element as a String. 801 * Unit test hook that returns code of an element as a String.
1433 * 802 *
1434 * Invariant: [element] must be a declaration element. 803 * Invariant: [element] must be a declaration element.
1435 */ 804 */
1436 String assembleCode(Element element) { 805 String assembleCode(Element element) {
1437 assert(invariant(element, element.isDeclaration)); 806 assert(invariant(element, element.isDeclaration));
1438 return jsAst.prettyPrint(generatedCode[element], compiler).getText(); 807 return jsAst.prettyPrint(generatedCode[element], compiler).getText();
1439 } 808 }
1440 809
1441 void assembleProgram() { 810 void assembleProgram() {
1442 emitter.assembleProgram(); 811 emitter.assembleProgram();
1443 } 812 }
1444 813
1445 /**
1446 * Documentation wanted -- johnniwinther
1447 *
1448 * Invariant: [element] must be a declaration element.
1449 */
1450 void scheduleForRecompilation(Element element) {
1451 assert(invariant(element, element.isDeclaration));
1452 if (compiler.phase == Compiler.PHASE_COMPILING) {
1453 invalidateAfterCodegen.add(element);
1454 }
1455 }
1456
1457 /**
1458 * Register a dynamic invocation and collect the provided types for the
1459 * named selector.
1460 */
1461 void registerDynamicInvocation(HInvoke node, Selector selector) {
1462 HTypeList providedTypes =
1463 new HTypeList.fromDynamicInvocation(node, selector);
1464 argumentTypes.registerDynamicInvocation(providedTypes, selector);
1465 }
1466
1467 /**
1468 * Register a static invocation and collect the provided types for the
1469 * named selector.
1470 */
1471 void registerStaticInvocation(HInvokeStatic node) {
1472 argumentTypes.registerStaticInvocation(node);
1473 }
1474
1475 /**
1476 * Register that a static is used for something else than a direct call
1477 * target.
1478 */
1479 void registerNonCallStaticUse(HStatic node) {
1480 argumentTypes.registerNonCallStaticUse(node);
1481 }
1482
1483 /**
1484 * Retrieve the types of the parameters used for calling the [element]
1485 * function. The types are optimistic in the sense as they are based on the
1486 * possible invocations of the function seen so far.
1487 *
1488 * Invariant: [element] must be a declaration element.
1489 */
1490 HTypeList optimisticParameterTypes(
1491 FunctionElement element,
1492 OptionalParameterTypes defaultValueTypes) {
1493 assert(invariant(element, element.isDeclaration));
1494 if (element.parameterCount(compiler) == 0) return HTypeList.ALL_UNKNOWN;
1495 return argumentTypes.parameterTypes(element, defaultValueTypes);
1496 }
1497
1498 /**
1499 * Register that the function [element] has been optimized under the
1500 * assumptions that the types [parameterType] will be used for calling it.
1501 * The passed [defaultValueTypes] holds the types of default values for
1502 * the optional parameters. If this assumption fail the function will be
1503 * scheduled for recompilation.
1504 *
1505 * Invariant: [element] must be a declaration element.
1506 */
1507 registerParameterTypesOptimization(
1508 FunctionElement element,
1509 HTypeList parameterTypes,
1510 OptionalParameterTypes defaultValueTypes) {
1511 assert(invariant(element, element.isDeclaration));
1512 if (element.parameterCount(compiler) == 0) return;
1513 argumentTypes.registerOptimizedFunction(
1514 element, parameterTypes, defaultValueTypes);
1515 }
1516
1517 registerFieldTypesOptimization(Element element,
1518 Element field,
1519 HType type) {
1520 fieldTypes.registerOptimizedFunction(element, field, type);
1521 }
1522
1523 /**
1524 * Documentation wanted -- johnniwinther
1525 *
1526 * Invariant: [element] must be a declaration element.
1527 */
1528 void registerReturnType(FunctionElement element, HType returnType) {
1529 assert(invariant(element, element.isDeclaration));
1530 ReturnInfo info = returnInfo[element];
1531 if (info != null) {
1532 info.update(returnType, scheduleForRecompilation, compiler);
1533 } else {
1534 returnInfo[element] = new ReturnInfo(returnType);
1535 }
1536 }
1537
1538 /**
1539 * Retrieve the return type of the function [callee]. The type is optimistic
1540 * in the sense that is is based on the compilation of [callee]. If [callee]
1541 * is recompiled the return type might change to someting broader. For that
1542 * reason [caller] is registered for recompilation if this happens. If the
1543 * function [callee] has not yet been compiled the returned type is [null].
1544 *
1545 * Invariant: Both [caller] and [callee] must be declaration elements.
1546 */
1547 HType optimisticReturnTypesWithRecompilationOnTypeChange(
1548 Element caller, FunctionElement callee) {
1549 assert(invariant(callee, callee.isDeclaration));
1550 returnInfo.putIfAbsent(callee, () => new ReturnInfo.unknownType());
1551 ReturnInfo info = returnInfo[callee];
1552 HType returnType = info.returnType;
1553 if (returnType != HType.UNKNOWN && returnType != null && caller != null) {
1554 assert(invariant(caller, caller.isDeclaration));
1555 info.addCompiledFunction(caller);
1556 }
1557 return info.returnType;
1558 }
1559
1560 void dumpReturnTypes() {
1561 returnInfo.forEach((Element element, ReturnInfo info) {
1562 if (info.returnType != HType.UNKNOWN) {
1563 print("Inferred $element has return type ${info.returnType}");
1564 }
1565 });
1566 }
1567
1568 void registerConstructor(Element element) {
1569 fieldTypes.registerConstructor(element);
1570 }
1571
1572 void registerFieldInitializer(Element field, HType type) {
1573 fieldTypes.registerFieldInitializer(field, type);
1574 }
1575
1576 void registerFieldConstructor(Element field, HType type) {
1577 fieldTypes.registerFieldConstructor(field, type);
1578 }
1579
1580 void registerFieldSetter(Element element, Element field, HType type) {
1581 fieldTypes.registerFieldSetter(element, field, type);
1582 }
1583
1584 void addedDynamicSetter(Selector setter, HType type) {
1585 fieldTypes.addedDynamicSetter(setter, type);
1586 }
1587
1588 HType optimisticFieldType(Element element) {
1589 return fieldTypes.optimisticFieldType(element);
1590 }
1591
1592 Element getImplementationClass(Element element) { 814 Element getImplementationClass(Element element) {
1593 if (element == compiler.intClass) { 815 if (element == compiler.intClass) {
1594 return jsIntClass; 816 return jsIntClass;
1595 } else if (element == compiler.boolClass) { 817 } else if (element == compiler.boolClass) {
1596 return jsBoolClass; 818 return jsBoolClass;
1597 } else if (element == compiler.numClass) { 819 } else if (element == compiler.numClass) {
1598 return jsNumberClass; 820 return jsNumberClass;
1599 } else if (element == compiler.doubleClass) { 821 } else if (element == compiler.doubleClass) {
1600 return jsDoubleClass; 822 return jsDoubleClass;
1601 } else if (element == compiler.stringClass) { 823 } else if (element == compiler.stringClass) {
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
1733 } else { 955 } else {
1734 return typeCast 956 return typeCast
1735 ? const SourceString('propertyTypeCast') 957 ? const SourceString('propertyTypeCast')
1736 : const SourceString('propertyTypeCheck'); 958 : const SourceString('propertyTypeCheck');
1737 } 959 }
1738 } 960 }
1739 } 961 }
1740 } 962 }
1741 } 963 }
1742 964
1743 void dumpInferredTypes() {
1744 print("Inferred argument types:");
1745 print("------------------------");
1746 argumentTypes.dump();
1747 print("");
1748 print("Inferred return types:");
1749 print("----------------------");
1750 dumpReturnTypes();
1751 print("");
1752 print("Inferred field types:");
1753 print("------------------------");
1754 fieldTypes.dump();
1755 print("");
1756 }
1757
1758 Element getExceptionUnwrapper() { 965 Element getExceptionUnwrapper() {
1759 return compiler.findHelper(const SourceString('unwrapException')); 966 return compiler.findHelper(const SourceString('unwrapException'));
1760 } 967 }
1761 968
1762 Element getThrowRuntimeError() { 969 Element getThrowRuntimeError() {
1763 return compiler.findHelper(const SourceString('throwRuntimeError')); 970 return compiler.findHelper(const SourceString('throwRuntimeError'));
1764 } 971 }
1765 972
1766 Element getThrowMalformedSubtypeError() { 973 Element getThrowMalformedSubtypeError() {
1767 return compiler.findHelper( 974 return compiler.findHelper(
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
1874 ClassElement get listImplementation => jsArrayClass; 1081 ClassElement get listImplementation => jsArrayClass;
1875 ClassElement get constListImplementation => jsArrayClass; 1082 ClassElement get constListImplementation => jsArrayClass;
1876 ClassElement get fixedListImplementation => jsFixedArrayClass; 1083 ClassElement get fixedListImplementation => jsFixedArrayClass;
1877 ClassElement get growableListImplementation => jsExtendableArrayClass; 1084 ClassElement get growableListImplementation => jsExtendableArrayClass;
1878 ClassElement get mapImplementation => mapLiteralClass; 1085 ClassElement get mapImplementation => mapLiteralClass;
1879 ClassElement get constMapImplementation => constMapLiteralClass; 1086 ClassElement get constMapImplementation => constMapLiteralClass;
1880 ClassElement get typeImplementation => typeLiteralClass; 1087 ClassElement get typeImplementation => typeLiteralClass;
1881 ClassElement get boolImplementation => jsBoolClass; 1088 ClassElement get boolImplementation => jsBoolClass;
1882 ClassElement get nullImplementation => jsNullClass; 1089 ClassElement get nullImplementation => jsNullClass;
1883 } 1090 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/implementation/ssa/builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698