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

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

Issue 2779003002: Move collection of native classes from NativeEnqueuerBase to NativeResolutionEnqueuer (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
« no previous file with comments | « no previous file | tests/compiler/dart2js/inference/inference_test_helper.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/native/enqueue.dart
diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart
index 525ff98f032daa11ee1c5f23e9211afce149a262..444eb6f7dad286f2dfc8828ef9ef492981d873f5 100644
--- a/pkg/compiler/lib/src/native/enqueue.dart
+++ b/pkg/compiler/lib/src/native/enqueue.dart
@@ -2,25 +2,23 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:front_end/src/fasta/scanner.dart' show BeginGroupToken, Token;
+import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN;
+
import '../common.dart';
-import '../common/backend_api.dart' show ForeignResolver;
+import '../common/backend_api.dart';
import '../common/resolution.dart' show Resolution;
import '../compiler.dart' show Compiler;
-import '../constants/values.dart';
import '../common_elements.dart' show CommonElements;
import '../elements/elements.dart';
import '../elements/entities.dart';
-import '../elements/modelx.dart' show FunctionElementX;
import '../elements/resolution_types.dart';
import '../elements/types.dart';
import '../js_backend/backend_helpers.dart' show BackendHelpers;
import '../js_backend/backend_usage.dart' show BackendUsageBuilder;
import '../js_backend/js_backend.dart';
-import '../js_backend/native_data.dart' show NativeBasicDataBuilder;
+import '../js_backend/native_data.dart' show NativeBasicData, NativeData;
import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter;
-import 'package:front_end/src/fasta/scanner.dart' show BeginGroupToken, Token;
-import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN;
-import '../tree/tree.dart';
import '../universe/use.dart' show StaticUse, TypeUse;
import '../universe/world_impact.dart'
show WorldImpact, WorldImpactBuilder, WorldImpactBuilderImpl;
@@ -50,75 +48,216 @@ class NativeEnqueuer {
}
abstract class NativeEnqueuerBase implements NativeEnqueuer {
Johnni Winther 2017/03/28 09:30:28 Weird diff. Code is moved from NativeEnqueuerBase
- /// The set of all native classes. Each native class is in [nativeClasses]
- /// and exactly one of [unusedClasses] and [registeredClasses].
- final Set<ClassElement> _nativeClasses = new Set<ClassElement>();
-
final Set<ClassElement> _registeredClasses = new Set<ClassElement>();
final Set<ClassElement> _unusedClasses = new Set<ClassElement>();
bool get hasInstantiatedNativeClasses => !_registeredClasses.isEmpty;
- final Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>();
-
- final Compiler compiler;
+ final Compiler _compiler;
final bool enableLiveTypeAnalysis;
/// Subclasses of [NativeEnqueuerBase] are constructed by the backend.
- NativeEnqueuerBase(Compiler compiler, this.enableLiveTypeAnalysis)
- : this.compiler = compiler;
+ NativeEnqueuerBase(this._compiler, this.enableLiveTypeAnalysis);
+
+ JavaScriptBackend get _backend => _compiler.backend;
+ BackendHelpers get _helpers => _backend.helpers;
+ Resolution get _resolution => _compiler.resolution;
- JavaScriptBackend get backend => compiler.backend;
- BackendHelpers get helpers => backend.helpers;
- Resolution get resolution => compiler.resolution;
+ DiagnosticReporter get _reporter => _compiler.reporter;
+ CommonElements get _commonElements => _compiler.commonElements;
- DiagnosticReporter get reporter => compiler.reporter;
- CommonElements get commonElements => compiler.commonElements;
+ NativeBasicData get _nativeBasicData => _backend.nativeBasicData;
- void onInstantiatedType(ResolutionInterfaceType type) {
+ BackendClasses get _backendClasses => _backend.backendClasses;
+
+ void onInstantiatedType(InterfaceType type) {
if (_unusedClasses.remove(type.element)) {
_registeredClasses.add(type.element);
}
}
- WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) {
- WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
- _processNativeClasses(impactBuilder, libraries);
- return impactBuilder;
+ /// Register [classes] as natively instantiated in [impactBuilder].
+ void _registerTypeUses(
+ WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) {
+ for (ClassElement cls in classes) {
+ if (!_unusedClasses.contains(cls)) {
+ // No need to add [classElement] to [impactBuilder]: it has already been
+ // instantiated and we don't track origins of native instantiations
+ // precisely.
+ continue;
+ }
+ cls.ensureResolved(_resolution);
+ impactBuilder
+ .registerTypeUse(new TypeUse.nativeInstantiation(cls.rawType));
+ }
+ }
+
+ void registerNativeBehavior(
+ WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) {
+ _processNativeBehavior(impactBuilder, nativeBehavior, cause);
}
- void _processNativeClasses(
- WorldImpactBuilder impactBuilder, Iterable<LibraryElement> libraries) {
- libraries.forEach(processNativeClassesInLibrary);
- if (helpers.isolateHelperLibrary != null) {
- processNativeClassesInLibrary(helpers.isolateHelperLibrary);
+ void _processNativeBehavior(
+ WorldImpactBuilder impactBuilder, NativeBehavior behavior, cause) {
+ void registerInstantiation(ResolutionInterfaceType type) {
+ impactBuilder.registerTypeUse(new TypeUse.nativeInstantiation(type));
}
- processSubclassesOfNativeClasses(libraries);
+
+ int unusedBefore = _unusedClasses.length;
+ Set<ClassElement> matchingClasses = new Set<ClassElement>();
+ for (var type in behavior.typesInstantiated) {
+ if (type is SpecialType) {
+ if (type == SpecialType.JsObject) {
+ registerInstantiation(_commonElements.objectType);
+ }
+ continue;
+ }
+ if (type is ResolutionInterfaceType) {
+ if (type == _commonElements.numType) {
+ registerInstantiation(_commonElements.doubleType);
+ registerInstantiation(_commonElements.intType);
+ } else if (type == _commonElements.intType ||
+ type == _commonElements.doubleType ||
+ type == _commonElements.stringType ||
+ type == _commonElements.nullType ||
+ type == _commonElements.boolType ||
+ type.asInstanceOf(_backendClasses.listClass) != null) {
+ registerInstantiation(type);
+ }
+ // TODO(johnniwinther): Improve spec string precision to handle type
+ // arguments and implements relations that preserve generics. Currently
+ // we cannot distinguish between `List`, `List<dynamic>`, and
+ // `List<int>` and take all to mean `List<E>`; in effect not including
+ // any native subclasses of generic classes.
+ // TODO(johnniwinther,sra): Find and replace uses of `List` with the
+ // actual implementation classes such as `JSArray` et al.
+ matchingClasses
+ .addAll(_findUnusedClassesMatching((ClassElement nativeClass) {
+ ResolutionInterfaceType nativeType = nativeClass.thisType;
+ ResolutionInterfaceType specType = type.element.thisType;
+ return _compiler.types.isSubtype(nativeType, specType);
+ }));
+ } else if (type.isDynamic) {
+ matchingClasses.addAll(_unusedClasses);
+ } else {
+ assert(type is ResolutionVoidType);
+ }
+ }
+ if (matchingClasses.isNotEmpty && _registeredClasses.isEmpty) {
+ matchingClasses.addAll(_onFirstNativeClass(impactBuilder));
+ }
+ _registerTypeUses(impactBuilder, matchingClasses, cause);
+
+ // Give an info so that library developers can compile with -v to find why
+ // all the native classes are included.
+ if (unusedBefore > 0 && unusedBefore == matchingClasses.length) {
+ _reporter.log('All native types marked as used due to $cause.');
+ }
+ }
+
+ Iterable<ClassElement> _findUnusedClassesMatching(
+ bool predicate(classElement)) {
+ return _unusedClasses.where(predicate);
+ }
+
+ void _registerBackendUse(FunctionEntity element) {}
+
+ Iterable<ClassElement> _onFirstNativeClass(WorldImpactBuilder impactBuilder) {
+ void staticUse(FunctionEntity element) {
+ impactBuilder.registerStaticUse(new StaticUse.implicitInvoke(element));
+ _registerBackendUse(element);
+ }
+
+ staticUse(_helpers.defineProperty);
+ staticUse(_helpers.toStringForNativeObject);
+ staticUse(_helpers.hashCodeForNativeObject);
+ staticUse(_helpers.closureConverter);
+ return _findNativeExceptions();
+ }
+
+ Iterable<ClassElement> _findNativeExceptions() {
+ return _findUnusedClassesMatching((classElement) {
+ // TODO(sra): Annotate exception classes in dart:html.
+ String name = classElement.name;
+ if (name.contains('Exception')) return true;
+ if (name.contains('Error')) return true;
+ return false;
+ });
+ }
+}
+
+class NativeResolutionEnqueuer extends NativeEnqueuerBase {
+ /// The set of all native classes. Each native class is in [nativeClasses]
+ /// and exactly one of [unusedClasses] and [registeredClasses].
+ final Set<ClassElement> _nativeClasses = new Set<ClassElement>();
+
+ Map<String, ClassElement> tagOwner = new Map<String, ClassElement>();
+
+ NativeResolutionEnqueuer(Compiler compiler)
+ : super(compiler, compiler.options.enableNativeLiveTypeAnalysis);
+
+ BackendUsageBuilder get _backendUsageBuilder => _backend.backendUsageBuilder;
+
+ void _registerBackendUse(FunctionEntity element) {
+ _backendUsageBuilder.registerBackendFunctionUse(element);
+ _backendUsageBuilder.registerGlobalFunctionDependency(element);
+ }
+
+ WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) {
+ WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
+ Set<ClassElement> nativeClasses = new Set<ClassElement>();
+ libraries.forEach((l) => _processNativeClassesInLibrary(l, nativeClasses));
+ if (_helpers.isolateHelperLibrary != null) {
+ _processNativeClassesInLibrary(
+ _helpers.isolateHelperLibrary, nativeClasses);
+ }
+ _processSubclassesOfNativeClasses(libraries, nativeClasses);
+ _nativeClasses.addAll(nativeClasses);
+ _unusedClasses.addAll(nativeClasses);
if (!enableLiveTypeAnalysis) {
_registerTypeUses(impactBuilder, _nativeClasses, 'forced');
}
+ return impactBuilder;
}
- void processNativeClassesInLibrary(LibraryElement library) {
+ void _processNativeClassesInLibrary(
+ LibraryElement library, Set<ClassElement> nativeClasses) {
// Use implementation to ensure the inclusion of injected members.
library.implementation.forEachLocalMember((Element element) {
if (element.isClass) {
ClassElement cls = element;
- if (backend.nativeBasicData.isNativeClass(cls)) {
- processNativeClass(element);
+ if (_nativeBasicData.isNativeClass(cls)) {
+ _processNativeClass(element, nativeClasses);
}
}
});
}
- void processNativeClass(ClassElement classElement) {
- _nativeClasses.add(classElement);
- _unusedClasses.add(classElement);
+ void _processNativeClass(
+ ClassElement classElement, Set<ClassElement> nativeClasses) {
+ nativeClasses.add(classElement);
// Resolve class to ensure the class has valid inheritance info.
- classElement.ensureResolved(resolution);
+ classElement.ensureResolved(_resolution);
+ // Js Interop interfaces do not have tags.
+ if (_nativeBasicData.isJsInteropClass(classElement)) return;
+ // Since we map from dispatch tags to classes, a dispatch tag must be used
+ // on only one native class.
+ for (String tag in _nativeBasicData.getNativeTagsOfClass(classElement)) {
+ ClassElement owner = tagOwner[tag];
+ if (owner != null) {
+ if (owner != classElement) {
+ _reporter.internalError(
+ classElement, "Tag '$tag' already in use by '${owner.name}'");
+ }
+ } else {
+ tagOwner[tag] = classElement;
+ }
+ }
}
- void processSubclassesOfNativeClasses(Iterable<LibraryElement> libraries) {
+ void _processSubclassesOfNativeClasses(
+ Iterable<LibraryElement> libraries, Set<ClassElement> nativeClasses) {
+ Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>();
// Collect potential subclasses, e.g.
//
// class B extends foo.A {}
@@ -130,7 +269,7 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer {
libraries.forEach((library) {
library.implementation.forEachLocalMember((element) {
if (element.isClass) {
- String extendsName = findExtendsNameOfClass(element);
+ String extendsName = _findExtendsNameOfClass(element);
if (extendsName != null) {
Set<ClassElement> potentialSubclasses = potentialExtends
.putIfAbsent(extendsName, () => new Set<ClassElement>());
@@ -145,15 +284,14 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer {
// fact a subclass of a native class.
ClassElement nativeSuperclassOf(ClassElement classElement) {
- if (backend.nativeBasicData.isNativeClass(classElement))
- return classElement;
+ if (_nativeBasicData.isNativeClass(classElement)) return classElement;
if (classElement.superclass == null) return null;
return nativeSuperclassOf(classElement.superclass);
}
void walkPotentialSubclasses(ClassElement element) {
if (nativeClassesAndSubclasses.contains(element)) return;
- element.ensureResolved(resolution);
+ element.ensureResolved(_resolution);
ClassElement nativeSuperclass = nativeSuperclassOf(element);
if (nativeSuperclass != null) {
nativeClassesAndSubclasses.add(element);
@@ -164,17 +302,15 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer {
}
}
- _nativeClasses.forEach(walkPotentialSubclasses);
-
- _nativeClasses.addAll(nativeClassesAndSubclasses);
- _unusedClasses.addAll(nativeClassesAndSubclasses);
+ nativeClasses.forEach(walkPotentialSubclasses);
+ nativeClasses.addAll(nativeClassesAndSubclasses);
}
/**
* Returns the source string of the class named in the extends clause, or
* `null` if there is no extends clause.
*/
- String findExtendsNameOfClass(ClassElement classElement) {
+ String _findExtendsNameOfClass(ClassElement classElement) {
if (classElement.isResolved) {
ClassElement superClass = classElement.superclass;
while (superClass != null) {
@@ -235,155 +371,11 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer {
return id.lexeme;
}
- return reporter.withCurrentElement(classElement, () {
+ return _reporter.withCurrentElement(classElement, () {
return scanForExtendsName(classElement.position);
});
}
- /// Register [classes] as natively instantiated in [impactBuilder].
- void _registerTypeUses(
- WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) {
- for (ClassElement cls in classes) {
- if (!_unusedClasses.contains(cls)) {
- // No need to add [classElement] to [impactBuilder]: it has already been
- // instantiated and we don't track origins of native instantiations
- // precisely.
- continue;
- }
- cls.ensureResolved(resolution);
- impactBuilder
- .registerTypeUse(new TypeUse.nativeInstantiation(cls.rawType));
- }
- }
-
- void registerNativeBehavior(
- WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) {
- _processNativeBehavior(impactBuilder, nativeBehavior, cause);
- }
-
- void _processNativeBehavior(
- WorldImpactBuilder impactBuilder, NativeBehavior behavior, cause) {
- void registerInstantiation(ResolutionInterfaceType type) {
- impactBuilder.registerTypeUse(new TypeUse.nativeInstantiation(type));
- }
-
- int unusedBefore = _unusedClasses.length;
- Set<ClassElement> matchingClasses = new Set<ClassElement>();
- for (var type in behavior.typesInstantiated) {
- if (type is SpecialType) {
- if (type == SpecialType.JsObject) {
- registerInstantiation(compiler.commonElements.objectType);
- }
- continue;
- }
- if (type is ResolutionInterfaceType) {
- if (type == commonElements.numType) {
- registerInstantiation(commonElements.doubleType);
- registerInstantiation(commonElements.intType);
- } else if (type == commonElements.intType ||
- type == commonElements.doubleType ||
- type == commonElements.stringType ||
- type == commonElements.nullType ||
- type == commonElements.boolType ||
- type.asInstanceOf(backend.backendClasses.listClass) != null) {
- registerInstantiation(type);
- }
- // TODO(johnniwinther): Improve spec string precision to handle type
- // arguments and implements relations that preserve generics. Currently
- // we cannot distinguish between `List`, `List<dynamic>`, and
- // `List<int>` and take all to mean `List<E>`; in effect not including
- // any native subclasses of generic classes.
- // TODO(johnniwinther,sra): Find and replace uses of `List` with the
- // actual implementation classes such as `JSArray` et al.
- matchingClasses
- .addAll(_findUnusedClassesMatching((ClassElement nativeClass) {
- ResolutionInterfaceType nativeType = nativeClass.thisType;
- ResolutionInterfaceType specType = type.element.thisType;
- return compiler.types.isSubtype(nativeType, specType);
- }));
- } else if (type.isDynamic) {
- matchingClasses.addAll(_unusedClasses);
- } else {
- assert(type is ResolutionVoidType);
- }
- }
- if (matchingClasses.isNotEmpty && _registeredClasses.isEmpty) {
- matchingClasses.addAll(_onFirstNativeClass(impactBuilder));
- }
- _registerTypeUses(impactBuilder, matchingClasses, cause);
-
- // Give an info so that library developers can compile with -v to find why
- // all the native classes are included.
- if (unusedBefore > 0 && unusedBefore == matchingClasses.length) {
- reporter.log('All native types marked as used due to $cause.');
- }
- }
-
- Iterable<ClassElement> _findUnusedClassesMatching(
- bool predicate(classElement)) {
- return _unusedClasses.where(predicate);
- }
-
- void registerBackendUse(MethodElement element) {}
-
- Iterable<ClassElement> _onFirstNativeClass(WorldImpactBuilder impactBuilder) {
- void staticUse(MethodElement element) {
- impactBuilder.registerStaticUse(new StaticUse.implicitInvoke(element));
- registerBackendUse(element);
- }
-
- staticUse(helpers.defineProperty);
- staticUse(helpers.toStringForNativeObject);
- staticUse(helpers.hashCodeForNativeObject);
- staticUse(helpers.closureConverter);
- return _findNativeExceptions();
- }
-
- Iterable<ClassElement> _findNativeExceptions() {
- return _findUnusedClassesMatching((classElement) {
- // TODO(sra): Annotate exception classes in dart:html.
- String name = classElement.name;
- if (name.contains('Exception')) return true;
- if (name.contains('Error')) return true;
- return false;
- });
- }
-}
-
-class NativeResolutionEnqueuer extends NativeEnqueuerBase {
- Map<String, ClassElement> tagOwner = new Map<String, ClassElement>();
-
- NativeResolutionEnqueuer(Compiler compiler)
- : super(compiler, compiler.options.enableNativeLiveTypeAnalysis);
-
- BackendUsageBuilder get _backendUsageBuilder => backend.backendUsageBuilder;
-
- void registerBackendUse(MethodElement element) {
- _backendUsageBuilder.registerBackendFunctionUse(element);
- _backendUsageBuilder.registerGlobalFunctionDependency(element);
- }
-
- void processNativeClass(ClassElement classElement) {
- super.processNativeClass(classElement);
-
- // Js Interop interfaces do not have tags.
- if (backend.nativeBasicData.isJsInteropClass(classElement)) return;
- // Since we map from dispatch tags to classes, a dispatch tag must be used
- // on only one native class.
- for (String tag
- in backend.nativeBasicData.getNativeTagsOfClass(classElement)) {
- ClassElement owner = tagOwner[tag];
- if (owner != null) {
- if (owner != classElement) {
- reporter.internalError(
- classElement, "Tag '$tag' already in use by '${owner.name}'");
- }
- } else {
- tagOwner[tag] = classElement;
- }
- }
- }
-
void logSummary(log(message)) {
log('Resolved ${_registeredClasses.length} native elements used, '
'${_unusedClasses.length} native elements dead.');
@@ -399,11 +391,18 @@ class NativeCodegenEnqueuer extends NativeEnqueuerBase {
NativeCodegenEnqueuer(
Compiler compiler, this.emitter, this._resolutionEnqueuer)
- : super(compiler, compiler.options.enableNativeLiveTypeAnalysis);
+ : super(compiler, compiler.options.enableNativeLiveTypeAnalysis) {}
+
+ NativeData get _nativeData => _backend.nativeData;
+
+ WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) {
+ WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
+ _unusedClasses.addAll(_resolutionEnqueuer._nativeClasses);
- void _processNativeClasses(
- WorldImpactBuilder impactBuilder, Iterable<LibraryElement> libraries) {
- super._processNativeClasses(impactBuilder, libraries);
+ if (!enableLiveTypeAnalysis) {
+ _registerTypeUses(
+ impactBuilder, _resolutionEnqueuer._nativeClasses, 'forced');
+ }
// HACK HACK - add all the resolved classes.
Set<ClassElement> matchingClasses = new Set<ClassElement>();
@@ -416,6 +415,7 @@ class NativeCodegenEnqueuer extends NativeEnqueuerBase {
matchingClasses.addAll(_onFirstNativeClass(impactBuilder));
}
_registerTypeUses(impactBuilder, matchingClasses, 'was resolved');
+ return impactBuilder;
}
void _registerTypeUses(
@@ -430,7 +430,7 @@ class NativeCodegenEnqueuer extends NativeEnqueuerBase {
}
void _addSubtypes(ClassElement cls, NativeEmitter emitter) {
- if (!backend.nativeData.isNativeClass(cls)) return;
+ if (!_nativeData.isNativeClass(cls)) return;
if (doneAddSubtypes.contains(cls)) return;
doneAddSubtypes.add(cls);
@@ -449,7 +449,7 @@ class NativeCodegenEnqueuer extends NativeEnqueuerBase {
// natives classes.
ClassElement superclass = cls.superclass;
while (superclass != null && superclass.isMixinApplication) {
- assert(!backend.nativeData.isNativeClass(superclass));
+ assert(!_nativeData.isNativeClass(superclass));
superclass = superclass.superclass;
}
« no previous file with comments | « no previous file | tests/compiler/dart2js/inference/inference_test_helper.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698