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

Side by Side Diff: sdk/lib/_internal/compiler/js_lib/js_mirrors.dart

Issue 1212513002: sdk files reorganization to make dart2js a proper package (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: renamed Created 5 years, 5 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
OLDNEW
(Empty)
1 // Copyright (c) 2013, 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 dart._js_mirrors;
6
7 import 'dart:_js_embedded_names' show
8 JsGetName,
9 ALL_CLASSES,
10 LAZIES,
11 LIBRARIES,
12 STATICS,
13 TYPE_INFORMATION,
14 TYPEDEF_PREDICATE_PROPERTY_NAME,
15 TYPEDEF_TYPE_PROPERTY_NAME;
16
17 import 'dart:collection' show
18 UnmodifiableListView,
19 UnmodifiableMapView;
20
21 import 'dart:mirrors';
22
23 import 'dart:_foreign_helper' show
24 JS,
25 JS_GET_FLAG,
26 JS_CURRENT_ISOLATE,
27 JS_CURRENT_ISOLATE_CONTEXT,
28 JS_EMBEDDED_GLOBAL,
29 JS_GET_NAME,
30 JS_TYPEDEF_TAG,
31 JS_FUNCTION_TYPE_RETURN_TYPE_TAG,
32 JS_FUNCTION_TYPE_VOID_RETURN_TAG,
33 JS_FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG,
34 JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG,
35 JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG;
36
37
38 import 'dart:_internal' as _symbol_dev;
39
40 import 'dart:_js_helper' show
41 BoundClosure,
42 CachedInvocation,
43 Closure,
44 JSInvocationMirror,
45 JsCache,
46 Null,
47 Primitives,
48 ReflectionInfo,
49 RuntimeError,
50 TearOffClosure,
51 TypeVariable,
52 UnimplementedNoSuchMethodError,
53 createRuntimeType,
54 createUnmangledInvocationMirror,
55 getMangledTypeName,
56 getMetadata,
57 getType,
58 getRuntimeType,
59 isDartFunctionType,
60 runtimeTypeToString,
61 setRuntimeTypeInfo,
62 throwInvalidReflectionError,
63 TypeImpl,
64 deferredLoadHook;
65
66 import 'dart:_interceptors' show
67 Interceptor,
68 JSArray,
69 JSExtendableArray,
70 getInterceptor;
71
72 import 'dart:_js_names';
73
74 const String METHODS_WITH_OPTIONAL_ARGUMENTS = r'$methodsWithOptionalArguments';
75
76 bool hasReflectableProperty(var jsFunction) {
77 return JS('bool', '# in #', JS_GET_NAME(JsGetName.REFLECTABLE), jsFunction);
78 }
79
80 /// No-op method that is called to inform the compiler that tree-shaking needs
81 /// to be disabled.
82 disableTreeShaking() => preserveNames();
83
84 /// No-op method that is called to inform the compiler that metadata must be
85 /// preserved at runtime.
86 preserveMetadata() {}
87
88 /// No-op method that is called to inform the compiler that the compiler must
89 /// preserve the URIs.
90 preserveUris() {}
91
92 /// No-op method that is called to inform the compiler that the compiler must
93 /// preserve the library names.
94 preserveLibraryNames() {}
95
96 String getName(Symbol symbol) {
97 preserveNames();
98 return n(symbol);
99 }
100
101 class JsMirrorSystem implements MirrorSystem {
102 UnmodifiableMapView<Uri, LibraryMirror> _cachedLibraries;
103
104 final IsolateMirror isolate = new JsIsolateMirror();
105
106 JsTypeMirror get dynamicType => _dynamicType;
107 JsTypeMirror get voidType => _voidType;
108
109 static final JsTypeMirror _dynamicType =
110 new JsTypeMirror(const Symbol('dynamic'));
111 static final JsTypeMirror _voidType = new JsTypeMirror(const Symbol('void'));
112
113 static Map<String, List<LibraryMirror>> _librariesByName;
114
115 // Will be set to `true` when we have installed a hook on [deferredLoadHook]
116 // to avoid installing it multiple times.
117 static bool _hasInstalledDeferredLoadHook = false;
118
119 static Map<String, List<LibraryMirror>> get librariesByName {
120 if (_librariesByName == null) {
121 _librariesByName = computeLibrariesByName();
122 if (!_hasInstalledDeferredLoadHook) {
123 _hasInstalledDeferredLoadHook = true;
124 // After a deferred import has been loaded new libraries might have
125 // been created, so in the hook we erase _librariesByName, so it will be
126 // recomputed on the next access.
127 deferredLoadHook = () => _librariesByName = null;
128 }
129 }
130 return _librariesByName;
131 }
132
133 Map<Uri, LibraryMirror> get libraries {
134 if (_cachedLibraries != null) return _cachedLibraries;
135 Map<Uri, LibraryMirror> result = new Map();
136 for (List<LibraryMirror> list in librariesByName.values) {
137 for (LibraryMirror library in list) {
138 result[library.uri] = library;
139 }
140 }
141 return _cachedLibraries =
142 new UnmodifiableMapView<Uri, LibraryMirror>(result);
143 }
144
145 LibraryMirror findLibrary(Symbol libraryName) {
146 return librariesByName[n(libraryName)].single;
147 }
148
149 static Map<String, List<LibraryMirror>> computeLibrariesByName() {
150 disableTreeShaking();
151 var result = new Map<String, List<LibraryMirror>>();
152 var jsLibraries = JS_EMBEDDED_GLOBAL('JSExtendableArray|Null', LIBRARIES);
153 if (jsLibraries == null) return result;
154 for (List data in jsLibraries) {
155 String name = data[0];
156 String uriString = data[1];
157 Uri uri;
158 // The Uri has been compiled out. Create a URI from the simple name.
159 if (uriString != "") {
160 uri = Uri.parse(uriString);
161 } else {
162 uri = new Uri(scheme: 'https',
163 host: 'dartlang.org',
164 path: 'dart2js-stripped-uri',
165 queryParameters: { 'lib': name });
166 }
167 List<String> classes = data[2];
168 List<String> functions = data[3];
169 var metadataFunction = data[4];
170 var fields = data[5];
171 bool isRoot = data[6];
172 var globalObject = data[7];
173 List metadata = (metadataFunction == null)
174 ? const [] : JS('List', '#()', metadataFunction);
175 var libraries = result.putIfAbsent(name, () => <LibraryMirror>[]);
176 libraries.add(
177 new JsLibraryMirror(
178 s(name), uri, classes, functions, metadata, fields, isRoot,
179 globalObject));
180 }
181 return result;
182 }
183 }
184
185 abstract class JsMirror implements Mirror {
186 const JsMirror();
187
188 String get _prettyName;
189
190 String toString() => _prettyName;
191
192 // TODO(ahe): Remove this method from the API.
193 MirrorSystem get mirrors => currentJsMirrorSystem;
194
195 _getField(JsMirror receiver) {
196 throw new UnimplementedError();
197 }
198
199 void _setField(JsMirror receiver, Object arg) {
200 throw new UnimplementedError();
201 }
202
203 _loadField(String name) {
204 throw new UnimplementedError();
205 }
206
207 void _storeField(String name, Object arg) {
208 throw new UnimplementedError();
209 }
210 }
211
212 // This class is somewhat silly in the current implementation.
213 class JsIsolateMirror extends JsMirror implements IsolateMirror {
214 final _isolateContext = JS_CURRENT_ISOLATE_CONTEXT();
215
216 String get _prettyName => 'Isolate';
217
218 String get debugName {
219 String id = _isolateContext == null ? 'X' : _isolateContext.id.toString();
220 // Using name similar to what the VM uses.
221 return '${n(rootLibrary.simpleName)}-$id';
222 }
223
224 bool get isCurrent => JS_CURRENT_ISOLATE_CONTEXT() == _isolateContext;
225
226 LibraryMirror get rootLibrary {
227 return currentJsMirrorSystem.libraries.values.firstWhere(
228 (JsLibraryMirror library) => library._isRoot);
229 }
230 }
231
232 abstract class JsDeclarationMirror extends JsMirror
233 implements DeclarationMirror {
234 final Symbol simpleName;
235
236 const JsDeclarationMirror(this.simpleName);
237
238 Symbol get qualifiedName => computeQualifiedName(owner, simpleName);
239
240 bool get isPrivate => n(simpleName).startsWith('_');
241
242 bool get isTopLevel => owner != null && owner is LibraryMirror;
243
244 // TODO(ahe): This should use qualifiedName.
245 String toString() => "$_prettyName on '${n(simpleName)}'";
246
247 List<JsMethodMirror> get _methods {
248 throw new RuntimeError('Should not call _methods');
249 }
250
251 _invoke(List positionalArguments, Map<Symbol, dynamic> namedArguments) {
252 throw new RuntimeError('Should not call _invoke');
253 }
254
255 // TODO(ahe): Implement this.
256 SourceLocation get location => throw new UnimplementedError();
257 }
258
259 class JsTypeVariableMirror extends JsTypeMirror implements TypeVariableMirror {
260 final DeclarationMirror owner;
261 final TypeVariable _typeVariable;
262 final int _metadataIndex;
263 TypeMirror _cachedUpperBound;
264
265 JsTypeVariableMirror(TypeVariable typeVariable, this.owner,
266 this._metadataIndex)
267 : this._typeVariable = typeVariable,
268 super(s(typeVariable.name));
269
270 bool operator ==(other) {
271 return (other is JsTypeVariableMirror &&
272 simpleName == other.simpleName &&
273 owner == other.owner);
274 }
275
276 int get hashCode {
277 int code = 0x3FFFFFFF & (JsTypeVariableMirror).hashCode;
278 code ^= 17 * simpleName.hashCode;
279 code ^= 19 * owner.hashCode;
280 return code;
281 }
282
283 String get _prettyName => 'TypeVariableMirror';
284
285 bool get isTopLevel => false;
286 bool get isStatic => false;
287
288 TypeMirror get upperBound {
289 if (_cachedUpperBound != null) return _cachedUpperBound;
290 return _cachedUpperBound = typeMirrorFromRuntimeTypeRepresentation(
291 owner, getType(_typeVariable.bound));
292 }
293
294 bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError();
295 bool isAssignableTo(TypeMirror other) => throw new UnimplementedError();
296
297 _asRuntimeType() => _metadataIndex;
298 }
299
300 class JsTypeMirror extends JsDeclarationMirror implements TypeMirror {
301 JsTypeMirror(Symbol simpleName)
302 : super(simpleName);
303
304 String get _prettyName => 'TypeMirror';
305
306 DeclarationMirror get owner => null;
307
308 // TODO(ahe): Doesn't match the specification, see http://dartbug.com/11569.
309 bool get isTopLevel => true;
310
311 // TODO(ahe): Implement these.
312 List<InstanceMirror> get metadata => throw new UnimplementedError();
313
314 bool get hasReflectedType => false;
315 Type get reflectedType {
316 throw new UnsupportedError("This type does not support reflectedType");
317 }
318
319 List<TypeVariableMirror> get typeVariables => const <TypeVariableMirror>[];
320 List<TypeMirror> get typeArguments => const <TypeMirror>[];
321
322 bool get isOriginalDeclaration => true;
323 TypeMirror get originalDeclaration => this;
324
325 bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError();
326 bool isAssignableTo(TypeMirror other) => throw new UnimplementedError();
327
328 _asRuntimeType() {
329 if (this == JsMirrorSystem._dynamicType) return null;
330 if (this == JsMirrorSystem._voidType) return null;
331 throw new RuntimeError('Should not call _asRuntimeType');
332 }
333 }
334
335 class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror
336 implements LibraryMirror {
337 final Uri _uri;
338 final List<String> _classes;
339 final List<String> _functions;
340 final List _metadata;
341 final String _compactFieldSpecification;
342 final bool _isRoot;
343 final _globalObject;
344 List<JsMethodMirror> _cachedFunctionMirrors;
345 List<VariableMirror> _cachedFields;
346 UnmodifiableMapView<Symbol, ClassMirror> _cachedClasses;
347 UnmodifiableMapView<Symbol, MethodMirror> _cachedFunctions;
348 UnmodifiableMapView<Symbol, MethodMirror> _cachedGetters;
349 UnmodifiableMapView<Symbol, MethodMirror> _cachedSetters;
350 UnmodifiableMapView<Symbol, VariableMirror> _cachedVariables;
351 UnmodifiableMapView<Symbol, Mirror> _cachedMembers;
352 UnmodifiableMapView<Symbol, DeclarationMirror> _cachedDeclarations;
353 UnmodifiableListView<InstanceMirror> _cachedMetadata;
354
355 JsLibraryMirror(Symbol simpleName,
356 this._uri,
357 this._classes,
358 this._functions,
359 this._metadata,
360 this._compactFieldSpecification,
361 this._isRoot,
362 this._globalObject)
363 : super(simpleName) {
364 preserveLibraryNames();
365 }
366
367 String get _prettyName => 'LibraryMirror';
368
369 Uri get uri {
370 preserveUris();
371 return _uri;
372 }
373
374 Symbol get qualifiedName => simpleName;
375
376 List<JsMethodMirror> get _methods => _functionMirrors;
377
378 Map<Symbol, ClassMirror> get __classes {
379 if (_cachedClasses != null) return _cachedClasses;
380 var result = new Map();
381 for (String className in _classes) {
382 var cls = reflectClassByMangledName(className);
383 if (cls is ClassMirror) {
384 cls = cls.originalDeclaration;
385 }
386 if (cls is JsClassMirror) {
387 result[cls.simpleName] = cls;
388 cls._owner = this;
389 } else if (cls is JsTypedefMirror) {
390 result[cls.simpleName] = cls;
391 }
392 }
393 return _cachedClasses =
394 new UnmodifiableMapView<Symbol, ClassMirror>(result);
395 }
396
397 InstanceMirror setField(Symbol fieldName, Object arg) {
398 String name = n(fieldName);
399 if (name.endsWith('=')) throw new ArgumentError('');
400 var mirror = __functions[s('$name=')];
401 if (mirror == null) mirror = __variables[fieldName];
402 if (mirror == null) {
403 throw new NoSuchStaticMethodError.method(
404 null, setterSymbol(fieldName), [arg], null);
405 }
406 mirror._setField(this, arg);
407 return reflect(arg);
408 }
409
410 InstanceMirror getField(Symbol fieldName) {
411 JsMirror mirror = __members[fieldName];
412 if (mirror == null) {
413 throw new NoSuchStaticMethodError.method(null, fieldName, [], null);
414 }
415 if (mirror is! MethodMirror) return reflect(mirror._getField(this));
416 JsMethodMirror methodMirror = mirror;
417 if (methodMirror.isGetter) return reflect(mirror._getField(this));
418 assert(methodMirror.isRegularMethod);
419 var getter = JS("", "#['\$getter']", methodMirror._jsFunction);
420 if (getter == null) throw new UnimplementedError();
421 return reflect(JS("", "#()", getter));
422 }
423
424 InstanceMirror invoke(Symbol memberName,
425 List positionalArguments,
426 [Map<Symbol, dynamic> namedArguments]) {
427 if (namedArguments != null && !namedArguments.isEmpty) {
428 throw new UnsupportedError('Named arguments are not implemented.');
429 }
430 JsDeclarationMirror mirror = __members[memberName];
431
432 if (mirror is JsMethodMirror && !mirror.canInvokeReflectively()) {
433 throwInvalidReflectionError(n(memberName));
434 }
435 if (mirror == null || mirror is JsMethodMirror && mirror.isSetter) {
436 throw new NoSuchStaticMethodError.method(
437 null, memberName, positionalArguments, namedArguments);
438 }
439 if (mirror is JsMethodMirror && !mirror.isGetter) {
440 return reflect(mirror._invoke(positionalArguments, namedArguments));
441 }
442 return getField(memberName)
443 .invoke(#call, positionalArguments, namedArguments);
444 }
445
446 _loadField(String name) {
447 // TODO(ahe): What about lazily initialized fields? See
448 // [JsClassMirror.getField].
449
450 // '$' (JS_CURRENT_ISOLATE()) stores state which is read directly, so we
451 // shouldn't use [_globalObject] here.
452 assert(JS('bool', '# in #', name, JS_CURRENT_ISOLATE()));
453 return JS('', '#[#]', JS_CURRENT_ISOLATE(), name);
454 }
455
456 void _storeField(String name, Object arg) {
457 // '$' (JS_CURRENT_ISOLATE()) stores state which is stored directly, so we
458 // shouldn't use [_globalObject] here.
459 assert(JS('bool', '# in #', name, JS_CURRENT_ISOLATE()));
460 JS('void', '#[#] = #', JS_CURRENT_ISOLATE(), name, arg);
461 }
462
463 List<JsMethodMirror> get _functionMirrors {
464 if (_cachedFunctionMirrors != null) return _cachedFunctionMirrors;
465 var result = new List<JsMethodMirror>();
466 for (int i = 0; i < _functions.length; i++) {
467 String name = _functions[i];
468 var jsFunction = JS('', '#[#]', _globalObject, name);
469 String unmangledName = mangledGlobalNames[name];
470 if (unmangledName == null ||
471 JS('bool', "!!#['\$getterStub']", jsFunction)) {
472 // If there is no unmangledName, [jsFunction] is either a synthetic
473 // implementation detail, or something that is excluded
474 // by @MirrorsUsed.
475 // If it has a getterStub property it is a synthetic stub.
476 // TODO(floitsch): Remove the getterStub hack.
477 continue;
478 }
479 bool isConstructor = unmangledName.startsWith('new ');
480 bool isStatic = !isConstructor; // Top-level functions are static, but
481 // constructors are not.
482 if (isConstructor) {
483 unmangledName = unmangledName.substring(4).replaceAll(r'$', '.');
484 }
485 JsMethodMirror mirror =
486 new JsMethodMirror.fromUnmangledName(
487 unmangledName, jsFunction, isStatic, isConstructor);
488 result.add(mirror);
489 mirror._owner = this;
490 }
491 return _cachedFunctionMirrors = result;
492 }
493
494 List<VariableMirror> get _fields {
495 if (_cachedFields != null) return _cachedFields;
496 var result = <VariableMirror>[];
497 parseCompactFieldSpecification(
498 this, _compactFieldSpecification, true, result);
499 return _cachedFields = result;
500 }
501
502 Map<Symbol, MethodMirror> get __functions {
503 if (_cachedFunctions != null) return _cachedFunctions;
504 var result = new Map();
505 for (JsMethodMirror mirror in _functionMirrors) {
506 if (!mirror.isConstructor) result[mirror.simpleName] = mirror;
507 }
508 return _cachedFunctions =
509 new UnmodifiableMapView<Symbol, MethodMirror>(result);
510 }
511
512 Map<Symbol, MethodMirror> get __getters {
513 if (_cachedGetters != null) return _cachedGetters;
514 var result = new Map();
515 // TODO(ahe): Implement this.
516 return _cachedGetters =
517 new UnmodifiableMapView<Symbol, MethodMirror>(result);
518 }
519
520 Map<Symbol, MethodMirror> get __setters {
521 if (_cachedSetters != null) return _cachedSetters;
522 var result = new Map();
523 // TODO(ahe): Implement this.
524 return _cachedSetters =
525 new UnmodifiableMapView<Symbol, MethodMirror>(result);
526 }
527
528 Map<Symbol, VariableMirror> get __variables {
529 if (_cachedVariables != null) return _cachedVariables;
530 var result = new Map();
531 for (JsVariableMirror mirror in _fields) {
532 result[mirror.simpleName] = mirror;
533 }
534 return _cachedVariables =
535 new UnmodifiableMapView<Symbol, VariableMirror>(result);
536 }
537
538 Map<Symbol, Mirror> get __members {
539 if (_cachedMembers != null) return _cachedMembers;
540 Map<Symbol, Mirror> result = new Map.from(__classes);
541 addToResult(Symbol key, Mirror value) {
542 result[key] = value;
543 }
544 __functions.forEach(addToResult);
545 __getters.forEach(addToResult);
546 __setters.forEach(addToResult);
547 __variables.forEach(addToResult);
548 return _cachedMembers = new UnmodifiableMapView<Symbol, Mirror>(result);
549 }
550
551 Map<Symbol, DeclarationMirror> get declarations {
552 if (_cachedDeclarations != null) return _cachedDeclarations;
553 var result = new Map<Symbol, DeclarationMirror>();
554 addToResult(Symbol key, Mirror value) {
555 result[key] = value;
556 }
557 __members.forEach(addToResult);
558 return _cachedDeclarations =
559 new UnmodifiableMapView<Symbol, DeclarationMirror>(result);
560 }
561
562 List<InstanceMirror> get metadata {
563 if (_cachedMetadata != null) return _cachedMetadata;
564 preserveMetadata();
565 return _cachedMetadata =
566 new UnmodifiableListView<InstanceMirror>(_metadata.map(reflect));
567 }
568
569 // TODO(ahe): Test this getter.
570 DeclarationMirror get owner => null;
571
572 List<LibraryDependencyMirror> get libraryDependencies
573 => throw new UnimplementedError();
574 }
575
576 String n(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
577
578 Symbol s(String name) {
579 if (name == null) return null;
580 return new _symbol_dev.Symbol.unvalidated(name);
581 }
582
583 Symbol setterSymbol(Symbol symbol) => s("${n(symbol)}=");
584
585 final JsMirrorSystem currentJsMirrorSystem = new JsMirrorSystem();
586
587 InstanceMirror reflect(Object reflectee) {
588 if (reflectee is Closure) {
589 return new JsClosureMirror(reflectee);
590 } else {
591 return new JsInstanceMirror(reflectee);
592 }
593 }
594
595 TypeMirror reflectType(Type key) {
596 return reflectClassByMangledName(getMangledTypeName(key));
597 }
598
599 TypeMirror reflectClassByMangledName(String mangledName) {
600 String unmangledName = mangledGlobalNames[mangledName];
601 if (mangledName == 'dynamic') return JsMirrorSystem._dynamicType;
602 if (mangledName == 'void') return JsMirrorSystem._voidType;
603 if (unmangledName == null) unmangledName = mangledName;
604 return reflectClassByName(s(unmangledName), mangledName);
605 }
606
607 var classMirrors;
608
609 TypeMirror reflectClassByName(Symbol symbol, String mangledName) {
610 if (classMirrors == null) classMirrors = JsCache.allocate();
611 var mirror = JsCache.fetch(classMirrors, mangledName);
612 if (mirror != null) return mirror;
613 disableTreeShaking();
614 int typeArgIndex = mangledName.indexOf("<");
615 if (typeArgIndex != -1) {
616 TypeMirror originalDeclaration =
617 reflectClassByMangledName(mangledName.substring(0, typeArgIndex))
618 .originalDeclaration;
619 if (originalDeclaration is JsTypedefMirror) {
620 throw new UnimplementedError();
621 }
622 mirror = new JsTypeBoundClassMirror(originalDeclaration,
623 // Remove the angle brackets enclosing the type arguments.
624 mangledName.substring(typeArgIndex + 1, mangledName.length - 1));
625 JsCache.update(classMirrors, mangledName, mirror);
626 return mirror;
627 }
628 var allClasses = JS_EMBEDDED_GLOBAL('', ALL_CLASSES);
629 var constructor = JS('var', '#[#]', allClasses, mangledName);
630 if (constructor == null) {
631 // Probably an intercepted class.
632 // TODO(ahe): How to handle intercepted classes?
633 throw new UnsupportedError('Cannot find class for: ${n(symbol)}');
634 }
635 var descriptor = JS('', '#["@"]', constructor);
636 var fields;
637 var fieldsMetadata;
638 if (descriptor == null) {
639 // This is a native class, or an intercepted class.
640 // TODO(ahe): Preserve descriptor for such classes.
641 } else if (JS('bool', '# in #',
642 TYPEDEF_PREDICATE_PROPERTY_NAME, descriptor)) {
643 // Typedefs are represented as normal classes with two special properties:
644 // TYPEDEF_PREDICATE_PROPERTY_NAME and TYPEDEF_TYPE_PROPERTY_NAME.
645 // For example:
646 // MyTypedef: {
647 // "^": "Object;",
648 // $typedefType: 58,
649 // $$isTypedef: true
650 // }
651 // The typedefType is the index into the metadata table.
652 int index = JS('int', '#[#]', descriptor, TYPEDEF_TYPE_PROPERTY_NAME);
653 mirror = new JsTypedefMirror(symbol, mangledName, getType(index));
654 } else {
655 fields = JS('', '#[#]', descriptor,
656 JS_GET_NAME(JsGetName.CLASS_DESCRIPTOR_PROPERTY));
657 if (fields is List) {
658 fieldsMetadata = fields.getRange(1, fields.length).toList();
659 fields = fields[0];
660 }
661 if (fields is! String) {
662 // TODO(ahe): This is CSP mode. Find a way to determine the
663 // fields of this class.
664 fields = '';
665 }
666 }
667
668 if (mirror == null) {
669 var superclassName = fields.split(';')[0];
670 var mixins = superclassName.split('+');
671 if (mixins.length > 1 && mangledGlobalNames[mangledName] == null) {
672 mirror = reflectMixinApplication(mixins, mangledName);
673 } else {
674 ClassMirror classMirror = new JsClassMirror(
675 symbol, mangledName, constructor, fields, fieldsMetadata);
676 List typeVariables =
677 JS('JSExtendableArray|Null', '#.prototype["<>"]', constructor);
678 if (typeVariables == null || typeVariables.length == 0) {
679 mirror = classMirror;
680 } else {
681 String typeArguments = 'dynamic';
682 for (int i = 1; i < typeVariables.length; i++) {
683 typeArguments += ',dynamic';
684 }
685 mirror = new JsTypeBoundClassMirror(classMirror, typeArguments);
686 }
687 }
688 }
689
690 JsCache.update(classMirrors, mangledName, mirror);
691 return mirror;
692 }
693
694 Map<Symbol, MethodMirror> filterMethods(List<MethodMirror> methods) {
695 var result = new Map();
696 for (JsMethodMirror method in methods) {
697 if (!method.isConstructor && !method.isGetter && !method.isSetter) {
698 result[method.simpleName] = method;
699 }
700 }
701 return result;
702 }
703
704 Map<Symbol, MethodMirror> filterConstructors(methods) {
705 var result = new Map();
706 for (JsMethodMirror method in methods) {
707 if (method.isConstructor) {
708 result[method.simpleName] = method;
709 }
710 }
711 return result;
712 }
713
714 Map<Symbol, MethodMirror> filterGetters(List<MethodMirror> methods,
715 Map<Symbol, VariableMirror> fields) {
716 var result = new Map();
717 for (JsMethodMirror method in methods) {
718 if (method.isGetter) {
719
720 // TODO(ahe): This is a hack to remove getters corresponding to a field.
721 if (fields[method.simpleName] != null) continue;
722
723 result[method.simpleName] = method;
724 }
725 }
726 return result;
727 }
728
729 Map<Symbol, MethodMirror> filterSetters(List<MethodMirror> methods,
730 Map<Symbol, VariableMirror> fields) {
731 var result = new Map();
732 for (JsMethodMirror method in methods) {
733 if (method.isSetter) {
734
735 // TODO(ahe): This is a hack to remove setters corresponding to a field.
736 String name = n(method.simpleName);
737 name = name.substring(0, name.length - 1); // Remove '='.
738 if (fields[s(name)] != null) continue;
739
740 result[method.simpleName] = method;
741 }
742 }
743 return result;
744 }
745
746 Map<Symbol, Mirror> filterMembers(List<MethodMirror> methods,
747 Map<Symbol, VariableMirror> variables) {
748 Map<Symbol, Mirror> result = new Map.from(variables);
749 for (JsMethodMirror method in methods) {
750 if (method.isSetter) {
751 String name = n(method.simpleName);
752 name = name.substring(0, name.length - 1);
753 // Filter-out setters corresponding to variables.
754 if (result[s(name)] is VariableMirror) continue;
755 }
756 // Constructors aren't 'members'.
757 if (method.isConstructor) continue;
758 // Filter out synthetic tear-off stubs
759 if (JS('bool', r'!!#.$getterStub', method._jsFunction)) continue;
760 // Use putIfAbsent to filter-out getters corresponding to variables.
761 result.putIfAbsent(method.simpleName, () => method);
762 }
763 return result;
764 }
765
766 int counter = 0;
767
768 ClassMirror reflectMixinApplication(mixinNames, String mangledName) {
769 disableTreeShaking();
770 var mixins = [];
771 for (String mangledName in mixinNames) {
772 mixins.add(reflectClassByMangledName(mangledName));
773 }
774 var it = mixins.iterator;
775 it.moveNext();
776 var superclass = it.current;
777 while (it.moveNext()) {
778 superclass = new JsMixinApplication(superclass, it.current, mangledName);
779 }
780 return superclass;
781 }
782
783 class JsMixinApplication extends JsTypeMirror with JsObjectMirror
784 implements ClassMirror {
785 final ClassMirror superclass;
786 final ClassMirror mixin;
787 Symbol _cachedSimpleName;
788 Map<Symbol, MethodMirror> _cachedInstanceMembers;
789
790 JsMixinApplication(ClassMirror superclass, ClassMirror mixin,
791 String mangledName)
792 : this.superclass = superclass,
793 this.mixin = mixin,
794 super(s(mangledName));
795
796 String get _prettyName => 'ClassMirror';
797
798 Symbol get simpleName {
799 if (_cachedSimpleName != null) return _cachedSimpleName;
800 String superName = n(superclass.qualifiedName);
801 return _cachedSimpleName = (superName.contains(' with '))
802 ? s('$superName, ${n(mixin.qualifiedName)}')
803 : s('$superName with ${n(mixin.qualifiedName)}');
804 }
805
806 Symbol get qualifiedName => simpleName;
807
808 // TODO(ahe): Remove this method, only here to silence warning.
809 get _mixin => mixin;
810
811 Map<Symbol, Mirror> get __members => _mixin.__members;
812
813 Map<Symbol, MethodMirror> get __methods => _mixin.__methods;
814
815 Map<Symbol, MethodMirror> get __getters => _mixin.__getters;
816
817 Map<Symbol, MethodMirror> get __setters => _mixin.__setters;
818
819 Map<Symbol, VariableMirror> get __variables => _mixin.__variables;
820
821 Map<Symbol, DeclarationMirror> get declarations => mixin.declarations;
822
823 Map<Symbol, MethodMirror> get instanceMembers {
824 if (_cachedInstanceMembers == null) {
825 var result = new Map<Symbol, MethodMirror>();
826 if (superclass != null) {
827 result.addAll(superclass.instanceMembers);
828 }
829 result.addAll(mixin.instanceMembers);
830 _cachedInstanceMembers = result;
831 }
832 return _cachedInstanceMembers;
833 }
834
835 Map<Symbol, MethodMirror> get staticMembers => mixin.staticMembers;
836
837 _asRuntimeType() => null;
838
839 InstanceMirror invoke(
840 Symbol memberName,
841 List positionalArguments,
842 [Map<Symbol,dynamic> namedArguments]) {
843 throw new NoSuchStaticMethodError.method(
844 null, memberName, positionalArguments, namedArguments);
845 }
846
847 InstanceMirror getField(Symbol fieldName) {
848 throw new NoSuchStaticMethodError.method(null, fieldName, null, null);
849 }
850
851 InstanceMirror setField(Symbol fieldName, Object arg) {
852 throw new NoSuchStaticMethodError.method(
853 null, setterSymbol(fieldName), [arg], null);
854 }
855
856 List<ClassMirror> get superinterfaces => [mixin];
857
858 Map<Symbol, MethodMirror> get __constructors => _mixin.__constructors;
859
860 InstanceMirror newInstance(
861 Symbol constructorName,
862 List positionalArguments,
863 [Map<Symbol,dynamic> namedArguments]) {
864 throw new UnsupportedError(
865 "Can't instantiate mixin application '${n(qualifiedName)}'");
866 }
867
868 bool get isOriginalDeclaration => true;
869
870 ClassMirror get originalDeclaration => this;
871
872 // TODO(ahe): Implement this.
873 List<TypeVariableMirror> get typeVariables {
874 throw new UnimplementedError();
875 }
876
877 List<TypeMirror> get typeArguments => const <TypeMirror>[];
878
879 bool get isAbstract => throw new UnimplementedError();
880
881 bool get isEnum => throw new UnimplementedError();
882
883 bool isSubclassOf(ClassMirror other) {
884 superclass.isSubclassOf(other) || mixin.isSubclassOf(other);
885 }
886
887 bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError();
888
889 bool isAssignableTo(TypeMirror other) => throw new UnimplementedError();
890 }
891
892 abstract class JsObjectMirror implements ObjectMirror {
893 }
894
895 class JsInstanceMirror extends JsObjectMirror implements InstanceMirror {
896 final reflectee;
897
898 JsInstanceMirror(this.reflectee);
899
900 bool get hasReflectee => true;
901
902 ClassMirror get type {
903 // The spec guarantees that `null` is the singleton instance of the `Null`
904 // class.
905 if (reflectee == null) return reflectClass(Null);
906 return reflectType(getRuntimeType(reflectee));
907 }
908
909 InstanceMirror invoke(Symbol memberName,
910 List positionalArguments,
911 [Map<Symbol,dynamic> namedArguments]) {
912 if (namedArguments == null) namedArguments = const {};
913 // We can safely pass positionalArguments to _invoke as it will wrap it in
914 // a JSArray if needed.
915 return _invoke(memberName, JSInvocationMirror.METHOD,
916 positionalArguments, namedArguments);
917 }
918
919 InstanceMirror _invokeMethodWithNamedArguments(
920 String reflectiveName,
921 List positionalArguments, Map<Symbol,dynamic> namedArguments) {
922 assert(namedArguments.isNotEmpty);
923 var interceptor = getInterceptor(reflectee);
924
925 var jsFunction = JS('', '#[#]', interceptor, reflectiveName);
926 if (jsFunction == null) {
927 // TODO(ahe): Invoke noSuchMethod.
928 throw new UnimplementedNoSuchMethodError(
929 'Invoking noSuchMethod with named arguments not implemented');
930 }
931 ReflectionInfo info = new ReflectionInfo(jsFunction);
932 if (jsFunction == null) {
933 // TODO(ahe): Invoke noSuchMethod.
934 throw new UnimplementedNoSuchMethodError(
935 'Invoking noSuchMethod with named arguments not implemented');
936 }
937
938 positionalArguments = new List.from(positionalArguments);
939 // Check the number of positional arguments is valid.
940 if (info.requiredParameterCount != positionalArguments.length) {
941 // TODO(ahe): Invoke noSuchMethod.
942 throw new UnimplementedNoSuchMethodError(
943 'Invoking noSuchMethod with named arguments not implemented');
944 }
945 var defaultArguments = new Map();
946 for (int i = 0; i < info.optionalParameterCount; i++) {
947 var parameterName = info.parameterName(i + info.requiredParameterCount);
948 var defaultValue =
949 getMetadata(info.defaultValue(i + info.requiredParameterCount));
950 defaultArguments[parameterName] = defaultValue;
951 }
952 namedArguments.forEach((Symbol symbol, value) {
953 String parameter = n(symbol);
954 if (defaultArguments.containsKey(parameter)) {
955 defaultArguments[parameter] = value;
956 } else {
957 // Extraneous named argument.
958 // TODO(ahe): Invoke noSuchMethod.
959 throw new UnimplementedNoSuchMethodError(
960 'Invoking noSuchMethod with named arguments not implemented');
961 }
962 });
963 positionalArguments.addAll(defaultArguments.values);
964 // TODO(ahe): Handle intercepted methods.
965 return reflect(
966 JS('', '#.apply(#, #)', jsFunction, reflectee, positionalArguments));
967 }
968
969 /// Grabs hold of the class-specific invocation cache for the reflectee.
970 /// All reflectees with the same class share the same cache. The cache
971 /// maps reflective names to cached invocation objects with enough decoded
972 /// reflective information to know how to to invoke a specific member.
973 get _classInvocationCache {
974 String cacheName = Primitives.mirrorInvokeCacheName;
975 var cacheHolder = (reflectee == null) ? getInterceptor(null) : reflectee;
976 var cache = JS('', r'#.constructor[#]', cacheHolder, cacheName);
977 if (cache == null) {
978 cache = JsCache.allocate();
979 JS('void', r'#.constructor[#] = #', cacheHolder, cacheName, cache);
980 }
981 return cache;
982 }
983
984 String _computeReflectiveName(Symbol symbolName, int type,
985 List positionalArguments,
986 Map<Symbol, dynamic> namedArguments) {
987 String name = n(symbolName);
988 switch (type) {
989 case JSInvocationMirror.GETTER: return name;
990 case JSInvocationMirror.SETTER: return '$name=';
991 case JSInvocationMirror.METHOD:
992 if (namedArguments.isNotEmpty) return '$name*';
993 int nbArgs = positionalArguments.length as int;
994 return "$name:$nbArgs";
995 }
996 throw new RuntimeError("Could not compute reflective name for $name");
997 }
998
999 /**
1000 * Returns a `CachedInvocation` or `CachedNoSuchMethodInvocation` for the
1001 * given member.
1002 *
1003 * Caches the result.
1004 */
1005 _getCachedInvocation(Symbol name, int type, String reflectiveName,
1006 List positionalArguments, Map<Symbol,dynamic> namedArguments) {
1007
1008 var cache = _classInvocationCache;
1009 var cacheEntry = JsCache.fetch(cache, reflectiveName);
1010 var result;
1011 if (cacheEntry == null) {
1012 disableTreeShaking();
1013 String mangledName = reflectiveNames[reflectiveName];
1014 List<String> argumentNames = const [];
1015
1016 // TODO(ahe): We don't need to create an invocation mirror here. The
1017 // logic from JSInvocationMirror.getCachedInvocation could easily be
1018 // inlined here.
1019 Invocation invocation = createUnmangledInvocationMirror(
1020 name, mangledName, type, positionalArguments, argumentNames);
1021
1022 cacheEntry =
1023 JSInvocationMirror.getCachedInvocation(invocation, reflectee);
1024 JsCache.update(cache, reflectiveName, cacheEntry);
1025 }
1026 return cacheEntry;
1027 }
1028
1029 bool _isReflectable(CachedInvocation cachedInvocation) {
1030 // TODO(floitsch): tear-off closure does not guarantee that the
1031 // function is reflectable.
1032 var method = cachedInvocation.jsFunction;
1033 return hasReflectableProperty(method) || reflectee is TearOffClosure;
1034 }
1035
1036 /// Invoke the member specified through name and type on the reflectee.
1037 /// As a side-effect, this populates the class-specific invocation cache
1038 /// for the reflectee.
1039 InstanceMirror _invoke(Symbol name,
1040 int type,
1041 List positionalArguments,
1042 Map<Symbol,dynamic> namedArguments) {
1043 String reflectiveName =
1044 _computeReflectiveName(name, type, positionalArguments, namedArguments);
1045
1046 if (namedArguments.isNotEmpty) {
1047 // TODO(floitsch): first, make sure it's not a getter.
1048 return _invokeMethodWithNamedArguments(
1049 reflectiveName, positionalArguments, namedArguments);
1050 }
1051 var cacheEntry = _getCachedInvocation(
1052 name, type, reflectiveName, positionalArguments, namedArguments);
1053
1054 if (cacheEntry.isNoSuchMethod || !_isReflectable(cacheEntry)) {
1055 // Could be that we want to invoke a getter, or get a method.
1056 if (type == JSInvocationMirror.METHOD && _instanceFieldExists(name)) {
1057 return getField(name).invoke(
1058 #call, positionalArguments, namedArguments);
1059 }
1060
1061 if (type == JSInvocationMirror.SETTER) {
1062 // For setters we report the setter name "field=".
1063 name = s("${n(name)}=");
1064 }
1065
1066 if (!cacheEntry.isNoSuchMethod) {
1067 // Not reflectable.
1068 throwInvalidReflectionError(reflectiveName);
1069 }
1070
1071 String mangledName = reflectiveNames[reflectiveName];
1072 // TODO(ahe): Get the argument names.
1073 List<String> argumentNames = [];
1074 Invocation invocation = createUnmangledInvocationMirror(
1075 name, mangledName, type, positionalArguments, argumentNames);
1076 return reflect(cacheEntry.invokeOn(reflectee, invocation));
1077 } else {
1078 return reflect(cacheEntry.invokeOn(reflectee, positionalArguments));
1079 }
1080 }
1081
1082 InstanceMirror setField(Symbol fieldName, Object arg) {
1083 _invoke(fieldName, JSInvocationMirror.SETTER, [arg], const {});
1084 return reflect(arg);
1085 }
1086
1087 // JS helpers for getField optimizations.
1088 static bool isUndefined(x)
1089 => JS('bool', 'typeof # == "undefined"', x);
1090 static bool isMissingCache(x)
1091 => JS('bool', 'typeof # == "number"', x);
1092 static bool isMissingProbe(Symbol symbol)
1093 => JS('bool', 'typeof #.\$p == "undefined"', symbol);
1094 static bool isEvalAllowed()
1095 => !JS_GET_FLAG("USE_CONTENT_SECURITY_POLICY");
1096
1097
1098 /// The getter cache is lazily allocated after a couple
1099 /// of invocations of [InstanceMirror.getField]. The delay is
1100 /// used to avoid too aggressive caching and dynamic function
1101 /// generation for rarely used mirrors. The cache is specific to
1102 /// this [InstanceMirror] and maps reflective names to functions
1103 /// that will invoke the corresponding getter on the reflectee.
1104 /// The reflectee is passed to the function as the first argument
1105 /// to avoid the overhead of fetching it from this mirror repeatedly.
1106 /// The cache is lazily initialized to a JS object so we can
1107 /// benefit from "map transitions" in the underlying JavaScript
1108 /// engine to speed up cache probing.
1109 var _getterCache = 4;
1110
1111 bool _instanceFieldExists(Symbol name) {
1112 int getterType = JSInvocationMirror.GETTER;
1113 String getterName =
1114 _computeReflectiveName(name, getterType, const [], const {});
1115 var getterCacheEntry = _getCachedInvocation(
1116 name, getterType, getterName, const [], const {});
1117 return !getterCacheEntry.isNoSuchMethod && !getterCacheEntry.isGetterStub;
1118 }
1119
1120 InstanceMirror getField(Symbol fieldName) {
1121 FASTPATH: {
1122 var cache = _getterCache;
1123 if (isMissingCache(cache) || isMissingProbe(fieldName)) break FASTPATH;
1124 // If the [fieldName] has an associated probe function, we can use
1125 // it to read from the getter cache specific to this [InstanceMirror].
1126 var getter = JS('', '#.\$p(#)', fieldName, cache);
1127 if (isUndefined(getter)) break FASTPATH;
1128 // Call the getter passing the reflectee as the first argument.
1129 var value = JS('', '#(#)', getter, reflectee);
1130 // The getter has an associate cache of the last [InstanceMirror]
1131 // returned to avoid repeated invocations of [reflect]. To validate
1132 // the cache, we check that the value returned by the getter is the
1133 // same value as last time.
1134 if (JS('bool', '# === #.v', value, getter)) {
1135 return JS('InstanceMirror', '#.m', getter);
1136 } else {
1137 var result = reflect(value);
1138 JS('void', '#.v = #', getter, value);
1139 JS('void', '#.m = #', getter, result);
1140 return result;
1141 }
1142 }
1143 return _getFieldSlow(fieldName);
1144 }
1145
1146 InstanceMirror _getFieldSlow(Symbol fieldName) {
1147 // First do the slow-case getter invocation. As a side-effect of this,
1148 // the invocation cache is filled in so we can query it afterwards.
1149 var result =
1150 _invoke(fieldName, JSInvocationMirror.GETTER, const [], const {});
1151 String name = n(fieldName);
1152 var cacheEntry = JsCache.fetch(_classInvocationCache, name);
1153 if (cacheEntry.isNoSuchMethod) {
1154 return result;
1155 }
1156
1157 // Make sure we have a getter cache in this [InstanceMirror].
1158 var cache = _getterCache;
1159 if (isMissingCache(cache)) {
1160 if ((_getterCache = --cache) != 0) return result;
1161 cache = _getterCache = JS('=Object', 'Object.create(null)');
1162 }
1163
1164 // Make sure that symbol [fieldName] has a cache probing function ($p).
1165 bool useEval = isEvalAllowed();
1166 if (isMissingProbe(fieldName)) {
1167 var probe = _newProbeFn(name, useEval);
1168 JS('void', '#.\$p = #', fieldName, probe);
1169 }
1170
1171 // Create a new getter function and install it in the cache.
1172 var mangledName = cacheEntry.mangledName;
1173 var getter = (cacheEntry.isIntercepted)
1174 ? _newInterceptedGetterFn(mangledName, useEval)
1175 : _newGetterFn(mangledName, useEval);
1176 JS('void', '#[#] = #', cache, name, getter);
1177
1178 // Initialize the last value (v) and last mirror (m) on the
1179 // newly generated getter to be a sentinel value that is hard
1180 // to get hold of through user code.
1181 JS('void', '#.v = #.m = #', getter, getter, cache);
1182
1183 // Return the result of the slow-path getter invocation.
1184 return result;
1185 }
1186
1187 _newProbeFn(String id, bool useEval) {
1188 if (useEval) {
1189 String body = "return c.$id;";
1190 return JS('', 'new Function("c", #)', body);
1191 } else {
1192 return JS('', '(function(n){return(function(c){return c[n]})})(#)', id);
1193 }
1194 }
1195
1196 _newGetterFn(String name, bool useEval) {
1197 if (!useEval) return _newGetterNoEvalFn(name);
1198 // We use a comment that associates the generated function with the
1199 // class of the reflectee. This makes it more likely that the underlying
1200 // JavaScript engine will only share the generated code for accessors on the
1201 // same class (through caching of eval'ed code). This makes the
1202 // generated call to the getter - e.g. o.get$foo() - much more likely
1203 // to be monomorphic and inlineable.
1204 String className = JS('String', '#.constructor.name', reflectee);
1205 String body = "/* $className */ return o.$name();";
1206 return JS('', 'new Function("o", #)', body);
1207 }
1208
1209 _newGetterNoEvalFn(n) => JS('',
1210 '(function(n){return(function(o){return o[n]()})})(#)', n);
1211
1212 _newInterceptedGetterFn(String name, bool useEval) {
1213 var object = reflectee;
1214 // It is possible that the interceptor for a given object is the object
1215 // itself, so it is important not to share the code that captures the
1216 // interceptor between multiple different instances of [InstanceMirror].
1217 var interceptor = getInterceptor(object);
1218 if (!useEval) return _newInterceptGetterNoEvalFn(name, interceptor);
1219 String className = JS('String', '#.constructor.name', interceptor);
1220 String functionName = '$className\$$name';
1221 String body =
1222 ' function $functionName(o){return i.$name(o)}'
1223 ' return $functionName;';
1224 return JS('', '(new Function("i", #))(#)', body, interceptor);
1225 }
1226
1227 _newInterceptGetterNoEvalFn(n, i) => JS('',
1228 '(function(n,i){return(function(o){return i[n](o)})})(#,#)', n, i);
1229
1230 delegate(Invocation invocation) {
1231 return JSInvocationMirror.invokeFromMirror(invocation, reflectee);
1232 }
1233
1234 operator ==(other) {
1235 return other is JsInstanceMirror &&
1236 identical(reflectee, other.reflectee);
1237 }
1238
1239 int get hashCode {
1240 // Avoid hash collisions with the reflectee. This constant is in Smi range
1241 // and happens to be the inner padding from RFC 2104.
1242 return identityHashCode(reflectee) ^ 0x36363636;
1243 }
1244
1245 String toString() => 'InstanceMirror on ${Error.safeToString(reflectee)}';
1246
1247 // TODO(ahe): Remove this method from the API.
1248 MirrorSystem get mirrors => currentJsMirrorSystem;
1249 }
1250
1251 /**
1252 * ClassMirror for generic classes where the type parameters are bound.
1253 *
1254 * [typeArguments] will return a list of the type arguments, in constrast
1255 * to JsCLassMirror that returns an empty list since it represents original
1256 * declarations and classes that are not generic.
1257 */
1258 class JsTypeBoundClassMirror extends JsDeclarationMirror
1259 implements ClassMirror {
1260 final JsClassMirror _class;
1261
1262 /**
1263 * When instantiated this field will hold a string representing the list of
1264 * type arguments for the class, i.e. what is inside the outermost angle
1265 * brackets. Then, when get typeArguments is called the first time, the string
1266 * is parsed into the actual list of TypeMirrors, and stored in
1267 * [_cachedTypeArguments]. Due to type substitution of, for instance,
1268 * superclasses the mangled name of the class and hence this string is needed
1269 * after [_cachedTypeArguments] has been computed.
1270 *
1271 * If an integer is encountered as a type argument, it represents the type
1272 * variable at the corresponding entry in [emitter.globalMetadata].
1273 */
1274 String _typeArguments;
1275
1276 UnmodifiableListView<TypeMirror> _cachedTypeArguments;
1277 UnmodifiableMapView<Symbol, DeclarationMirror> _cachedDeclarations;
1278 UnmodifiableMapView<Symbol, DeclarationMirror> _cachedMembers;
1279 UnmodifiableMapView<Symbol, MethodMirror> _cachedConstructors;
1280 Map<Symbol, VariableMirror> _cachedVariables;
1281 Map<Symbol, MethodMirror> _cachedGetters;
1282 Map<Symbol, MethodMirror> _cachedSetters;
1283 Map<Symbol, MethodMirror> _cachedMethodsMap;
1284 List<JsMethodMirror> _cachedMethods;
1285 ClassMirror _superclass;
1286 List<ClassMirror> _cachedSuperinterfaces;
1287 Map<Symbol, MethodMirror> _cachedInstanceMembers;
1288 Map<Symbol, MethodMirror> _cachedStaticMembers;
1289
1290 JsTypeBoundClassMirror(JsClassMirror originalDeclaration, this._typeArguments)
1291 : _class = originalDeclaration,
1292 super(originalDeclaration.simpleName);
1293
1294 String get _prettyName => 'ClassMirror';
1295
1296 String toString() {
1297 String result = '$_prettyName on ${n(simpleName)}';
1298 if (typeArguments != null) {
1299 result = "$result<${typeArguments.join(', ')}>";
1300 }
1301 return result;
1302 }
1303
1304 String get _mangledName {
1305 for (TypeMirror typeArgument in typeArguments) {
1306 if (typeArgument != JsMirrorSystem._dynamicType) {
1307 return '${_class._mangledName}<$_typeArguments>';
1308 }
1309 }
1310 // When all type arguments are dynamic, the canonical representation is to
1311 // drop them.
1312 return _class._mangledName;
1313 }
1314
1315 List<TypeVariableMirror> get typeVariables => _class.typeVariables;
1316
1317 List<TypeMirror> get typeArguments {
1318 if (_cachedTypeArguments != null) return _cachedTypeArguments;
1319 List result = new List();
1320
1321 addTypeArgument(String typeArgument) {
1322 int parsedIndex = int.parse(typeArgument, onError: (_) => -1);
1323 if (parsedIndex == -1) {
1324 result.add(reflectClassByMangledName(typeArgument.trim()));
1325 } else {
1326 TypeVariable typeVariable = getMetadata(parsedIndex);
1327 TypeMirror owner = reflectClass(typeVariable.owner);
1328 TypeVariableMirror typeMirror =
1329 new JsTypeVariableMirror(typeVariable, owner, parsedIndex);
1330 result.add(typeMirror);
1331 }
1332 }
1333
1334 if (_typeArguments.indexOf('<') == -1) {
1335 _typeArguments.split(',').forEach((t) => addTypeArgument(t));
1336 } else {
1337 int level = 0;
1338 String currentTypeArgument = '';
1339
1340 for (int i = 0; i < _typeArguments.length; i++) {
1341 var character = _typeArguments[i];
1342 if (character == ' ') {
1343 continue;
1344 } else if (character == '<') {
1345 currentTypeArgument += character;
1346 level++;
1347 } else if (character == '>') {
1348 currentTypeArgument += character;
1349 level--;
1350 } else if (character == ',') {
1351 if (level > 0) {
1352 currentTypeArgument += character;
1353 } else {
1354 addTypeArgument(currentTypeArgument);
1355 currentTypeArgument = '';
1356 }
1357 } else {
1358 currentTypeArgument += character;
1359 }
1360 }
1361 addTypeArgument(currentTypeArgument);
1362 }
1363 return _cachedTypeArguments = new UnmodifiableListView(result);
1364 }
1365
1366 List<JsMethodMirror> get _methods {
1367 if (_cachedMethods != null) return _cachedMethods;
1368 return _cachedMethods =_class._getMethodsWithOwner(this);
1369 }
1370
1371 Map<Symbol, MethodMirror> get __methods {
1372 if (_cachedMethodsMap != null) return _cachedMethodsMap;
1373 return _cachedMethodsMap = new UnmodifiableMapView<Symbol, MethodMirror>(
1374 filterMethods(_methods));
1375 }
1376
1377 Map<Symbol, MethodMirror> get __constructors {
1378 if (_cachedConstructors != null) return _cachedConstructors;
1379 return _cachedConstructors =
1380 new UnmodifiableMapView<Symbol, MethodMirror>(
1381 filterConstructors(_methods));
1382 }
1383
1384 Map<Symbol, MethodMirror> get __getters {
1385 if (_cachedGetters != null) return _cachedGetters;
1386 return _cachedGetters = new UnmodifiableMapView<Symbol, MethodMirror>(
1387 filterGetters(_methods, __variables));
1388 }
1389
1390 Map<Symbol, MethodMirror> get __setters {
1391 if (_cachedSetters != null) return _cachedSetters;
1392 return _cachedSetters = new UnmodifiableMapView<Symbol, MethodMirror>(
1393 filterSetters(_methods, __variables));
1394 }
1395
1396 Map<Symbol, VariableMirror> get __variables {
1397 if (_cachedVariables != null) return _cachedVariables;
1398 var result = new Map();
1399 for (JsVariableMirror mirror in _class._getFieldsWithOwner(this)) {
1400 result[mirror.simpleName] = mirror;
1401 }
1402 return _cachedVariables =
1403 new UnmodifiableMapView<Symbol, VariableMirror>(result);
1404 }
1405
1406 Map<Symbol, DeclarationMirror> get __members {
1407 if (_cachedMembers != null) return _cachedMembers;
1408 return _cachedMembers = new UnmodifiableMapView<Symbol, DeclarationMirror>(
1409 filterMembers(_methods, __variables));
1410 }
1411
1412 Map<Symbol, DeclarationMirror> get declarations {
1413 if (_cachedDeclarations != null) return _cachedDeclarations;
1414 Map<Symbol, DeclarationMirror> result =
1415 new Map<Symbol, DeclarationMirror>();
1416 result.addAll(__members);
1417 result.addAll(__constructors);
1418 typeVariables.forEach((tv) => result[tv.simpleName] = tv);
1419 return _cachedDeclarations =
1420 new UnmodifiableMapView<Symbol, DeclarationMirror>(result);
1421 }
1422
1423 Map<Symbol, MethodMirror> get staticMembers {
1424 if (_cachedStaticMembers == null) {
1425 var result = new Map<Symbol, MethodMirror>();
1426 declarations.values.forEach((decl) {
1427 if (decl is MethodMirror && decl.isStatic && !decl.isConstructor) {
1428 result[decl.simpleName] = decl;
1429 }
1430 if (decl is VariableMirror && decl.isStatic) {
1431 var getterName = decl.simpleName;
1432 result[getterName] = new JsSyntheticAccessor(
1433 this, getterName, true, true, false, decl);
1434 if (!decl.isFinal) {
1435 var setterName = setterSymbol(decl.simpleName);
1436 result[setterName] = new JsSyntheticAccessor(
1437 this, setterName, false, true, false, decl);
1438 }
1439 }
1440 });
1441 _cachedStaticMembers = result;
1442 }
1443 return _cachedStaticMembers;
1444 }
1445
1446 Map<Symbol, MethodMirror> get instanceMembers {
1447 if (_cachedInstanceMembers == null) {
1448 var result = new Map<Symbol, MethodMirror>();
1449 if (superclass != null) {
1450 result.addAll(superclass.instanceMembers);
1451 }
1452 declarations.values.forEach((decl) {
1453 if (decl is MethodMirror && !decl.isStatic &&
1454 !decl.isConstructor && !decl.isAbstract) {
1455 result[decl.simpleName] = decl;
1456 }
1457 if (decl is VariableMirror && !decl.isStatic) {
1458 var getterName = decl.simpleName;
1459 result[getterName] = new JsSyntheticAccessor(
1460 this, getterName, true, false, false, decl);
1461 if (!decl.isFinal) {
1462 var setterName = setterSymbol(decl.simpleName);
1463 result[setterName] = new JsSyntheticAccessor(
1464 this, setterName, false, false, false, decl);
1465 }
1466 }
1467 });
1468 _cachedInstanceMembers = result;
1469 }
1470 return _cachedInstanceMembers;
1471 }
1472
1473 InstanceMirror setField(Symbol fieldName, Object arg) {
1474 return _class.setField(fieldName, arg);
1475 }
1476
1477 InstanceMirror getField(Symbol fieldName) => _class.getField(fieldName);
1478
1479 InstanceMirror newInstance(Symbol constructorName,
1480 List positionalArguments,
1481 [Map<Symbol, dynamic> namedArguments]) {
1482 var instance = _class._getInvokedInstance(constructorName,
1483 positionalArguments,
1484 namedArguments);
1485 return reflect(setRuntimeTypeInfo(
1486 instance, typeArguments.map((t) => t._asRuntimeType()).toList()));
1487 }
1488
1489 _asRuntimeType() {
1490 return [_class._jsConstructor].addAll(
1491 typeArguments.map((t) => t._asRuntimeType()));
1492 }
1493
1494 JsLibraryMirror get owner => _class.owner;
1495
1496 List<InstanceMirror> get metadata => _class.metadata;
1497
1498 ClassMirror get superclass {
1499 if (_superclass != null) return _superclass;
1500
1501 var typeInformationContainer = JS_EMBEDDED_GLOBAL('', TYPE_INFORMATION);
1502 List<int> typeInformation =
1503 JS('List|Null', '#[#]', typeInformationContainer, _class._mangledName);
1504 assert(typeInformation != null);
1505 var type = getType(typeInformation[0]);
1506 return _superclass = typeMirrorFromRuntimeTypeRepresentation(this, type);
1507 }
1508
1509 InstanceMirror invoke(Symbol memberName,
1510 List positionalArguments,
1511 [Map<Symbol,dynamic> namedArguments]) {
1512 return _class.invoke(memberName, positionalArguments, namedArguments);
1513 }
1514
1515 bool get isOriginalDeclaration => false;
1516
1517 ClassMirror get originalDeclaration => _class;
1518
1519 List<ClassMirror> get superinterfaces {
1520 if (_cachedSuperinterfaces != null) return _cachedSuperinterfaces;
1521 return _cachedSuperinterfaces = _class._getSuperinterfacesWithOwner(this);
1522 }
1523
1524 bool get isPrivate => _class.isPrivate;
1525
1526 bool get isTopLevel => _class.isTopLevel;
1527
1528 bool get isAbstract => _class.isAbstract;
1529
1530 bool get isEnum => _class.isEnum;
1531
1532 bool isSubclassOf(ClassMirror other) => _class.isSubclassOf(other);
1533
1534 SourceLocation get location => _class.location;
1535
1536 MirrorSystem get mirrors => _class.mirrors;
1537
1538 Symbol get qualifiedName => _class.qualifiedName;
1539
1540 bool get hasReflectedType => true;
1541
1542 Type get reflectedType => createRuntimeType(_mangledName);
1543
1544 Symbol get simpleName => _class.simpleName;
1545
1546 // TODO(ahe): Implement this.
1547 ClassMirror get mixin => throw new UnimplementedError();
1548
1549 bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError();
1550
1551 bool isAssignableTo(TypeMirror other) => throw new UnimplementedError();
1552 }
1553
1554 class JsSyntheticAccessor implements MethodMirror {
1555 final DeclarationMirror owner;
1556 final Symbol simpleName;
1557 final bool isGetter;
1558 final bool isStatic;
1559 final bool isTopLevel;
1560 final _target; /// The field or type that introduces the synthetic accessor.
1561
1562 JsSyntheticAccessor(this.owner,
1563 this.simpleName,
1564 this.isGetter,
1565 this.isStatic,
1566 this.isTopLevel,
1567 this._target);
1568
1569 bool get isSynthetic => true;
1570 bool get isRegularMethod => false;
1571 bool get isOperator => false;
1572 bool get isConstructor => false;
1573 bool get isConstConstructor => false;
1574 bool get isGenerativeConstructor => false;
1575 bool get isFactoryConstructor => false;
1576 bool get isRedirectingConstructor => false;
1577 bool get isAbstract => false;
1578
1579 bool get isSetter => !isGetter;
1580 bool get isPrivate => n(simpleName).startsWith('_');
1581
1582 Symbol get qualifiedName => computeQualifiedName(owner, simpleName);
1583 Symbol get constructorName => const Symbol('');
1584
1585 TypeMirror get returnType => _target.type;
1586 List<ParameterMirror> get parameters {
1587 if (isGetter) return const [];
1588 return new UnmodifiableListView(
1589 [new JsSyntheticSetterParameter(this, this._target)]);
1590 }
1591
1592 List<InstanceMirror> get metadata => const [];
1593 String get source => null;
1594 SourceLocation get location => throw new UnimplementedError();
1595 }
1596
1597 class JsSyntheticSetterParameter implements ParameterMirror {
1598 final DeclarationMirror owner;
1599 final VariableMirror _target;
1600
1601 JsSyntheticSetterParameter(this.owner, this._target);
1602
1603 Symbol get simpleName => _target.simpleName;
1604 Symbol get qualifiedName => computeQualifiedName(owner, simpleName);
1605 TypeMirror get type => _target.type;
1606
1607 bool get isOptional => false;
1608 bool get isNamed => false;
1609 bool get isStatic => false;
1610 bool get isTopLevel => false;
1611 bool get isConst => false;
1612 bool get isFinal => true;
1613 bool get isPrivate => false;
1614 bool get hasDefaultValue => false;
1615 InstanceMirror get defaultValue => null;
1616 List<InstanceMirror> get metadata => const [];
1617 SourceLocation get location => throw new UnimplementedError();
1618 }
1619
1620 class JsClassMirror extends JsTypeMirror with JsObjectMirror
1621 implements ClassMirror {
1622 final String _mangledName;
1623 final _jsConstructor;
1624 final String _fieldsDescriptor;
1625 final List _fieldsMetadata;
1626 final _jsConstructorCache = JsCache.allocate();
1627 List _metadata;
1628 ClassMirror _superclass;
1629 List<JsMethodMirror> _cachedMethods;
1630 List<VariableMirror> _cachedFields;
1631 UnmodifiableMapView<Symbol, MethodMirror> _cachedConstructors;
1632 UnmodifiableMapView<Symbol, MethodMirror> _cachedMethodsMap;
1633 UnmodifiableMapView<Symbol, MethodMirror> _cachedGetters;
1634 UnmodifiableMapView<Symbol, MethodMirror> _cachedSetters;
1635 UnmodifiableMapView<Symbol, VariableMirror> _cachedVariables;
1636 UnmodifiableMapView<Symbol, Mirror> _cachedMembers;
1637 UnmodifiableMapView<Symbol, DeclarationMirror> _cachedDeclarations;
1638 UnmodifiableListView<InstanceMirror> _cachedMetadata;
1639 UnmodifiableListView<ClassMirror> _cachedSuperinterfaces;
1640 UnmodifiableListView<TypeVariableMirror> _cachedTypeVariables;
1641 Map<Symbol, MethodMirror> _cachedInstanceMembers;
1642 Map<Symbol, MethodMirror> _cachedStaticMembers;
1643
1644 // Set as side-effect of accessing JsLibraryMirror.classes.
1645 JsLibraryMirror _owner;
1646
1647 JsClassMirror(Symbol simpleName,
1648 this._mangledName,
1649 this._jsConstructor,
1650 this._fieldsDescriptor,
1651 this._fieldsMetadata)
1652 : super(simpleName);
1653
1654 String get _prettyName => 'ClassMirror';
1655
1656 Map<Symbol, MethodMirror> get __constructors {
1657 if (_cachedConstructors != null) return _cachedConstructors;
1658 return _cachedConstructors =
1659 new UnmodifiableMapView<Symbol, MethodMirror>(
1660 filterConstructors(_methods));
1661 }
1662
1663 _asRuntimeType() {
1664 if (typeVariables.isEmpty) return _jsConstructor;
1665 var type = [_jsConstructor];
1666 for (int i = 0; i < typeVariables.length; i ++) {
1667 type.add(JsMirrorSystem._dynamicType._asRuntimeType);
1668 }
1669 return type;
1670 }
1671
1672 List<JsMethodMirror> _getMethodsWithOwner(DeclarationMirror methodOwner) {
1673 var prototype = JS('', '#.prototype', _jsConstructor);
1674 // The prototype might not have been processed yet, so do that now.
1675 JS('', '#[#]()', prototype,
1676 JS_GET_NAME(JsGetName.DEFERRED_ACTION_PROPERTY));
1677 List<String> keys = extractKeys(prototype);
1678 var result = <JsMethodMirror>[];
1679 for (String key in keys) {
1680 if (isReflectiveDataInPrototype(key)) continue;
1681 String simpleName = mangledNames[key];
1682 // [simpleName] can be null if [key] represents an implementation
1683 // detail, for example, a bailout method, or runtime type support.
1684 // It might also be null if the user has limited what is reified for
1685 // reflection with metadata.
1686 if (simpleName == null) continue;
1687 var function = JS('', '#[#]', prototype, key);
1688 if (!isOrdinaryReflectableMethod(function)) continue;
1689 if (isAliasedSuperMethod(function, key)) continue;
1690 var mirror =
1691 new JsMethodMirror.fromUnmangledName(
1692 simpleName, function, false, false);
1693 result.add(mirror);
1694 mirror._owner = methodOwner;
1695 }
1696
1697 var statics = JS_EMBEDDED_GLOBAL('', STATICS);
1698 keys = extractKeys(JS('', '#[#]', statics, _mangledName));
1699 for (String mangledName in keys) {
1700 if (isReflectiveDataInPrototype(mangledName)) continue;
1701 String unmangledName = mangledName;
1702 var jsFunction = JS('', '#[#]', owner._globalObject, mangledName);
1703
1704 bool isConstructor = false;
1705 if (hasReflectableProperty(jsFunction)) {
1706 String reflectionName =
1707 JS('String|Null', r'#.$reflectionName', jsFunction);
1708 if (reflectionName == null) continue;
1709 isConstructor = reflectionName.startsWith('new ');
1710 if (isConstructor) {
1711 reflectionName = reflectionName.substring(4).replaceAll(r'$', '.');
1712 }
1713 unmangledName = reflectionName;
1714 } else {
1715 continue;
1716 }
1717 bool isStatic = !isConstructor; // Constructors are not static.
1718 JsMethodMirror mirror =
1719 new JsMethodMirror.fromUnmangledName(
1720 unmangledName, jsFunction, isStatic, isConstructor);
1721 result.add(mirror);
1722 mirror._owner = methodOwner;
1723 }
1724
1725 return result;
1726 }
1727
1728 List<JsMethodMirror> get _methods {
1729 if (_cachedMethods != null) return _cachedMethods;
1730 return _cachedMethods = _getMethodsWithOwner(this);
1731 }
1732
1733 List<VariableMirror> _getFieldsWithOwner(DeclarationMirror fieldOwner) {
1734 var result = <VariableMirror>[];
1735
1736 var instanceFieldSpecfication = _fieldsDescriptor.split(';')[1];
1737 if (_fieldsMetadata != null) {
1738 instanceFieldSpecfication =
1739 [instanceFieldSpecfication]..addAll(_fieldsMetadata);
1740 }
1741 parseCompactFieldSpecification(
1742 fieldOwner, instanceFieldSpecfication, false, result);
1743
1744 var statics = JS_EMBEDDED_GLOBAL('', STATICS);
1745 var staticDescriptor = JS('', '#[#]', statics, _mangledName);
1746 if (staticDescriptor != null) {
1747 parseCompactFieldSpecification(
1748 fieldOwner,
1749 JS('', '#[#]',
1750 staticDescriptor,
1751 JS_GET_NAME(JsGetName.CLASS_DESCRIPTOR_PROPERTY)),
1752 true, result);
1753 }
1754 return result;
1755 }
1756
1757 List<VariableMirror> get _fields {
1758 if (_cachedFields != null) return _cachedFields;
1759 return _cachedFields = _getFieldsWithOwner(this);
1760 }
1761
1762 Map<Symbol, MethodMirror> get __methods {
1763 if (_cachedMethodsMap != null) return _cachedMethodsMap;
1764 return _cachedMethodsMap =
1765 new UnmodifiableMapView<Symbol, MethodMirror>(filterMethods(_methods));
1766 }
1767
1768 Map<Symbol, MethodMirror> get __getters {
1769 if (_cachedGetters != null) return _cachedGetters;
1770 return _cachedGetters = new UnmodifiableMapView<Symbol, MethodMirror>(
1771 filterGetters(_methods, __variables));
1772 }
1773
1774 Map<Symbol, MethodMirror> get __setters {
1775 if (_cachedSetters != null) return _cachedSetters;
1776 return _cachedSetters = new UnmodifiableMapView<Symbol, MethodMirror>(
1777 filterSetters(_methods, __variables));
1778 }
1779
1780 Map<Symbol, VariableMirror> get __variables {
1781 if (_cachedVariables != null) return _cachedVariables;
1782 var result = new Map();
1783 for (JsVariableMirror mirror in _fields) {
1784 result[mirror.simpleName] = mirror;
1785 }
1786 return _cachedVariables =
1787 new UnmodifiableMapView<Symbol, VariableMirror>(result);
1788 }
1789
1790 Map<Symbol, Mirror> get __members {
1791 if (_cachedMembers != null) return _cachedMembers;
1792 return _cachedMembers = new UnmodifiableMapView<Symbol, Mirror>(
1793 filterMembers(_methods, __variables));
1794 }
1795
1796 Map<Symbol, DeclarationMirror> get declarations {
1797 if (_cachedDeclarations != null) return _cachedDeclarations;
1798 var result = new Map<Symbol, DeclarationMirror>();
1799 addToResult(Symbol key, Mirror value) {
1800 result[key] = value;
1801 }
1802 __members.forEach(addToResult);
1803 __constructors.forEach(addToResult);
1804 typeVariables.forEach((tv) => result[tv.simpleName] = tv);
1805 return _cachedDeclarations =
1806 new UnmodifiableMapView<Symbol, DeclarationMirror>(result);
1807 }
1808
1809 Map<Symbol, MethodMirror> get staticMembers {
1810 if (_cachedStaticMembers == null) {
1811 var result = new Map<Symbol, MethodMirror>();
1812 declarations.values.forEach((decl) {
1813 if (decl is MethodMirror && decl.isStatic && !decl.isConstructor) {
1814 result[decl.simpleName] = decl;
1815 }
1816 if (decl is VariableMirror && decl.isStatic) {
1817 var getterName = decl.simpleName;
1818 result[getterName] = new JsSyntheticAccessor(
1819 this, getterName, true, true, false, decl);
1820 if (!decl.isFinal) {
1821 var setterName = setterSymbol(decl.simpleName);
1822 result[setterName] = new JsSyntheticAccessor(
1823 this, setterName, false, true, false, decl);
1824 }
1825 }
1826 });
1827 _cachedStaticMembers = result;
1828 }
1829 return _cachedStaticMembers;
1830 }
1831
1832 Map<Symbol, MethodMirror> get instanceMembers {
1833 if (_cachedInstanceMembers == null) {
1834 var result = new Map<Symbol, MethodMirror>();
1835 if (superclass != null) {
1836 result.addAll(superclass.instanceMembers);
1837 }
1838 declarations.values.forEach((decl) {
1839 if (decl is MethodMirror && !decl.isStatic &&
1840 !decl.isConstructor && !decl.isAbstract) {
1841 result[decl.simpleName] = decl;
1842 }
1843 if (decl is VariableMirror && !decl.isStatic) {
1844 var getterName = decl.simpleName;
1845 result[getterName] = new JsSyntheticAccessor(
1846 this, getterName, true, false, false, decl);
1847 if (!decl.isFinal) {
1848 var setterName = setterSymbol(decl.simpleName);
1849 result[setterName] = new JsSyntheticAccessor(
1850 this, setterName, false, false, false, decl);
1851 }
1852 }
1853 });
1854 _cachedInstanceMembers = result;
1855 }
1856 return _cachedInstanceMembers;
1857 }
1858
1859 InstanceMirror setField(Symbol fieldName, Object arg) {
1860 JsVariableMirror mirror = __variables[fieldName];
1861 if (mirror != null && mirror.isStatic && !mirror.isFinal) {
1862 // '$' (JS_CURRENT_ISOLATE()) stores state which is stored directly, so
1863 // we shouldn't use [JsLibraryMirror._globalObject] here.
1864 String jsName = mirror._jsName;
1865 if (!JS('bool', '# in #', jsName, JS_CURRENT_ISOLATE())) {
1866 throw new RuntimeError('Cannot find "$jsName" in current isolate.');
1867 }
1868 JS('void', '#[#] = #', JS_CURRENT_ISOLATE(), jsName, arg);
1869 return reflect(arg);
1870 }
1871 Symbol setterName = setterSymbol(fieldName);
1872 if (mirror == null) {
1873 JsMethodMirror setter = __setters[setterName];
1874 if (setter != null) {
1875 setter._invoke([arg], const {});
1876 return reflect(arg);
1877 }
1878 }
1879 throw new NoSuchStaticMethodError.method(null, setterName, [arg], null);
1880 }
1881
1882 bool _staticFieldExists(Symbol fieldName) {
1883 JsVariableMirror mirror = __variables[fieldName];
1884 if (mirror != null) return mirror.isStatic;
1885 JsMethodMirror getter = __getters[fieldName];
1886 return getter != null && getter.isStatic;
1887 }
1888
1889 InstanceMirror getField(Symbol fieldName) {
1890 JsVariableMirror mirror = __variables[fieldName];
1891 if (mirror != null && mirror.isStatic) {
1892 String jsName = mirror._jsName;
1893 // '$' (JS_CURRENT_ISOLATE()) stores state which is read directly, so
1894 // we shouldn't use [JsLibraryMirror._globalObject] here.
1895 if (!JS('bool', '# in #', jsName, JS_CURRENT_ISOLATE())) {
1896 throw new RuntimeError('Cannot find "$jsName" in current isolate.');
1897 }
1898 var lazies = JS_EMBEDDED_GLOBAL('', LAZIES);
1899 if (JS('bool', '# in #', jsName, lazies)) {
1900 String getterName = JS('String', '#[#]', lazies, jsName);
1901 return reflect(JS('', '#[#]()', JS_CURRENT_ISOLATE(), getterName));
1902 } else {
1903 return reflect(JS('', '#[#]', JS_CURRENT_ISOLATE(), jsName));
1904 }
1905 }
1906 JsMethodMirror getter = __getters[fieldName];
1907 if (getter != null && getter.isStatic) {
1908 return reflect(getter._invoke(const [], const {}));
1909 }
1910 // If the fieldName designates a static function we have to return
1911 // its closure.
1912 JsMethodMirror method = __methods[fieldName];
1913 if (method != null && method.isStatic) {
1914 // We invoke the same getter that Dart code would execute. During
1915 // initialization we have stored that getter on the function (so that
1916 // we can find it more easily here).
1917 var getter = JS("", "#['\$getter']", method._jsFunction);
1918 if (getter == null) throw new UnimplementedError();
1919 return reflect(JS("", "#()", getter));
1920 }
1921 throw new NoSuchStaticMethodError.method(null, fieldName, null, null);
1922 }
1923
1924 _getInvokedInstance(Symbol constructorName,
1925 List positionalArguments,
1926 [Map<Symbol, dynamic> namedArguments]) {
1927 if (namedArguments != null && !namedArguments.isEmpty) {
1928 throw new UnsupportedError('Named arguments are not implemented.');
1929 }
1930 JsMethodMirror mirror =
1931 JsCache.fetch(_jsConstructorCache, n(constructorName));
1932 if (mirror == null) {
1933 mirror = __constructors.values.firstWhere(
1934 (m) => m.constructorName == constructorName,
1935 orElse: () {
1936 throw new NoSuchStaticMethodError.method(
1937 null, constructorName, positionalArguments, namedArguments);
1938 });
1939 JsCache.update(_jsConstructorCache, n(constructorName), mirror);
1940 }
1941 return mirror._invoke(positionalArguments, namedArguments);
1942 }
1943
1944 InstanceMirror newInstance(Symbol constructorName,
1945 List positionalArguments,
1946 [Map<Symbol, dynamic> namedArguments]) {
1947 return reflect(_getInvokedInstance(constructorName,
1948 positionalArguments,
1949 namedArguments));
1950 }
1951
1952 JsLibraryMirror get owner {
1953 if (_owner == null) {
1954 for (var list in JsMirrorSystem.librariesByName.values) {
1955 for (JsLibraryMirror library in list) {
1956 // This will set _owner field on all classes as a side
1957 // effect. This gives us a fast path to reflect on a
1958 // class without parsing reflection data.
1959 library.__classes;
1960 }
1961 }
1962 if (_owner == null) {
1963 throw new StateError('Class "${n(simpleName)}" has no owner');
1964 }
1965 }
1966 return _owner;
1967 }
1968
1969 List<InstanceMirror> get metadata {
1970 if (_cachedMetadata != null) return _cachedMetadata;
1971 if (_metadata == null) {
1972 _metadata = extractMetadata(JS('', '#.prototype', _jsConstructor));
1973 }
1974 return _cachedMetadata =
1975 new UnmodifiableListView<InstanceMirror>(_metadata.map(reflect));
1976 }
1977
1978 ClassMirror get superclass {
1979 if (_superclass == null) {
1980 var typeInformationContainer = JS_EMBEDDED_GLOBAL('', TYPE_INFORMATION);
1981 List<int> typeInformation =
1982 JS('List|Null', '#[#]', typeInformationContainer, _mangledName);
1983 if (typeInformation != null) {
1984 var type = getType(typeInformation[0]);
1985 _superclass = typeMirrorFromRuntimeTypeRepresentation(this, type);
1986 } else {
1987 var superclassName = _fieldsDescriptor.split(';')[0].split(':')[0];
1988 // TODO(zarah): Remove special handing of mixins.
1989 var mixins = superclassName.split('+');
1990 if (mixins.length > 1) {
1991 if (mixins.length != 2) {
1992 throw new RuntimeError('Strange mixin: $_fieldsDescriptor');
1993 }
1994 _superclass = reflectClassByMangledName(mixins[0]);
1995 } else {
1996 // Use _superclass == this to represent class with no superclass
1997 // (Object).
1998 _superclass = (superclassName == '')
1999 ? this : reflectClassByMangledName(superclassName);
2000 }
2001 }
2002 }
2003 return _superclass == this ? null : _superclass;
2004 }
2005
2006 InstanceMirror invoke(Symbol memberName,
2007 List positionalArguments,
2008 [Map<Symbol,dynamic> namedArguments]) {
2009 // Mirror API gotcha: Calling [invoke] on a ClassMirror means invoke a
2010 // static method.
2011
2012 if (namedArguments != null && !namedArguments.isEmpty) {
2013 throw new UnsupportedError('Named arguments are not implemented.');
2014 }
2015 JsMethodMirror mirror = __methods[memberName];
2016
2017 if (mirror == null && _staticFieldExists(memberName)) {
2018 return getField(memberName)
2019 .invoke(#call, positionalArguments, namedArguments);
2020 }
2021 if (mirror == null || !mirror.isStatic) {
2022 throw new NoSuchStaticMethodError.method(
2023 null, memberName, positionalArguments, namedArguments);
2024 }
2025 if (!mirror.canInvokeReflectively()) {
2026 throwInvalidReflectionError(n(memberName));
2027 }
2028 return reflect(mirror._invoke(positionalArguments, namedArguments));
2029 }
2030
2031 bool get isOriginalDeclaration => true;
2032
2033 ClassMirror get originalDeclaration => this;
2034
2035 List<ClassMirror> _getSuperinterfacesWithOwner(DeclarationMirror owner) {
2036 var typeInformationContainer = JS_EMBEDDED_GLOBAL('', TYPE_INFORMATION);
2037 List<int> typeInformation =
2038 JS('List|Null', '#[#]', typeInformationContainer, _mangledName);
2039 List<ClassMirror> result = const <ClassMirror>[];
2040 if (typeInformation != null) {
2041 ClassMirror lookupType(int i) {
2042 var type = getType(i);
2043 return typeMirrorFromRuntimeTypeRepresentation(owner, type);
2044 }
2045
2046 //We skip the first since it is the supertype.
2047 result = typeInformation.skip(1).map(lookupType).toList();
2048 }
2049
2050 return new UnmodifiableListView<ClassMirror>(result);
2051 }
2052
2053 List<ClassMirror> get superinterfaces {
2054 if (_cachedSuperinterfaces != null) return _cachedSuperinterfaces;
2055 return _cachedSuperinterfaces = _getSuperinterfacesWithOwner(this);
2056 }
2057
2058 List<TypeVariableMirror> get typeVariables {
2059 if (_cachedTypeVariables != null) return _cachedTypeVariables;
2060 List result = new List();
2061 List typeVariables =
2062 JS('JSExtendableArray|Null', '#.prototype["<>"]', _jsConstructor);
2063 if (typeVariables == null) return result;
2064 for (int i = 0; i < typeVariables.length; i++) {
2065 TypeVariable typeVariable = getMetadata(typeVariables[i]);
2066 result.add(new JsTypeVariableMirror(typeVariable, this,
2067 typeVariables[i]));
2068 }
2069 return _cachedTypeVariables = new UnmodifiableListView(result);
2070 }
2071
2072 List<TypeMirror> get typeArguments => const <TypeMirror>[];
2073
2074 bool get hasReflectedType => typeVariables.length == 0;
2075
2076 Type get reflectedType {
2077 if (!hasReflectedType) {
2078 throw new UnsupportedError(
2079 "Declarations of generics have no reflected type");
2080 }
2081 return createRuntimeType(_mangledName);
2082 }
2083
2084 // TODO(ahe): Implement this.
2085 ClassMirror get mixin => throw new UnimplementedError();
2086
2087 bool get isAbstract => throw new UnimplementedError();
2088
2089 bool get isEnum => throw new UnimplementedError();
2090
2091 bool isSubclassOf(ClassMirror other) {
2092 if (other is! ClassMirror) {
2093 throw new ArgumentError(other);
2094 }
2095 if (other is JsFunctionTypeMirror) {
2096 return false;
2097 } if (other is JsClassMirror &&
2098 JS('bool', '# == #', other._jsConstructor, _jsConstructor)) {
2099 return true;
2100 } else if (superclass == null) {
2101 return false;
2102 } else {
2103 return superclass.isSubclassOf(other);
2104 }
2105 }
2106 }
2107
2108 class JsVariableMirror extends JsDeclarationMirror implements VariableMirror {
2109
2110 // TODO(ahe): The values in these fields are virtually untested.
2111 final String _jsName;
2112 final bool isFinal;
2113 final bool isStatic;
2114 final _metadataFunction;
2115 final DeclarationMirror _owner;
2116 final int _type;
2117 List _metadata;
2118
2119 JsVariableMirror(Symbol simpleName,
2120 this._jsName,
2121 this._type,
2122 this.isFinal,
2123 this.isStatic,
2124 this._metadataFunction,
2125 this._owner)
2126 : super(simpleName);
2127
2128 factory JsVariableMirror.from(String descriptor,
2129 metadataFunction,
2130 JsDeclarationMirror owner,
2131 bool isStatic) {
2132 List<String> fieldInformation = descriptor.split('-');
2133 if (fieldInformation.length == 1) {
2134 // The field is not available for reflection.
2135 // TODO(ahe): Should return an unreflectable field.
2136 return null;
2137 }
2138
2139 String field = fieldInformation[0];
2140 int length = field.length;
2141 var code = fieldCode(field.codeUnitAt(length - 1));
2142 bool isFinal = false;
2143 if (code == 0) return null; // Inherited field.
2144 bool hasGetter = (code & 3) != 0;
2145 bool hasSetter = (code >> 2) != 0;
2146 isFinal = !hasSetter;
2147 length--;
2148 String jsName;
2149 String accessorName = jsName = field.substring(0, length);
2150 int divider = field.indexOf(':');
2151 if (divider > 0) {
2152 accessorName = accessorName.substring(0, divider);
2153 jsName = field.substring(divider + 1);
2154 }
2155 var unmangledName;
2156 if (isStatic) {
2157 unmangledName = mangledGlobalNames[accessorName];
2158 } else {
2159 String getterPrefix = JS_GET_NAME(JsGetName.GETTER_PREFIX);
2160 unmangledName = mangledNames['$getterPrefix$accessorName'];
2161 }
2162 if (unmangledName == null) unmangledName = accessorName;
2163 if (!hasSetter) {
2164 // TODO(ahe): This is a hack to handle checked setters in checked mode.
2165 var setterName = s('$unmangledName=');
2166 for (JsMethodMirror method in owner._methods) {
2167 if (method.simpleName == setterName) {
2168 isFinal = false;
2169 break;
2170 }
2171 }
2172 }
2173 int type = int.parse(fieldInformation[1], onError: (_) => null);
2174 return new JsVariableMirror(s(unmangledName),
2175 jsName,
2176 type,
2177 isFinal,
2178 isStatic,
2179 metadataFunction,
2180 owner);
2181 }
2182
2183 String get _prettyName => 'VariableMirror';
2184
2185 TypeMirror get type {
2186 return typeMirrorFromRuntimeTypeRepresentation(owner, getType(_type));
2187 }
2188
2189 DeclarationMirror get owner => _owner;
2190
2191 List<InstanceMirror> get metadata {
2192 preserveMetadata();
2193 if (_metadata == null) {
2194 _metadata = (_metadataFunction == null)
2195 ? const [] : JS('', '#()', _metadataFunction);
2196 }
2197 return _metadata.map(reflect).toList();
2198 }
2199
2200 static int fieldCode(int code) {
2201 if (code >= 60 && code <= 64) return code - 59;
2202 if (code >= 123 && code <= 126) return code - 117;
2203 if (code >= 37 && code <= 43) return code - 27;
2204 return 0;
2205 }
2206
2207 _getField(JsMirror receiver) => receiver._loadField(_jsName);
2208
2209 void _setField(JsMirror receiver, Object arg) {
2210 if (isFinal) {
2211 // TODO(floitsch): when the field is non-static we don't want to have
2212 // a mirror as receiver.
2213 if (isStatic) {
2214 throw new NoSuchStaticMethodError.method(
2215 null, setterSymbol(simpleName), [arg], null);
2216 }
2217 throw new NoSuchMethodError(this, setterSymbol(simpleName), [arg], null);
2218 }
2219 receiver._storeField(_jsName, arg);
2220 }
2221
2222 // TODO(ahe): Implement this method.
2223 bool get isConst => throw new UnimplementedError();
2224 }
2225
2226 class JsClosureMirror extends JsInstanceMirror implements ClosureMirror {
2227 JsClosureMirror(reflectee)
2228 : super(reflectee);
2229
2230 MethodMirror get function {
2231 String cacheName = Primitives.mirrorFunctionCacheName;
2232 JsMethodMirror cachedFunction;
2233 // TODO(ahe): Restore caching.
2234 //= JS('JsMethodMirror|Null', r'#.constructor[#]', reflectee, cacheName);
2235 if (cachedFunction != null) return cachedFunction;
2236 disableTreeShaking();
2237 // TODO(ahe): What about optional parameters (named or not).
2238 String callPrefix = "${JS_GET_NAME(JsGetName.CALL_PREFIX)}\$";
2239 var extractCallName = JS('', r'''
2240 function(reflectee) {
2241 var properties = Object.keys(reflectee.constructor.prototype);
2242 for (var i = 0; i < properties.length; i++) {
2243 var property = properties[i];
2244 if (# == property.substring(0, #) &&
2245 property[#] >= '0' &&
2246 property[#] <= '9') return property;
2247 }
2248 return null;
2249 }
2250 ''', callPrefix, callPrefix.length, callPrefix.length, callPrefix.length);
2251 String callName = JS('String|Null', '#(#)', extractCallName, reflectee);
2252 if (callName == null) {
2253 throw new RuntimeError('Cannot find callName on "$reflectee"');
2254 }
2255 // TODO(floitsch): What about optional parameters?
2256 int parameterCount = int.parse(callName.split(r'$')[1]);
2257 if (reflectee is BoundClosure) {
2258 var target = BoundClosure.targetOf(reflectee);
2259 var self = BoundClosure.selfOf(reflectee);
2260 var name = mangledNames[BoundClosure.nameOf(reflectee)];
2261 if (name == null) {
2262 throwInvalidReflectionError(name);
2263 }
2264 cachedFunction = new JsMethodMirror.fromUnmangledName(
2265 name, target, false, false);
2266 } else {
2267 bool isStatic = true; // TODO(ahe): Compute isStatic correctly.
2268 var jsFunction = JS('', '#[#]', reflectee, callName);
2269 var dummyOptionalParameterCount = 0;
2270 cachedFunction = new JsMethodMirror(
2271 s(callName), jsFunction, parameterCount, dummyOptionalParameterCount,
2272 false, false, isStatic, false, false);
2273 }
2274 JS('void', r'#.constructor[#] = #', reflectee, cacheName, cachedFunction);
2275 return cachedFunction;
2276 }
2277
2278 InstanceMirror apply(List positionalArguments,
2279 [Map<Symbol, dynamic> namedArguments]) {
2280 return reflect(
2281 Function.apply(reflectee, positionalArguments, namedArguments));
2282 }
2283
2284 String toString() => "ClosureMirror on '${Error.safeToString(reflectee)}'";
2285
2286 // TODO(ahe): Implement this method.
2287 String get source => throw new UnimplementedError();
2288 }
2289
2290 class JsMethodMirror extends JsDeclarationMirror implements MethodMirror {
2291 final _jsFunction;
2292 final int _requiredParameterCount;
2293 final int _optionalParameterCount;
2294 final bool isGetter;
2295 final bool isSetter;
2296 final bool isStatic;
2297 final bool isConstructor;
2298 final bool isOperator;
2299 DeclarationMirror _owner;
2300 List _metadata;
2301 TypeMirror _returnType;
2302 UnmodifiableListView<ParameterMirror> _parameters;
2303
2304 JsMethodMirror(Symbol simpleName,
2305 this._jsFunction,
2306 this._requiredParameterCount,
2307 this._optionalParameterCount,
2308 this.isGetter,
2309 this.isSetter,
2310 this.isStatic,
2311 this.isConstructor,
2312 this.isOperator)
2313 : super(simpleName);
2314
2315 factory JsMethodMirror.fromUnmangledName(String name,
2316 jsFunction,
2317 bool isStatic,
2318 bool isConstructor) {
2319 List<String> info = name.split(':');
2320 name = info[0];
2321 bool isOperator = isOperatorName(name);
2322 bool isSetter = !isOperator && name.endsWith('=');
2323 int requiredParameterCount = 0;
2324 int optionalParameterCount = 0;
2325 bool isGetter = false;
2326 if (info.length == 1) {
2327 if (isSetter) {
2328 requiredParameterCount = 1;
2329 } else {
2330 isGetter = true;
2331 requiredParameterCount = 0;
2332 }
2333 } else {
2334 ReflectionInfo reflectionInfo = new ReflectionInfo(jsFunction);
2335 requiredParameterCount = reflectionInfo.requiredParameterCount;
2336 optionalParameterCount = reflectionInfo.optionalParameterCount;
2337 assert(int.parse(info[1]) == requiredParameterCount
2338 + optionalParameterCount);
2339 }
2340 return new JsMethodMirror(
2341 s(name), jsFunction, requiredParameterCount, optionalParameterCount,
2342 isGetter, isSetter, isStatic, isConstructor, isOperator);
2343 }
2344
2345 String get _prettyName => 'MethodMirror';
2346
2347 int get _parameterCount => _requiredParameterCount + _optionalParameterCount;
2348
2349 List<ParameterMirror> get parameters {
2350 if (_parameters != null) return _parameters;
2351 metadata; // Compute _parameters as a side-effect of extracting metadata.
2352 return _parameters;
2353 }
2354
2355 bool canInvokeReflectively() {
2356 return hasReflectableProperty(_jsFunction);
2357 }
2358
2359 DeclarationMirror get owner => _owner;
2360
2361 TypeMirror get returnType {
2362 metadata; // Compute _returnType as a side-effect of extracting metadata.
2363 return _returnType;
2364 }
2365
2366 List<InstanceMirror> get metadata {
2367 if (_metadata == null) {
2368 var raw = extractMetadata(_jsFunction);
2369 var formals = new List(_parameterCount);
2370 ReflectionInfo info = new ReflectionInfo(_jsFunction);
2371 if (info != null) {
2372 assert(_parameterCount
2373 == info.requiredParameterCount + info.optionalParameterCount);
2374 var functionType = info.functionType;
2375 var type;
2376 if (functionType is int) {
2377 type = new JsFunctionTypeMirror(info.computeFunctionRti(null), this);
2378 assert(_parameterCount == type.parameters.length);
2379 } else if (isTopLevel) {
2380 type = new JsFunctionTypeMirror(info.computeFunctionRti(null), owner);
2381 } else {
2382 TypeMirror ownerType = owner;
2383 JsClassMirror ownerClass = ownerType.originalDeclaration;
2384 type = new JsFunctionTypeMirror(
2385 info.computeFunctionRti(ownerClass._jsConstructor),
2386 owner);
2387 }
2388 // Constructors aren't reified with their return type.
2389 if (isConstructor) {
2390 _returnType = owner;
2391 } else {
2392 _returnType = type.returnType;
2393 }
2394 int i = 0;
2395 bool isNamed = info.areOptionalParametersNamed;
2396 for (JsParameterMirror parameter in type.parameters) {
2397 var name = info.parameterName(i);
2398 List<int> annotations = info.parameterMetadataAnnotations(i);
2399 var p;
2400 if (i < info.requiredParameterCount) {
2401 p = new JsParameterMirror(name, this, parameter._type,
2402 metadataList: annotations);
2403 } else {
2404 var defaultValue = info.defaultValue(i);
2405 p = new JsParameterMirror(
2406 name, this, parameter._type, metadataList: annotations,
2407 isOptional: true, isNamed: isNamed, defaultValue: defaultValue);
2408 }
2409 formals[i++] = p;
2410 }
2411 }
2412 _parameters = new UnmodifiableListView<ParameterMirror>(formals);
2413 _metadata = new UnmodifiableListView(raw.map(reflect));
2414 }
2415 return _metadata;
2416 }
2417
2418 Symbol get constructorName {
2419 // TODO(ahe): I believe it is more appropriate to throw an exception or
2420 // return null.
2421 if (!isConstructor) return const Symbol('');
2422 String name = n(simpleName);
2423 int index = name.indexOf('.');
2424 if (index == -1) return const Symbol('');
2425 return s(name.substring(index + 1));
2426 }
2427
2428 _invoke(List positionalArguments, Map<Symbol, dynamic> namedArguments) {
2429 if (namedArguments != null && !namedArguments.isEmpty) {
2430 throw new UnsupportedError('Named arguments are not implemented.');
2431 }
2432 if (!isStatic && !isConstructor) {
2433 throw new RuntimeError('Cannot invoke instance method without receiver.');
2434 }
2435 int positionalLength = positionalArguments.length;
2436 if (positionalLength < _requiredParameterCount ||
2437 positionalLength > _parameterCount ||
2438 _jsFunction == null) {
2439 // TODO(ahe): What receiver to use?
2440 throw new NoSuchMethodError(
2441 owner, simpleName, positionalArguments, namedArguments);
2442 }
2443 if (positionalLength < _parameterCount) {
2444 // Fill up with default values.
2445 // Make a copy so we don't modify the input.
2446 positionalArguments = positionalArguments.toList();
2447 for (int i = positionalLength; i < parameters.length; i++) {
2448 JsParameterMirror parameter = parameters[i];
2449 positionalArguments.add(parameter.defaultValue.reflectee);
2450 }
2451 }
2452 // Using JS_CURRENT_ISOLATE() ('$') here is actually correct, although
2453 // _jsFunction may not be a property of '$', most static functions do not
2454 // care who their receiver is. But to lazy getters, it is important that
2455 // 'this' is '$'.
2456 return JS('', r'#.apply(#, #)', _jsFunction, JS_CURRENT_ISOLATE(),
2457 new List.from(positionalArguments));
2458 }
2459
2460 _getField(JsMirror receiver) {
2461 if (isGetter) {
2462 return _invoke([], null);
2463 } else {
2464 // TODO(ahe): Closurize method.
2465 throw new UnimplementedError('getField on $receiver');
2466 }
2467 }
2468
2469 _setField(JsMirror receiver, Object arg) {
2470 if (isSetter) {
2471 return _invoke([arg], null);
2472 } else {
2473 throw new NoSuchMethodError(this, setterSymbol(simpleName), [], null);
2474 }
2475 }
2476
2477 // Abstract methods are tree-shaken away.
2478 bool get isAbstract => false;
2479
2480 // TODO(ahe, 14633): This might not be true for all cases.
2481 bool get isSynthetic => false;
2482
2483 // TODO(ahe): Test this.
2484 bool get isRegularMethod => !isGetter && !isSetter && !isConstructor;
2485
2486 // TODO(ahe): Implement this method.
2487 bool get isConstConstructor => throw new UnimplementedError();
2488
2489 // TODO(ahe): Implement this method.
2490 bool get isGenerativeConstructor => throw new UnimplementedError();
2491
2492 // TODO(ahe): Implement this method.
2493 bool get isRedirectingConstructor => throw new UnimplementedError();
2494
2495 // TODO(ahe): Implement this method.
2496 bool get isFactoryConstructor => throw new UnimplementedError();
2497
2498 // TODO(ahe): Implement this method.
2499 String get source => throw new UnimplementedError();
2500 }
2501
2502 class JsParameterMirror extends JsDeclarationMirror implements ParameterMirror {
2503 final DeclarationMirror owner;
2504 // A JS object representing the type.
2505 final _type;
2506
2507 final bool isOptional;
2508
2509 final bool isNamed;
2510
2511 final int _defaultValue;
2512
2513 final List<int> metadataList;
2514
2515 JsParameterMirror(String unmangledName,
2516 this.owner,
2517 this._type,
2518 {this.metadataList: const <int>[],
2519 this.isOptional: false,
2520 this.isNamed: false,
2521 defaultValue})
2522 : _defaultValue = defaultValue,
2523 super(s(unmangledName));
2524
2525 String get _prettyName => 'ParameterMirror';
2526
2527 TypeMirror get type {
2528 return typeMirrorFromRuntimeTypeRepresentation(owner, _type);
2529 }
2530
2531 // Only true for static fields, never for a parameter.
2532 bool get isStatic => false;
2533
2534 // TODO(ahe): Implement this.
2535 bool get isFinal => false;
2536
2537 // TODO(ahe): Implement this.
2538 bool get isConst => false;
2539
2540 bool get hasDefaultValue => _defaultValue != null;
2541
2542 get defaultValue {
2543 return hasDefaultValue ? reflect(getMetadata(_defaultValue)) : null;
2544 }
2545
2546 List<InstanceMirror> get metadata {
2547 preserveMetadata();
2548 return metadataList.map((int i) => reflect(getMetadata(i))).toList();
2549 }
2550 }
2551
2552 class JsTypedefMirror extends JsDeclarationMirror implements TypedefMirror {
2553 final String _mangledName;
2554 JsFunctionTypeMirror referent;
2555
2556 JsTypedefMirror(Symbol simpleName, this._mangledName, _typeData)
2557 : super(simpleName) {
2558 referent = new JsFunctionTypeMirror(_typeData, this);
2559 }
2560
2561 JsFunctionTypeMirror get value => referent;
2562
2563 String get _prettyName => 'TypedefMirror';
2564
2565 bool get hasReflectedType => throw new UnimplementedError();
2566
2567 Type get reflectedType => createRuntimeType(_mangledName);
2568
2569 // TODO(floitsch): Implement this method.
2570 List<TypeVariableMirror> get typeVariables => throw new UnimplementedError();
2571
2572 // TODO(floitsch): Implement this method.
2573 List<TypeMirror> get typeArguments => throw new UnimplementedError();
2574
2575 bool get isOriginalDeclaration => true;
2576
2577 TypeMirror get originalDeclaration => this;
2578
2579 // TODO(floitsch): Implement this method.
2580 DeclarationMirror get owner => throw new UnimplementedError();
2581
2582 // TODO(ahe): Implement this method.
2583 List<InstanceMirror> get metadata => throw new UnimplementedError();
2584
2585 bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError();
2586 bool isAssignableTo(TypeMirror other) => throw new UnimplementedError();
2587 }
2588
2589 // TODO(ahe): Remove this class when API is updated.
2590 class BrokenClassMirror {
2591 bool get hasReflectedType => throw new UnimplementedError();
2592 Type get reflectedType => throw new UnimplementedError();
2593 ClassMirror get superclass => throw new UnimplementedError();
2594 List<ClassMirror> get superinterfaces => throw new UnimplementedError();
2595 Map<Symbol, DeclarationMirror> get declarations
2596 => throw new UnimplementedError();
2597 Map<Symbol, MethodMirror> get instanceMembers
2598 => throw new UnimplementedError();
2599 Map<Symbol, MethodMirror> get staticMembers => throw new UnimplementedError();
2600 ClassMirror get mixin => throw new UnimplementedError();
2601 InstanceMirror newInstance(
2602 Symbol constructorName,
2603 List positionalArguments,
2604 [Map<Symbol, dynamic> namedArguments]) => throw new UnimplementedError();
2605 InstanceMirror invoke(Symbol memberName,
2606 List positionalArguments,
2607 [Map<Symbol, dynamic> namedArguments])
2608 => throw new UnimplementedError();
2609 InstanceMirror getField(Symbol fieldName) => throw new UnimplementedError();
2610 InstanceMirror setField(Symbol fieldName, Object value)
2611 => throw new UnimplementedError();
2612 List<TypeVariableMirror> get typeVariables => throw new UnimplementedError();
2613 List<TypeMirror> get typeArguments => throw new UnimplementedError();
2614 TypeMirror get originalDeclaration => throw new UnimplementedError();
2615 Symbol get simpleName => throw new UnimplementedError();
2616 Symbol get qualifiedName => throw new UnimplementedError();
2617 bool get isPrivate => throw new UnimplementedError();
2618 bool get isTopLevel => throw new UnimplementedError();
2619 SourceLocation get location => throw new UnimplementedError();
2620 List<InstanceMirror> get metadata => throw new UnimplementedError();
2621 }
2622
2623 class JsFunctionTypeMirror extends BrokenClassMirror
2624 implements FunctionTypeMirror {
2625 final _typeData;
2626 String _cachedToString;
2627 TypeMirror _cachedReturnType;
2628 UnmodifiableListView<ParameterMirror> _cachedParameters;
2629 DeclarationMirror owner;
2630
2631 JsFunctionTypeMirror(this._typeData, this.owner);
2632
2633 bool get _hasReturnType {
2634 return JS('bool', '# in #',
2635 JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG), _typeData);
2636 }
2637
2638 get _returnType {
2639 return JS('', '#[#]', _typeData,
2640 JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG));
2641 }
2642
2643 bool get _isVoid {
2644 return JS('bool', '!!#[#]', _typeData,
2645 JS_GET_NAME(JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG));
2646 }
2647
2648 bool get _hasArguments {
2649 return JS('bool', '# in #',
2650 JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG),
2651 _typeData);
2652 }
2653 List get _arguments {
2654 return JS('JSExtendableArray', '#[#]',
2655 _typeData,
2656 JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG));
2657 }
2658
2659 bool get _hasOptionalArguments {
2660 return JS('bool', '# in #',
2661 JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG),
2662 _typeData);
2663 }
2664 List get _optionalArguments {
2665 return JS('JSExtendableArray', '#[#]',
2666 _typeData,
2667 JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG));
2668 }
2669
2670 bool get _hasNamedArguments {
2671 return JS('bool', '# in #',
2672 JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG),
2673 _typeData);
2674 }
2675 get _namedArguments {
2676 return JS('=Object', '#[#]',
2677 _typeData,
2678 JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG));
2679 }
2680
2681 bool get isOriginalDeclaration => true;
2682
2683 bool get isAbstract => false;
2684
2685 bool get isEnum => false;
2686
2687 TypeMirror get returnType {
2688 if (_cachedReturnType != null) return _cachedReturnType;
2689 if (_isVoid) return _cachedReturnType = JsMirrorSystem._voidType;
2690 if (!_hasReturnType) return _cachedReturnType = JsMirrorSystem._dynamicType;
2691 return _cachedReturnType =
2692 typeMirrorFromRuntimeTypeRepresentation(owner, _returnType);
2693 }
2694
2695 List<ParameterMirror> get parameters {
2696 if (_cachedParameters != null) return _cachedParameters;
2697 List result = [];
2698 int parameterCount = 0;
2699 if (_hasArguments) {
2700 for (var type in _arguments) {
2701 result.add(
2702 new JsParameterMirror('argument${parameterCount++}', this, type));
2703 }
2704 }
2705 if (_hasOptionalArguments) {
2706 for (var type in _optionalArguments) {
2707 result.add(
2708 new JsParameterMirror('argument${parameterCount++}', this, type));
2709 }
2710 }
2711 if (_hasNamedArguments) {
2712 for (var name in extractKeys(_namedArguments)) {
2713 var type = JS('', '#[#]', _namedArguments, name);
2714 result.add(new JsParameterMirror(name, this, type));
2715 }
2716 }
2717 return _cachedParameters = new UnmodifiableListView<ParameterMirror>(
2718 result);
2719 }
2720
2721 String _unmangleIfPreserved(String mangled) {
2722 String result = unmangleGlobalNameIfPreservedAnyways(mangled);
2723 if (result != null) return result;
2724 return mangled;
2725 }
2726
2727 String toString() {
2728 if (_cachedToString != null) return _cachedToString;
2729 var s = "FunctionTypeMirror on '(";
2730 var sep = '';
2731 if (_hasArguments) {
2732 for (var argument in _arguments) {
2733 s += sep;
2734 s += _unmangleIfPreserved(runtimeTypeToString(argument));
2735 sep = ', ';
2736 }
2737 }
2738 if (_hasOptionalArguments) {
2739 s += '$sep[';
2740 sep = '';
2741 for (var argument in _optionalArguments) {
2742 s += sep;
2743 s += _unmangleIfPreserved(runtimeTypeToString(argument));
2744 sep = ', ';
2745 }
2746 s += ']';
2747 }
2748 if (_hasNamedArguments) {
2749 s += '$sep{';
2750 sep = '';
2751 for (var name in extractKeys(_namedArguments)) {
2752 s += sep;
2753 s += '$name: ';
2754 s += _unmangleIfPreserved(
2755 runtimeTypeToString(JS('', '#[#]', _namedArguments, name)));
2756 sep = ', ';
2757 }
2758 s += '}';
2759 }
2760 s += ') -> ';
2761 if (_isVoid) {
2762 s += 'void';
2763 } else if (_hasReturnType) {
2764 s += _unmangleIfPreserved(runtimeTypeToString(_returnType));
2765 } else {
2766 s += 'dynamic';
2767 }
2768 return _cachedToString = "$s'";
2769 }
2770
2771 bool isSubclassOf(ClassMirror other) => false;
2772
2773 bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError();
2774
2775 bool isAssignableTo(TypeMirror other) => throw new UnimplementedError();
2776
2777 // TODO(ahe): Implement this method.
2778 MethodMirror get callMethod => throw new UnimplementedError();
2779 }
2780
2781 int findTypeVariableIndex(List<TypeVariableMirror> typeVariables, String name) {
2782 for (int i = 0; i < typeVariables.length; i++) {
2783 if (typeVariables[i].simpleName == s(name)) {
2784 return i;
2785 }
2786 }
2787 throw new ArgumentError('Type variable not present in list.');
2788 }
2789
2790 TypeMirror typeMirrorFromRuntimeTypeRepresentation(
2791 DeclarationMirror owner,
2792 var /*int|List|JsFunction|TypeImpl*/ type) {
2793 // TODO(ahe): This method might benefit from using convertRtiToRuntimeType
2794 // instead of working on strings.
2795 ClassMirror ownerClass;
2796 DeclarationMirror context = owner;
2797 while (context != null) {
2798 if (context is ClassMirror) {
2799 ownerClass = context;
2800 break;
2801 }
2802 // TODO(ahe): Get type parameters and arguments from typedefs.
2803 if (context is TypedefMirror) break;
2804 context = context.owner;
2805 }
2806
2807 String representation;
2808 if (type == null) {
2809 return JsMirrorSystem._dynamicType;
2810 } else if (type is TypeImpl) {
2811 return reflectType(type);
2812 } else if (ownerClass == null) {
2813 representation = runtimeTypeToString(type);
2814 } else if (ownerClass.isOriginalDeclaration) {
2815 if (type is num) {
2816 // [type] represents a type variable so in the context of an original
2817 // declaration the corresponding type variable should be returned.
2818 TypeVariable typeVariable = getMetadata(type);
2819 List<TypeVariableMirror> typeVariables = ownerClass.typeVariables;
2820 int index = findTypeVariableIndex(typeVariables, typeVariable.name);
2821 return typeVariables[index];
2822 } else {
2823 // Nested type variables will be retrieved lazily (the integer
2824 // representation is kept in the string) so they are not processed here.
2825 representation = runtimeTypeToString(type);
2826 }
2827 } else {
2828 TypeMirror getTypeArgument(int index) {
2829 TypeVariable typeVariable = getMetadata(index);
2830 int variableIndex =
2831 findTypeVariableIndex(ownerClass.typeVariables, typeVariable.name);
2832 return ownerClass.typeArguments[variableIndex];
2833 }
2834
2835 if (type is num) {
2836 // [type] represents a type variable used as type argument for example
2837 // the type argument of Bar: class Foo<T> extends Bar<T> {}
2838 TypeMirror typeArgument = getTypeArgument(type);
2839 if (typeArgument is JsTypeVariableMirror)
2840 return typeArgument;
2841 }
2842 String substituteTypeVariable(int index) {
2843 var typeArgument = getTypeArgument(index);
2844 if (typeArgument is JsTypeVariableMirror) {
2845 return '${typeArgument._metadataIndex}';
2846 }
2847 if (typeArgument is! JsClassMirror &&
2848 typeArgument is! JsTypeBoundClassMirror) {
2849 if (typeArgument == JsMirrorSystem._dynamicType) {
2850 return 'dynamic';
2851 } else if (typeArgument == JsMirrorSystem._voidType) {
2852 return 'void';
2853 } else {
2854 // TODO(ahe): This case shouldn't happen.
2855 return 'dynamic';
2856 }
2857 }
2858 return typeArgument._mangledName;
2859 }
2860 representation =
2861 runtimeTypeToString(type, onTypeVariable: substituteTypeVariable);
2862 }
2863 if (representation != null) {
2864 return reflectClassByMangledName(
2865 getMangledTypeName(createRuntimeType(representation)));
2866 }
2867 String typedefPropertyName = JS_GET_NAME(JsGetName.TYPEDEF_TAG);
2868 if (type != null && JS('', '#[#]', type, typedefPropertyName) != null) {
2869 return typeMirrorFromRuntimeTypeRepresentation(
2870 owner, JS('', '#[#]', type, typedefPropertyName));
2871 } else if (type != null && isDartFunctionType(type)) {
2872 return new JsFunctionTypeMirror(type, owner);
2873 }
2874 return reflectClass(Function);
2875 }
2876
2877 Symbol computeQualifiedName(DeclarationMirror owner, Symbol simpleName) {
2878 if (owner == null) return simpleName;
2879 String ownerName = n(owner.qualifiedName);
2880 return s('$ownerName.${n(simpleName)}');
2881 }
2882
2883 List extractMetadata(victim) {
2884 preserveMetadata();
2885 var metadataFunction;
2886 if (JS('bool', 'Object.prototype.hasOwnProperty.call(#, "@")', victim)) {
2887 metadataFunction = JS('', '#["@"]', victim);
2888 }
2889 if (metadataFunction != null) return JS('', '#()', metadataFunction);
2890 if (JS('bool', 'typeof # != "function"', victim)) return const [];
2891 if (JS('bool', '# in #', r'$metadataIndex', victim)) {
2892 return JSArray.markFixedList(
2893 JS('JSExtendableArray',
2894 r'#.$reflectionInfo.splice(#.$metadataIndex)', victim, victim))
2895 .map((int i) => getMetadata(i)).toList();
2896 }
2897 return const [];
2898 }
2899
2900 void parseCompactFieldSpecification(
2901 JsDeclarationMirror owner,
2902 fieldSpecification,
2903 bool isStatic,
2904 List<Mirror> result) {
2905 List fieldsMetadata = null;
2906 List<String> fields;
2907 if (fieldSpecification is List) {
2908 fields = splitFields(fieldSpecification[0], ',');
2909 fieldsMetadata = fieldSpecification.sublist(1);
2910 } else if (fieldSpecification is String) {
2911 fields = splitFields(fieldSpecification, ',');
2912 } else {
2913 fields = [];
2914 }
2915 int fieldNumber = 0;
2916 for (String field in fields) {
2917 var metadata;
2918 if (fieldsMetadata != null) {
2919 metadata = fieldsMetadata[fieldNumber++];
2920 }
2921 var mirror = new JsVariableMirror.from(field, metadata, owner, isStatic);
2922 if (mirror != null) {
2923 result.add(mirror);
2924 }
2925 }
2926 }
2927
2928 /// Similar to [String.split], but returns an empty list if [string] is empty.
2929 List<String> splitFields(String string, Pattern pattern) {
2930 if (string.isEmpty) return <String>[];
2931 return string.split(pattern);
2932 }
2933
2934 bool isOperatorName(String name) {
2935 switch (name) {
2936 case '==':
2937 case '[]':
2938 case '*':
2939 case '/':
2940 case '%':
2941 case '~/':
2942 case '+':
2943 case '<<':
2944 case '>>':
2945 case '>=':
2946 case '>':
2947 case '<=':
2948 case '<':
2949 case '&':
2950 case '^':
2951 case '|':
2952 case '-':
2953 case 'unary-':
2954 case '[]=':
2955 case '~':
2956 return true;
2957 default:
2958 return false;
2959 }
2960 }
2961
2962 /// Returns true if the key represent ancillary reflection data, that is, not a
2963 /// method.
2964 bool isReflectiveDataInPrototype(String key) {
2965 if (key == JS_GET_NAME(JsGetName.CLASS_DESCRIPTOR_PROPERTY) ||
2966 key == METHODS_WITH_OPTIONAL_ARGUMENTS) {
2967 return true;
2968 }
2969 String firstChar = key[0];
2970 return firstChar == '*' || firstChar == '+';
2971 }
2972
2973 /// Returns `true` if [jsFunction] is an ordinary reflectable method and
2974 /// not a (potentially reflectable) stub or otherwise non-reflectable method.
2975 bool isOrdinaryReflectableMethod(var jsFunction) {
2976 return JS('bool', r'#.$reflectable === 1', jsFunction);
2977 }
2978
2979 /// Returns true if [key] is only an aliased entry for [function] in the
2980 /// prototype.
2981 bool isAliasedSuperMethod(var jsFunction, String key) {
2982 var stubName = JS('String|Null', r'#.$stubName', jsFunction);
2983 return stubName != null && key != stubName;
2984 }
2985
2986 class NoSuchStaticMethodError extends Error implements NoSuchMethodError {
2987 static const int MISSING_CONSTRUCTOR = 0;
2988 static const int MISSING_METHOD = 1;
2989 final ClassMirror _cls;
2990 final Symbol _name;
2991 final List _positionalArguments;
2992 final Map<Symbol, dynamic> _namedArguments;
2993 final int _kind;
2994
2995 NoSuchStaticMethodError.missingConstructor(
2996 this._cls,
2997 this._name,
2998 this._positionalArguments,
2999 this._namedArguments)
3000 : _kind = MISSING_CONSTRUCTOR;
3001
3002 /// If the given class is `null` the static method/getter/setter is top-level.
3003 NoSuchStaticMethodError.method(
3004 this._cls,
3005 this._name,
3006 this._positionalArguments,
3007 this._namedArguments)
3008 : _kind = MISSING_METHOD;
3009
3010 String toString() {
3011 // TODO(floitsch): show arguments.
3012 switch(_kind) {
3013 case MISSING_CONSTRUCTOR:
3014 return
3015 "NoSuchMethodError: No constructor named '${n(_name)}' in class"
3016 " '${n(_cls.qualifiedName)}'.";
3017 case MISSING_METHOD:
3018 if (_cls == null) {
3019 return "NoSuchMethodError: No top-level method named '${n(_name)}'.";
3020 }
3021 return "NoSuchMethodError: No static method named '${n(_name)}' in"
3022 " class '${n(_cls.qualifiedName)}'";
3023 default:
3024 return 'NoSuchMethodError';
3025 }
3026 }
3027 }
3028
3029 Symbol getSymbol(String name, LibraryMirror library) {
3030 if (_isPublicSymbol(name)) {
3031 return new _symbol_dev.Symbol.validated(name);
3032 }
3033 if (library == null) {
3034 throw new ArgumentError(
3035 "Library required for private symbol name: $name");
3036 }
3037 if (!_symbol_dev.Symbol.isValidSymbol(name)) {
3038 throw new ArgumentError("Not a valid symbol name: $name");
3039 }
3040 throw new UnimplementedError(
3041 "MirrorSystem.getSymbol not implemented for private names");
3042 }
3043
3044 bool _isPublicSymbol(String name) {
3045 // A symbol is public if it doesn't start with '_' and it doesn't
3046 // have a part (following a '.') that starts with '_'.
3047 const int UNDERSCORE = 0x5f;
3048 if (name.isEmpty) return true;
3049 int index = -1;
3050 do {
3051 if (name.codeUnitAt(index + 1) == UNDERSCORE) return false;
3052 index = name.indexOf('.', index + 1);
3053 } while (index >= 0 && index + 1 < name.length);
3054 return true;
3055 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698