| 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 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 ArgumentTypesRegistry { | 226 class ArgumentTypesRegistry { |
| 227 final JavaScriptBackend backend; | 227 final JavaScriptBackend backend; |
| 228 |
| 229 /** |
| 230 * Documentation wanted -- johnniwinther |
| 231 * |
| 232 * Invariant: Keys must be declaration elements. |
| 233 */ |
| 228 final Map<Element, HTypeList> staticTypeMap; | 234 final Map<Element, HTypeList> staticTypeMap; |
| 235 |
| 236 /** |
| 237 * Documentation wanted -- johnniwinther |
| 238 * |
| 239 * Invariant: Elements must be declaration elements. |
| 240 */ |
| 229 final Set<Element> optimizedStaticFunctions; | 241 final Set<Element> optimizedStaticFunctions; |
| 230 final SelectorMap<HTypeList> selectorTypeMap; | 242 final SelectorMap<HTypeList> selectorTypeMap; |
| 231 final FunctionSet optimizedFunctions; | 243 final FunctionSet optimizedFunctions; |
| 244 |
| 245 /** |
| 246 * Documentation wanted -- johnniwinther |
| 247 * |
| 248 * Invariant: Keys must be declaration elements. |
| 249 */ |
| 232 final Map<Element, HTypeList> optimizedTypes; | 250 final Map<Element, HTypeList> optimizedTypes; |
| 233 final Map<Element, OptionalParameterTypes> optimizedDefaultValueTypes; | 251 final Map<Element, OptionalParameterTypes> optimizedDefaultValueTypes; |
| 234 | 252 |
| 235 ArgumentTypesRegistry(JavaScriptBackend backend) | 253 ArgumentTypesRegistry(JavaScriptBackend backend) |
| 236 : staticTypeMap = new Map<Element, HTypeList>(), | 254 : staticTypeMap = new Map<Element, HTypeList>(), |
| 237 optimizedStaticFunctions = new Set<Element>(), | 255 optimizedStaticFunctions = new Set<Element>(), |
| 238 selectorTypeMap = new SelectorMap<HTypeList>(backend.compiler), | 256 selectorTypeMap = new SelectorMap<HTypeList>(backend.compiler), |
| 239 optimizedFunctions = new FunctionSet(backend.compiler), | 257 optimizedFunctions = new FunctionSet(backend.compiler), |
| 240 optimizedTypes = new Map<Element, HTypeList>(), | 258 optimizedTypes = new Map<Element, HTypeList>(), |
| 241 optimizedDefaultValueTypes = | 259 optimizedDefaultValueTypes = |
| 242 new Map<Element, OptionalParameterTypes>(), | 260 new Map<Element, OptionalParameterTypes>(), |
| 243 this.backend = backend; | 261 this.backend = backend; |
| 244 | 262 |
| 245 Compiler get compiler => backend.compiler; | 263 Compiler get compiler => backend.compiler; |
| 246 | 264 |
| 247 void registerStaticInvocation(HInvokeStatic node, HTypeMap types) { | 265 void registerStaticInvocation(HInvokeStatic node, HTypeMap types) { |
| 248 Element element = node.element; | 266 Element element = node.element; |
| 267 assert(invariant(node, element.isDeclaration)); |
| 249 HTypeList oldTypes = staticTypeMap[element]; | 268 HTypeList oldTypes = staticTypeMap[element]; |
| 250 if (oldTypes == null) { | 269 if (oldTypes == null) { |
| 251 staticTypeMap[element] = new HTypeList.fromStaticInvocation(node, types); | 270 staticTypeMap[element] = new HTypeList.fromStaticInvocation(node, types); |
| 252 } else { | 271 } else { |
| 253 if (oldTypes.allUnknown) return; | 272 if (oldTypes.allUnknown) return; |
| 254 HTypeList newTypes = oldTypes.unionWithInvoke(node, types); | 273 HTypeList newTypes = oldTypes.unionWithInvoke(node, types); |
| 255 if (newTypes === oldTypes) return; | 274 if (newTypes === oldTypes) return; |
| 256 staticTypeMap[element] = newTypes; | 275 staticTypeMap[element] = newTypes; |
| 257 if (optimizedStaticFunctions.contains(element)) { | 276 if (optimizedStaticFunctions.contains(element)) { |
| 258 backend.scheduleForRecompilation(element); | 277 backend.scheduleForRecompilation(element); |
| 259 } | 278 } |
| 260 } | 279 } |
| 261 } | 280 } |
| 262 | 281 |
| 263 void registerNonCallStaticUse(HStatic node) { | 282 void registerNonCallStaticUse(HStatic node) { |
| 264 // When a static is used for anything else than a call target we cannot | 283 // When a static is used for anything else than a call target we cannot |
| 265 // infer anything about its parameter types. | 284 // infer anything about its parameter types. |
| 266 Element element = node.element; | 285 Element element = node.element; |
| 286 assert(invariant(node, element.isDeclaration)); |
| 267 if (optimizedStaticFunctions.contains(element)) { | 287 if (optimizedStaticFunctions.contains(element)) { |
| 268 backend.scheduleForRecompilation(element); | 288 backend.scheduleForRecompilation(element); |
| 269 } | 289 } |
| 270 staticTypeMap[element] = HTypeList.ALL_UNKNOWN; | 290 staticTypeMap[element] = HTypeList.ALL_UNKNOWN; |
| 271 } | 291 } |
| 272 | 292 |
| 273 void registerDynamicInvocation(HInvokeDynamicMethod node, | 293 void registerDynamicInvocation(HInvokeDynamicMethod node, |
| 274 Selector selector, | 294 Selector selector, |
| 275 HTypeMap types) { | 295 HTypeMap types) { |
| 276 // If there are any getters for this method we cannot know anything about | 296 // If there are any getters for this method we cannot know anything about |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 break; | 340 break; |
| 321 } | 341 } |
| 322 } | 342 } |
| 323 } | 343 } |
| 324 if (recompile) backend.scheduleForRecompilation(element); | 344 if (recompile) backend.scheduleForRecompilation(element); |
| 325 }); | 345 }); |
| 326 } | 346 } |
| 327 | 347 |
| 328 HTypeList parameterTypes(FunctionElement element, | 348 HTypeList parameterTypes(FunctionElement element, |
| 329 OptionalParameterTypes defaultValueTypes) { | 349 OptionalParameterTypes defaultValueTypes) { |
| 350 assert(invariant(element, element.isDeclaration)); |
| 330 // Handle static functions separately. | 351 // Handle static functions separately. |
| 331 if (Elements.isStaticOrTopLevelFunction(element) || | 352 if (Elements.isStaticOrTopLevelFunction(element) || |
| 332 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { | 353 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { |
| 333 HTypeList types = staticTypeMap[element]; | 354 HTypeList types = staticTypeMap[element]; |
| 334 if (types !== null) { | 355 if (types !== null) { |
| 335 if (!optimizedStaticFunctions.contains(element)) { | 356 if (!optimizedStaticFunctions.contains(element)) { |
| 336 optimizedStaticFunctions.add(element); | 357 optimizedStaticFunctions.add(element); |
| 337 } | 358 } |
| 338 return types; | 359 return types; |
| 339 } else { | 360 } else { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 360 assert(types.allUnknown || types.length == signature.parameterCount); | 381 assert(types.allUnknown || types.length == signature.parameterCount); |
| 361 found = (found === null) ? types : found.union(types); | 382 found = (found === null) ? types : found.union(types); |
| 362 return !found.allUnknown; | 383 return !found.allUnknown; |
| 363 }); | 384 }); |
| 364 return found !== null ? found : HTypeList.ALL_UNKNOWN; | 385 return found !== null ? found : HTypeList.ALL_UNKNOWN; |
| 365 } | 386 } |
| 366 | 387 |
| 367 void registerOptimization(Element element, | 388 void registerOptimization(Element element, |
| 368 HTypeList parameterTypes, | 389 HTypeList parameterTypes, |
| 369 OptionalParameterTypes defaultValueTypes) { | 390 OptionalParameterTypes defaultValueTypes) { |
| 391 assert(invariant(element, element.isDeclaration)); |
| 370 if (Elements.isStaticOrTopLevelFunction(element)) { | 392 if (Elements.isStaticOrTopLevelFunction(element)) { |
| 371 if (parameterTypes.allUnknown) { | 393 if (parameterTypes.allUnknown) { |
| 372 optimizedStaticFunctions.remove(element); | 394 optimizedStaticFunctions.remove(element); |
| 373 } else { | 395 } else { |
| 374 optimizedStaticFunctions.add(element); | 396 optimizedStaticFunctions.add(element); |
| 375 } | 397 } |
| 376 } | 398 } |
| 377 | 399 |
| 378 // TODO(kasperl): What kind of non-members do we get here? | 400 // TODO(kasperl): What kind of non-members do we get here? |
| 379 if (!element.isMember()) return; | 401 if (!element.isMember()) return; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 * libraries. | 442 * libraries. |
| 421 */ | 443 */ |
| 422 ClassElement jsIndexingBehaviorInterface; | 444 ClassElement jsIndexingBehaviorInterface; |
| 423 | 445 |
| 424 final Map<Element, Map<Element, HType>> fieldInitializers; | 446 final Map<Element, Map<Element, HType>> fieldInitializers; |
| 425 final Map<Element, Map<Element, HType>> fieldConstructorSetters; | 447 final Map<Element, Map<Element, HType>> fieldConstructorSetters; |
| 426 final Map<Element, Map<Element, HType>> fieldSettersType; | 448 final Map<Element, Map<Element, HType>> fieldSettersType; |
| 427 | 449 |
| 428 final Map<Element, ReturnInfo> returnInfo; | 450 final Map<Element, ReturnInfo> returnInfo; |
| 429 | 451 |
| 452 /** |
| 453 * Documentation wanted -- johnniwinther |
| 454 * |
| 455 * Invariant: Elements must be declaration elements. |
| 456 */ |
| 430 final List<Element> invalidateAfterCodegen; | 457 final List<Element> invalidateAfterCodegen; |
| 431 ArgumentTypesRegistry argumentTypes; | 458 ArgumentTypesRegistry argumentTypes; |
| 432 | 459 |
| 433 List<CompilerTask> get tasks { | 460 List<CompilerTask> get tasks { |
| 434 return <CompilerTask>[builder, optimizer, generator, emitter]; | 461 return <CompilerTask>[builder, optimizer, generator, emitter]; |
| 435 } | 462 } |
| 436 | 463 |
| 437 JavaScriptBackend(Compiler compiler, bool generateSourceMap) | 464 JavaScriptBackend(Compiler compiler, bool generateSourceMap) |
| 438 : fieldInitializers = new Map<Element, Map<Element, HType>>(), | 465 : fieldInitializers = new Map<Element, Map<Element, HType>>(), |
| 439 fieldConstructorSetters = new Map<Element, Map<Element, HType>>(), | 466 fieldConstructorSetters = new Map<Element, Map<Element, HType>>(), |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 605 assert(field.isMember()); | 632 assert(field.isMember()); |
| 606 ClassElement enclosingClass = field.getEnclosingClass(); | 633 ClassElement enclosingClass = field.getEnclosingClass(); |
| 607 if (!fieldSettersType.containsKey(enclosingClass)) { | 634 if (!fieldSettersType.containsKey(enclosingClass)) { |
| 608 return HType.CONFLICTING; | 635 return HType.CONFLICTING; |
| 609 } | 636 } |
| 610 Map<Element, HType> fields = fieldSettersType[enclosingClass]; | 637 Map<Element, HType> fields = fieldSettersType[enclosingClass]; |
| 611 if (!fields.containsKey(field)) return HType.CONFLICTING; | 638 if (!fields.containsKey(field)) return HType.CONFLICTING; |
| 612 return fields[field]; | 639 return fields[field]; |
| 613 } | 640 } |
| 614 | 641 |
| 642 /** |
| 643 * Documentation wanted -- johnniwinther |
| 644 * |
| 645 * Invariant: [element] must be a declaration element. |
| 646 */ |
| 615 void scheduleForRecompilation(Element element) { | 647 void scheduleForRecompilation(Element element) { |
| 648 assert(invariant(element, element.isDeclaration)); |
| 616 if (compiler.phase == Compiler.PHASE_COMPILING) { | 649 if (compiler.phase == Compiler.PHASE_COMPILING) { |
| 617 invalidateAfterCodegen.add(element); | 650 invalidateAfterCodegen.add(element); |
| 618 } | 651 } |
| 619 } | 652 } |
| 620 | 653 |
| 621 /** | 654 /** |
| 622 * Register a dynamic invocation and collect the provided types for the | 655 * Register a dynamic invocation and collect the provided types for the |
| 623 * named selector. | 656 * named selector. |
| 624 */ | 657 */ |
| 625 void registerDynamicInvocation(HInvokeDynamicMethod node, | 658 void registerDynamicInvocation(HInvokeDynamicMethod node, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 641 * target. | 674 * target. |
| 642 */ | 675 */ |
| 643 void registerNonCallStaticUse(HStatic node) { | 676 void registerNonCallStaticUse(HStatic node) { |
| 644 argumentTypes.registerNonCallStaticUse(node); | 677 argumentTypes.registerNonCallStaticUse(node); |
| 645 } | 678 } |
| 646 | 679 |
| 647 /** | 680 /** |
| 648 * Retrieve the types of the parameters used for calling the [element] | 681 * Retrieve the types of the parameters used for calling the [element] |
| 649 * function. The types are optimistic in the sense as they are based on the | 682 * function. The types are optimistic in the sense as they are based on the |
| 650 * possible invocations of the function seen so far. | 683 * possible invocations of the function seen so far. |
| 684 * |
| 685 * Invariant: [element] must be a declaration element. |
| 651 */ | 686 */ |
| 652 HTypeList optimisticParameterTypes( | 687 HTypeList optimisticParameterTypes( |
| 653 FunctionElement element, | 688 FunctionElement element, |
| 654 OptionalParameterTypes defaultValueTypes) { | 689 OptionalParameterTypes defaultValueTypes) { |
| 690 assert(invariant(element, element.isDeclaration)); |
| 655 if (element.parameterCount(compiler) == 0) return HTypeList.ALL_UNKNOWN; | 691 if (element.parameterCount(compiler) == 0) return HTypeList.ALL_UNKNOWN; |
| 656 return argumentTypes.parameterTypes(element, defaultValueTypes); | 692 return argumentTypes.parameterTypes(element, defaultValueTypes); |
| 657 } | 693 } |
| 658 | 694 |
| 659 /** | 695 /** |
| 660 * Register that the function [element] has been optimized under the | 696 * Register that the function [element] has been optimized under the |
| 661 * assumptions that the types [parameterType] will be used for calling it. | 697 * assumptions that the types [parameterType] will be used for calling it. |
| 662 * The passed [defaultValueTypes] holds the types of default values for | 698 * The passed [defaultValueTypes] holds the types of default values for |
| 663 * the optional parameters. If this assumption fail the function will be | 699 * the optional parameters. If this assumption fail the function will be |
| 664 * scheduled for recompilation. | 700 * scheduled for recompilation. |
| 701 * |
| 702 * Invariant: [element] must be a declaration element. |
| 665 */ | 703 */ |
| 666 registerParameterTypesOptimization( | 704 registerParameterTypesOptimization( |
| 667 FunctionElement element, | 705 FunctionElement element, |
| 668 HTypeList parameterTypes, | 706 HTypeList parameterTypes, |
| 669 OptionalParameterTypes defaultValueTypes) { | 707 OptionalParameterTypes defaultValueTypes) { |
| 708 assert(invariant(element, element.isDeclaration)); |
| 670 if (element.parameterCount(compiler) == 0) return; | 709 if (element.parameterCount(compiler) == 0) return; |
| 671 argumentTypes.registerOptimization( | 710 argumentTypes.registerOptimization( |
| 672 element, parameterTypes, defaultValueTypes); | 711 element, parameterTypes, defaultValueTypes); |
| 673 } | 712 } |
| 674 | 713 |
| 714 /** |
| 715 * Documentation wanted -- johnniwinther |
| 716 * |
| 717 * Invariant: [element] must be a declaration element. |
| 718 */ |
| 675 void registerReturnType(FunctionElement element, HType returnType) { | 719 void registerReturnType(FunctionElement element, HType returnType) { |
| 720 assert(invariant(element, element.isDeclaration)); |
| 676 ReturnInfo info = returnInfo[element]; | 721 ReturnInfo info = returnInfo[element]; |
| 677 if (info != null) { | 722 if (info != null) { |
| 678 info.update(returnType, scheduleForRecompilation); | 723 info.update(returnType, scheduleForRecompilation); |
| 679 } else { | 724 } else { |
| 680 returnInfo[element] = new ReturnInfo(returnType); | 725 returnInfo[element] = new ReturnInfo(returnType); |
| 681 } | 726 } |
| 682 } | 727 } |
| 683 | 728 |
| 684 /** | 729 /** |
| 685 * Retrieve the return type of the function [callee]. The type is optimistic | 730 * Retrieve the return type of the function [callee]. The type is optimistic |
| 686 * in the sense that is is based on the compilation of [callee]. If [callee] | 731 * in the sense that is is based on the compilation of [callee]. If [callee] |
| 687 * is recompiled the return type might change to someting broader. For that | 732 * is recompiled the return type might change to someting broader. For that |
| 688 * reason [caller] is registered for recompilation if this happens. If the | 733 * reason [caller] is registered for recompilation if this happens. If the |
| 689 * function [callee] has not yet been compiled the returned type is [null]. | 734 * function [callee] has not yet been compiled the returned type is [null]. |
| 735 * |
| 736 * Invariant: Both [caller] and [callee] must be declaration elements. |
| 690 */ | 737 */ |
| 691 HType optimisticReturnTypesWithRecompilationOnTypeChange( | 738 HType optimisticReturnTypesWithRecompilationOnTypeChange( |
| 692 Element caller, FunctionElement callee) { | 739 Element caller, FunctionElement callee) { |
| 740 assert(invariant(callee, callee.isDeclaration)); |
| 693 returnInfo.putIfAbsent(callee, () => new ReturnInfo.unknownType()); | 741 returnInfo.putIfAbsent(callee, () => new ReturnInfo.unknownType()); |
| 694 ReturnInfo info = returnInfo[callee]; | 742 ReturnInfo info = returnInfo[callee]; |
| 695 if (info.returnType != HType.UNKNOWN && caller != null) { | 743 if (info.returnType != HType.UNKNOWN && caller != null) { |
| 744 assert(invariant(caller, caller.isDeclaration)); |
| 696 info.addCompiledFunction(caller); | 745 info.addCompiledFunction(caller); |
| 697 } | 746 } |
| 698 return info.returnType; | 747 return info.returnType; |
| 699 } | 748 } |
| 700 | 749 |
| 701 void dumpReturnTypes() { | 750 void dumpReturnTypes() { |
| 702 returnInfo.forEach((Element element, ReturnInfo info) { | 751 returnInfo.forEach((Element element, ReturnInfo info) { |
| 703 if (info.returnType != HType.UNKNOWN) { | 752 if (info.returnType != HType.UNKNOWN) { |
| 704 print("Inferred $element has return type ${info.returnType}"); | 753 print("Inferred $element has return type ${info.returnType}"); |
| 705 } | 754 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 738 ? const SourceString('listSuperNativeTypeCheck') | 787 ? const SourceString('listSuperNativeTypeCheck') |
| 739 : const SourceString('listSuperTypeCheck'); | 788 : const SourceString('listSuperTypeCheck'); |
| 740 } else { | 789 } else { |
| 741 return nativeCheck | 790 return nativeCheck |
| 742 ? const SourceString('callTypeCheck') | 791 ? const SourceString('callTypeCheck') |
| 743 : const SourceString('propertyTypeCheck'); | 792 : const SourceString('propertyTypeCheck'); |
| 744 } | 793 } |
| 745 } | 794 } |
| 746 } | 795 } |
| 747 } | 796 } |
| OLD | NEW |