Remove use of Element in ResolutionEnqueuerListener.

This makes ResolutionEnqueuerListener reusable for kernel-based elements.

R=efortuna@google.com

Review-Url: https://codereview.chromium.org/2797173004 .
This commit is contained in:
Johnni Winther 2017-04-07 09:41:54 +02:00
parent 12615de38f
commit 7108d7b7a4
8 changed files with 184 additions and 74 deletions

View file

@ -8,6 +8,7 @@ library dart2js.type_system;
import 'common/names.dart' show Uris;
import 'elements/types.dart';
import 'elements/entities.dart';
import 'universe/call_structure.dart';
/// The common elements and types in Dart.
abstract class CommonElements {
@ -284,6 +285,17 @@ abstract class ElementEnvironment {
/// Returns `true` if [a] is a subtype of [b].
bool isSubtype(DartType a, DartType b);
/// Returns the type if [function].
FunctionType getFunctionType(FunctionEntity function);
/// Returns the [CallStructure] corresponding to calling [entity] with all
/// arguments, both required and optional.
CallStructure getCallStructure(FunctionEntity entity);
/// Returns `true` if [member] a the synthetic getter `loadLibrary` injected
/// on deferred libraries.
bool isDeferredLoadLibraryGetter(MemberEntity member);
}
class CommonElementsImpl implements CommonElements {

View file

@ -37,6 +37,7 @@ import 'elements/resolution_types.dart'
show
ResolutionDartType,
ResolutionDynamicType,
ResolutionFunctionType,
ResolutionInterfaceType,
Types;
import 'enqueue.dart' show Enqueuer, EnqueueTask, ResolutionEnqueuer;
@ -1972,4 +1973,25 @@ class _CompilerElementEnvironment implements ElementEnvironment {
}
return library;
}
@override
CallStructure getCallStructure(MethodElement method) {
ResolutionFunctionType type = method.computeType(_resolution);
return new CallStructure(
type.parameterTypes.length +
type.optionalParameterTypes.length +
type.namedParameterTypes.length,
type.namedParameters);
}
@override
bool isDeferredLoadLibraryGetter(MemberElement member) {
return member.isDeferredLoaderGetter;
}
@override
ResolutionFunctionType getFunctionType(MethodElement method) {
method.computeType(_resolution);
return method.type;
}
}

View file

@ -23,7 +23,10 @@ abstract class Entity implements Spannable {
///
/// Currently only [LibraryElement] but later also kernel based Dart classes
/// and/or Dart-in-JS classes.
abstract class LibraryEntity extends Entity {}
abstract class LibraryEntity extends Entity {
/// Return the canonical uri that identifies this library.
Uri get canonicalUri;
}
/// Stripped down super interface for class like entities.
///
@ -83,7 +86,10 @@ abstract class MemberEntity extends Entity {
/// Whether this member is assignable, i.e. a non-final field.
bool get isAssignable;
/// The enclosing class if this is a constuctor, instance member or
/// Whether this member is constant, i.e. a constant field or constructor.
bool get isConst;
/// The enclosing class if this is a constructor, instance member or
/// static member of a class.
ClassEntity get enclosingClass;

View file

@ -59,6 +59,9 @@ abstract class DartType {
/// Is `true` if this type is a malformed type.
bool get isMalformed => false;
/// Whether this type contains a type variable.
bool get containsTypeVariables => false;
}
class InterfaceType extends DartType {
@ -67,6 +70,9 @@ class InterfaceType extends DartType {
InterfaceType(this.element, this.typeArguments);
bool get containsTypeVariables =>
typeArguments.any((type) => type.containsTypeVariables);
int get hashCode {
int hash = element.hashCode;
for (DartType argument in typeArguments) {
@ -108,6 +114,8 @@ class TypeVariableType extends DartType {
bool get isTypeVariable => true;
bool get containsTypeVariables => true;
int get hashCode => 17 * element.hashCode;
bool operator ==(other) {
@ -161,6 +169,13 @@ class FunctionType extends DartType {
this.namedParameters,
this.namedParameterTypes);
bool get containsTypeVariables {
return returnType.containsTypeVariables ||
parameterTypes.any((type) => type.containsTypeVariables) ||
optionalParameterTypes.any((type) => type.containsTypeVariables) ||
namedParameterTypes.any((type) => type.containsTypeVariables);
}
bool get isFunctionType => true;
int get hashCode {

View file

@ -7,8 +7,9 @@ import '../common/resolution.dart';
import '../common_elements.dart';
import '../constants/constant_system.dart';
import '../constants/values.dart';
import '../elements/resolution_types.dart';
import '../elements/elements.dart';
import '../elements/entities.dart';
import '../elements/resolution_types.dart';
import '../universe/call_structure.dart';
import '../universe/use.dart' show ConstantUse, StaticUse;
import '../universe/world_impact.dart'
@ -74,7 +75,7 @@ abstract class CustomElementsAnalysisBase {
join.instantiatedClasses.add(classElement);
}
void registerStaticUse(Element element) {
void registerStaticUse(MemberEntity element) {
assert(element != null);
if (element == _helpers.findIndexForNativeSubclassType) {
join.demanded = true;

View file

@ -9,7 +9,6 @@ import '../common/names.dart' show Identifiers, Uris;
import '../common_elements.dart' show CommonElements, ElementEnvironment;
import '../constants/values.dart';
import '../deferred_load.dart';
import '../elements/elements.dart';
import '../elements/entities.dart';
import '../elements/types.dart';
import '../enqueue.dart' show Enqueuer, EnqueuerListener;
@ -90,19 +89,21 @@ class ResolutionEnqueuerListener extends EnqueuerListener {
_backendUsage.processBackendImpact(impact);
}
void _addInterceptors(ClassElement cls, WorldImpactBuilder impactBuilder) {
void _addInterceptors(ClassEntity cls, WorldImpactBuilder impactBuilder) {
_interceptorData.addInterceptors(cls);
impactBuilder.registerTypeUse(new TypeUse.instantiation(cls.rawType));
impactBuilder.registerTypeUse(
new TypeUse.instantiation(_elementEnvironment.getRawType(cls)));
_backendUsage.registerBackendClassUse(cls);
}
@override
WorldImpact registerClosurizedMember(MemberElement element) {
WorldImpact registerClosurizedMember(FunctionEntity element) {
WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
_backendUsage.processBackendImpact(_impacts.memberClosure);
impactBuilder
.addImpact(_impacts.memberClosure.createImpact(_elementEnvironment));
if (element.type.containsTypeVariables) {
FunctionType type = _elementEnvironment.getFunctionType(element);
if (type.containsTypeVariables) {
impactBuilder.addImpact(_registerComputeSignature());
}
return impactBuilder;
@ -132,7 +133,7 @@ class ResolutionEnqueuerListener extends EnqueuerListener {
/// Called to enable support for isolates. Any backend specific [WorldImpact]
/// of this is returned.
WorldImpact _enableIsolateSupport(MethodElement mainMethod) {
WorldImpact _enableIsolateSupport(FunctionEntity mainMethod) {
WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
// TODO(floitsch): We should also ensure that the class IsolateMessage is
// instantiated. Currently, just enabling isolate support works.
@ -155,14 +156,16 @@ class ResolutionEnqueuerListener extends EnqueuerListener {
}
/// Computes the [WorldImpact] of calling [mainMethod] as the entry point.
WorldImpact _computeMainImpact(MethodElement mainMethod) {
WorldImpact _computeMainImpact(FunctionEntity mainMethod) {
WorldImpactBuilderImpl mainImpact = new WorldImpactBuilderImpl();
if (mainMethod.parameters.isNotEmpty) {
CallStructure callStructure =
_elementEnvironment.getCallStructure(mainMethod);
if (callStructure.argumentCount > 0) {
_impacts.mainWithArguments
.registerImpact(mainImpact, _elementEnvironment);
_backendUsage.processBackendImpact(_impacts.mainWithArguments);
mainImpact.registerStaticUse(
new StaticUse.staticInvoke(mainMethod, CallStructure.TWO_ARGS));
new StaticUse.staticInvoke(mainMethod, callStructure));
// If the main method takes arguments, this compilation could be the
// target of Isolate.spawnUri. Strictly speaking, that can happen also if
// main takes no arguments, but in this case the spawned isolate can't
@ -258,10 +261,10 @@ class ResolutionEnqueuerListener extends EnqueuerListener {
} else if (constant.isInterceptor) {
// An interceptor constant references the class's prototype chain.
InterceptorConstantValue interceptor = constant;
ClassElement cls = interceptor.cls;
_computeImpactForInstantiatedConstantType(cls.thisType, impactBuilder);
InterfaceType type = _elementEnvironment.getThisType(interceptor.cls);
_computeImpactForInstantiatedConstantType(type, impactBuilder);
} else if (constant.isType) {
MethodElement helper = _helpers.createRuntimeType;
FunctionEntity helper = _helpers.createRuntimeType;
impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
// TODO(johnniwinther): Find the right [CallStructure].
helper,
@ -296,21 +299,23 @@ class ResolutionEnqueuerListener extends EnqueuerListener {
}
@override
WorldImpact registerUsedElement(MemberElement member) {
WorldImpact registerUsedElement(MemberEntity member) {
WorldImpactBuilderImpl worldImpact = new WorldImpactBuilderImpl();
_mirrorsDataBuilder.registerUsedMember(member);
_customElementsAnalysis.registerStaticUse(member);
if (member.isFunction && member.isInstanceMember) {
MethodElement method = member;
ClassElement cls = method.enclosingClass;
if (method.name == Identifiers.call && !cls.typeVariables.isEmpty) {
FunctionEntity method = member;
ClassEntity cls = method.enclosingClass;
if (method.name == Identifiers.call &&
_elementEnvironment.getThisType(cls).typeArguments.isNotEmpty) {
worldImpact.addImpact(_registerComputeSignature());
}
}
_backendUsage.registerUsedMember(member);
if (member.isDeferredLoaderGetter) {
if (_elementEnvironment.isDeferredLoadLibraryGetter(member)) {
// TODO(sigurdm): Create a function registerLoadLibraryAccess.
if (!_isLoadLibraryFunctionResolved) {
_isLoadLibraryFunctionResolved = true;
@ -322,7 +327,7 @@ class ResolutionEnqueuerListener extends EnqueuerListener {
// library, or timers for the async library. We exclude constant fields,
// which are ending here because their initializing expression is
// compiled.
LibraryElement library = member.library;
LibraryEntity library = member.library;
if (!_backendUsage.isIsolateInUse && !(member.isField && member.isConst)) {
Uri uri = library.canonicalUri;
if (uri == Uris.dart_isolate) {
@ -361,9 +366,9 @@ class ResolutionEnqueuerListener extends EnqueuerListener {
return _impacts.runtimeTypeSupport.createImpact(_elementEnvironment);
}
WorldImpact _processClass(ClassElement cls) {
WorldImpact _processClass(ClassEntity cls) {
WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
if (!cls.typeVariables.isEmpty) {
if (_elementEnvironment.getThisType(cls).typeArguments.isNotEmpty) {
_typeVariableResolutionAnalysis.registerClassWithTypeVariables(cls);
}
// TODO(johnniwinther): Extract an `implementationClassesOf(...)` function

View file

@ -11,8 +11,9 @@ class KLibrary implements LibraryEntity {
/// Library index used for fast lookup in [KernelWorldBuilder].
final int libraryIndex;
final String name;
final Uri canonicalUri;
KLibrary(this.libraryIndex, this.name);
KLibrary(this.libraryIndex, this.name, this.canonicalUri);
String toString() => 'library($name)';
}
@ -33,12 +34,15 @@ class KClass implements ClassEntity {
}
abstract class KMember implements MemberEntity {
/// Member index used for fast lookup in [KernelWorldBuilder].
final int memberIndex;
final KLibrary library;
final KClass enclosingClass;
final Name _name;
final bool _isStatic;
KMember(this.library, this.enclosingClass, this._name, {bool isStatic: false})
KMember(this.memberIndex, this.library, this.enclosingClass, this._name,
{bool isStatic: false})
: _isStatic = isStatic;
String get name => _name.text;
@ -46,6 +50,9 @@ abstract class KMember implements MemberEntity {
@override
bool get isAssignable => false;
@override
bool get isConst => false;
@override
bool get isSetter => false;
@ -79,18 +86,17 @@ abstract class KMember implements MemberEntity {
abstract class KFunction extends KMember implements FunctionEntity {
final bool isExternal;
KFunction(KLibrary library, KClass enclosingClass, Name name,
KFunction(int memberIndex, KLibrary library, KClass enclosingClass, Name name,
{bool isStatic: false, this.isExternal: false})
: super(library, enclosingClass, name, isStatic: isStatic);
: super(memberIndex, library, enclosingClass, name, isStatic: isStatic);
}
abstract class KConstructor extends KFunction implements ConstructorEntity {
/// Constructor index used for fast lookup in [KernelWorldBuilder].
final int constructorIndex;
final bool isConst;
KConstructor(this.constructorIndex, KClass enclosingClass, Name name,
{bool isExternal})
: super(enclosingClass.library, enclosingClass, name,
KConstructor(int memberIndex, KClass enclosingClass, Name name,
{bool isExternal, this.isConst})
: super(memberIndex, enclosingClass.library, enclosingClass, name,
isExternal: isExternal);
@override
@ -110,8 +116,9 @@ abstract class KConstructor extends KFunction implements ConstructorEntity {
class KGenerativeConstructor extends KConstructor {
KGenerativeConstructor(int constructorIndex, KClass enclosingClass, Name name,
{bool isExternal})
: super(constructorIndex, enclosingClass, name, isExternal: isExternal);
{bool isExternal, bool isConst})
: super(constructorIndex, enclosingClass, name,
isExternal: isExternal, isConst: isConst);
@override
bool get isFactoryConstructor => false;
@ -121,9 +128,10 @@ class KGenerativeConstructor extends KConstructor {
}
class KFactoryConstructor extends KConstructor {
KFactoryConstructor(int constructorIndex, KClass enclosingClass, Name name,
{bool isExternal})
: super(constructorIndex, enclosingClass, name, isExternal: isExternal);
KFactoryConstructor(int memberIndex, KClass enclosingClass, Name name,
{bool isExternal, bool isConst})
: super(memberIndex, enclosingClass, name,
isExternal: isExternal, isConst: isConst);
@override
bool get isFactoryConstructor => true;
@ -133,9 +141,9 @@ class KFactoryConstructor extends KConstructor {
}
class KMethod extends KFunction {
KMethod(KLibrary library, KClass enclosingClass, Name name,
KMethod(int memberIndex, KLibrary library, KClass enclosingClass, Name name,
{bool isStatic, bool isExternal})
: super(library, enclosingClass, name,
: super(memberIndex, library, enclosingClass, name,
isStatic: isStatic, isExternal: isExternal);
@override
@ -145,9 +153,9 @@ class KMethod extends KFunction {
}
class KGetter extends KFunction {
KGetter(KLibrary library, KClass enclosingClass, Name name,
KGetter(int memberIndex, KLibrary library, KClass enclosingClass, Name name,
{bool isStatic, bool isExternal})
: super(library, enclosingClass, name,
: super(memberIndex, library, enclosingClass, name,
isStatic: isStatic, isExternal: isExternal);
@override
@ -157,9 +165,9 @@ class KGetter extends KFunction {
}
class KSetter extends KFunction {
KSetter(KLibrary library, KClass enclosingClass, Name name,
KSetter(int memberIndex, KLibrary library, KClass enclosingClass, Name name,
{bool isStatic, bool isExternal})
: super(library, enclosingClass, name,
: super(memberIndex, library, enclosingClass, name,
isStatic: isStatic, isExternal: isExternal);
@override
@ -172,13 +180,12 @@ class KSetter extends KFunction {
}
class KField extends KMember implements FieldEntity {
/// Field index used for fast lookup in [KernelWorldBuilder].
final int fieldIndex;
final bool isAssignable;
final bool isConst;
KField(this.fieldIndex, KLibrary library, KClass enclosingClass, Name name,
{bool isStatic, this.isAssignable})
: super(library, enclosingClass, name, isStatic: isStatic);
KField(int memberIndex, KLibrary library, KClass enclosingClass, Name name,
{bool isStatic, this.isAssignable, this.isConst})
: super(memberIndex, library, enclosingClass, name, isStatic: isStatic);
@override
bool get isField => true;

View file

@ -23,6 +23,7 @@ import '../js_backend/constant_system_javascript.dart';
import '../js_backend/no_such_method_registry.dart';
import '../native/native.dart' as native;
import '../native/resolver.dart';
import '../universe/call_structure.dart';
import 'element_adapter.dart';
import 'elements.dart';
@ -55,19 +56,17 @@ class KernelWorldBuilder extends KernelElementAdapterMixin {
Map<ir.TypeParameter, KTypeVariable> _typeVariableMap =
<ir.TypeParameter, KTypeVariable>{};
// TODO(johnniwinther): Change this to a list of 'KMemberData' class if we
// need more data for members.
List<ir.Member> _memberList = <ir.Member>[];
Map<ir.Member, KConstructor> _constructorMap = <ir.Member, KConstructor>{};
// TODO(johnniwinther): Change this to a list of 'KConstructorData' class
// holding the [ConstantConstructor] if we need more data for constructors.
List<ir.Member> _constructorList = <ir.Member>[];
Map<KConstructor, ConstantConstructor> _constructorConstantMap =
<KConstructor, ConstantConstructor>{};
Map<ir.Procedure, KFunction> _methodMap = <ir.Procedure, KFunction>{};
Map<ir.Field, KField> _fieldMap = <ir.Field, KField>{};
// TODO(johnniwinther): Change this to a list of 'KFieldData' class
// holding the [ConstantExpression] if we need more data for fields.
List<ir.Field> _fieldList = <ir.Field>[];
Map<KField, ConstantExpression> _fieldConstantMap =
<KField, ConstantExpression>{};
@ -112,14 +111,15 @@ class KernelWorldBuilder extends KernelElementAdapterMixin {
KLibrary _getLibrary(ir.Library node, [KLibraryEnv libraryEnv]) {
return _libraryMap.putIfAbsent(node, () {
_libraryEnvs.add(libraryEnv ?? _env.lookupLibrary(node.importUri));
Uri canonicalUri = node.importUri;
_libraryEnvs.add(libraryEnv ?? _env.lookupLibrary(canonicalUri));
String name = node.name;
if (name == null) {
// Use the file name as script name.
String path = node.importUri.path;
String path = canonicalUri.path;
name = path.substring(path.lastIndexOf('/') + 1);
}
return new KLibrary(_libraryMap.length, name);
return new KLibrary(_libraryMap.length, name, canonicalUri);
});
}
@ -194,27 +194,31 @@ class KernelWorldBuilder extends KernelElementAdapterMixin {
KConstructor _getConstructor(ir.Member node) {
return _constructorMap.putIfAbsent(node, () {
int constructorIndex = _constructorList.length;
int memberIndex = _memberList.length;
KConstructor constructor;
KClass enclosingClass = _getClass(node.enclosingClass);
Name name = getName(node.name);
bool isExternal = node.isExternal;
if (node is ir.Constructor) {
constructor = new KGenerativeConstructor(
constructorIndex, enclosingClass, name,
isExternal: isExternal);
memberIndex, enclosingClass, name,
isExternal: isExternal, isConst: node.isConst);
} else if (node is ir.Procedure) {
constructor = new KFactoryConstructor(memberIndex, enclosingClass, name,
isExternal: isExternal, isConst: node.isConst);
} else {
constructor = new KFactoryConstructor(
constructorIndex, enclosingClass, name,
isExternal: isExternal);
// TODO(johnniwinther): Convert `node.location` to a [SourceSpan].
throw new SpannableAssertionFailure(
NO_LOCATION_SPANNABLE, "Unexpected constructor node: ${node}.");
}
_constructorList.add(node);
_memberList.add(node);
return constructor;
});
}
KFunction _getMethod(ir.Procedure node) {
return _methodMap.putIfAbsent(node, () {
int memberIndex = _memberList.length;
KLibrary library;
KClass enclosingClass;
if (node.enclosingClass != null) {
@ -226,26 +230,33 @@ class KernelWorldBuilder extends KernelElementAdapterMixin {
Name name = getName(node.name);
bool isStatic = node.isStatic;
bool isExternal = node.isExternal;
KFunction function;
switch (node.kind) {
case ir.ProcedureKind.Factory:
throw new UnsupportedError("Cannot create method from factory.");
case ir.ProcedureKind.Getter:
return new KGetter(library, enclosingClass, name,
function = new KGetter(memberIndex, library, enclosingClass, name,
isStatic: isStatic, isExternal: isExternal);
break;
case ir.ProcedureKind.Method:
case ir.ProcedureKind.Operator:
return new KMethod(library, enclosingClass, name,
function = new KMethod(memberIndex, library, enclosingClass, name,
isStatic: isStatic, isExternal: isExternal);
break;
case ir.ProcedureKind.Setter:
return new KSetter(library, enclosingClass, getName(node.name).setter,
function = new KSetter(
memberIndex, library, enclosingClass, getName(node.name).setter,
isStatic: isStatic, isExternal: isExternal);
break;
}
_memberList.add(node);
return function;
});
}
KField _getField(ir.Field node) {
return _fieldMap.putIfAbsent(node, () {
int fieldIndex = _fieldList.length;
int memberIndex = _memberList.length;
KLibrary library;
KClass enclosingClass;
if (node.enclosingClass != null) {
@ -256,9 +267,11 @@ class KernelWorldBuilder extends KernelElementAdapterMixin {
}
Name name = getName(node.name);
bool isStatic = node.isStatic;
_fieldList.add(node);
return new KField(fieldIndex, library, enclosingClass, name,
isStatic: isStatic, isAssignable: node.isMutable);
_memberList.add(node);
return new KField(memberIndex, library, enclosingClass, name,
isStatic: isStatic,
isAssignable: node.isMutable,
isConst: node.isConst);
});
}
@ -400,7 +413,7 @@ class KernelWorldBuilder extends KernelElementAdapterMixin {
ConstantConstructor _getConstructorConstant(KConstructor constructor) {
return _constructorConstantMap.putIfAbsent(constructor, () {
ir.Member node = _constructorList[constructor.constructorIndex];
ir.Member node = _memberList[constructor.memberIndex];
if (node is ir.Constructor && node.isConst) {
return new Constantifier(this).computeConstantConstructor(node);
}
@ -413,7 +426,7 @@ class KernelWorldBuilder extends KernelElementAdapterMixin {
ConstantExpression _getFieldConstant(KField field) {
return _fieldConstantMap.putIfAbsent(field, () {
ir.Field node = _fieldList[field.fieldIndex];
ir.Field node = _memberList[field.memberIndex];
if (node.isConst) {
return new Constantifier(this).visit(node.initializer);
}
@ -555,6 +568,11 @@ class KernelElementEnvironment implements ElementEnvironment {
throw new UnimplementedError('KernelElementEnvironment.isSubtype');
}
@override
FunctionType getFunctionType(KFunction function) {
throw new UnimplementedError('KernelElementEnvironment.getFunctionType');
}
@override
ConstructorEntity lookupConstructor(ClassEntity cls, String name,
{bool required: false}) {
@ -627,6 +645,30 @@ class KernelElementEnvironment implements ElementEnvironment {
}
return library;
}
@override
CallStructure getCallStructure(KFunction function) {
ir.Member member = worldBuilder._memberList[function.memberIndex];
ir.FunctionNode functionNode;
if (member is ir.Procedure) {
functionNode = member.function;
} else if (member is ir.Constructor) {
functionNode = member.function;
} else {
throw new SpannableAssertionFailure(
function, "Unexpected function node ${member} for $function.");
}
return new CallStructure(
functionNode.positionalParameters.length +
functionNode.namedParameters.length,
functionNode.namedParameters.map((d) => d.name).toList());
}
@override
bool isDeferredLoadLibraryGetter(KMember member) {
// TODO(johnniwinther): Support these.
return false;
}
}
/// Visitor that converts kernel dart types into [DartType].