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

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

Issue 10964016: Change the type inference for fields in dart2js (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed second round of comments Created 8 years, 2 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
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 typedef void Recompile(Element element); 5 typedef void Recompile(Element element);
6 6
7 class ReturnInfo { 7 class ReturnInfo {
8 HType returnType; 8 HType returnType;
9 List<Element> compiledFunctions; 9 List<Element> compiledFunctions;
10 10
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 } 216 }
217 index++; 217 index++;
218 }); 218 });
219 return result; 219 return result;
220 } 220 }
221 221
222 String toString() => 222 String toString() =>
223 allUnknown ? "HTypeList.ALL_UNKNOWN" : "HTypeList $types"; 223 allUnknown ? "HTypeList.ALL_UNKNOWN" : "HTypeList $types";
224 } 224 }
225 225
226 class FieldTypesRegistry {
227 final JavaScriptBackend backend;
228 final Map<Element, HType> fieldInitializerTypeMap;
229 final Map<Element, HType> fieldConstructorTypeMap;
230 final Map<Element, HType> fieldTypeMap;
231 final Set<SourceString> selectorSet;
232 final Map<Element, Set<Element>> optimizedStaticFunctions;
233 final Map<Element, FunctionSet> optimizedFunctions;
234
235 FieldTypesRegistry(JavaScriptBackend backend)
236 : fieldInitializerTypeMap = new Map<Element, HType>(),
237 fieldConstructorTypeMap = new Map<Element, HType>(),
238 fieldTypeMap = new Map<Element, HType>(),
239 selectorSet = new Set<SourceString>(),
240 optimizedStaticFunctions = new Map<Element, Set<Element>>(),
241 optimizedFunctions = new Map<Element, FunctionSet>(),
242 this.backend = backend;
243
244 Compiler get compiler => backend.compiler;
245
246 void scheduleRecompilation(Element field) {
247 Set optimizedStatics = optimizedStaticFunctions[field];
248 if (optimizedStatics != null) {
249 optimizedStatics.forEach(backend.scheduleForRecompilation);
250 }
251 optimizedStaticFunctions.remove(field);
ngeoffray 2012/09/24 15:39:29 Put the remove in the if?
Søren Gjesse 2012/09/25 13:33:21 Done.
252 FunctionSet optimized = optimizedFunctions[field];
253 if (optimized != null) {
254 optimized.forEach(backend.scheduleForRecompilation);
255 }
256 optimizedFunctions.remove(field);
ngeoffray 2012/09/24 15:39:29 ditto
Søren Gjesse 2012/09/25 13:33:21 Done.
257 }
258
259 void registerFieldType(Map<Element, HType> typeMap,
260 Element field,
261 HType type) {
262 assert(field.isField());
263 HType oldType = typeMap[field];
264 HType newType;
265
266 if (oldType != null) {
267 newType = oldType.union(type);
268 } else {
269 newType = type;
270 }
271 typeMap[field] = newType;
272 if (oldType != newType) {
273 scheduleRecompilation(field);
274 }
275 }
276
277 void registerFieldInitializer(Element field, HType type) {
278 registerFieldType(fieldInitializerTypeMap, field, type);
279 }
280
281 void registerFieldConstructor(Element field, HType type) {
282 registerFieldType(fieldConstructorTypeMap, field, type);
283 }
284
285 void registerFieldSetter(Element field, HType type) {
286 HType initializerType = fieldInitializerTypeMap[field];
287 HType constructorType = fieldConstructorTypeMap[field];
288 HType setterType = fieldTypeMap[field];
289 registerFieldType(fieldTypeMap, field, type);
290 }
291
292 void addedDynamicSetter(Selector setter, HType type) {
293 // TODO(sgjesse): Take the type of the setter into account.
294 assert(setter.isSetter());
295 if (selectorSet.contains(setter.name)) return;
ngeoffray 2012/09/24 15:39:29 Please add comments on the field saying that this
Søren Gjesse 2012/09/25 13:33:21 Changed name to setterSelectorsUsed and added comm
296 selectorSet.add(setter.name);
297 optimizedStaticFunctions.forEach((Element field, _) {
298 if (field.name == setter.name) {
299 scheduleRecompilation(field);
300 }
301 });
302 optimizedFunctions.forEach((Element field, _) {
303 if (field.name == setter.name) {
304 scheduleRecompilation(field);
305 }
306 });
307 }
308
309 HType optimisticFieldType(Element field) {
310 assert(field.isField());
311 assert(field.isMember());
312 if (selectorSet.contains(field.name)) {
313 return HType.UNKNOWN;
314 }
315 HType initializerType = fieldInitializerTypeMap[field];
316 HType constructorType = fieldConstructorTypeMap[field];
317 if (initializerType === null && constructorType === null) {
318 return HType.UNKNOWN;
319 }
320 HType result = constructorType != null ? constructorType : initializerType;
321 HType type = fieldTypeMap[field];
322 if (type !== null) result = result.union(type);
ngeoffray 2012/09/24 15:39:29 You could avoid these checks and union if you comp
Søren Gjesse 2012/09/25 13:33:21 As far as I can see the generative constructor, ge
323 return result;
324 }
325
326 void registerOptimizedFunction(FunctionElement element,
327 Element field,
328 HType type) {
329 assert(field.isField());
330 if (Elements.isStaticOrTopLevel(element)) {
331 optimizedStaticFunctions.putIfAbsent(
332 field, () => new Set<Element>());
333 optimizedStaticFunctions[field].add(element);
334 } else {
335 optimizedFunctions.putIfAbsent(
336 field, () => new FunctionSet(backend.compiler));
337 optimizedFunctions[field].add(element);
338 }
339 }
340
341 void dump() {
342 Set<Element> allFields = new Set<Element>();
343 fieldInitializerTypeMap.getKeys().forEach(allFields.add);
344 fieldConstructorTypeMap.getKeys().forEach(allFields.add);
345 fieldTypeMap.getKeys().forEach(allFields.add);
346 allFields.forEach((Element field) {
347 print("Inferred $field has type ${optimisticFieldType(field)}");
348 });
349 }
350 }
351
226 class ArgumentTypesRegistry { 352 class ArgumentTypesRegistry {
227 final JavaScriptBackend backend; 353 final JavaScriptBackend backend;
228 354
229 /** 355 /**
230 * Documentation wanted -- johnniwinther 356 * Documentation wanted -- johnniwinther
231 * 357 *
232 * Invariant: Keys must be declaration elements. 358 * Invariant: Keys must be declaration elements.
233 */ 359 */
234 final Map<Element, HTypeList> staticTypeMap; 360 final Map<Element, HTypeList> staticTypeMap;
235 361
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 signature, 504 signature,
379 defaultValueTypes); 505 defaultValueTypes);
380 } 506 }
381 assert(types.allUnknown || types.length == signature.parameterCount); 507 assert(types.allUnknown || types.length == signature.parameterCount);
382 found = (found === null) ? types : found.union(types); 508 found = (found === null) ? types : found.union(types);
383 return !found.allUnknown; 509 return !found.allUnknown;
384 }); 510 });
385 return found !== null ? found : HTypeList.ALL_UNKNOWN; 511 return found !== null ? found : HTypeList.ALL_UNKNOWN;
386 } 512 }
387 513
388 void registerOptimization(Element element, 514 void registerOptimizedFunction(Element element,
389 HTypeList parameterTypes, 515 HTypeList parameterTypes,
390 OptionalParameterTypes defaultValueTypes) { 516 OptionalParameterTypes defaultValueTypes) {
391 assert(invariant(element, element.isDeclaration));
392 if (Elements.isStaticOrTopLevelFunction(element)) { 517 if (Elements.isStaticOrTopLevelFunction(element)) {
393 if (parameterTypes.allUnknown) { 518 if (parameterTypes.allUnknown) {
394 optimizedStaticFunctions.remove(element); 519 optimizedStaticFunctions.remove(element);
395 } else { 520 } else {
396 optimizedStaticFunctions.add(element); 521 optimizedStaticFunctions.add(element);
397 } 522 }
398 } 523 }
399 524
400 // TODO(kasperl): What kind of non-members do we get here? 525 // TODO(kasperl): What kind of non-members do we get here?
401 if (!element.isMember()) return; 526 if (!element.isMember()) return;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
436 561
437 final Namer namer; 562 final Namer namer;
438 563
439 /** 564 /**
440 * Interface used to determine if an object has the JavaScript 565 * Interface used to determine if an object has the JavaScript
441 * indexing behavior. The interface is only visible to specific 566 * indexing behavior. The interface is only visible to specific
442 * libraries. 567 * libraries.
443 */ 568 */
444 ClassElement jsIndexingBehaviorInterface; 569 ClassElement jsIndexingBehaviorInterface;
445 570
446 final Map<Element, Map<Element, HType>> fieldInitializers;
447 final Map<Element, Map<Element, HType>> fieldConstructorSetters;
448 final Map<Element, Map<Element, HType>> fieldSettersType;
449
450 final Map<Element, ReturnInfo> returnInfo; 571 final Map<Element, ReturnInfo> returnInfo;
451 572
452 /** 573 /**
453 * Documentation wanted -- johnniwinther 574 * Documentation wanted -- johnniwinther
454 * 575 *
455 * Invariant: Elements must be declaration elements. 576 * Invariant: Elements must be declaration elements.
456 */ 577 */
457 final List<Element> invalidateAfterCodegen; 578 final List<Element> invalidateAfterCodegen;
458 ArgumentTypesRegistry argumentTypes; 579 ArgumentTypesRegistry argumentTypes;
580 FieldTypesRegistry fieldTypes;
459 581
460 List<CompilerTask> get tasks { 582 List<CompilerTask> get tasks {
461 return <CompilerTask>[builder, optimizer, generator, emitter]; 583 return <CompilerTask>[builder, optimizer, generator, emitter];
462 } 584 }
463 585
464 JavaScriptBackend(Compiler compiler, bool generateSourceMap) 586 JavaScriptBackend(Compiler compiler, bool generateSourceMap)
465 : fieldInitializers = new Map<Element, Map<Element, HType>>(), 587 : namer = new Namer(compiler),
466 fieldConstructorSetters = new Map<Element, Map<Element, HType>>(),
467 fieldSettersType = new Map<Element, Map<Element, HType>>(),
468 namer = new Namer(compiler),
469 returnInfo = new Map<Element, ReturnInfo>(), 588 returnInfo = new Map<Element, ReturnInfo>(),
470 invalidateAfterCodegen = new List<Element>(), 589 invalidateAfterCodegen = new List<Element>(),
471 super(compiler, constantSystem: JAVA_SCRIPT_CONSTANT_SYSTEM) { 590 super(compiler, constantSystem: JAVA_SCRIPT_CONSTANT_SYSTEM) {
472 emitter = new CodeEmitterTask(compiler, namer, generateSourceMap); 591 emitter = new CodeEmitterTask(compiler, namer, generateSourceMap);
473 builder = new SsaBuilderTask(this); 592 builder = new SsaBuilderTask(this);
474 optimizer = new SsaOptimizerTask(this); 593 optimizer = new SsaOptimizerTask(this);
475 generator = new SsaCodeGeneratorTask(this); 594 generator = new SsaCodeGeneratorTask(this);
476 argumentTypes = new ArgumentTypesRegistry(this); 595 argumentTypes = new ArgumentTypesRegistry(this);
596 fieldTypes = new FieldTypesRegistry(this);
477 } 597 }
478 598
479 Element get cyclicThrowHelper { 599 Element get cyclicThrowHelper {
480 return compiler.findHelper(const SourceString("throwCyclicInit")); 600 return compiler.findHelper(const SourceString("throwCyclicInit"));
481 } 601 }
482 602
483 JavaScriptItemCompilationContext createItemCompilationContext() { 603 JavaScriptItemCompilationContext createItemCompilationContext() {
484 return new JavaScriptItemCompilationContext(); 604 return new JavaScriptItemCompilationContext();
485 } 605 }
486 606
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
532 652
533 void processNativeClasses(Enqueuer world, 653 void processNativeClasses(Enqueuer world,
534 Collection<LibraryElement> libraries) { 654 Collection<LibraryElement> libraries) {
535 native.processNativeClasses(world, emitter, libraries); 655 native.processNativeClasses(world, emitter, libraries);
536 } 656 }
537 657
538 void assembleProgram() { 658 void assembleProgram() {
539 emitter.assembleProgram(); 659 emitter.assembleProgram();
540 } 660 }
541 661
542 void updateFieldInitializers(Element field, HType propagatedType) {
543 assert(field.isField());
544 assert(field.isMember());
545 Map<Element, HType> fields =
546 fieldInitializers.putIfAbsent(
547 field.getEnclosingClass(), () => new Map<Element, HType>());
548 if (!fields.containsKey(field)) {
549 fields[field] = propagatedType;
550 } else {
551 fields[field] = fields[field].union(propagatedType);
552 }
553 }
554
555 HType typeFromInitializersSoFar(Element field) {
556 assert(field.isField());
557 assert(field.isMember());
558 if (!fieldInitializers.containsKey(field.getEnclosingClass())) {
559 return HType.CONFLICTING;
560 }
561 Map<Element, HType> fields = fieldInitializers[field.getEnclosingClass()];
562 return fields[field];
563 }
564
565 void updateFieldConstructorSetters(Element field, HType type) {
566 assert(field.isField());
567 assert(field.isMember());
568 Map<Element, HType> fields =
569 fieldConstructorSetters.putIfAbsent(
570 field.getEnclosingClass(), () => new Map<Element, HType>());
571 if (!fields.containsKey(field)) {
572 fields[field] = type;
573 } else {
574 fields[field] = fields[field].union(type);
575 }
576 }
577
578 // Check if this field is set in the constructor body.
579 bool hasConstructorBodyFieldSetter(Element field) {
580 ClassElement enclosingClass = field.getEnclosingClass();
581 if (!fieldConstructorSetters.containsKey(enclosingClass)) {
582 return false;
583 }
584 return fieldConstructorSetters[enclosingClass][field] != null;
585 }
586
587 // Provide an optimistic estimate of the type of a field after construction.
588 // If the constructor body has setters for fields returns HType.UNKNOWN.
589 // This only takes the initializer lists and field assignments in the
590 // constructor body into account. The constructor body might have method calls
591 // that could alter the field.
592 HType optimisticFieldTypeAfterConstruction(Element field) {
593 assert(field.isField());
594 assert(field.isMember());
595
596 ClassElement classElement = field.getEnclosingClass();
597 if (hasConstructorBodyFieldSetter(field)) {
598 // If there are field setters but there is only constructor then the type
599 // of the field is determined by the assignments in the constructor
600 // body.
601 var constructors = classElement.constructors;
602 if (constructors.head !== null && constructors.tail.isEmpty()) {
603 return fieldConstructorSetters[classElement][field];
604 } else {
605 return HType.UNKNOWN;
606 }
607 } else if (fieldInitializers.containsKey(classElement)) {
608 HType type = fieldInitializers[classElement][field];
609 return type == null ? HType.CONFLICTING : type;
610 } else {
611 return HType.CONFLICTING;
612 }
613 }
614
615 void updateFieldSetters(Element field, HType type) {
616 assert(field.isField());
617 assert(field.isMember());
618 Map<Element, HType> fields =
619 fieldSettersType.putIfAbsent(
620 field.getEnclosingClass(), () => new Map<Element, HType>());
621 if (!fields.containsKey(field)) {
622 fields[field] = type;
623 } else {
624 fields[field] = fields[field].union(type);
625 }
626 }
627
628 // Returns the type that field setters are setting the field to based on what
629 // have been seen during compilation so far.
630 HType fieldSettersTypeSoFar(Element field) {
631 assert(field.isField());
632 assert(field.isMember());
633 ClassElement enclosingClass = field.getEnclosingClass();
634 if (!fieldSettersType.containsKey(enclosingClass)) {
635 return HType.CONFLICTING;
636 }
637 Map<Element, HType> fields = fieldSettersType[enclosingClass];
638 if (!fields.containsKey(field)) return HType.CONFLICTING;
639 return fields[field];
640 }
641
642 /** 662 /**
643 * Documentation wanted -- johnniwinther 663 * Documentation wanted -- johnniwinther
644 * 664 *
645 * Invariant: [element] must be a declaration element. 665 * Invariant: [element] must be a declaration element.
646 */ 666 */
647 void scheduleForRecompilation(Element element) { 667 void scheduleForRecompilation(Element element) {
648 assert(invariant(element, element.isDeclaration)); 668 assert(invariant(element, element.isDeclaration));
649 if (compiler.phase == Compiler.PHASE_COMPILING) { 669 if (compiler.phase == Compiler.PHASE_COMPILING) {
650 invalidateAfterCodegen.add(element); 670 invalidateAfterCodegen.add(element);
651 } 671 }
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
700 * scheduled for recompilation. 720 * scheduled for recompilation.
701 * 721 *
702 * Invariant: [element] must be a declaration element. 722 * Invariant: [element] must be a declaration element.
703 */ 723 */
704 registerParameterTypesOptimization( 724 registerParameterTypesOptimization(
705 FunctionElement element, 725 FunctionElement element,
706 HTypeList parameterTypes, 726 HTypeList parameterTypes,
707 OptionalParameterTypes defaultValueTypes) { 727 OptionalParameterTypes defaultValueTypes) {
708 assert(invariant(element, element.isDeclaration)); 728 assert(invariant(element, element.isDeclaration));
709 if (element.parameterCount(compiler) == 0) return; 729 if (element.parameterCount(compiler) == 0) return;
710 argumentTypes.registerOptimization( 730 argumentTypes.registerOptimizedFunction(
711 element, parameterTypes, defaultValueTypes); 731 element, parameterTypes, defaultValueTypes);
712 } 732 }
713 733
734 registerFieldTypesOptimization(FunctionElement element,
735 Element field,
736 HType type) {
737 fieldTypes.registerOptimizedFunction(element, field, type);
738 }
739
714 /** 740 /**
715 * Documentation wanted -- johnniwinther 741 * Documentation wanted -- johnniwinther
716 * 742 *
717 * Invariant: [element] must be a declaration element. 743 * Invariant: [element] must be a declaration element.
718 */ 744 */
719 void registerReturnType(FunctionElement element, HType returnType) { 745 void registerReturnType(FunctionElement element, HType returnType) {
720 assert(invariant(element, element.isDeclaration)); 746 assert(invariant(element, element.isDeclaration));
721 ReturnInfo info = returnInfo[element]; 747 ReturnInfo info = returnInfo[element];
722 if (info != null) { 748 if (info != null) {
723 info.update(returnType, scheduleForRecompilation); 749 info.update(returnType, scheduleForRecompilation);
(...skipping 24 matching lines...) Expand all
748 } 774 }
749 775
750 void dumpReturnTypes() { 776 void dumpReturnTypes() {
751 returnInfo.forEach((Element element, ReturnInfo info) { 777 returnInfo.forEach((Element element, ReturnInfo info) {
752 if (info.returnType != HType.UNKNOWN) { 778 if (info.returnType != HType.UNKNOWN) {
753 print("Inferred $element has return type ${info.returnType}"); 779 print("Inferred $element has return type ${info.returnType}");
754 } 780 }
755 }); 781 });
756 } 782 }
757 783
784 void registerFieldInitializer(Element field, HType type) {
785 fieldTypes.registerFieldInitializer(field, type);
786 }
787
788 void registerFieldConstructor(Element field, HType type) {
789 fieldTypes.registerFieldConstructor(field, type);
790 }
791
792 void registerFieldSetter(Element field, HType type) {
793 fieldTypes.registerFieldSetter(field, type);
794 }
795
796 void addedDynamicSetter(Selector setter, HType type) {
797 fieldTypes.addedDynamicSetter(setter, type);
798 }
799
800 HType optimisticFieldType(Element element) {
801 return fieldTypes.optimisticFieldType(element);
802 }
803
758 SourceString getCheckedModeHelper(DartType type) { 804 SourceString getCheckedModeHelper(DartType type) {
759 Element element = type.element; 805 Element element = type.element;
760 bool nativeCheck = 806 bool nativeCheck =
761 emitter.nativeEmitter.requiresNativeIsCheck(element); 807 emitter.nativeEmitter.requiresNativeIsCheck(element);
762 if (element == compiler.stringClass) { 808 if (element == compiler.stringClass) {
763 return const SourceString('stringTypeCheck'); 809 return const SourceString('stringTypeCheck');
764 } else if (element == compiler.doubleClass) { 810 } else if (element == compiler.doubleClass) {
765 return const SourceString('doubleTypeCheck'); 811 return const SourceString('doubleTypeCheck');
766 } else if (element == compiler.numClass) { 812 } else if (element == compiler.numClass) {
767 return const SourceString('numTypeCheck'); 813 return const SourceString('numTypeCheck');
(...skipping 19 matching lines...) Expand all
787 ? const SourceString('listSuperNativeTypeCheck') 833 ? const SourceString('listSuperNativeTypeCheck')
788 : const SourceString('listSuperTypeCheck'); 834 : const SourceString('listSuperTypeCheck');
789 } else { 835 } else {
790 return nativeCheck 836 return nativeCheck
791 ? const SourceString('callTypeCheck') 837 ? const SourceString('callTypeCheck')
792 : const SourceString('propertyTypeCheck'); 838 : const SourceString('propertyTypeCheck');
793 } 839 }
794 } 840 }
795 } 841 }
796 } 842 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698