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 | |
| 229 /** | |
| 230 * For each class [constructors] holds the set of constructors. If there is | |
|
ngeoffray
2012/09/27 12:35:46
each class,
Søren Gjesse
2012/09/27 13:22:49
Done.
| |
| 231 * more than one constructor for a class it is currently not possible to | |
| 232 * infer the field types from construction as the information collected does | |
|
ngeoffray
2012/09/27 12:35:46
from construction,
Søren Gjesse
2012/09/27 13:22:49
Done.
| |
| 233 * not correlate the generative constructors and generative constructor | |
| 234 * body/bodies. | |
| 235 */ | |
| 236 final Map<Element, Set<Element>> constructors; | |
|
ngeoffray
2012/09/27 12:35:46
Type the keys as ClassElement?
Søren Gjesse
2012/09/27 13:22:49
Done.
| |
| 237 | |
| 238 /** | |
| 239 * The collected type information is stored in three maps. One for types | |
| 240 * assigned in the initializer list(s) [fieldInitializerTypeMap], one for | |
| 241 * types assigned in the constructor(s) [fieldConstructorTypeMap] and one | |
|
ngeoffray
2012/09/27 12:35:46
, and
Søren Gjesse
2012/09/27 13:22:49
Done.
| |
| 242 * for typesassigned in the rest of the code [fieldTypeMap]. | |
|
ngeoffray
2012/09/27 12:35:46
typesassigned -> types assigned
ngeoffray
2012/09/27 12:35:46
rest of the code where the field can be resolved.
Søren Gjesse
2012/09/27 13:22:49
Done.
Søren Gjesse
2012/09/27 13:22:49
Done.
| |
| 243 * | |
| 244 * If a field has a type both from constructors and from the initializer | |
| 245 * list(s) then the type from the constructor(s) will owerride the one from | |
|
ngeoffray
2012/09/27 12:35:46
, then
Søren Gjesse
2012/09/27 13:22:49
Done.
| |
| 246 * the initializer list(s). | |
| 247 * | |
| 248 * As the order in which generative constructors, generative constructor | |
|
ngeoffray
2012/09/27 12:35:46
As -> Because ?
Søren Gjesse
2012/09/27 13:22:49
Done.
| |
| 249 * bodies and normal methods/functions is undefined, and as they can all be | |
|
ngeoffray
2012/09/27 12:35:46
bodies,
ngeoffray
2012/09/27 12:35:46
as -> because ?
Søren Gjesse
2012/09/27 13:22:49
Done.
Søren Gjesse
2012/09/27 13:22:49
Done.
| |
| 250 * recompiled it is not possible to combile this information into one map at | |
|
ngeoffray
2012/09/27 12:35:46
recompiled,
ngeoffray
2012/09/27 12:35:46
combile -> combine
Søren Gjesse
2012/09/27 13:22:49
Done.
Søren Gjesse
2012/09/27 13:22:49
Done.
| |
| 251 * the moment. | |
| 252 */ | |
| 253 final Map<Element, HType> fieldInitializerTypeMap; | |
| 254 final Map<Element, HType> fieldConstructorTypeMap; | |
| 255 final Map<Element, HType> fieldTypeMap; | |
| 256 | |
| 257 /** | |
| 258 * The set of current names setter selectors used. If a named selector is | |
| 259 * used it is currently not possible to infer the type of the field. | |
| 260 */ | |
| 261 final Set<SourceString> setterSelectorsUsed; | |
| 262 | |
| 263 final Map<Element, Set<Element>> optimizedStaticFunctions; | |
| 264 final Map<Element, FunctionSet> optimizedFunctions; | |
| 265 | |
| 266 FieldTypesRegistry(JavaScriptBackend backend) | |
| 267 : constructors = new Map<Element, Set<Element>>(), | |
| 268 fieldInitializerTypeMap = new Map<Element, HType>(), | |
| 269 fieldConstructorTypeMap = new Map<Element, HType>(), | |
| 270 fieldTypeMap = new Map<Element, HType>(), | |
| 271 setterSelectorsUsed = new Set<SourceString>(), | |
| 272 optimizedStaticFunctions = new Map<Element, Set<Element>>(), | |
| 273 optimizedFunctions = new Map<Element, FunctionSet>(), | |
| 274 this.backend = backend; | |
| 275 | |
| 276 Compiler get compiler => backend.compiler; | |
| 277 | |
| 278 void scheduleRecompilation(Element field) { | |
| 279 Set optimizedStatics = optimizedStaticFunctions[field]; | |
| 280 if (optimizedStatics != null) { | |
| 281 optimizedStatics.forEach(backend.scheduleForRecompilation); | |
| 282 optimizedStaticFunctions.remove(field); | |
| 283 } | |
| 284 FunctionSet optimized = optimizedFunctions[field]; | |
| 285 if (optimized != null) { | |
| 286 optimized.forEach(backend.scheduleForRecompilation); | |
| 287 optimizedFunctions.remove(field); | |
| 288 } | |
| 289 } | |
| 290 | |
| 291 int constructorCount(Element element) { | |
| 292 assert(element.isClass()); | |
| 293 Set<Element> ctors = constructors[element]; | |
| 294 return ctors === null ? 0 : ctors.length; | |
| 295 } | |
| 296 | |
| 297 void registerFieldType(Map<Element, HType> typeMap, | |
| 298 Element field, | |
| 299 HType type) { | |
| 300 assert(field.isField()); | |
| 301 HType before = optimisticFieldType(field); | |
| 302 | |
| 303 HType oldType = typeMap[field]; | |
| 304 HType newType; | |
| 305 | |
| 306 if (oldType != null) { | |
| 307 newType = oldType.union(type); | |
| 308 } else { | |
| 309 newType = type; | |
| 310 } | |
| 311 typeMap[field] = newType; | |
| 312 if (oldType != newType) { | |
| 313 scheduleRecompilation(field); | |
| 314 } | |
| 315 } | |
| 316 | |
| 317 void registerConstructor(Element element) { | |
| 318 assert(element.isGenerativeConstructor()); | |
| 319 Element cls = element.enclosingElement; | |
| 320 constructors.putIfAbsent(cls, () => new Set<Element>()); | |
| 321 Set<Element> ctors = constructors[cls]; | |
| 322 if (ctors.contains(element)) return; | |
| 323 ctors.add(element); | |
| 324 // We cannot infer field types for classes with more than one constructor. | |
| 325 // When the second constructor is seen recompile all functions relying on | |
|
ngeoffray
2012/09/27 12:35:46
seen,
Søren Gjesse
2012/09/27 13:22:49
Done.
| |
| 326 // optimistic field types for that class. | |
| 327 // TODO(sgjesse): Handle field types for classes with more than one | |
| 328 // constructor. | |
| 329 if (ctors.length == 2) { | |
| 330 optimizedFunctions.forEach((Element field, _) { | |
| 331 if (field.enclosingElement === cls) { | |
| 332 scheduleRecompilation(field); | |
| 333 } | |
| 334 }); | |
| 335 } | |
| 336 } | |
| 337 | |
| 338 void registerFieldInitializer(Element field, HType type) { | |
| 339 registerFieldType(fieldInitializerTypeMap, field, type); | |
| 340 } | |
| 341 | |
| 342 void registerFieldConstructor(Element field, HType type) { | |
| 343 registerFieldType(fieldConstructorTypeMap, field, type); | |
| 344 } | |
| 345 | |
| 346 void registerFieldSetter(FunctionElement element, Element field, HType type) { | |
| 347 HType initializerType = fieldInitializerTypeMap[field]; | |
| 348 HType constructorType = fieldConstructorTypeMap[field]; | |
| 349 HType setterType = fieldTypeMap[field]; | |
| 350 if (type == HType.UNKNOWN | |
| 351 && initializerType == null | |
| 352 && constructorType == null | |
| 353 && setterType == null) { | |
| 354 // Don't register UNKONWN if there is currently no type information | |
| 355 // present for the field. Instead register the function holding the | |
| 356 // setter for recompilation if better type information for the field | |
| 357 // becomes available. | |
| 358 registerOptimizedFunction(element, field, type); | |
| 359 return; | |
| 360 } | |
| 361 registerFieldType(fieldTypeMap, field, type); | |
| 362 } | |
| 363 | |
| 364 void addedDynamicSetter(Selector setter, HType type) { | |
| 365 // Field type optimizations are disabled for all fields matching a | |
| 366 // setter selector. | |
| 367 assert(setter.isSetter()); | |
| 368 // TODO(sgjesse): Take the type of the setter into account. | |
| 369 if (setterSelectorsUsed.contains(setter.name)) return; | |
| 370 setterSelectorsUsed.add(setter.name); | |
| 371 optimizedStaticFunctions.forEach((Element field, _) { | |
| 372 if (field.name == setter.name) { | |
| 373 scheduleRecompilation(field); | |
| 374 } | |
| 375 }); | |
| 376 optimizedFunctions.forEach((Element field, _) { | |
| 377 if (field.name == setter.name) { | |
| 378 scheduleRecompilation(field); | |
| 379 } | |
| 380 }); | |
| 381 } | |
| 382 | |
| 383 HType optimisticFieldType(Element field) { | |
| 384 assert(field.isField()); | |
| 385 if (constructorCount(field.enclosingElement) > 1) { | |
| 386 return HType.UNKNOWN; | |
| 387 } | |
| 388 if (setterSelectorsUsed.contains(field.name)) { | |
| 389 return HType.UNKNOWN; | |
| 390 } | |
| 391 HType initializerType = fieldInitializerTypeMap[field]; | |
| 392 HType constructorType = fieldConstructorTypeMap[field]; | |
| 393 if (initializerType === null && constructorType === null) { | |
| 394 return HType.UNKNOWN; | |
|
ngeoffray
2012/09/27 12:35:46
Why don't you also check fieldTypeMap here? Please
Søren Gjesse
2012/09/27 13:22:49
Done.
| |
| 395 } | |
| 396 HType result = constructorType != null ? constructorType : initializerType; | |
|
ngeoffray
2012/09/27 12:35:46
Also add a comment here on why you're using constr
Søren Gjesse
2012/09/27 13:22:49
Done.
| |
| 397 HType type = fieldTypeMap[field]; | |
| 398 if (type !== null) result = result.union(type); | |
| 399 return result; | |
| 400 } | |
| 401 | |
| 402 void registerOptimizedFunction(FunctionElement element, | |
| 403 Element field, | |
| 404 HType type) { | |
| 405 assert(field.isField()); | |
| 406 if (Elements.isStaticOrTopLevel(element)) { | |
| 407 optimizedStaticFunctions.putIfAbsent( | |
| 408 field, () => new Set<Element>()); | |
| 409 optimizedStaticFunctions[field].add(element); | |
| 410 } else { | |
| 411 optimizedFunctions.putIfAbsent( | |
| 412 field, () => new FunctionSet(backend.compiler)); | |
| 413 optimizedFunctions[field].add(element); | |
| 414 } | |
| 415 } | |
| 416 | |
| 417 void dump() { | |
| 418 Set<Element> allFields = new Set<Element>(); | |
| 419 fieldInitializerTypeMap.getKeys().forEach(allFields.add); | |
| 420 fieldConstructorTypeMap.getKeys().forEach(allFields.add); | |
| 421 fieldTypeMap.getKeys().forEach(allFields.add); | |
| 422 allFields.forEach((Element field) { | |
| 423 print("Inferred $field has type ${optimisticFieldType(field)}"); | |
| 424 }); | |
| 425 } | |
| 426 } | |
| 427 | |
| 226 class ArgumentTypesRegistry { | 428 class ArgumentTypesRegistry { |
| 227 final JavaScriptBackend backend; | 429 final JavaScriptBackend backend; |
| 228 | 430 |
| 229 /** | 431 /** |
| 230 * Documentation wanted -- johnniwinther | 432 * Documentation wanted -- johnniwinther |
| 231 * | 433 * |
| 232 * Invariant: Keys must be declaration elements. | 434 * Invariant: Keys must be declaration elements. |
| 233 */ | 435 */ |
| 234 final Map<Element, HTypeList> staticTypeMap; | 436 final Map<Element, HTypeList> staticTypeMap; |
| 235 | 437 |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 378 signature, | 580 signature, |
| 379 defaultValueTypes); | 581 defaultValueTypes); |
| 380 } | 582 } |
| 381 assert(types.allUnknown || types.length == signature.parameterCount); | 583 assert(types.allUnknown || types.length == signature.parameterCount); |
| 382 found = (found === null) ? types : found.union(types); | 584 found = (found === null) ? types : found.union(types); |
| 383 return !found.allUnknown; | 585 return !found.allUnknown; |
| 384 }); | 586 }); |
| 385 return found !== null ? found : HTypeList.ALL_UNKNOWN; | 587 return found !== null ? found : HTypeList.ALL_UNKNOWN; |
| 386 } | 588 } |
| 387 | 589 |
| 388 void registerOptimization(Element element, | 590 void registerOptimizedFunction(Element element, |
| 389 HTypeList parameterTypes, | 591 HTypeList parameterTypes, |
| 390 OptionalParameterTypes defaultValueTypes) { | 592 OptionalParameterTypes defaultValueTypes) { |
| 391 assert(invariant(element, element.isDeclaration)); | |
| 392 if (Elements.isStaticOrTopLevelFunction(element)) { | 593 if (Elements.isStaticOrTopLevelFunction(element)) { |
| 393 if (parameterTypes.allUnknown) { | 594 if (parameterTypes.allUnknown) { |
| 394 optimizedStaticFunctions.remove(element); | 595 optimizedStaticFunctions.remove(element); |
| 395 } else { | 596 } else { |
| 396 optimizedStaticFunctions.add(element); | 597 optimizedStaticFunctions.add(element); |
| 397 } | 598 } |
| 398 } | 599 } |
| 399 | 600 |
| 400 // TODO(kasperl): What kind of non-members do we get here? | 601 // TODO(kasperl): What kind of non-members do we get here? |
| 401 if (!element.isMember()) return; | 602 if (!element.isMember()) return; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 436 | 637 |
| 437 final Namer namer; | 638 final Namer namer; |
| 438 | 639 |
| 439 /** | 640 /** |
| 440 * Interface used to determine if an object has the JavaScript | 641 * Interface used to determine if an object has the JavaScript |
| 441 * indexing behavior. The interface is only visible to specific | 642 * indexing behavior. The interface is only visible to specific |
| 442 * libraries. | 643 * libraries. |
| 443 */ | 644 */ |
| 444 ClassElement jsIndexingBehaviorInterface; | 645 ClassElement jsIndexingBehaviorInterface; |
| 445 | 646 |
| 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; | 647 final Map<Element, ReturnInfo> returnInfo; |
| 451 | 648 |
| 452 /** | 649 /** |
| 453 * Documentation wanted -- johnniwinther | 650 * Documentation wanted -- johnniwinther |
| 454 * | 651 * |
| 455 * Invariant: Elements must be declaration elements. | 652 * Invariant: Elements must be declaration elements. |
| 456 */ | 653 */ |
| 457 final List<Element> invalidateAfterCodegen; | 654 final List<Element> invalidateAfterCodegen; |
| 458 ArgumentTypesRegistry argumentTypes; | 655 ArgumentTypesRegistry argumentTypes; |
| 656 FieldTypesRegistry fieldTypes; | |
| 459 | 657 |
| 460 List<CompilerTask> get tasks { | 658 List<CompilerTask> get tasks { |
| 461 return <CompilerTask>[builder, optimizer, generator, emitter]; | 659 return <CompilerTask>[builder, optimizer, generator, emitter]; |
| 462 } | 660 } |
| 463 | 661 |
| 464 JavaScriptBackend(Compiler compiler, bool generateSourceMap) | 662 JavaScriptBackend(Compiler compiler, bool generateSourceMap) |
| 465 : fieldInitializers = new Map<Element, Map<Element, HType>>(), | 663 : 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>(), | 664 returnInfo = new Map<Element, ReturnInfo>(), |
| 470 invalidateAfterCodegen = new List<Element>(), | 665 invalidateAfterCodegen = new List<Element>(), |
| 471 super(compiler, constantSystem: JAVA_SCRIPT_CONSTANT_SYSTEM) { | 666 super(compiler, constantSystem: JAVA_SCRIPT_CONSTANT_SYSTEM) { |
| 472 emitter = new CodeEmitterTask(compiler, namer, generateSourceMap); | 667 emitter = new CodeEmitterTask(compiler, namer, generateSourceMap); |
| 473 builder = new SsaBuilderTask(this); | 668 builder = new SsaBuilderTask(this); |
| 474 optimizer = new SsaOptimizerTask(this); | 669 optimizer = new SsaOptimizerTask(this); |
| 475 generator = new SsaCodeGeneratorTask(this); | 670 generator = new SsaCodeGeneratorTask(this); |
| 476 argumentTypes = new ArgumentTypesRegistry(this); | 671 argumentTypes = new ArgumentTypesRegistry(this); |
| 672 fieldTypes = new FieldTypesRegistry(this); | |
| 477 } | 673 } |
| 478 | 674 |
| 479 Element get cyclicThrowHelper { | 675 Element get cyclicThrowHelper { |
| 480 return compiler.findHelper(const SourceString("throwCyclicInit")); | 676 return compiler.findHelper(const SourceString("throwCyclicInit")); |
| 481 } | 677 } |
| 482 | 678 |
| 483 JavaScriptItemCompilationContext createItemCompilationContext() { | 679 JavaScriptItemCompilationContext createItemCompilationContext() { |
| 484 return new JavaScriptItemCompilationContext(); | 680 return new JavaScriptItemCompilationContext(); |
| 485 } | 681 } |
| 486 | 682 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 509 } else { | 705 } else { |
| 510 // If the constant-handler was not able to produce a result we have to | 706 // If the constant-handler was not able to produce a result we have to |
| 511 // go through the builder (below) to generate the lazy initializer for | 707 // go through the builder (below) to generate the lazy initializer for |
| 512 // the static variable. | 708 // the static variable. |
| 513 // We also need to register the use of the cyclic-error helper. | 709 // We also need to register the use of the cyclic-error helper. |
| 514 compiler.enqueuer.codegen.registerStaticUse(cyclicThrowHelper); | 710 compiler.enqueuer.codegen.registerStaticUse(cyclicThrowHelper); |
| 515 } | 711 } |
| 516 } | 712 } |
| 517 | 713 |
| 518 HGraph graph = builder.build(work); | 714 HGraph graph = builder.build(work); |
| 519 optimizer.optimize(work, graph); | 715 optimizer.optimize(work, graph, false); |
| 520 if (work.allowSpeculativeOptimization | 716 if (work.allowSpeculativeOptimization |
| 521 && optimizer.trySpeculativeOptimizations(work, graph)) { | 717 && optimizer.trySpeculativeOptimizations(work, graph)) { |
| 522 CodeBuffer codeBuffer = generator.generateBailoutMethod(work, graph); | 718 CodeBuffer codeBuffer = generator.generateBailoutMethod(work, graph); |
| 523 compiler.codegenWorld.addBailoutCode(work, codeBuffer); | 719 compiler.codegenWorld.addBailoutCode(work, codeBuffer); |
| 524 optimizer.prepareForSpeculativeOptimizations(work, graph); | 720 optimizer.prepareForSpeculativeOptimizations(work, graph); |
| 525 optimizer.optimize(work, graph); | 721 optimizer.optimize(work, graph, true); |
| 526 } | 722 } |
| 527 CodeBuffer codeBuffer = generator.generateCode(work, graph); | 723 CodeBuffer codeBuffer = generator.generateCode(work, graph); |
| 528 compiler.codegenWorld.addGeneratedCode(work, codeBuffer); | 724 compiler.codegenWorld.addGeneratedCode(work, codeBuffer); |
| 529 invalidateAfterCodegen.forEach(compiler.enqueuer.codegen.eagerRecompile); | 725 invalidateAfterCodegen.forEach(compiler.enqueuer.codegen.eagerRecompile); |
| 530 invalidateAfterCodegen.clear(); | 726 invalidateAfterCodegen.clear(); |
| 531 } | 727 } |
| 532 | 728 |
| 533 void processNativeClasses(Enqueuer world, | 729 void processNativeClasses(Enqueuer world, |
| 534 Collection<LibraryElement> libraries) { | 730 Collection<LibraryElement> libraries) { |
| 535 native.processNativeClasses(world, emitter, libraries); | 731 native.processNativeClasses(world, emitter, libraries); |
| 536 } | 732 } |
| 537 | 733 |
| 538 void assembleProgram() { | 734 void assembleProgram() { |
| 539 emitter.assembleProgram(); | 735 emitter.assembleProgram(); |
| 540 } | 736 } |
| 541 | 737 |
| 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 /** | 738 /** |
| 643 * Documentation wanted -- johnniwinther | 739 * Documentation wanted -- johnniwinther |
| 644 * | 740 * |
| 645 * Invariant: [element] must be a declaration element. | 741 * Invariant: [element] must be a declaration element. |
| 646 */ | 742 */ |
| 647 void scheduleForRecompilation(Element element) { | 743 void scheduleForRecompilation(Element element) { |
| 648 assert(invariant(element, element.isDeclaration)); | 744 assert(invariant(element, element.isDeclaration)); |
| 649 if (compiler.phase == Compiler.PHASE_COMPILING) { | 745 if (compiler.phase == Compiler.PHASE_COMPILING) { |
| 650 invalidateAfterCodegen.add(element); | 746 invalidateAfterCodegen.add(element); |
| 651 } | 747 } |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 700 * scheduled for recompilation. | 796 * scheduled for recompilation. |
| 701 * | 797 * |
| 702 * Invariant: [element] must be a declaration element. | 798 * Invariant: [element] must be a declaration element. |
| 703 */ | 799 */ |
| 704 registerParameterTypesOptimization( | 800 registerParameterTypesOptimization( |
| 705 FunctionElement element, | 801 FunctionElement element, |
| 706 HTypeList parameterTypes, | 802 HTypeList parameterTypes, |
| 707 OptionalParameterTypes defaultValueTypes) { | 803 OptionalParameterTypes defaultValueTypes) { |
| 708 assert(invariant(element, element.isDeclaration)); | 804 assert(invariant(element, element.isDeclaration)); |
| 709 if (element.parameterCount(compiler) == 0) return; | 805 if (element.parameterCount(compiler) == 0) return; |
| 710 argumentTypes.registerOptimization( | 806 argumentTypes.registerOptimizedFunction( |
| 711 element, parameterTypes, defaultValueTypes); | 807 element, parameterTypes, defaultValueTypes); |
| 712 } | 808 } |
| 713 | 809 |
| 810 registerFieldTypesOptimization(FunctionElement element, | |
| 811 Element field, | |
| 812 HType type) { | |
| 813 fieldTypes.registerOptimizedFunction(element, field, type); | |
| 814 } | |
| 815 | |
| 714 /** | 816 /** |
| 715 * Documentation wanted -- johnniwinther | 817 * Documentation wanted -- johnniwinther |
| 716 * | 818 * |
| 717 * Invariant: [element] must be a declaration element. | 819 * Invariant: [element] must be a declaration element. |
| 718 */ | 820 */ |
| 719 void registerReturnType(FunctionElement element, HType returnType) { | 821 void registerReturnType(FunctionElement element, HType returnType) { |
| 720 assert(invariant(element, element.isDeclaration)); | 822 assert(invariant(element, element.isDeclaration)); |
| 721 ReturnInfo info = returnInfo[element]; | 823 ReturnInfo info = returnInfo[element]; |
| 722 if (info != null) { | 824 if (info != null) { |
| 723 info.update(returnType, scheduleForRecompilation); | 825 info.update(returnType, scheduleForRecompilation); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 748 } | 850 } |
| 749 | 851 |
| 750 void dumpReturnTypes() { | 852 void dumpReturnTypes() { |
| 751 returnInfo.forEach((Element element, ReturnInfo info) { | 853 returnInfo.forEach((Element element, ReturnInfo info) { |
| 752 if (info.returnType != HType.UNKNOWN) { | 854 if (info.returnType != HType.UNKNOWN) { |
| 753 print("Inferred $element has return type ${info.returnType}"); | 855 print("Inferred $element has return type ${info.returnType}"); |
| 754 } | 856 } |
| 755 }); | 857 }); |
| 756 } | 858 } |
| 757 | 859 |
| 860 void registerConstructor(Element element) { | |
| 861 fieldTypes.registerConstructor(element); | |
| 862 } | |
| 863 | |
| 864 void registerFieldInitializer(Element field, HType type) { | |
| 865 fieldTypes.registerFieldInitializer(field, type); | |
| 866 } | |
| 867 | |
| 868 void registerFieldConstructor(Element field, HType type) { | |
| 869 fieldTypes.registerFieldConstructor(field, type); | |
| 870 } | |
| 871 | |
| 872 void registerFieldSetter(FunctionElement element, Element field, HType type) { | |
| 873 fieldTypes.registerFieldSetter(element, field, type); | |
| 874 } | |
| 875 | |
| 876 void addedDynamicSetter(Selector setter, HType type) { | |
| 877 fieldTypes.addedDynamicSetter(setter, type); | |
| 878 } | |
| 879 | |
| 880 HType optimisticFieldType(Element element) { | |
| 881 return fieldTypes.optimisticFieldType(element); | |
| 882 } | |
| 883 | |
| 758 SourceString getCheckedModeHelper(DartType type) { | 884 SourceString getCheckedModeHelper(DartType type) { |
| 759 Element element = type.element; | 885 Element element = type.element; |
| 760 bool nativeCheck = | 886 bool nativeCheck = |
| 761 emitter.nativeEmitter.requiresNativeIsCheck(element); | 887 emitter.nativeEmitter.requiresNativeIsCheck(element); |
| 762 if (element == compiler.stringClass) { | 888 if (element == compiler.stringClass) { |
| 763 return const SourceString('stringTypeCheck'); | 889 return const SourceString('stringTypeCheck'); |
| 764 } else if (element == compiler.doubleClass) { | 890 } else if (element == compiler.doubleClass) { |
| 765 return const SourceString('doubleTypeCheck'); | 891 return const SourceString('doubleTypeCheck'); |
| 766 } else if (element == compiler.numClass) { | 892 } else if (element == compiler.numClass) { |
| 767 return const SourceString('numTypeCheck'); | 893 return const SourceString('numTypeCheck'); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 787 ? const SourceString('listSuperNativeTypeCheck') | 913 ? const SourceString('listSuperNativeTypeCheck') |
| 788 : const SourceString('listSuperTypeCheck'); | 914 : const SourceString('listSuperTypeCheck'); |
| 789 } else { | 915 } else { |
| 790 return nativeCheck | 916 return nativeCheck |
| 791 ? const SourceString('callTypeCheck') | 917 ? const SourceString('callTypeCheck') |
| 792 : const SourceString('propertyTypeCheck'); | 918 : const SourceString('propertyTypeCheck'); |
| 793 } | 919 } |
| 794 } | 920 } |
| 795 } | 921 } |
| 796 } | 922 } |
| OLD | NEW |