Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Side by Side Diff: pkg/compiler/lib/src/native/behavior.dart

Issue 2455073003: Compute NativeBehavior for foreign functions. (Closed)
Patch Set: Updated cf. comment. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 import '../common.dart'; 5 import '../common.dart';
6 import '../common/backend_api.dart' show ForeignResolver; 6 import '../common/backend_api.dart' show ForeignResolver;
7 import '../common/resolution.dart' show ParsingContext, Resolution; 7 import '../common/resolution.dart' show ParsingContext, Resolution;
8 import '../compiler.dart' show Compiler; 8 import '../compiler.dart' show Compiler;
9 import '../constants/expressions.dart';
9 import '../constants/values.dart'; 10 import '../constants/values.dart';
10 import '../core_types.dart' show CoreTypes; 11 import '../core_types.dart' show CoreTypes;
11 import '../dart_types.dart'; 12 import '../dart_types.dart';
12 import '../elements/elements.dart'; 13 import '../elements/elements.dart';
13 import '../js/js.dart' as js; 14 import '../js/js.dart' as js;
14 import '../js_backend/js_backend.dart'; 15 import '../js_backend/js_backend.dart';
15 import '../tree/tree.dart'; 16 import '../tree/tree.dart';
16 import '../universe/side_effects.dart' show SideEffects; 17 import '../universe/side_effects.dart' show SideEffects;
17 import '../util/util.dart'; 18 import '../util/util.dart';
18 import 'enqueue.dart'; 19 import 'enqueue.dart';
19 import 'js.dart'; 20 import 'js.dart';
20 21
22 typedef dynamic /*DartType|SpecialType*/ TypeLookup(String typeString);
23
21 /// This class is a temporary work-around until we get a more powerful DartType. 24 /// This class is a temporary work-around until we get a more powerful DartType.
22 class SpecialType { 25 class SpecialType {
23 final String name; 26 final String name;
24 const SpecialType._(this.name); 27 const SpecialType._(this.name);
25 28
26 /// The type Object, but no subtypes: 29 /// The type Object, but no subtypes:
27 static const JsObject = const SpecialType._('=Object'); 30 static const JsObject = const SpecialType._('=Object');
28 31
29 int get hashCode => name.hashCode; 32 int get hashCode => name.hashCode;
30 33
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 /// [nullType] define the types for `Object` and `Null`, respectively. The 259 /// [nullType] define the types for `Object` and `Null`, respectively. The
257 /// latter is used for the type strings of the form '' and 'var'. 260 /// latter is used for the type strings of the form '' and 'var'.
258 /// [validTags] can be used to restrict which tags are accepted. 261 /// [validTags] can be used to restrict which tags are accepted.
259 static void processSpecString( 262 static void processSpecString(
260 DiagnosticReporter reporter, Spannable spannable, String specString, 263 DiagnosticReporter reporter, Spannable spannable, String specString,
261 {Iterable<String> validTags, 264 {Iterable<String> validTags,
262 void setSideEffects(SideEffects newEffects), 265 void setSideEffects(SideEffects newEffects),
263 void setThrows(NativeThrowBehavior throwKind), 266 void setThrows(NativeThrowBehavior throwKind),
264 void setIsAllocation(bool isAllocation), 267 void setIsAllocation(bool isAllocation),
265 void setUseGvn(bool useGvn), 268 void setUseGvn(bool useGvn),
266 dynamic resolveType(String typeString), 269 TypeLookup lookupType,
267 List typesReturned, 270 List typesReturned,
268 List typesInstantiated, 271 List typesInstantiated,
269 objectType, 272 objectType,
270 nullType}) { 273 nullType}) {
271 bool seenError = false; 274 bool seenError = false;
272 275
273 void reportError(String message) { 276 void reportError(String message) {
274 seenError = true; 277 seenError = true;
275 reporter.reportErrorMessage( 278 reporter.reportErrorMessage(
276 spannable, MessageKind.GENERIC, {'text': message}); 279 spannable, MessageKind.GENERIC, {'text': message});
(...skipping 22 matching lines...) Expand all
299 } 302 }
300 return; 303 return;
301 } 304 }
302 if (typesString == '' || typesString == 'var') { 305 if (typesString == '' || typesString == 'var') {
303 if (onVar != null) { 306 if (onVar != null) {
304 onVar(); 307 onVar();
305 } 308 }
306 return; 309 return;
307 } 310 }
308 for (final typeString in typesString.split('|')) { 311 for (final typeString in typesString.split('|')) {
309 onType(resolveType(typeString.trim())); 312 onType(_parseType(typeString.trim(), spannable, reporter, lookupType));
310 } 313 }
311 } 314 }
312 315
313 if (!specString.contains(';') && !specString.contains(':')) { 316 if (!specString.contains(';') && !specString.contains(':')) {
314 // Form (1), types or pseudo-types like 'void' and 'var'. 317 // Form (1), types or pseudo-types like 'void' and 'var'.
315 resolveTypesString(specString.trim(), onVar: () { 318 resolveTypesString(specString.trim(), onVar: () {
316 typesReturned.add(objectType); 319 typesReturned.add(objectType);
317 typesReturned.add(nullType); 320 typesReturned.add(nullType);
318 }, onType: (type) { 321 }, onType: (type) {
319 typesInstantiated.add(type); 322 typesInstantiated.add(type);
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
479 break; 482 break;
480 default: 483 default:
481 reportError("Unrecognized side-effect flag: '$dependency'."); 484 reportError("Unrecognized side-effect flag: '$dependency'.");
482 } 485 }
483 } 486 }
484 } 487 }
485 488
486 return sideEffects; 489 return sideEffects;
487 } 490 }
488 491
489 static NativeBehavior ofJsCall(Send jsCall, DiagnosticReporter reporter, 492 /// Returns a [TypeLookup] that uses [resolver] to perform lookup and [node]
493 /// as position for errors.
494 static TypeLookup _typeLookup(Node node, ForeignResolver resolver) {
495 return (String name) => resolver.resolveTypeFromString(node, name);
496 }
497
498 /// Compute the [NativeBehavior] for a [Send] node calling the 'JS' function.
499 static NativeBehavior ofJsCallSend(Send jsCall, DiagnosticReporter reporter,
490 ParsingContext parsing, CoreTypes coreTypes, ForeignResolver resolver) { 500 ParsingContext parsing, CoreTypes coreTypes, ForeignResolver resolver) {
501 var argNodes = jsCall.arguments;
502 if (argNodes.isEmpty || argNodes.tail.isEmpty) {
503 reporter.reportErrorMessage(jsCall, MessageKind.WRONG_ARGUMENT_FOR_JS);
504 return new NativeBehavior();
505 }
506
507 var specArgument = argNodes.head;
508 if (specArgument is! StringNode || specArgument.isInterpolation) {
509 reporter.reportErrorMessage(
510 specArgument, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST);
511 return new NativeBehavior();
512 }
513
514 var codeArgument = argNodes.tail.head;
515 if (codeArgument is! StringNode || codeArgument.isInterpolation) {
516 reporter.reportErrorMessage(
517 codeArgument, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND);
518 return new NativeBehavior();
519 }
520
521 String specString = specArgument.dartString.slowToString();
522 String codeString = codeArgument.dartString.slowToString();
523
524 return ofJsCall(specString, codeString, _typeLookup(specArgument, resolver),
525 specArgument, reporter, coreTypes);
526 }
527
528 /// Compute the [NativeBehavior] for a call to the 'JS' function with the
529 /// given [specString] and [codeString] (first and second arguments).
530 static NativeBehavior ofJsCall(
531 String specString,
532 String codeString,
533 TypeLookup lookupType,
534 Spannable spannable,
535 DiagnosticReporter reporter,
536 CoreTypes coreTypes) {
491 // The first argument of a JS-call is a string encoding various attributes 537 // The first argument of a JS-call is a string encoding various attributes
492 // of the code. 538 // of the code.
493 // 539 //
494 // 'Type1|Type2'. A union type. 540 // 'Type1|Type2'. A union type.
495 // '=Object'. A JavaScript Object, no subtype. 541 // '=Object'. A JavaScript Object, no subtype.
496 542
497 NativeBehavior behavior = new NativeBehavior(); 543 NativeBehavior behavior = new NativeBehavior();
498 544
499 var argNodes = jsCall.arguments; 545 behavior.codeTemplateText = codeString;
500 if (argNodes.isEmpty || argNodes.tail.isEmpty) {
501 reporter.reportErrorMessage(jsCall, MessageKind.GENERIC,
502 {'text': "JS expression takes two or more arguments."});
503 return behavior;
504 }
505
506 var specArgument = argNodes.head;
507 if (specArgument is! StringNode || specArgument.isInterpolation) {
508 reporter.reportErrorMessage(specArgument, MessageKind.GENERIC,
509 {'text': "JS first argument must be a string literal."});
510 return behavior;
511 }
512
513 var codeArgument = argNodes.tail.head;
514 if (codeArgument is! StringNode || codeArgument.isInterpolation) {
515 reporter.reportErrorMessage(codeArgument, MessageKind.GENERIC,
516 {'text': "JS second argument must be a string literal."});
517 return behavior;
518 }
519
520 behavior.codeTemplateText = codeArgument.dartString.slowToString();
521 behavior.codeTemplate = js.js.parseForeignJS(behavior.codeTemplateText); 546 behavior.codeTemplate = js.js.parseForeignJS(behavior.codeTemplateText);
522 547
523 String specString = specArgument.dartString.slowToString();
524
525 dynamic resolveType(String typeString) {
526 return _parseType(
527 typeString,
528 parsing,
529 (name) => resolver.resolveTypeFromString(specArgument, name),
530 specArgument);
531 }
532
533 bool sideEffectsAreEncodedInSpecString = false; 548 bool sideEffectsAreEncodedInSpecString = false;
534 549
535 void setSideEffects(SideEffects newEffects) { 550 void setSideEffects(SideEffects newEffects) {
536 sideEffectsAreEncodedInSpecString = true; 551 sideEffectsAreEncodedInSpecString = true;
537 behavior.sideEffects.setTo(newEffects); 552 behavior.sideEffects.setTo(newEffects);
538 } 553 }
539 554
540 bool throwBehaviorFromSpecString = false; 555 bool throwBehaviorFromSpecString = false;
541 void setThrows(NativeThrowBehavior throwBehavior) { 556 void setThrows(NativeThrowBehavior throwBehavior) {
542 throwBehaviorFromSpecString = true; 557 throwBehaviorFromSpecString = true;
543 behavior.throwBehavior = throwBehavior; 558 behavior.throwBehavior = throwBehavior;
544 } 559 }
545 560
546 void setIsAllocation(bool isAllocation) { 561 void setIsAllocation(bool isAllocation) {
547 behavior.isAllocation = isAllocation; 562 behavior.isAllocation = isAllocation;
548 } 563 }
549 564
550 void setUseGvn(bool useGvn) { 565 void setUseGvn(bool useGvn) {
551 behavior.useGvn = useGvn; 566 behavior.useGvn = useGvn;
552 } 567 }
553 568
554 processSpecString(reporter, specArgument, specString, 569 processSpecString(reporter, spannable, specString,
555 setSideEffects: setSideEffects, 570 setSideEffects: setSideEffects,
556 setThrows: setThrows, 571 setThrows: setThrows,
557 setIsAllocation: setIsAllocation, 572 setIsAllocation: setIsAllocation,
558 setUseGvn: setUseGvn, 573 setUseGvn: setUseGvn,
559 resolveType: resolveType, 574 lookupType: lookupType,
560 typesReturned: behavior.typesReturned, 575 typesReturned: behavior.typesReturned,
561 typesInstantiated: behavior.typesInstantiated, 576 typesInstantiated: behavior.typesInstantiated,
562 objectType: coreTypes.objectType, 577 objectType: coreTypes.objectType,
563 nullType: coreTypes.nullType); 578 nullType: coreTypes.nullType);
564 579
565 if (!sideEffectsAreEncodedInSpecString) { 580 if (!sideEffectsAreEncodedInSpecString) {
566 new SideEffectsVisitor(behavior.sideEffects) 581 new SideEffectsVisitor(behavior.sideEffects)
567 .visit(behavior.codeTemplate.ast); 582 .visit(behavior.codeTemplate.ast);
568 } 583 }
569 if (!throwBehaviorFromSpecString) { 584 if (!throwBehaviorFromSpecString) {
570 behavior.throwBehavior = 585 behavior.throwBehavior =
571 new ThrowBehaviorVisitor().analyze(behavior.codeTemplate.ast); 586 new ThrowBehaviorVisitor().analyze(behavior.codeTemplate.ast);
572 } 587 }
573 588
574 return behavior; 589 return behavior;
575 } 590 }
576 591
577 static void _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal( 592 static void _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal(
578 NativeBehavior behavior, 593 NativeBehavior behavior,
579 Send jsBuiltinOrEmbeddedGlobalCall, 594 Spannable spannable,
595 String specString,
596 TypeLookup lookupType,
580 DiagnosticReporter reporter, 597 DiagnosticReporter reporter,
581 ParsingContext parsing,
582 CoreTypes coreTypes, 598 CoreTypes coreTypes,
583 ForeignResolver resolver, 599 {List<String> validTags}) {
584 {bool isBuiltin, 600 void setSideEffects(SideEffects newEffects) {
585 List<String> validTags}) { 601 behavior.sideEffects.setTo(newEffects);
602 }
603
604 processSpecString(reporter, spannable, specString,
605 validTags: validTags,
606 lookupType: lookupType,
607 setSideEffects: setSideEffects,
608 typesReturned: behavior.typesReturned,
609 typesInstantiated: behavior.typesInstantiated,
610 objectType: coreTypes.objectType,
611 nullType: coreTypes.nullType);
612 }
613
614 static NativeBehavior ofJsBuiltinCallSend(
615 Send jsBuiltinCall,
616 DiagnosticReporter reporter,
617 CoreTypes coreTypes,
618 ForeignResolver resolver) {
619 NativeBehavior behavior = new NativeBehavior();
620 behavior.sideEffects.setTo(new SideEffects());
621
586 // The first argument of a JS-embedded global call is a string encoding 622 // The first argument of a JS-embedded global call is a string encoding
587 // the type of the code. 623 // the type of the code.
588 // 624 //
589 // 'Type1|Type2'. A union type. 625 // 'Type1|Type2'. A union type.
590 // '=Object'. A JavaScript Object, no subtype. 626 // '=Object'. A JavaScript Object, no subtype.
591 627
592 String builtinOrGlobal = isBuiltin ? "builtin" : "embedded global"; 628 Link<Node> argNodes = jsBuiltinCall.arguments;
593
594 Link<Node> argNodes = jsBuiltinOrEmbeddedGlobalCall.arguments;
595 if (argNodes.isEmpty) { 629 if (argNodes.isEmpty) {
596 reporter.internalError(jsBuiltinOrEmbeddedGlobalCall, 630 reporter.internalError(
597 "JS $builtinOrGlobal expression has no type."); 631 jsBuiltinCall, "JS builtin expression has no type.");
598 } 632 }
599 633
600 // We don't check the given name. That needs to be done at a later point. 634 // We don't check the given name. That needs to be done at a later point.
601 // This is, because we want to allow non-literals (like references to 635 // This is, because we want to allow non-literals (like references to
602 // enums) as names. 636 // enums) as names.
603 if (argNodes.tail.isEmpty) { 637 if (argNodes.tail.isEmpty) {
604 reporter.internalError(jsBuiltinOrEmbeddedGlobalCall, 638 reporter.internalError(jsBuiltinCall, "JS builtin is missing name.");
605 'JS $builtinOrGlobal is missing name.');
606 }
607
608 if (!isBuiltin) {
609 if (!argNodes.tail.tail.isEmpty) {
610 reporter.internalError(argNodes.tail.tail.head,
611 'JS embedded global has more than 2 arguments');
612 }
613 } 639 }
614 640
615 LiteralString specLiteral = argNodes.head.asLiteralString(); 641 LiteralString specLiteral = argNodes.head.asLiteralString();
616 if (specLiteral == null) { 642 if (specLiteral == null) {
617 // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It 643 // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It
618 // is not very satisfactory because it does not work for void, dynamic. 644 // is not very satisfactory because it does not work for void, dynamic.
619 reporter.internalError(argNodes.head, "Unexpected first argument."); 645 reporter.internalError(argNodes.head, "Unexpected first argument.");
620 } 646 }
621 647
622 String specString = specLiteral.dartString.slowToString(); 648 String specString = specLiteral.dartString.slowToString();
623 649
624 dynamic resolveType(String typeString) { 650 return ofJsBuiltinCall(specString, _typeLookup(jsBuiltinCall, resolver),
625 return _parseType( 651 jsBuiltinCall, reporter, coreTypes);
626 typeString,
627 parsing,
628 (name) => resolver.resolveTypeFromString(specLiteral, name),
629 jsBuiltinOrEmbeddedGlobalCall);
630 }
631
632 void setSideEffects(SideEffects newEffects) {
633 behavior.sideEffects.setTo(newEffects);
634 }
635
636 processSpecString(reporter, jsBuiltinOrEmbeddedGlobalCall, specString,
637 validTags: validTags,
638 resolveType: resolveType,
639 setSideEffects: setSideEffects,
640 typesReturned: behavior.typesReturned,
641 typesInstantiated: behavior.typesInstantiated,
642 objectType: coreTypes.objectType,
643 nullType: coreTypes.nullType);
644 } 652 }
645 653
646 static NativeBehavior ofJsBuiltinCall( 654 static NativeBehavior ofJsBuiltinCall(
647 Send jsBuiltinCall, 655 String specString,
656 TypeLookup lookupType,
657 Spannable spannable,
648 DiagnosticReporter reporter, 658 DiagnosticReporter reporter,
649 ParsingContext parsing, 659 CoreTypes coreTypes) {
660 NativeBehavior behavior = new NativeBehavior();
661 behavior.sideEffects.setTo(new SideEffects());
662 _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal(
663 behavior, spannable, specString, lookupType, reporter, coreTypes);
664 return behavior;
665 }
666
667 static NativeBehavior ofJsEmbeddedGlobalCallSend(
668 Send jsEmbeddedGlobalCall,
669 DiagnosticReporter reporter,
650 CoreTypes coreTypes, 670 CoreTypes coreTypes,
651 ForeignResolver resolver) { 671 ForeignResolver resolver) {
652 NativeBehavior behavior = new NativeBehavior(); 672 NativeBehavior behavior = new NativeBehavior();
653 behavior.sideEffects.setTo(new SideEffects());
654
655 _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal(
656 behavior, jsBuiltinCall, reporter, parsing, coreTypes, resolver,
657 isBuiltin: true);
658
659 return behavior;
660 }
661
662 static NativeBehavior ofJsEmbeddedGlobalCall(
663 Send jsEmbeddedGlobalCall,
664 DiagnosticReporter reporter,
665 ParsingContext parsing,
666 CoreTypes coreTypes,
667 ForeignResolver resolver) {
668 NativeBehavior behavior = new NativeBehavior();
669 // TODO(sra): Allow the use site to override these defaults. 673 // TODO(sra): Allow the use site to override these defaults.
670 // Embedded globals are usually pre-computed data structures or JavaScript 674 // Embedded globals are usually pre-computed data structures or JavaScript
671 // functions that never change. 675 // functions that never change.
672 behavior.sideEffects.setTo(new SideEffects.empty()); 676 behavior.sideEffects.setTo(new SideEffects.empty());
673 behavior.throwBehavior = NativeThrowBehavior.NEVER; 677 behavior.throwBehavior = NativeThrowBehavior.NEVER;
674 678
679 // The first argument of a JS-embedded global call is a string encoding
680 // the type of the code.
681 //
682 // 'Type1|Type2'. A union type.
683 // '=Object'. A JavaScript Object, no subtype.
684
685 Link<Node> argNodes = jsEmbeddedGlobalCall.arguments;
686 if (argNodes.isEmpty) {
687 reporter.internalError(
688 jsEmbeddedGlobalCall, "JS embedded global expression has no type.");
689 }
690
691 // We don't check the given name. That needs to be done at a later point.
692 // This is, because we want to allow non-literals (like references to
693 // enums) as names.
694 if (argNodes.tail.isEmpty) {
695 reporter.internalError(
696 jsEmbeddedGlobalCall, "JS embedded global is missing name.");
697 }
698
699 if (!argNodes.tail.tail.isEmpty) {
700 reporter.internalError(argNodes.tail.tail.head,
701 'JS embedded global has more than 2 arguments');
702 }
703
704 LiteralString specLiteral = argNodes.head.asLiteralString();
705 if (specLiteral == null) {
706 // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It
707 // is not very satisfactory because it does not work for void, dynamic.
708 reporter.internalError(argNodes.head, "Unexpected first argument.");
709 }
710
711 String specString = specLiteral.dartString.slowToString();
712
713 return ofJsEmbeddedGlobalCall(
714 specString,
715 _typeLookup(jsEmbeddedGlobalCall, resolver),
716 jsEmbeddedGlobalCall,
717 reporter,
718 coreTypes);
719 }
720
721 static NativeBehavior ofJsEmbeddedGlobalCall(
722 String specString,
723 TypeLookup lookupType,
724 Spannable spannable,
725 DiagnosticReporter reporter,
726 CoreTypes coreTypes) {
727 NativeBehavior behavior = new NativeBehavior();
728 // TODO(sra): Allow the use site to override these defaults.
729 // Embedded globals are usually pre-computed data structures or JavaScript
730 // functions that never change.
731 behavior.sideEffects.setTo(new SideEffects.empty());
732 behavior.throwBehavior = NativeThrowBehavior.NEVER;
675 _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal( 733 _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal(
676 behavior, jsEmbeddedGlobalCall, reporter, parsing, coreTypes, resolver, 734 behavior, spannable, specString, lookupType, reporter, coreTypes,
677 isBuiltin: false, validTags: const ['returns', 'creates']); 735 validTags: ['returns', 'creates']);
678
679 return behavior; 736 return behavior;
680 } 737 }
681 738
682 static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) { 739 static NativeBehavior ofMethodElement(
683 FunctionType type = method.computeType(compiler.resolution); 740 FunctionElement element, Compiler compiler) {
741 FunctionType type = element.computeType(compiler.resolution);
742 List<ConstantExpression> metadata = <ConstantExpression>[];
743 for (MetadataAnnotation annotation in element.implementation.metadata) {
744 annotation.ensureResolved(compiler.resolution);
745 metadata.add(annotation.constant);
746 }
747
748 DartType lookup(String name) {
749 Element e = element.buildScope().lookup(name);
750 if (e == null) return null;
751 if (e is! ClassElement) return null;
752 ClassElement cls = e;
753 cls.ensureResolved(compiler.resolution);
754 return cls.thisType;
755 }
756
757 return ofMethod(element, type, metadata, lookup, compiler,
758 isJsInterop: compiler.backend.isJsInterop(element));
759 }
760
761 static NativeBehavior ofMethod(
762 Spannable spannable,
763 FunctionType type,
764 List<ConstantExpression> metadata,
765 TypeLookup lookupType,
766 Compiler compiler,
767 {bool isJsInterop}) {
684 var behavior = new NativeBehavior(); 768 var behavior = new NativeBehavior();
685 var returnType = type.returnType; 769 var returnType = type.returnType;
686 bool isInterop = compiler.backend.isJsInterop(method);
687 // Note: For dart:html and other internal libraries we maintain, we can 770 // Note: For dart:html and other internal libraries we maintain, we can
688 // trust the return type and use it to limit what we enqueue. We have to 771 // trust the return type and use it to limit what we enqueue. We have to
689 // be more conservative about JS interop types and assume they can return 772 // be more conservative about JS interop types and assume they can return
690 // anything (unless the user provides the experimental flag to trust the 773 // anything (unless the user provides the experimental flag to trust the
691 // type of js-interop APIs). We do restrict the allocation effects and say 774 // type of js-interop APIs). We do restrict the allocation effects and say
692 // that interop calls create only interop types (which may be unsound if 775 // that interop calls create only interop types (which may be unsound if
693 // an interop call returns a DOM type and declares a dynamic return type, 776 // an interop call returns a DOM type and declares a dynamic return type,
694 // but otherwise we would include a lot of code by default). 777 // but otherwise we would include a lot of code by default).
695 // TODO(sigmund,sra): consider doing something better for numeric types. 778 // TODO(sigmund,sra): consider doing something better for numeric types.
696 behavior.typesReturned.add( 779 behavior.typesReturned.add(
697 !isInterop || compiler.options.trustJSInteropTypeAnnotations 780 !isJsInterop || compiler.options.trustJSInteropTypeAnnotations
698 ? returnType 781 ? returnType
699 : const DynamicType()); 782 : const DynamicType());
700 if (!type.returnType.isVoid) { 783 if (!type.returnType.isVoid) {
701 // Declared types are nullable. 784 // Declared types are nullable.
702 behavior.typesReturned.add(compiler.coreTypes.nullType); 785 behavior.typesReturned.add(compiler.coreTypes.nullType);
703 } 786 }
704 behavior._capture(type, compiler.resolution, 787 behavior._capture(type, compiler.resolution,
705 isInterop: isInterop, compiler: compiler); 788 isInterop: isJsInterop, compiler: compiler);
706 789
707 for (DartType type in type.optionalParameterTypes) { 790 for (DartType type in type.optionalParameterTypes) {
708 behavior._escape(type, compiler.resolution); 791 behavior._escape(type, compiler.resolution);
709 } 792 }
710 for (DartType type in type.namedParameterTypes) { 793 for (DartType type in type.namedParameterTypes) {
711 behavior._escape(type, compiler.resolution); 794 behavior._escape(type, compiler.resolution);
712 } 795 }
713 796
714 behavior._overrideWithAnnotations(method, compiler); 797 behavior._overrideWithAnnotations(
798 spannable, metadata, lookupType, compiler);
715 return behavior; 799 return behavior;
716 } 800 }
717 801
718 static NativeBehavior ofFieldLoad(MemberElement field, Compiler compiler) { 802 static NativeBehavior ofFieldElementLoad(
803 MemberElement element, Compiler compiler) {
719 Resolution resolution = compiler.resolution; 804 Resolution resolution = compiler.resolution;
720 DartType type = field.computeType(resolution); 805 DartType type = element.computeType(resolution);
806 List<ConstantExpression> metadata = <ConstantExpression>[];
807 for (MetadataAnnotation annotation in element.implementation.metadata) {
808 annotation.ensureResolved(compiler.resolution);
809 metadata.add(annotation.constant);
810 }
811
812 DartType lookup(String name) {
813 Element e = element.buildScope().lookup(name);
814 if (e == null) return null;
815 if (e is! ClassElement) return null;
816 ClassElement cls = e;
817 cls.ensureResolved(compiler.resolution);
818 return cls.thisType;
819 }
820
821 return ofFieldLoad(element, type, metadata, lookup, compiler,
822 isJsInterop: compiler.backend.isJsInterop(element));
823 }
824
825 static NativeBehavior ofFieldLoad(
826 Spannable spannable,
827 DartType type,
828 List<ConstantExpression> metadata,
829 TypeLookup lookupType,
830 Compiler compiler,
831 {bool isJsInterop}) {
832 Resolution resolution = compiler.resolution;
721 var behavior = new NativeBehavior(); 833 var behavior = new NativeBehavior();
722 bool isInterop = compiler.backend.isJsInterop(field);
723 // TODO(sigmund,sra): consider doing something better for numeric types. 834 // TODO(sigmund,sra): consider doing something better for numeric types.
724 behavior.typesReturned.add( 835 behavior.typesReturned.add(
725 !isInterop || compiler.options.trustJSInteropTypeAnnotations 836 !isJsInterop || compiler.options.trustJSInteropTypeAnnotations
726 ? type 837 ? type
727 : const DynamicType()); 838 : const DynamicType());
728 // Declared types are nullable. 839 // Declared types are nullable.
729 behavior.typesReturned.add(resolution.coreTypes.nullType); 840 behavior.typesReturned.add(resolution.coreTypes.nullType);
730 behavior._capture(type, resolution, 841 behavior._capture(type, resolution,
731 isInterop: isInterop, compiler: compiler); 842 isInterop: isJsInterop, compiler: compiler);
732 behavior._overrideWithAnnotations(field, compiler); 843 behavior._overrideWithAnnotations(
844 spannable, metadata, lookupType, compiler);
733 return behavior; 845 return behavior;
734 } 846 }
735 847
736 static NativeBehavior ofFieldStore(MemberElement field, Compiler compiler) { 848 static NativeBehavior ofFieldElementStore(
737 Resolution resolution = compiler.resolution; 849 MemberElement field, Resolution resolution) {
738 DartType type = field.computeType(resolution); 850 DartType type = field.computeType(resolution);
851 return ofFieldStore(type, resolution);
852 }
853
854 static NativeBehavior ofFieldStore(DartType type, Resolution resolution) {
739 var behavior = new NativeBehavior(); 855 var behavior = new NativeBehavior();
740 behavior._escape(type, resolution); 856 behavior._escape(type, resolution);
741 // We don't override the default behaviour - the annotations apply to 857 // We don't override the default behaviour - the annotations apply to
742 // loading the field. 858 // loading the field.
743 return behavior; 859 return behavior;
744 } 860 }
745 861
746 void _overrideWithAnnotations(Element element, Compiler compiler) { 862 void _overrideWithAnnotations(
747 if (element.implementation.metadata.isEmpty) return; 863 Spannable spannable,
748 864 Iterable<ConstantExpression> metadata,
749 DartType lookup(String name) { 865 TypeLookup lookupType,
750 Element e = element.buildScope().lookup(name); 866 Compiler compiler) {
751 if (e == null) return null; 867 if (metadata.isEmpty) return;
752 if (e is! ClassElement) return null;
753 ClassElement cls = e;
754 cls.ensureResolved(compiler.resolution);
755 return cls.thisType;
756 }
757 868
758 NativeEnqueuer enqueuer = compiler.enqueuer.resolution.nativeEnqueuer; 869 NativeEnqueuer enqueuer = compiler.enqueuer.resolution.nativeEnqueuer;
759 var creates = 870 var creates = _collect(spannable, metadata, compiler,
760 _collect(element, compiler, enqueuer.annotationCreatesClass, lookup); 871 enqueuer.annotationCreatesClass, lookupType);
761 var returns = 872 var returns = _collect(spannable, metadata, compiler,
762 _collect(element, compiler, enqueuer.annotationReturnsClass, lookup); 873 enqueuer.annotationReturnsClass, lookupType);
763 874
764 if (creates != null) { 875 if (creates != null) {
765 typesInstantiated 876 typesInstantiated
766 ..clear() 877 ..clear()
767 ..addAll(creates); 878 ..addAll(creates);
768 } 879 }
769 if (returns != null) { 880 if (returns != null) {
770 typesReturned 881 typesReturned
771 ..clear() 882 ..clear()
772 ..addAll(returns); 883 ..addAll(returns);
773 } 884 }
774 } 885 }
775 886
776 /** 887 /**
777 * Returns a list of type constraints from the annotations of 888 * Returns a list of type constraints from the annotations of
778 * [annotationClass]. 889 * [annotationClass].
779 * Returns `null` if no constraints. 890 * Returns `null` if no constraints.
780 */ 891 */
781 static _collect(Element element, Compiler compiler, Element annotationClass, 892 static _collect(Spannable spannable, Iterable<ConstantExpression> metadata,
782 lookup(str)) { 893 Compiler compiler, Element annotationClass, TypeLookup lookupType) {
783 DiagnosticReporter reporter = compiler.reporter; 894 DiagnosticReporter reporter = compiler.reporter;
784 var types = null; 895 var types = null;
785 for (MetadataAnnotation annotation in element.implementation.metadata) { 896 for (ConstantExpression constant in metadata) {
786 annotation.ensureResolved(compiler.resolution); 897 ConstantValue value = compiler.constants.getConstantValue(constant);
787 ConstantValue value =
788 compiler.constants.getConstantValue(annotation.constant);
789 if (!value.isConstructedObject) continue; 898 if (!value.isConstructedObject) continue;
790 ConstructedConstantValue constructedObject = value; 899 ConstructedConstantValue constructedObject = value;
791 if (constructedObject.type.element != annotationClass) continue; 900 if (constructedObject.type.element != annotationClass) continue;
792 901
793 Iterable<ConstantValue> fields = constructedObject.fields.values; 902 Iterable<ConstantValue> fields = constructedObject.fields.values;
794 // TODO(sra): Better validation of the constant. 903 // TODO(sra): Better validation of the constant.
795 if (fields.length != 1 || !fields.single.isString) { 904 if (fields.length != 1 || !fields.single.isString) {
796 reporter.internalError( 905 reporter.internalError(spannable,
797 annotation, 'Annotations needs one string: ${annotation.node}'); 906 'Annotations needs one string: ${constant.toStructuredText()}');
798 } 907 }
799 StringConstantValue specStringConstant = fields.single; 908 StringConstantValue specStringConstant = fields.single;
800 String specString = specStringConstant.toDartString().slowToString(); 909 String specString = specStringConstant.toDartString().slowToString();
801 for (final typeString in specString.split('|')) { 910 for (final typeString in specString.split('|')) {
802 var type = 911 var type = _parseType(typeString, spannable, reporter, lookupType);
803 _parseType(typeString, compiler.parsingContext, lookup, annotation);
804 if (types == null) types = []; 912 if (types == null) types = [];
805 types.add(type); 913 types.add(type);
806 } 914 }
807 } 915 }
808 return types; 916 return types;
809 } 917 }
810 918
811 /// Models the behavior of having intances of [type] escape from Dart code 919 /// Models the behavior of having intances of [type] escape from Dart code
812 /// into native code. 920 /// into native code.
813 void _escape(DartType type, Resolution resolution) { 921 void _escape(DartType type, Resolution resolution) {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
867 } else { 975 } else {
868 // Otherwise, when the declared type is a Dart type, we do not 976 // Otherwise, when the declared type is a Dart type, we do not
869 // register an allocation because we assume it cannot be instantiated 977 // register an allocation because we assume it cannot be instantiated
870 // from within the JS-interop code. It must have escaped from another 978 // from within the JS-interop code. It must have escaped from another
871 // API. 979 // API.
872 } 980 }
873 } 981 }
874 } 982 }
875 } 983 }
876 984
877 static dynamic _parseType(String typeString, ParsingContext parsing, 985 static dynamic /*DartType|SpecialType*/ _parseType(String typeString,
878 lookup(name), locationNodeOrElement) { 986 Spannable spannable, DiagnosticReporter reporter, TypeLookup lookupType) {
879 DiagnosticReporter reporter = parsing.reporter;
880 if (typeString == '=Object') return SpecialType.JsObject; 987 if (typeString == '=Object') return SpecialType.JsObject;
881 if (typeString == 'dynamic') { 988 if (typeString == 'dynamic') {
882 return const DynamicType(); 989 return const DynamicType();
883 } 990 }
884 var type = lookup(typeString); 991 var type = lookupType(typeString);
885 if (type != null) return type; 992 if (type != null) return type;
886 993
887 int index = typeString.indexOf('<'); 994 int index = typeString.indexOf('<');
888 if (index < 1) { 995 if (index < 1) {
889 reporter.reportErrorMessage(_errorNode(locationNodeOrElement, parsing), 996 reporter.reportErrorMessage(spannable, MessageKind.GENERIC,
890 MessageKind.GENERIC, {'text': "Type '$typeString' not found."}); 997 {'text': "Type '$typeString' not found."});
891 return const DynamicType(); 998 return const DynamicType();
892 } 999 }
893 type = lookup(typeString.substring(0, index)); 1000 type = lookupType(typeString.substring(0, index));
894 if (type != null) { 1001 if (type != null) {
895 // TODO(sra): Parse type parameters. 1002 // TODO(sra): Parse type parameters.
896 return type; 1003 return type;
897 } 1004 }
898 reporter.reportErrorMessage(_errorNode(locationNodeOrElement, parsing), 1005 reporter.reportErrorMessage(spannable, MessageKind.GENERIC,
899 MessageKind.GENERIC, {'text': "Type '$typeString' not found."}); 1006 {'text': "Type '$typeString' not found."});
900 return const DynamicType(); 1007 return const DynamicType();
901 } 1008 }
902
903 static _errorNode(locationNodeOrElement, ParsingContext parsing) {
904 if (locationNodeOrElement is Node) return locationNodeOrElement;
905 return locationNodeOrElement.parseNode(parsing);
906 }
907 } 1009 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_backend/backend_helpers.dart ('k') | pkg/compiler/lib/src/native/enqueue.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698