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

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

Issue 1062913003: Extract CallStructure from Selector. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 8 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 | Annotate | Revision Log
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 '../elements/elements.dart'; 7 import '../elements/elements.dart';
8 import '../dart2jslib.dart'; 8 import '../dart2jslib.dart';
9 import '../dart_types.dart'; 9 import '../dart_types.dart';
10 import '../types/types.dart'; 10 import '../types/types.dart';
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
221 221
222 static const SelectorKind GETTER = const SelectorKind('getter', 0); 222 static const SelectorKind GETTER = const SelectorKind('getter', 0);
223 static const SelectorKind SETTER = const SelectorKind('setter', 1); 223 static const SelectorKind SETTER = const SelectorKind('setter', 1);
224 static const SelectorKind CALL = const SelectorKind('call', 2); 224 static const SelectorKind CALL = const SelectorKind('call', 2);
225 static const SelectorKind OPERATOR = const SelectorKind('operator', 3); 225 static const SelectorKind OPERATOR = const SelectorKind('operator', 3);
226 static const SelectorKind INDEX = const SelectorKind('index', 4); 226 static const SelectorKind INDEX = const SelectorKind('index', 4);
227 227
228 String toString() => name; 228 String toString() => name;
229 } 229 }
230 230
231 class Selector { 231 /// The structure of the arguments at a call-site.
232 final SelectorKind kind; 232 // TODO(johnniwinther): Should these be cached?
233 final String name; 233 // TODO(johnniwinther): Should isGetter/isSetter be part of the call structure
234 final LibraryElement library; // Library is null for non-private selectors. 234 // instead of the selector?
235 class CallStructure {
236 static const CallStructure NO_ARGS = const CallStructure.unnamed(0);
237 static const CallStructure ONE_ARG = const CallStructure.unnamed(1);
238 static const CallStructure TWO_ARGS = const CallStructure.unnamed(2);
235 239
236 // The numbers of arguments of the selector. Includes named arguments. 240 /// The numbers of arguments of the call. Includes named arguments.
237 final int argumentCount; 241 final int argumentCount;
238 final List<String> namedArguments;
239 final List<String> _orderedNamedArguments;
240 final int hashCode;
241 242
242 static const String INDEX_NAME ="[]"; 243 /// The number of named arguments of the call.
243 static const String INDEX_SET_NAME = "[]="; 244 int get namedArgumentCount => 0;
244 static const String CALL_NAME = Compiler.CALL_OPERATOR_NAME;
245 245
246 Selector.internal(this.kind, 246 /// The number of positional argument of the call.
247 this.name, 247 int get positionalArgumentCount => argumentCount;
248 this.library, 248
249 this.argumentCount, 249 const CallStructure.unnamed(this.argumentCount);
250 this.namedArguments, 250
251 this._orderedNamedArguments, 251 factory CallStructure(int argumentCount, [List<String> namedArguments]) {
252 this.hashCode) { 252 if (namedArguments == null || namedArguments.isEmpty) {
253 assert(kind == SelectorKind.INDEX 253 return new CallStructure.unnamed(argumentCount);
254 || (name != INDEX_NAME && name != INDEX_SET_NAME)); 254 }
255 assert(kind == SelectorKind.OPERATOR 255 return new NamedCallStructure(argumentCount, namedArguments);
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 } 256 }
264 257
265 static Map<int, List<Selector>> canonicalizedValues = 258 /// `true` if this call has named arguments.
266 new Map<int, List<Selector>>(); 259 bool get isNamed => false;
267 260
268 factory Selector(SelectorKind kind, 261 /// `true` if this call has no named arguments.
269 String name, 262 bool get isUnnamed => true;
270 LibraryElement library, 263
271 int argumentCount, 264 /// The names of the named arguments in call-site order.
272 [List<String> namedArguments]) { 265 List<String> get namedArguments => const <String>[];
273 if (!isPrivateName(name)) library = null; 266
274 if (namedArguments == null) namedArguments = const <String>[]; 267 /// The names of the named arguments in canonicalized order.
275 int hashCode = computeHashCode( 268 List<String> getOrderedNamedArguments() => const <String>[];
276 kind, name, library, argumentCount, namedArguments); 269
277 List<Selector> list = canonicalizedValues.putIfAbsent(hashCode, 270 /// A description of the argument structure.
278 () => <Selector>[]); 271 String structureToString() => 'arity=$argumentCount';
279 for (int i = 0; i < list.length; i++) { 272
280 Selector existing = list[i]; 273 String toString() => 'CallStructure(${structureToString()})';
281 if (existing.match(kind, name, library, argumentCount, namedArguments)) { 274
282 assert(existing.hashCode == hashCode); 275 Selector get callSelector {
283 assert(existing.mask == null); 276 return new Selector(SelectorKind.CALL, Selector.CALL_NAME, this);
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 } 277 }
297 278
298 factory Selector.fromElement(Element element) { 279 bool match(CallStructure other) {
299 String name = element.name; 280 if (identical(this, other)) return true;
300 if (element.isFunction) { 281 return this.argumentCount == other.argumentCount
301 if (name == '[]') { 282 && this.namedArgumentCount == other.namedArgumentCount
302 return new Selector.index(); 283 && sameNames(this.namedArguments, other.namedArguments);
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 if (element.isConstructor) {
330 return new Selector.callConstructor(name, element.library);
331 } else {
332 throw new SpannableAssertionFailure(
333 element, "Can't get selector from $element");
334 }
335 } 284 }
336 285
337 factory Selector.getter(String name, LibraryElement library) 286 // TODO(johnniwinther): Cache hash code?
338 => new Selector(SelectorKind.GETTER, name, library, 0); 287 int get hashCode {
339 288 int named = namedArguments.length;
340 factory Selector.getterFrom(Selector selector) 289 int hash = mixHashCodeBits(argumentCount, named);
341 => new Selector(SelectorKind.GETTER, selector.name, selector.library, 0); 290 for (int i = 0; i < named; i++) {
342 291 hash = mixHashCodeBits(hash, namedArguments[i].hashCode);
343 factory Selector.setter(String name, LibraryElement library) 292 }
344 => new Selector(SelectorKind.SETTER, name, library, 1); 293 return hash;
345
346 factory Selector.unaryOperator(String name)
347 => new Selector(SelectorKind.OPERATOR,
348 Elements.constructOperatorName(name, true),
349 null, 0);
350
351 factory Selector.binaryOperator(String name)
352 => new Selector(SelectorKind.OPERATOR,
353 Elements.constructOperatorName(name, false),
354 null, 1);
355
356 factory Selector.index()
357 => new Selector(SelectorKind.INDEX,
358 Elements.constructOperatorName(INDEX_NAME, false),
359 null, 1);
360
361 factory Selector.indexSet()
362 => new Selector(SelectorKind.INDEX,
363 Elements.constructOperatorName(INDEX_SET_NAME, false),
364 null, 2);
365
366 factory Selector.call(String name,
367 LibraryElement library,
368 int arity,
369 [List<String> namedArguments])
370 => new Selector(SelectorKind.CALL, name, library, arity, namedArguments);
371
372 factory Selector.callClosure(int arity, [List<String> namedArguments])
373 => new Selector(SelectorKind.CALL, CALL_NAME, null,
374 arity, namedArguments);
375
376 factory Selector.callClosureFrom(Selector selector)
377 => new Selector(SelectorKind.CALL, CALL_NAME, null,
378 selector.argumentCount, selector.namedArguments);
379
380 factory Selector.callConstructor(String name, LibraryElement library,
381 [int arity = 0,
382 List<String> namedArguments])
383 => new Selector(SelectorKind.CALL, name, library,
384 arity, namedArguments);
385
386 factory Selector.callDefaultConstructor()
387 => new Selector(SelectorKind.CALL, "", null, 0);
388
389 bool get isGetter => identical(kind, SelectorKind.GETTER);
390 bool get isSetter => identical(kind, SelectorKind.SETTER);
391 bool get isCall => identical(kind, SelectorKind.CALL);
392 bool get isClosureCall {
393 String callName = Compiler.CALL_OPERATOR_NAME;
394 return isCall && name == callName;
395 } 294 }
396 295
397 bool get isIndex => identical(kind, SelectorKind.INDEX) && argumentCount == 1; 296 bool operator ==(other) {
398 bool get isIndexSet => identical(kind, SelectorKind.INDEX) && argumentCount == 2; 297 if (other is! CallStructure) return false;
399 298 return match(other);
400 bool get isOperator => identical(kind, SelectorKind.OPERATOR);
401 bool get isUnaryOperator => isOperator && argumentCount == 0;
402
403 /** Check whether this is a call to 'assert'. */
404 bool get isAssert => isCall && identical(name, "assert");
405
406 int get namedArgumentCount => namedArguments.length;
407 int get positionalArgumentCount => argumentCount - namedArgumentCount;
408
409 bool get hasExactMask => false;
410 TypeMask get mask => null;
411 Selector get asUntyped => this;
412
413 /**
414 * The member name for invocation mirrors created from this selector.
415 */
416 String get invocationMirrorMemberName =>
417 isSetter ? '$name=' : name;
418
419 int get invocationMirrorKind {
420 const int METHOD = 0;
421 const int GETTER = 1;
422 const int SETTER = 2;
423 int kind = METHOD;
424 if (isGetter) {
425 kind = GETTER;
426 } else if (isSetter) {
427 kind = SETTER;
428 }
429 return kind;
430 }
431
432 bool appliesUnnamed(Element element, World world) {
433 assert(sameNameHack(element, world));
434 return appliesUntyped(element, world);
435 }
436
437 bool appliesUntyped(Element element, World world) {
438 assert(sameNameHack(element, world));
439 if (Elements.isUnresolved(element)) return false;
440 if (isPrivateName(name) && library != element.library) return false;
441 if (world.isForeign(element)) return true;
442 if (element.isSetter) return isSetter;
443 if (element.isGetter) return isGetter || isCall;
444 if (element.isField) {
445 return isSetter
446 ? !element.isFinal && !element.isConst
447 : isGetter || isCall;
448 }
449 if (isGetter) return true;
450 if (isSetter) return false;
451 return signatureApplies(element);
452 } 299 }
453 300
454 bool signatureApplies(FunctionElement function) { 301 bool signatureApplies(FunctionElement function) {
302 if (Elements.isUnresolved(function)) return false;
455 FunctionSignature parameters = function.functionSignature; 303 FunctionSignature parameters = function.functionSignature;
456 if (argumentCount > parameters.parameterCount) return false; 304 if (argumentCount > parameters.parameterCount) return false;
457 int requiredParameterCount = parameters.requiredParameterCount; 305 int requiredParameterCount = parameters.requiredParameterCount;
458 int optionalParameterCount = parameters.optionalParameterCount; 306 int optionalParameterCount = parameters.optionalParameterCount;
459 if (positionalArgumentCount < requiredParameterCount) return false; 307 if (positionalArgumentCount < requiredParameterCount) return false;
460 308
461 if (!parameters.optionalParametersAreNamed) { 309 if (!parameters.optionalParametersAreNamed) {
462 // We have already checked that the number of arguments are 310 // We have already checked that the number of arguments are
463 // not greater than the number of parameters. Therefore the 311 // not greater than the number of parameters. Therefore the
464 // number of positional arguments are not greater than the 312 // number of positional arguments are not greater than the
(...skipping 12 matching lines...) Expand all
477 if (!nameSet.contains(name)) return false; 325 if (!nameSet.contains(name)) return false;
478 // TODO(5213): By removing from the set we are checking 326 // TODO(5213): By removing from the set we are checking
479 // that we are not passing the name twice. We should have this 327 // that we are not passing the name twice. We should have this
480 // check in the resolver also. 328 // check in the resolver also.
481 nameSet.remove(name); 329 nameSet.remove(name);
482 } 330 }
483 return true; 331 return true;
484 } 332 }
485 } 333 }
486 334
487 bool sameNameHack(Element element, World world) {
488 // TODO(ngeoffray): Remove workaround checks.
489 return element.isConstructor ||
490 name == element.name ||
491 name == 'assert' && world.isAssertMethod(element);
492 }
493
494 bool applies(Element element, World world) {
495 if (!sameNameHack(element, world)) return false;
496 return appliesUnnamed(element, world);
497 }
498
499 /** 335 /**
500 * Returns a `List` with the evaluated arguments in the normalized order. 336 * Returns a `List` with the evaluated arguments in the normalized order.
501 * 337 *
502 * [compileDefaultValue] is a function that returns a compiled constant 338 * [compileDefaultValue] is a function that returns a compiled constant
503 * of an optional argument that is not in [compiledArguments]. 339 * of an optional argument that is not in [compiledArguments].
504 * 340 *
505 * Precondition: `this.applies(element, world)`. 341 * Precondition: `this.applies(element, world)`.
506 * 342 *
507 * Invariant: [element] must be the implementation element. 343 * Invariant: [element] must be the implementation element.
508 */ 344 */
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
557 * 393 *
558 * [compileArgument] is a function that returns a compiled version 394 * [compileArgument] is a function that returns a compiled version
559 * of a parameter of [callee]. 395 * of a parameter of [callee].
560 * 396 *
561 * [compileConstant] is a function that returns a compiled constant 397 * [compileConstant] is a function that returns a compiled constant
562 * of an optional argument that is not in the parameters of [callee]. 398 * of an optional argument that is not in the parameters of [callee].
563 * 399 *
564 * Returns [:true:] if the signature of the [caller] matches the 400 * Returns [:true:] if the signature of the [caller] matches the
565 * signature of the [callee], [:false:] otherwise. 401 * signature of the [callee], [:false:] otherwise.
566 */ 402 */
567 static bool addForwardingElementArgumentsToList( 403 static /*<T>*/ bool addForwardingElementArgumentsToList(
568 FunctionElement caller, 404 ConstructorElement caller,
569 List list, 405 List/*<T>*/ list,
570 FunctionElement callee, 406 ConstructorElement callee,
571 compileArgument(Element element), 407 /*T*/ compileArgument(ParameterElement element),
572 compileConstant(Element element), 408 /*T*/ compileConstant(ParameterElement element)) {
573 World world) {
574 409
575 FunctionSignature signature = caller.functionSignature; 410 FunctionSignature signature = caller.functionSignature;
576 Map mapping = new Map(); 411 Map<Node, ParameterElement> mapping = <Node, ParameterElement>{};
577 412
578 // TODO(ngeoffray): This is a hack that fakes up AST nodes, so 413 // TODO(ngeoffray): This is a hack that fakes up AST nodes, so
579 // that we can call [addArgumentsToList]. 414 // that we can call [addArgumentsToList].
580 Link computeCallNodesFromParameters() { 415 Link<Node> computeCallNodesFromParameters() {
581 LinkBuilder builder = new LinkBuilder(); 416 LinkBuilder<Node> builder = new LinkBuilder<Node>();
582 signature.forEachRequiredParameter((ParameterElement element) { 417 signature.forEachRequiredParameter((ParameterElement element) {
583 Node node = element.node; 418 Node node = element.node;
584 mapping[node] = element; 419 mapping[node] = element;
585 builder.addLast(node); 420 builder.addLast(node);
586 }); 421 });
587 if (signature.optionalParametersAreNamed) { 422 if (signature.optionalParametersAreNamed) {
588 signature.forEachOptionalParameter((ParameterElement element) { 423 signature.forEachOptionalParameter((ParameterElement element) {
589 mapping[element.initializer] = element; 424 mapping[element.initializer] = element;
590 builder.addLast(new NamedArgument(null, null, element.initializer)); 425 builder.addLast(new NamedArgument(null, null, element.initializer));
591 }); 426 });
592 } else { 427 } else {
593 signature.forEachOptionalParameter((ParameterElement element) { 428 signature.forEachOptionalParameter((ParameterElement element) {
594 Node node = element.node; 429 Node node = element.node;
595 mapping[node] = element; 430 mapping[node] = element;
596 builder.addLast(node); 431 builder.addLast(node);
597 }); 432 });
598 } 433 }
599 return builder.toLink(); 434 return builder.toLink();
600 } 435 }
601 436
602 internalCompileArgument(Node node) { 437 /*T*/ internalCompileArgument(Node node) {
603 return compileArgument(mapping[node]); 438 return compileArgument(mapping[node]);
604 } 439 }
605 440
606 Link<Node> nodes = computeCallNodesFromParameters(); 441 Link<Node> nodes = computeCallNodesFromParameters();
607 442
608 // Synthesize a selector for the call. 443 // Synthesize a structure for the call.
609 // TODO(ngeoffray): Should the resolver do it instead? 444 // TODO(ngeoffray): Should the resolver do it instead?
610 List<String> namedParameters; 445 List<String> namedParameters;
611 if (signature.optionalParametersAreNamed) { 446 if (signature.optionalParametersAreNamed) {
612 namedParameters = 447 namedParameters = signature.optionalParameters.mapToList((e) => e.name);
613 signature.optionalParameters.mapToList((e) => e.name);
614 } 448 }
615 Selector selector = new Selector.call(callee.name, 449 CallStructure callStructure =
616 caller.library, 450 new CallStructure(signature.parameterCount, namedParameters);
617 signature.parameterCount, 451 if (!callStructure.signatureApplies(callee)) {
618 namedParameters); 452 return false;
619 453 }
620 if (!selector.applies(callee, world)) return false; 454 list.addAll(callStructure.makeArgumentsList(
621 list.addAll(selector.makeArgumentsList(nodes, 455 nodes,
622 callee, 456 callee,
623 internalCompileArgument, 457 internalCompileArgument,
624 compileConstant)); 458 compileConstant));
625 459
626 return true; 460 return true;
627 } 461 }
628 462
629 static bool sameNames(List<String> first, List<String> second) { 463 static bool sameNames(List<String> first, List<String> second) {
630 for (int i = 0; i < first.length; i++) { 464 for (int i = 0; i < first.length; i++) {
631 if (first[i] != second[i]) return false; 465 if (first[i] != second[i]) return false;
632 } 466 }
633 return true; 467 return true;
634 } 468 }
469 }
635 470
636 bool match(SelectorKind kind, 471 ///
637 String name, 472 class NamedCallStructure extends CallStructure {
638 LibraryElement library, 473 final List<String> namedArguments;
639 int argumentCount, 474 final List<String> _orderedNamedArguments = <String>[];
640 List<String> namedArguments) { 475
641 return this.kind == kind 476 NamedCallStructure(int argumentCount, this.namedArguments)
642 && this.name == name 477 : super.unnamed(argumentCount) {
643 && identical(this.library, library) 478 assert(namedArguments.isNotEmpty);
644 && this.argumentCount == argumentCount
645 && this.namedArguments.length == namedArguments.length
646 && sameNames(this.namedArguments, namedArguments);
647 } 479 }
648 480
649 static int computeHashCode(SelectorKind kind, 481 @override
650 String name, 482 bool get isNamed => true;
651 LibraryElement library,
652 int argumentCount,
653 List<String> namedArguments) {
654 // Add bits from name and kind.
655 int hash = mixHashCodeBits(name.hashCode, kind.hashCode);
656 // Add bits from the library.
657 if (library != null) hash = mixHashCodeBits(hash, library.hashCode);
658 // Add bits from the unnamed arguments.
659 hash = mixHashCodeBits(hash, argumentCount);
660 // Add bits from the named arguments.
661 int named = namedArguments.length;
662 hash = mixHashCodeBits(hash, named);
663 for (int i = 0; i < named; i++) {
664 hash = mixHashCodeBits(hash, namedArguments[i].hashCode);
665 }
666 return hash;
667 }
668 483
669 // TODO(kasperl): Move this out so it becomes useful in other places too? 484 @override
670 static int mixHashCodeBits(int existing, int value) { 485 bool get isUnnamed => false;
671 // Spread the bits of value. Try to stay in the 30-bit range to
672 // avoid overflowing into a more expensive integer representation.
673 int h = value & 0x1fffffff;
674 h += ((h & 0x3fff) << 15) ^ 0x1fffcd7d;
675 h ^= (h >> 10);
676 h += ((h & 0x3ffffff) << 3);
677 h ^= (h >> 6);
678 h += ((h & 0x7ffffff) << 2) + ((h & 0x7fff) << 14);
679 h ^= (h >> 16);
680 // Combine the two hash values.
681 int high = existing >> 15;
682 int low = existing & 0x7fff;
683 return ((high * 13) ^ (low * 997) ^ h) & SMI_MASK;
684 }
685 486
487 @override
488 int get namedArgumentCount => namedArguments.length;
489
490 @override
491 int get positionalArgumentCount => argumentCount - namedArgumentCount;
492
493 @override
686 List<String> getOrderedNamedArguments() { 494 List<String> getOrderedNamedArguments() {
687 if (namedArguments.isEmpty) return namedArguments;
688 if (!_orderedNamedArguments.isEmpty) return _orderedNamedArguments; 495 if (!_orderedNamedArguments.isEmpty) return _orderedNamedArguments;
689 496
690 _orderedNamedArguments.addAll(namedArguments); 497 _orderedNamedArguments.addAll(namedArguments);
691 _orderedNamedArguments.sort((String first, String second) { 498 _orderedNamedArguments.sort((String first, String second) {
692 return first.compareTo(second); 499 return first.compareTo(second);
693 }); 500 });
694 return _orderedNamedArguments; 501 return _orderedNamedArguments;
695 } 502 }
696 503
697 String namedArgumentsToString() { 504 @override
698 if (namedArgumentCount > 0) { 505 String structureToString() {
699 StringBuffer result = new StringBuffer(); 506 return 'arity=$argumentCount, named=[${namedArguments.join(', ')}]';
700 for (int i = 0; i < namedArgumentCount; i++) { 507 }
701 if (i != 0) result.write(', '); 508 }
702 result.write(namedArguments[i]); 509
703 } 510 class Selector {
704 return "[$result]"; 511 final SelectorKind kind;
705 } 512 final Name memberName;
706 return ''; 513 final CallStructure callStructure;
514
515 final int hashCode;
516
517 int get argumentCount => callStructure.argumentCount;
518 int get namedArgumentCount => callStructure.namedArgumentCount;
519 int get positionalArgumentCount => callStructure.positionalArgumentCount;
520 List<String> get namedArguments => callStructure.namedArguments;
521
522 String get name => memberName.text;
523
524 LibraryElement get library => memberName.library;
525
526 static const Name INDEX_NAME = const PublicName("[]");
527 static const Name INDEX_SET_NAME = const PublicName("[]=");
528 static const Name CALL_NAME = const PublicName(Compiler.CALL_OPERATOR_NAME);
529
530 Selector.internal(this.kind,
531 this.memberName,
532 this.callStructure,
533 this.hashCode) {
534 assert(kind == SelectorKind.INDEX ||
535 (memberName != INDEX_NAME && memberName != INDEX_SET_NAME));
536 assert(kind == SelectorKind.OPERATOR ||
537 kind == SelectorKind.INDEX ||
538 !Elements.isOperatorName(memberName.text));
539 assert(kind == SelectorKind.CALL ||
540 kind == SelectorKind.GETTER ||
541 kind == SelectorKind.SETTER ||
542 Elements.isOperatorName(memberName.text));
543 }
544
545 static Map<int, List<Selector>> canonicalizedValues =
floitsch 2015/04/07 14:09:21 To think about: I would like to remove this static
Johnni Winther 2015/04/08 12:25:11 Added a TODO.
546 new Map<int, List<Selector>>();
547
548 factory Selector(SelectorKind kind,
549 Name name,
550 CallStructure callStructure) {
551 int hashCode = computeHashCode(kind, name, callStructure);
552 List<Selector> list = canonicalizedValues.putIfAbsent(hashCode,
floitsch 2015/04/07 14:09:21 Not your code (and not for this CL): I wonder if
Johnni Winther 2015/04/08 12:25:11 Add a TODO.
553 () => <Selector>[]);
554 for (int i = 0; i < list.length; i++) {
555 Selector existing = list[i];
556 if (existing.match(kind, name, callStructure)) {
557 assert(existing.hashCode == hashCode);
558 assert(existing.mask == null);
559 return existing;
560 }
561 }
562 Selector result = new Selector.internal(
563 kind, name, callStructure, hashCode);
564 list.add(result);
565 return result;
566 }
567
568 factory Selector.fromElement(Element element) {
569 String name = element.name;
570 if (element.isFunction) {
571 if (name == '[]') {
572 return new Selector.index();
573 } else if (name == '[]=') {
574 return new Selector.indexSet();
575 }
576 FunctionSignature signature =
577 element.asFunctionElement().functionSignature;
578 int arity = signature.parameterCount;
579 List<String> namedArguments = null;
580 if (signature.optionalParametersAreNamed) {
581 namedArguments =
582 signature.orderedOptionalParameters.map((e) => e.name).toList();
583 }
584 if (element.isOperator) {
585 // Operators cannot have named arguments, however, that doesn't prevent
586 // a user from declaring such an operator.
587 return new Selector(
588 SelectorKind.OPERATOR,
589 new PublicName(name),
590 new CallStructure(arity, namedArguments));
591 } else {
592 return new Selector.call(
593 name, element.library, arity, namedArguments);
594 }
595 } else if (element.isSetter) {
596 return new Selector.setter(name, element.library);
597 } else if (element.isGetter) {
598 return new Selector.getter(name, element.library);
599 } else if (element.isField) {
600 return new Selector.getter(name, element.library);
601 } else if (element.isConstructor) {
602 return new Selector.callConstructor(name, element.library);
603 } else {
604 throw new SpannableAssertionFailure(
605 element, "Can't get selector from $element");
606 }
607 }
608
609 factory Selector.getter(String name, LibraryElement library)
610 => new Selector(SelectorKind.GETTER,
611 new Name(name, library),
612 CallStructure.NO_ARGS);
613
614 factory Selector.getterFrom(Selector selector)
615 => new Selector(SelectorKind.GETTER,
616 selector.memberName,
617 CallStructure.NO_ARGS);
618
619 factory Selector.setter(String name, LibraryElement library)
620 => new Selector(SelectorKind.SETTER,
621 new Name(name, library, isSetter: true),
622 CallStructure.ONE_ARG);
623
624 factory Selector.unaryOperator(String name) => new Selector(
625 SelectorKind.OPERATOR,
626 new PublicName(Elements.constructOperatorName(name, true)),
627 CallStructure.NO_ARGS);
628
629 factory Selector.binaryOperator(String name) => new Selector(
630 SelectorKind.OPERATOR,
631 new PublicName(Elements.constructOperatorName(name, false)),
632 CallStructure.ONE_ARG);
633
634 factory Selector.index()
635 => new Selector(SelectorKind.INDEX, INDEX_NAME,
636 CallStructure.ONE_ARG);
637
638 factory Selector.indexSet()
639 => new Selector(SelectorKind.INDEX, INDEX_SET_NAME,
640 CallStructure.TWO_ARGS);
641
642 factory Selector.call(String name,
643 LibraryElement library,
644 int arity,
645 [List<String> namedArguments])
646 => new Selector(SelectorKind.CALL,
647 new Name(name, library),
648 new CallStructure(arity, namedArguments));
649
650 factory Selector.callClosure(int arity, [List<String> namedArguments])
651 => new Selector(SelectorKind.CALL, CALL_NAME,
652 new CallStructure(arity, namedArguments));
653
654 factory Selector.callClosureFrom(Selector selector)
655 => new Selector(SelectorKind.CALL, CALL_NAME, selector.callStructure);
656
657 factory Selector.callConstructor(String name, LibraryElement library,
658 [int arity = 0,
659 List<String> namedArguments])
660 => new Selector(SelectorKind.CALL, new Name(name, library),
661 new CallStructure(arity, namedArguments));
662
663 factory Selector.callDefaultConstructor()
664 => new Selector(
665 SelectorKind.CALL,
666 const PublicName(''),
667 CallStructure.NO_ARGS);
668
669 bool get isGetter => kind == SelectorKind.GETTER;
670 bool get isSetter => kind == SelectorKind.SETTER;
671 bool get isCall => kind == SelectorKind.CALL;
672 bool get isClosureCall => isCall && memberName == CALL_NAME;
673
674 bool get isIndex => kind == SelectorKind.INDEX && argumentCount == 1;
675 bool get isIndexSet => kind == SelectorKind.INDEX && argumentCount == 2;
676
677 bool get isOperator => kind == SelectorKind.OPERATOR;
678 bool get isUnaryOperator => isOperator && argumentCount == 0;
679
680 /** Check whether this is a call to 'assert'. */
681 bool get isAssert => isCall && identical(name, "assert");
682
683 bool get hasExactMask => false;
684 TypeMask get mask => null;
685 Selector get asUntyped => this;
686
687 /**
688 * The member name for invocation mirrors created from this selector.
689 */
690 String get invocationMirrorMemberName =>
691 isSetter ? '$name=' : name;
692
693 int get invocationMirrorKind {
694 const int METHOD = 0;
695 const int GETTER = 1;
696 const int SETTER = 2;
697 int kind = METHOD;
698 if (isGetter) {
699 kind = GETTER;
700 } else if (isSetter) {
701 kind = SETTER;
702 }
703 return kind;
704 }
705
706 bool appliesUnnamed(Element element, World world) {
707 assert(sameNameHack(element, world));
708 return appliesUntyped(element, world);
709 }
710
711 bool appliesUntyped(Element element, World world) {
712 assert(sameNameHack(element, world));
713 if (Elements.isUnresolved(element)) return false;
714 if (memberName.isPrivate && memberName.library != element.library) {
715 // TODO(johnniwinther): Maybe this should be
716 // `memberName != element.memberName`.
717 return false;
718 }
719 if (world.isForeign(element)) return true;
720 if (element.isSetter) return isSetter;
721 if (element.isGetter) return isGetter || isCall;
722 if (element.isField) {
723 return isSetter
724 ? !element.isFinal && !element.isConst
725 : isGetter || isCall;
726 }
727 if (isGetter) return true;
728 if (isSetter) return false;
729 return signatureApplies(element);
730 }
731
732 bool signatureApplies(FunctionElement function) {
733 return callStructure.signatureApplies(function);
734 }
735
736 bool sameNameHack(Element element, World world) {
737 // TODO(ngeoffray): Remove workaround checks.
738 return element.isConstructor ||
739 name == element.name ||
740 name == 'assert' && world.isAssertMethod(element);
741 }
742
743 bool applies(Element element, World world) {
744 if (!sameNameHack(element, world)) return false;
745 return appliesUnnamed(element, world);
746 }
747
748 bool match(SelectorKind kind,
749 Name memberName,
750 CallStructure callStructure) {
751 return this.kind == kind
752 && this.memberName == memberName
753 && this.callStructure.match(callStructure);
754 }
755
756 static int computeHashCode(SelectorKind kind,
757 Name name,
758 CallStructure callStructure) {
759 // Add bits from name and kind.
760 int hash = mixHashCodeBits(name.hashCode, kind.hashCode);
761 // Add bits from the call structure.
762 return mixHashCodeBits(hash, callStructure.hashCode);
707 } 763 }
708 764
709 String toString() { 765 String toString() {
710 String named = '';
711 String type = ''; 766 String type = '';
712 if (namedArgumentCount > 0) named = ', named=${namedArgumentsToString()}';
713 if (mask != null) type = ', mask=$mask'; 767 if (mask != null) type = ', mask=$mask';
714 return 'Selector($kind, $name, ' 768 return 'Selector($kind, $name, ${callStructure.structureToString()}$type)';
715 'arity=$argumentCount$named$type)';
716 } 769 }
717 770
718 Selector extendIfReachesAll(Compiler compiler) { 771 Selector extendIfReachesAll(Compiler compiler) {
719 return new TypedSelector( 772 return new TypedSelector(
720 compiler.typesTask.dynamicType, this, compiler.world); 773 compiler.typesTask.dynamicType, this, compiler.world);
721 } 774 }
722 775
723 Selector toCallSelector() => new Selector.callClosureFrom(this); 776 Selector toCallSelector() => new Selector.callClosureFrom(this);
724 } 777 }
725 778
726 class TypedSelector extends Selector { 779 class TypedSelector extends Selector {
727 final Selector asUntyped; 780 final Selector asUntyped;
728 final TypeMask mask; 781 final TypeMask mask;
729 782
730 TypedSelector.internal(this.mask, Selector selector, int hashCode) 783 TypedSelector.internal(this.mask, Selector selector, int hashCode)
731 : asUntyped = selector, 784 : asUntyped = selector,
732 super.internal(selector.kind, 785 super.internal(selector.kind,
733 selector.name, 786 selector.memberName,
734 selector.library, 787 selector.callStructure,
735 selector.argumentCount,
736 selector.namedArguments,
737 selector._orderedNamedArguments,
738 hashCode) { 788 hashCode) {
739 assert(mask != null); 789 assert(mask != null);
740 assert(asUntyped.mask == null); 790 assert(asUntyped.mask == null);
741 } 791 }
742 792
743 793
744 factory TypedSelector(TypeMask mask, Selector selector, World world) { 794 factory TypedSelector(TypeMask mask, Selector selector, World world) {
745 if (!world.hasClosedWorldAssumption) { 795 if (!world.hasClosedWorldAssumption) {
746 // TODO(johnniwinther): Improve use of TypedSelector in an open world. 796 // TODO(johnniwinther): Improve use of TypedSelector in an open world.
747 bool isNullable = mask.isNullable; 797 bool isNullable = mask.isNullable;
748 mask = world.compiler.typesTask.dynamicType; 798 mask = world.compiler.typesTask.dynamicType;
749 if (isNullable) { 799 if (isNullable) {
750 mask = mask.nullable(); 800 mask = mask.nullable();
751 } 801 }
752 } 802 }
753 // TODO(johnniwinther): Allow more TypeSelector kinds during resoluton. 803 // TODO(johnniwinther): Allow more TypeSelector kinds during resoluton.
754 assert(world.isClosed || mask.isExact); 804 assert(world.isClosed || mask.isExact);
755 if (selector.mask == mask) return selector; 805 if (selector.mask == mask) return selector;
756 Selector untyped = selector.asUntyped; 806 Selector untyped = selector.asUntyped;
757 Map<TypeMask, TypedSelector> map = world.canonicalizedValues 807 Map<TypeMask, TypedSelector> map = world.canonicalizedValues
758 .putIfAbsent(untyped, () => new Map<TypeMask, TypedSelector>()); 808 .putIfAbsent(untyped, () => new Map<TypeMask, TypedSelector>());
759 TypedSelector result = map[mask]; 809 TypedSelector result = map[mask];
760 if (result == null) { 810 if (result == null) {
761 int hashCode = Selector.mixHashCodeBits(untyped.hashCode, mask.hashCode); 811 int hashCode = mixHashCodeBits(untyped.hashCode, mask.hashCode);
762 result = map[mask] = new TypedSelector.internal(mask, untyped, hashCode); 812 result = map[mask] = new TypedSelector.internal(mask, untyped, hashCode);
763 } 813 }
764 return result; 814 return result;
765 } 815 }
766 816
767 factory TypedSelector.exact( 817 factory TypedSelector.exact(
768 ClassElement base, Selector selector, World world) 818 ClassElement base, Selector selector, World world)
769 => new TypedSelector(new TypeMask.exact(base, world), selector, 819 => new TypedSelector(new TypeMask.exact(base, world), selector,
770 world); 820 world);
771 821
(...skipping 27 matching lines...) Expand all
799 849
800 Selector extendIfReachesAll(Compiler compiler) { 850 Selector extendIfReachesAll(Compiler compiler) {
801 bool canReachAll = compiler.enabledInvokeOn 851 bool canReachAll = compiler.enabledInvokeOn
802 && mask.needsNoSuchMethodHandling(this, compiler.world); 852 && mask.needsNoSuchMethodHandling(this, compiler.world);
803 return canReachAll 853 return canReachAll
804 ? new TypedSelector( 854 ? new TypedSelector(
805 compiler.typesTask.dynamicType, this, compiler.world) 855 compiler.typesTask.dynamicType, this, compiler.world)
806 : this; 856 : this;
807 } 857 }
808 } 858 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart ('k') | pkg/compiler/lib/src/use_unused_api.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698