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

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: Minor fixes and rebased Created 8 years, 3 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;
ngeoffray 2012/09/20 14:43:01 Why do you need three maps and not one?
Søren Gjesse 2012/09/21 13:49:44 I need to separate the types set by the initialize
231 final Map<Element, FunctionSet> optimizedFunctions;
232
233 FieldTypesRegistry(JavaScriptBackend backend)
234 : fieldInitializerTypeMap = new Map<Element, HType>(),
235 fieldConstructorTypeMap = new Map<Element, HType>(),
236 fieldTypeMap = new Map<Element, HType>(),
237 optimizedFunctions = new Map<Element, FunctionSet>(),
238 this.backend = backend;
239
240 Compiler get compiler => backend.compiler;
241
242 void scheduleRecompilation(Element field) {
243 FunctionSet optimized = optimizedFunctions[field];
244 if (optimized != null) {
245 optimized.forEach(backend.scheduleForRecompilation);
246 }
247 optimizedFunctions.remove(field);
248 }
249
250 void registerFieldType(Map<Element, HType> typeMap,
251 Element field,
252 HType type) {
253 assert(field.isField());
254 HType oldType = typeMap[field];
255 HType newType;
256
257 if (oldType != null) {
258 newType = oldType.union(type);
259 } else {
260 newType = type;
261 }
262 typeMap[field] = newType;
263 if (oldType != newType) {
264 scheduleRecompilation(field);
265 }
266 }
267
268 void registerFieldInitializer(Element field, HType type) {
269 registerFieldType(fieldInitializerTypeMap, field, type);
270 }
271
272 void registerFieldConstructor(Element field, HType type) {
273 registerFieldType(fieldConstructorTypeMap, field, type);
274 }
275
276 void registerFieldSetter(HFieldSet node, HTypeMap types) {
277 Element field = node.element;
278 HType initializerType = fieldInitializerTypeMap[field];
279 HType constructorType = fieldConstructorTypeMap[field];
280 HType setterType = fieldTypeMap[field];
281 HType type = types[node.value];
282 if (type == HType.UNKNOWN &&
283 initializerType == null &&
284 constructorType == null &&
285 setterType == null) {
ngeoffray 2012/09/20 14:43:01 Not sure what all these checks really mean. If the
Søren Gjesse 2012/09/21 13:49:44 This checks whether there is any type information
286 return;
287 }
288 registerFieldType(fieldTypeMap, field, type);
289 }
290
291 void addedDynamicSetter(Selector setter) {
292 optimizedFunctions.getKeys().forEach((Element field) {
ngeoffray 2012/09/20 14:43:01 I would do optimizedFunctions.forEach((Element fie
Søren Gjesse 2012/09/21 13:49:44 Done.
293 if (field.name == setter.name) {
294 if (compiler.codegenWorld.hasInvokedSetter(field, compiler)) {
295 scheduleRecompilation(field);
296 }
297 }
298 });
299 }
300
301 HType optimisticFieldType(Element field) {
302 assert(field.isField());
303 assert(field.isMember());
304 if (compiler.codegenWorld.hasInvokedSetter(field, compiler)) {
305 return HType.UNKNOWN;
306 }
307 HType initializerType = fieldInitializerTypeMap[field];
308 HType constructorType = fieldConstructorTypeMap[field];
309 if (initializerType === null && constructorType === null) {
310 return HType.UNKNOWN;
311 }
312 HType result = constructorType != null ? constructorType : initializerType;
313 HType type = fieldTypeMap[field];
314 if (type !== null) result = result.union(type);
315 return result;
316 }
317
318 void registerOptimization(FunctionElement element,
ngeoffray 2012/09/20 14:43:01 registerOptimization -> registerOptimizedFunction
Søren Gjesse 2012/09/21 13:49:44 Done.
319 Element field,
320 HType type) {
321 assert(field.isField());
322 optimizedFunctions.putIfAbsent(
ngeoffray 2012/09/20 14:43:01 FunctionSet set = optimizedFunctions... set.add(el
Søren Gjesse 2012/09/21 13:49:44 This pattern is used in many places. Is it the per
323 field, () => new FunctionSet(backend.compiler));
324 optimizedFunctions[field].add(element);
325 }
326
327 void dump() {
328 optimizedFunctions.getKeys().forEach((Element field) {
329 print("Inferred $field has type ${optimisticFieldType(field)}");
330 });
331 }
332 }
333
226 class ArgumentTypesRegistry { 334 class ArgumentTypesRegistry {
227 final JavaScriptBackend backend; 335 final JavaScriptBackend backend;
228 final Map<Element, HTypeList> staticTypeMap; 336 final Map<Element, HTypeList> staticTypeMap;
229 final Set<Element> optimizedStaticFunctions; 337 final Set<Element> optimizedStaticFunctions;
230 final SelectorMap<HTypeList> selectorTypeMap; 338 final SelectorMap<HTypeList> selectorTypeMap;
231 final FunctionSet optimizedFunctions; 339 final FunctionSet optimizedFunctions;
232 final Map<Element, HTypeList> optimizedTypes; 340 final Map<Element, HTypeList> optimizedTypes;
233 final Map<Element, OptionalParameterTypes> optimizedDefaultValueTypes; 341 final Map<Element, OptionalParameterTypes> optimizedDefaultValueTypes;
234 342
235 ArgumentTypesRegistry(JavaScriptBackend backend) 343 ArgumentTypesRegistry(JavaScriptBackend backend)
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
414 522
415 final Namer namer; 523 final Namer namer;
416 524
417 /** 525 /**
418 * Interface used to determine if an object has the JavaScript 526 * Interface used to determine if an object has the JavaScript
419 * indexing behavior. The interface is only visible to specific 527 * indexing behavior. The interface is only visible to specific
420 * libraries. 528 * libraries.
421 */ 529 */
422 ClassElement jsIndexingBehaviorInterface; 530 ClassElement jsIndexingBehaviorInterface;
423 531
424 final Map<Element, Map<Element, HType>> fieldInitializers;
425 final Map<Element, Map<Element, HType>> fieldConstructorSetters;
426 final Map<Element, Map<Element, HType>> fieldSettersType;
427
428 final Map<Element, ReturnInfo> returnInfo; 532 final Map<Element, ReturnInfo> returnInfo;
429 533
430 final List<Element> invalidateAfterCodegen; 534 final List<Element> invalidateAfterCodegen;
431 ArgumentTypesRegistry argumentTypes; 535 ArgumentTypesRegistry argumentTypes;
536 FieldTypesRegistry fieldTypes;
432 537
433 List<CompilerTask> get tasks { 538 List<CompilerTask> get tasks {
434 return <CompilerTask>[builder, optimizer, generator, emitter]; 539 return <CompilerTask>[builder, optimizer, generator, emitter];
435 } 540 }
436 541
437 JavaScriptBackend(Compiler compiler, bool generateSourceMap) 542 JavaScriptBackend(Compiler compiler, bool generateSourceMap)
438 : fieldInitializers = new Map<Element, Map<Element, HType>>(), 543 : namer = new Namer(compiler),
439 fieldConstructorSetters = new Map<Element, Map<Element, HType>>(),
440 fieldSettersType = new Map<Element, Map<Element, HType>>(),
441 namer = new Namer(compiler),
442 returnInfo = new Map<Element, ReturnInfo>(), 544 returnInfo = new Map<Element, ReturnInfo>(),
443 invalidateAfterCodegen = new List<Element>(), 545 invalidateAfterCodegen = new List<Element>(),
444 super(compiler, constantSystem: JAVA_SCRIPT_CONSTANT_SYSTEM) { 546 super(compiler, constantSystem: JAVA_SCRIPT_CONSTANT_SYSTEM) {
445 emitter = new CodeEmitterTask(compiler, namer, generateSourceMap); 547 emitter = new CodeEmitterTask(compiler, namer, generateSourceMap);
446 builder = new SsaBuilderTask(this); 548 builder = new SsaBuilderTask(this);
447 optimizer = new SsaOptimizerTask(this); 549 optimizer = new SsaOptimizerTask(this);
448 generator = new SsaCodeGeneratorTask(this); 550 generator = new SsaCodeGeneratorTask(this);
449 argumentTypes = new ArgumentTypesRegistry(this); 551 argumentTypes = new ArgumentTypesRegistry(this);
552 fieldTypes = new FieldTypesRegistry(this);
450 } 553 }
451 554
452 Element get cyclicThrowHelper { 555 Element get cyclicThrowHelper {
453 return compiler.findHelper(const SourceString("throwCyclicInit")); 556 return compiler.findHelper(const SourceString("throwCyclicInit"));
454 } 557 }
455 558
456 JavaScriptItemCompilationContext createItemCompilationContext() { 559 JavaScriptItemCompilationContext createItemCompilationContext() {
457 return new JavaScriptItemCompilationContext(); 560 return new JavaScriptItemCompilationContext();
458 } 561 }
459 562
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 608
506 void processNativeClasses(Enqueuer world, 609 void processNativeClasses(Enqueuer world,
507 Collection<LibraryElement> libraries) { 610 Collection<LibraryElement> libraries) {
508 native.processNativeClasses(world, emitter, libraries); 611 native.processNativeClasses(world, emitter, libraries);
509 } 612 }
510 613
511 void assembleProgram() { 614 void assembleProgram() {
512 emitter.assembleProgram(); 615 emitter.assembleProgram();
513 } 616 }
514 617
515 void updateFieldInitializers(Element field, HType propagatedType) {
516 assert(field.isField());
517 assert(field.isMember());
518 Map<Element, HType> fields =
519 fieldInitializers.putIfAbsent(
520 field.getEnclosingClass(), () => new Map<Element, HType>());
521 if (!fields.containsKey(field)) {
522 fields[field] = propagatedType;
523 } else {
524 fields[field] = fields[field].union(propagatedType);
525 }
526 }
527
528 HType typeFromInitializersSoFar(Element field) {
529 assert(field.isField());
530 assert(field.isMember());
531 if (!fieldInitializers.containsKey(field.getEnclosingClass())) {
532 return HType.CONFLICTING;
533 }
534 Map<Element, HType> fields = fieldInitializers[field.getEnclosingClass()];
535 return fields[field];
536 }
537
538 void updateFieldConstructorSetters(Element field, HType type) {
539 assert(field.isField());
540 assert(field.isMember());
541 Map<Element, HType> fields =
542 fieldConstructorSetters.putIfAbsent(
543 field.getEnclosingClass(), () => new Map<Element, HType>());
544 if (!fields.containsKey(field)) {
545 fields[field] = type;
546 } else {
547 fields[field] = fields[field].union(type);
548 }
549 }
550
551 // Check if this field is set in the constructor body.
552 bool hasConstructorBodyFieldSetter(Element field) {
553 ClassElement enclosingClass = field.getEnclosingClass();
554 if (!fieldConstructorSetters.containsKey(enclosingClass)) {
555 return false;
556 }
557 return fieldConstructorSetters[enclosingClass][field] != null;
558 }
559
560 // Provide an optimistic estimate of the type of a field after construction.
561 // If the constructor body has setters for fields returns HType.UNKNOWN.
562 // This only takes the initializer lists and field assignments in the
563 // constructor body into account. The constructor body might have method calls
564 // that could alter the field.
565 HType optimisticFieldTypeAfterConstruction(Element field) {
566 assert(field.isField());
567 assert(field.isMember());
568
569 ClassElement classElement = field.getEnclosingClass();
570 if (hasConstructorBodyFieldSetter(field)) {
571 // If there are field setters but there is only constructor then the type
572 // of the field is determined by the assignments in the constructor
573 // body.
574 var constructors = classElement.constructors;
575 if (constructors.head !== null && constructors.tail.isEmpty()) {
576 return fieldConstructorSetters[classElement][field];
577 } else {
578 return HType.UNKNOWN;
579 }
580 } else if (fieldInitializers.containsKey(classElement)) {
581 HType type = fieldInitializers[classElement][field];
582 return type == null ? HType.CONFLICTING : type;
583 } else {
584 return HType.CONFLICTING;
585 }
586 }
587
588 void updateFieldSetters(Element field, HType type) {
589 assert(field.isField());
590 assert(field.isMember());
591 Map<Element, HType> fields =
592 fieldSettersType.putIfAbsent(
593 field.getEnclosingClass(), () => new Map<Element, HType>());
594 if (!fields.containsKey(field)) {
595 fields[field] = type;
596 } else {
597 fields[field] = fields[field].union(type);
598 }
599 }
600
601 // Returns the type that field setters are setting the field to based on what
602 // have been seen during compilation so far.
603 HType fieldSettersTypeSoFar(Element field) {
604 assert(field.isField());
605 assert(field.isMember());
606 ClassElement enclosingClass = field.getEnclosingClass();
607 if (!fieldSettersType.containsKey(enclosingClass)) {
608 return HType.CONFLICTING;
609 }
610 Map<Element, HType> fields = fieldSettersType[enclosingClass];
611 if (!fields.containsKey(field)) return HType.CONFLICTING;
612 return fields[field];
613 }
614
615 void scheduleForRecompilation(Element element) { 618 void scheduleForRecompilation(Element element) {
616 if (compiler.phase == Compiler.PHASE_COMPILING) { 619 if (compiler.phase == Compiler.PHASE_COMPILING) {
617 invalidateAfterCodegen.add(element); 620 invalidateAfterCodegen.add(element);
618 } 621 }
619 } 622 }
620 623
621 /** 624 /**
622 * Register a dynamic invocation and collect the provided types for the 625 * Register a dynamic invocation and collect the provided types for the
623 * named selector. 626 * named selector.
624 */ 627 */
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
665 */ 668 */
666 registerParameterTypesOptimization( 669 registerParameterTypesOptimization(
667 FunctionElement element, 670 FunctionElement element,
668 HTypeList parameterTypes, 671 HTypeList parameterTypes,
669 OptionalParameterTypes defaultValueTypes) { 672 OptionalParameterTypes defaultValueTypes) {
670 if (element.parameterCount(compiler) == 0) return; 673 if (element.parameterCount(compiler) == 0) return;
671 argumentTypes.registerOptimization( 674 argumentTypes.registerOptimization(
672 element, parameterTypes, defaultValueTypes); 675 element, parameterTypes, defaultValueTypes);
673 } 676 }
674 677
678 registerFieldTypesOptimization(FunctionElement element,
679 Element field,
680 HType type) {
681 fieldTypes.registerOptimization(element, field, type);
682 }
683
675 void registerReturnType(FunctionElement element, HType returnType) { 684 void registerReturnType(FunctionElement element, HType returnType) {
676 ReturnInfo info = returnInfo[element]; 685 ReturnInfo info = returnInfo[element];
677 if (info != null) { 686 if (info != null) {
678 info.update(returnType, scheduleForRecompilation); 687 info.update(returnType, scheduleForRecompilation);
679 } else { 688 } else {
680 returnInfo[element] = new ReturnInfo(returnType); 689 returnInfo[element] = new ReturnInfo(returnType);
681 } 690 }
682 } 691 }
683 692
684 /** 693 /**
(...skipping 14 matching lines...) Expand all
699 } 708 }
700 709
701 void dumpReturnTypes() { 710 void dumpReturnTypes() {
702 returnInfo.forEach((Element element, ReturnInfo info) { 711 returnInfo.forEach((Element element, ReturnInfo info) {
703 if (info.returnType != HType.UNKNOWN) { 712 if (info.returnType != HType.UNKNOWN) {
704 print("Inferred $element has return type ${info.returnType}"); 713 print("Inferred $element has return type ${info.returnType}");
705 } 714 }
706 }); 715 });
707 } 716 }
708 717
718 void registerFieldInitializer(Element field, HType type) {
719 fieldTypes.registerFieldInitializer(field, type);
720 }
721
722 void registerFieldConstructor(Element field, HType type) {
723 fieldTypes.registerFieldConstructor(field, type);
724 }
725
726 void registerFieldSetter(HFieldSet node, HTypeMap types) {
727 fieldTypes.registerFieldSetter(node, types);
728 }
729
730 void addedDynamicSetter(Selector setter) {
731 fieldTypes.addedDynamicSetter(setter);
732 }
733
734 HType optimisticFieldType(Element element) {
735 return fieldTypes.optimisticFieldType(element);
736 }
737
709 SourceString getCheckedModeHelper(DartType type) { 738 SourceString getCheckedModeHelper(DartType type) {
710 Element element = type.element; 739 Element element = type.element;
711 bool nativeCheck = 740 bool nativeCheck =
712 emitter.nativeEmitter.requiresNativeIsCheck(element); 741 emitter.nativeEmitter.requiresNativeIsCheck(element);
713 if (element == compiler.stringClass) { 742 if (element == compiler.stringClass) {
714 return const SourceString('stringTypeCheck'); 743 return const SourceString('stringTypeCheck');
715 } else if (element == compiler.doubleClass) { 744 } else if (element == compiler.doubleClass) {
716 return const SourceString('doubleTypeCheck'); 745 return const SourceString('doubleTypeCheck');
717 } else if (element == compiler.numClass) { 746 } else if (element == compiler.numClass) {
718 return const SourceString('numTypeCheck'); 747 return const SourceString('numTypeCheck');
(...skipping 19 matching lines...) Expand all
738 ? const SourceString('listSuperNativeTypeCheck') 767 ? const SourceString('listSuperNativeTypeCheck')
739 : const SourceString('listSuperTypeCheck'); 768 : const SourceString('listSuperTypeCheck');
740 } else { 769 } else {
741 return nativeCheck 770 return nativeCheck
742 ? const SourceString('callTypeCheck') 771 ? const SourceString('callTypeCheck')
743 : const SourceString('propertyTypeCheck'); 772 : const SourceString('propertyTypeCheck');
744 } 773 }
745 } 774 }
746 } 775 }
747 } 776 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698