| 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
|
|
|