OLD | NEW |
| (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 } | |
OLD | NEW |