mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 12:58:05 +00:00
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:
parent
aecf8e8dc4
commit
bbef9aee7c
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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].
|
||||
///
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue