Use AbstractValue in most of ssa

Change-Id: I157081f817e033181d7c314f7567517e5ce85058
Reviewed-on: https://dart-review.googlesource.com/56522
Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
Johnni Winther 2018-05-31 07:26:52 +00:00 committed by commit-bot@chromium.org
parent aecf8e8dc4
commit bbef9aee7c
12 changed files with 338 additions and 192 deletions

View file

@ -7,6 +7,7 @@ library dart2js.type_system;
import 'common.dart';
import 'common/names.dart' show Identifiers, Uris;
import 'constants/expressions.dart' show ConstantExpression;
import 'constants/values.dart';
import 'elements/entities.dart';
import 'elements/names.dart' show PublicName;
@ -14,12 +15,10 @@ import 'elements/types.dart';
import 'js_backend/backend.dart' show JavaScriptBackend;
import 'js_backend/constant_system_javascript.dart';
import 'js_backend/native_data.dart' show NativeBasicData;
import 'constants/expressions.dart' show ConstantExpression;
import 'types/abstract_value_domain.dart';
import 'universe/call_structure.dart' show CallStructure;
import 'universe/selector.dart' show Selector;
import 'universe/call_structure.dart';
import 'universe/world_builder.dart';
import 'world.dart';
/// The common elements and types in Dart.
class CommonElements {
@ -748,8 +747,8 @@ class CommonElements {
/// in the given [world].
///
/// Returns `false` if `JSString.split` is not available.
bool appliesToJsStringSplit(
Selector selector, ReceiverConstraint receiver, World world) {
bool appliesToJsStringSplit(Selector selector, AbstractValue receiver,
AbstractValueDomain abstractValueDomain) {
if (_jsStringSplit == null) {
ClassEntity cls =
_findClass(interceptorsLibrary, 'JSString', required: false);
@ -758,7 +757,8 @@ class CommonElements {
if (_jsStringSplit == null) return false;
}
return selector.applies(_jsStringSplit) &&
(receiver == null || receiver.canHit(jsStringSplit, selector, world));
(receiver == null ||
abstractValueDomain.canHit(receiver, jsStringSplit, selector));
}
FunctionEntity _jsStringSplit;

View file

@ -126,7 +126,7 @@ class KernelToTypeInferenceMapImpl implements KernelToTypeInferenceMap {
.resultOfMember(e is ConstructorBodyEntity ? e.constructor : e);
AbstractValue getReturnTypeOf(FunctionEntity function) {
return TypeMaskFactory.inferredReturnTypeForElement(
return AbstractValueFactory.inferredReturnTypeForElement(
function, _globalInferenceResults);
}
@ -173,28 +173,28 @@ class KernelToTypeInferenceMapImpl implements KernelToTypeInferenceMap {
}
AbstractValue inferredIndexType(ir.ForInStatement node) {
return TypeMaskFactory.inferredTypeForSelector(
return AbstractValueFactory.inferredTypeForSelector(
new Selector.index(), typeOfIterator(node), _globalInferenceResults);
}
AbstractValue getInferredTypeOf(MemberEntity member) {
return TypeMaskFactory.inferredTypeForMember(
return AbstractValueFactory.inferredTypeForMember(
member, _globalInferenceResults);
}
AbstractValue getInferredTypeOfParameter(Local parameter) {
return TypeMaskFactory.inferredTypeForParameter(
return AbstractValueFactory.inferredTypeForParameter(
parameter, _globalInferenceResults);
}
AbstractValue selectorTypeOf(Selector selector, AbstractValue mask) {
return TypeMaskFactory.inferredTypeForSelector(
return AbstractValueFactory.inferredTypeForSelector(
selector, mask, _globalInferenceResults);
}
AbstractValue typeFromNativeBehavior(
NativeBehavior nativeBehavior, ClosedWorld closedWorld) {
return TypeMaskFactory.fromNativeBehavior(nativeBehavior, closedWorld);
return AbstractValueFactory.fromNativeBehavior(nativeBehavior, closedWorld);
}
}

View file

@ -31,7 +31,7 @@ import '../js_model/elements.dart' show JGeneratorBody;
import '../kernel/element_map.dart';
import '../kernel/kernel_backend_strategy.dart';
import '../native/native.dart' as native;
import '../types/masks.dart';
import '../types/abstract_value_domain.dart';
import '../types/types.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
@ -541,7 +541,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
}
newObject = new HCreate(cls, constructorArguments,
new TypeMask.nonNullExact(cls, closedWorld), sourceInformation,
abstractValueDomain.createNonNullExact(cls), sourceInformation,
instantiatedTypes: instantiatedTypes,
hasRtiInput: needsTypeArguments);
@ -1206,7 +1206,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
String arguments = templateArguments.join(',');
// TODO(sra): Use declared type or NativeBehavior type.
TypeMask typeMask = abstractValueDomain.dynamicType;
AbstractValue typeMask = abstractValueDomain.dynamicType;
String template;
if (targetElement.isGetter) {
template = '${templateReceiver}$nativeName';
@ -1245,7 +1245,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
}
void openFunction(MemberEntity member, [ir.FunctionNode functionNode]) {
Map<Local, TypeMask> parameterMap = <Local, TypeMask>{};
Map<Local, AbstractValue> parameterMap = <Local, AbstractValue>{};
if (functionNode != null) {
void handleParameter(ir.VariableDeclaration node) {
Local local = localsMap.getLocalVariable(node);
@ -1593,7 +1593,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
// array, as this is stronger than the iterator's `get current` type, for
// example, `get current` includes null.
// TODO(sra): The element type of a container type mask might be better.
TypeMask type = _typeInferenceMap.inferredIndexType(node);
AbstractValue type = _typeInferenceMap.inferredIndexType(node);
SourceInformation sourceInformation =
_sourceInformationBuilder.buildForInCurrent(node);
@ -1658,7 +1658,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
HInstruction iterator;
void buildInitializer() {
TypeMask mask = _typeInferenceMap.typeOfIterator(node);
AbstractValue mask = _typeInferenceMap.typeOfIterator(node);
node.iterable.accept(this);
HInstruction receiver = pop();
_pushDynamicInvocation(
@ -1672,7 +1672,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
}
HInstruction buildCondition() {
TypeMask mask = _typeInferenceMap.typeOfIteratorMoveNext(node);
AbstractValue mask = _typeInferenceMap.typeOfIteratorMoveNext(node);
_pushDynamicInvocation(
node,
mask,
@ -1686,7 +1686,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
void buildBody() {
SourceInformation sourceInformation =
_sourceInformationBuilder.buildForInCurrent(node);
TypeMask mask = _typeInferenceMap.typeOfIteratorCurrent(node);
AbstractValue mask = _typeInferenceMap.typeOfIteratorCurrent(node);
_pushDynamicInvocation(node, mask, Selectors.current, [iterator],
const <DartType>[], sourceInformation);
@ -1742,7 +1742,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
void buildInitializer() {}
HInstruction buildCondition() {
TypeMask mask = _typeInferenceMap.typeOfIteratorMoveNext(node);
AbstractValue mask = _typeInferenceMap.typeOfIteratorMoveNext(node);
_pushDynamicInvocation(
node,
mask,
@ -1756,7 +1756,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
}
void buildBody() {
TypeMask mask = _typeInferenceMap.typeOfIteratorCurrent(node);
AbstractValue mask = _typeInferenceMap.typeOfIteratorCurrent(node);
_pushDynamicInvocation(
node,
mask,
@ -2033,8 +2033,8 @@ class KernelSsaGraphBuilder extends ir.Visitor
}
}
void generateError(FunctionEntity function, String message, TypeMask typeMask,
SourceInformation sourceInformation) {
void generateError(FunctionEntity function, String message,
AbstractValue typeMask, SourceInformation sourceInformation) {
HInstruction errorMessage = graph.addConstantString(message, closedWorld);
_pushStaticInvocation(
function, [errorMessage], typeMask, const <DartType>[],
@ -2687,9 +2687,9 @@ class KernelSsaGraphBuilder extends ir.Visitor
listInstruction, type, sourceInformation);
}
TypeMask type = _typeInferenceMap.typeOfListLiteral(
AbstractValue type = _typeInferenceMap.typeOfListLiteral(
targetElement, node, abstractValueDomain);
if (!type.containsAll(closedWorld)) {
if (!abstractValueDomain.containsAll(type)) {
listInstruction.instructionType = type;
}
stack.add(listInstruction);
@ -2762,11 +2762,12 @@ class KernelSsaGraphBuilder extends ir.Visitor
// type inference might discover a more specific type, or find nothing (in
// dart2js unit tests).
TypeMask mapType = new TypeMask.nonNullSubtype(
_commonElements.mapLiteralClass, closedWorld);
TypeMask returnTypeMask = _typeInferenceMap.getReturnTypeOf(constructor);
TypeMask instructionType =
mapType.intersection(returnTypeMask, closedWorld);
AbstractValue mapType = abstractValueDomain
.createNonNullSubtype(_commonElements.mapLiteralClass);
AbstractValue returnTypeMask =
_typeInferenceMap.getReturnTypeOf(constructor);
AbstractValue instructionType =
abstractValueDomain.intersection(mapType, returnTypeMask);
addImplicitInstantiation(type);
_pushStaticInvocation(
@ -3249,7 +3250,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
return;
}
TypeMask typeMask = _typeInferenceMap.getReturnTypeOf(function);
AbstractValue typeMask = _typeInferenceMap.getReturnTypeOf(function);
List<DartType> typeArguments =
_getStaticTypeArguments(function, node.arguments);
@ -3279,7 +3280,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
void handleInvokeFactoryConstructor(
ir.StaticInvocation invocation,
ConstructorEntity function,
TypeMask typeMask,
AbstractValue typeMask,
List<HInstruction> arguments,
SourceInformation sourceInformation) {
if (function.isExternal && function.isFromEnvironmentConstructor) {
@ -3317,7 +3318,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
return;
}
TypeMask resultType = typeMask;
AbstractValue resultType = typeMask;
bool isJSArrayTypedConstructor =
function == commonElements.jsArrayTypedConstructor;
@ -3750,7 +3751,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
failedAt(_elementMap.getSpannable(targetElement, invocation),
"No NativeBehavior for $invocation"));
TypeMask ssaType =
AbstractValue ssaType =
_typeInferenceMap.typeFromNativeBehavior(nativeBehavior, closedWorld);
push(new HForeignCode(expr, ssaType, const <HInstruction>[],
nativeBehavior: nativeBehavior));
@ -3797,7 +3798,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
failedAt(_elementMap.getSpannable(targetElement, invocation),
"No NativeBehavior for $invocation"));
TypeMask ssaType =
AbstractValue ssaType =
_typeInferenceMap.typeFromNativeBehavior(nativeBehavior, closedWorld);
push(new HForeignCode(template, ssaType, inputs,
nativeBehavior: nativeBehavior));
@ -3893,7 +3894,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
MessageKind.JS_PLACEHOLDER_CAPTURE);
}
TypeMask ssaType =
AbstractValue ssaType =
_typeInferenceMap.typeFromNativeBehavior(nativeBehavior, closedWorld);
SourceInformation sourceInformation = null;
@ -3906,7 +3907,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
push(code);
DartType type = _getDartTypeIfValid(invocation.arguments.types.single);
TypeMask trustedMask = typeBuilder.trustTypeMask(type);
AbstractValue trustedMask = typeBuilder.trustTypeMask(type);
if (trustedMask != null) {
// We only allow the type argument to narrow `dynamic`, which probably
@ -3914,7 +3915,8 @@ class KernelSsaGraphBuilder extends ir.Visitor
if (abstractValueDomain.containsAll(code.instructionType)) {
// Overwrite the type with the narrower type.
code.instructionType = trustedMask;
} else if (trustedMask.containsMask(code.instructionType, closedWorld)) {
} else if (abstractValueDomain.contains(
trustedMask, code.instructionType)) {
// It is acceptable for the type parameter to be broader than the
// specified type.
} else {
@ -3942,7 +3944,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
}
void _pushStaticInvocation(MemberEntity target, List<HInstruction> arguments,
TypeMask typeMask, List<DartType> typeArguments,
AbstractValue typeMask, List<DartType> typeArguments,
{SourceInformation sourceInformation, InterfaceType instanceType}) {
// TODO(redemption): Pass current node if needed.
if (_tryInlineMethod(target, null, null, arguments, null, sourceInformation,
@ -3970,7 +3972,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
void _pushDynamicInvocation(
ir.Node node,
TypeMask mask,
AbstractValue mask,
Selector selector,
List<HInstruction> arguments,
List<DartType> typeArguments,
@ -4035,7 +4037,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
}
inputs.addAll(arguments);
TypeMask type = _typeInferenceMap.selectorTypeOf(selector, mask);
AbstractValue type = _typeInferenceMap.selectorTypeOf(selector, mask);
if (selector.isGetter) {
push(new HInvokeDynamicGetter(selector, mask, null, inputs, isIntercepted,
type, sourceInformation));
@ -4165,7 +4167,8 @@ class KernelSsaGraphBuilder extends ir.Visitor
.add(localsHandler.readLocal(closureInfo.getLocalForField(field)));
});
TypeMask type = new TypeMask.nonNullExact(closureClassEntity, closedWorld);
AbstractValue type =
abstractValueDomain.createNonNullExact(closureClassEntity);
// TODO(efortuna): Add source information here.
push(new HCreate(
closureClassEntity, capturedVariables, type, sourceInformation,
@ -4338,7 +4341,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
inputs.add(receiver);
inputs.addAll(arguments);
TypeMask typeMask;
AbstractValue typeMask;
if (target is FunctionEntity) {
typeMask = _typeInferenceMap.getReturnTypeOf(target);
} else {
@ -4537,7 +4540,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
ConstructorEntity constructor = _elementMap.getConstructor(target);
ClassEntity cls = constructor.enclosingClass;
TypeMask typeMask = new TypeMask.nonNullExact(cls, closedWorld);
AbstractValue typeMask = abstractValueDomain.createNonNullExact(cls);
InterfaceType instanceType = _elementMap.createInterfaceType(
target.enclosingClass, node.arguments.types);
instanceType = localsHandler.substInContext(instanceType);
@ -4819,7 +4822,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
bool _tryInlineMethod(
FunctionEntity function,
Selector selector,
TypeMask mask,
AbstractValue mask,
List<HInstruction> providedArguments,
ir.Node currentNode,
SourceInformation sourceInformation,
@ -4857,7 +4860,8 @@ class KernelSsaGraphBuilder extends ir.Visitor
failedAt(function, "Missing selector for inlining of $function."));
if (selector != null) {
if (!selector.applies(function)) return false;
if (mask != null && !mask.canHit(function, selector, closedWorld)) {
if (mask != null &&
!abstractValueDomain.canHit(mask, function, selector)) {
return false;
}
}
@ -4989,7 +4993,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
// NoSuchMethodError message as if we had called it.
if (function.isInstanceMember &&
function is! ConstructorBodyEntity &&
(mask == null || mask.isNullable)) {
(mask == null || abstractValueDomain.canBeNull(mask))) {
add(new HFieldGet(
null, providedArguments[0], abstractValueDomain.dynamicType,
isAssignable: false)

View file

@ -24,7 +24,6 @@ import '../js_backend/runtime_types.dart';
import '../js_emitter/code_emitter_task.dart';
import '../options.dart';
import '../types/abstract_value_domain.dart';
import '../types/masks.dart';
import '../types/types.dart';
import '../world.dart' show ClosedWorld;
import 'jump_handler.dart';
@ -215,7 +214,7 @@ abstract class GraphBuilder {
current.add(instruction);
}
HParameterValue addParameter(Entity parameter, TypeMask type) {
HParameterValue addParameter(Entity parameter, AbstractValue type) {
HParameterValue result = new HParameterValue(parameter, type);
if (lastAddedParameter == null) {
graph.entry.addBefore(graph.entry.first, result);

View file

@ -8,7 +8,7 @@ import '../constants/values.dart';
import '../elements/entities.dart';
import '../elements/names.dart';
import '../options.dart';
import '../types/masks.dart';
import '../types/abstract_value_domain.dart';
import '../types/types.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
@ -25,12 +25,12 @@ import 'types.dart';
class InvokeDynamicSpecializer {
const InvokeDynamicSpecializer();
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
ClosedWorld closedWorld) {
return TypeMaskFactory.inferredTypeForSelector(
return AbstractValueFactory.inferredTypeForSelector(
instruction.selector, instruction.mask, results);
}
@ -192,9 +192,9 @@ class IndexSpecializer extends InvokeDynamicSpecializer {
// We want the right checked mode error.
return null;
}
TypeMask receiverType =
AbstractValue receiverType =
instruction.getDartReceiver(closedWorld).instructionType;
TypeMask type = TypeMaskFactory.inferredTypeForSelector(
AbstractValue type = AbstractValueFactory.inferredTypeForSelector(
instruction.selector, receiverType, results);
return new HIndex(instruction.inputs[1], instruction.inputs[2],
instruction.selector, type);
@ -208,7 +208,7 @@ class BitNotSpecializer extends InvokeDynamicSpecializer {
return constantSystem.bitNot;
}
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
@ -249,7 +249,7 @@ class UnaryNegateSpecializer extends InvokeDynamicSpecializer {
return constantSystem.negate;
}
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
@ -296,7 +296,7 @@ class AbsSpecializer extends InvokeDynamicSpecializer {
return constantSystem.abs;
}
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
@ -331,7 +331,7 @@ class AbsSpecializer extends InvokeDynamicSpecializer {
abstract class BinaryArithmeticSpecializer extends InvokeDynamicSpecializer {
const BinaryArithmeticSpecializer();
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
@ -402,7 +402,7 @@ abstract class BinaryArithmeticSpecializer extends InvokeDynamicSpecializer {
class AddSpecializer extends BinaryArithmeticSpecializer {
const AddSpecializer();
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
@ -441,7 +441,7 @@ class DivideSpecializer extends BinaryArithmeticSpecializer {
return constantSystem.divide;
}
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInstruction instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
@ -467,7 +467,7 @@ class DivideSpecializer extends BinaryArithmeticSpecializer {
class ModuloSpecializer extends BinaryArithmeticSpecializer {
const ModuloSpecializer();
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
@ -553,7 +553,7 @@ class ModuloSpecializer extends BinaryArithmeticSpecializer {
class RemainderSpecializer extends BinaryArithmeticSpecializer {
const RemainderSpecializer();
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
@ -589,7 +589,7 @@ class MultiplySpecializer extends BinaryArithmeticSpecializer {
return constantSystem.multiply;
}
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
@ -641,7 +641,7 @@ class TruncatingDivideSpecializer extends BinaryArithmeticSpecializer {
return constantSystem.truncatingDivide;
}
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
@ -727,7 +727,7 @@ class TruncatingDivideSpecializer extends BinaryArithmeticSpecializer {
abstract class BinaryBitOpSpecializer extends BinaryArithmeticSpecializer {
const BinaryBitOpSpecializer();
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
@ -819,7 +819,7 @@ class ShiftLeftSpecializer extends BinaryBitOpSpecializer {
class ShiftRightSpecializer extends BinaryBitOpSpecializer {
const ShiftRightSpecializer();
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
@ -887,7 +887,7 @@ class BitOrSpecializer extends BinaryBitOpSpecializer {
return constantSystem.bitOr;
}
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
@ -922,7 +922,7 @@ class BitAndSpecializer extends BinaryBitOpSpecializer {
return constantSystem.bitAnd;
}
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
@ -958,7 +958,7 @@ class BitXorSpecializer extends BinaryBitOpSpecializer {
return constantSystem.bitXor;
}
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
@ -989,7 +989,7 @@ class BitXorSpecializer extends BinaryBitOpSpecializer {
abstract class RelationalSpecializer extends InvokeDynamicSpecializer {
const RelationalSpecializer();
TypeMask computeTypeFromInputTypes(
AbstractValue computeTypeFromInputTypes(
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
@ -1034,7 +1034,7 @@ class EqualsSpecializer extends RelationalSpecializer {
ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
TypeMask instructionType = left.instructionType;
AbstractValue instructionType = left.instructionType;
if (right.isConstantNull() ||
left.isPrimitiveOrNull(closedWorld.abstractValueDomain)) {
return newBuiltinVariant(instruction, closedWorld);

View file

@ -12,7 +12,6 @@ import '../js_backend/interceptor_data.dart';
import '../js_model/closure.dart' show JRecordField, JClosureField;
import '../js_model/locals.dart' show JLocal;
import '../types/abstract_value_domain.dart';
import '../types/masks.dart';
import '../types/types.dart';
import '../world.dart' show ClosedWorld;
@ -196,12 +195,12 @@ class LocalsHandler {
MemberEntity element,
ScopeInfo scopeInfo,
CapturedScope scopeData,
Map<Local, TypeMask> parameters,
Map<Local, AbstractValue> parameters,
SourceInformation sourceInformation,
{bool isGenerativeConstructorBody}) {
this.scopeInfo = scopeInfo;
parameters.forEach((Local local, TypeMask typeMask) {
parameters.forEach((Local local, AbstractValue typeMask) {
if (isGenerativeConstructorBody) {
if (scopeData.isBoxed(local)) {
// The parameter will be a field in the box passed as the
@ -275,8 +274,8 @@ class LocalsHandler {
SyntheticLocal parameter = createLocal('receiver');
// Unlike `this`, receiver is nullable since direct calls to generative
// constructor call the constructor with `null`.
HParameterValue value =
new HParameterValue(parameter, new TypeMask.exact(cls, closedWorld));
HParameterValue value = new HParameterValue(
parameter, closedWorld.abstractValueDomain.createNullableExact(cls));
builder.graph.explicitReceiverParameter = value;
builder.graph.entry.addAtEntry(value);
if (builder.lastAddedParameter == null) {
@ -341,7 +340,7 @@ class LocalsHandler {
ClosureRepresentationInfo closureData = scopeInfo;
FieldEntity redirect = redirectionMapping[local];
HInstruction receiver = readLocal(closureData.closureEntity);
TypeMask type = local is BoxLocal
AbstractValue type = local is BoxLocal
? _abstractValueDomain.nonNullType
: getTypeOfCapturedVariable(redirect);
HInstruction fieldGet = new HFieldGet(redirect, receiver, type);
@ -643,10 +642,10 @@ class LocalsHandler {
return this;
}
TypeMask cachedTypeOfThis;
AbstractValue cachedTypeOfThis;
TypeMask getTypeOfThis() {
TypeMask result = cachedTypeOfThis;
AbstractValue getTypeOfThis() {
AbstractValue result = cachedTypeOfThis;
if (result == null) {
ThisLocal local = scopeInfo.thisLocal;
ClassEntity cls = local.enclosingClass;
@ -655,21 +654,21 @@ class LocalsHandler {
// of the class that mixins the enclosing class. These two
// classes do not have a subclass relationship, so, for
// simplicity, we mark the type as an interface type.
result = new TypeMask.nonNullSubtype(cls, closedWorld);
result = _abstractValueDomain.createNonNullSubtype(cls);
} else {
result = new TypeMask.nonNullSubclass(cls, closedWorld);
result = _abstractValueDomain.createNonNullSubclass(cls);
}
cachedTypeOfThis = result;
}
return result;
}
Map<FieldEntity, TypeMask> cachedTypesOfCapturedVariables =
new Map<FieldEntity, TypeMask>();
Map<FieldEntity, AbstractValue> cachedTypesOfCapturedVariables =
new Map<FieldEntity, AbstractValue>();
TypeMask getTypeOfCapturedVariable(FieldEntity element) {
AbstractValue getTypeOfCapturedVariable(FieldEntity element) {
return cachedTypesOfCapturedVariables.putIfAbsent(element, () {
return TypeMaskFactory.inferredTypeForMember(
return AbstractValueFactory.inferredTypeForMember(
element, _globalInferenceResults);
});
}

View file

@ -18,7 +18,6 @@ import '../js/js.dart' as js;
import '../js_backend/js_backend.dart';
import '../native/native.dart' as native;
import '../types/abstract_value_domain.dart';
import '../types/masks.dart' show TypeMask;
import '../universe/selector.dart' show Selector;
import '../universe/side_effects.dart' show SideEffects;
import '../util/util.dart';
@ -1013,7 +1012,8 @@ abstract class HInstruction implements Spannable {
bool isExact(AbstractValueDomain domain) => domain.isExact(instructionType);
bool isValue(AbstractValueDomain domain) => domain.isValue(instructionType);
bool isValue(AbstractValueDomain domain) =>
domain.isPrimitiveValue(instructionType);
bool canBeNull(AbstractValueDomain domain) =>
domain.canBeNull(instructionType);
@ -3204,8 +3204,8 @@ class HTypeConversion extends HCheck {
}
// Type is refined from `dynamic`, so it might become non-redundant.
if (abstractValueDomain.containsAll(checkedType)) return false;
TypeMask inputType = checkedInput.instructionType;
return inputType.isInMask(checkedType, closedWorld);
AbstractValue inputType = checkedInput.instructionType;
return abstractValueDomain.isIn(inputType, checkedType);
}
String toString() => 'HTypeConversion(type=$typeExpression, kind=$kind, '
@ -3253,8 +3253,8 @@ class HTypeKnown extends HCheck {
bool isRedundant(ClosedWorld closedWorld) {
AbstractValueDomain abstractValueDomain = closedWorld.abstractValueDomain;
if (abstractValueDomain.containsAll(knownType)) return false;
TypeMask inputType = checkedInput.instructionType;
return inputType.isInMask(knownType, closedWorld);
AbstractValue inputType = checkedInput.instructionType;
return abstractValueDomain.isIn(inputType, knownType);
}
}

View file

@ -18,7 +18,7 @@ import '../js_backend/runtime_types.dart';
import '../native/native.dart' as native;
import '../options.dart';
import '../types/abstract_value_domain.dart';
import '../types/masks.dart';
//import '../types/masks.dart';
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
import '../universe/side_effects.dart' show SideEffects;
@ -224,7 +224,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
instruction.isNumberOrNull(_abstractValueDomain))) {
// If we can replace [instruction] with [replacement], then
// [replacement]'s type can be narrowed.
TypeMask newType = _abstractValueDomain.intersection(
AbstractValue newType = _abstractValueDomain.intersection(
replacement.instructionType, instruction.instructionType);
replacement.instructionType = newType;
}
@ -256,9 +256,10 @@ class SsaInstructionSimplifier extends HBaseVisitor
ConstantValue getConstantFromType(HInstruction node) {
if (node.isValue(_abstractValueDomain) &&
!node.canBeNull(_abstractValueDomain)) {
ValueTypeMask valueMask = node.instructionType;
if (valueMask.value.isBool) {
return valueMask.value;
ConstantValue value =
_abstractValueDomain.getPrimitiveValue(node.instructionType);
if (value.isBool) {
return value;
}
// TODO(het): consider supporting other values (short strings?)
}
@ -314,8 +315,8 @@ class SsaInstructionSimplifier extends HBaseVisitor
if (_abstractValueDomain.isEmpty(input.instructionType)) return input;
// All values that cannot be 'true' are boolified to false.
TypeMask mask = input.instructionType;
if (!mask.contains(commonElements.jsBoolClass, _closedWorld)) {
AbstractValue mask = input.instructionType;
if (!_abstractValueDomain.containsType(mask, commonElements.jsBoolClass)) {
return _graph.addConstantBool(false, _closedWorld);
}
return node;
@ -364,13 +365,13 @@ class SsaInstructionSimplifier extends HBaseVisitor
}
bool isFixed =
isFixedLength(actualReceiver.instructionType, _closedWorld);
TypeMask actualType = node.instructionType;
TypeMask resultType = _abstractValueDomain.positiveIntType;
AbstractValue actualType = node.instructionType;
AbstractValue resultType = _abstractValueDomain.positiveIntType;
// If we already have computed a more specific type, keep that type.
if (_abstractValueDomain.isInstanceOf(
if (_abstractValueDomain.isInstanceOfOrNull(
actualType, commonElements.jsUInt31Class)) {
resultType = _abstractValueDomain.uint31Type;
} else if (_abstractValueDomain.isInstanceOf(
} else if (_abstractValueDomain.isInstanceOfOrNull(
actualType, commonElements.jsUInt32Class)) {
resultType = _abstractValueDomain.uint32Type;
}
@ -406,12 +407,13 @@ class SsaInstructionSimplifier extends HBaseVisitor
if (instruction != null) return instruction;
Selector selector = node.selector;
TypeMask mask = node.mask;
AbstractValue mask = node.mask;
HInstruction input = node.inputs[1];
bool applies(MemberEntity element) {
return selector.applies(element) &&
(mask == null || mask.canHit(element, selector, _closedWorld));
(mask == null ||
_abstractValueDomain.canHit(mask, element, selector));
}
if (selector.isCall || selector.isOperator) {
@ -428,7 +430,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
}
} else if (input.isStringOrNull(_abstractValueDomain)) {
if (commonElements.appliesToJsStringSplit(
selector, mask, _closedWorld)) {
selector, mask, _abstractValueDomain)) {
return handleStringSplit(node);
} else if (applies(commonElements.jsStringOperatorAdd)) {
// `operator+` is turned into a JavaScript '+' so we need to
@ -486,7 +488,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
// t4 = setRuntimeTypeInfo(t1, t3);
//
TypeMask resultMask = _abstractValueDomain.growableListType;
AbstractValue resultMask = _abstractValueDomain.growableListType;
HInvokeDynamicMethod splitInstruction = new HInvokeDynamicMethod(
node.selector,
@ -541,7 +543,8 @@ class SsaInstructionSimplifier extends HBaseVisitor
if (folded != node) return folded;
}
TypeMask receiverType = node.getDartReceiver(_closedWorld).instructionType;
AbstractValue receiverType =
node.getDartReceiver(_closedWorld).instructionType;
MemberEntity element =
_closedWorld.locateSingleMember(node.selector, receiverType);
// TODO(ngeoffray): Also fold if it's a getter or variable.
@ -579,7 +582,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
if (!_nativeData.isNativeMember(field) &&
!node.isCallOnInterceptor(_closedWorld)) {
HInstruction receiver = node.getDartReceiver(_closedWorld);
TypeMask type = TypeMaskFactory.inferredTypeForMember(
AbstractValue type = AbstractValueFactory.inferredTypeForMember(
// ignore: UNNECESSARY_CAST
field as Entity,
_globalInferenceResults);
@ -651,8 +654,8 @@ class SsaInstructionSimplifier extends HBaseVisitor
// dependent instructions.
native.NativeBehavior nativeBehavior =
_nativeData.getNativeMethodBehavior(method);
TypeMask returnType =
TypeMaskFactory.fromNativeBehavior(nativeBehavior, _closedWorld);
AbstractValue returnType =
AbstractValueFactory.fromNativeBehavior(nativeBehavior, _closedWorld);
HInvokeDynamicMethod result = new HInvokeDynamicMethod(
node.selector,
node.mask,
@ -745,8 +748,8 @@ class SsaInstructionSimplifier extends HBaseVisitor
HInstruction handleIdentityCheck(HRelational node) {
HInstruction left = node.left;
HInstruction right = node.right;
TypeMask leftType = left.instructionType;
TypeMask rightType = right.instructionType;
AbstractValue leftType = left.instructionType;
AbstractValue rightType = right.instructionType;
HInstruction makeTrue() => _graph.addConstantBool(true, _closedWorld);
HInstruction makeFalse() => _graph.addConstantBool(false, _closedWorld);
@ -755,7 +758,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
// we don't optimize on numbers to preserve the runtime semantics.
if (!(left.isNumberOrNull(_abstractValueDomain) &&
right.isNumberOrNull(_abstractValueDomain))) {
if (leftType.isDisjoint(rightType, _closedWorld)) {
if (_abstractValueDomain.areDisjoint(leftType, rightType)) {
return makeFalse();
}
}
@ -910,14 +913,12 @@ class SsaInstructionSimplifier extends HBaseVisitor
// a class [:A<T>:], is currently always considered to have the
// raw type.
} else if (!RuntimeTypesSubstitutions.hasTypeArguments(type)) {
TypeMask expressionMask = expression.instructionType;
assert(TypeMask.assertIsNormalized(expressionMask, _closedWorld));
TypeMask typeMask = (element == commonElements.nullClass)
? new TypeMask.subtype(element, _closedWorld)
: new TypeMask.nonNullSubtype(element, _closedWorld);
if (expressionMask.union(typeMask, _closedWorld) == typeMask) {
AbstractValue expressionMask = expression.instructionType;
AbstractBool isInstanceOf =
_abstractValueDomain.isInstanceOf(expressionMask, element);
if (isInstanceOf == AbstractBool.True) {
return _graph.addConstantBool(true, _closedWorld);
} else if (expressionMask.isDisjoint(typeMask, _closedWorld)) {
} else if (isInstanceOf == AbstractBool.False) {
return _graph.addConstantBool(false, _closedWorld);
}
}
@ -934,7 +935,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
FieldEntity findConcreteFieldForDynamicAccess(
HInstruction receiver, Selector selector) {
TypeMask receiverType = receiver.instructionType;
AbstractValue receiverType = receiver.instructionType;
return _closedWorld.locateSingleField(selector, receiverType);
}
@ -1043,12 +1044,12 @@ class SsaInstructionSimplifier extends HBaseVisitor
HInstruction directFieldGet(HInstruction receiver, FieldEntity field) {
bool isAssignable = !_closedWorld.fieldNeverChanges(field);
TypeMask type;
AbstractValue type;
if (_nativeData.isNativeClass(field.enclosingClass)) {
type = TypeMaskFactory.fromNativeBehavior(
type = AbstractValueFactory.fromNativeBehavior(
_nativeData.getNativeFieldLoadBehavior(field), _closedWorld);
} else {
type = TypeMaskFactory.inferredTypeForMember(
type = AbstractValueFactory.inferredTypeForMember(
// ignore: UNNECESSARY_CAST
field as Entity,
_globalInferenceResults);
@ -1274,14 +1275,15 @@ class SsaInstructionSimplifier extends HBaseVisitor
if (input.canBePrimitive(_abstractValueDomain)) return null;
if (input.canBeNull(_abstractValueDomain)) return null;
Selector selector = Selectors.toString_;
TypeMask toStringType = TypeMaskFactory.inferredTypeForSelector(
AbstractValue toStringType = AbstractValueFactory.inferredTypeForSelector(
selector, input.instructionType, _globalInferenceResults);
if (!toStringType.containsOnlyString(_closedWorld)) return null;
if (!_abstractValueDomain.containsOnlyType(
toStringType, _closedWorld.commonElements.jsStringClass)) {
return null;
}
// All intercepted classes extend `Interceptor`, so if the receiver can't
// be a class extending `Interceptor` then it can be called directly.
if (new TypeMask.nonNullSubclass(
commonElements.jsInterceptorClass, _closedWorld)
.isDisjoint(input.instructionType, _closedWorld)) {
if (!_abstractValueDomain.canBeInterceptor(toStringType)) {
var inputs = <HInstruction>[input, input]; // [interceptor, receiver].
HInstruction result = new HInvokeDynamicMethod(
selector,
@ -1488,9 +1490,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
// be a class extending `Interceptor` then the substitution methods can be
// called directly. (We don't care about Null since contexts reading class
// type variables originate from instance methods.)
if (new TypeMask.nonNullSubclass(
commonElements.jsInterceptorClass, _closedWorld)
.isDisjoint(object.instructionType, _closedWorld)) {
if (!_abstractValueDomain.canBeInterceptor(object.instructionType)) {
return new HTypeInfoReadVariable.noInterceptor(
variable, object, node.instructionType);
}
@ -1539,7 +1539,7 @@ class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase {
isAssignable: !isFixedLength(array.instructionType, closedWorld));
indexNode.block.addBefore(indexNode, length);
TypeMask type = indexArgument.isPositiveInteger(_abstractValueDomain)
AbstractValue type = indexArgument.isPositiveInteger(_abstractValueDomain)
? indexArgument.instructionType
: closedWorld.abstractValueDomain.positiveIntType;
HBoundsCheck check = new HBoundsCheck(indexArgument, length, array, type)
@ -1607,7 +1607,7 @@ class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase {
if (zapInstructionCache == null) {
// A constant with no type does not pollute types at phi nodes.
ConstantValue constant = new SyntheticConstantValue(
SyntheticConstantKind.EMPTY_VALUE, const TypeMask.nonNullEmpty());
SyntheticConstantKind.EMPTY_VALUE, _abstractValueDomain.emptyType);
zapInstructionCache = analyzer.graph.addConstant(constant, closedWorld);
}
return zapInstructionCache;
@ -2459,7 +2459,7 @@ class SsaTypeConversionInserter extends HBaseVisitor
// on the control flow, we mark the inserted [HTypeKnown] nodes as
// non-movable.
void insertTypePropagationForDominatedUsers(
HBasicBlock dominator, HInstruction input, TypeMask convertedType) {
HBasicBlock dominator, HInstruction input, AbstractValue convertedType) {
DominatedUses dominatedUses = DominatedUses.of(input, dominator.first);
if (dominatedUses.isEmpty) return;
@ -2498,7 +2498,8 @@ class SsaTypeConversionInserter extends HBaseVisitor
if (trueTargets.isEmpty && falseTargets.isEmpty) return;
TypeMask convertedType = new TypeMask.nonNullSubtype(cls, closedWorld);
AbstractValue convertedType =
_abstractValueDomain.createNonNullSubtype(cls);
HInstruction input = instruction.expression;
for (HBasicBlock block in trueTargets) {
@ -2531,7 +2532,7 @@ class SsaTypeConversionInserter extends HBaseVisitor
if (trueTargets.isEmpty && falseTargets.isEmpty) return;
TypeMask nonNullType =
AbstractValue nonNullType =
_abstractValueDomain.excludeNull(input.instructionType);
for (HBasicBlock block in falseTargets) {
@ -3083,7 +3084,7 @@ class MemorySet {
}
}
}
TypeMask phiType = _abstractValueDomain.union(
AbstractValue phiType = _abstractValueDomain.union(
second.instructionType, first.instructionType);
if (first is HPhi && first.block == block) {
HPhi phi = first;

View file

@ -7,7 +7,7 @@ import 'nodes.dart';
import '../elements/entities.dart';
import '../elements/types.dart';
import '../io/source_information.dart';
import '../types/masks.dart';
import '../types/abstract_value_domain.dart';
import '../universe/use.dart' show TypeUse;
/// Enum that defines how a member has access to the current type variables.
@ -40,7 +40,7 @@ abstract class TypeBuilder {
/// Create a type mask for 'trusting' a DartType. Returns `null` if there is
/// no approximating type mask (i.e. the type mask would be `dynamic`).
TypeMask trustTypeMask(DartType type) {
AbstractValue trustTypeMask(DartType type) {
if (type == null) return null;
type = builder.localsHandler.substInContext(type);
type = type.unaliased;
@ -49,13 +49,13 @@ abstract class TypeBuilder {
if (type == builder.commonElements.objectType) return null;
// The type element is either a class or the void element.
ClassEntity element = (type as InterfaceType).element;
return new TypeMask.subtype(element, builder.closedWorld);
return builder.abstractValueDomain.createNullableSubtype(element);
}
/// Create an instruction to simply trust the provided type.
HInstruction _trustType(HInstruction original, DartType type) {
assert(type != null);
TypeMask mask = trustTypeMask(type);
AbstractValue mask = trustTypeMask(type);
if (mask == null) return original;
return new HTypeKnown.pinned(mask, original);
}
@ -273,8 +273,8 @@ abstract class TypeBuilder {
type = type.unaliased;
if (type.isInterfaceType && !type.treatAsRaw) {
InterfaceType interfaceType = type;
TypeMask subtype =
new TypeMask.subtype(interfaceType.element, builder.closedWorld);
AbstractValue subtype = builder.abstractValueDomain
.createNullableSubtype(interfaceType.element);
HInstruction representations = buildTypeArgumentRepresentations(
type, builder.sourceElement, sourceInformation);
builder.add(representations);
@ -282,7 +282,7 @@ abstract class TypeBuilder {
type, kind, subtype, original, representations)
..sourceInformation = sourceInformation;
} else if (type.isTypeVariable) {
TypeMask subtype = original.instructionType;
AbstractValue subtype = original.instructionType;
HInstruction typeVariable =
addTypeVariableReference(type, builder.sourceElement);
return new HTypeConversion.withTypeRepresentation(
@ -292,7 +292,7 @@ abstract class TypeBuilder {
HInstruction reifiedType =
analyzeTypeArgument(type, builder.sourceElement);
// TypeMasks don't encode function types or FutureOr types.
TypeMask refinedMask = original.instructionType;
AbstractValue refinedMask = original.instructionType;
return new HTypeConversion.withTypeRepresentation(
type, kind, refinedMask, original, reifiedType)
..sourceInformation = sourceInformation;

View file

@ -5,63 +5,66 @@
import '../common_elements.dart' show CommonElements;
import '../elements/entities.dart';
import '../native/native.dart' as native;
import '../types/masks.dart';
import '../types/abstract_value_domain.dart';
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
import '../world.dart' show ClosedWorld;
class TypeMaskFactory {
static TypeMask inferredReturnTypeForElement(
class AbstractValueFactory {
static AbstractValue inferredReturnTypeForElement(
FunctionEntity element, GlobalTypeInferenceResults results) {
return results.resultOfMember(element).returnType ??
results.closedWorld.abstractValueDomain.dynamicType;
}
static TypeMask inferredTypeForMember(
static AbstractValue inferredTypeForMember(
MemberEntity element, GlobalTypeInferenceResults results) {
return results.resultOfMember(element).type ??
results.closedWorld.abstractValueDomain.dynamicType;
}
static TypeMask inferredTypeForParameter(
static AbstractValue inferredTypeForParameter(
Local element, GlobalTypeInferenceResults results) {
return results.resultOfParameter(element).type ??
results.closedWorld.abstractValueDomain.dynamicType;
}
static TypeMask inferredTypeForSelector(
Selector selector, TypeMask mask, GlobalTypeInferenceResults results) {
return results.typeOfSelector(selector, mask) ??
static AbstractValue inferredTypeForSelector(Selector selector,
AbstractValue receiver, GlobalTypeInferenceResults results) {
return results.typeOfSelector(selector, receiver) ??
results.closedWorld.abstractValueDomain.dynamicType;
}
static TypeMask fromNativeBehavior(
static AbstractValue fromNativeBehavior(
native.NativeBehavior nativeBehavior, ClosedWorld closedWorld) {
CommonMasks commonMasks = closedWorld.abstractValueDomain;
AbstractValueDomain abstractValueDomain = closedWorld.abstractValueDomain;
var typesReturned = nativeBehavior.typesReturned;
if (typesReturned.isEmpty) return commonMasks.dynamicType;
if (typesReturned.isEmpty) return abstractValueDomain.dynamicType;
CommonElements commonElements = closedWorld.commonElements;
// [type] is either an instance of [DartType] or special objects
// like [native.SpecialType.JsObject].
TypeMask fromNativeType(dynamic type) {
AbstractValue fromNativeType(dynamic type) {
if (type == native.SpecialType.JsObject) {
return new TypeMask.nonNullExact(
commonElements.objectClass, closedWorld);
return abstractValueDomain
.createNonNullExact(commonElements.objectClass);
} else if (type.isVoid) {
return abstractValueDomain.nullType;
} else if (type.isDynamic) {
return abstractValueDomain.dynamicType;
} else if (type == commonElements.nullType) {
return abstractValueDomain.nullType;
} else if (type.treatAsDynamic) {
return abstractValueDomain.dynamicType;
} else {
return abstractValueDomain.createNonNullSubtype(type.element);
}
if (type.isVoid) return commonMasks.nullType;
if (type.isDynamic) return commonMasks.dynamicType;
if (type.element == commonElements.nullClass) return commonMasks.nullType;
if (type.treatAsDynamic) return commonMasks.dynamicType;
return new TypeMask.nonNullSubtype(type.element, closedWorld);
}
TypeMask result = typesReturned
.map(fromNativeType)
.reduce((t1, t2) => t1.union(t2, closedWorld));
assert(!result.isEmpty);
AbstractValue result =
abstractValueDomain.unionOfMany(typesReturned.map(fromNativeType));
assert(!abstractValueDomain.isEmpty(result));
return result;
}
}

View file

@ -8,6 +8,8 @@ import '../constants/values.dart' show ConstantValue;
import '../elements/entities.dart';
import '../universe/selector.dart';
enum AbstractBool { True, False, Maybe }
/// A value in an abstraction of runtime values.
abstract class AbstractValue {}
@ -89,12 +91,20 @@ abstract class AbstractValueDomain {
/// The [AbstractValue] that represents the empty set of runtime values.
AbstractValue get emptyType;
/// Creates an [AbstractValue] for non-null exact instance of [cls].
/// Creates an [AbstractValue] for a non-null exact instance of [cls].
AbstractValue createNonNullExact(ClassEntity cls);
/// Creates an [AbstractValue] for non-null instance that implements [cls].
/// Creates an [AbstractValue] for a potentially null exact instance of [cls].
AbstractValue createNullableExact(ClassEntity cls);
/// Creates an [AbstractValue] for a non-null instance that extends [cls].
AbstractValue createNonNullSubclass(ClassEntity cls);
/// Creates an [AbstractValue] for a non-null instance that implements [cls].
AbstractValue createNonNullSubtype(ClassEntity cls);
/// Creates an [AbstractValue] for a potentially null instance that implements
/// [cls].
AbstractValue createNullableSubtype(ClassEntity cls);
/// Returns `true` if [value] is a native typed array or `null` at runtime.
@ -117,7 +127,18 @@ abstract class AbstractValueDomain {
bool containsOnlyType(covariant AbstractValue value, ClassEntity cls);
/// Returns `true` if [value] is an instance of [cls] or `null` at runtime.
bool isInstanceOf(covariant AbstractValue value, ClassEntity cls);
// TODO(johnniwinther): Merge this with [isInstanceOf].
bool isInstanceOfOrNull(covariant AbstractValue value, ClassEntity cls);
/// Returns an [AbstractBool] that describes how [value] is known to be an
/// instance of [cls] at runtime.
///
/// If the returned value is `Abstract.True`, [value] is known _always_ to be
/// an instance of [cls]. If the returned value is `Abstract.False`, [value]
/// is known _never_ to be an instance of [cls]. If the returned value is
/// `Abstract.Maybe` [value] might or might not be an instance of [cls] at
/// runtime.
AbstractBool isInstanceOf(AbstractValue value, ClassEntity cls);
/// Returns `true` if [value] is empty set of runtime values.
bool isEmpty(covariant AbstractValue value);
@ -126,7 +147,7 @@ abstract class AbstractValueDomain {
bool isExact(covariant AbstractValue value);
/// Returns `true` if [value] a known primitive JavaScript value at runtime.
bool isValue(covariant AbstractValue value);
bool isPrimitiveValue(covariant AbstractValue value);
/// Returns `true` if [value] can be `null` at runtime.
bool canBeNull(covariant AbstractValue value);
@ -174,6 +195,9 @@ abstract class AbstractValueDomain {
/// Returns `true` if [value] could be a JavaScript string at runtime.
bool canBePrimitiveString(covariant AbstractValue value);
/// Return `true` if [value] could be an interceptor at runtime.
bool canBeInterceptor(covariant AbstractValue value);
/// Returns `true` if [value] is a non-null integer value at runtime.
bool isInteger(covariant AbstractValue value);
@ -233,7 +257,7 @@ abstract class AbstractValueDomain {
/// Returns [AbstractValue] for the runtime values contained in at least one
/// of [values].
AbstractValue unionOfMany(List<AbstractValue> values);
AbstractValue unionOfMany(Iterable<AbstractValue> values);
/// Returns [AbstractValue] for the runtime values that [a] and [b] have in
/// common.
@ -257,6 +281,11 @@ abstract class AbstractValueDomain {
/// Returns [dynamicType] otherwise.
AbstractValue getMapValueType(AbstractValue value);
/// Returns the primitive JavaScript value of [value] if it represents a
/// primitive JavaScript value at runtime, value at runtime. Returns `null`
/// otherwise.
ConstantValue getPrimitiveValue(covariant AbstractValue value);
/// Compute the type of all potential receivers of the set of live [members].
AbstractValue computeReceiver(Iterable<MemberEntity> members);
@ -273,6 +302,10 @@ abstract class AbstractValueDomain {
/// of runtime values of [superset].
bool contains(AbstractValue superset, AbstractValue subset);
/// Returns `true` if the set of runtime values of [subset] are all in the set
/// of runtime values of [superset].
bool isIn(AbstractValue subset, AbstractValue superset);
/// Returns the [MemberEntity] that is known to always be hit at runtime
/// [receiver].
///

View file

@ -79,59 +79,77 @@ class CommonMasks implements AbstractValueDomain {
return cachedMasks.putIfAbsent(base, createMask);
}
@override
TypeMask get dynamicType => _dynamicType ??= new TypeMask.subclass(
_closedWorld.commonElements.objectClass, _closedWorld);
@override
TypeMask get nonNullType => _nonNullType ??= new TypeMask.nonNullSubclass(
_closedWorld.commonElements.objectClass, _closedWorld);
@override
TypeMask get intType => _intType ??=
new TypeMask.nonNullSubclass(commonElements.jsIntClass, _closedWorld);
@override
TypeMask get uint32Type => _uint32Type ??=
new TypeMask.nonNullSubclass(commonElements.jsUInt32Class, _closedWorld);
@override
TypeMask get uint31Type => _uint31Type ??=
new TypeMask.nonNullExact(commonElements.jsUInt31Class, _closedWorld);
@override
TypeMask get positiveIntType =>
_positiveIntType ??= new TypeMask.nonNullSubclass(
commonElements.jsPositiveIntClass, _closedWorld);
@override
TypeMask get doubleType => _doubleType ??=
new TypeMask.nonNullExact(commonElements.jsDoubleClass, _closedWorld);
@override
TypeMask get numType => _numType ??=
new TypeMask.nonNullSubclass(commonElements.jsNumberClass, _closedWorld);
@override
TypeMask get boolType => _boolType ??=
new TypeMask.nonNullExact(commonElements.jsBoolClass, _closedWorld);
@override
TypeMask get functionType => _functionType ??=
new TypeMask.nonNullSubtype(commonElements.functionClass, _closedWorld);
@override
TypeMask get listType => _listType ??=
new TypeMask.nonNullExact(commonElements.jsArrayClass, _closedWorld);
@override
TypeMask get constListType => _constListType ??= new TypeMask.nonNullExact(
commonElements.jsUnmodifiableArrayClass, _closedWorld);
@override
TypeMask get fixedListType => _fixedListType ??=
new TypeMask.nonNullExact(commonElements.jsFixedArrayClass, _closedWorld);
@override
TypeMask get growableListType =>
_growableListType ??= new TypeMask.nonNullExact(
commonElements.jsExtendableArrayClass, _closedWorld);
@override
TypeMask get mapType => _mapType ??=
new TypeMask.nonNullSubtype(commonElements.mapLiteralClass, _closedWorld);
@override
TypeMask get constMapType => _constMapType ??= new TypeMask.nonNullSubtype(
commonElements.constMapLiteralClass, _closedWorld);
@override
TypeMask get stringType => _stringType ??=
new TypeMask.nonNullExact(commonElements.jsStringClass, _closedWorld);
@override
TypeMask get typeType => _typeType ??=
new TypeMask.nonNullExact(commonElements.typeLiteralClass, _closedWorld);
@ -146,8 +164,10 @@ class CommonMasks implements AbstractValueDomain {
new TypeMask.nonNullExact(commonElements.controllerStream, _closedWorld);
// TODO(johnniwinther): Assert that the null type has been resolved.
@override
TypeMask get nullType => _nullType ??= const TypeMask.empty();
@override
TypeMask get emptyType => const TypeMask.nonNullEmpty();
TypeMask get indexablePrimitiveType =>
@ -169,6 +189,7 @@ class CommonMasks implements AbstractValueDomain {
_interceptorType ??= new TypeMask.nonNullSubclass(
commonElements.jsInterceptorClass, _closedWorld);
@override
bool isTypedArray(TypeMask mask) {
// Just checking for `TypedData` is not sufficient, as it is an abstract
// class any user-defined class can implement. So we also check for the
@ -181,6 +202,7 @@ class CommonMasks implements AbstractValueDomain {
_closedWorld);
}
@override
bool couldBeTypedArray(TypeMask mask) {
bool intersects(TypeMask type1, TypeMask type2) =>
!type1.intersection(type2, _closedWorld).isEmpty;
@ -197,47 +219,94 @@ class CommonMasks implements AbstractValueDomain {
_closedWorld));
}
@override
TypeMask createNonNullExact(ClassEntity cls) {
return new TypeMask.nonNullExact(cls, _closedWorld);
}
@override
TypeMask createNullableExact(ClassEntity cls) {
return new TypeMask.exact(cls, _closedWorld);
}
@override
TypeMask createNonNullSubclass(ClassEntity cls) {
return new TypeMask.nonNullSubclass(cls, _closedWorld);
}
@override
TypeMask createNonNullSubtype(ClassEntity cls) {
return new TypeMask.nonNullSubtype(cls, _closedWorld);
}
@override
TypeMask createNullableSubtype(ClassEntity cls) {
return new TypeMask.subtype(cls, _closedWorld);
}
@override
TypeMask excludeNull(TypeMask mask) => mask.nonNullable();
@override
TypeMask includeNull(TypeMask mask) => mask.nullable();
@override
bool containsType(TypeMask typeMask, ClassEntity cls) {
return _closedWorld.isInstantiated(cls) &&
typeMask.contains(cls, _closedWorld);
}
@override
bool containsOnlyType(TypeMask typeMask, ClassEntity cls) {
return _closedWorld.isInstantiated(cls) && typeMask.containsOnly(cls);
}
bool isInstanceOf(TypeMask typeMask, ClassEntity cls) {
@override
bool isInstanceOfOrNull(TypeMask typeMask, ClassEntity cls) {
return _closedWorld.isImplemented(cls) &&
typeMask.satisfies(cls, _closedWorld);
}
@override
AbstractBool isInstanceOf(
covariant TypeMask expressionMask, ClassEntity cls) {
AbstractValue typeMask = (cls == commonElements.nullClass)
? createNullableSubtype(cls)
: createNonNullSubtype(cls);
if (expressionMask.union(typeMask, _closedWorld) == typeMask) {
return AbstractBool.True;
} else if (expressionMask.isDisjoint(typeMask, _closedWorld)) {
return AbstractBool.False;
} else {
return AbstractBool.Maybe;
}
}
@override
bool isEmpty(TypeMask value) => value.isEmpty;
@override
bool isExact(TypeMask value) => value.isExact || isNull(value);
bool isValue(TypeMask value) => value.isValue;
@override
bool isPrimitiveValue(TypeMask value) => value.isValue;
@override
ConstantValue getPrimitiveValue(TypeMask mask) {
if (mask.isValue) {
ValueTypeMask valueMask = mask;
return valueMask.value;
}
return null;
}
@override
bool canBeNull(TypeMask value) => value.isNullable;
@override
bool isNull(TypeMask value) => value.isNull;
@override
bool canBePrimitive(TypeMask value) {
return canBePrimitiveNumber(value) ||
canBePrimitiveArray(value) ||
@ -246,6 +315,7 @@ class CommonMasks implements AbstractValueDomain {
isNull(value);
}
@override
bool canBePrimitiveNumber(TypeMask value) {
// TODO(sra): It should be possible to test only jsDoubleClass and
// jsUInt31Class, since all others are superclasses of these two.
@ -257,10 +327,12 @@ class CommonMasks implements AbstractValueDomain {
containsType(value, commonElements.jsDoubleClass);
}
@override
bool canBePrimitiveBoolean(TypeMask value) {
return containsType(value, commonElements.jsBoolClass);
}
@override
bool canBePrimitiveArray(TypeMask value) {
return containsType(value, commonElements.jsArrayClass) ||
containsType(value, commonElements.jsFixedArrayClass) ||
@ -268,102 +340,123 @@ class CommonMasks implements AbstractValueDomain {
containsType(value, commonElements.jsUnmodifiableArrayClass);
}
@override
bool isIndexablePrimitive(TypeMask value) {
return value.containsOnlyString(_closedWorld) ||
isInstanceOf(value, commonElements.jsIndexableClass);
isInstanceOfOrNull(value, commonElements.jsIndexableClass);
}
@override
bool isFixedArray(TypeMask value) {
// TODO(sra): Recognize the union of these types as well.
return containsOnlyType(value, commonElements.jsFixedArrayClass) ||
containsOnlyType(value, commonElements.jsUnmodifiableArrayClass);
}
@override
bool isExtendableArray(TypeMask value) {
return containsOnlyType(value, commonElements.jsExtendableArrayClass);
}
@override
bool isMutableArray(TypeMask value) {
return isInstanceOf(value, commonElements.jsMutableArrayClass);
}
bool isReadableArray(TypeMask value) {
return isInstanceOf(value, commonElements.jsArrayClass);
return isInstanceOfOrNull(value, commonElements.jsMutableArrayClass);
}
@override
bool isMutableIndexable(TypeMask value) {
return isInstanceOf(value, commonElements.jsMutableIndexableClass);
return isInstanceOfOrNull(value, commonElements.jsMutableIndexableClass);
}
bool isArray(TypeMask value) => isReadableArray(value);
@override
bool isArray(TypeMask value) {
return isInstanceOfOrNull(value, commonElements.jsArrayClass);
}
@override
bool canBePrimitiveString(TypeMask value) {
return containsType(value, commonElements.jsStringClass);
}
@override
bool isInteger(TypeMask value) {
return value.containsOnlyInt(_closedWorld) && !value.isNullable;
}
@override
bool isUInt32(TypeMask value) {
return !value.isNullable &&
isInstanceOf(value, commonElements.jsUInt32Class);
isInstanceOfOrNull(value, commonElements.jsUInt32Class);
}
@override
bool isUInt31(TypeMask value) {
return !value.isNullable &&
isInstanceOf(value, commonElements.jsUInt31Class);
isInstanceOfOrNull(value, commonElements.jsUInt31Class);
}
@override
bool isPositiveInteger(TypeMask value) {
return !value.isNullable &&
isInstanceOf(value, commonElements.jsPositiveIntClass);
isInstanceOfOrNull(value, commonElements.jsPositiveIntClass);
}
@override
bool isPositiveIntegerOrNull(TypeMask value) {
return isInstanceOf(value, commonElements.jsPositiveIntClass);
return isInstanceOfOrNull(value, commonElements.jsPositiveIntClass);
}
@override
bool isIntegerOrNull(TypeMask value) {
return value.containsOnlyInt(_closedWorld);
}
@override
bool isNumber(TypeMask value) {
return value.containsOnlyNum(_closedWorld) && !value.isNullable;
}
@override
bool isNumberOrNull(TypeMask value) {
return value.containsOnlyNum(_closedWorld);
}
@override
bool isDouble(TypeMask value) {
return value.containsOnlyDouble(_closedWorld) && !value.isNullable;
}
@override
bool isDoubleOrNull(TypeMask value) {
return value.containsOnlyDouble(_closedWorld);
}
@override
bool isBoolean(TypeMask value) {
return value.containsOnlyBool(_closedWorld) && !value.isNullable;
}
@override
bool isBooleanOrNull(TypeMask value) {
return value.containsOnlyBool(_closedWorld);
}
@override
bool isString(TypeMask value) {
return value.containsOnlyString(_closedWorld) && !value.isNullable;
}
@override
bool isStringOrNull(TypeMask value) {
return value.containsOnlyString(_closedWorld);
}
@override
bool isPrimitive(TypeMask value) {
return (isPrimitiveOrNull(value) && !value.isNullable) || isNull(value);
}
@override
bool isPrimitiveOrNull(TypeMask value) {
return isIndexablePrimitive(value) ||
isNumberOrNull(value) ||
@ -371,13 +464,17 @@ class CommonMasks implements AbstractValueDomain {
isNull(value);
}
@override
TypeMask union(TypeMask a, TypeMask b) => a.union(b, _closedWorld);
@override
TypeMask intersection(TypeMask a, TypeMask b) =>
a.intersection(b, _closedWorld);
@override
bool areDisjoint(TypeMask a, TypeMask b) => a.isDisjoint(b, _closedWorld);
@override
bool containsAll(TypeMask a) => a.containsAll(_closedWorld);
@override
@ -402,7 +499,7 @@ class CommonMasks implements AbstractValueDomain {
}
@override
AbstractValue unionOfMany(List<AbstractValue> values) {
AbstractValue unionOfMany(Iterable<AbstractValue> values) {
TypeMask result = const TypeMask.nonNullEmpty();
for (TypeMask value in values) {
result = result.union(value, _closedWorld);
@ -448,6 +545,11 @@ class CommonMasks implements AbstractValueDomain {
return superset.containsMask(subset, _closedWorld);
}
@override
bool isIn(covariant TypeMask subset, covariant TypeMask superset) {
return subset.isInMask(superset, _closedWorld);
}
@override
MemberEntity locateSingleMember(
covariant TypeMask receiver, Selector selector) {
@ -480,4 +582,9 @@ class CommonMasks implements AbstractValueDomain {
}
return false;
}
@override
bool canBeInterceptor(TypeMask value) {
return !interceptorType.isDisjoint(value, _closedWorld);
}
}