Chromium Code Reviews| 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..60dac4bf73239c46cf48c3a4e5336234a8af1620 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 || |
| @@ -274,6 +273,20 @@ String _getJsName(mirrors.DeclarationMirror mirror) { |
| return 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; |
| @@ -302,8 +315,10 @@ String _accessJsPath(String path) => |
| @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; |
| + 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"); |
| @@ -362,8 +377,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 +392,119 @@ 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. |
| - 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.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. |
| + 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 || !declaration.isAbstract || !isExternal) return; |
| + if (_hasLiteralAnnotation(declaration) && declaration.isFactoryConstructor) { |
| sbPatch.write(" factory ${className}({"); |
| int i = 0; |
| var args = <String>[]; |
| @@ -411,10 +529,10 @@ List<String> _generateExternalMethods() { |
| sbPatch.write(" return ret;\n" |
| " }\n"); |
| - } else if (declaration.isConstructor) { |
| + } else if (declaration.isConstructor || declaration.isFactoryConstructor) { |
| sbPatch.write(" "); |
| addMemberHelper(declaration, |
| - (jsLibraryName != null && jsLibraryName.isNotEmpty) ? "${jsLibraryName}" : "", |
| + (jsLibraryName != null && jsLibraryName.isNotEmpty) ? "${jsLibraryName}.${jsClassName}" : jsClassName, |
| sbPatch, |
| isStatic: true, |
| memberName: className); |
| @@ -430,9 +548,13 @@ List<String> _generateExternalMethods() { |
| 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 +598,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)) { |
| @@ -737,7 +858,7 @@ void setDartHtmlWrapperFor(JsObject object, wrapper) { |
| */ |
| @Deprecated("Internal Use Only") |
| unwrap_jso(dartClass_instance) { |
| - if (dartClass_instance is html.DartHtmlDomObject) |
| + if (dartClass_instance is html.DartHtmlDomObject && dartClass_instance is! JsObject) |
|
Alan Knight
2015/10/30 00:38:58
There's a way it can be both?
Jacob
2015/10/30 00:41:24
yep... and not just by accident.
@JS
class MyPoly
|
| return dartClass_instance.blink_jsObject; |
| else |
| return dartClass_instance; |
| @@ -764,7 +885,7 @@ 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); |