Index: sdk/lib/js/dartium/js_dartium.dart |
diff --git a/sdk/lib/js/dartium/js_dartium.dart b/sdk/lib/js/dartium/js_dartium.dart |
index eeecd93c492709ee57c817d4bd7f8e2631671933..3e0ea790e7eae71088a8b8c93c0c223ba6f41bfd 100644 |
--- a/sdk/lib/js/dartium/js_dartium.dart |
+++ b/sdk/lib/js/dartium/js_dartium.dart |
@@ -104,8 +104,8 @@ final _allowedMethods = new Map<Symbol, _DeclarationSet>(); |
final _allowedGetters = new Map<Symbol, _DeclarationSet>(); |
final _allowedSetters = new Map<Symbol, _DeclarationSet>(); |
-final _jsInterfaceTypes = new Set<Type>(); |
-Iterable<Type> get jsInterfaceTypes => _jsInterfaceTypes; |
+final _jsInterfaceTypes = new Set<mirrors.ClassMirror>(); |
+Iterable<mirrors.ClassMirror> get jsInterfaceTypes => _jsInterfaceTypes; |
/// A collection of methods where all methods have the same name. |
/// This class is intended to optimize whether a specific invocation is |
@@ -213,7 +213,6 @@ void registerJsInterfaces([List<Type> classes]) { |
void _registerJsInterfaces(List<Type> classes) { |
for (Type type in classes) { |
- if (!_jsInterfaceTypes.add(type)) continue; // Already registered. |
mirrors.ClassMirror typeMirror = mirrors.reflectType(type); |
typeMirror.declarations.forEach((symbol, declaration) { |
if (declaration is mirrors.MethodMirror || |
@@ -266,22 +265,33 @@ String _getJsName(mirrors.DeclarationMirror mirror) { |
try { |
var name = annotation.reflectee.name; |
return name != null ? name : ""; |
- } catch (e) { |
- } |
+ } catch (e) {} |
} |
} |
} |
return null; |
} |
-bool _hasJsName(mirrors.DeclarationMirror mirror) => |
- _getJsName(mirror) != null; |
+bool _isAnonymousClass(mirrors.ClassMirror mirror) { |
+ for (var annotation in mirror.metadata) { |
+ if (mirrors.MirrorSystem.getName(annotation.type.simpleName) == |
+ "_Anonymous") { |
+ mirrors.LibraryMirror library = annotation.type.owner; |
+ var uri = library.uri; |
+ // make sure the annotation is from package://js |
+ if (uri.scheme == 'package' && uri.path == 'js/js.dart') { |
+ return true; |
+ } |
+ } |
+ } |
+ return false; |
+} |
+bool _hasJsName(mirrors.DeclarationMirror mirror) => _getJsName(mirror) != null; |
_getJsMemberName(mirrors.DeclarationMirror mirror) { |
var name = _getJsName(mirror); |
- return name == null || name.isEmpty ? _getDeclarationName(mirror) : |
- name; |
+ return name == null || name.isEmpty ? _getDeclarationName(mirror) : name; |
} |
// TODO(jacobr): handle setters correctyl. |
@@ -301,9 +311,13 @@ String _accessJsPath(String path) => |
"${_JS_LIBRARY_PREFIX}.context${path.split(".").map((p) => "['$p']").join('')}"; |
@Deprecated("Internal Use Only") |
-void addMemberHelper(mirrors.MethodMirror declaration, String path, StringBuffer sb, {bool isStatic: false, String memberName}) { |
- var jsName = _getJsMemberName(declaration); |
- path = (path != null && path.isNotEmpty) ? "${path}.${jsName}" : jsName; |
+void addMemberHelper( |
+ mirrors.MethodMirror declaration, String path, StringBuffer sb, |
+ {bool isStatic: false, String memberName}) { |
+ if (!declaration.isConstructor) { |
+ var jsName = _getJsMemberName(declaration); |
+ path = (path != null && path.isNotEmpty) ? "${path}.${jsName}" : jsName; |
+ } |
var name = memberName != null ? memberName : _getDeclarationName(declaration); |
if (declaration.isConstructor) { |
sb.write("factory"); |
@@ -346,7 +360,7 @@ void addMemberHelper(mirrors.MethodMirror declaration, String path, StringBuffer |
// TODO(jacobr): |
sb.write(") => "); |
if (declaration.isConstructor) { |
- sb.write("new ${_JS_LIBRARY_PREFIX}.JsObject("); |
+ sb.write("new ${_JS_LIBRARY_PREFIX}.JsObject("); |
} |
sb |
..write(_accessJsPath(path)) |
@@ -362,8 +376,13 @@ void addMemberHelper(mirrors.MethodMirror declaration, String path, StringBuffer |
} |
// TODO(jacobr): make this check more robust. |
-bool _isExternal(mirrors.MethodMirror mirror) => |
- mirror.source != null && mirror.source.startsWith("external "); |
+bool _isExternal(mirrors.Mirror mirror) { |
+ /* |
+ var source = mirror.source; |
+ return source != null && source.startsWith("external "); |
+ */ |
+ return mirror.isExternal; |
+} |
List<String> _generateExternalMethods() { |
var staticCodegen = <String>[]; |
@@ -372,21 +391,134 @@ List<String> _generateExternalMethods() { |
String jsLibraryName = _getJsName(library); |
library.declarations.forEach((name, declaration) { |
if (declaration is mirrors.MethodMirror) { |
- if (_isExternal(declaration) && (_hasJsName(declaration) || jsLibraryName != null)) { |
+ if ((_hasJsName(declaration) || jsLibraryName != null) && |
+ _isExternal(declaration)) { |
+ addMemberHelper(declaration, jsLibraryName, sb); |
+ } |
+ } else if (declaration is mirrors.ClassMirror) { |
+ mirrors.ClassMirror clazz = declaration; |
+ if (_hasJsName(clazz)) { |
+ // TODO(jacobr): verify class implements JavaScriptObject. |
+ String jsClassName = _getJsMemberName(clazz); |
+ var className = mirrors.MirrorSystem.getName(clazz.simpleName); |
+ var sbPatch = new StringBuffer(); |
+ jsInterfaceTypes.add(clazz); |
+ clazz.declarations.forEach((name, declaration) { |
+ if (declaration is! mirrors.MethodMirror || |
+ !_isExternal(declaration)) return; |
+ if (declaration.isFactoryConstructor && _isAnonymousClass(clazz)) { |
+ sbPatch.write(" factory ${className}({"); |
+ int i = 0; |
+ var args = <String>[]; |
+ for (var p in declaration.parameters) { |
+ args.add(mirrors.MirrorSystem.getName(p.simpleName)); |
+ i++; |
+ } |
+ sbPatch |
+ ..write( |
+ args.map((name) => '$name:${_UNDEFINED_VAR}').join(", ")) |
+ ..write("}) {\n" |
+ " var ret = new ${_JS_LIBRARY_PREFIX}.JsObject.jsify({});\n"); |
+ i = 0; |
+ for (var p in declaration.parameters) { |
+ assert(p.isNamed); // XXX throw |
+ var name = args[i]; |
+ var jsName = mirrors.MirrorSystem.getName(p.simpleName); |
+ // XXX apply name conversion rules. |
+ sbPatch.write( |
+ " if($name != ${_UNDEFINED_VAR}) ret['$jsName'] = $name;\n"); |
+ i++; |
+ } |
+ |
+ sbPatch.write(" return ret;\n" |
+ " }\n"); |
+ } else if (declaration.isConstructor || |
+ declaration.isFactoryConstructor) { |
+ sbPatch.write(" "); |
+ addMemberHelper( |
+ declaration, |
+ (jsLibraryName != null && jsLibraryName.isNotEmpty) |
+ ? "${jsLibraryName}.${jsClassName}" |
+ : jsClassName, |
+ sbPatch, |
+ isStatic: true, |
+ memberName: className); |
+ } |
+ }); |
+ |
+ clazz.staticMembers.forEach((memberName, member) { |
+ if (_isExternal(member)) { |
+ sbPatch.write(" "); |
+ addMemberHelper( |
+ member, |
+ (jsLibraryName != null && jsLibraryName.isNotEmpty) |
+ ? "${jsLibraryName}.${jsClassName}" |
+ : jsClassName, |
+ sbPatch, |
+ isStatic: true); |
+ } |
+ }); |
+ var typeVariablesClause = ''; |
+ if (!clazz.typeVariables.isEmpty) { |
+ typeVariablesClause = |
+ '<${clazz.typeVariables.map((m) => mirrors.MirrorSystem.getName(m.simpleName)).join(',')}>'; |
+ } |
+ if (sbPatch.isNotEmpty) { |
+ sb.write(""" |
+patch class $className$typeVariablesClause { |
+$sbPatch |
+} |
+"""); |
+ } |
+ } |
+ } |
+ }); |
+ if (sb.isNotEmpty) { |
+ staticCodegen |
+ ..add(uri.toString()) |
+ ..add("${uri}_js_interop_patch.dart") |
+ ..add(""" |
+import 'dart:js' as ${_JS_LIBRARY_PREFIX}; |
+ |
+/** |
+ * Placeholder object for cases where we need to determine exactly how many |
+ * args were passed to a function. |
+ */ |
+const ${_UNDEFINED_VAR} = const Object(); |
+ |
+${sb} |
+"""); |
+ } |
+ }); |
+ |
+ return staticCodegen; |
+} |
+ |
+List<String> _generateExternalMethods2() { |
+ var staticCodegen = <String>[]; |
+ mirrors.currentMirrorSystem().libraries.forEach((uri, library) { |
+ var sb = new StringBuffer(); |
+ String jsLibraryName = _getJsName(library); |
+ library.declarations.forEach((name, declaration) { |
+ var isExternal = _isExternal(declaration); |
+ if (declaration is mirrors.MethodMirror) { |
+ if (isExternal && (_hasJsName(declaration) || jsLibraryName != null)) { |
addMemberHelper(declaration, jsLibraryName, sb); |
} |
} else if (declaration is mirrors.ClassMirror) { |
mirrors.ClassMirror clazz = declaration; |
if (_hasJsName(clazz)) { |
// TODO(jacobr): verify class implements JavaScriptObject. |
- assert(clazz.hasReflectedType); |
- jsInterfaceTypes.add(clazz.reflectedType); |
String jsClassName = _getJsMemberName(clazz); |
var className = mirrors.MirrorSystem.getName(clazz.simpleName); |
var sbPatch = new StringBuffer(); |
+ jsInterfaceTypes.add(clazz); |
clazz.declarations.forEach((name, declaration) { |
- if (declaration is! mirrors.MethodMirror || !_isExternal(declaration)) return; |
- if (declaration.isFactoryConstructor) { |
+ if (declaration is! mirrors.MethodMirror || |
+ !declaration.isAbstract || |
+ !isExternal) return; |
+ if (_hasLiteralAnnotation(declaration) && |
+ declaration.isFactoryConstructor) { |
sbPatch.write(" factory ${className}({"); |
int i = 0; |
var args = <String>[]; |
@@ -396,25 +528,31 @@ List<String> _generateExternalMethods() { |
i++; |
} |
sbPatch |
- ..write(args.map((name) => '$name:${_UNDEFINED_VAR}').join(", ")) |
+ ..write( |
+ args.map((name) => '$name:${_UNDEFINED_VAR}').join(", ")) |
..write("}) {\n" |
- " var ret = new ${_JS_LIBRARY_PREFIX}.JsObject.jsify({});\n"); |
+ " var ret = new ${_JS_LIBRARY_PREFIX}.JsObject.jsify({});\n"); |
i = 0; |
for (var p in declaration.parameters) { |
assert(p.isNamed); // XXX throw |
var name = args[i]; |
var jsName = mirrors.MirrorSystem.getName(p.simpleName); |
// XXX apply name conversion rules. |
- sbPatch.write(" if($name != ${_UNDEFINED_VAR}) ret['$jsName'] = $name;\n"); |
+ sbPatch.write( |
+ " if($name != ${_UNDEFINED_VAR}) ret['$jsName'] = $name;\n"); |
i++; |
} |
sbPatch.write(" return ret;\n" |
- " }\n"); |
- } else if (declaration.isConstructor) { |
+ " }\n"); |
+ } else if (declaration.isConstructor || |
+ declaration.isFactoryConstructor) { |
sbPatch.write(" "); |
- addMemberHelper(declaration, |
- (jsLibraryName != null && jsLibraryName.isNotEmpty) ? "${jsLibraryName}" : "", |
+ addMemberHelper( |
+ declaration, |
+ (jsLibraryName != null && jsLibraryName.isNotEmpty) |
+ ? "${jsLibraryName}.${jsClassName}" |
+ : jsClassName, |
sbPatch, |
isStatic: true, |
memberName: className); |
@@ -424,15 +562,23 @@ List<String> _generateExternalMethods() { |
clazz.staticMembers.forEach((memberName, member) { |
if (_isExternal(member)) { |
sbPatch.write(" "); |
- addMemberHelper(member, |
- (jsLibraryName != null && jsLibraryName.isNotEmpty) ? "${jsLibraryName}.${jsClassName}" : jsClassName, |
+ addMemberHelper( |
+ member, |
+ (jsLibraryName != null && jsLibraryName.isNotEmpty) |
+ ? "${jsLibraryName}.${jsClassName}" |
+ : jsClassName, |
sbPatch, |
isStatic: true); |
} |
}); |
+ var typeVariablesClause = ''; |
+ if (!clazz.typeVariables.isEmpty) { |
+ typeVariablesClause = |
+ '<${clazz.typeVariables.map((m) => mirrors.MirrorSystem.getName(m.simpleName)).join(',')}>'; |
+ } |
if (sbPatch.isNotEmpty) { |
sb.write(""" |
-patch class $className { |
+patch class $className$typeVariablesClause { |
$sbPatch |
} |
"""); |
@@ -476,8 +622,7 @@ List<String> _generateInteropPatchFiles() { |
var implementsArray = <String>[]; |
var listMirror = mirrors.reflectType(List); |
- for (var type in jsInterfaceTypes) { |
- mirrors.ClassMirror typeMirror = mirrors.reflectType(type); |
+ for (var typeMirror in jsInterfaceTypes) { |
mirrors.LibraryMirror libraryMirror = typeMirror.owner; |
var prefixName; |
if (libraryPrefixes.containsKey(libraryMirror)) { |
@@ -504,7 +649,7 @@ List<String> _generateInteropPatchFiles() { |
sb.writeln('import "${libraryMirror.uri}" as $prefix;'); |
}); |
buildImplementsClause(classes) => |
- classes.isEmpty ? "" : "implements ${classes.join(', ')}" |
+ classes.isEmpty ? "" : "implements ${classes.join(', ')}"; |
var implementsClause = buildImplementsClause(implements); |
// TODO(jacobr): only certain classes need to be implemented by |
// JsFunctionImpl. |
@@ -579,7 +724,7 @@ String _arrayJoin(List list, sep) { |
String _arrayToString(List list) => _arrayJoin(list, ","); |
int _arrayPush(List list, List args) { |
- for(var e in args) { |
+ for (var e in args) { |
list.add(e); |
} |
return list.length; |
@@ -703,13 +848,13 @@ JsObject get context { |
_maybeWrap(o) { |
var wrapped = html_common.wrap_jso_no_SerializedScriptvalue(o); |
if (identical(wrapped, o)) return o; |
- return (wrapped is html.Blob |
- || wrapped is html.Event |
- || wrapped is indexed_db.KeyRange |
- || wrapped is html.ImageData |
- || wrapped is html.Node |
- || wrapped is TypedData |
- || wrapped is html.Window) ? wrapped : o; |
+ return (wrapped is html.Blob || |
+ wrapped is html.Event || |
+ wrapped is indexed_db.KeyRange || |
+ wrapped is html.ImageData || |
+ wrapped is html.Node || |
+ wrapped is TypedData || |
+ wrapped is html.Window) ? wrapped : o; |
} |
/** |
@@ -737,10 +882,9 @@ void setDartHtmlWrapperFor(JsObject object, wrapper) { |
*/ |
@Deprecated("Internal Use Only") |
unwrap_jso(dartClass_instance) { |
- if (dartClass_instance is html.DartHtmlDomObject) |
- return dartClass_instance.blink_jsObject; |
- else |
- return dartClass_instance; |
+ if (dartClass_instance is html.DartHtmlDomObject && |
+ dartClass_instance is! JsObject) return dartClass_instance.blink_jsObject; |
+ else return dartClass_instance; |
} |
/** |
@@ -764,15 +908,15 @@ class JsObject extends NativeFieldWrapperClass2 { |
*/ |
factory JsObject(JsFunction constructor, [List arguments]) { |
try { |
- return _create(constructor, arguments); |
+ return html_common.unwrap_jso(_create(constructor, arguments)); |
} catch (e) { |
// Re-throw any errors (returned as a string) as a DomException. |
throw new html.DomException.jsInterop(e); |
} |
} |
- static JsObject _create( |
- JsFunction constructor, arguments) native "JsObject_constructorCallback"; |
+ static JsObject _create(JsFunction constructor, arguments) |
+ native "JsObject_constructorCallback"; |
_buildArgs(Invocation invocation) { |
if (invocation.namedArguments.isEmpty) { |
@@ -839,6 +983,7 @@ class JsObject extends NativeFieldWrapperClass2 { |
throw new html.DomException.jsInterop(e); |
} |
} |
+ |
_operator_getter(property) native "JsObject_[]"; |
/** |
@@ -855,6 +1000,7 @@ class JsObject extends NativeFieldWrapperClass2 { |
throw new html.DomException.jsInterop(e); |
} |
} |
+ |
_operator_setter(property, value) native "JsObject_[]="; |
int get hashCode native "JsObject_hashCode"; |
@@ -868,8 +1014,8 @@ class JsObject extends NativeFieldWrapperClass2 { |
return is_JsObject && _identityEquality(this, other); |
} |
- static bool _identityEquality( |
- JsObject a, JsObject b) native "JsObject_identityEquality"; |
+ static bool _identityEquality(JsObject a, JsObject b) |
+ native "JsObject_identityEquality"; |
/** |
* Returns `true` if the JavaScript object contains the specified property |
@@ -1019,7 +1165,7 @@ class JsFunction extends JsObject implements Function { |
* supplied it is the value of `this` for the invocation. |
*/ |
dynamic apply(List args, {thisArg}) => |
- _maybeWrap(_apply(args, thisArg: thisArg)); |
+ _maybeWrap(_apply(args, thisArg: thisArg)); |
dynamic _apply(List args, {thisArg}) native "JsFunction_apply"; |
@@ -1036,8 +1182,8 @@ class JsFunction extends JsObject implements Function { |
* efficiently implemented in Dart2Js so should only be used by internal |
* tools. |
*/ |
- _applyDebuggerOnly(List args, |
- {thisArg}) native "JsFunction_applyDebuggerOnly"; |
+ _applyDebuggerOnly(List args, {thisArg}) |
+ native "JsFunction_applyDebuggerOnly"; |
static JsFunction _withThis(Function f) native "JsFunction_withThis"; |
} |
@@ -1055,8 +1201,8 @@ class JsArray<E> extends JsObject with ListMixin<E> { |
factory JsArray.from(Iterable<E> other) => |
_newJsArrayFromSafeList(new List.from(other)); |
- static JsArray _newJsArrayFromSafeList( |
- List list) native "JsArray_newJsArrayFromSafeList"; |
+ static JsArray _newJsArrayFromSafeList(List list) |
+ native "JsArray_newJsArrayFromSafeList"; |
_checkIndex(int index, {bool insert: false}) { |
int length = insert ? this.length + 1 : this.length; |
@@ -1158,11 +1304,19 @@ List _stripUndefinedArgs(List args) => |
* Returns a method that can be called with an arbitrary number (for n less |
* than 11) of arguments without violating Dart type checks. |
*/ |
-Function _wrapAsDebuggerVarArgsFunction(JsFunction jsFunction) => |
- ([a1 = _UNDEFINED, a2 = _UNDEFINED, a3 = _UNDEFINED, a4 = _UNDEFINED, |
- a5 = _UNDEFINED, a6 = _UNDEFINED, a7 = _UNDEFINED, a8 = _UNDEFINED, |
- a9 = _UNDEFINED, a10 = _UNDEFINED]) => jsFunction._applyDebuggerOnly( |
- _stripUndefinedArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10])); |
+Function _wrapAsDebuggerVarArgsFunction(JsFunction jsFunction) => ( |
+ [a1 = _UNDEFINED, |
+ a2 = _UNDEFINED, |
+ a3 = _UNDEFINED, |
+ a4 = _UNDEFINED, |
+ a5 = _UNDEFINED, |
+ a6 = _UNDEFINED, |
+ a7 = _UNDEFINED, |
+ a8 = _UNDEFINED, |
+ a9 = _UNDEFINED, |
+ a10 = _UNDEFINED]) => |
+ jsFunction._applyDebuggerOnly( |
+ _stripUndefinedArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10])); |
// The allowInterop method is a no-op in Dartium. |
// TODO(jacobr): tag methods so we can throw if a Dart method is passed to |