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