| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 part of native; | 5 part of native; |
| 6 | 6 |
| 7 /// This class is a temporary work-around until we get a more powerful DartType. | 7 /// This class is a temporary work-around until we get a more powerful DartType. |
| 8 class SpecialType { | 8 class SpecialType { |
| 9 final String name; | 9 final String name; |
| 10 const SpecialType._(this.name); | 10 const SpecialType._(this.name); |
| (...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 459 } | 459 } |
| 460 | 460 |
| 461 behavior.codeTemplate = | 461 behavior.codeTemplate = |
| 462 js.js.parseForeignJS(codeArgument.dartString.slowToString()); | 462 js.js.parseForeignJS(codeArgument.dartString.slowToString()); |
| 463 | 463 |
| 464 String specString = specArgument.dartString.slowToString(); | 464 String specString = specArgument.dartString.slowToString(); |
| 465 | 465 |
| 466 dynamic resolveType(String typeString) { | 466 dynamic resolveType(String typeString) { |
| 467 return _parseType( | 467 return _parseType( |
| 468 typeString, | 468 typeString, |
| 469 compiler, | 469 compiler.resolution, |
| 470 (name) => resolver.resolveTypeFromString(specArgument, name), | 470 (name) => resolver.resolveTypeFromString(specArgument, name), |
| 471 specArgument); | 471 specArgument); |
| 472 } | 472 } |
| 473 | 473 |
| 474 bool sideEffectsAreEncodedInSpecString = false; | 474 bool sideEffectsAreEncodedInSpecString = false; |
| 475 | 475 |
| 476 void setSideEffects(SideEffects newEffects) { | 476 void setSideEffects(SideEffects newEffects) { |
| 477 sideEffectsAreEncodedInSpecString = true; | 477 sideEffectsAreEncodedInSpecString = true; |
| 478 behavior.sideEffects.setTo(newEffects); | 478 behavior.sideEffects.setTo(newEffects); |
| 479 } | 479 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 494 | 494 |
| 495 processSpecString(compiler, specArgument, | 495 processSpecString(compiler, specArgument, |
| 496 specString, | 496 specString, |
| 497 setSideEffects: setSideEffects, | 497 setSideEffects: setSideEffects, |
| 498 setThrows: setThrows, | 498 setThrows: setThrows, |
| 499 setIsAllocation: setIsAllocation, | 499 setIsAllocation: setIsAllocation, |
| 500 setUseGvn: setUseGvn, | 500 setUseGvn: setUseGvn, |
| 501 resolveType: resolveType, | 501 resolveType: resolveType, |
| 502 typesReturned: behavior.typesReturned, | 502 typesReturned: behavior.typesReturned, |
| 503 typesInstantiated: behavior.typesInstantiated, | 503 typesInstantiated: behavior.typesInstantiated, |
| 504 objectType: compiler.objectClass.computeType(compiler), | 504 objectType: compiler.coreTypes.objectType, |
| 505 nullType: compiler.nullClass.computeType(compiler)); | 505 nullType: compiler.coreTypes.nullType); |
| 506 | 506 |
| 507 if (!sideEffectsAreEncodedInSpecString) { | 507 if (!sideEffectsAreEncodedInSpecString) { |
| 508 new SideEffectsVisitor(behavior.sideEffects) | 508 new SideEffectsVisitor(behavior.sideEffects) |
| 509 .visit(behavior.codeTemplate.ast); | 509 .visit(behavior.codeTemplate.ast); |
| 510 } | 510 } |
| 511 if (!throwBehaviorFromSpecString) { | 511 if (!throwBehaviorFromSpecString) { |
| 512 behavior.throwBehavior = | 512 behavior.throwBehavior = |
| 513 new ThrowBehaviorVisitor().analyze(behavior.codeTemplate.ast); | 513 new ThrowBehaviorVisitor().analyze(behavior.codeTemplate.ast); |
| 514 } | 514 } |
| 515 | 515 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 557 // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It | 557 // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It |
| 558 // is not very satisfactory because it does not work for void, dynamic. | 558 // is not very satisfactory because it does not work for void, dynamic. |
| 559 compiler.internalError(argNodes.head, "Unexpected first argument."); | 559 compiler.internalError(argNodes.head, "Unexpected first argument."); |
| 560 } | 560 } |
| 561 | 561 |
| 562 String specString = specLiteral.dartString.slowToString(); | 562 String specString = specLiteral.dartString.slowToString(); |
| 563 | 563 |
| 564 dynamic resolveType(String typeString) { | 564 dynamic resolveType(String typeString) { |
| 565 return _parseType( | 565 return _parseType( |
| 566 typeString, | 566 typeString, |
| 567 compiler, | 567 compiler.resolution, |
| 568 (name) => resolver.resolveTypeFromString(specLiteral, name), | 568 (name) => resolver.resolveTypeFromString(specLiteral, name), |
| 569 jsBuiltinOrEmbeddedGlobalCall); | 569 jsBuiltinOrEmbeddedGlobalCall); |
| 570 } | 570 } |
| 571 | 571 |
| 572 void setSideEffects(SideEffects newEffects) { | 572 void setSideEffects(SideEffects newEffects) { |
| 573 behavior.sideEffects.setTo(newEffects); | 573 behavior.sideEffects.setTo(newEffects); |
| 574 } | 574 } |
| 575 | 575 |
| 576 processSpecString(compiler, jsBuiltinOrEmbeddedGlobalCall, | 576 processSpecString(compiler, jsBuiltinOrEmbeddedGlobalCall, |
| 577 specString, | 577 specString, |
| 578 validTags: validTags, | 578 validTags: validTags, |
| 579 resolveType: resolveType, | 579 resolveType: resolveType, |
| 580 setSideEffects: setSideEffects, | 580 setSideEffects: setSideEffects, |
| 581 typesReturned: behavior.typesReturned, | 581 typesReturned: behavior.typesReturned, |
| 582 typesInstantiated: behavior.typesInstantiated, | 582 typesInstantiated: behavior.typesInstantiated, |
| 583 objectType: compiler.objectClass.computeType(compiler), | 583 objectType: compiler.coreTypes.objectType, |
| 584 nullType: compiler.nullClass.computeType(compiler)); | 584 nullType: compiler.coreTypes.nullType); |
| 585 } | 585 } |
| 586 | 586 |
| 587 static NativeBehavior ofJsBuiltinCall(Send jsBuiltinCall, | 587 static NativeBehavior ofJsBuiltinCall(Send jsBuiltinCall, |
| 588 Compiler compiler, | 588 Compiler compiler, |
| 589 ResolverVisitor resolver) { | 589 ResolverVisitor resolver) { |
| 590 NativeBehavior behavior = new NativeBehavior(); | 590 NativeBehavior behavior = new NativeBehavior(); |
| 591 behavior.sideEffects.setTo(new SideEffects()); | 591 behavior.sideEffects.setTo(new SideEffects()); |
| 592 | 592 |
| 593 _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal( | 593 _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal( |
| 594 behavior, jsBuiltinCall, compiler, resolver, isBuiltin: true); | 594 behavior, jsBuiltinCall, compiler, resolver, isBuiltin: true); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 607 behavior.throwBehavior = NativeThrowBehavior.NEVER; | 607 behavior.throwBehavior = NativeThrowBehavior.NEVER; |
| 608 | 608 |
| 609 _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal( | 609 _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal( |
| 610 behavior, jsEmbeddedGlobalCall, compiler, resolver, | 610 behavior, jsEmbeddedGlobalCall, compiler, resolver, |
| 611 isBuiltin: false, | 611 isBuiltin: false, |
| 612 validTags: const ['returns', 'creates']); | 612 validTags: const ['returns', 'creates']); |
| 613 | 613 |
| 614 return behavior; | 614 return behavior; |
| 615 } | 615 } |
| 616 | 616 |
| 617 static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) { | 617 static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) { |
| 618 FunctionType type = method.computeType(compiler); | 618 FunctionType type = method.computeType(compiler.resolution); |
| 619 var behavior = new NativeBehavior(); | 619 var behavior = new NativeBehavior(); |
| 620 behavior.typesReturned.add(type.returnType); | 620 behavior.typesReturned.add(type.returnType); |
| 621 if (!type.returnType.isVoid) { | 621 if (!type.returnType.isVoid) { |
| 622 // Declared types are nullable. | 622 // Declared types are nullable. |
| 623 behavior.typesReturned.add(compiler.nullClass.computeType(compiler)); | 623 behavior.typesReturned.add(compiler.coreTypes.nullType); |
| 624 } | 624 } |
| 625 behavior._capture(type, compiler); | 625 behavior._capture(type, compiler.resolution); |
| 626 | 626 |
| 627 // TODO(sra): Optional arguments are currently missing from the | 627 // TODO(sra): Optional arguments are currently missing from the |
| 628 // DartType. This should be fixed so the following work-around can be | 628 // DartType. This should be fixed so the following work-around can be |
| 629 // removed. | 629 // removed. |
| 630 method.functionSignature.forEachOptionalParameter( | 630 method.functionSignature.forEachOptionalParameter( |
| 631 (ParameterElement parameter) { | 631 (ParameterElement parameter) { |
| 632 behavior._escape(parameter.type, compiler); | 632 behavior._escape(parameter.type, compiler.resolution); |
| 633 }); | 633 }); |
| 634 | 634 |
| 635 behavior._overrideWithAnnotations(method, compiler); | 635 behavior._overrideWithAnnotations(method, compiler); |
| 636 return behavior; | 636 return behavior; |
| 637 } | 637 } |
| 638 | 638 |
| 639 static NativeBehavior ofFieldLoad(MemberElement field, Compiler compiler) { | 639 static NativeBehavior ofFieldLoad(MemberElement field, Compiler compiler) { |
| 640 DartType type = field.computeType(compiler); | 640 DartType type = field.computeType(compiler.resolution); |
| 641 var behavior = new NativeBehavior(); | 641 var behavior = new NativeBehavior(); |
| 642 behavior.typesReturned.add(type); | 642 behavior.typesReturned.add(type); |
| 643 // Declared types are nullable. | 643 // Declared types are nullable. |
| 644 behavior.typesReturned.add(compiler.nullClass.computeType(compiler)); | 644 behavior.typesReturned.add(compiler.coreTypes.nullType); |
| 645 behavior._capture(type, compiler); | 645 behavior._capture(type, compiler.resolution); |
| 646 behavior._overrideWithAnnotations(field, compiler); | 646 behavior._overrideWithAnnotations(field, compiler); |
| 647 return behavior; | 647 return behavior; |
| 648 } | 648 } |
| 649 | 649 |
| 650 static NativeBehavior ofFieldStore(MemberElement field, Compiler compiler) { | 650 static NativeBehavior ofFieldStore(MemberElement field, Compiler compiler) { |
| 651 DartType type = field.computeType(compiler); | 651 DartType type = field.computeType(compiler.resolution); |
| 652 var behavior = new NativeBehavior(); | 652 var behavior = new NativeBehavior(); |
| 653 behavior._escape(type, compiler); | 653 behavior._escape(type, compiler.resolution); |
| 654 // We don't override the default behaviour - the annotations apply to | 654 // We don't override the default behaviour - the annotations apply to |
| 655 // loading the field. | 655 // loading the field. |
| 656 return behavior; | 656 return behavior; |
| 657 } | 657 } |
| 658 | 658 |
| 659 void _overrideWithAnnotations(Element element, Compiler compiler) { | 659 void _overrideWithAnnotations(Element element, Compiler compiler) { |
| 660 if (element.implementation.metadata.isEmpty) return; | 660 if (element.implementation.metadata.isEmpty) return; |
| 661 | 661 |
| 662 DartType lookup(String name) { | 662 DartType lookup(String name) { |
| 663 Element e = element.buildScope().lookup(name); | 663 Element e = element.buildScope().lookup(name); |
| 664 if (e == null) return null; | 664 if (e == null) return null; |
| 665 if (e is! ClassElement) return null; | 665 if (e is! ClassElement) return null; |
| 666 ClassElement cls = e; | 666 ClassElement cls = e; |
| 667 cls.ensureResolved(compiler); | 667 cls.ensureResolved(compiler.resolution); |
| 668 return cls.thisType; | 668 return cls.thisType; |
| 669 } | 669 } |
| 670 | 670 |
| 671 NativeEnqueuer enqueuer = compiler.enqueuer.resolution.nativeEnqueuer; | 671 NativeEnqueuer enqueuer = compiler.enqueuer.resolution.nativeEnqueuer; |
| 672 var creates = _collect(element, compiler, enqueuer.annotationCreatesClass, | 672 var creates = _collect(element, compiler, enqueuer.annotationCreatesClass, |
| 673 lookup); | 673 lookup); |
| 674 var returns = _collect(element, compiler, enqueuer.annotationReturnsClass, | 674 var returns = _collect(element, compiler, enqueuer.annotationReturnsClass, |
| 675 lookup); | 675 lookup); |
| 676 | 676 |
| 677 if (creates != null) { | 677 if (creates != null) { |
| 678 typesInstantiated..clear()..addAll(creates); | 678 typesInstantiated..clear()..addAll(creates); |
| 679 } | 679 } |
| 680 if (returns != null) { | 680 if (returns != null) { |
| 681 typesReturned..clear()..addAll(returns); | 681 typesReturned..clear()..addAll(returns); |
| 682 } | 682 } |
| 683 } | 683 } |
| 684 | 684 |
| 685 /** | 685 /** |
| 686 * Returns a list of type constraints from the annotations of | 686 * Returns a list of type constraints from the annotations of |
| 687 * [annotationClass]. | 687 * [annotationClass]. |
| 688 * Returns `null` if no constraints. | 688 * Returns `null` if no constraints. |
| 689 */ | 689 */ |
| 690 static _collect(Element element, Compiler compiler, Element annotationClass, | 690 static _collect(Element element, Compiler compiler, Element annotationClass, |
| 691 lookup(str)) { | 691 lookup(str)) { |
| 692 var types = null; | 692 var types = null; |
| 693 for (MetadataAnnotation annotation in element.implementation.metadata) { | 693 for (MetadataAnnotation annotation in element.implementation.metadata) { |
| 694 annotation.ensureResolved(compiler); | 694 annotation.ensureResolved(compiler.resolution); |
| 695 ConstantValue value = | 695 ConstantValue value = |
| 696 compiler.constants.getConstantValue(annotation.constant); | 696 compiler.constants.getConstantValue(annotation.constant); |
| 697 if (!value.isConstructedObject) continue; | 697 if (!value.isConstructedObject) continue; |
| 698 ConstructedConstantValue constructedObject = value; | 698 ConstructedConstantValue constructedObject = value; |
| 699 if (constructedObject.type.element != annotationClass) continue; | 699 if (constructedObject.type.element != annotationClass) continue; |
| 700 | 700 |
| 701 Iterable<ConstantValue> fields = constructedObject.fields.values; | 701 Iterable<ConstantValue> fields = constructedObject.fields.values; |
| 702 // TODO(sra): Better validation of the constant. | 702 // TODO(sra): Better validation of the constant. |
| 703 if (fields.length != 1 || !fields.single.isString) { | 703 if (fields.length != 1 || !fields.single.isString) { |
| 704 PartialMetadataAnnotation partial = annotation; | |
| 705 compiler.internalError(annotation, | 704 compiler.internalError(annotation, |
| 706 'Annotations needs one string: ${partial.parseNode(compiler)}'); | 705 'Annotations needs one string: ${annotation.node}'); |
| 707 } | 706 } |
| 708 StringConstantValue specStringConstant = fields.single; | 707 StringConstantValue specStringConstant = fields.single; |
| 709 String specString = specStringConstant.toDartString().slowToString(); | 708 String specString = specStringConstant.toDartString().slowToString(); |
| 710 for (final typeString in specString.split('|')) { | 709 for (final typeString in specString.split('|')) { |
| 711 var type = _parseType(typeString, compiler, lookup, annotation); | 710 var type = |
| 711 _parseType(typeString, compiler.resolution, lookup, annotation); |
| 712 if (types == null) types = []; | 712 if (types == null) types = []; |
| 713 types.add(type); | 713 types.add(type); |
| 714 } | 714 } |
| 715 } | 715 } |
| 716 return types; | 716 return types; |
| 717 } | 717 } |
| 718 | 718 |
| 719 /// Models the behavior of having intances of [type] escape from Dart code | 719 /// Models the behavior of having intances of [type] escape from Dart code |
| 720 /// into native code. | 720 /// into native code. |
| 721 void _escape(DartType type, Compiler compiler) { | 721 void _escape(DartType type, Resolution resolution) { |
| 722 type = type.unalias(compiler); | 722 type = type.unalias(resolution); |
| 723 if (type is FunctionType) { | 723 if (type is FunctionType) { |
| 724 FunctionType functionType = type; | 724 FunctionType functionType = type; |
| 725 // A function might be called from native code, passing us novel | 725 // A function might be called from native code, passing us novel |
| 726 // parameters. | 726 // parameters. |
| 727 _escape(functionType.returnType, compiler); | 727 _escape(functionType.returnType, resolution); |
| 728 for (DartType parameter in functionType.parameterTypes) { | 728 for (DartType parameter in functionType.parameterTypes) { |
| 729 _capture(parameter, compiler); | 729 _capture(parameter, resolution); |
| 730 } | 730 } |
| 731 } | 731 } |
| 732 } | 732 } |
| 733 | 733 |
| 734 /// Models the behavior of Dart code receiving instances and methods of [type] | 734 /// Models the behavior of Dart code receiving instances and methods of [type] |
| 735 /// from native code. We usually start the analysis by capturing a native | 735 /// from native code. We usually start the analysis by capturing a native |
| 736 /// method that has been used. | 736 /// method that has been used. |
| 737 void _capture(DartType type, Compiler compiler) { | 737 void _capture(DartType type, Resolution resolution) { |
| 738 type = type.unalias(compiler); | 738 type = type.unalias(resolution); |
| 739 if (type is FunctionType) { | 739 if (type is FunctionType) { |
| 740 FunctionType functionType = type; | 740 FunctionType functionType = type; |
| 741 _capture(functionType.returnType, compiler); | 741 _capture(functionType.returnType, resolution); |
| 742 for (DartType parameter in functionType.parameterTypes) { | 742 for (DartType parameter in functionType.parameterTypes) { |
| 743 _escape(parameter, compiler); | 743 _escape(parameter, resolution); |
| 744 } | 744 } |
| 745 } else { | 745 } else { |
| 746 typesInstantiated.add(type); | 746 typesInstantiated.add(type); |
| 747 } | 747 } |
| 748 } | 748 } |
| 749 | 749 |
| 750 static dynamic _parseType(String typeString, Compiler compiler, | 750 static dynamic _parseType( |
| 751 String typeString, |
| 752 Resolution resolution, |
| 751 lookup(name), locationNodeOrElement) { | 753 lookup(name), locationNodeOrElement) { |
| 752 if (typeString == '=Object') return SpecialType.JsObject; | 754 if (typeString == '=Object') return SpecialType.JsObject; |
| 753 if (typeString == 'dynamic') { | 755 if (typeString == 'dynamic') { |
| 754 return const DynamicType(); | 756 return const DynamicType(); |
| 755 } | 757 } |
| 756 var type = lookup(typeString); | 758 var type = lookup(typeString); |
| 757 if (type != null) return type; | 759 if (type != null) return type; |
| 758 | 760 |
| 759 int index = typeString.indexOf('<'); | 761 int index = typeString.indexOf('<'); |
| 760 if (index < 1) { | 762 if (index < 1) { |
| 761 compiler.reportErrorMessage( | 763 resolution.listener.reportErrorMessage( |
| 762 _errorNode(locationNodeOrElement, compiler), | 764 _errorNode(locationNodeOrElement, resolution.parsing), |
| 763 MessageKind.GENERIC, | 765 MessageKind.GENERIC, |
| 764 {'text': "Type '$typeString' not found."}); | 766 {'text': "Type '$typeString' not found."}); |
| 765 return const DynamicType(); | 767 return const DynamicType(); |
| 766 } | 768 } |
| 767 type = lookup(typeString.substring(0, index)); | 769 type = lookup(typeString.substring(0, index)); |
| 768 if (type != null) { | 770 if (type != null) { |
| 769 // TODO(sra): Parse type parameters. | 771 // TODO(sra): Parse type parameters. |
| 770 return type; | 772 return type; |
| 771 } | 773 } |
| 772 compiler.reportErrorMessage( | 774 resolution.listener.reportErrorMessage( |
| 773 _errorNode(locationNodeOrElement, compiler), | 775 _errorNode(locationNodeOrElement, resolution.parsing), |
| 774 MessageKind.GENERIC, | 776 MessageKind.GENERIC, |
| 775 {'text': "Type '$typeString' not found."}); | 777 {'text': "Type '$typeString' not found."}); |
| 776 return const DynamicType(); | 778 return const DynamicType(); |
| 777 } | 779 } |
| 778 | 780 |
| 779 static _errorNode(locationNodeOrElement, compiler) { | 781 static _errorNode(locationNodeOrElement, Parsing parsing) { |
| 780 if (locationNodeOrElement is Node) return locationNodeOrElement; | 782 if (locationNodeOrElement is Node) return locationNodeOrElement; |
| 781 return locationNodeOrElement.parseNode(compiler); | 783 return locationNodeOrElement.parseNode(parsing); |
| 782 } | 784 } |
| 783 } | 785 } |
| OLD | NEW |