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

Unified Diff: pkg/compiler/lib/src/js_backend/native_data.dart

Issue 2738513007: Split NativeDataImpl (Closed)
Patch Set: Created 3 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: pkg/compiler/lib/src/js_backend/native_data.dart
diff --git a/pkg/compiler/lib/src/js_backend/native_data.dart b/pkg/compiler/lib/src/js_backend/native_data.dart
index 283e16d1d08c1804d4cedd58eff5807cc71ce5ae..9eedad7698bfc043c950aa6f959e6708b7eb5749 100644
--- a/pkg/compiler/lib/src/js_backend/native_data.dart
+++ b/pkg/compiler/lib/src/js_backend/native_data.dart
@@ -8,6 +8,7 @@ import '../common.dart';
import '../elements/elements.dart' show ClassElement;
import '../elements/entities.dart';
import '../native/behavior.dart' show NativeBehavior;
+import '../util/util.dart';
/// Basic information for native classes and methods and js-interop
/// classes.
@@ -21,6 +22,12 @@ abstract class NativeClassData {
/// mechanism allowed for user libraries.
bool isNativeClass(ClassEntity element);
+ /// Returns the list of non-directive native tag words for [cls].
+ List<String> getNativeTagsOfClass(ClassEntity cls);
+
+ /// Returns `true` if [cls] has a `!nonleaf` tag word.
+ bool hasNativeTagsForcedNonLeaf(ClassEntity cls);
+
/// Returns `true` if [element] or any of its superclasses is native.
bool isNativeOrExtendsNative(ClassEntity element);
@@ -66,12 +73,6 @@ abstract class NativeData extends NativeClassData {
/// names for the library and/or the enclosing class.
String getFixedBackendMethodPath(FunctionEntity element);
- /// Returns the list of non-directive native tag words for [cls].
- List<String> getNativeTagsOfClass(ClassEntity cls);
-
- /// Returns `true` if [cls] has a `!nonleaf` tag word.
- bool hasNativeTagsForcedNonLeaf(ClassEntity cls);
-
/// Returns `true` if [element] is a JsInterop method.
bool isJsInteropMember(MemberEntity element);
@@ -116,9 +117,6 @@ abstract class NativeDataBuilder {
/// Registers the [behavior] for writing to the native [field].
void setNativeFieldStoreBehavior(FieldEntity field, NativeBehavior behavior);
- /// Returns the list of native tag words for [cls].
- List<String> getNativeTagsOfClassRaw(ClassEntity cls);
-
/// Returns [element] as an explicit part of JsInterop. The js interop name is
/// expected to be computed later.
void markAsJsInteropMember(MemberEntity element);
@@ -137,21 +135,96 @@ abstract class NativeDataBuilder {
void setJsInteropMemberName(MemberEntity element, String name);
}
-class NativeDataImpl
- implements NativeData, NativeDataBuilder, NativeClassDataBuilder {
- /// The JavaScript names for elements implemented via typed JavaScript
- /// interop.
- Map<LibraryEntity, String> jsInteropLibraryNames = <LibraryEntity, String>{};
- Map<ClassEntity, String> jsInteropClassNames = <ClassEntity, String>{};
- Map<MemberEntity, String> jsInteropMemberNames = <MemberEntity, String>{};
+class NativeClassDataImpl implements NativeClassDataBuilder, NativeClassData {
+ /// Tag info for native JavaScript classes names. See
+ /// [setNativeClassTagInfo].
+ Map<ClassEntity, NativeClassTag> nativeClassTagInfo =
+ <ClassEntity, NativeClassTag>{};
+
+ /// The JavaScript libraries implemented via typed JavaScript interop.
+ Set<LibraryEntity> jsInteropLibraries = new Set<LibraryEntity>();
+
+ /// The JavaScript classes implemented via typed JavaScript interop.
+ Set<ClassEntity> jsInteropClasses = new Set<ClassEntity>();
+
+ /// Sets the native tag info for [cls].
+ ///
+ /// The tag info string contains comma-separated 'words' which are either
+ /// dispatch tags (having JavaScript identifier syntax) and directives that
+ /// begin with `!`.
+ void setNativeClassTagInfo(ClassEntity cls, String tagInfo) {
+ String tagText = tagInfo.substring(1, tagInfo.length - 1);
+ // TODO(johnniwinther): Assert that this is only called once. The memory
+ // compiler copies pre-processed elements into a new compiler through
+ // [Compiler.onLibraryScanned] and thereby causes multiple calls to this
+ // method.
+ assert(invariant(
+ cls,
+ nativeClassTagInfo[cls] == null ||
+ nativeClassTagInfo[cls].text == tagText,
+ message: "Native tag info set inconsistently on $cls: "
+ "Existing tag info '${nativeClassTagInfo[cls]}', "
+ "new tag info '$tagText'."));
+ nativeClassTagInfo[cls] = new NativeClassTag(tagText);
+ }
+
+ @override
+ void markAsJsInteropLibrary(LibraryEntity element) {
+ jsInteropLibraries.add(element);
+ }
+
+ @override
+ void markAsJsInteropClass(ClassEntity element) {
+ jsInteropClasses.add(element);
+ }
+
+ /// Returns `true` if [cls] is a native class.
+ bool isNativeClass(ClassEntity element) {
+ if (isJsInteropClass(element)) return true;
+ return nativeClassTagInfo.containsKey(element);
+ }
+
+ /// Returns the list of non-directive native tag words for [cls].
+ List<String> getNativeTagsOfClass(ClassEntity cls) {
+ return nativeClassTagInfo[cls].names;
+ }
+
+ /// Returns `true` if [cls] has a `!nonleaf` tag word.
+ bool hasNativeTagsForcedNonLeaf(ClassEntity cls) {
+ return nativeClassTagInfo[cls].isNonLeaf;
+ }
+
+ /// Returns `true` if [element] is explicitly marked as part of JsInterop.
+ bool isJsInteropLibrary(LibraryEntity element) {
+ return jsInteropLibraries.contains(element);
+ }
+
+ /// Returns `true` if [element] is explicitly marked as part of JsInterop.
+ bool isJsInteropClass(ClassEntity element) {
+ return jsInteropClasses.contains(element);
+ }
+
+ /// Returns `true` if [element] or any of its superclasses is native.
+ bool isNativeOrExtendsNative(ClassElement element) {
+ if (element == null) return false;
+ if (isNativeClass(element) || isJsInteropClass(element)) {
+ return true;
+ }
+ assert(element.isResolved);
+ return isNativeOrExtendsNative(element.superclass);
+ }
+}
+
+class NativeDataImpl implements NativeDataBuilder, NativeData {
+ /// Prefix used to escape JS names that are not valid Dart names
+ /// when using JSInterop.
+ static const String _jsInteropEscapePrefix = r'JS$';
+
+ final NativeClassData _nativeClassData;
/// The JavaScript names for native JavaScript elements implemented.
Map<MemberEntity, String> nativeMemberName = <MemberEntity, String>{};
- /// Tag info for native JavaScript classes names. See
- /// [setNativeClassTagInfo].
- Map<ClassEntity, String> nativeClassTagInfo = <ClassEntity, String>{};
-
/// Cache for [NativeBehavior]s for calling native methods.
Map<FunctionEntity, NativeBehavior> nativeMethodBehavior =
<FunctionEntity, NativeBehavior>{};
@@ -164,43 +237,49 @@ class NativeDataImpl
Map<MemberEntity, NativeBehavior> nativeFieldStoreBehavior =
<FieldEntity, NativeBehavior>{};
- /// Prefix used to escape JS names that are not valid Dart names
- /// when using JSInterop.
- static const String _jsInteropEscapePrefix = r'JS$';
+ /// The JavaScript names for elements implemented via typed JavaScript
+ /// interop.
+ Map<LibraryEntity, String> jsInteropLibraryNames = <LibraryEntity, String>{};
+ Map<ClassEntity, String> jsInteropClassNames = <ClassEntity, String>{};
- /// Returns `true` if [element] is explicitly marked as part of JsInterop.
- bool _isJsInteropLibrary(LibraryEntity element) {
- return jsInteropLibraryNames.containsKey(element);
- }
+ /// The JavaScript names for elements implemented via typed JavaScript
+ /// interop.
+ Map<MemberEntity, String> jsInteropMemberNames = <MemberEntity, String>{};
- /// Returns `true` if [element] is explicitly marked as part of JsInterop.
- bool _isJsInteropClass(ClassEntity element) {
- return jsInteropClassNames.containsKey(element);
- }
+ NativeDataImpl(this._nativeClassData);
- /// Returns `true` if [element] is explicitly marked as part of JsInterop.
- bool _isJsInteropMember(MemberEntity element) {
- return jsInteropMemberNames.containsKey(element);
+ /// Sets the native [name] for the member [element]. This name is used for
+ /// [element] in the generated JavaScript.
+ void setNativeMemberName(MemberEntity element, String name) {
+ // TODO(johnniwinther): Avoid setting this more than once. The enqueuer
+ // might enqueue [element] several times (before processing it) and computes
+ // name on each call to `internalAddToWorkList`.
+ assert(invariant(element,
+ nativeMemberName[element] == null || nativeMemberName[element] == name,
+ message: "Native member name set inconsistently on $element: "
+ "Existing name '${nativeMemberName[element]}', "
+ "new name '$name'."));
+ nativeMemberName[element] = name;
}
- @override
- void markAsJsInteropLibrary(LibraryEntity element) {
- jsInteropLibraryNames[element] = null;
+ /// Registers the [behavior] for calling the native [method].
+ void setNativeMethodBehavior(FunctionEntity method, NativeBehavior behavior) {
+ nativeMethodBehavior[method] = behavior;
}
- @override
- void markAsJsInteropClass(ClassEntity element) {
- jsInteropClassNames[element] = null;
+ /// Registers the [behavior] for reading from the native [field].
+ void setNativeFieldLoadBehavior(FieldEntity field, NativeBehavior behavior) {
+ nativeFieldLoadBehavior[field] = behavior;
}
- @override
- void markAsJsInteropMember(MemberEntity element) {
- jsInteropMemberNames[element] = null;
+ /// Registers the [behavior] for writing to the native [field].
+ void setNativeFieldStoreBehavior(FieldEntity field, NativeBehavior behavior) {
+ nativeFieldStoreBehavior[field] = behavior;
}
/// Sets the explicit js interop [name] for the library [element].
void setJsInteropLibraryName(LibraryEntity element, String name) {
- assert(invariant(element, _isJsInteropLibrary(element),
+ assert(invariant(element, _nativeClassData.isJsInteropLibrary(element),
message:
'Library $element is not js interop but given a js interop name.'));
jsInteropLibraryNames[element] = name;
@@ -208,12 +287,22 @@ class NativeDataImpl
/// Sets the explicit js interop [name] for the class [element].
void setJsInteropClassName(ClassEntity element, String name) {
- assert(invariant(element, _isJsInteropClass(element),
+ assert(invariant(element, _nativeClassData.isJsInteropClass(element),
message:
'Class $element is not js interop but given a js interop name.'));
jsInteropClassNames[element] = name;
}
+ @override
+ void markAsJsInteropMember(MemberEntity element) {
+ jsInteropMemberNames[element] = null;
+ }
+
+ /// Returns `true` if [element] is explicitly marked as part of JsInterop.
+ bool _isJsInteropMember(MemberEntity element) {
+ return jsInteropMemberNames.containsKey(element);
+ }
+
/// Sets the explicit js interop [name] for the member [element].
void setJsInteropMemberName(MemberEntity element, String name) {
assert(invariant(element, _isJsInteropMember(element),
@@ -222,6 +311,30 @@ class NativeDataImpl
jsInteropMemberNames[element] = name;
}
+ /// Returns `true` if [cls] is a native class.
+ bool isNativeClass(ClassEntity element) =>
+ _nativeClassData.isNativeClass(element);
+
+ /// Returns the list of non-directive native tag words for [cls].
+ List<String> getNativeTagsOfClass(ClassEntity cls) =>
+ _nativeClassData.getNativeTagsOfClass(cls);
+
+ /// Returns `true` if [cls] has a `!nonleaf` tag word.
+ bool hasNativeTagsForcedNonLeaf(ClassEntity cls) =>
+ _nativeClassData.hasNativeTagsForcedNonLeaf(cls);
+
+ /// Returns `true` if [element] is a JsInterop library.
+ bool isJsInteropLibrary(LibraryEntity element) =>
+ _nativeClassData.isJsInteropLibrary(element);
+
+ /// Returns `true` if [element] is a JsInterop class.
+ bool isJsInteropClass(ClassEntity element) =>
+ _nativeClassData.isJsInteropClass(element);
+
+ /// Returns `true` if [element] or any of its superclasses is native.
+ bool isNativeOrExtendsNative(ClassEntity element) =>
+ _nativeClassData.isNativeOrExtendsNative(element);
+
/// Returns the explicit js interop name for library [element].
String getJsInteropLibraryName(LibraryEntity element) {
return jsInteropLibraryNames[element];
@@ -237,13 +350,6 @@ class NativeDataImpl
return jsInteropMemberNames[element];
}
- /// Returns `true` if [element] is a JsInterop library.
- bool isJsInteropLibrary(LibraryEntity element) =>
- _isJsInteropLibrary(element);
-
- /// Returns `true` if [element] is a JsInterop class.
- bool isJsInteropClass(ClassEntity element) => _isJsInteropClass(element);
-
/// Returns `true` if [element] is a JsInterop method.
bool isJsInteropMember(MemberEntity element) {
if (element.isFunction ||
@@ -255,10 +361,10 @@ class NativeDataImpl
if (_isJsInteropMember(function)) return true;
if (function.enclosingClass != null) {
- return _isJsInteropClass(function.enclosingClass);
+ return isJsInteropClass(function.enclosingClass);
}
if (function.isTopLevel) {
- return _isJsInteropLibrary(function.library);
+ return isJsInteropLibrary(function.library);
}
return false;
} else {
@@ -337,78 +443,12 @@ class NativeDataImpl
return _jsLibraryNameHelper(element.library);
}
- /// Returns `true` if [cls] is a native class.
- bool isNativeClass(ClassEntity element) {
- if (isJsInteropClass(element)) return true;
- return nativeClassTagInfo.containsKey(element);
- }
-
/// Returns `true` if [element] is a native member of a native class.
bool isNativeMember(MemberEntity element) {
if (isJsInteropMember(element)) return true;
return nativeMemberName.containsKey(element);
}
- /// Returns `true` if [element] or any of its superclasses is native.
- bool isNativeOrExtendsNative(ClassElement element) {
- if (element == null) return false;
- if (isNativeClass(element) || isJsInteropClass(element)) {
- return true;
- }
- assert(element.isResolved);
- return isNativeOrExtendsNative(element.superclass);
- }
-
- /// Sets the native [name] for the member [element]. This name is used for
- /// [element] in the generated JavaScript.
- void setNativeMemberName(MemberEntity element, String name) {
- // TODO(johnniwinther): Avoid setting this more than once. The enqueuer
- // might enqueue [element] several times (before processing it) and computes
- // name on each call to `internalAddToWorkList`.
- assert(invariant(element,
- nativeMemberName[element] == null || nativeMemberName[element] == name,
- message: "Native member name set inconsistently on $element: "
- "Existing name '${nativeMemberName[element]}', "
- "new name '$name'."));
- nativeMemberName[element] = name;
- }
-
- /// Sets the native tag info for [cls].
- ///
- /// The tag info string contains comma-separated 'words' which are either
- /// dispatch tags (having JavaScript identifier syntax) and directives that
- /// begin with `!`.
- void setNativeClassTagInfo(ClassEntity cls, String tagInfo) {
- // TODO(johnniwinther): Assert that this is only called once. The memory
- // compiler copies pre-processed elements into a new compiler through
- // [Compiler.onLibraryScanned] and thereby causes multiple calls to this
- // method.
- assert(invariant(cls,
- nativeClassTagInfo[cls] == null || nativeClassTagInfo[cls] == tagInfo,
- message: "Native tag info set inconsistently on $cls: "
- "Existing tag info '${nativeClassTagInfo[cls]}', "
- "new tag info '$tagInfo'."));
- nativeClassTagInfo[cls] = tagInfo;
- }
-
- /// Returns the list of native tag words for [cls].
- List<String> getNativeTagsOfClassRaw(ClassEntity cls) {
- String quotedName = nativeClassTagInfo[cls];
- return quotedName.substring(1, quotedName.length - 1).split(',');
- }
-
- /// Returns the list of non-directive native tag words for [cls].
- List<String> getNativeTagsOfClass(ClassEntity cls) {
- return getNativeTagsOfClassRaw(cls)
- .where((s) => !s.startsWith('!'))
- .toList();
- }
-
- /// Returns `true` if [cls] has a `!nonleaf` tag word.
- bool hasNativeTagsForcedNonLeaf(ClassEntity cls) {
- return getNativeTagsOfClassRaw(cls).contains('!nonleaf');
- }
-
/// Returns the [NativeBehavior] for calling the native [method].
NativeBehavior getNativeMethodBehavior(FunctionEntity method) {
assert(invariant(method, nativeMethodBehavior.containsKey(method),
@@ -432,21 +472,6 @@ class NativeDataImpl
return nativeFieldStoreBehavior[field];
}
- /// Registers the [behavior] for calling the native [method].
- void setNativeMethodBehavior(FunctionEntity method, NativeBehavior behavior) {
- nativeMethodBehavior[method] = behavior;
- }
-
- /// Registers the [behavior] for reading from the native [field].
- void setNativeFieldLoadBehavior(FieldEntity field, NativeBehavior behavior) {
- nativeFieldLoadBehavior[field] = behavior;
- }
-
- /// Registers the [behavior] for writing to the native [field].
- void setNativeFieldStoreBehavior(FieldEntity field, NativeBehavior behavior) {
- nativeFieldStoreBehavior[field] = behavior;
- }
-
/// Apply JS$ escaping scheme to convert possible escaped Dart names into
/// JS names.
String computeUnescapedJSInteropName(String name) {
@@ -455,3 +480,39 @@ class NativeDataImpl
: name;
}
}
+
+class NativeClassTag {
+ final List<String> names;
+ final bool isNonLeaf;
+
+ factory NativeClassTag(String tagText) {
+ List<String> tags = tagText.split(',');
+ List<String> names = tags.where((s) => !s.startsWith('!')).toList();
+ bool isNonLeaf = tags.contains('!nonleaf');
+ return new NativeClassTag.internal(names, isNonLeaf);
+ }
+
+ NativeClassTag.internal(this.names, this.isNonLeaf);
+
+ String get text {
+ StringBuffer sb = new StringBuffer();
+ sb.write(names.join(','));
+ if (isNonLeaf) {
+ if (names.isNotEmpty) {
+ sb.write(',');
+ }
+ sb.write('!nonleaf');
+ }
+ return sb.toString();
+ }
+
+ int get hashCode => Hashing.listHash(names, isNonLeaf.hashCode);
+
+ bool operator ==(other) {
+ if (identical(this, other)) return true;
+ if (other is! NativeClassTag) return false;
+ return equalElements(names, other.names) && isNonLeaf == other.isNonLeaf;
+ }
+
+ String toString() => text;
+}
« no previous file with comments | « pkg/compiler/lib/src/js_backend/backend_serialization.dart ('k') | pkg/compiler/lib/src/native/enqueue.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698