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

Unified Diff: sdk/lib/html/html_common/conversions_dartium.dart

Issue 1832713002: Optimize dartium dart:html bindings so real world application performance is acceptable. Improves d… (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: update cached patches Created 4 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 side-by-side diff with in-line comments
Download patch
Index: sdk/lib/html/html_common/conversions_dartium.dart
diff --git a/sdk/lib/html/html_common/conversions_dartium.dart b/sdk/lib/html/html_common/conversions_dartium.dart
index 66299a05389fd4c7b79a0ef086ac052eccdd82ec..ef02c00b649893a847584e2d827e179424b73e14 100644
--- a/sdk/lib/html/html_common/conversions_dartium.dart
+++ b/sdk/lib/html/html_common/conversions_dartium.dart
@@ -7,11 +7,11 @@ convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) =>
new _AcceptStructuredCloneDartium().convertNativeToDart_AcceptStructuredClone(object, mustCopy: mustCopy);
class _StructuredCloneDartium extends _StructuredClone {
- newJsMap() => new js.JsObject(js.context["Object"]);
- putIntoMap(map, key, value) => map[key] = value;
- // TODO(alanknight): Don't create two extra lists to get a fixed-length JS list.
- newJsList(length) => new js.JsArray.from(new List(length));
- cloneNotRequired(e) => e is js.JsObject;
+ newJsMap() => js.JsNative.newObject();
+ putIntoMap(map, key, value) => js.JsNative.setProperty(map, key, value);
+ newJsList(length) => js.JsNative.newArray()..length = length;
+ cloneNotRequired(e) =>
+ e is js.JSObject || e is TypedData || e is ByteBuffer;
}
/// A version of _AcceptStructuredClone, but using a different algorithm
@@ -24,15 +24,14 @@ class _StructuredCloneDartium extends _StructuredClone {
class _AcceptStructuredCloneDartium {
newDartList(length) => new List(length);
- // JsObjects won't be identical, but will be equal only if the underlying
- // Js entities are identical.
- bool identicalInJs(a, b) =>
- (a is js.JsObject) ? a == b : identical(a, b);
+ // As long as we stick to JSObject instead of intermingling legacy JsObject,
+ // we can simply use identical.
+ bool identicalInJs(a, b) => identical(a, b);
void forEachJsField(jsObject, action) {
- var keys = js.context["Object"].callMethod("keys", [jsObject]);
+ var keys = js.JsNative.callMethod(_object, "keys", [jsObject]);
for (var key in keys) {
- action(key, jsObject[key]);
+ action(key, js.JsNative.getProperty(jsObject, key));
}
}
@@ -52,10 +51,7 @@ class _AcceptStructuredCloneDartium {
if (e is bool) return e;
if (e is num) return e;
if (e is String) return e;
-
- if (isJavaScriptDate(e)) {
- return convertNativeToDart_DateTime(e);
- }
+ if (e is DateTime) return e;
if (isJavaScriptRegExp(e)) {
// TODO(sra).
@@ -106,51 +102,60 @@ class _AcceptStructuredCloneDartium {
}
}
-final _dateConstructor = js.context["Date"];
-final _regexConstructor = js.context["RegExp"];
+final _dateConstructor = js.JsNative.getProperty(window, "Date");
+final _regexConstructor = js.JsNative.getProperty(window, "RegExp");
-bool isJavaScriptDate(value) => value is js.JsObject && value.instanceof(_dateConstructor);
-bool isJavaScriptRegExp(value) => value is js.JsObject && value.instanceof(_regexConstructor);
-bool isJavaScriptArray(value) => value is js.JsArray;
+bool isJavaScriptDate(value) => value is js.JSObject && js.JsNative.instanceof(value, _dateConstructor);
+bool isJavaScriptRegExp(value) => value is js.JSObject && js.JsNative.instanceof(value, _regexConstructor);
+bool isJavaScriptArray(value) => value is js.JSArray;
-final _object = js.context["Object"];
-final _getPrototypeOf = _object["getPrototypeOf"];
+final _object = js.JsNative.getProperty(window, "Object");
+final _getPrototypeOf = js.JsNative.getProperty(_object, "getPrototypeOf");
_getProto(object) {
- return _getPrototypeOf.apply([object]);
+ return _getPrototypeOf(object);
}
-final _objectProto = js.context["Object"]["prototype"];
+final _objectProto = js.JsNative.getProperty(_object, "prototype");
bool isJavaScriptSimpleObject(value) {
- if (value is! js.JsObject) return false;
+ if (value is! js.JSObject) return false;
var proto = _getProto(value);
return proto == _objectProto || proto == null;
}
+
+// TODO(jacobr): this makes little sense unless we are doing something
+// ambitious to make Dartium and Dart2Js interop well with each other.
bool isImmutableJavaScriptArray(value) =>
- isJavaScriptArray(value) && value["immutable$list"] != null;
+ isJavaScriptArray(value) && js.JsNative.getProperty(value, "immutable$list") != null;
-final _promiseConstructor = js.context['Promise'];
-bool isJavaScriptPromise(value) => value is js.JsObject && value['constructor'] == _promiseConstructor;
+final _promiseConstructor = js.JsNative.getProperty(window, 'Promise');
+bool isJavaScriptPromise(value) => value is js.JSObject && identical(js.JsNative.getProperty(value, 'constructor'), _promiseConstructor);
-Future convertNativePromiseToDartFuture(js.JsObject promise) {
+Future convertNativePromiseToDartFuture(js.JSObject promise) {
var completer = new Completer();
- var newPromise = promise
- .callMethod("then", [(result) => completer.complete(result)])
- .callMethod("catch", [(result) => completer.completeError(result)]);
+ var newPromise = js.JsNative.callMethod(js.JsNative.callMethod(promise,
+ "then", [js.allowInterop((result) => completer.complete(result))]),
+ "catch", [js.allowInterop((result) => completer.completeError(result))]);
return completer.future;
}
convertDartToNative_DateTime(DateTime date) {
- return new js.JsObject(js.context["Date"], [date.millisecondsSinceEpoch]);
+ return date;
}
/// Creates a Dart Rectangle from a Javascript object with properties
-/// left, top, width and height. Used internally in Dartium.
-Rectangle make_dart_rectangle(r) =>
- r == null ? null : new Rectangle(
- js.JsNative.getProperty(r, 'left'),
- js.JsNative.getProperty(r, 'top'),
- js.JsNative.getProperty(r, 'width'),
- js.JsNative.getProperty(r, 'height'));
+/// left, top, width and height or a 4 element array of integers. Used internally in Dartium.
+Rectangle make_dart_rectangle(r) {
+ if (r == null) return null;
+ if (r is List) {
+ return new Rectangle(r[0], r[1], r[2], r[3]);
+ }
+
+ return new Rectangle(
+ js.JsNative.getProperty(r, 'left'),
+ js.JsNative.getProperty(r, 'top'),
+ js.JsNative.getProperty(r, 'width'),
+ js.JsNative.getProperty(r, 'height'));
+}
// Converts a flat Dart map into a JavaScript object with properties this is
// is the Dartium only version it uses dart:js.
@@ -158,16 +163,16 @@ Rectangle make_dart_rectangle(r) =>
// code in html_common and be more general.
convertDartToNative_Dictionary(Map dict) {
if (dict == null) return null;
- var jsObject = new js.JsObject(js.JsNative.getProperty(js.context, 'Object'));
+ var jsObject = js.JsNative.newObject();
dict.forEach((String key, value) {
if (value is List) {
- var jsArray = new js.JsArray();
+ var jsArray = js.JsNative.newArray();
value.forEach((elem) {
jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem);
});
- jsObject[key] = jsArray;
+ js.JsNative.setProperty(jsObject, key, jsArray);
} else {
- jsObject[key] = value;
+ js.JsNative.setProperty(jsObject, key, value);
}
});
return jsObject;
@@ -196,8 +201,15 @@ class _ReturnedDictionary {
// Helper function to wrapped a returned dictionary from blink to a Dart looking
// class.
-convertNativeDictionaryToDartDictionary(Map values) =>
- values != null ? new _ReturnedDictionary(values) : null;
+convertNativeDictionaryToDartDictionary(values) {
+ if (values is! Map) {
+ // TODO(jacobr): wish wwe didn't have to do this.
+ values = convertNativeToDart_SerializedScriptValue(values);
+ }
+ return values != null ? new _ReturnedDictionary(values) : null;
+}
+
+convertNativeToDart_Dictionary(values) => convertNativeToDart_SerializedScriptValue(values);
// Conversion function place holder (currently not used in dart2js or dartium).
List convertDartToNative_StringArray(List<String> input) => input;
@@ -205,284 +217,59 @@ List convertDartToNative_StringArray(List<String> input) => input;
// Converts a Dart list into a JsArray. For the Dartium version only.
convertDartToNative_List(List input) => new js.JsArray()..addAll(input);
-/// Find the underlying JS object for a dart:html Dart object.
-unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance);
-
-// Flag to disable JS interop asserts. Setting to false will speed up the
-// wrap_jso calls.
-bool interop_checks = false;
-
-/// Wrap a JS object with an instance of the matching dart:html class. Used only in Dartium.
-wrap_jso(jsObject) {
+// Incredibly slow implementation to lookup the runtime type for an object.
+// Fortunately, performance doesn't matter much as the results are cached
+// as long as the object being looked up has a valid prototype.
+// TODO(jacobr): we should track the # of lookups to ensure that things aren't
+// going off the rails due to objects with null prototypes, etc.
+// Note: unlike all other methods in this class, here we intentionally use
+// the old JsObject types to bootstrap the new typed bindings.
+Type lookupType(js.JsObject jsObject, bool isElement) {
try {
- if (jsObject is! js.JsObject || jsObject == null) {
- // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
- // or it's a simple type.
- return jsObject;
- }
-
- var wrapper = js.getDartHtmlWrapperFor(jsObject);
- // if we have a wrapper return the Dart instance.
- if (wrapper != null) {
- return wrapper;
- }
-
- if (jsObject is js.JsArray) {
- wrapper = new js.JSArray.create(jsObject);
- js.setDartHtmlWrapperFor(jsObject, wrapper);
- return wrapper;
- }
- if (jsObject is js.JsFunction) {
- wrapper = new js.JSFunction.create(jsObject);
- js.setDartHtmlWrapperFor(jsObject, wrapper);
- return wrapper;
- }
-
- // Try the most general type conversions on it.
- // TODO(alanknight): We may be able to do better. This maintains identity,
- // which is useful, but expensive. And if we nest something that only
- // this conversion handles, how does that work? e.g. a list of maps of elements.
- var converted = convertNativeToDart_SerializedScriptValue(jsObject);
- if (!identical(converted, jsObject)) {
- return converted;
- }
+ // TODO(jacobr): add static methods that return the runtime type of the patch
+ // class so that this code works as expected.
+ if (jsObject is js.JsArray) {
+ return js.JSArray.instanceRuntimeType;
+ }
+ if (jsObject is js.JsFunction) {
+ return js.JSFunction.instanceRuntimeType;
+ }
var constructor = js.JsNative.getProperty(jsObject, 'constructor');
if (constructor == null) {
// Perfectly valid case for JavaScript objects where __proto__ has
// intentionally been set to null.
- js.setDartHtmlWrapperFor(jsObject, new js.JSObject.create(jsObject));
- return jsObject;
+ // We should track and warn about this case as peformance will be poor.
+ return js.JSObject.instanceRuntimeType;
}
var jsTypeName = js.JsNative.getProperty(constructor, 'name');
if (jsTypeName is! String || jsTypeName.length == 0) {
// Not an html type.
- wrapper = new js.JSObject.create(jsObject);
- js.setDartHtmlWrapperFor(jsObject, wrapper);
- return wrapper;
+ return js.JSObject.instanceRuntimeType;
}
var dartClass_instance;
var customElementClass = null;
- var extendsTag = "";
- var custom = getCustomElementEntry(jsObject);
- if (custom != null) {
- customElementClass = custom['type'];
- extendsTag = custom['extends'];
- }
-
- // Only allow custom elements to be created in the html or svg default
- // namespace.
- var func;
- var defaultNS = jsObject['namespaceURI'] == 'http://www.w3.org/1999/xhtml' ||
- jsObject['namespaceURI'] == 'http://www.w3.org/2000/svg';
- if (customElementClass != null && extendsTag == "" && defaultNS) {
- // The customElementClass is known but we can't create the real class so
- // create the HtmlElement and it will get upgraded when registerElement's
- // createdCallback is called.
- func = getHtmlCreateFunction('HTMLElement');
- } else {
- func = getHtmlCreateFunction(jsTypeName);
- if (func == null) {
- // Start walking the prototype chain looking for a JS class.
- var prototype = jsObject['__proto__'];
- var keepWalking = true;
- while (keepWalking && prototype.hasProperty('__proto__')) {
- prototype = prototype['__proto__'];
- if (prototype != null && prototype is Element &&
- prototype.blink_jsObject != null) {
- // We're a Dart class that's pointing to a JS class.
- var blinkJso = prototype.blink_jsObject;
- jsTypeName = blinkJso['constructor']['name'];
- func = getHtmlCreateFunction(jsTypeName);
- keepWalking = func == null;
- }
- }
+ var extendsTag = "";
+
+ Type type = getHtmlCreateType(jsTypeName);
+ if (type != null) return type;
+
+ // Start walking the prototype chain looking for a JS class.
+ var prototype = js.JsNative.getProperty(jsObject, '__proto__');
+ while (prototype != null) {
+ // We're a Dart class that's pointing to a JS class.
+ var constructor = js.JsNative.getProperty(prototype, 'constructor');
+ if (constructor != null) {
+ jsTypeName = js.JsNative.getProperty(constructor, 'name');
+ type = getHtmlCreateType(jsTypeName);
+ if (type != null) return type;
}
+ prototype = js.JsNative.getProperty(prototype, '__proto__');
}
-
- // Can we construct a Dart class?
- if (func != null) {
- dartClass_instance = func();
-
- // Wrap our Dart instance in both directions.
- dartClass_instance.blink_jsObject = jsObject;
- js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
- }
-
- // TODO(jacobr): cache that this is not a dart:html JS class.
- return dartClass_instance;
- } catch (e, stacktrace) {
- if (interop_checks) {
- if (e is DebugAssertException) window.console
- .log("${e.message}\n ${stacktrace}");
- else window.console.log("${stacktrace}");
- }
- }
-
- return null;
-}
-
-/**
- * Create Dart class that maps to the JS Type, add the JsObject as an expando
- * on the Dart class and return the created Dart class.
- */
-wrap_jso_no_SerializedScriptvalue(jsObject) {
- try {
- if (jsObject is! js.JsObject || jsObject == null) {
- // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
- // or it's a simple type.
- return jsObject;
- }
-
- // TODO(alanknight): With upgraded custom elements this causes a failure because
- // we need a new wrapper after the type changes. We could possibly invalidate this
- // if the constructor name didn't match?
- var wrapper = js.getDartHtmlWrapperFor(jsObject);
- if (wrapper != null) {
- return wrapper;
- }
-
- if (jsObject is js.JsArray) {
- wrapper = new js.JSArray.create(jsObject);
- js.setDartHtmlWrapperFor(jsObject, wrapper);
- return wrapper;
- }
- if (jsObject is js.JsFunction) {
- wrapper = new js.JSFunction.create(jsObject);
- js.setDartHtmlWrapperFor(jsObject, wrapper);
- return wrapper;
- }
-
- var constructor = js.JsNative.getProperty(jsObject, 'constructor');
- if (constructor == null) {
- // Perfectly valid case for JavaScript objects where __proto__ has
- // intentionally been set to null.
- js.setDartHtmlWrapperFor(jsObject, new js.JSObject.create(jsObject));
- return jsObject;
- }
- var jsTypeName = js.JsNative.getProperty(constructor, 'name');
- if (jsTypeName is! String || jsTypeName.length == 0) {
- // Not an html type.
- wrapper = new js.JSObject.create(jsObject);
- js.setDartHtmlWrapperFor(jsObject, wrapper);
- return wrapper;
- }
-
- var func = getHtmlCreateFunction(jsTypeName);
- if (func != null) {
- var dartClass_instance = func();
- dartClass_instance.blink_jsObject = jsObject;
- js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
- return dartClass_instance;
- }
- wrapper = new js.JSObject.create(jsObject);
- js.setDartHtmlWrapperFor(jsObject, wrapper);
- return wrapper;
} catch (e, stacktrace) {
- if (interop_checks) {
- if (e is DebugAssertException) window.console
- .log("${e.message}\n ${stacktrace}");
- else window.console.log("${stacktrace}");
- }
- }
-
- return null;
-}
-
-/**
- * Create Dart class that maps to the JS Type that is the JS type being
- * extended using JS interop createCallback (we need the base type of the
- * custom element) not the Dart created constructor.
- */
-wrap_jso_custom_element(jsObject) {
- try {
- if (jsObject is! js.JsObject) {
- // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
- return jsObject;
- }
-
- // Find out what object we're extending.
- var objectName = jsObject.toString();
- // Expect to see something like '[object HTMLElement]'.
- if (!objectName.startsWith('[object ')) {
- return jsObject;
- }
-
- var extendsClass = objectName.substring(8, objectName.length - 1);
- var func = getHtmlCreateFunction(extendsClass);
- if (interop_checks)
- debug_or_assert("func != null name = ${extendsClass}", func != null);
- var dartClass_instance = func();
- dartClass_instance.blink_jsObject = jsObject;
- return dartClass_instance;
- } catch(e, stacktrace){
- if (interop_checks) {
- if (e is DebugAssertException)
- window.console.log("${e.message}\n ${stacktrace}");
- else
- window.console.log("${stacktrace}");
- }
-
- // Problem?
- return null;
- }
-}
-
-getCustomElementEntry(element) {
- var hasAttribute = false;
-
- var jsObject;
- var tag = "";
- var runtimeType = element.runtimeType;
- if (runtimeType == HtmlElement) {
- tag = element.localName;
- } else if (runtimeType == TemplateElement) {
- // Data binding with a Dart class.
- tag = element.attributes['is'];
- } else if (runtimeType == js.JsObject) {
- // It's a Polymer core element (written in JS).
- // Make sure it's an element anything else we can ignore.
- if (element.hasProperty('nodeType') && element['nodeType'] == 1) {
- if (js.JsNative.callMethod(element, 'hasAttribute', ['is'])) {
- hasAttribute = true;
- // It's data binding use the is attribute.
- tag = js.JsNative.callMethod(element, 'getAttribute', ['is']);
- } else {
- // It's a custom element we want the local name.
- tag = element['localName'];
- }
- }
- } else {
- throw new UnsupportedError(
- 'Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObject.');
- }
-
- var entry = _knownCustomElements[tag];
- if (entry != null) {
- // If there's an 'is' attribute then check if the extends tag registered
- // matches the tag if so then return the entry that's registered for this
- // extendsTag or if there's no 'is' tag then return the entry found.
- if ((hasAttribute && entry['extends'] == tag) || !hasAttribute) {
- return entry;
- }
- }
-
- return null;
-}
-
-// List of known tagName to DartClass for custom elements, used for upgrade.
-var _knownCustomElements = new Map<String, Map<Type, String>>();
-
-void addCustomElementType(String tagName, Type dartClass, [String extendTag]) {
- _knownCustomElements[tagName] =
- {'type': dartClass, 'extends': extendTag != null ? extendTag : "" };
-}
-
-Type getCustomElementType(object) {
- var entry = getCustomElementEntry(object);
- if (entry != null) {
- return entry['type'];
+ if (e is DebugAssertException) print("${e.message}\n ${stacktrace}");
+ else print("${stacktrace}");
}
- return null;
+ return js.JSObject.instanceRuntimeType;
}
« no previous file with comments | « sdk/lib/html/html_common/conversions_dart2js.dart ('k') | sdk/lib/indexed_db/dartium/indexed_db_dartium.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698