Chromium Code Reviews| 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; | |
|
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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |