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

Side by Side Diff: tool/input_sdk_patch/js_mirrors.dart

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

Powered by Google App Engine
This is Rietveld 408576698