Skip to content

Commit

Permalink
Use AbstractValue in the rest of type inference
Browse files Browse the repository at this point in the history
Change-Id: Ic782af55e7b9ab9942eab9809f180e3979d2b326
Reviewed-on: https://dart-review.googlesource.com/56920
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
  • Loading branch information
johnniwinther authored and commit-bot@chromium.org committed May 31, 2018
1 parent 947760f commit c6129f7
Show file tree
Hide file tree
Showing 14 changed files with 658 additions and 353 deletions.
14 changes: 8 additions & 6 deletions pkg/compiler/lib/src/dump_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import 'deferred_load.dart' show OutputUnit;
import 'elements/entities.dart';
import 'js/js.dart' as jsAst;
import 'js_backend/js_backend.dart' show JavaScriptBackend;
import 'types/masks.dart';
import 'types/abstract_value_domain.dart';
import 'types/types.dart'
show GlobalTypeInferenceElementResult, GlobalTypeInferenceMemberResult;
import 'universe/world_builder.dart' show CodegenWorldBuilder;
Expand Down Expand Up @@ -118,9 +118,12 @@ class ElementInfoCollector {
if (!isInInstantiatedClass && !_hasBeenResolved(field)) {
return null;
}
TypeMask inferredType = _resultOfMember(field).type;
AbstractValue inferredType = _resultOfMember(field).type;
// If a field has an empty inferred type it is never used.
if (inferredType == null || inferredType.isEmpty) return null;
if (inferredType == null ||
closedWorld.abstractValueDomain.isEmpty(inferredType)) {
return null;
}

int size = compiler.dumpInfoTask.sizeOf(field);
String code = compiler.dumpInfoTask.codeOf(field);
Expand Down Expand Up @@ -461,13 +464,12 @@ class DumpInfoTask extends CompilerTask implements InfoReporter {
entity,
impact,
new WorldImpactVisitorImpl(visitDynamicUse: (dynamicUse) {
TypeMask mask = dynamicUse.receiverConstraint;
AbstractValue mask = dynamicUse.receiverConstraint;
selections.addAll(closedWorld
// TODO(het): Handle `call` on `Closure` through
// `world.includesClosureCall`.
.locateMembers(dynamicUse.selector, mask)
.map((MemberEntity e) =>
new Selection(e, dynamicUse.receiverConstraint)));
.map((MemberEntity e) => new Selection(e, mask)));
}, visitStaticUse: (staticUse) {
selections.add(new Selection(staticUse.element, null));
}),
Expand Down
36 changes: 21 additions & 15 deletions pkg/compiler/lib/src/inferrer/inferrer_engine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -440,8 +440,8 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {

info.bailedOut = false;
info.elementType.inferred = true;
AbstractValue fixedListType = abstractValueDomain.fixedListType;
if (info.originalType.forwardTo == fixedListType) {
if (abstractValueDomain.isSpecializationOf(
info.originalType, abstractValueDomain.fixedListType)) {
info.checksGrowable = tracer.callsGrowableMethod;
}
tracer.assignments.forEach(info.elementType.addAssignment);
Expand All @@ -460,12 +460,12 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {

info.bailedOut = false;
for (int i = 0; i < tracer.keyAssignments.length; ++i) {
TypeInformation newType = info.addEntryAssignment(
TypeInformation newType = info.addEntryAssignment(abstractValueDomain,
tracer.keyAssignments[i], tracer.valueAssignments[i]);
if (newType != null) workQueue.add(newType);
}
for (TypeInformation map in tracer.mapAssignments) {
workQueue.addAll(info.addMapAssignment(map));
workQueue.addAll(info.addMapAssignment(abstractValueDomain, map));
}

info.markAsInferred();
Expand Down Expand Up @@ -596,15 +596,15 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
types.allocatedLists.values.forEach((_info) {
ListTypeInformation info = _info;
print('${info.type} '
'for ${info.originalType.allocationNode} '
'at ${info.originalType.allocationElement} '
'for ${abstractValueDomain.getAllocationNode(info.originalType)} '
'at ${abstractValueDomain.getAllocationElement(info.originalType)}'
'after ${info.refineCount}');
});
types.allocatedMaps.values.forEach((_info) {
MapTypeInformation info = _info;
print('${info.type} '
'for ${info.originalType.allocationNode} '
'at ${info.originalType.allocationElement} '
'for ${abstractValueDomain.getAllocationNode(info.originalType)} '
'at ${abstractValueDomain.getAllocationElement(info.originalType)}'
'after ${info.refineCount}');
});
types.allocatedClosures.forEach((TypeInformation info) {
Expand Down Expand Up @@ -711,7 +711,8 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
// the old type around to ensure that we get a complete view
// of the type graph and do not drop any flow edges.
AbstractValue refinedType = computeTypeMask(closedWorld, value);
type = new NarrowTypeInformation(type, refinedType);
type = new NarrowTypeInformation(
abstractValueDomain, type, refinedType);
types.allocatedTypes.add(type);
}
}
Expand Down Expand Up @@ -766,7 +767,8 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
if (info is StaticCallSiteTypeInformation) {
MemberEntity member = info.calledElement;
closedWorldRefiner.addFunctionCalledInLoop(member);
} else if (info.mask != null && !info.mask.containsAll(closedWorld)) {
} else if (info.mask != null &&
!abstractValueDomain.containsAll(info.mask)) {
// For instance methods, we only register a selector called in a
// loop if it is a typed selector, to avoid marking too many
// methods as being called from within a loop. This cuts down
Expand Down Expand Up @@ -906,7 +908,8 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {

TypeInformation getDefaultTypeOfParameter(Local parameter) {
return defaultTypeOfParameter.putIfAbsent(parameter, () {
return new PlaceholderTypeInformation(types.currentMember);
return new PlaceholderTypeInformation(
abstractValueDomain, types.currentMember);
});
}

Expand Down Expand Up @@ -967,6 +970,7 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
SideEffectsBuilder sideEffectsBuilder,
bool inLoop) {
CallSiteTypeInformation info = new StaticCallSiteTypeInformation(
abstractValueDomain,
types.currentMember,
node,
caller,
Expand Down Expand Up @@ -1020,6 +1024,7 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
});

CallSiteTypeInformation info = new DynamicCallSiteTypeInformation(
abstractValueDomain,
types.currentMember,
callType,
node,
Expand All @@ -1037,16 +1042,16 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
}

TypeInformation registerAwait(T node, TypeInformation argument) {
AwaitTypeInformation info =
new AwaitTypeInformation<T>(types.currentMember, node);
AwaitTypeInformation info = new AwaitTypeInformation<T>(
abstractValueDomain, types.currentMember, node);
info.addAssignment(argument);
types.allocatedTypes.add(info);
return info;
}

TypeInformation registerYield(T node, TypeInformation argument) {
YieldTypeInformation info =
new YieldTypeInformation<T>(types.currentMember, node);
YieldTypeInformation info = new YieldTypeInformation<T>(
abstractValueDomain, types.currentMember, node);
info.addAssignment(argument);
types.allocatedTypes.add(info);
return info;
Expand All @@ -1063,6 +1068,7 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
{bool inLoop}) {
sideEffectsBuilder.setAllSideEffectsAndDependsOnSomething();
CallSiteTypeInformation info = new ClosureCallSiteTypeInformation(
abstractValueDomain,
types.currentMember,
node,
caller,
Expand Down
34 changes: 22 additions & 12 deletions pkg/compiler/lib/src/inferrer/kernel_inferrer_engine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,9 @@ class KernelTypeSystemStrategy implements TypeSystemStrategy<ir.Node> {

@override
ParameterTypeInformation createParameterTypeInformation(
covariant JLocal parameter, TypeSystem<ir.Node> types) {
AbstractValueDomain abstractValueDomain,
covariant JLocal parameter,
TypeSystem<ir.Node> types) {
MemberEntity context = parameter.memberContext;
KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(context);
ir.FunctionNode functionNode =
Expand All @@ -289,40 +291,48 @@ class KernelTypeSystemStrategy implements TypeSystemStrategy<ir.Node> {
types.getInferredTypeOfMember(member);
if (isClosure) {
return new ParameterTypeInformation.localFunction(
memberTypeInformation, parameter, type, member);
abstractValueDomain, memberTypeInformation, parameter, type, member);
} else if (member.isInstanceMember) {
return new ParameterTypeInformation.instanceMember(memberTypeInformation,
parameter, type, member, new ParameterAssignments());
return new ParameterTypeInformation.instanceMember(
abstractValueDomain,
memberTypeInformation,
parameter,
type,
member,
new ParameterAssignments());
} else {
return new ParameterTypeInformation.static(
memberTypeInformation, parameter, type, member);
abstractValueDomain, memberTypeInformation, parameter, type, member);
}
}

@override
MemberTypeInformation createMemberTypeInformation(MemberEntity member) {
MemberTypeInformation createMemberTypeInformation(
AbstractValueDomain abstractValueDomain, MemberEntity member) {
if (member.isField) {
FieldEntity field = member;
DartType type = _elementEnvironment.getFieldType(field);
return new FieldTypeInformation(field, type);
return new FieldTypeInformation(abstractValueDomain, field, type);
} else if (member.isGetter) {
FunctionEntity getter = member;
DartType type = _elementEnvironment.getFunctionType(getter);
return new GetterTypeInformation(getter, type);
return new GetterTypeInformation(abstractValueDomain, getter, type);
} else if (member.isSetter) {
FunctionEntity setter = member;
return new SetterTypeInformation(setter);
return new SetterTypeInformation(abstractValueDomain, setter);
} else if (member.isFunction) {
FunctionEntity method = member;
DartType type = _elementEnvironment.getFunctionType(method);
return new MethodTypeInformation(method, type);
return new MethodTypeInformation(abstractValueDomain, method, type);
} else {
ConstructorEntity constructor = member;
if (constructor.isFactoryConstructor) {
DartType type = _elementEnvironment.getFunctionType(constructor);
return new FactoryConstructorTypeInformation(constructor, type);
return new FactoryConstructorTypeInformation(
abstractValueDomain, constructor, type);
} else {
return new GenerativeConstructorTypeInformation(constructor);
return new GenerativeConstructorTypeInformation(
abstractValueDomain, constructor);
}
}
}
Expand Down
36 changes: 19 additions & 17 deletions pkg/compiler/lib/src/inferrer/node_tracer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ library compiler.src.inferrer.node_tracer;

import '../common/names.dart' show Identifiers;
import '../elements/entities.dart';
import '../types/masks.dart' show ContainerTypeMask, MapTypeMask;
import '../types/abstract_value_domain.dart';
import '../util/util.dart' show Setlet;
import 'debug.dart' as debug;
import 'inferrer_engine.dart';
Expand Down Expand Up @@ -306,41 +306,43 @@ abstract class TracerVisitor implements TypeInformationVisitor {

void visitDynamicCallSiteTypeInformation(
DynamicCallSiteTypeInformation info) {
void addsToContainer(ContainerTypeMask mask) {
if (mask.allocationNode != null) {
void addsToContainer(AbstractValue mask) {
Object allocationNode =
inferrer.abstractValueDomain.getAllocationNode(mask);
if (allocationNode != null) {
ListTypeInformation list =
inferrer.types.allocatedLists[mask.allocationNode];
inferrer.types.allocatedLists[allocationNode];
listsToAnalyze.add(list);
} else {
// The [ContainerTypeMask] is a union of two containers, and we lose
// track of where these containers have been allocated at this point.
// The [mask] is a union of two containers, and we lose track of where
// these containers have been allocated at this point.
bailout('Stored in too many containers');
}
}

void addsToMapValue(MapTypeMask mask) {
if (mask.allocationNode != null) {
MapTypeInformation map =
inferrer.types.allocatedMaps[mask.allocationNode];
void addsToMapValue(AbstractValue mask) {
Object allocationNode =
inferrer.abstractValueDomain.getAllocationNode(mask);
if (allocationNode != null) {
MapTypeInformation map = inferrer.types.allocatedMaps[allocationNode];
mapsToAnalyze.add(map);
} else {
// The [MapTypeMask] is a union. See comment for [ContainerTypeMask]
// above.
// The [mask] is a union. See comment for [mask] above.
bailout('Stored in too many maps');
}
}

void addsToMapKey(MapTypeMask mask) {
void addsToMapKey(AbstractValue mask) {
// We do not track the use of keys from a map, so we have to bail.
bailout('Used as key in Map');
}

// "a[...] = x" could be a list (container) or map assignemnt.
if (isIndexSetValue(info)) {
var receiverType = info.receiver.type;
if (receiverType is ContainerTypeMask) {
if (inferrer.abstractValueDomain.isContainer(receiverType)) {
addsToContainer(receiverType);
} else if (receiverType is MapTypeMask) {
} else if (inferrer.abstractValueDomain.isMap(receiverType)) {
addsToMapValue(receiverType);
} else {
// Not a container or map, so the targets could be any methods. There
Expand All @@ -363,7 +365,7 @@ abstract class TracerVisitor implements TypeInformationVisitor {
// Could be: m[x] = ...;
if (isIndexSetKey(info)) {
var receiverType = info.receiver.type;
if (receiverType is MapTypeMask) {
if (inferrer.abstractValueDomain.isMap(receiverType)) {
addsToMapKey(receiverType);
} else {
bailoutIfReaches(isParameterOfListAddingMethod);
Expand All @@ -373,7 +375,7 @@ abstract class TracerVisitor implements TypeInformationVisitor {

if (mightAddToContainer(info)) {
var receiverType = info.receiver.type;
if (receiverType is ContainerTypeMask) {
if (inferrer.abstractValueDomain.isContainer(receiverType)) {
addsToContainer(receiverType);
} else {
// Not a container, see note above.
Expand Down
46 changes: 5 additions & 41 deletions pkg/compiler/lib/src/inferrer/type_graph_dump.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ library dart2js.inferrer.type_graph_dump;
import '../../compiler_new.dart';
import '../elements/entities.dart';
import '../elements/entity_utils.dart' as utils;
import '../types/masks.dart';
import '../types/abstract_value_domain.dart';
import 'inferrer_engine.dart';
import 'type_graph_nodes.dart';
import 'debug.dart';
Expand Down Expand Up @@ -80,7 +80,8 @@ class TypeGraphDump {
String name = filenameFromElement(element);
output = compilerOutput.createOutputSink(
'$outputDir/$name', 'dot', OutputType.debug);
_GraphGenerator visitor = new _GraphGenerator(this, element, output);
_GraphGenerator visitor = new _GraphGenerator(
this, element, output, inferrer.abstractValueDomain.getCompactText);
for (TypeInformation node in nodes[element]) {
visitor.visit(node);
}
Expand Down Expand Up @@ -137,12 +138,13 @@ class _GraphGenerator extends TypeInformationVisitor {
final Set<TypeInformation> seen = new Set<TypeInformation>();
final List<TypeInformation> worklist = new List<TypeInformation>();
final Map<TypeInformation, int> nodeId = <TypeInformation, int>{};
final String Function(AbstractValue) formatType;
int usedIds = 0;
final OutputSink output;
final MemberEntity element;
TypeInformation returnValue;

_GraphGenerator(this.global, this.element, this.output) {
_GraphGenerator(this.global, this.element, this.output, this.formatType) {
returnValue = global.inferrer.types.getInferredTypeOfMember(element);
getNode(returnValue); // Ensure return value is part of graph.
append('digraph {');
Expand Down Expand Up @@ -413,41 +415,3 @@ class _GraphGenerator extends TypeInformationVisitor {
addNode(info, 'Yield\n$text');
}
}

/// Convert the given TypeMask to a compact string format.
///
/// The default format is too verbose for the graph format since long strings
/// create oblong nodes that obstruct the graph layout.
String formatType(TypeMask type) {
if (type is FlatTypeMask) {
// TODO(asgerf): Disambiguate classes whose name is not unique. Using the
// library name for all classes is not a good idea, since library names
// can be really long and mess up the layout.
// Capitalize Null to emphasize that it's the null type mask and not
// a null value we accidentally printed out.
if (type.isEmptyOrNull) return type.isNullable ? 'Null' : 'Empty';
String nullFlag = type.isNullable ? '?' : '';
String subFlag = type.isExact ? '' : type.isSubclass ? '+' : '*';
return '${type.base.name}$nullFlag$subFlag';
}
if (type is UnionTypeMask) {
return type.disjointMasks.map(formatType).join(' | ');
}
if (type is ContainerTypeMask) {
String container = formatType(type.forwardTo);
String member = formatType(type.elementType);
return '$container<$member>';
}
if (type is MapTypeMask) {
String container = formatType(type.forwardTo);
String key = formatType(type.keyType);
String value = formatType(type.valueType);
return '$container<$key,$value>';
}
if (type is ValueTypeMask) {
String baseType = formatType(type.forwardTo);
String value = type.value.toStructuredText();
return '$baseType=$value';
}
return '$type'; // Fall back on toString if not supported here.
}
Loading

0 comments on commit c6129f7

Please sign in to comment.