Index: sdk/lib/_internal/lib/native_helper.dart |
diff --git a/sdk/lib/_internal/lib/native_helper.dart b/sdk/lib/_internal/lib/native_helper.dart |
index 5c311f4f69196f764bb7acc1d9aec14534964db1..547061100cf01550eb023cbfa25b1013a5b8bae8 100644 |
--- a/sdk/lib/_internal/lib/native_helper.dart |
+++ b/sdk/lib/_internal/lib/native_helper.dart |
@@ -240,10 +240,17 @@ var interceptorsByTag; |
/// A JavaScript object mapping tags to `true` or `false`. |
var leafTags; |
+/// A JavaScript list mapping subclass interceptor constructors to the native |
+/// superclass tag. |
+var interceptorToTag; |
+ |
/** |
- * Associates tags with an interceptor. Called from generated code. The tags |
- * are all 'leaf' tags representing classes that have no subclasses with |
- * different behaviour. |
+ * Associates dispatch tags (JavaScript constructor names e.g. DOM interface |
+ * names like HTMLDivElement) with an interceptor. Called from generated code |
+ * during initial isolate definition. |
+ * |
+ * The tags are all 'leaf' tags representing classes that have no subclasses |
+ * with different behaviour. |
* |
* [tags] is a string of `|`-separated tags. |
*/ |
@@ -252,14 +259,45 @@ void defineNativeMethods(String tags, interceptorClass) { |
} |
/** |
- * Associates tags with an interceptor. Called from generated code. The tags |
- * are all non-'leaf' tags, representing classes that have a subclass with |
- * different behaviour. |
+ * Associates dispatch tags (JavaScript constructor names e.g. DOM interface |
+ * names like HTMLElement) with an interceptor. Called from generated code |
+ * during initial isolate definition. |
+ * |
+ * The tags are all non-'leaf' tags, representing classes that have a subclass |
+ * with different behaviour. |
*/ |
void defineNativeMethodsNonleaf(String tags, interceptorClass) { |
defineNativeMethodsCommon(tags, interceptorClass, false); |
} |
+/** |
+ * Associates dispatch tags (JavaScript constructor names e.g. DOM interface |
+ * names like HTMLElement) with an interceptor. Called from generated code |
+ * during initial isolate definition. |
+ * |
+ * The tags are all non-'leaf' tags, representing classes that have a user |
+ * defined subclass that requires additional dispatch. |
+ * [subclassInterceptorClasses] is a list of interceptor classes |
+ * (i.e. constructors) for the user defined subclasses. |
+ */ |
+void defineNativeMethodsExtended(String tags, interceptorClass, |
+ subclassInterceptorClasses) { |
+ if (interceptorToTag == null) { |
+ interceptorToTag = []; |
+ } |
+ List classes = JS('JSFixedArray', '#', subclassInterceptorClasses); |
+ for (int i = 0; i < classes.length; i++) { |
+ interceptorToTag.add(classes[i]); |
+ // 'tags' is a single tag. |
+ interceptorToTag.add(tags); |
+ } |
+ |
+ defineNativeMethodsCommon(tags, interceptorClass, false); |
+} |
+ |
+// TODO(sra): Try to encode all the calls to defineNativeMethodsXXX as pure |
+// data. The challenge is that the calls remove a lot of redundancy that is |
+// expanded by the loops in these methods. |
void defineNativeMethodsCommon(String tags, var interceptorClass, bool isLeaf) { |
var methods = JS('', '#.prototype', interceptorClass); |
if (interceptorsByTag == null) interceptorsByTag = JS('=Object', '{}'); |
@@ -280,6 +318,14 @@ void defineNativeMethodsFinish() { |
// classes over unknown. |
} |
+String findDispatchTagForInterceptorClass(interceptorClassConstructor) { |
+ if (interceptorToTag == null) return null; |
+ int i = |
+ JS('int', '#.indexOf(#)', interceptorToTag, interceptorClassConstructor); |
+ if (i < 0) return null; |
+ return JS('', '#[#]', interceptorToTag, i + 1); |
+} |
+ |
lookupInterceptor(var hasOwnPropertyFunction, String tag) { |
var map = interceptorsByTag; |
if (map == null) return null; |
@@ -313,11 +359,23 @@ lookupDispatchRecord(obj) { |
var isLeaf = |
(leafTags != null) && JS('bool', '(#[#]) === true', leafTags, tag); |
if (isLeaf) { |
- var fieldName = JS_IS_INDEXABLE_FIELD_NAME(); |
- bool indexability = JS('bool', r'!!#[#]', interceptor, fieldName); |
- return makeDispatchRecord(interceptor, false, null, indexability); |
+ return makeLeafDispatchRecord(interceptor); |
} else { |
var proto = JS('', 'Object.getPrototypeOf(#)', obj); |
return makeDispatchRecord(interceptor, proto, null, null); |
} |
} |
+ |
+makeLeafDispatchRecord(interceptor) { |
+ var fieldName = JS_IS_INDEXABLE_FIELD_NAME(); |
+ bool indexability = JS('bool', r'!!#[#]', interceptor, fieldName); |
+ return makeDispatchRecord(interceptor, false, null, indexability); |
+} |
+ |
+/** |
+ * [proto] should have no shadowing prototypes that are not also assigned a |
+ * dispatch rescord. |
+ */ |
+setNativeSubclassDispatchRecord(proto, interceptor) { |
+ setDispatchProperty(proto, makeLeafDispatchRecord(interceptor)); |
+} |