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

Unified Diff: pkg/compiler/lib/src/native/resolver.dart

Issue 2873113004: Add equivalence check of NativeData and InterceptorData (Closed)
Patch Set: Created 3 years, 7 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/native/resolver.dart
diff --git a/pkg/compiler/lib/src/native/resolver.dart b/pkg/compiler/lib/src/native/resolver.dart
index ba302d652cbdc8e1b10d6ae3aea221909df7ac13..30e91708f14ef88f9c76f5b2a31b479219e19fa8 100644
--- a/pkg/compiler/lib/src/native/resolver.dart
+++ b/pkg/compiler/lib/src/native/resolver.dart
@@ -29,16 +29,19 @@ import '../patch_parser.dart';
import '../tree/tree.dart';
import 'behavior.dart';
+/// Interface for computing native members.
+abstract class NativeMemberResolver {
+ /// Computes whether [element] is native or JsInterop and, if so, registers
+ /// its [NativeBehavior]s to [registry].
+ void resolveNativeMember(MemberEntity element, [NativeRegistry registry]);
+}
+
/// Interface for computing native members and [NativeBehavior]s in member code
/// based on the AST.
-abstract class NativeDataResolver {
+abstract class NativeDataResolver implements NativeMemberResolver {
/// Returns `true` if [element] is a JsInterop member.
bool isJsInteropMember(MemberElement element);
- /// Computes whether [element] is native or JsInterop and, if so, registers
- /// its [NativeBehavior]s to [registry].
- void resolveNativeMember(MemberElement element, NativeRegistry registry);
-
/// Computes the [NativeBehavior] for a `JS` call, which can be an
/// instantiation point for types.
///
@@ -69,81 +72,65 @@ abstract class NativeDataResolver {
NativeBehavior resolveJsBuiltinCall(Send node, ForeignResolver resolver);
}
-class NativeDataResolverImpl implements NativeDataResolver {
+abstract class NativeMemberResolverBase implements NativeMemberResolver {
static final RegExp _identifier = new RegExp(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$');
- final Compiler _compiler;
+ ElementEnvironment get elementEnvironment;
+ CommonElements get commonElements;
+ NativeBasicData get nativeBasicData;
+ NativeDataBuilder get nativeDataBuilder;
- NativeDataResolverImpl(this._compiler);
+ bool isJsInteropMember(MemberEntity element);
+ bool isNativeMethod(FunctionEntity element);
- JavaScriptBackend get _backend => _compiler.backend;
- DiagnosticReporter get _reporter => _compiler.reporter;
- NativeBasicData get _nativeBasicData => _backend.nativeBasicData;
- NativeDataBuilder get _nativeDataBuilder => _backend.nativeDataBuilder;
+ NativeBehavior computeNativeMethodBehavior(FunctionEntity function,
+ {bool isJsInterop});
+ NativeBehavior computeNativeFieldLoadBehavior(FieldEntity field,
+ {bool isJsInterop});
+ NativeBehavior computeNativeFieldStoreBehavior(FieldEntity field);
@override
- bool isJsInteropMember(MemberElement element) {
- // TODO(johnniwinther): Avoid computing this twice for external function;
- // once from JavaScriptBackendTarget.resolveExternalFunction and once
- // through JavaScriptBackendTarget.resolveNativeMember.
- bool isJsInterop =
- checkJsInteropMemberAnnotations(_compiler, element, _nativeDataBuilder);
- // TODO(johnniwinther): Avoid this duplication of logic from
- // NativeData.isJsInterop.
- if (!isJsInterop && element is MethodElement && element.isExternal) {
- if (element.enclosingClass != null) {
- isJsInterop = _nativeBasicData.isJsInteropClass(element.enclosingClass);
- } else {
- isJsInterop = _nativeBasicData.isJsInteropLibrary(element.library);
- }
- }
- return isJsInterop;
- }
-
- void resolveNativeMember(MemberElement element, NativeRegistry registry) {
+ void resolveNativeMember(MemberEntity element, [NativeRegistry registry]) {
bool isJsInterop = isJsInteropMember(element);
if (element.isFunction ||
element.isConstructor ||
element.isGetter ||
element.isSetter) {
- MethodElement method = element;
+ FunctionEntity method = element;
bool isNative = _processMethodAnnotations(method);
if (isNative || isJsInterop) {
- NativeBehavior behavior = NativeBehavior
- .ofMethodElement(method, _compiler, isJsInterop: isJsInterop);
- _nativeDataBuilder.setNativeMethodBehavior(method, behavior);
- registry.registerNativeData(behavior);
+ NativeBehavior behavior =
+ computeNativeMethodBehavior(method, isJsInterop: isJsInterop);
+ nativeDataBuilder.setNativeMethodBehavior(method, behavior);
+ registry?.registerNativeData(behavior);
}
} else if (element.isField) {
- FieldElement field = element;
+ FieldEntity field = element;
bool isNative = _processFieldAnnotations(field);
if (isNative || isJsInterop) {
- NativeBehavior fieldLoadBehavior = NativeBehavior
- .ofFieldElementLoad(field, _compiler, isJsInterop: isJsInterop);
+ NativeBehavior fieldLoadBehavior =
+ computeNativeFieldLoadBehavior(field, isJsInterop: isJsInterop);
NativeBehavior fieldStoreBehavior =
- NativeBehavior.ofFieldElementStore(field, _compiler);
- _nativeDataBuilder.setNativeFieldLoadBehavior(field, fieldLoadBehavior);
- _nativeDataBuilder.setNativeFieldStoreBehavior(
+ computeNativeFieldStoreBehavior(field);
+ nativeDataBuilder.setNativeFieldLoadBehavior(field, fieldLoadBehavior);
+ nativeDataBuilder.setNativeFieldStoreBehavior(
field, fieldStoreBehavior);
// TODO(sra): Process fields for storing separately.
// We have to handle both loading and storing to the field because we
// only get one look at each member and there might be a load or store
// we have not seen yet.
- registry.registerNativeData(fieldLoadBehavior);
- registry.registerNativeData(fieldStoreBehavior);
+ registry?.registerNativeData(fieldLoadBehavior);
+ registry?.registerNativeData(fieldStoreBehavior);
}
}
}
/// Process the potentially native [field]. Adds information from metadata
/// attributes. Returns `true` of [method] is native.
- bool _processFieldAnnotations(Element element) {
- if (_compiler.serialization.isDeserialized(element)) {
- return false;
- }
+ bool _processFieldAnnotations(FieldEntity element) {
if (element.isInstanceMember &&
- _backend.nativeBasicData.isNativeClass(element.enclosingClass)) {
+ nativeBasicData.isNativeClass(element.enclosingClass)) {
// Exclude non-instance (static) fields - they are not really native and
// are compiled as isolate globals. Access of a property of a constructor
// function or a non-method property in the prototype chain, must be coded
@@ -156,11 +143,8 @@ class NativeDataResolverImpl implements NativeDataResolver {
/// Process the potentially native [method]. Adds information from metadata
/// attributes. Returns `true` of [method] is native.
- bool _processMethodAnnotations(Element method) {
- if (_compiler.serialization.isDeserialized(method)) {
- return false;
- }
- if (_isNativeMethod(method)) {
+ bool _processMethodAnnotations(FunctionEntity method) {
+ if (isNativeMethod(method)) {
if (method.isStatic) {
_setNativeNameForStaticMethod(method);
} else {
@@ -173,10 +157,10 @@ class NativeDataResolverImpl implements NativeDataResolver {
/// Sets the native name of [element], either from an annotation, or
/// defaulting to the Dart name.
- void _setNativeName(MemberElement element) {
+ void _setNativeName(MemberEntity element) {
String name = _findJsNameFromAnnotation(element);
if (name == null) name = element.name;
- _nativeDataBuilder.setNativeMemberName(element, name);
+ nativeDataBuilder.setNativeMemberName(element, name);
}
/// Sets the native name of the static native method [element], using the
@@ -187,28 +171,97 @@ class NativeDataResolverImpl implements NativeDataResolver {
/// use the declared @JSName as the expression
/// 3. If [element] does not have a @JSName annotation, qualify the name of
/// the method with the @Native name of the enclosing class.
- void _setNativeNameForStaticMethod(MethodElement element) {
+ void _setNativeNameForStaticMethod(FunctionEntity element) {
String name = _findJsNameFromAnnotation(element);
if (name == null) name = element.name;
if (_isIdentifier(name)) {
List<String> nativeNames =
- _nativeBasicData.getNativeTagsOfClass(element.enclosingClass);
+ nativeBasicData.getNativeTagsOfClass(element.enclosingClass);
if (nativeNames.length != 1) {
- _reporter.internalError(
+ throw new SpannableAssertionFailure(
element,
'Unable to determine a native name for the enclosing class, '
'options: $nativeNames');
}
- _nativeDataBuilder.setNativeMemberName(
- element, '${nativeNames[0]}.$name');
+ nativeDataBuilder.setNativeMemberName(element, '${nativeNames[0]}.$name');
} else {
- _nativeDataBuilder.setNativeMemberName(element, name);
+ nativeDataBuilder.setNativeMemberName(element, name);
}
}
bool _isIdentifier(String s) => _identifier.hasMatch(s);
- bool _isNativeMethod(FunctionElementX element) {
+ /// Returns the JSName annotation string or `null` if no JSName annotation is
+ /// present.
+ String _findJsNameFromAnnotation(MemberEntity element) {
+ String jsName = null;
+ for (ConstantValue value in elementEnvironment.getMemberMetadata(element)) {
+ String name = readAnnotationName(
+ element, value, commonElements.annotationJSNameClass);
+ if (jsName == null) {
+ jsName = name;
+ } else if (name != null) {
+ throw new SpannableAssertionFailure(
+ element, 'Too many JSName annotations: ${value.toDartText()}');
+ }
+ }
+ return jsName;
+ }
+}
+
+class NativeDataResolverImpl extends NativeMemberResolverBase
+ implements NativeDataResolver {
+ final Compiler _compiler;
+
+ NativeDataResolverImpl(this._compiler);
+
+ JavaScriptBackend get _backend => _compiler.backend;
+ DiagnosticReporter get _reporter => _compiler.reporter;
+ ElementEnvironment get elementEnvironment => _compiler.elementEnvironment;
+ CommonElements get commonElements => _compiler.commonElements;
+ NativeBasicData get nativeBasicData => _backend.nativeBasicData;
+ NativeDataBuilder get nativeDataBuilder => _backend.nativeDataBuilder;
+
+ @override
+ bool isJsInteropMember(MemberElement element) {
+ // TODO(johnniwinther): Avoid computing this twice for external function;
+ // once from JavaScriptBackendTarget.resolveExternalFunction and once
+ // through JavaScriptBackendTarget.resolveNativeMember.
+ bool isJsInterop =
+ checkJsInteropMemberAnnotations(_compiler, element, nativeDataBuilder);
+ // TODO(johnniwinther): Avoid this duplication of logic from
+ // NativeData.isJsInterop.
+ if (!isJsInterop && element is MethodElement && element.isExternal) {
+ if (element.enclosingClass != null) {
+ isJsInterop = nativeBasicData.isJsInteropClass(element.enclosingClass);
+ } else {
+ isJsInterop = nativeBasicData.isJsInteropLibrary(element.library);
+ }
+ }
+ return isJsInterop;
+ }
+
+ @override
+ NativeBehavior computeNativeMethodBehavior(MethodElement function,
+ {bool isJsInterop}) {
+ return NativeBehavior.ofMethodElement(function, _compiler,
+ isJsInterop: isJsInterop);
+ }
+
+ @override
+ NativeBehavior computeNativeFieldLoadBehavior(FieldElement field,
+ {bool isJsInterop}) {
+ return NativeBehavior.ofFieldElementLoad(field, _compiler,
+ isJsInterop: isJsInterop);
+ }
+
+ @override
+ NativeBehavior computeNativeFieldStoreBehavior(FieldElement field) {
+ return NativeBehavior.ofFieldElementStore(field, _compiler);
+ }
+
+ @override
+ bool isNativeMethod(FunctionElementX element) {
if (!_backend.canLibraryUseNative(element.library)) return false;
// Native method?
return _reporter.withCurrentElement(element, () {
@@ -222,24 +275,20 @@ class NativeDataResolverImpl implements NativeDataResolver {
});
}
- /// Returns the JSName annotation string or `null` if no JSName annotation is
- /// present.
- String _findJsNameFromAnnotation(Element element) {
- String jsName = null;
- for (MetadataAnnotation annotation in element.implementation.metadata) {
- annotation.ensureResolved(_compiler.resolution);
- ConstantValue value =
- _compiler.constants.getConstantValue(annotation.constant);
- String name = readAnnotationName(
- annotation, value, _compiler.commonElements.annotationJSNameClass);
- if (jsName == null) {
- jsName = name;
- } else if (name != null) {
- throw new SpannableAssertionFailure(
- annotation, 'Too many JSName annotations: ${annotation}');
- }
+ @override
+ bool _processMethodAnnotations(MethodElement method) {
+ if (_compiler.serialization.isDeserialized(method)) {
+ return false;
}
- return jsName;
+ return super._processMethodAnnotations(method);
+ }
+
+ @override
+ bool _processFieldAnnotations(FieldElement element) {
+ if (_compiler.serialization.isDeserialized(element)) {
+ return false;
+ }
+ return super._processFieldAnnotations(element);
}
@override

Powered by Google App Engine
This is Rietveld 408576698