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

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

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