OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |