From bbef9aee7c61eabc726ee9b8a4c0a743c9f19f31 Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Thu, 31 May 2018 07:26:52 +0000 Subject: [PATCH] Use AbstractValue in most of ssa Change-Id: I157081f817e033181d7c314f7567517e5ce85058 Reviewed-on: https://dart-review.googlesource.com/56522 Reviewed-by: Sigmund Cherem --- pkg/compiler/lib/src/common_elements.dart | 12 +- .../src/kernel/kernel_backend_strategy.dart | 12 +- pkg/compiler/lib/src/ssa/builder_kernel.dart | 76 +++++----- pkg/compiler/lib/src/ssa/graph_builder.dart | 3 +- .../src/ssa/invoke_dynamic_specializers.dart | 44 +++--- pkg/compiler/lib/src/ssa/locals_handler.dart | 29 ++-- pkg/compiler/lib/src/ssa/nodes.dart | 12 +- pkg/compiler/lib/src/ssa/optimize.dart | 95 ++++++------ pkg/compiler/lib/src/ssa/type_builder.dart | 16 +- pkg/compiler/lib/src/ssa/types.dart | 51 ++++--- .../lib/src/types/abstract_value_domain.dart | 43 +++++- pkg/compiler/lib/src/types/masks.dart | 137 ++++++++++++++++-- 12 files changed, 338 insertions(+), 192 deletions(-) diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart index 884aadba48c..c4419b51f9d 100644 --- a/pkg/compiler/lib/src/common_elements.dart +++ b/pkg/compiler/lib/src/common_elements.dart @@ -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; diff --git a/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart index b0487dbede5..f3b7c59016a 100644 --- a/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart +++ b/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart @@ -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); } } diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart index df419aac50e..468e0384e68 100644 --- a/pkg/compiler/lib/src/ssa/builder_kernel.dart +++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart @@ -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 parameterMap = {}; + Map parameterMap = {}; 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 [], 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 [], @@ -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 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 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 [], 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 arguments, - TypeMask typeMask, List typeArguments, + AbstractValue typeMask, List 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 arguments, List 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 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) diff --git a/pkg/compiler/lib/src/ssa/graph_builder.dart b/pkg/compiler/lib/src/ssa/graph_builder.dart index 6dc7c0aac0a..aa99124770f 100644 --- a/pkg/compiler/lib/src/ssa/graph_builder.dart +++ b/pkg/compiler/lib/src/ssa/graph_builder.dart @@ -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); diff --git a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart index e5b000349ee..5801f3f58f9 100644 --- a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart +++ b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart @@ -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); diff --git a/pkg/compiler/lib/src/ssa/locals_handler.dart b/pkg/compiler/lib/src/ssa/locals_handler.dart index bf5b34b9921..1bfef1ffd69 100644 --- a/pkg/compiler/lib/src/ssa/locals_handler.dart +++ b/pkg/compiler/lib/src/ssa/locals_handler.dart @@ -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 parameters, + Map 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 cachedTypesOfCapturedVariables = - new Map(); + Map cachedTypesOfCapturedVariables = + new Map(); - TypeMask getTypeOfCapturedVariable(FieldEntity element) { + AbstractValue getTypeOfCapturedVariable(FieldEntity element) { return cachedTypesOfCapturedVariables.putIfAbsent(element, () { - return TypeMaskFactory.inferredTypeForMember( + return AbstractValueFactory.inferredTypeForMember( element, _globalInferenceResults); }); } diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart index cb3258dd30d..67bd1e0bbdd 100644 --- a/pkg/compiler/lib/src/ssa/nodes.dart +++ b/pkg/compiler/lib/src/ssa/nodes.dart @@ -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); } } diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart index 0b25f855a02..a0ce7bea847 100644 --- a/pkg/compiler/lib/src/ssa/optimize.dart +++ b/pkg/compiler/lib/src/ssa/optimize.dart @@ -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:], 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 = [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; diff --git a/pkg/compiler/lib/src/ssa/type_builder.dart b/pkg/compiler/lib/src/ssa/type_builder.dart index 6e4c5bbc907..95cb53ed965 100644 --- a/pkg/compiler/lib/src/ssa/type_builder.dart +++ b/pkg/compiler/lib/src/ssa/type_builder.dart @@ -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; diff --git a/pkg/compiler/lib/src/ssa/types.dart b/pkg/compiler/lib/src/ssa/types.dart index 9e938c49af2..6e7ee44b59b 100644 --- a/pkg/compiler/lib/src/ssa/types.dart +++ b/pkg/compiler/lib/src/ssa/types.dart @@ -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; } } diff --git a/pkg/compiler/lib/src/types/abstract_value_domain.dart b/pkg/compiler/lib/src/types/abstract_value_domain.dart index 113002900c8..bbc5153d0b5 100644 --- a/pkg/compiler/lib/src/types/abstract_value_domain.dart +++ b/pkg/compiler/lib/src/types/abstract_value_domain.dart @@ -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 values); + AbstractValue unionOfMany(Iterable 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 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]. /// diff --git a/pkg/compiler/lib/src/types/masks.dart b/pkg/compiler/lib/src/types/masks.dart index c8a17fb896b..aba1f0a0107 100644 --- a/pkg/compiler/lib/src/types/masks.dart +++ b/pkg/compiler/lib/src/types/masks.dart @@ -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 values) { + AbstractValue unionOfMany(Iterable 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); + } }