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

Unified Diff: sdk/lib/_internal/lib/js_mirrors.dart

Issue 195793013: Add support for closure calls through getters. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix status file and remove bad type.wq Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sdk/lib/_internal/lib/js_helper.dart ('k') | tests/lib/lib.status » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/_internal/lib/js_mirrors.dart
diff --git a/sdk/lib/_internal/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart
index ceb177f872fe6584ba45af99180f097958e13d18..1036bfdb25540a67d5e265feb3ca4b8c3aefdfed 100644
--- a/sdk/lib/_internal/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/lib/js_mirrors.dart
@@ -341,7 +341,13 @@ class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror
// TODO(ahe): What receiver to use?
throw new NoSuchMethodError(this, fieldName, [], null);
}
- return reflect(mirror._getField(this));
+ if (mirror is! MethodMirror) return reflect(mirror._getField(this));
+ JsMethodMirror methodMirror = mirror;
+ if (methodMirror.isGetter) return reflect(mirror._getField(this));
+ assert(methodMirror.isRegularMethod);
+ var getter = JS("", "#['\$getter']", methodMirror._jsFunction);
+ if (getter == null) throw new UnimplementedError();
+ return reflect(JS("", "#()", getter));
}
InstanceMirror invoke(Symbol memberName,
@@ -351,15 +357,20 @@ class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror
throw new UnsupportedError('Named arguments are not implemented.');
}
JsDeclarationMirror mirror = __members[memberName];
- if (mirror == null) {
+
+ if (mirror is JsMethodMirror && !mirror.canInvokeReflectively()) {
+ throwInvalidReflectionError(n(memberName));
+ }
+ if (mirror == null || mirror is JsMethodMirror && mirror.isSetter) {
// TODO(ahe): What receiver to use?
throw new NoSuchMethodError(
this, memberName, positionalArguments, namedArguments);
}
- if (mirror is JsMethodMirror && !mirror.canInvokeReflectively()) {
- throwInvalidReflectionError(n(memberName));
+ if (mirror is JsMethodMirror && !mirror.isGetter) {
+ return reflect(mirror._invoke(positionalArguments, namedArguments));
}
- return reflect(mirror._invoke(positionalArguments, namedArguments));
+ return getField(memberName)
+ .invoke(#call, positionalArguments, namedArguments);
}
_loadField(String name) {
@@ -387,7 +398,7 @@ class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror
var jsFunction = JS('', '#[#]', _globalObject, name);
String unmangledName = mangledGlobalNames[name];
if (unmangledName == null ||
- JS('bool', "!!#['getterStub']", jsFunction)) {
+ JS('bool', "!!#['\$getterStub']", jsFunction)) {
// If there is no unmangledName, [jsFunction] is either a synthetic
// implementation detail, or something that is excluded
// by @MirrorsUsed.
@@ -816,61 +827,61 @@ class JsInstanceMirror extends JsObjectMirror implements InstanceMirror {
InstanceMirror invoke(Symbol memberName,
List positionalArguments,
[Map<Symbol,dynamic> namedArguments]) {
- String name = n(memberName);
- String reflectiveName;
- if (namedArguments != null && !namedArguments.isEmpty) {
- var interceptor = getInterceptor(reflectee);
-
- var jsFunction = JS('', '#[# + "*"]', interceptor, name);
- if (jsFunction == null) {
- // TODO(ahe): Invoke noSuchMethod.
- throw new UnimplementedNoSuchMethodError(
- 'Invoking noSuchMethod with named arguments not implemented');
- }
- ReflectionInfo info = new ReflectionInfo(jsFunction);
- if (jsFunction == null) {
- // TODO(ahe): Invoke noSuchMethod.
- throw new UnimplementedNoSuchMethodError(
- 'Invoking noSuchMethod with named arguments not implemented');
- }
-
- positionalArguments = new List.from(positionalArguments);
- // Check the number of positional arguments is valid.
- if (info.requiredParameterCount != positionalArguments.length) {
+ if (namedArguments == null) namedArguments = const {};
+ // We can safely pass positionalArguments to _invoke as it will wrap it in
+ // a JSArray if needed.
+ return _invoke(memberName, JSInvocationMirror.METHOD,
+ positionalArguments, namedArguments);
+ }
+
+ InstanceMirror _invokeMethodWithNamedArguments(
+ String reflectiveName,
+ List positionalArguments, Map<Symbol,dynamic> namedArguments) {
+ assert(namedArguments.isNotEmpty);
+ var interceptor = getInterceptor(reflectee);
+
+ var jsFunction = JS('', '#[#]', interceptor, reflectiveName);
+ if (jsFunction == null) {
+ // TODO(ahe): Invoke noSuchMethod.
+ throw new UnimplementedNoSuchMethodError(
+ 'Invoking noSuchMethod with named arguments not implemented');
+ }
+ ReflectionInfo info = new ReflectionInfo(jsFunction);
+ if (jsFunction == null) {
+ // TODO(ahe): Invoke noSuchMethod.
+ throw new UnimplementedNoSuchMethodError(
+ 'Invoking noSuchMethod with named arguments not implemented');
+ }
+
+ positionalArguments = new List.from(positionalArguments);
+ // Check the number of positional arguments is valid.
+ if (info.requiredParameterCount != positionalArguments.length) {
+ // TODO(ahe): Invoke noSuchMethod.
+ throw new UnimplementedNoSuchMethodError(
+ 'Invoking noSuchMethod with named arguments not implemented');
+ }
+ var defaultArguments = new Map();
+ for (int i = 0; i < info.optionalParameterCount; i++) {
+ var parameterName = info.parameterName(i + info.requiredParameterCount);
+ var defaultValue =
+ getMetadata(info.defaultValue(i + info.requiredParameterCount));
+ defaultArguments[parameterName] = defaultValue;
+ }
+ namedArguments.forEach((Symbol symbol, value) {
+ String parameter = n(symbol);
+ if (defaultArguments.containsKey(parameter)) {
+ defaultArguments[parameter] = value;
+ } else {
+ // Extraneous named argument.
// TODO(ahe): Invoke noSuchMethod.
throw new UnimplementedNoSuchMethodError(
'Invoking noSuchMethod with named arguments not implemented');
}
- var defaultArguments = new Map();
- for (int i = 0; i < info.optionalParameterCount; i++) {
- var parameterName = info.parameterName(i + info.requiredParameterCount);
- var defaultValue =
- getMetadata(info.defaultValue(i + info.requiredParameterCount));
- defaultArguments[parameterName] = defaultValue;
- }
- namedArguments.forEach((Symbol symbol, value) {
- String parameter = n(symbol);
- if (defaultArguments.containsKey(parameter)) {
- defaultArguments[parameter] = value;
- } else {
- // Extraneous named argument.
- // TODO(ahe): Invoke noSuchMethod.
- throw new UnimplementedNoSuchMethodError(
- 'Invoking noSuchMethod with named arguments not implemented');
- }
- });
- positionalArguments.addAll(defaultArguments.values);
- // TODO(ahe): Handle intercepted methods.
- return reflect(
- JS('', '#.apply(#, #)', jsFunction, reflectee, positionalArguments));
- } else {
- reflectiveName =
- JS('String', '# + ":" + # + ":0"', name, positionalArguments.length);
- }
- // We can safely pass positionalArguments to _invoke as it will wrap it in
- // a JSArray if needed.
- return _invoke(memberName, JSInvocationMirror.METHOD, reflectiveName,
- positionalArguments);
+ });
+ positionalArguments.addAll(defaultArguments.values);
+ // TODO(ahe): Handle intercepted methods.
+ return reflect(
+ JS('', '#.apply(#, #)', jsFunction, reflectee, positionalArguments));
}
/// Grabs hold of the class-specific invocation cache for the reflectee.
@@ -888,55 +899,94 @@ class JsInstanceMirror extends JsObjectMirror implements InstanceMirror {
return cache;
}
- /// Invoke the member specified through name and type on the reflectee.
- /// As a side-effect, this populates the class-specific invocation cache
- /// for the reflectee.
- InstanceMirror _invoke(Symbol name,
- int type,
- String reflectiveName,
- List arguments) {
+ String _computeReflectiveName(Symbol symbolName, int type,
+ List positionalArguments,
+ Map<Symbol, dynamic> namedArguments) {
+ String name = n(symbolName);
+ switch (type) {
+ case JSInvocationMirror.GETTER: return name;
+ case JSInvocationMirror.SETTER: return '$name=';
+ case JSInvocationMirror.METHOD:
+ if (namedArguments.isNotEmpty) return '$name*';
+ int nbArgs = positionalArguments.length as int;
+ return "$name:$nbArgs:0";
+ }
+ throw new RuntimeError("Could not compute reflective name for $name");
+ }
+
+ /**
+ * Returns a `CachedInvocation` or `CachedNoSuchMethodInvocation` for the
+ * given member.
+ *
+ * Caches the result.
+ */
+ _getCachedInvocation(Symbol name, int type, String reflectiveName,
+ List positionalArguments, Map<Symbol,dynamic> namedArguments) {
+
var cache = _classInvocationCache;
var cacheEntry = JsCache.fetch(cache, reflectiveName);
var result;
- Invocation invocation;
if (cacheEntry == null) {
disableTreeShaking();
String mangledName = reflectiveNames[reflectiveName];
List<String> argumentNames = const [];
- if (type == JSInvocationMirror.METHOD) {
- // Note: [argumentNames] are not what the user actually provided, it is
- // always all the named parameters.
- argumentNames = reflectiveName.split(':').skip(3).toList();
- }
// TODO(ahe): We don't need to create an invocation mirror here. The
// logic from JSInvocationMirror.getCachedInvocation could easily be
// inlined here.
- invocation = createUnmangledInvocationMirror(
- name, mangledName, type, arguments, argumentNames);
+ Invocation invocation = createUnmangledInvocationMirror(
+ name, mangledName, type, positionalArguments, argumentNames);
cacheEntry =
JSInvocationMirror.getCachedInvocation(invocation, reflectee);
JsCache.update(cache, reflectiveName, cacheEntry);
}
+ return cacheEntry;
+ }
+
+ /// Invoke the member specified through name and type on the reflectee.
+ /// As a side-effect, this populates the class-specific invocation cache
+ /// for the reflectee.
+ InstanceMirror _invoke(Symbol name,
+ int type,
+ List positionalArguments,
+ Map<Symbol,dynamic> namedArguments) {
+ String reflectiveName =
+ _computeReflectiveName(name, type, positionalArguments, namedArguments);
+
+ if (namedArguments.isNotEmpty) {
+ // TODO(floitsch): first, make sure it's not a getter.
+ return _invokeMethodWithNamedArguments(
+ reflectiveName, positionalArguments, namedArguments);
+ }
+ var cacheEntry = _getCachedInvocation(
+ name, type, reflectiveName, positionalArguments, namedArguments);
+
if (cacheEntry.isNoSuchMethod) {
- if (invocation == null) {
- String mangledName = reflectiveNames[reflectiveName];
- // TODO(ahe): Get the argument names.
- List<String> argumentNames = [];
- invocation = createUnmangledInvocationMirror(
- name, mangledName, type, arguments, argumentNames);
+ // Could be that we want to invoke a getter, or get a method.
+ if (type == JSInvocationMirror.METHOD && _instanceFieldExists(name)) {
+ return getField(name).invoke(
+ #call, positionalArguments, namedArguments);
}
+
+ if (type == JSInvocationMirror.SETTER) {
+ // For setters we report the setter name "field=".
+ name = s("${n(name)}=");
+ }
+
+ String mangledName = reflectiveNames[reflectiveName];
+ // TODO(ahe): Get the argument names.
+ List<String> argumentNames = [];
+ Invocation invocation = createUnmangledInvocationMirror(
+ name, mangledName, type, positionalArguments, argumentNames);
return reflect(cacheEntry.invokeOn(reflectee, invocation));
} else {
- return reflect(cacheEntry.invokeOn(reflectee, arguments));
+ return reflect(cacheEntry.invokeOn(reflectee, positionalArguments));
}
}
InstanceMirror setField(Symbol fieldName, Object arg) {
- String reflectiveName = '${n(fieldName)}=';
- _invoke(
- s(reflectiveName), JSInvocationMirror.SETTER, reflectiveName, [arg]);
+ _invoke(fieldName, JSInvocationMirror.SETTER, [arg], const {});
return reflect(arg);
}
@@ -964,6 +1014,15 @@ class JsInstanceMirror extends JsObjectMirror implements InstanceMirror {
/// engine to speed up cache probing.
var _getterCache = 4;
+ bool _instanceFieldExists(Symbol name) {
+ int getterType = JSInvocationMirror.GETTER;
+ String getterName =
+ _computeReflectiveName(name, getterType, const [], const {});
+ var getterCacheEntry = _getCachedInvocation(
+ name, getterType, getterName, const [], const {});
+ return !getterCacheEntry.isNoSuchMethod && !getterCacheEntry.isGetterStub;
+ }
+
InstanceMirror getField(Symbol fieldName) {
// BUG(16400): This should be a labelled block, but that makes
// dart2js crash when merging locals information in the type
@@ -996,8 +1055,9 @@ class JsInstanceMirror extends JsObjectMirror implements InstanceMirror {
InstanceMirror _getFieldSlow(Symbol fieldName) {
// First do the slow-case getter invocation. As a side-effect of this,
// the invocation cache is filled in so we can query it afterwards.
+ var result =
+ _invoke(fieldName, JSInvocationMirror.GETTER, const [], const {});
String name = n(fieldName);
- var result = _invoke(fieldName, JSInvocationMirror.GETTER, name, const []);
var cacheEntry = JsCache.fetch(_classInvocationCache, name);
if (cacheEntry.isNoSuchMethod) {
return result;
@@ -1723,6 +1783,13 @@ class JsClassMirror extends JsTypeMirror with JsObjectMirror
throw new NoSuchMethodError(this, setterSymbol(fieldName), [arg], null);
}
+ bool _staticFieldExists(Symbol fieldName) {
+ JsVariableMirror mirror = __variables[fieldName];
+ if (mirror != null) return mirror.isStatic;
+ JsMethodMirror getter = __getters[fieldName];
+ return getter != null && getter.isStatic;
+ }
+
InstanceMirror getField(Symbol fieldName) {
JsVariableMirror mirror = __variables[fieldName];
if (mirror != null && mirror.isStatic) {
@@ -1739,6 +1806,21 @@ class JsClassMirror extends JsTypeMirror with JsObjectMirror
return reflect(JS('', '#[#]', JS_CURRENT_ISOLATE(), jsName));
}
}
+ JsMethodMirror getter = __getters[fieldName];
+ if (getter != null && getter.isStatic) {
+ return reflect(getter._invoke(const [], const {}));
+ }
+ // If the fieldName designates a static function we have to return
+ // its closure.
+ JsMethodMirror method = __methods[fieldName];
+ if (method != null && method.isStatic) {
+ // We invoke the same getter that Dart code would execute. During
+ // initialization we have stored that getter on the function (so that
+ // we can find it more easily here).
+ var getter = JS("", "#['\$getter']", method._jsFunction);
+ if (getter == null) throw new UnimplementedError();
+ return reflect(JS("", "#()", getter));
+ }
// TODO(ahe): What receiver to use?
throw new NoSuchMethodError(this, fieldName, null, null);
}
@@ -1839,6 +1921,11 @@ class JsClassMirror extends JsTypeMirror with JsObjectMirror
throw new UnsupportedError('Named arguments are not implemented.');
}
JsMethodMirror mirror = __methods[memberName];
+
+ if (mirror == null && _staticFieldExists(memberName)) {
+ return getField(memberName)
+ .invoke(#call, positionalArguments, namedArguments);
+ }
if (mirror == null || !mirror.isStatic) {
// TODO(ahe): What receiver to use?
throw new NoSuchMethodError(
« no previous file with comments | « sdk/lib/_internal/lib/js_helper.dart ('k') | tests/lib/lib.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698