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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/universe/universe.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library universe;
6
7 import '../elements/elements.dart';
8 import '../dart2jslib.dart';
9 import '../dart_types.dart';
10 import '../types/types.dart';
11 import '../tree/tree.dart';
12 import '../util/util.dart';
13
14 part 'function_set.dart';
15 part 'side_effects.dart';
16
17 class Universe {
18 /// The set of all directly instantiated classes, that is, classes with a
19 /// generative constructor that has been called directly and not only through
20 /// a super-call.
21 ///
22 /// Invariant: Elements are declaration elements.
23 // TODO(johnniwinther): [_directlyInstantiatedClasses] and
24 // [_instantiatedTypes] sets should be merged.
25 final Set<ClassElement> _directlyInstantiatedClasses =
26 new Set<ClassElement>();
27
28 /// The set of all directly instantiated types, that is, the types of the
29 /// directly instantiated classes.
30 ///
31 /// See [_directlyInstantiatedClasses].
32 final Set<DartType> _instantiatedTypes = new Set<DartType>();
33
34 /// The set of all instantiated classes, either directly, as superclasses or
35 /// as supertypes.
36 ///
37 /// Invariant: Elements are declaration elements.
38 final Set<ClassElement> _allInstantiatedClasses = new Set<ClassElement>();
39
40 /**
41 * Documentation wanted -- johnniwinther
42 *
43 * Invariant: Elements are declaration elements.
44 */
45 final Set<FunctionElement> staticFunctionsNeedingGetter =
46 new Set<FunctionElement>();
47 final Set<FunctionElement> methodsNeedingSuperGetter =
48 new Set<FunctionElement>();
49 final Map<String, Set<Selector>> invokedNames =
50 new Map<String, Set<Selector>>();
51 final Map<String, Set<Selector>> invokedGetters =
52 new Map<String, Set<Selector>>();
53 final Map<String, Set<Selector>> invokedSetters =
54 new Map<String, Set<Selector>>();
55
56 /**
57 * Fields accessed. Currently only the codegen knows this
58 * information. The resolver is too conservative when seeing a
59 * getter and only registers an invoked getter.
60 */
61 final Set<Element> fieldGetters = new Set<Element>();
62
63 /**
64 * Fields set. See comment in [fieldGetters].
65 */
66 final Set<Element> fieldSetters = new Set<Element>();
67 final Set<DartType> isChecks = new Set<DartType>();
68
69 /**
70 * Set of (live) [:call:] methods whose signatures reference type variables.
71 *
72 * A live [:call:] method is one whose enclosing class has been instantiated.
73 */
74 final Set<Element> callMethodsWithFreeTypeVariables = new Set<Element>();
75
76 /**
77 * Set of (live) local functions (closures) whose signatures reference type
78 * variables.
79 *
80 * A live function is one whose enclosing member function has been enqueued.
81 */
82 final Set<Element> closuresWithFreeTypeVariables = new Set<Element>();
83
84 /**
85 * Set of all closures in the program. Used by the mirror tracking system
86 * to find all live closure instances.
87 */
88 final Set<LocalFunctionElement> allClosures = new Set<LocalFunctionElement>();
89
90 /**
91 * Set of methods in instantiated classes that are potentially
92 * closurized.
93 */
94 final Set<Element> closurizedMembers = new Set<Element>();
95
96 bool usingFactoryWithTypeArguments = false;
97
98 /// All directly instantiated classes, that is, classes with a generative
99 /// constructor that has been called directly and not only through a
100 /// super-call.
101 // TODO(johnniwinther): Improve semantic precision.
102 Iterable<ClassElement> get directlyInstantiatedClasses {
103 return _directlyInstantiatedClasses;
104 }
105
106 /// All instantiated classes, either directly, as superclasses or as
107 /// supertypes.
108 // TODO(johnniwinther): Improve semantic precision.
109 Iterable<ClassElement> get allInstantiatedClasses {
110 return _allInstantiatedClasses;
111 }
112
113 /// All directly instantiated types, that is, the types of the directly
114 /// instantiated classes.
115 ///
116 /// See [directlyInstantiatedClasses].
117 // TODO(johnniwinther): Improve semantic precision.
118 Iterable<DartType> get instantiatedTypes => _instantiatedTypes;
119
120 /// Returns `true` if [cls] is considered to be instantiated, either directly,
121 /// through subclasses or throught subtypes.
122 // TODO(johnniwinther): Improve semantic precision.
123 bool isInstantiated(ClassElement cls) {
124 return _allInstantiatedClasses.contains(cls);
125 }
126
127 /// Register [type] as (directly) instantiated.
128 ///
129 /// If [byMirrors] is `true`, the instantiation is through mirrors.
130 // TODO(johnniwinther): Fully enforce the separation between exact, through
131 // subclass and through subtype instantiated types/classes.
132 // TODO(johnniwinther): Support unknown type arguments for generic types.
133 void registerTypeInstantiation(InterfaceType type,
134 {bool byMirrors: false}) {
135 _instantiatedTypes.add(type);
136 ClassElement cls = type.element;
137 if (!cls.isAbstract
138 // We can't use the closed-world assumption with native abstract
139 // classes; a native abstract class may have non-abstract subclasses
140 // not declared to the program. Instances of these classes are
141 // indistinguishable from the abstract class.
142 || cls.isNative
143 // Likewise, if this registration comes from the mirror system,
144 // all bets are off.
145 // TODO(herhut): Track classes required by mirrors seperately.
146 || byMirrors) {
147 _directlyInstantiatedClasses.add(cls);
148 }
149
150 // TODO(johnniwinther): Replace this by separate more specific mappings.
151 if (!_allInstantiatedClasses.add(cls)) return;
152 cls.allSupertypes.forEach((InterfaceType supertype) {
153 _allInstantiatedClasses.add(supertype.element);
154 });
155 }
156
157 bool hasMatchingSelector(Set<Selector> selectors,
158 Element member,
159 World world) {
160 if (selectors == null) return false;
161 for (Selector selector in selectors) {
162 if (selector.appliesUnnamed(member, world)) return true;
163 }
164 return false;
165 }
166
167 bool hasInvocation(Element member, World world) {
168 return hasMatchingSelector(invokedNames[member.name], member, world);
169 }
170
171 bool hasInvokedGetter(Element member, World world) {
172 return hasMatchingSelector(invokedGetters[member.name], member, world);
173 }
174
175 bool hasInvokedSetter(Element member, World world) {
176 return hasMatchingSelector(invokedSetters[member.name], member, world);
177 }
178
179 DartType registerIsCheck(DartType type, Compiler compiler) {
180 type = type.unalias(compiler);
181 // Even in checked mode, type annotations for return type and argument
182 // types do not imply type checks, so there should never be a check
183 // against the type variable of a typedef.
184 isChecks.add(type);
185 return type;
186 }
187
188 void forgetElement(Element element, Compiler compiler) {
189 allClosures.remove(element);
190 slowDirectlyNestedClosures(element).forEach(compiler.forgetElement);
191 closurizedMembers.remove(element);
192 fieldSetters.remove(element);
193 fieldGetters.remove(element);
194 _directlyInstantiatedClasses.remove(element);
195 _allInstantiatedClasses.remove(element);
196 if (element is ClassElement) {
197 assert(invariant(
198 element, element.thisType.isRaw,
199 message: 'Generic classes not supported (${element.thisType}).'));
200 _instantiatedTypes
201 ..remove(element.rawType)
202 ..remove(element.thisType);
203 }
204 }
205
206 // TODO(ahe): Replace this method with something that is O(1), for example,
207 // by using a map.
208 List<LocalFunctionElement> slowDirectlyNestedClosures(Element element) {
209 // Return new list to guard against concurrent modifications.
210 return new List<LocalFunctionElement>.from(
211 allClosures.where((LocalFunctionElement closure) {
212 return closure.executableContext == element;
213 }));
214 }
215 }
216
217 class SelectorKind {
218 final String name;
219 final int hashCode;
220 const SelectorKind(this.name, this.hashCode);
221
222 static const SelectorKind GETTER = const SelectorKind('getter', 0);
223 static const SelectorKind SETTER = const SelectorKind('setter', 1);
224 static const SelectorKind CALL = const SelectorKind('call', 2);
225 static const SelectorKind OPERATOR = const SelectorKind('operator', 3);
226 static const SelectorKind INDEX = const SelectorKind('index', 4);
227
228 String toString() => name;
229 }
230
231 class Selector {
232 final SelectorKind kind;
233 final String name;
234 final LibraryElement library; // Library is null for non-private selectors.
235
236 // The numbers of arguments of the selector. Includes named arguments.
237 final int argumentCount;
238 final List<String> namedArguments;
239 final List<String> _orderedNamedArguments;
240 final int hashCode;
241
242 static const String INDEX_NAME ="[]";
243 static const String INDEX_SET_NAME = "[]=";
244 static const String CALL_NAME = Compiler.CALL_OPERATOR_NAME;
245
246 Selector.internal(this.kind,
247 this.name,
248 this.library,
249 this.argumentCount,
250 this.namedArguments,
251 this._orderedNamedArguments,
252 this.hashCode) {
253 assert(kind == SelectorKind.INDEX
254 || (name != INDEX_NAME && name != INDEX_SET_NAME));
255 assert(kind == SelectorKind.OPERATOR
256 || kind == SelectorKind.INDEX
257 || !Elements.isOperatorName(name));
258 assert(kind == SelectorKind.CALL
259 || kind == SelectorKind.GETTER
260 || kind == SelectorKind.SETTER
261 || Elements.isOperatorName(name));
262 assert(!isPrivateName(name) || library != null);
263 }
264
265 static Map<int, List<Selector>> canonicalizedValues =
266 new Map<int, List<Selector>>();
267
268 factory Selector(SelectorKind kind,
269 String name,
270 LibraryElement library,
271 int argumentCount,
272 [List<String> namedArguments]) {
273 if (!isPrivateName(name)) library = null;
274 if (namedArguments == null) namedArguments = const <String>[];
275 int hashCode = computeHashCode(
276 kind, name, library, argumentCount, namedArguments);
277 List<Selector> list = canonicalizedValues.putIfAbsent(hashCode,
278 () => <Selector>[]);
279 for (int i = 0; i < list.length; i++) {
280 Selector existing = list[i];
281 if (existing.match(kind, name, library, argumentCount, namedArguments)) {
282 assert(existing.hashCode == hashCode);
283 assert(existing.mask == null);
284 return existing;
285 }
286 }
287 List<String> orderedNamedArguments = namedArguments.isEmpty
288 ? const <String>[]
289 : <String>[];
290 Selector result = new Selector.internal(
291 kind, name, library, argumentCount,
292 namedArguments, orderedNamedArguments,
293 hashCode);
294 list.add(result);
295 return result;
296 }
297
298 factory Selector.fromElement(Element element) {
299 String name = element.name;
300 if (element.isFunction) {
301 if (name == '[]') {
302 return new Selector.index();
303 } else if (name == '[]=') {
304 return new Selector.indexSet();
305 }
306 FunctionSignature signature =
307 element.asFunctionElement().functionSignature;
308 int arity = signature.parameterCount;
309 List<String> namedArguments = null;
310 if (signature.optionalParametersAreNamed) {
311 namedArguments =
312 signature.orderedOptionalParameters.map((e) => e.name).toList();
313 }
314 if (element.isOperator) {
315 // Operators cannot have named arguments, however, that doesn't prevent
316 // a user from declaring such an operator.
317 return new Selector(
318 SelectorKind.OPERATOR, name, null, arity, namedArguments);
319 } else {
320 return new Selector.call(
321 name, element.library, arity, namedArguments);
322 }
323 } else if (element.isSetter) {
324 return new Selector.setter(name, element.library);
325 } else if (element.isGetter) {
326 return new Selector.getter(name, element.library);
327 } else if (element.isField) {
328 return new Selector.getter(name, element.library);
329 } else {
330 throw new SpannableAssertionFailure(
331 element, "Can't get selector from $element");
332 }
333 }
334
335 factory Selector.getter(String name, LibraryElement library)
336 => new Selector(SelectorKind.GETTER, name, library, 0);
337
338 factory Selector.getterFrom(Selector selector)
339 => new Selector(SelectorKind.GETTER, selector.name, selector.library, 0);
340
341 factory Selector.setter(String name, LibraryElement library)
342 => new Selector(SelectorKind.SETTER, name, library, 1);
343
344 factory Selector.unaryOperator(String name)
345 => new Selector(SelectorKind.OPERATOR,
346 Elements.constructOperatorName(name, true),
347 null, 0);
348
349 factory Selector.binaryOperator(String name)
350 => new Selector(SelectorKind.OPERATOR,
351 Elements.constructOperatorName(name, false),
352 null, 1);
353
354 factory Selector.index()
355 => new Selector(SelectorKind.INDEX,
356 Elements.constructOperatorName(INDEX_NAME, false),
357 null, 1);
358
359 factory Selector.indexSet()
360 => new Selector(SelectorKind.INDEX,
361 Elements.constructOperatorName(INDEX_SET_NAME, false),
362 null, 2);
363
364 factory Selector.call(String name,
365 LibraryElement library,
366 int arity,
367 [List<String> namedArguments])
368 => new Selector(SelectorKind.CALL, name, library, arity, namedArguments);
369
370 factory Selector.callClosure(int arity, [List<String> namedArguments])
371 => new Selector(SelectorKind.CALL, CALL_NAME, null,
372 arity, namedArguments);
373
374 factory Selector.callClosureFrom(Selector selector)
375 => new Selector(SelectorKind.CALL, CALL_NAME, null,
376 selector.argumentCount, selector.namedArguments);
377
378 factory Selector.callConstructor(String name, LibraryElement library,
379 [int arity = 0,
380 List<String> namedArguments])
381 => new Selector(SelectorKind.CALL, name, library,
382 arity, namedArguments);
383
384 factory Selector.callDefaultConstructor(LibraryElement library)
385 => new Selector(SelectorKind.CALL, "", library, 0);
386
387 bool get isGetter => identical(kind, SelectorKind.GETTER);
388 bool get isSetter => identical(kind, SelectorKind.SETTER);
389 bool get isCall => identical(kind, SelectorKind.CALL);
390 bool get isClosureCall {
391 String callName = Compiler.CALL_OPERATOR_NAME;
392 return isCall && name == callName;
393 }
394
395 bool get isIndex => identical(kind, SelectorKind.INDEX) && argumentCount == 1;
396 bool get isIndexSet => identical(kind, SelectorKind.INDEX) && argumentCount == 2;
397
398 bool get isOperator => identical(kind, SelectorKind.OPERATOR);
399 bool get isUnaryOperator => isOperator && argumentCount == 0;
400
401 /** Check whether this is a call to 'assert'. */
402 bool get isAssert => isCall && identical(name, "assert");
403
404 int get namedArgumentCount => namedArguments.length;
405 int get positionalArgumentCount => argumentCount - namedArgumentCount;
406
407 bool get hasExactMask => false;
408 TypeMask get mask => null;
409 Selector get asUntyped => this;
410
411 /**
412 * The member name for invocation mirrors created from this selector.
413 */
414 String get invocationMirrorMemberName =>
415 isSetter ? '$name=' : name;
416
417 int get invocationMirrorKind {
418 const int METHOD = 0;
419 const int GETTER = 1;
420 const int SETTER = 2;
421 int kind = METHOD;
422 if (isGetter) {
423 kind = GETTER;
424 } else if (isSetter) {
425 kind = SETTER;
426 }
427 return kind;
428 }
429
430 bool appliesUnnamed(Element element, World world) {
431 assert(sameNameHack(element, world));
432 return appliesUntyped(element, world);
433 }
434
435 bool appliesUntyped(Element element, World world) {
436 assert(sameNameHack(element, world));
437 if (Elements.isUnresolved(element)) return false;
438 if (isPrivateName(name) && library != element.library) return false;
439 if (world.isForeign(element)) return true;
440 if (element.isSetter) return isSetter;
441 if (element.isGetter) return isGetter || isCall;
442 if (element.isField) {
443 return isSetter
444 ? !element.isFinal && !element.isConst
445 : isGetter || isCall;
446 }
447 if (isGetter) return true;
448 if (isSetter) return false;
449 return signatureApplies(element);
450 }
451
452 bool signatureApplies(FunctionElement function) {
453 FunctionSignature parameters = function.functionSignature;
454 if (argumentCount > parameters.parameterCount) return false;
455 int requiredParameterCount = parameters.requiredParameterCount;
456 int optionalParameterCount = parameters.optionalParameterCount;
457 if (positionalArgumentCount < requiredParameterCount) return false;
458
459 if (!parameters.optionalParametersAreNamed) {
460 // We have already checked that the number of arguments are
461 // not greater than the number of parameters. Therefore the
462 // number of positional arguments are not greater than the
463 // number of parameters.
464 assert(positionalArgumentCount <= parameters.parameterCount);
465 return namedArguments.isEmpty;
466 } else {
467 if (positionalArgumentCount > requiredParameterCount) return false;
468 assert(positionalArgumentCount == requiredParameterCount);
469 if (namedArgumentCount > optionalParameterCount) return false;
470 Set<String> nameSet = new Set<String>();
471 parameters.optionalParameters.forEach((Element element) {
472 nameSet.add(element.name);
473 });
474 for (String name in namedArguments) {
475 if (!nameSet.contains(name)) return false;
476 // TODO(5213): By removing from the set we are checking
477 // that we are not passing the name twice. We should have this
478 // check in the resolver also.
479 nameSet.remove(name);
480 }
481 return true;
482 }
483 }
484
485 bool sameNameHack(Element element, World world) {
486 // TODO(ngeoffray): Remove workaround checks.
487 return element.isConstructor ||
488 name == element.name ||
489 name == 'assert' && world.isAssertMethod(element);
490 }
491
492 bool applies(Element element, World world) {
493 if (!sameNameHack(element, world)) return false;
494 return appliesUnnamed(element, world);
495 }
496
497 /**
498 * Fills [list] with the arguments in the normalized order.
499 *
500 * [compileArgument] is a function that returns a compiled version
501 * of an argument located in [arguments].
502 *
503 * [compileDefaultValue] is a function that returns a compiled constant
504 * of an optional argument that is not in [arguments].
505 *
506 * Returns [:true:] if the selector and the [element] match; [:false:]
507 * otherwise.
508 *
509 * Invariant: [element] must be the implementation element.
510 */
511 /*<T>*/ bool addArgumentsToList(
512 Link<Node> arguments,
513 List/*<T>*/ list,
514 FunctionElement element,
515 /*T*/ compileArgument(Node argument),
516 /*T*/ compileDefaultValue(ParameterElement element),
517 World world) {
518 assert(invariant(element, element.isImplementation));
519 if (!this.applies(element, world)) return false;
520
521 FunctionSignature parameters = element.functionSignature;
522 parameters.forEachRequiredParameter((ParameterElement element) {
523 list.add(compileArgument(arguments.head));
524 arguments = arguments.tail;
525 });
526
527 if (!parameters.optionalParametersAreNamed) {
528 parameters.forEachOptionalParameter((ParameterElement element) {
529 if (!arguments.isEmpty) {
530 list.add(compileArgument(arguments.head));
531 arguments = arguments.tail;
532 } else {
533 list.add(compileDefaultValue(element));
534 }
535 });
536 } else {
537 // Visit named arguments and add them into a temporary list.
538 List compiledNamedArguments = [];
539 for (; !arguments.isEmpty; arguments = arguments.tail) {
540 NamedArgument namedArgument = arguments.head;
541 compiledNamedArguments.add(compileArgument(namedArgument.expression));
542 }
543 // Iterate over the optional parameters of the signature, and try to
544 // find them in [compiledNamedArguments]. If found, we use the
545 // value in the temporary list, otherwise the default value.
546 parameters.orderedOptionalParameters.forEach((ParameterElement element) {
547 int foundIndex = namedArguments.indexOf(element.name);
548 if (foundIndex != -1) {
549 list.add(compiledNamedArguments[foundIndex]);
550 } else {
551 list.add(compileDefaultValue(element));
552 }
553 });
554 }
555 return true;
556 }
557
558 /**
559 * Fills [list] with the arguments in the order expected by
560 * [callee], and where [caller] is a synthesized element
561 *
562 * [compileArgument] is a function that returns a compiled version
563 * of a parameter of [callee].
564 *
565 * [compileConstant] is a function that returns a compiled constant
566 * of an optional argument that is not in the parameters of [callee].
567 *
568 * Returns [:true:] if the signature of the [caller] matches the
569 * signature of the [callee], [:false:] otherwise.
570 */
571 static bool addForwardingElementArgumentsToList(
572 FunctionElement caller,
573 List list,
574 FunctionElement callee,
575 compileArgument(Element element),
576 compileConstant(Element element),
577 World world) {
578
579 FunctionSignature signature = caller.functionSignature;
580 Map mapping = new Map();
581
582 // TODO(ngeoffray): This is a hack that fakes up AST nodes, so
583 // that we can call [addArgumentsToList].
584 Link computeCallNodesFromParameters() {
585 LinkBuilder builder = new LinkBuilder();
586 signature.forEachRequiredParameter((ParameterElement element) {
587 Node node = element.node;
588 mapping[node] = element;
589 builder.addLast(node);
590 });
591 if (signature.optionalParametersAreNamed) {
592 signature.forEachOptionalParameter((ParameterElement element) {
593 mapping[element.initializer] = element;
594 builder.addLast(new NamedArgument(null, null, element.initializer));
595 });
596 } else {
597 signature.forEachOptionalParameter((ParameterElement element) {
598 Node node = element.node;
599 mapping[node] = element;
600 builder.addLast(node);
601 });
602 }
603 return builder.toLink();
604 }
605
606 internalCompileArgument(Node node) {
607 return compileArgument(mapping[node]);
608 }
609
610 Link<Node> nodes = computeCallNodesFromParameters();
611
612 // Synthesize a selector for the call.
613 // TODO(ngeoffray): Should the resolver do it instead?
614 List<String> namedParameters;
615 if (signature.optionalParametersAreNamed) {
616 namedParameters =
617 signature.optionalParameters.mapToList((e) => e.name);
618 }
619 Selector selector = new Selector.call(callee.name,
620 caller.library,
621 signature.parameterCount,
622 namedParameters);
623
624 return selector.addArgumentsToList(nodes,
625 list,
626 callee,
627 internalCompileArgument,
628 compileConstant,
629 world);
630 }
631
632 static bool sameNames(List<String> first, List<String> second) {
633 for (int i = 0; i < first.length; i++) {
634 if (first[i] != second[i]) return false;
635 }
636 return true;
637 }
638
639 bool match(SelectorKind kind,
640 String name,
641 LibraryElement library,
642 int argumentCount,
643 List<String> namedArguments) {
644 return this.kind == kind
645 && this.name == name
646 && identical(this.library, library)
647 && this.argumentCount == argumentCount
648 && this.namedArguments.length == namedArguments.length
649 && sameNames(this.namedArguments, namedArguments);
650 }
651
652 static int computeHashCode(SelectorKind kind,
653 String name,
654 LibraryElement library,
655 int argumentCount,
656 List<String> namedArguments) {
657 // Add bits from name and kind.
658 int hash = mixHashCodeBits(name.hashCode, kind.hashCode);
659 // Add bits from the library.
660 if (library != null) hash = mixHashCodeBits(hash, library.hashCode);
661 // Add bits from the unnamed arguments.
662 hash = mixHashCodeBits(hash, argumentCount);
663 // Add bits from the named arguments.
664 int named = namedArguments.length;
665 hash = mixHashCodeBits(hash, named);
666 for (int i = 0; i < named; i++) {
667 hash = mixHashCodeBits(hash, namedArguments[i].hashCode);
668 }
669 return hash;
670 }
671
672 // TODO(kasperl): Move this out so it becomes useful in other places too?
673 static int mixHashCodeBits(int existing, int value) {
674 // Spread the bits of value. Try to stay in the 30-bit range to
675 // avoid overflowing into a more expensive integer representation.
676 int h = value & 0x1fffffff;
677 h += ((h & 0x3fff) << 15) ^ 0x1fffcd7d;
678 h ^= (h >> 10);
679 h += ((h & 0x3ffffff) << 3);
680 h ^= (h >> 6);
681 h += ((h & 0x7ffffff) << 2) + ((h & 0x7fff) << 14);
682 h ^= (h >> 16);
683 // Combine the two hash values.
684 int high = existing >> 15;
685 int low = existing & 0x7fff;
686 return ((high * 13) ^ (low * 997) ^ h) & SMI_MASK;
687 }
688
689 List<String> getOrderedNamedArguments() {
690 if (namedArguments.isEmpty) return namedArguments;
691 if (!_orderedNamedArguments.isEmpty) return _orderedNamedArguments;
692
693 _orderedNamedArguments.addAll(namedArguments);
694 _orderedNamedArguments.sort((String first, String second) {
695 return first.compareTo(second);
696 });
697 return _orderedNamedArguments;
698 }
699
700 String namedArgumentsToString() {
701 if (namedArgumentCount > 0) {
702 StringBuffer result = new StringBuffer();
703 for (int i = 0; i < namedArgumentCount; i++) {
704 if (i != 0) result.write(', ');
705 result.write(namedArguments[i]);
706 }
707 return "[$result]";
708 }
709 return '';
710 }
711
712 String toString() {
713 String named = '';
714 String type = '';
715 if (namedArgumentCount > 0) named = ', named=${namedArgumentsToString()}';
716 if (mask != null) type = ', mask=$mask';
717 return 'Selector($kind, $name, '
718 'arity=$argumentCount$named$type)';
719 }
720
721 Selector extendIfReachesAll(Compiler compiler) {
722 return new TypedSelector(
723 compiler.typesTask.dynamicType, this, compiler.world);
724 }
725
726 Selector toCallSelector() => new Selector.callClosureFrom(this);
727 }
728
729 class TypedSelector extends Selector {
730 final Selector asUntyped;
731 final TypeMask mask;
732
733 TypedSelector.internal(this.mask, Selector selector, int hashCode)
734 : asUntyped = selector,
735 super.internal(selector.kind,
736 selector.name,
737 selector.library,
738 selector.argumentCount,
739 selector.namedArguments,
740 selector._orderedNamedArguments,
741 hashCode) {
742 assert(mask != null);
743 assert(asUntyped.mask == null);
744 }
745
746 static Map<Selector, Map<TypeMask, TypedSelector>> canonicalizedValues =
747 new Map<Selector, Map<TypeMask, TypedSelector>>();
748
749 factory TypedSelector(TypeMask mask, Selector selector, World world) {
750 // TODO(johnniwinther): Allow more TypeSelector kinds during resoluton.
751 assert(world.isClosed || mask.isExact);
752 if (selector.mask == mask) return selector;
753 Selector untyped = selector.asUntyped;
754 Map<TypeMask, TypedSelector> map = canonicalizedValues.putIfAbsent(untyped,
755 () => new Map<TypeMask, TypedSelector>());
756 TypedSelector result = map[mask];
757 if (result == null) {
758 int hashCode = Selector.mixHashCodeBits(untyped.hashCode, mask.hashCode);
759 result = map[mask] = new TypedSelector.internal(mask, untyped, hashCode);
760 }
761 return result;
762 }
763
764 factory TypedSelector.exact(
765 ClassElement base, Selector selector, World world)
766 => new TypedSelector(new TypeMask.exact(base, world), selector,
767 world);
768
769 factory TypedSelector.subclass(
770 ClassElement base, Selector selector, World world)
771 => new TypedSelector(new TypeMask.subclass(base, world),
772 selector, world);
773
774 factory TypedSelector.subtype(
775 ClassElement base, Selector selector, World world)
776 => new TypedSelector(new TypeMask.subtype(base, world),
777 selector, world);
778
779 bool appliesUnnamed(Element element, World world) {
780 assert(sameNameHack(element, world));
781 // [TypedSelector] are only used after resolution.
782 if (!element.isClassMember) return false;
783
784 // A closure can be called through any typed selector:
785 // class A {
786 // get foo => () => 42;
787 // bar() => foo(); // The call to 'foo' is a typed selector.
788 // }
789 if (element.enclosingClass.isClosure) {
790 return appliesUntyped(element, world);
791 }
792
793 if (!mask.canHit(element, this, world)) return false;
794 return appliesUntyped(element, world);
795 }
796
797 Selector extendIfReachesAll(Compiler compiler) {
798 bool canReachAll = compiler.enabledInvokeOn
799 && mask.needsNoSuchMethodHandling(this, compiler.world);
800 return canReachAll
801 ? new TypedSelector(
802 compiler.typesTask.dynamicType, this, compiler.world)
803 : this;
804 }
805 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698