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

Side by Side Diff: pkg/compiler/lib/src/universe/universe.dart

Issue 1346593002: Move Selector and CallStructure into parts. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years, 3 months 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
« no previous file with comments | « pkg/compiler/lib/src/universe/selector.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library universe; 5 library universe;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 8
9 import '../common/names.dart' show 9 import '../common/names.dart' show
10 Identifiers, 10 Identifiers,
11 Names, 11 Names,
12 Selectors; 12 Selectors;
13 import '../compiler.dart' show 13 import '../compiler.dart' show
14 Compiler; 14 Compiler;
15 import '../diagnostics/invariant.dart' show 15 import '../diagnostics/invariant.dart' show
16 invariant; 16 invariant;
17 import '../diagnostics/spannable.dart' show 17 import '../diagnostics/spannable.dart' show
18 SpannableAssertionFailure; 18 SpannableAssertionFailure;
19 import '../elements/elements.dart'; 19 import '../elements/elements.dart';
20 import '../dart_types.dart'; 20 import '../dart_types.dart';
21 import '../tree/tree.dart'; 21 import '../tree/tree.dart';
22 import '../types/types.dart'; 22 import '../types/types.dart';
23 import '../util/util.dart'; 23 import '../util/util.dart';
24 import '../world.dart' show 24 import '../world.dart' show
25 ClassWorld, 25 ClassWorld,
26 World; 26 World;
27 27
28 part 'call_structure.dart';
28 part 'function_set.dart'; 29 part 'function_set.dart';
30 part 'selector.dart';
29 part 'side_effects.dart'; 31 part 'side_effects.dart';
30 32
31 class UniverseSelector { 33 class UniverseSelector {
32 final Selector selector; 34 final Selector selector;
33 final ReceiverMask mask; 35 final ReceiverMask mask;
34 36
35 UniverseSelector(this.selector, this.mask); 37 UniverseSelector(this.selector, this.mask);
36 38
37 bool appliesUnnamed(Element element, ClassWorld world) { 39 bool appliesUnnamed(Element element, ClassWorld world) {
38 return selector.appliesUnnamed(element, world) && 40 return selector.appliesUnnamed(element, world) &&
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 // TODO(ahe): Replace this method with something that is O(1), for example, 366 // TODO(ahe): Replace this method with something that is O(1), for example,
365 // by using a map. 367 // by using a map.
366 List<LocalFunctionElement> slowDirectlyNestedClosures(Element element) { 368 List<LocalFunctionElement> slowDirectlyNestedClosures(Element element) {
367 // Return new list to guard against concurrent modifications. 369 // Return new list to guard against concurrent modifications.
368 return new List<LocalFunctionElement>.from( 370 return new List<LocalFunctionElement>.from(
369 allClosures.where((LocalFunctionElement closure) { 371 allClosures.where((LocalFunctionElement closure) {
370 return closure.executableContext == element; 372 return closure.executableContext == element;
371 })); 373 }));
372 } 374 }
373 } 375 }
374
375 class SelectorKind {
376 final String name;
377 final int hashCode;
378 const SelectorKind(this.name, this.hashCode);
379
380 static const SelectorKind GETTER = const SelectorKind('getter', 0);
381 static const SelectorKind SETTER = const SelectorKind('setter', 1);
382 static const SelectorKind CALL = const SelectorKind('call', 2);
383 static const SelectorKind OPERATOR = const SelectorKind('operator', 3);
384 static const SelectorKind INDEX = const SelectorKind('index', 4);
385
386 String toString() => name;
387 }
388
389 /// The structure of the arguments at a call-site.
390 // TODO(johnniwinther): Should these be cached?
391 // TODO(johnniwinther): Should isGetter/isSetter be part of the call structure
392 // instead of the selector?
393 class CallStructure {
394 static const CallStructure NO_ARGS = const CallStructure.unnamed(0);
395 static const CallStructure ONE_ARG = const CallStructure.unnamed(1);
396 static const CallStructure TWO_ARGS = const CallStructure.unnamed(2);
397
398 /// The numbers of arguments of the call. Includes named arguments.
399 final int argumentCount;
400
401 /// The number of named arguments of the call.
402 int get namedArgumentCount => 0;
403
404 /// The number of positional argument of the call.
405 int get positionalArgumentCount => argumentCount;
406
407 const CallStructure.unnamed(this.argumentCount);
408
409 factory CallStructure(int argumentCount, [List<String> namedArguments]) {
410 if (namedArguments == null || namedArguments.isEmpty) {
411 return new CallStructure.unnamed(argumentCount);
412 }
413 return new NamedCallStructure(argumentCount, namedArguments);
414 }
415
416 /// `true` if this call has named arguments.
417 bool get isNamed => false;
418
419 /// `true` if this call has no named arguments.
420 bool get isUnnamed => true;
421
422 /// The names of the named arguments in call-site order.
423 List<String> get namedArguments => const <String>[];
424
425 /// The names of the named arguments in canonicalized order.
426 List<String> getOrderedNamedArguments() => const <String>[];
427
428 /// A description of the argument structure.
429 String structureToString() => 'arity=$argumentCount';
430
431 String toString() => 'CallStructure(${structureToString()})';
432
433 Selector get callSelector {
434 return new Selector(SelectorKind.CALL, Selector.CALL_NAME, this);
435 }
436
437 bool match(CallStructure other) {
438 if (identical(this, other)) return true;
439 return this.argumentCount == other.argumentCount
440 && this.namedArgumentCount == other.namedArgumentCount
441 && sameNames(this.namedArguments, other.namedArguments);
442 }
443
444 // TODO(johnniwinther): Cache hash code?
445 int get hashCode {
446 return Hashing.listHash(namedArguments,
447 Hashing.objectHash(argumentCount, namedArguments.length));
448 }
449
450 bool operator ==(other) {
451 if (other is! CallStructure) return false;
452 return match(other);
453 }
454
455 bool signatureApplies(FunctionSignature parameters) {
456 if (argumentCount > parameters.parameterCount) return false;
457 int requiredParameterCount = parameters.requiredParameterCount;
458 int optionalParameterCount = parameters.optionalParameterCount;
459 if (positionalArgumentCount < requiredParameterCount) return false;
460
461 if (!parameters.optionalParametersAreNamed) {
462 // We have already checked that the number of arguments are
463 // not greater than the number of parameters. Therefore the
464 // number of positional arguments are not greater than the
465 // number of parameters.
466 assert(positionalArgumentCount <= parameters.parameterCount);
467 return namedArguments.isEmpty;
468 } else {
469 if (positionalArgumentCount > requiredParameterCount) return false;
470 assert(positionalArgumentCount == requiredParameterCount);
471 if (namedArgumentCount > optionalParameterCount) return false;
472 Set<String> nameSet = new Set<String>();
473 parameters.optionalParameters.forEach((Element element) {
474 nameSet.add(element.name);
475 });
476 for (String name in namedArguments) {
477 if (!nameSet.contains(name)) return false;
478 // TODO(5213): By removing from the set we are checking
479 // that we are not passing the name twice. We should have this
480 // check in the resolver also.
481 nameSet.remove(name);
482 }
483 return true;
484 }
485 }
486
487 /**
488 * Returns a `List` with the evaluated arguments in the normalized order.
489 *
490 * [compileDefaultValue] is a function that returns a compiled constant
491 * of an optional argument that is not in [compiledArguments].
492 *
493 * Precondition: `this.applies(element, world)`.
494 *
495 * Invariant: [element] must be the implementation element.
496 */
497 /*<T>*/ List/*<T>*/ makeArgumentsList(
498 Link<Node> arguments,
499 FunctionElement element,
500 /*T*/ compileArgument(Node argument),
501 /*T*/ compileDefaultValue(ParameterElement element)) {
502 assert(invariant(element, element.isImplementation));
503 List/*<T>*/ result = new List();
504
505 FunctionSignature parameters = element.functionSignature;
506 parameters.forEachRequiredParameter((ParameterElement element) {
507 result.add(compileArgument(arguments.head));
508 arguments = arguments.tail;
509 });
510
511 if (!parameters.optionalParametersAreNamed) {
512 parameters.forEachOptionalParameter((ParameterElement element) {
513 if (!arguments.isEmpty) {
514 result.add(compileArgument(arguments.head));
515 arguments = arguments.tail;
516 } else {
517 result.add(compileDefaultValue(element));
518 }
519 });
520 } else {
521 // Visit named arguments and add them into a temporary list.
522 List compiledNamedArguments = [];
523 for (; !arguments.isEmpty; arguments = arguments.tail) {
524 NamedArgument namedArgument = arguments.head;
525 compiledNamedArguments.add(compileArgument(namedArgument.expression));
526 }
527 // Iterate over the optional parameters of the signature, and try to
528 // find them in [compiledNamedArguments]. If found, we use the
529 // value in the temporary list, otherwise the default value.
530 parameters.orderedOptionalParameters.forEach((ParameterElement element) {
531 int foundIndex = namedArguments.indexOf(element.name);
532 if (foundIndex != -1) {
533 result.add(compiledNamedArguments[foundIndex]);
534 } else {
535 result.add(compileDefaultValue(element));
536 }
537 });
538 }
539 return result;
540 }
541
542 /**
543 * Fills [list] with the arguments in the order expected by
544 * [callee], and where [caller] is a synthesized element
545 *
546 * [compileArgument] is a function that returns a compiled version
547 * of a parameter of [callee].
548 *
549 * [compileConstant] is a function that returns a compiled constant
550 * of an optional argument that is not in the parameters of [callee].
551 *
552 * Returns [:true:] if the signature of the [caller] matches the
553 * signature of the [callee], [:false:] otherwise.
554 */
555 static /*<T>*/ bool addForwardingElementArgumentsToList(
556 ConstructorElement caller,
557 List/*<T>*/ list,
558 ConstructorElement callee,
559 /*T*/ compileArgument(ParameterElement element),
560 /*T*/ compileConstant(ParameterElement element)) {
561 assert(invariant(caller, !callee.isErroneous,
562 message: "Cannot compute arguments to erroneous constructor: "
563 "$caller calling $callee."));
564
565 FunctionSignature signature = caller.functionSignature;
566 Map<Node, ParameterElement> mapping = <Node, ParameterElement>{};
567
568 // TODO(ngeoffray): This is a hack that fakes up AST nodes, so
569 // that we can call [addArgumentsToList].
570 Link<Node> computeCallNodesFromParameters() {
571 LinkBuilder<Node> builder = new LinkBuilder<Node>();
572 signature.forEachRequiredParameter((ParameterElement element) {
573 Node node = element.node;
574 mapping[node] = element;
575 builder.addLast(node);
576 });
577 if (signature.optionalParametersAreNamed) {
578 signature.forEachOptionalParameter((ParameterElement element) {
579 mapping[element.initializer] = element;
580 builder.addLast(new NamedArgument(null, null, element.initializer));
581 });
582 } else {
583 signature.forEachOptionalParameter((ParameterElement element) {
584 Node node = element.node;
585 mapping[node] = element;
586 builder.addLast(node);
587 });
588 }
589 return builder.toLink();
590 }
591
592 /*T*/ internalCompileArgument(Node node) {
593 return compileArgument(mapping[node]);
594 }
595
596 Link<Node> nodes = computeCallNodesFromParameters();
597
598 // Synthesize a structure for the call.
599 // TODO(ngeoffray): Should the resolver do it instead?
600 List<String> namedParameters;
601 if (signature.optionalParametersAreNamed) {
602 namedParameters =
603 signature.optionalParameters.map((e) => e.name).toList();
604 }
605 CallStructure callStructure =
606 new CallStructure(signature.parameterCount, namedParameters);
607 if (!callStructure.signatureApplies(signature)) {
608 return false;
609 }
610 list.addAll(callStructure.makeArgumentsList(
611 nodes,
612 callee,
613 internalCompileArgument,
614 compileConstant));
615
616 return true;
617 }
618
619 static bool sameNames(List<String> first, List<String> second) {
620 for (int i = 0; i < first.length; i++) {
621 if (first[i] != second[i]) return false;
622 }
623 return true;
624 }
625 }
626
627 ///
628 class NamedCallStructure extends CallStructure {
629 final List<String> namedArguments;
630 final List<String> _orderedNamedArguments = <String>[];
631
632 NamedCallStructure(int argumentCount, this.namedArguments)
633 : super.unnamed(argumentCount) {
634 assert(namedArguments.isNotEmpty);
635 }
636
637 @override
638 bool get isNamed => true;
639
640 @override
641 bool get isUnnamed => false;
642
643 @override
644 int get namedArgumentCount => namedArguments.length;
645
646 @override
647 int get positionalArgumentCount => argumentCount - namedArgumentCount;
648
649 @override
650 List<String> getOrderedNamedArguments() {
651 if (!_orderedNamedArguments.isEmpty) return _orderedNamedArguments;
652
653 _orderedNamedArguments.addAll(namedArguments);
654 _orderedNamedArguments.sort((String first, String second) {
655 return first.compareTo(second);
656 });
657 return _orderedNamedArguments;
658 }
659
660 @override
661 String structureToString() {
662 return 'arity=$argumentCount, named=[${namedArguments.join(', ')}]';
663 }
664 }
665
666 class Selector {
667 final SelectorKind kind;
668 final Name memberName;
669 final CallStructure callStructure;
670
671 final int hashCode;
672
673 int get argumentCount => callStructure.argumentCount;
674 int get namedArgumentCount => callStructure.namedArgumentCount;
675 int get positionalArgumentCount => callStructure.positionalArgumentCount;
676 List<String> get namedArguments => callStructure.namedArguments;
677
678 String get name => memberName.text;
679
680 LibraryElement get library => memberName.library;
681
682 static const Name INDEX_NAME = const PublicName("[]");
683 static const Name INDEX_SET_NAME = const PublicName("[]=");
684 static const Name CALL_NAME = Names.call;
685
686 Selector.internal(this.kind,
687 this.memberName,
688 this.callStructure,
689 this.hashCode) {
690 assert(kind == SelectorKind.INDEX ||
691 (memberName != INDEX_NAME && memberName != INDEX_SET_NAME));
692 assert(kind == SelectorKind.OPERATOR ||
693 kind == SelectorKind.INDEX ||
694 !Elements.isOperatorName(memberName.text) ||
695 identical(memberName.text, '??'));
696 assert(kind == SelectorKind.CALL ||
697 kind == SelectorKind.GETTER ||
698 kind == SelectorKind.SETTER ||
699 Elements.isOperatorName(memberName.text) ||
700 identical(memberName.text, '??'));
701 }
702
703 // TODO(johnniwinther): Extract caching.
704 static Map<int, List<Selector>> canonicalizedValues =
705 new Map<int, List<Selector>>();
706
707 factory Selector(SelectorKind kind,
708 Name name,
709 CallStructure callStructure) {
710 // TODO(johnniwinther): Maybe use equality instead of implicit hashing.
711 int hashCode = computeHashCode(kind, name, callStructure);
712 List<Selector> list = canonicalizedValues.putIfAbsent(hashCode,
713 () => <Selector>[]);
714 for (int i = 0; i < list.length; i++) {
715 Selector existing = list[i];
716 if (existing.match(kind, name, callStructure)) {
717 assert(existing.hashCode == hashCode);
718 return existing;
719 }
720 }
721 Selector result = new Selector.internal(
722 kind, name, callStructure, hashCode);
723 list.add(result);
724 return result;
725 }
726
727 factory Selector.fromElement(Element element) {
728 Name name = new Name(element.name, element.library);
729 if (element.isFunction) {
730 if (name == INDEX_NAME) {
731 return new Selector.index();
732 } else if (name == INDEX_SET_NAME) {
733 return new Selector.indexSet();
734 }
735 FunctionSignature signature =
736 element.asFunctionElement().functionSignature;
737 int arity = signature.parameterCount;
738 List<String> namedArguments = null;
739 if (signature.optionalParametersAreNamed) {
740 namedArguments =
741 signature.orderedOptionalParameters.map((e) => e.name).toList();
742 }
743 if (element.isOperator) {
744 // Operators cannot have named arguments, however, that doesn't prevent
745 // a user from declaring such an operator.
746 return new Selector(
747 SelectorKind.OPERATOR,
748 name,
749 new CallStructure(arity, namedArguments));
750 } else {
751 return new Selector.call(
752 name, new CallStructure(arity, namedArguments));
753 }
754 } else if (element.isSetter) {
755 return new Selector.setter(name);
756 } else if (element.isGetter) {
757 return new Selector.getter(name);
758 } else if (element.isField) {
759 return new Selector.getter(name);
760 } else if (element.isConstructor) {
761 return new Selector.callConstructor(name);
762 } else {
763 throw new SpannableAssertionFailure(
764 element, "Can't get selector from $element");
765 }
766 }
767
768 factory Selector.getter(Name name)
769 => new Selector(SelectorKind.GETTER,
770 name.getter,
771 CallStructure.NO_ARGS);
772
773 factory Selector.setter(Name name)
774 => new Selector(SelectorKind.SETTER,
775 name.setter,
776 CallStructure.ONE_ARG);
777
778 factory Selector.unaryOperator(String name) => new Selector(
779 SelectorKind.OPERATOR,
780 new PublicName(Elements.constructOperatorName(name, true)),
781 CallStructure.NO_ARGS);
782
783 factory Selector.binaryOperator(String name) => new Selector(
784 SelectorKind.OPERATOR,
785 new PublicName(Elements.constructOperatorName(name, false)),
786 CallStructure.ONE_ARG);
787
788 factory Selector.index()
789 => new Selector(SelectorKind.INDEX, INDEX_NAME,
790 CallStructure.ONE_ARG);
791
792 factory Selector.indexSet()
793 => new Selector(SelectorKind.INDEX, INDEX_SET_NAME,
794 CallStructure.TWO_ARGS);
795
796 factory Selector.call(Name name, CallStructure callStructure)
797 => new Selector(SelectorKind.CALL, name, callStructure);
798
799 factory Selector.callClosure(int arity, [List<String> namedArguments])
800 => new Selector(SelectorKind.CALL, CALL_NAME,
801 new CallStructure(arity, namedArguments));
802
803 factory Selector.callClosureFrom(Selector selector)
804 => new Selector(SelectorKind.CALL, CALL_NAME, selector.callStructure);
805
806 factory Selector.callConstructor(Name name,
807 [int arity = 0,
808 List<String> namedArguments])
809 => new Selector(SelectorKind.CALL, name,
810 new CallStructure(arity, namedArguments));
811
812 factory Selector.callDefaultConstructor()
813 => new Selector(
814 SelectorKind.CALL,
815 const PublicName(''),
816 CallStructure.NO_ARGS);
817
818 bool get isGetter => kind == SelectorKind.GETTER;
819 bool get isSetter => kind == SelectorKind.SETTER;
820 bool get isCall => kind == SelectorKind.CALL;
821 bool get isClosureCall => isCall && memberName == CALL_NAME;
822
823 bool get isIndex => kind == SelectorKind.INDEX && argumentCount == 1;
824 bool get isIndexSet => kind == SelectorKind.INDEX && argumentCount == 2;
825
826 bool get isOperator => kind == SelectorKind.OPERATOR;
827 bool get isUnaryOperator => isOperator && argumentCount == 0;
828
829 /** Check whether this is a call to 'assert'. */
830 bool get isAssert => isCall && identical(name, "assert");
831
832 /**
833 * The member name for invocation mirrors created from this selector.
834 */
835 String get invocationMirrorMemberName =>
836 isSetter ? '$name=' : name;
837
838 int get invocationMirrorKind {
839 const int METHOD = 0;
840 const int GETTER = 1;
841 const int SETTER = 2;
842 int kind = METHOD;
843 if (isGetter) {
844 kind = GETTER;
845 } else if (isSetter) {
846 kind = SETTER;
847 }
848 return kind;
849 }
850
851 bool appliesUnnamed(Element element, World world) {
852 assert(sameNameHack(element, world));
853 return appliesUntyped(element, world);
854 }
855
856 bool appliesUntyped(Element element, World world) {
857 assert(sameNameHack(element, world));
858 if (Elements.isUnresolved(element)) return false;
859 if (memberName.isPrivate && memberName.library != element.library) {
860 // TODO(johnniwinther): Maybe this should be
861 // `memberName != element.memberName`.
862 return false;
863 }
864 if (world.isForeign(element)) return true;
865 if (element.isSetter) return isSetter;
866 if (element.isGetter) return isGetter || isCall;
867 if (element.isField) {
868 return isSetter
869 ? !element.isFinal && !element.isConst
870 : isGetter || isCall;
871 }
872 if (isGetter) return true;
873 if (isSetter) return false;
874 return signatureApplies(element);
875 }
876
877 bool signatureApplies(FunctionElement function) {
878 if (Elements.isUnresolved(function)) return false;
879 return callStructure.signatureApplies(function.functionSignature);
880 }
881
882 bool sameNameHack(Element element, World world) {
883 // TODO(ngeoffray): Remove workaround checks.
884 return element.isConstructor ||
885 name == element.name ||
886 name == 'assert' && world.isAssertMethod(element);
887 }
888
889 bool applies(Element element, World world) {
890 if (!sameNameHack(element, world)) return false;
891 return appliesUnnamed(element, world);
892 }
893
894 bool match(SelectorKind kind,
895 Name memberName,
896 CallStructure callStructure) {
897 return this.kind == kind
898 && this.memberName == memberName
899 && this.callStructure.match(callStructure);
900 }
901
902 static int computeHashCode(SelectorKind kind,
903 Name name,
904 CallStructure callStructure) {
905 // Add bits from name and kind.
906 int hash = Hashing.mixHashCodeBits(name.hashCode, kind.hashCode);
907 // Add bits from the call structure.
908 return Hashing.mixHashCodeBits(hash, callStructure.hashCode);
909 }
910
911 String toString() {
912 return 'Selector($kind, $name, ${callStructure.structureToString()})';
913 }
914
915 Selector toCallSelector() => new Selector.callClosureFrom(this);
916 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/universe/selector.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698