Reduce use of Compiler.closedWorld

- in preparation for passing ClosedWorld directly between phases.

R=sigmund@google.com

Review-Url: https://codereview.chromium.org/2563443007 .
This commit is contained in:
Johnni Winther 2016-12-12 10:35:23 +01:00
parent 756cfc963d
commit 415ba7948c
25 changed files with 738 additions and 784 deletions

View file

@ -397,6 +397,7 @@ abstract class BackendClasses {
ClassElement get numImplementation;
ClassElement get stringImplementation;
ClassElement get listImplementation;
ClassElement get mutableListImplementation;
ClassElement get growableListImplementation;
ClassElement get fixedListImplementation;
ClassElement get constListImplementation;
@ -412,4 +413,8 @@ abstract class BackendClasses {
ClassElement get syncStarIterableImplementation;
ClassElement get asyncFutureImplementation;
ClassElement get asyncStarStreamImplementation;
ClassElement get indexableImplementation;
ClassElement get mutableIndexableImplementation;
bool isDefaultEqualityImplementation(Element element);
}

View file

@ -751,6 +751,8 @@ abstract class InferrerVisitor<T, E extends MinimalInferrerEngine<T>>
DiagnosticReporter get reporter => compiler.reporter;
ClosedWorld get closedWorld => compiler.closedWorld;
@override
SemanticSendVisitor get sendVisitor => this;
@ -963,7 +965,6 @@ abstract class InferrerVisitor<T, E extends MinimalInferrerEngine<T>>
T get thisType {
if (_thisType != null) return _thisType;
ClassElement cls = outermostElement.enclosingClass;
ClosedWorld closedWorld = compiler.closedWorld;
if (closedWorld.isUsedAsMixin(cls)) {
return _thisType = types.nonNullSubtype(cls);
} else {

View file

@ -180,7 +180,7 @@ abstract class InferrerEngine<T, V extends TypeSystem>
void forEachElementMatching(
Selector selector, TypeMask mask, bool f(Element element)) {
Iterable<Element> elements =
compiler.closedWorld.allFunctions.filter(selector, mask);
closedWorld.allFunctions.filter(selector, mask);
for (Element e in elements) {
if (!f(e.implementation)) return;
}
@ -492,7 +492,7 @@ class SimpleTypeInferrerVisitor<T>
});
}
if (analyzedElement.isGenerativeConstructor && cls.isAbstract) {
if (compiler.closedWorld.isInstantiated(cls)) {
if (closedWorld.isInstantiated(cls)) {
returnType = types.nonNullSubclass(cls);
} else {
// TODO(johnniwinther): Avoid analyzing [analyzedElement] in this
@ -655,7 +655,7 @@ class SimpleTypeInferrerVisitor<T>
bool isInClassOrSubclass(Element element) {
ClassElement cls = outermostElement.enclosingClass.declaration;
ClassElement enclosing = element.enclosingClass.declaration;
return compiler.closedWorld.isSubclassOf(enclosing, cls);
return closedWorld.isSubclassOf(enclosing, cls);
}
void checkIfExposesThis(Selector selector, TypeMask mask) {
@ -1362,7 +1362,7 @@ class SimpleTypeInferrerVisitor<T>
(node.asSendSet() != null) &&
(node.asSendSet().receiver != null) &&
node.asSendSet().receiver.isThis()) {
Iterable<Element> targets = compiler.closedWorld.allFunctions.filter(
Iterable<Element> targets = closedWorld.allFunctions.filter(
setterSelector, types.newTypedSelector(thisType, setterMask));
// We just recognized a field initialization of the form:
// `this.foo = 42`. If there is only one target, we can update
@ -1635,7 +1635,7 @@ class SimpleTypeInferrerVisitor<T>
} else if (element != null &&
element.isField &&
Elements.isStaticOrTopLevelField(element) &&
compiler.closedWorld.fieldNeverChanges(element)) {
closedWorld.fieldNeverChanges(element)) {
FieldElement fieldElement = element;
ConstantValue value =
compiler.backend.constants.getConstantValue(fieldElement.constant);

View file

@ -252,8 +252,7 @@ class TypeInformationSystem extends TypeSystem<TypeInformation> {
TypeInformation refineReceiver(Selector selector, TypeMask mask,
TypeInformation receiver, bool isConditional) {
if (receiver.type.isExact) return receiver;
TypeMask otherType =
compiler.closedWorld.allFunctions.receiverType(selector, mask);
TypeMask otherType = closedWorld.allFunctions.receiverType(selector, mask);
// Conditional sends (a?.b) can still narrow the possible types of `a`,
// however, we still need to consider that `a` may be null.
if (isConditional) {
@ -916,8 +915,7 @@ class TypeGraphInferrerEngine
if (!info.inLoop) return;
if (info is StaticCallSiteTypeInformation) {
compiler.inferenceWorld.addFunctionCalledInLoop(info.calledElement);
} else if (info.mask != null &&
!info.mask.containsAll(compiler.closedWorld)) {
} else if (info.mask != null && !info.mask.containsAll(closedWorld)) {
// For instance methods, we only register a selector called in a
// loop if it is a typed selector, to avoid marking too many
// methods as being called from within a loop. This cuts down
@ -1189,7 +1187,7 @@ class TypeGraphInferrerEngine
arguments, sideEffects, inLoop);
}
compiler.closedWorld.allFunctions.filter(selector, mask).forEach((callee) {
closedWorld.allFunctions.filter(selector, mask).forEach((callee) {
updateSideEffects(sideEffects, selector, callee);
});
@ -1414,11 +1412,11 @@ class TypeGraphInferrer implements TypesInferrer {
TypeMask result = const TypeMask.nonNullEmpty();
Iterable<Element> elements =
compiler.closedWorld.allFunctions.filter(selector, mask);
inferrer.closedWorld.allFunctions.filter(selector, mask);
for (Element element in elements) {
TypeMask type =
inferrer.typeOfElementWithSelector(element, selector).type;
result = result.union(type, compiler.closedWorld);
result = result.union(type, inferrer.closedWorld);
}
return result;
}

View file

@ -522,13 +522,13 @@ class MemberTypeInformation extends ElementTypeInformation
return mask;
}
if (element.isField) {
return _narrowType(compiler.closedWorld, mask, element.type);
return _narrowType(inferrer.closedWorld, mask, element.type);
}
assert(
element.isFunction || element.isGetter || element.isFactoryConstructor);
FunctionType type = element.type;
return _narrowType(compiler.closedWorld, mask, type.returnType);
return _narrowType(inferrer.closedWorld, mask, type.returnType);
}
TypeMask computeType(TypeGraphInferrerEngine inferrer) {
@ -669,7 +669,7 @@ class ParameterTypeInformation extends ElementTypeInformation {
// ignore type annotations to ensure that the checks are actually inserted
// into the function body and retained until runtime.
assert(!compiler.options.enableTypeAssertions);
return _narrowType(compiler.closedWorld, mask, element.type);
return _narrowType(inferrer.closedWorld, mask, element.type);
}
TypeMask computeType(TypeGraphInferrerEngine inferrer) {
@ -818,8 +818,7 @@ class DynamicCallSiteTypeInformation extends CallSiteTypeInformation {
void addToGraph(TypeGraphInferrerEngine inferrer) {
assert(receiver != null);
TypeMask typeMask = computeTypedSelector(inferrer);
targets =
inferrer.compiler.closedWorld.allFunctions.filter(selector, typeMask);
targets = inferrer.closedWorld.allFunctions.filter(selector, typeMask);
receiver.addUser(this);
if (arguments != null) {
arguments.forEach((info) => info.addUser(this));
@ -973,16 +972,16 @@ class DynamicCallSiteTypeInformation extends CallSiteTypeInformation {
Compiler compiler = inferrer.compiler;
JavaScriptBackend backend = compiler.backend;
TypeMask maskToUse =
compiler.closedWorld.extendMaskIfReachesAll(selector, typeMask);
inferrer.closedWorld.extendMaskIfReachesAll(selector, typeMask);
bool canReachAll = backend.hasInvokeOnSupport && (maskToUse != typeMask);
// If this call could potentially reach all methods that satisfy
// the untyped selector (through noSuchMethod's `Invocation`
// and a call to `delegate`), we iterate over all these methods to
// update their parameter types.
targets = compiler.closedWorld.allFunctions.filter(selector, maskToUse);
targets = inferrer.closedWorld.allFunctions.filter(selector, maskToUse);
Iterable<Element> typedTargets = canReachAll
? compiler.closedWorld.allFunctions.filter(selector, typeMask)
? inferrer.closedWorld.allFunctions.filter(selector, typeMask)
: targets;
// Update the call graph if the targets could have changed.
@ -1078,8 +1077,7 @@ class DynamicCallSiteTypeInformation extends CallSiteTypeInformation {
if (!abandonInferencing) {
inferrer.updateSelectorInTree(caller, call, selector, mask);
Iterable<Element> oldTargets = targets;
targets =
inferrer.compiler.closedWorld.allFunctions.filter(selector, mask);
targets = inferrer.closedWorld.allFunctions.filter(selector, mask);
for (Element element in targets) {
if (!oldTargets.contains(element)) {
MemberTypeInformation callee =

View file

@ -337,74 +337,6 @@ class JavaScriptBackend extends Backend {
static const bool TRACE_CALLS =
TRACE_METHOD == 'post' || TRACE_METHOD == 'console';
TypeMask get stringType => compiler.closedWorld.commonMasks.stringType;
TypeMask get doubleType => compiler.closedWorld.commonMasks.doubleType;
TypeMask get intType => compiler.closedWorld.commonMasks.intType;
TypeMask get uint32Type => compiler.closedWorld.commonMasks.uint32Type;
TypeMask get uint31Type => compiler.closedWorld.commonMasks.uint31Type;
TypeMask get positiveIntType =>
compiler.closedWorld.commonMasks.positiveIntType;
TypeMask get numType => compiler.closedWorld.commonMasks.numType;
TypeMask get boolType => compiler.closedWorld.commonMasks.boolType;
TypeMask get dynamicType => compiler.closedWorld.commonMasks.dynamicType;
TypeMask get nullType => compiler.closedWorld.commonMasks.nullType;
TypeMask get emptyType => const TypeMask.nonNullEmpty();
TypeMask get nonNullType => compiler.closedWorld.commonMasks.nonNullType;
TypeMask _indexablePrimitiveTypeCache;
TypeMask get indexablePrimitiveType {
if (_indexablePrimitiveTypeCache == null) {
_indexablePrimitiveTypeCache = new TypeMask.nonNullSubtype(
helpers.jsIndexableClass, compiler.closedWorld);
}
return _indexablePrimitiveTypeCache;
}
TypeMask _readableArrayTypeCache;
TypeMask get readableArrayType {
if (_readableArrayTypeCache == null) {
_readableArrayTypeCache = new TypeMask.nonNullSubclass(
helpers.jsArrayClass, compiler.closedWorld);
}
return _readableArrayTypeCache;
}
TypeMask _mutableArrayTypeCache;
TypeMask get mutableArrayType {
if (_mutableArrayTypeCache == null) {
_mutableArrayTypeCache = new TypeMask.nonNullSubclass(
helpers.jsMutableArrayClass, compiler.closedWorld);
}
return _mutableArrayTypeCache;
}
TypeMask _fixedArrayTypeCache;
TypeMask get fixedArrayType {
if (_fixedArrayTypeCache == null) {
_fixedArrayTypeCache = new TypeMask.nonNullExact(
helpers.jsFixedArrayClass, compiler.closedWorld);
}
return _fixedArrayTypeCache;
}
TypeMask _extendableArrayTypeCache;
TypeMask get extendableArrayType {
if (_extendableArrayTypeCache == null) {
_extendableArrayTypeCache = new TypeMask.nonNullExact(
helpers.jsExtendableArrayClass, compiler.closedWorld);
}
return _extendableArrayTypeCache;
}
TypeMask _unmodifiableArrayTypeCache;
TypeMask get unmodifiableArrayType {
if (_unmodifiableArrayTypeCache == null) {
_unmodifiableArrayTypeCache = new TypeMask.nonNullExact(
helpers.jsUnmodifiableArrayClass, compiler.closedWorld);
}
return _fixedArrayTypeCache;
}
/// Maps special classes to their implementation (JSXxx) class.
Map<ClassElement, ClassElement> implementationClasses;
@ -1487,14 +1419,6 @@ class JavaScriptBackend extends Backend {
bool isComplexNoSuchMethod(FunctionElement element) =>
noSuchMethodRegistry.isComplex(element);
bool isDefaultEqualityImplementation(Element element) {
assert(element.name == '==');
ClassElement classElement = element.enclosingClass;
return classElement == coreClasses.objectClass ||
classElement == helpers.jsInterceptorClass ||
classElement == helpers.jsNullClass;
}
bool methodNeedsRti(FunctionElement function) {
return rti.methodsNeedingRti.contains(function) || hasRuntimeTypeSupport;
}
@ -2099,7 +2023,7 @@ class JavaScriptBackend extends Backend {
* be visible by reflection unless some other interfaces makes them
* accessible.
*/
computeMembersNeededForReflection() {
void computeMembersNeededForReflection() {
if (_membersNeededForReflection != null) return;
if (compiler.commonElements.mirrorsLibrary == null) {
_membersNeededForReflection = const ImmutableEmptySet<Element>();
@ -3287,6 +3211,7 @@ class JavaScriptBackendClasses implements BackendClasses {
ClassElement get numImplementation => helpers.jsNumberClass;
ClassElement get stringImplementation => helpers.jsStringClass;
ClassElement get listImplementation => helpers.jsArrayClass;
ClassElement get mutableListImplementation => helpers.jsMutableArrayClass;
ClassElement get constListImplementation => helpers.jsUnmodifiableArrayClass;
ClassElement get fixedListImplementation => helpers.jsFixedArrayClass;
ClassElement get growableListImplementation => helpers.jsExtendableArrayClass;
@ -3299,4 +3224,15 @@ class JavaScriptBackendClasses implements BackendClasses {
ClassElement get asyncFutureImplementation => helpers.futureImplementation;
ClassElement get asyncStarStreamImplementation => helpers.controllerStream;
ClassElement get functionImplementation => helpers.coreClasses.functionClass;
ClassElement get indexableImplementation => helpers.jsIndexableClass;
ClassElement get mutableIndexableImplementation =>
helpers.jsMutableIndexableClass;
bool isDefaultEqualityImplementation(Element element) {
assert(element.name == '==');
ClassElement classElement = element.enclosingClass;
return classElement == helpers.coreClasses.objectClass ||
classElement == helpers.jsInterceptorClass ||
classElement == helpers.jsNullClass;
}
}

View file

@ -101,7 +101,7 @@ void handleSsaNative(SsaBuilder builder, Expression nativeBody) {
// be proportional to the number of native methods, which is bounded
// by the dart: libraries.
js.js.uncachedExpressionTemplate(nativeMethodCall),
backend.dynamicType,
builder.commonMasks.dynamicType,
inputs,
effects: new SideEffects()));
// TODO(johnniwinther): Provide source information.
@ -122,6 +122,6 @@ void handleSsaNative(SsaBuilder builder, Expression nativeBody) {
<HInstruction>[],
new SideEffects(),
null,
backend.dynamicType));
builder.commonMasks.dynamicType));
}
}

View file

@ -441,8 +441,7 @@ class SsaBuilder extends ast.Visitor
message: "Missing selector for inlining of $element."));
if (selector != null) {
if (!selector.applies(function)) return false;
if (mask != null &&
!mask.canHit(function, selector, compiler.closedWorld)) {
if (mask != null && !mask.canHit(function, selector, closedWorld)) {
return false;
}
}
@ -567,7 +566,7 @@ class SsaBuilder extends ast.Visitor
!element.isGenerativeConstructorBody &&
(mask == null || mask.isNullable)) {
addWithPosition(
new HFieldGet(null, providedArguments[0], backend.dynamicType,
new HFieldGet(null, providedArguments[0], commonMasks.dynamicType,
isAssignable: false),
currentNode);
}
@ -685,7 +684,7 @@ class SsaBuilder extends ast.Visitor
*/
HGraph buildMethod(FunctionElement functionElement) {
assert(invariant(functionElement, functionElement.isImplementation));
graph.calledInLoop = compiler.closedWorld.isCalledInLoop(functionElement);
graph.calledInLoop = closedWorld.isCalledInLoop(functionElement);
ast.FunctionExpression function = resolvedAst.node;
assert(function != null);
assert(elements.getFunctionDefinition(function) != null);
@ -711,7 +710,7 @@ class SsaBuilder extends ast.Visitor
visitCondition: () {
HParameterValue parameter = parameters.values.first;
push(new HIdentity(parameter, graph.addConstantNull(compiler),
null, backend.boolType));
null, commonMasks.boolType));
},
visitThen: () {
closeAndGotoExit(new HReturn(
@ -744,7 +743,7 @@ class SsaBuilder extends ast.Visitor
// TODO(sra): Figure out how to keep comment anchored without effects.
void addComment(String text) {
add(new HForeignCode(js.js.statementTemplateYielding(new js.Comment(text)),
backend.dynamicType, <HInstruction>[],
commonMasks.dynamicType, <HInstruction>[],
isStatement: true));
}
@ -754,7 +753,8 @@ class SsaBuilder extends ast.Visitor
HInstruction thisInstruction = localsHandler.readThis();
// Use dynamic type because the type computed by the inferrer is
// narrowed to the type annotation.
HInstruction parameter = new HParameterValue(field, backend.dynamicType);
HInstruction parameter =
new HParameterValue(field, commonMasks.dynamicType);
// Add the parameter as the last instruction of the entry block.
// If the method is intercepted, we want the actual receiver
// to be the first parameter.
@ -1284,8 +1284,8 @@ class SsaBuilder extends ast.Visitor
}, includeSuperAndInjectedMembers: true);
InterfaceType type = classElement.thisType;
TypeMask ssaType = new TypeMask.nonNullExact(
classElement.declaration, compiler.closedWorld);
TypeMask ssaType =
new TypeMask.nonNullExact(classElement.declaration, closedWorld);
List<DartType> instantiatedTypes;
addInlinedInstantiation(type);
if (!currentInlinedInstantiations.isEmpty) {
@ -1311,7 +1311,7 @@ class SsaBuilder extends ast.Visitor
TypeInfoExpressionKind.INSTANCE,
classElement.thisType,
typeArguments,
backend.dynamicType);
commonMasks.dynamicType);
add(typeInfo);
constructorArguments.add(typeInfo);
}
@ -1331,7 +1331,7 @@ class SsaBuilder extends ast.Visitor
// Null guard ensures an error if we are being called from an explicit
// 'new' of the constructor instead of via an upgrade. It is optimized out
// if there are field initializers.
add(new HFieldGet(null, newObject, backend.dynamicType,
add(new HFieldGet(null, newObject, commonMasks.dynamicType,
isAssignable: false));
for (int i = 0; i < fields.length; i++) {
add(new HFieldSet(fields[i], newObject, constructorArguments[i]));
@ -1398,9 +1398,8 @@ class SsaBuilder extends ast.Visitor
pop();
} else {
HInvokeConstructorBody invoke = new HInvokeConstructorBody(
body.declaration, bodyCallInputs, backend.nonNullType);
invoke.sideEffects =
compiler.closedWorld.getSideEffectsOfElement(constructor);
body.declaration, bodyCallInputs, commonMasks.nonNullType);
invoke.sideEffects = closedWorld.getSideEffectsOfElement(constructor);
add(invoke);
}
}
@ -1437,7 +1436,7 @@ class SsaBuilder extends ast.Visitor
backend.classNeedsRti(enclosing)) {
enclosing.typeVariables.forEach((TypeVariableType typeVariable) {
HParameterValue param =
addParameter(typeVariable.element, backend.nonNullType);
addParameter(typeVariable.element, commonMasks.nonNullType);
localsHandler.directLocals[
localsHandler.getTypeVariableAsLocal(typeVariable)] = param;
});
@ -1501,7 +1500,7 @@ class SsaBuilder extends ast.Visitor
"${n(element)}";
HConstant nameConstant = addConstantString(name);
add(new HInvokeStatic(backend.helpers.traceHelper,
<HInstruction>[nameConstant], backend.dynamicType));
<HInstruction>[nameConstant], commonMasks.dynamicType));
}
}
@ -1512,7 +1511,7 @@ class SsaBuilder extends ast.Visitor
HConstant idConstant = graph.addConstantInt(element.hashCode, compiler);
HConstant nameConstant = addConstantString(element.name);
add(new HInvokeStatic(backend.helpers.traceHelper,
<HInstruction>[idConstant, nameConstant], backend.dynamicType));
<HInstruction>[idConstant, nameConstant], commonMasks.dynamicType));
}
}
@ -1558,7 +1557,7 @@ class SsaBuilder extends ast.Visitor
value, compiler.coreTypes.boolType,
kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK);
}
HInstruction result = new HBoolify(value, backend.boolType);
HInstruction result = new HBoolify(value, commonMasks.boolType);
add(result);
return result;
}
@ -1871,8 +1870,7 @@ class SsaBuilder extends ast.Visitor
capturedVariables.add(localsHandler.readLocal(capturedLocal));
});
TypeMask type =
new TypeMask.nonNullExact(closureClassElement, compiler.closedWorld);
TypeMask type = new TypeMask.nonNullExact(closureClassElement, closedWorld);
push(new HCreate(closureClassElement, capturedVariables, type)
..sourceInformation = sourceInformationBuilder.buildCreate(node));
@ -1976,7 +1974,7 @@ class SsaBuilder extends ast.Visitor
visit(expression);
SourceInformation sourceInformation =
sourceInformationBuilder.buildGeneric(node);
push(new HNot(popBoolified(), backend.boolType)
push(new HNot(popBoolified(), commonMasks.boolType)
..sourceInformation = sourceInformation);
}
@ -2021,7 +2019,8 @@ class SsaBuilder extends ast.Visitor
@override
void visitNotEquals(ast.Send node, ast.Node left, ast.Node right, _) {
handleBinary(node, left, right);
pushWithPosition(new HNot(popBoolified(), backend.boolType), node.selector);
pushWithPosition(
new HNot(popBoolified(), commonMasks.boolType), node.selector);
}
void handleBinary(ast.Send node, ast.Node left, ast.Node right) {
@ -2137,8 +2136,7 @@ class SsaBuilder extends ast.Visitor
// handler in the case of lists, because the constant handler
// does not look at elements in the list.
TypeMask type = TypeMaskFactory.inferredTypeForElement(field, compiler);
if (!type.containsAll(compiler.closedWorld) &&
!instruction.isConstantNull()) {
if (!type.containsAll(closedWorld) && !instruction.isConstantNull()) {
// TODO(13429): The inferrer should know that an element
// cannot be null.
instruction.instructionType = type.nonNullable();
@ -2202,7 +2200,7 @@ class SsaBuilder extends ast.Visitor
// creating an [HStatic].
SourceInformation sourceInformation =
sourceInformationBuilder.buildGet(node);
push(new HStatic(method, backend.nonNullType)
push(new HStatic(method, commonMasks.nonNullType)
..sourceInformation = sourceInformation);
}
@ -2376,13 +2374,14 @@ class SsaBuilder extends ast.Visitor
}
HInstruction invokeInterceptor(HInstruction receiver) {
HInterceptor interceptor = new HInterceptor(receiver, backend.nonNullType);
HInterceptor interceptor =
new HInterceptor(receiver, commonMasks.nonNullType);
add(interceptor);
return interceptor;
}
HLiteralList buildLiteralList(List<HInstruction> inputs) {
return new HLiteralList(inputs, backend.extendableArrayType);
return new HLiteralList(inputs, commonMasks.extendableArrayType);
}
@override
@ -2417,7 +2416,7 @@ class SsaBuilder extends ast.Visitor
HInstruction expressionInstruction = visitAndPop(expression);
HInstruction instruction = buildIsNode(node, type, expressionInstruction);
add(instruction);
push(new HNot(instruction, backend.boolType));
push(new HNot(instruction, commonMasks.boolType));
}
HInstruction buildIsNode(
@ -2435,7 +2434,7 @@ class SsaBuilder extends ast.Visitor
}
generateTypeError(node, message);
HInstruction call = pop();
return new HIs.compound(type, expression, call, backend.boolType);
return new HIs.compound(type, expression, call, commonMasks.boolType);
} else if (type.isFunctionType) {
List arguments = [buildFunctionType(type), expression];
pushInvokeDynamic(
@ -2444,15 +2443,15 @@ class SsaBuilder extends ast.Visitor
CallStructure.ONE_ARG),
null,
arguments);
return new HIs.compound(type, expression, pop(), backend.boolType);
return new HIs.compound(type, expression, pop(), commonMasks.boolType);
} else if (type.isTypeVariable) {
HInstruction runtimeType =
typeBuilder.addTypeVariableReference(type, sourceElement);
Element helper = helpers.checkSubtypeOfRuntimeType;
List<HInstruction> inputs = <HInstruction>[expression, runtimeType];
pushInvokeStatic(null, helper, inputs, typeMask: backend.boolType);
pushInvokeStatic(null, helper, inputs, typeMask: commonMasks.boolType);
HInstruction call = pop();
return new HIs.variable(type, expression, call, backend.boolType);
return new HIs.variable(type, expression, call, commonMasks.boolType);
} else if (RuntimeTypes.hasTypeArguments(type)) {
ClassElement element = type.element;
Element helper = helpers.checkSubtype;
@ -2461,8 +2460,7 @@ class SsaBuilder extends ast.Visitor
add(representations);
js.Name operator = backend.namer.operatorIs(element);
HInstruction isFieldName = addConstantStringFromName(operator);
HInstruction asFieldName = compiler.closedWorld
.hasAnyStrictSubtype(element)
HInstruction asFieldName = closedWorld.hasAnyStrictSubtype(element)
? addConstantStringFromName(backend.namer.substitutionName(element))
: graph.addConstantNull(compiler);
List<HInstruction> inputs = <HInstruction>[
@ -2471,17 +2469,17 @@ class SsaBuilder extends ast.Visitor
representations,
asFieldName
];
pushInvokeStatic(node, helper, inputs, typeMask: backend.boolType);
pushInvokeStatic(node, helper, inputs, typeMask: commonMasks.boolType);
HInstruction call = pop();
return new HIs.compound(type, expression, call, backend.boolType);
return new HIs.compound(type, expression, call, commonMasks.boolType);
} else {
if (backend.hasDirectCheckFor(type)) {
return new HIs.direct(type, expression, backend.boolType);
return new HIs.direct(type, expression, commonMasks.boolType);
}
// The interceptor is not always needed. It is removed by optimization
// when the receiver type or tested type permit.
return new HIs.raw(
type, expression, invokeInterceptor(expression), backend.boolType);
return new HIs.raw(type, expression, invokeInterceptor(expression),
commonMasks.boolType);
}
}
@ -2698,7 +2696,7 @@ class SsaBuilder extends ast.Visitor
if (inputs.length != 2) {
reporter.internalError(node.argumentsNode, 'Two arguments expected.');
}
push(new HStringConcat(inputs[0], inputs[1], backend.stringType));
push(new HStringConcat(inputs[0], inputs[1], commonMasks.stringType));
}
void handleForeignJsCurrentIsolateContext(ast.Send node) {
@ -2712,7 +2710,7 @@ class SsaBuilder extends ast.Visitor
// to fetch the static state.
String name = backend.namer.staticStateHolder;
push(new HForeignCode(
js.js.parseForeignJS(name), backend.dynamicType, <HInstruction>[],
js.js.parseForeignJS(name), commonMasks.dynamicType, <HInstruction>[],
nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
} else {
// Call a helper method from the isolate library. The isolate
@ -2722,7 +2720,7 @@ class SsaBuilder extends ast.Visitor
if (element == null) {
reporter.internalError(node, 'Isolate library and compiler mismatch.');
}
pushInvokeStatic(null, element, [], typeMask: backend.dynamicType);
pushInvokeStatic(null, element, [], typeMask: commonMasks.dynamicType);
}
}
@ -2908,7 +2906,7 @@ class SsaBuilder extends ast.Visitor
// closure.
visit(link.tail.head);
push(new HInvokeClosure(new Selector.callClosure(0),
<HInstruction>[pop()], backend.dynamicType));
<HInstruction>[pop()], commonMasks.dynamicType));
} else {
// Call a helper method from the isolate library.
Element element = helpers.callInIsolate;
@ -2917,7 +2915,8 @@ class SsaBuilder extends ast.Visitor
}
List<HInstruction> inputs = <HInstruction>[];
addGenericSendArgumentsToList(link, inputs);
pushInvokeStatic(node, element, inputs, typeMask: backend.dynamicType);
pushInvokeStatic(node, element, inputs,
typeMask: commonMasks.dynamicType);
}
}
@ -2947,7 +2946,7 @@ class SsaBuilder extends ast.Visitor
push(new HForeignCode(
js.js.expressionTemplateYielding(
backend.emitter.staticFunctionAccess(function)),
backend.dynamicType,
commonMasks.dynamicType,
<HInstruction>[],
nativeBehavior: native.NativeBehavior.PURE));
return params;
@ -2970,7 +2969,7 @@ class SsaBuilder extends ast.Visitor
SideEffects sideEffects = new SideEffects.empty();
sideEffects.setAllSideEffects();
push(new HForeignCode(js.js.parseForeignJS("$isolateName = #"),
backend.dynamicType, <HInstruction>[pop()],
commonMasks.dynamicType, <HInstruction>[pop()],
nativeBehavior: native.NativeBehavior.CHANGES_OTHER,
effects: sideEffects));
}
@ -2980,7 +2979,7 @@ class SsaBuilder extends ast.Visitor
reporter.internalError(node.argumentsNode, 'Too many arguments.');
}
push(new HForeignCode(js.js.parseForeignJS(backend.namer.staticStateHolder),
backend.dynamicType, <HInstruction>[],
commonMasks.dynamicType, <HInstruction>[],
nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
}
@ -3030,7 +3029,7 @@ class SsaBuilder extends ast.Visitor
var inputs = [
graph.addConstantString(new ast.DartString.literal(loadId), compiler)
];
push(new HInvokeStatic(loadFunction, inputs, backend.nonNullType,
push(new HInvokeStatic(loadFunction, inputs, commonMasks.nonNullType,
targetCanThrow: false)..sourceInformation = sourceInformation);
}
@ -3085,7 +3084,7 @@ class SsaBuilder extends ast.Visitor
argumentsInstruction,
argumentNamesInstruction
],
typeMask: backend.dynamicType);
typeMask: commonMasks.dynamicType);
var inputs = <HInstruction>[pop()];
push(buildInvokeSuper(Selectors.noSuchMethod_, element, inputs));
@ -3233,7 +3232,8 @@ class SsaBuilder extends ast.Visitor
void visitSuperNotEquals(
ast.Send node, MethodElement method, ast.Node argument, _) {
handleSuperMethodInvoke(node, method);
pushWithPosition(new HNot(popBoolified(), backend.boolType), node.selector);
pushWithPosition(
new HNot(popBoolified(), commonMasks.boolType), node.selector);
}
@override
@ -3262,11 +3262,9 @@ class SsaBuilder extends ast.Visitor
}
bool needsSubstitutionForTypeVariableAccess(ClassElement cls) {
ClosedWorld closedWorld = compiler.closedWorld;
if (closedWorld.isUsedAsMixin(cls)) return true;
return compiler.closedWorld.anyStrictSubclassOf(cls,
(ClassElement subclass) {
return closedWorld.anyStrictSubclassOf(cls, (ClassElement subclass) {
return !rti.isTrivialSubstitution(subclass, cls);
});
}
@ -3292,7 +3290,7 @@ class SsaBuilder extends ast.Visitor
Element typeInfoSetterElement = helpers.setRuntimeTypeInfo;
pushInvokeStatic(
null, typeInfoSetterElement, <HInstruction>[newObject, typeInfo],
typeMask: backend.dynamicType,
typeMask: commonMasks.dynamicType,
sourceInformation: newObject.sourceInformation);
// The new object will now be referenced through the
@ -3324,13 +3322,13 @@ class SsaBuilder extends ast.Visitor
originalElement, send, compiler)) {
isFixedList = true;
TypeMask inferred = _inferredTypeOfNewList(send);
return inferred.containsAll(compiler.closedWorld)
? backend.fixedArrayType
return inferred.containsAll(closedWorld)
? commonMasks.fixedArrayType
: inferred;
} else if (isGrowableListConstructorCall) {
TypeMask inferred = _inferredTypeOfNewList(send);
return inferred.containsAll(compiler.closedWorld)
? backend.extendableArrayType
return inferred.containsAll(closedWorld)
? commonMasks.extendableArrayType
: inferred;
} else if (Elements.isConstructorOfTypedArraySubclass(
originalElement, compiler)) {
@ -3338,9 +3336,8 @@ class SsaBuilder extends ast.Visitor
TypeMask inferred = _inferredTypeOfNewList(send);
ClassElement cls = element.enclosingClass;
assert(backend.isNative(cls.thisType.element));
return inferred.containsAll(compiler.closedWorld)
? new TypeMask.nonNullExact(
cls.thisType.element, compiler.closedWorld)
return inferred.containsAll(closedWorld)
? new TypeMask.nonNullExact(cls.thisType.element, closedWorld)
: inferred;
} else if (element.isGenerativeConstructor) {
ClassElement cls = element.enclosingClass;
@ -3348,8 +3345,7 @@ class SsaBuilder extends ast.Visitor
// An error will be thrown.
return new TypeMask.nonNullEmpty();
} else {
return new TypeMask.nonNullExact(
cls.thisType.element, compiler.closedWorld);
return new TypeMask.nonNullExact(cls.thisType.element, closedWorld);
}
} else {
return TypeMaskFactory.inferredReturnTypeForElement(
@ -3427,7 +3423,7 @@ class SsaBuilder extends ast.Visitor
return;
}
var inputs = <HInstruction>[];
List<HInstruction> inputs = <HInstruction>[];
if (constructor.isGenerativeConstructor &&
backend.isNativeOrExtendsNative(constructor.enclosingClass) &&
!backend.isJsInterop(constructor)) {
@ -3439,9 +3435,12 @@ class SsaBuilder extends ast.Visitor
TypeMask elementType = computeType(constructor);
if (isFixedListConstructorCall) {
if (!inputs[0].isNumber(compiler)) {
HTypeConversion conversion = new HTypeConversion(null,
HTypeConversion.ARGUMENT_TYPE_CHECK, backend.numType, inputs[0]);
if (!inputs[0].isNumber(closedWorld)) {
HTypeConversion conversion = new HTypeConversion(
null,
HTypeConversion.ARGUMENT_TYPE_CHECK,
commonMasks.numType,
inputs[0]);
add(conversion);
inputs[0] = conversion;
}
@ -3453,7 +3452,7 @@ class SsaBuilder extends ast.Visitor
// TODO(sra): Array allocation should be an instruction so that canThrow
// can depend on a length type discovered in optimization.
bool canThrow = true;
if (inputs[0].isInteger(compiler) && inputs[0] is HConstant) {
if (inputs[0].isInteger(closedWorld) && inputs[0] is HConstant) {
var constant = inputs[0];
int value = constant.constant.primitiveValue;
if (0 <= value && value < 0x100000000) canThrow = false;
@ -3468,7 +3467,7 @@ class SsaBuilder extends ast.Visitor
js.Template code = js.js.parseForeignJS(r'#.fixed$length = Array');
// We set the instruction as [canThrow] to avoid it being dead code.
// We need a finer grained side effect.
add(new HForeignCode(code, backend.nullType, [stack.last],
add(new HForeignCode(code, commonMasks.nullType, [stack.last],
throwBehavior: native.NativeThrowBehavior.MAY));
}
} else if (isGrowableListConstructorCall) {
@ -3593,7 +3592,8 @@ class SsaBuilder extends ast.Visitor
if (function == compiler.commonElements.identicalFunction) {
pushWithPosition(
new HIdentity(inputs[0], inputs[1], null, backend.boolType), node);
new HIdentity(inputs[0], inputs[1], null, commonMasks.boolType),
node);
return;
} else {
pushInvokeStatic(node, function, inputs,
@ -3798,7 +3798,7 @@ class SsaBuilder extends ast.Visitor
HInstruction value = typeBuilder.analyzeTypeArgument(type, sourceElement,
sourceInformation: sourceInformationBuilder.buildGet(node));
pushInvokeStatic(node, helpers.runtimeTypeToString, [value],
typeMask: backend.stringType);
typeMask: commonMasks.stringType);
pushInvokeStatic(node, helpers.createRuntimeType, [pop()]);
}
}
@ -3821,7 +3821,7 @@ class SsaBuilder extends ast.Visitor
List<HInstruction> inputs = <HInstruction>[target];
addDynamicSendArgumentsToList(node, inputs);
push(new HInvokeClosure(
new Selector.callClosureFrom(selector), inputs, backend.dynamicType)
new Selector.callClosureFrom(selector), inputs, commonMasks.dynamicType)
..sourceInformation = sourceInformation);
}
@ -3970,11 +3970,10 @@ class SsaBuilder extends ast.Visitor
bool isOptimizableOperationOnIndexable(Selector selector, Element element) {
bool isLength = selector.isGetter && selector.name == "length";
if (isLength || selector.isIndex) {
return compiler.closedWorld.isSubtypeOf(
return closedWorld.isSubtypeOf(
element.enclosingClass.declaration, helpers.jsIndexableClass);
} else if (selector.isIndexSet) {
return compiler.closedWorld.isSubtypeOf(
element.enclosingClass.declaration,
return closedWorld.isSubtypeOf(element.enclosingClass.declaration,
helpers.jsMutableIndexableClass);
} else {
return false;
@ -3997,7 +3996,7 @@ class SsaBuilder extends ast.Visitor
return false;
}
Element element = compiler.closedWorld.locateSingleElement(selector, mask);
Element element = closedWorld.locateSingleElement(selector, mask);
if (element != null &&
!element.isField &&
!(element.isGetter && selector.isCall) &&
@ -4067,14 +4066,14 @@ class SsaBuilder extends ast.Visitor
nativeBehavior.typesReturned.add(constructor.enclosingClass.thisType);
}
return new HForeignCode(
codeTemplate, backend.dynamicType, filteredArguments,
codeTemplate, commonMasks.dynamicType, filteredArguments,
nativeBehavior: nativeBehavior)
..sourceInformation = sourceInformation;
}
var target = new HForeignCode(
js.js.parseForeignJS("${backend.namer.fixedBackendPath(element)}."
"${backend.nativeData.getFixedBackendName(element)}"),
backend.dynamicType,
commonMasks.dynamicType,
<HInstruction>[]);
add(target);
// Strip off trailing arguments that were not specified.
@ -4125,7 +4124,7 @@ class SsaBuilder extends ast.Visitor
js.Template codeTemplate = js.js.parseForeignJS(code);
nativeBehavior.codeTemplate = codeTemplate;
return new HForeignCode(codeTemplate, backend.dynamicType, inputs,
return new HForeignCode(codeTemplate, commonMasks.dynamicType, inputs,
nativeBehavior: nativeBehavior)..sourceInformation = sourceInformation;
}
@ -4145,7 +4144,7 @@ class SsaBuilder extends ast.Visitor
typeMask =
TypeMaskFactory.inferredReturnTypeForElement(element, compiler);
}
bool targetCanThrow = !compiler.closedWorld.getCannotThrow(element);
bool targetCanThrow = !closedWorld.getCannotThrow(element);
// TODO(5346): Try to avoid the need for calling [declaration] before
var instruction;
if (backend.isJsInterop(element)) {
@ -4160,8 +4159,7 @@ class SsaBuilder extends ast.Visitor
instruction.instantiatedTypes =
new List<DartType>.from(currentInlinedInstantiations);
}
instruction.sideEffects =
compiler.closedWorld.getSideEffectsOfElement(element);
instruction.sideEffects = closedWorld.getSideEffectsOfElement(element);
}
if (location == null) {
push(instruction);
@ -4195,7 +4193,7 @@ class SsaBuilder extends ast.Visitor
selector, inputs, type, sourceInformation,
isSetter: selector.isSetter || selector.isIndexSet);
instruction.sideEffects =
compiler.closedWorld.getSideEffectsOfSelector(selector, null);
closedWorld.getSideEffectsOfSelector(selector, null);
return instruction;
}
@ -5199,8 +5197,8 @@ class SsaBuilder extends ast.Visitor
visit(node.expression);
HInstruction awaited = pop();
// TODO(herhut): Improve this type.
push(new HAwait(awaited,
new TypeMask.subclass(coreClasses.objectClass, compiler.closedWorld)));
push(new HAwait(
awaited, new TypeMask.subclass(coreClasses.objectClass, closedWorld)));
}
visitTypeAnnotation(ast.TypeAnnotation node) {
@ -5259,15 +5257,14 @@ class SsaBuilder extends ast.Visitor
}
TypeMask type = _inferredTypeOfNewList(node);
if (!type.containsAll(compiler.closedWorld)) {
if (!type.containsAll(closedWorld)) {
instruction.instructionType = type;
}
stack.add(instruction);
}
_inferredTypeOfNewList(ast.Node node) =>
_resultOf(sourceElement).typeOfNewList(node) ??
compiler.closedWorld.commonMasks.dynamicType;
_resultOf(sourceElement).typeOfNewList(node) ?? commonMasks.dynamicType;
visitConditional(ast.Conditional node) {
SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node);
@ -5366,9 +5363,7 @@ class SsaBuilder extends ast.Visitor
pushInvokeDynamic(node, selector, mask, [streamIterator]);
HInstruction future = pop();
push(new HAwait(
future,
new TypeMask.subclass(
coreClasses.objectClass, compiler.closedWorld)));
future, new TypeMask.subclass(coreClasses.objectClass, closedWorld)));
return popBoolified();
}
@ -5404,9 +5399,7 @@ class SsaBuilder extends ast.Visitor
}, () {
pushInvokeDynamic(node, Selectors.cancel, null, [streamIterator]);
push(new HAwait(
pop(),
new TypeMask.subclass(
coreClasses.objectClass, compiler.closedWorld)));
pop(), new TypeMask.subclass(coreClasses.objectClass, closedWorld)));
pop();
});
}
@ -5424,7 +5417,6 @@ class SsaBuilder extends ast.Visitor
TypeMask mask = elementInferenceResults.typeOfIterator(node);
ClosedWorld closedWorld = compiler.closedWorld;
if (mask != null &&
mask.satisfies(helpers.jsIndexableClass, closedWorld) &&
// String is indexable but not iterable.
@ -5503,7 +5495,7 @@ class SsaBuilder extends ast.Visitor
// }
Element loopVariable = elements.getForInVariable(node);
SyntheticLocal indexVariable = new SyntheticLocal('_i', loopVariable);
TypeMask boolType = backend.boolType;
TypeMask boolType = commonMasks.boolType;
// These variables are shared by initializer, condition, body and update.
HInstruction array; // Set in buildInitializer.
@ -5513,7 +5505,7 @@ class SsaBuilder extends ast.Visitor
HInstruction buildGetLength() {
MemberElement lengthElement = helpers.jsIndexableLength;
HFieldGet result = new HFieldGet(
lengthElement, array, backend.positiveIntType,
lengthElement, array, commonMasks.positiveIntType,
isAssignable: !isFixed);
add(result);
return result;
@ -5584,7 +5576,7 @@ class SsaBuilder extends ast.Visitor
HInstruction index = localsHandler.readLocal(indexVariable);
HInstruction one = graph.addConstantInt(1, compiler);
HInstruction addInstruction =
new HAdd(index, one, null, backend.positiveIntType);
new HAdd(index, one, null, commonMasks.positiveIntType);
add(addInstruction);
localsHandler.updateLocal(indexVariable, addInstruction);
}
@ -5705,12 +5697,12 @@ class SsaBuilder extends ast.Visitor
// The instruction type will always be a subtype of the mapLiteralClass, but
// type inference might discover a more specific type, or find nothing (in
// dart2js unit tests).
TypeMask mapType = new TypeMask.nonNullSubtype(
helpers.mapLiteralClass, compiler.closedWorld);
TypeMask mapType =
new TypeMask.nonNullSubtype(helpers.mapLiteralClass, closedWorld);
TypeMask returnTypeMask =
TypeMaskFactory.inferredReturnTypeForElement(constructor, compiler);
TypeMask instructionType =
mapType.intersection(returnTypeMask, compiler.closedWorld);
mapType.intersection(returnTypeMask, closedWorld);
addInlinedInstantiation(expectedType);
pushInvokeStatic(node, constructor, inputs,
@ -5946,7 +5938,7 @@ class SsaBuilder extends ast.Visitor
void buildCondition() {
js.Template code = js.js.parseForeignJS('#');
push(new HForeignCode(
code, backend.boolType, [localsHandler.readLocal(switchTarget)],
code, commonMasks.boolType, [localsHandler.readLocal(switchTarget)],
nativeBehavior: native.NativeBehavior.PURE));
}
@ -6228,7 +6220,7 @@ class SsaBuilder extends ast.Visitor
// Note that the name of this local is irrelevant.
SyntheticLocal local =
new SyntheticLocal('exception', localsHandler.executableContext);
exception = new HLocalValue(local, backend.nonNullType);
exception = new HLocalValue(local, commonMasks.nonNullType);
add(exception);
HInstruction oldRethrowableException = rethrowableException;
rethrowableException = exception;
@ -6538,7 +6530,7 @@ class StringBuilderVisitor extends ast.Visitor {
// conversions.
// 2. The value can be primitive, because the library stringifier has
// fast-path code for most primitives.
if (expression.canBePrimitive(compiler)) {
if (expression.canBePrimitive(builder.closedWorld)) {
append(stringify(node, expression));
return;
}
@ -6548,7 +6540,7 @@ class StringBuilderVisitor extends ast.Visitor {
Selector selector = Selectors.toString_;
TypeMask type = TypeMaskFactory.inferredTypeForSelector(
selector, expression.instructionType, compiler);
if (type.containsOnlyString(compiler.closedWorld)) {
if (type.containsOnlyString(builder.closedWorld)) {
builder.pushInvokeDynamic(node, selector, expression.instructionType,
<HInstruction>[expression]);
append(builder.pop());
@ -6581,14 +6573,14 @@ class StringBuilderVisitor extends ast.Visitor {
HInstruction concat(HInstruction left, HInstruction right) {
HInstruction instruction =
new HStringConcat(left, right, builder.backend.stringType);
new HStringConcat(left, right, builder.commonMasks.stringType);
builder.add(instruction);
return instruction;
}
HInstruction stringify(ast.Node node, HInstruction expression) {
HInstruction instruction =
new HStringify(expression, builder.backend.stringType);
new HStringify(expression, builder.commonMasks.stringType);
builder.add(instruction);
return instruction;
}

View file

@ -32,6 +32,7 @@ import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart';
import '../universe/use.dart' show StaticUse, TypeUse;
import '../universe/side_effects.dart' show SideEffects;
import '../world.dart' show ClosedWorld;
import 'graph_builder.dart';
import 'kernel_ast_adapter.dart';
import 'kernel_string_builder.dart';
@ -207,7 +208,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
value, compiler.coreTypes.boolType,
kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK);
}
HInstruction result = new HBoolify(value, backend.boolType);
HInstruction result = new HBoolify(value, commonMasks.boolType);
add(result);
return result;
}
@ -244,8 +245,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
astAdapter.getClass(constructor.enclosingClass),
constructorArguments,
new TypeMask.nonNullExact(
astAdapter.getClass(constructor.enclosingClass),
compiler.closedWorld),
astAdapter.getClass(constructor.enclosingClass), closedWorld),
instantiatedTypes: <DartType>[
astAdapter.getClass(constructor.enclosingClass).thisType
],
@ -426,8 +426,8 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
/// Pushes a boolean checking [expression] against null.
pushCheckNull(HInstruction expression) {
push(new HIdentity(
expression, graph.addConstantNull(compiler), null, backend.boolType));
push(new HIdentity(expression, graph.addConstantNull(compiler), null,
commonMasks.boolType));
}
@override
@ -447,7 +447,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
HInstruction errorMessage =
graph.addConstantString(new DartString.literal(message), compiler);
HInstruction trap = new HForeignCode(js.js.parseForeignJS("#.#"),
backend.dynamicType, <HInstruction>[nullValue, errorMessage]);
commonMasks.dynamicType, <HInstruction>[nullValue, errorMessage]);
trap.sideEffects
..setAllSideEffects()
..setDependsOnSomething();
@ -590,7 +590,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
HInstruction buildGetLength() {
HFieldGet result = new HFieldGet(
astAdapter.jsIndexableLength, array, backend.positiveIntType,
astAdapter.jsIndexableLength, array, commonMasks.positiveIntType,
isAssignable: !isFixed);
add(result);
return result;
@ -604,7 +604,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
// array.length == _end || throwConcurrentModificationError(array)
//
HInstruction length = buildGetLength();
push(new HIdentity(length, originalLength, null, backend.boolType));
push(new HIdentity(length, originalLength, null, commonMasks.boolType));
_pushStaticInvocation(
astAdapter.checkConcurrentModificationError,
[pop(), array],
@ -624,7 +624,8 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
HInstruction buildCondition() {
HInstruction index = localsHandler.readLocal(indexVariable);
HInstruction length = buildGetLength();
HInstruction compare = new HLess(index, length, null, backend.boolType);
HInstruction compare =
new HLess(index, length, null, commonMasks.boolType);
add(compare);
return compare;
}
@ -663,7 +664,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
HInstruction index = localsHandler.readLocal(indexVariable);
HInstruction one = graph.addConstantInt(1, compiler);
HInstruction addInstruction =
new HAdd(index, one, null, backend.positiveIntType);
new HAdd(index, one, null, commonMasks.positiveIntType);
add(addInstruction);
localsHandler.updateLocal(indexVariable, addInstruction);
}
@ -718,7 +719,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
ir.Procedure typeInfoSetterFn = astAdapter.setRuntimeTypeInfo;
// TODO(efortuna): Insert source information in this static invocation.
_pushStaticInvocation(typeInfoSetterFn, <HInstruction>[newObject, typeInfo],
backend.dynamicType);
commonMasks.dynamicType);
// The new object will now be referenced through the
// `setRuntimeTypeInfo` call. We therefore set the type of that
@ -895,14 +896,15 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
element.accept(this);
elements.add(pop());
}
listInstruction = new HLiteralList(elements, backend.extendableArrayType);
listInstruction =
new HLiteralList(elements, commonMasks.extendableArrayType);
add(listInstruction);
listInstruction =
setListRuntimeTypeInfoIfNeeded(listInstruction, listLiteral);
}
TypeMask type = astAdapter.typeOfListLiteral(targetElement, listLiteral);
if (!type.containsAll(compiler.closedWorld)) {
if (!type.containsAll(closedWorld)) {
listInstruction.instructionType = type;
}
stack.add(listInstruction);
@ -932,7 +934,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
} else {
constructor = astAdapter.mapLiteralConstructor;
HLiteralList argList =
new HLiteralList(constructorArgs, backend.extendableArrayType);
new HLiteralList(constructorArgs, commonMasks.extendableArrayType);
add(argList);
inputs.add(argList);
}
@ -973,12 +975,11 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
// type inference might discover a more specific type, or find nothing (in
// dart2js unit tests).
TypeMask mapType = new TypeMask.nonNullSubtype(
astAdapter.getElement(astAdapter.mapLiteralClass),
compiler.closedWorld);
astAdapter.getElement(astAdapter.mapLiteralClass), closedWorld);
TypeMask returnTypeMask = TypeMaskFactory.inferredReturnTypeForElement(
astAdapter.getElement(constructor), compiler);
TypeMask instructionType =
mapType.intersection(returnTypeMask, compiler.closedWorld);
mapType.intersection(returnTypeMask, closedWorld);
addImplicitInstantiation(type);
_pushStaticInvocation(constructor, inputs, instructionType);
@ -1009,7 +1010,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
dartType, sourceElement,
sourceInformation: null);
_pushStaticInvocation(astAdapter.runtimeTypeToString,
<HInstruction>[value], backend.stringType);
<HInstruction>[value], commonMasks.stringType);
_pushStaticInvocation(astAdapter.createRuntimeType, <HInstruction>[pop()],
astAdapter.createRuntimeTypeReturnType);
return;
@ -1374,7 +1375,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
// to fetch the static state.
String name = backend.namer.staticStateHolder;
push(new HForeignCode(
js.js.parseForeignJS(name), backend.dynamicType, <HInstruction>[],
js.js.parseForeignJS(name), commonMasks.dynamicType, <HInstruction>[],
nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
} else {
// Call a helper method from the isolate library. The isolate library uses
@ -1385,7 +1386,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
compiler.reporter.internalError(astAdapter.getNode(invocation),
'Isolate library and compiler mismatch.');
}
_pushStaticInvocation(target, <HInstruction>[], backend.dynamicType);
_pushStaticInvocation(target, <HInstruction>[], commonMasks.dynamicType);
}
}
@ -1401,7 +1402,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
// If the isolate library is not used, we ignore the isolate argument and
// just invoke the closure.
push(new HInvokeClosure(new Selector.callClosure(0),
<HInstruction>[inputs[1]], backend.dynamicType));
<HInstruction>[inputs[1]], commonMasks.dynamicType));
} else {
// Call a helper method from the isolate library.
ir.Procedure callInIsolate = astAdapter.callInIsolate;
@ -1409,7 +1410,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
compiler.reporter.internalError(astAdapter.getNode(invocation),
'Isolate library and compiler mismatch.');
}
_pushStaticInvocation(callInIsolate, inputs, backend.dynamicType);
_pushStaticInvocation(callInIsolate, inputs, commonMasks.dynamicType);
}
}
@ -1443,7 +1444,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
push(new HForeignCode(
js.js.expressionTemplateYielding(backend.emitter
.staticFunctionAccess(astAdapter.getMember(staticTarget))),
backend.dynamicType,
commonMasks.dynamicType,
<HInstruction>[],
nativeBehavior: native.NativeBehavior.PURE));
return;
@ -1470,8 +1471,8 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
String isolateName = backend.namer.staticStateHolder;
SideEffects sideEffects = new SideEffects.empty();
sideEffects.setAllSideEffects();
push(new HForeignCode(
js.js.parseForeignJS("$isolateName = #"), backend.dynamicType, inputs,
push(new HForeignCode(js.js.parseForeignJS("$isolateName = #"),
commonMasks.dynamicType, inputs,
nativeBehavior: native.NativeBehavior.CHANGES_OTHER,
effects: sideEffects));
}
@ -1483,7 +1484,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
}
push(new HForeignCode(js.js.parseForeignJS(backend.namer.staticStateHolder),
backend.dynamicType, <HInstruction>[],
commonMasks.dynamicType, <HInstruction>[],
nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
}
@ -1670,7 +1671,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
return;
}
List<HInstruction> inputs = _visitPositionalArguments(invocation.arguments);
push(new HStringConcat(inputs[0], inputs[1], backend.stringType));
push(new HStringConcat(inputs[0], inputs[1], commonMasks.stringType));
}
void _pushStaticInvocation(
@ -1736,8 +1737,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
capturedVariables.add(localsHandler.readLocal(capturedLocal));
});
TypeMask type =
new TypeMask.nonNullExact(closureClassElement, compiler.closedWorld);
TypeMask type = new TypeMask.nonNullExact(closureClassElement, closedWorld);
// TODO(efortuna): Add source information here.
push(new HCreate(closureClassElement, capturedVariables, type));
@ -1798,7 +1798,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
HInterceptor _interceptorFor(HInstruction intercepted) {
HInterceptor interceptor =
new HInterceptor(intercepted, backend.nonNullType);
new HInterceptor(intercepted, commonMasks.nonNullType);
add(interceptor);
return interceptor;
}
@ -1835,7 +1835,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
null,
isSetter: selector.isSetter || selector.isIndexSet);
instruction.sideEffects =
compiler.closedWorld.getSideEffectsOfSelector(selector, null);
closedWorld.getSideEffectsOfSelector(selector, null);
push(instruction);
}
@ -1846,7 +1846,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
List<HInstruction> arguments =
_visitArgumentsForStaticTarget(target.function, invocation.arguments);
TypeMask typeMask = new TypeMask.nonNullExact(
astAdapter.getElement(target.enclosingClass), compiler.closedWorld);
astAdapter.getElement(target.enclosingClass), closedWorld);
_pushStaticInvocation(target, arguments, typeMask);
}
@ -1868,17 +1868,17 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
if (type is MalformedType) {
ErroneousElement element = type.element;
generateTypeError(isExpression, element.message);
push(new HIs.compound(type, expression, pop(), backend.boolType));
push(new HIs.compound(type, expression, pop(), commonMasks.boolType));
return;
}
if (type.isFunctionType) {
List arguments = <HInstruction>[buildFunctionType(type), expression];
_pushDynamicInvocation(isExpression, backend.boolType, arguments,
_pushDynamicInvocation(isExpression, commonMasks.boolType, arguments,
selector: new Selector.call(
new PrivateName('_isTest', astAdapter.jsHelperLibrary),
CallStructure.ONE_ARG));
push(new HIs.compound(type, expression, pop(), backend.boolType));
push(new HIs.compound(type, expression, pop(), commonMasks.boolType));
return;
}
@ -1886,22 +1886,22 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
HInstruction runtimeType =
typeBuilder.addTypeVariableReference(type, sourceElement);
_pushStaticInvocation(astAdapter.checkSubtypeOfRuntimeType,
<HInstruction>[expression, runtimeType], backend.boolType);
push(new HIs.variable(type, expression, pop(), backend.boolType));
<HInstruction>[expression, runtimeType], commonMasks.boolType);
push(new HIs.variable(type, expression, pop(), commonMasks.boolType));
return;
}
// TODO(sra): Type with type parameters.
if (backend.hasDirectCheckFor(type)) {
push(new HIs.direct(type, expression, backend.boolType));
push(new HIs.direct(type, expression, commonMasks.boolType));
return;
}
// The interceptor is not always needed. It is removed by optimization
// when the receiver type or tested type permit.
HInterceptor interceptor = _interceptorFor(expression);
push(new HIs.raw(type, expression, interceptor, backend.boolType));
push(new HIs.raw(type, expression, interceptor, commonMasks.boolType));
}
@override
@ -1931,7 +1931,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
@override
void visitNot(ir.Not not) {
not.operand.accept(this);
push(new HNot(popBoolified(), backend.boolType));
push(new HNot(popBoolified(), commonMasks.boolType));
}
@override

View file

@ -179,6 +179,8 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
Compiler get compiler => backend.compiler;
ClosedWorld get closedWorld => compiler.closedWorld;
NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter;
CodegenRegistry get registry => work.registry;
@ -261,8 +263,8 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
return MAX;
}
bool requiresUintConversion(instruction) {
if (instruction.isUInt31(compiler)) return false;
bool requiresUintConversion(HInstruction instruction) {
if (instruction.isUInt31(closedWorld)) return false;
if (bitWidth(instruction) <= 31) return false;
// If the result of a bit-operation is only used by other bit
// operations, we do not have to convert to an unsigned integer.
@ -1381,11 +1383,11 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
visitShiftRight(HShiftRight node) => visitBitInvokeBinary(node, '>>>');
visitTruncatingDivide(HTruncatingDivide node) {
assert(node.isUInt31(compiler));
assert(node.isUInt31(closedWorld));
// TODO(karlklose): Enable this assertion again when type propagation is
// fixed. Issue 23555.
// assert(node.left.isUInt32(compiler));
assert(node.right.isPositiveInteger(compiler));
assert(node.right.isPositiveInteger(closedWorld));
use(node.left);
js.Expression jsLeft = pop();
use(node.right);
@ -1709,22 +1711,20 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
// type because our optimizations might end up in a state where the
// invoke dynamic knows more than the receiver.
ClassElement enclosing = node.element.enclosingClass;
if (compiler.closedWorld.isInstantiated(enclosing)) {
return new TypeMask.nonNullExact(
enclosing.declaration, compiler.closedWorld);
if (closedWorld.isInstantiated(enclosing)) {
return new TypeMask.nonNullExact(enclosing.declaration, closedWorld);
} else {
// The element is mixed in so a non-null subtype mask is the most
// precise we have.
assert(invariant(node, compiler.closedWorld.isUsedAsMixin(enclosing),
assert(invariant(node, closedWorld.isUsedAsMixin(enclosing),
message: "Element ${node.element} from $enclosing expected "
"to be mixed in."));
return new TypeMask.nonNullSubtype(
enclosing.declaration, compiler.closedWorld);
return new TypeMask.nonNullSubtype(enclosing.declaration, closedWorld);
}
}
// If [JSInvocationMirror._invokeOn] is enabled, and this call
// might hit a `noSuchMethod`, we register an untyped selector.
return compiler.closedWorld.extendMaskIfReachesAll(selector, mask);
return closedWorld.extendMaskIfReachesAll(selector, mask);
}
void registerMethodInvoke(HInvokeDynamic node) {
@ -2098,13 +2098,14 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
HInstruction left = relational.left;
HInstruction right = relational.right;
if (left.isStringOrNull(compiler) && right.isStringOrNull(compiler)) {
if (left.isStringOrNull(closedWorld) &&
right.isStringOrNull(closedWorld)) {
return true;
}
// This optimization doesn't work for NaN, so we only do it if the
// type is known to be an integer.
return left.isInteger(compiler) && right.isInteger(compiler);
return left.isInteger(closedWorld) && right.isInteger(closedWorld);
}
bool handledBySpecialCase = false;
@ -2240,13 +2241,13 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
js.Expression over;
if (node.staticChecks != HBoundsCheck.ALWAYS_ABOVE_ZERO) {
use(node.index);
if (node.index.isInteger(compiler)) {
if (node.index.isInteger(closedWorld)) {
under = js.js("# < 0", pop());
} else {
js.Expression jsIndex = pop();
under = js.js("# >>> 0 !== #", [jsIndex, jsIndex]);
}
} else if (!node.index.isInteger(compiler)) {
} else if (!node.index.isInteger(closedWorld)) {
checkInt(node.index, '!==');
under = pop();
}
@ -2376,9 +2377,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
void visitStringify(HStringify node) {
HInstruction input = node.inputs.first;
if (input.isString(compiler)) {
if (input.isString(closedWorld)) {
use(input);
} else if (input.isInteger(compiler) || input.isBoolean(compiler)) {
} else if (input.isInteger(closedWorld) || input.isBoolean(closedWorld)) {
// JavaScript's + operator with a string for the left operand will convert
// the right operand to a string, and the conversion result is correct.
use(input);
@ -2761,8 +2762,8 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
} else if (type.isFunctionType) {
checkType(input, interceptor, type, sourceInformation,
negative: negative);
} else if ((input.canBePrimitive(compiler) &&
!input.canBePrimitiveArray(compiler)) ||
} else if ((input.canBePrimitive(closedWorld) &&
!input.canBePrimitiveArray(closedWorld)) ||
input.canBeNull()) {
checkObject(input, relation, node.sourceInformation);
js.Expression objectTest = pop();
@ -2787,14 +2788,13 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
js.Expression generateReceiverOrArgumentTypeTest(
HInstruction input, TypeMask checkedType) {
ClosedWorld closedWorld = compiler.closedWorld;
TypeMask inputType = input.instructionType;
// Figure out if it is beneficial to turn this into a null check.
// V8 generally prefers 'typeof' checks, but for integers and
// indexable primitives we cannot compile this test into a single
// typeof check so the null check is cheaper.
bool isIntCheck = checkedType.containsOnlyInt(closedWorld);
bool turnIntoNumCheck = isIntCheck && input.isIntegerOrNull(compiler);
bool turnIntoNumCheck = isIntCheck && input.isIntegerOrNull(closedWorld);
bool turnIntoNullCheck = !turnIntoNumCheck &&
(checkedType.nullable() == inputType) &&
(isIntCheck ||
@ -2827,12 +2827,11 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
void visitTypeConversion(HTypeConversion node) {
if (node.isArgumentTypeCheck || node.isReceiverTypeCheck) {
ClosedWorld closedWorld = compiler.closedWorld;
// An int check if the input is not int or null, is not
// sufficient for doing an argument or receiver check.
assert(compiler.options.trustTypeAnnotations ||
!node.checkedType.containsOnlyInt(closedWorld) ||
node.checkedInput.isIntegerOrNull(compiler));
node.checkedInput.isIntegerOrNull(closedWorld));
js.Expression test = generateReceiverOrArgumentTypeTest(
node.checkedInput, node.checkedType);
js.Block oldContainer = currentContainer;
@ -3010,7 +3009,6 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
bool typeVariableAccessNeedsSubstitution(
TypeVariableElement element, TypeMask receiverMask) {
ClassElement cls = element.enclosingClass;
ClosedWorld closedWorld = compiler.closedWorld;
// See if the receiver type narrows the set of classes to ones that can be
// indexed.

View file

@ -8,6 +8,7 @@ import '../elements/elements.dart';
import '../js_backend/js_backend.dart';
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
import '../world.dart' show ClosedWorld;
import 'nodes.dart';
/**
@ -22,6 +23,8 @@ class SsaInstructionSelection extends HBaseVisitor {
JavaScriptBackend get backend => compiler.backend;
ClosedWorld get closedWorld => compiler.closedWorld;
void visitGraph(HGraph graph) {
this.graph = graph;
visitDominatorTree(graph);
@ -67,7 +70,7 @@ class SsaInstructionSelection extends HBaseVisitor {
HInstruction interceptor = node.interceptor;
if (interceptor != null) {
return new HIsViaInterceptor(
node.typeExpression, interceptor, backend.boolType);
node.typeExpression, interceptor, closedWorld.commonMasks.boolType);
}
}
return node;
@ -86,7 +89,7 @@ class SsaInstructionSelection extends HBaseVisitor {
if (leftType.isNullable && rightType.isNullable) {
if (left.isConstantNull() ||
right.isConstantNull() ||
(left.isPrimitive(compiler) && leftType == rightType)) {
(left.isPrimitive(closedWorld) && leftType == rightType)) {
return '==';
}
return null;
@ -242,7 +245,7 @@ class SsaInstructionSelection extends HBaseVisitor {
HInstruction bitop(String assignOp) {
// HBitAnd, HBitOr etc. are more difficult because HBitAnd(a.x, y)
// sometimes needs to be forced to unsigned: a.x = (a.x & y) >>> 0.
if (op.isUInt31(compiler)) return simpleBinary(assignOp);
if (op.isUInt31(closedWorld)) return simpleBinary(assignOp);
return noMatchingRead();
}

View file

@ -42,6 +42,10 @@ abstract class GraphBuilder {
CodegenRegistry get registry;
ClosedWorld get closedWorld => compiler.closedWorld;
CommonMasks get commonMasks => closedWorld.commonMasks;
/// Used to track the locals while building the graph.
LocalsHandler localsHandler;
@ -75,8 +79,8 @@ abstract class GraphBuilder {
/// Pushes a boolean checking [expression] against null.
pushCheckNull(HInstruction expression) {
push(new HIdentity(
expression, graph.addConstantNull(compiler), null, backend.boolType));
push(new HIdentity(expression, graph.addConstantNull(compiler), null,
closedWorld.commonMasks.boolType));
}
void dup() {
@ -225,7 +229,7 @@ abstract class GraphBuilder {
TypeInfoExpressionKind.INSTANCE,
(type.element as ClassElement).thisType,
rtiInputs,
backend.dynamicType);
closedWorld.commonMasks.dynamicType);
add(typeInfo);
return callSetRuntimeTypeInfo(typeInfo, newObject);
}

View file

@ -97,7 +97,7 @@ class SsaSimplifyInterceptors extends HBaseVisitor
bool canUseSelfForInterceptor(
HInstruction receiver, Set<ClassElement> interceptedClasses) {
if (receiver.canBePrimitive(compiler)) {
if (receiver.canBePrimitive(closedWorld)) {
// Primitives always need interceptors.
return false;
}
@ -312,9 +312,9 @@ class SsaSimplifyInterceptors extends HBaseVisitor
if (receiver.canBeNull()) {
if (!interceptedClasses.contains(helpers.jsNullClass)) {
// Can use `(receiver && C)` only if receiver is either null or truthy.
if (!(receiver.canBePrimitiveNumber(compiler) ||
receiver.canBePrimitiveBoolean(compiler) ||
receiver.canBePrimitiveString(compiler))) {
if (!(receiver.canBePrimitiveNumber(closedWorld) ||
receiver.canBePrimitiveBoolean(closedWorld) ||
receiver.canBePrimitiveString(closedWorld))) {
ClassElement interceptorClass = tryComputeConstantInterceptorFromType(
receiver.instructionType.nonNullable(), interceptedClasses);
if (interceptorClass != null) {

View file

@ -24,13 +24,13 @@ class InvokeDynamicSpecializer {
const InvokeDynamicSpecializer();
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
return TypeMaskFactory.inferredTypeForSelector(
instruction.selector, instruction.mask, compiler);
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
return null;
}
@ -85,9 +85,9 @@ class IndexAssignSpecializer extends InvokeDynamicSpecializer {
const IndexAssignSpecializer();
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler) {
if (instruction.inputs[1].isMutableIndexable(compiler)) {
if (!instruction.inputs[2].isInteger(compiler) &&
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
if (instruction.inputs[1].isMutableIndexable(closedWorld)) {
if (!instruction.inputs[2].isInteger(closedWorld) &&
compiler.options.enableTypeAssertions) {
// We want the right checked mode error.
return null;
@ -103,9 +103,9 @@ class IndexSpecializer extends InvokeDynamicSpecializer {
const IndexSpecializer();
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler) {
if (!instruction.inputs[1].isIndexablePrimitive(compiler)) return null;
if (!instruction.inputs[2].isInteger(compiler) &&
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
if (!instruction.inputs[1].isIndexablePrimitive(closedWorld)) return null;
if (!instruction.inputs[2].isInteger(closedWorld) &&
compiler.options.enableTypeAssertions) {
// We want the right checked mode error.
return null;
@ -127,22 +127,21 @@ class BitNotSpecializer extends InvokeDynamicSpecializer {
}
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
// All bitwise operations on primitive types either produce an
// integer or throw an error.
JavaScriptBackend backend = compiler.backend;
if (instruction.inputs[1].isPrimitiveOrNull(compiler)) {
return backend.uint32Type;
if (instruction.inputs[1].isPrimitiveOrNull(closedWorld)) {
return closedWorld.commonMasks.uint32Type;
}
return super.computeTypeFromInputTypes(instruction, compiler);
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInstruction input = instruction.inputs[1];
if (input.isNumber(compiler)) {
if (input.isNumber(closedWorld)) {
return new HBitNot(input, instruction.selector,
computeTypeFromInputTypes(instruction, compiler));
computeTypeFromInputTypes(instruction, compiler, closedWorld));
}
return null;
}
@ -156,16 +155,16 @@ class UnaryNegateSpecializer extends InvokeDynamicSpecializer {
}
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
TypeMask operandType = instruction.inputs[1].instructionType;
if (instruction.inputs[1].isNumberOrNull(compiler)) return operandType;
return super.computeTypeFromInputTypes(instruction, compiler);
if (instruction.inputs[1].isNumberOrNull(closedWorld)) return operandType;
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInstruction input = instruction.inputs[1];
if (input.isNumber(compiler)) {
if (input.isNumber(closedWorld)) {
return new HNegate(input, instruction.selector, input.instructionType);
}
return null;
@ -176,31 +175,33 @@ abstract class BinaryArithmeticSpecializer extends InvokeDynamicSpecializer {
const BinaryArithmeticSpecializer();
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
JavaScriptBackend backend = compiler.backend;
if (left.isIntegerOrNull(compiler) && right.isIntegerOrNull(compiler)) {
return backend.intType;
if (left.isIntegerOrNull(closedWorld) &&
right.isIntegerOrNull(closedWorld)) {
return closedWorld.commonMasks.intType;
}
if (left.isNumberOrNull(compiler)) {
if (left.isDoubleOrNull(compiler) || right.isDoubleOrNull(compiler)) {
return backend.doubleType;
if (left.isNumberOrNull(closedWorld)) {
if (left.isDoubleOrNull(closedWorld) ||
right.isDoubleOrNull(closedWorld)) {
return closedWorld.commonMasks.doubleType;
}
return backend.numType;
return closedWorld.commonMasks.numType;
}
return super.computeTypeFromInputTypes(instruction, compiler);
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
}
bool isBuiltin(HInvokeDynamic instruction, Compiler compiler) {
return instruction.inputs[1].isNumber(compiler) &&
instruction.inputs[2].isNumber(compiler);
bool isBuiltin(HInvokeDynamic instruction, ClosedWorld closedWorld) {
return instruction.inputs[1].isNumber(closedWorld) &&
instruction.inputs[2].isNumber(closedWorld);
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler) {
if (isBuiltin(instruction, compiler)) {
HInstruction builtin = newBuiltinVariant(instruction, compiler);
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
if (isBuiltin(instruction, closedWorld)) {
HInstruction builtin =
newBuiltinVariant(instruction, compiler, closedWorld);
if (builtin != null) return builtin;
// Even if there is no builtin equivalent instruction, we know
// the instruction does not have any side effect, and that it
@ -210,20 +211,22 @@ abstract class BinaryArithmeticSpecializer extends InvokeDynamicSpecializer {
return null;
}
bool inputsArePositiveIntegers(HInstruction instruction, Compiler compiler) {
bool inputsArePositiveIntegers(
HInstruction instruction, ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
return left.isPositiveIntegerOrNull(compiler) &&
right.isPositiveIntegerOrNull(compiler);
return left.isPositiveIntegerOrNull(closedWorld) &&
right.isPositiveIntegerOrNull(closedWorld);
}
bool inputsAreUInt31(HInstruction instruction, Compiler compiler) {
bool inputsAreUInt31(HInstruction instruction, ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
return left.isUInt31(compiler) && right.isUInt31(compiler);
return left.isUInt31(closedWorld) && right.isUInt31(closedWorld);
}
HInstruction newBuiltinVariant(HInvokeDynamic instruction, Compiler compiler);
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld);
Selector renameToOptimizedSelector(
String name, Selector selector, Compiler compiler) {
@ -239,16 +242,14 @@ class AddSpecializer extends BinaryArithmeticSpecializer {
const AddSpecializer();
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler) {
if (inputsAreUInt31(instruction, compiler)) {
JavaScriptBackend backend = compiler.backend;
return backend.uint32Type;
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
if (inputsAreUInt31(instruction, closedWorld)) {
return closedWorld.commonMasks.uint32Type;
}
if (inputsArePositiveIntegers(instruction, compiler)) {
JavaScriptBackend backend = compiler.backend;
return backend.positiveIntType;
if (inputsArePositiveIntegers(instruction, closedWorld)) {
return closedWorld.commonMasks.positiveIntType;
}
return super.computeTypeFromInputTypes(instruction, compiler);
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
}
BinaryOperation operation(ConstantSystem constantSystem) {
@ -256,9 +257,12 @@ class AddSpecializer extends BinaryArithmeticSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler) {
return new HAdd(instruction.inputs[1], instruction.inputs[2],
instruction.selector, computeTypeFromInputTypes(instruction, compiler));
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
return new HAdd(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
}
}
@ -270,20 +274,18 @@ class DivideSpecializer extends BinaryArithmeticSpecializer {
}
TypeMask computeTypeFromInputTypes(
HInstruction instruction, Compiler compiler) {
HInstruction instruction, Compiler compiler, ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
JavaScriptBackend backend = compiler.backend;
if (left.isNumberOrNull(compiler)) {
return backend.doubleType;
if (left.isNumberOrNull(closedWorld)) {
return closedWorld.commonMasks.doubleType;
}
return super.computeTypeFromInputTypes(instruction, compiler);
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler) {
JavaScriptBackend backend = compiler.backend;
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
return new HDivide(instruction.inputs[1], instruction.inputs[2],
instruction.selector, backend.doubleType);
instruction.selector, closedWorld.commonMasks.doubleType);
}
}
@ -291,12 +293,11 @@ class ModuloSpecializer extends BinaryArithmeticSpecializer {
const ModuloSpecializer();
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler) {
if (inputsArePositiveIntegers(instruction, compiler)) {
JavaScriptBackend backend = compiler.backend;
return backend.positiveIntType;
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
if (inputsArePositiveIntegers(instruction, closedWorld)) {
return closedWorld.commonMasks.positiveIntType;
}
return super.computeTypeFromInputTypes(instruction, compiler);
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
}
BinaryOperation operation(ConstantSystem constantSystem) {
@ -304,7 +305,7 @@ class ModuloSpecializer extends BinaryArithmeticSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
// Modulo cannot be mapped to the native operator (different semantics).
// TODO(sra): For non-negative values we can use JavaScript's %.
return null;
@ -319,18 +320,20 @@ class MultiplySpecializer extends BinaryArithmeticSpecializer {
}
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler) {
if (inputsArePositiveIntegers(instruction, compiler)) {
JavaScriptBackend backend = compiler.backend;
return backend.positiveIntType;
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
if (inputsArePositiveIntegers(instruction, closedWorld)) {
return closedWorld.commonMasks.positiveIntType;
}
return super.computeTypeFromInputTypes(instruction, compiler);
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler) {
return new HMultiply(instruction.inputs[1], instruction.inputs[2],
instruction.selector, computeTypeFromInputTypes(instruction, compiler));
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
return new HMultiply(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
}
}
@ -342,9 +345,12 @@ class SubtractSpecializer extends BinaryArithmeticSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler) {
return new HSubtract(instruction.inputs[1], instruction.inputs[2],
instruction.selector, computeTypeFromInputTypes(instruction, compiler));
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
return new HSubtract(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
}
}
@ -356,18 +362,17 @@ class TruncatingDivideSpecializer extends BinaryArithmeticSpecializer {
}
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler) {
JavaScriptBackend backend = compiler.backend;
if (hasUint31Result(instruction, compiler)) {
return backend.uint31Type;
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
if (hasUint31Result(instruction, closedWorld)) {
return closedWorld.commonMasks.uint31Type;
}
if (inputsArePositiveIntegers(instruction, compiler)) {
return backend.positiveIntType;
if (inputsArePositiveIntegers(instruction, closedWorld)) {
return closedWorld.commonMasks.positiveIntType;
}
return super.computeTypeFromInputTypes(instruction, compiler);
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
}
bool isNotZero(HInstruction instruction, Compiler compiler) {
bool isNotZero(HInstruction instruction) {
if (!instruction.isConstantInteger()) return false;
HConstant rightConstant = instruction;
IntConstantValue intConstant = rightConstant.constant;
@ -375,7 +380,7 @@ class TruncatingDivideSpecializer extends BinaryArithmeticSpecializer {
return count != 0;
}
bool isTwoOrGreater(HInstruction instruction, Compiler compiler) {
bool isTwoOrGreater(HInstruction instruction) {
if (!instruction.isConstantInteger()) return false;
HConstant rightConstant = instruction;
IntConstantValue intConstant = rightConstant.constant;
@ -383,14 +388,14 @@ class TruncatingDivideSpecializer extends BinaryArithmeticSpecializer {
return count >= 2;
}
bool hasUint31Result(HInstruction instruction, Compiler compiler) {
bool hasUint31Result(HInstruction instruction, ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
if (right.isPositiveInteger(compiler)) {
if (left.isUInt31(compiler) && isNotZero(right, compiler)) {
if (right.isPositiveInteger(closedWorld)) {
if (left.isUInt31(closedWorld) && isNotZero(right)) {
return true;
}
if (left.isUInt32(compiler) && isTwoOrGreater(right, compiler)) {
if (left.isUInt32(closedWorld) && isTwoOrGreater(right)) {
return true;
}
}
@ -398,12 +403,12 @@ class TruncatingDivideSpecializer extends BinaryArithmeticSpecializer {
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInstruction right = instruction.inputs[2];
if (isBuiltin(instruction, compiler)) {
if (right.isPositiveInteger(compiler) && isNotZero(right, compiler)) {
if (hasUint31Result(instruction, compiler)) {
return newBuiltinVariant(instruction, compiler);
if (isBuiltin(instruction, closedWorld)) {
if (right.isPositiveInteger(closedWorld) && isNotZero(right)) {
if (hasUint31Result(instruction, closedWorld)) {
return newBuiltinVariant(instruction, compiler, closedWorld);
}
// We can call _tdivFast because the rhs is a 32bit integer
// and not 0, nor -1.
@ -416,9 +421,12 @@ class TruncatingDivideSpecializer extends BinaryArithmeticSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler) {
return new HTruncatingDivide(instruction.inputs[1], instruction.inputs[2],
instruction.selector, computeTypeFromInputTypes(instruction, compiler));
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
return new HTruncatingDivide(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
}
}
@ -426,15 +434,14 @@ abstract class BinaryBitOpSpecializer extends BinaryArithmeticSpecializer {
const BinaryBitOpSpecializer();
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
// All bitwise operations on primitive types either produce an
// integer or throw an error.
HInstruction left = instruction.inputs[1];
JavaScriptBackend backend = compiler.backend;
if (left.isPrimitiveOrNull(compiler)) {
return backend.uint32Type;
if (left.isPrimitiveOrNull(closedWorld)) {
return closedWorld.commonMasks.uint32Type;
}
return super.computeTypeFromInputTypes(instruction, compiler);
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
}
bool argumentLessThan32(HInstruction instruction) {
@ -445,10 +452,10 @@ abstract class BinaryBitOpSpecializer extends BinaryArithmeticSpecializer {
return count >= 0 && count <= 31;
}
bool isPositive(HInstruction instruction, Compiler compiler) {
bool isPositive(HInstruction instruction, ClosedWorld closedWorld) {
// TODO: We should use the value range analysis. Currently, ranges
// are discarded just after the analysis.
return instruction.isPositiveInteger(compiler);
return instruction.isPositiveInteger(closedWorld);
}
}
@ -460,18 +467,18 @@ class ShiftLeftSpecializer extends BinaryBitOpSpecializer {
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
if (left.isNumber(compiler)) {
if (left.isNumber(closedWorld)) {
if (argumentLessThan32(right)) {
return newBuiltinVariant(instruction, compiler);
return newBuiltinVariant(instruction, compiler, closedWorld);
}
// Even if there is no builtin equivalent instruction, we know
// the instruction does not have any side effect, and that it
// can be GVN'ed.
clearAllSideEffects(instruction);
if (isPositive(right, compiler)) {
if (isPositive(right, closedWorld)) {
instruction.selector = renameToOptimizedSelector(
'_shlPositive', instruction.selector, compiler);
}
@ -480,9 +487,12 @@ class ShiftLeftSpecializer extends BinaryBitOpSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler) {
return new HShiftLeft(instruction.inputs[1], instruction.inputs[2],
instruction.selector, computeTypeFromInputTypes(instruction, compiler));
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
return new HShiftLeft(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
}
}
@ -490,31 +500,31 @@ class ShiftRightSpecializer extends BinaryBitOpSpecializer {
const ShiftRightSpecializer();
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
if (left.isUInt32(compiler)) return left.instructionType;
return super.computeTypeFromInputTypes(instruction, compiler);
if (left.isUInt32(closedWorld)) return left.instructionType;
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
if (left.isNumber(compiler)) {
if (argumentLessThan32(right) && isPositive(left, compiler)) {
return newBuiltinVariant(instruction, compiler);
if (left.isNumber(closedWorld)) {
if (argumentLessThan32(right) && isPositive(left, closedWorld)) {
return newBuiltinVariant(instruction, compiler, closedWorld);
}
// Even if there is no builtin equivalent instruction, we know
// the instruction does not have any side effect, and that it
// can be GVN'ed.
clearAllSideEffects(instruction);
if (isPositive(right, compiler) && isPositive(left, compiler)) {
if (isPositive(right, closedWorld) && isPositive(left, closedWorld)) {
instruction.selector = renameToOptimizedSelector(
'_shrBothPositive', instruction.selector, compiler);
} else if (isPositive(left, compiler) && right.isNumber(compiler)) {
} else if (isPositive(left, closedWorld) && right.isNumber(closedWorld)) {
instruction.selector = renameToOptimizedSelector(
'_shrReceiverPositive', instruction.selector, compiler);
} else if (isPositive(right, compiler)) {
} else if (isPositive(right, closedWorld)) {
instruction.selector = renameToOptimizedSelector(
'_shrOtherPositive', instruction.selector, compiler);
}
@ -523,9 +533,12 @@ class ShiftRightSpecializer extends BinaryBitOpSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler) {
return new HShiftRight(instruction.inputs[1], instruction.inputs[2],
instruction.selector, computeTypeFromInputTypes(instruction, compiler));
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
return new HShiftRight(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
}
BinaryOperation operation(ConstantSystem constantSystem) {
@ -541,20 +554,22 @@ class BitOrSpecializer extends BinaryBitOpSpecializer {
}
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
JavaScriptBackend backend = compiler.backend;
if (left.isUInt31(compiler) && right.isUInt31(compiler)) {
return backend.uint31Type;
if (left.isUInt31(closedWorld) && right.isUInt31(closedWorld)) {
return closedWorld.commonMasks.uint31Type;
}
return super.computeTypeFromInputTypes(instruction, compiler);
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler) {
return new HBitOr(instruction.inputs[1], instruction.inputs[2],
instruction.selector, computeTypeFromInputTypes(instruction, compiler));
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
return new HBitOr(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
}
}
@ -566,21 +581,23 @@ class BitAndSpecializer extends BinaryBitOpSpecializer {
}
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
JavaScriptBackend backend = compiler.backend;
if (left.isPrimitiveOrNull(compiler) &&
(left.isUInt31(compiler) || right.isUInt31(compiler))) {
return backend.uint31Type;
if (left.isPrimitiveOrNull(closedWorld) &&
(left.isUInt31(closedWorld) || right.isUInt31(closedWorld))) {
return closedWorld.commonMasks.uint31Type;
}
return super.computeTypeFromInputTypes(instruction, compiler);
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler) {
return new HBitAnd(instruction.inputs[1], instruction.inputs[2],
instruction.selector, computeTypeFromInputTypes(instruction, compiler));
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
return new HBitAnd(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
}
}
@ -592,20 +609,22 @@ class BitXorSpecializer extends BinaryBitOpSpecializer {
}
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
JavaScriptBackend backend = compiler.backend;
if (left.isUInt31(compiler) && right.isUInt31(compiler)) {
return backend.uint31Type;
if (left.isUInt31(closedWorld) && right.isUInt31(closedWorld)) {
return closedWorld.commonMasks.uint31Type;
}
return super.computeTypeFromInputTypes(instruction, compiler);
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler) {
return new HBitXor(instruction.inputs[1], instruction.inputs[2],
instruction.selector, computeTypeFromInputTypes(instruction, compiler));
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
return new HBitXor(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
}
}
@ -613,47 +632,46 @@ abstract class RelationalSpecializer extends InvokeDynamicSpecializer {
const RelationalSpecializer();
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler) {
JavaScriptBackend backend = compiler.backend;
if (instruction.inputs[1].isPrimitiveOrNull(compiler)) {
return backend.boolType;
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
if (instruction.inputs[1].isPrimitiveOrNull(closedWorld)) {
return closedWorld.commonMasks.boolType;
}
return super.computeTypeFromInputTypes(instruction, compiler);
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
if (left.isNumber(compiler) && right.isNumber(compiler)) {
return newBuiltinVariant(instruction, compiler);
if (left.isNumber(closedWorld) && right.isNumber(closedWorld)) {
return newBuiltinVariant(instruction, closedWorld);
}
return null;
}
HInstruction newBuiltinVariant(HInvokeDynamic instruction, Compiler compiler);
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, ClosedWorld closedWorld);
}
class EqualsSpecializer extends RelationalSpecializer {
const EqualsSpecializer();
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
TypeMask instructionType = left.instructionType;
if (right.isConstantNull() || left.isPrimitiveOrNull(compiler)) {
return newBuiltinVariant(instruction, compiler);
if (right.isConstantNull() || left.isPrimitiveOrNull(closedWorld)) {
return newBuiltinVariant(instruction, closedWorld);
}
ClosedWorld world = compiler.closedWorld;
JavaScriptBackend backend = compiler.backend;
Iterable<Element> matches =
world.allFunctions.filter(instruction.selector, instructionType);
closedWorld.allFunctions.filter(instruction.selector, instructionType);
// This test relies the on `Object.==` and `Interceptor.==` always being
// implemented because if the selector matches by subtype, it still will be
// a regular object or an interceptor.
if (matches.every(backend.isDefaultEqualityImplementation)) {
return newBuiltinVariant(instruction, compiler);
if (matches
.every(closedWorld.backendClasses.isDefaultEqualityImplementation)) {
return newBuiltinVariant(instruction, closedWorld);
}
return null;
}
@ -663,10 +681,9 @@ class EqualsSpecializer extends RelationalSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler) {
JavaScriptBackend backend = compiler.backend;
HInvokeDynamic instruction, ClosedWorld closedWorld) {
return new HIdentity(instruction.inputs[1], instruction.inputs[2],
instruction.selector, backend.boolType);
instruction.selector, closedWorld.commonMasks.boolType);
}
}
@ -678,10 +695,9 @@ class LessSpecializer extends RelationalSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler) {
JavaScriptBackend backend = compiler.backend;
HInvokeDynamic instruction, ClosedWorld closedWorld) {
return new HLess(instruction.inputs[1], instruction.inputs[2],
instruction.selector, backend.boolType);
instruction.selector, closedWorld.commonMasks.boolType);
}
}
@ -693,10 +709,9 @@ class GreaterSpecializer extends RelationalSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler) {
JavaScriptBackend backend = compiler.backend;
HInvokeDynamic instruction, ClosedWorld closedWorld) {
return new HGreater(instruction.inputs[1], instruction.inputs[2],
instruction.selector, backend.boolType);
instruction.selector, closedWorld.commonMasks.boolType);
}
}
@ -708,10 +723,9 @@ class GreaterEqualSpecializer extends RelationalSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler) {
JavaScriptBackend backend = compiler.backend;
HInvokeDynamic instruction, ClosedWorld closedWorld) {
return new HGreaterEqual(instruction.inputs[1], instruction.inputs[2],
instruction.selector, backend.boolType);
instruction.selector, closedWorld.commonMasks.boolType);
}
}
@ -723,10 +737,9 @@ class LessEqualSpecializer extends RelationalSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler) {
JavaScriptBackend backend = compiler.backend;
HInvokeDynamic instruction, ClosedWorld closedWorld) {
return new HLessEqual(instruction.inputs[1], instruction.inputs[2],
instruction.selector, backend.boolType);
instruction.selector, closedWorld.commonMasks.boolType);
}
}
@ -738,11 +751,11 @@ class CodeUnitAtSpecializer extends InvokeDynamicSpecializer {
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
// TODO(sra): Implement a builtin HCodeUnitAt instruction and the same index
// bounds checking optimizations as for HIndex.
HInstruction receiver = instruction.getDartReceiver(compiler);
if (receiver.isStringOrNull(compiler)) {
if (receiver.isStringOrNull(closedWorld)) {
// Even if there is no builtin equivalent instruction, we know
// String.codeUnitAt does not have any side effect (other than throwing),
// and that it can be GVN'ed.
@ -760,9 +773,9 @@ class RoundSpecializer extends InvokeDynamicSpecializer {
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler) {
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInstruction receiver = instruction.getDartReceiver(compiler);
if (receiver.isNumberOrNull(compiler)) {
if (receiver.isNumberOrNull(closedWorld)) {
// Even if there is no builtin equivalent instruction, we know the
// instruction does not have any side effect, and that it can be GVN'ed.
clearAllSideEffects(instruction);

View file

@ -67,6 +67,7 @@ class KernelAstAdapter {
TreeElements get elements => _resolvedAst.elements;
DiagnosticReporter get reporter => _compiler.reporter;
Element get _target => _resolvedAst.element;
ClosedWorld get _closedWorld => _compiler.closedWorld;
GlobalTypeInferenceElementResult _resultOf(Element e) =>
_compiler.globalInference.results.resultOf(e);
@ -127,7 +128,7 @@ class KernelAstAdapter {
bool getCanThrow(ir.Node procedure) {
FunctionElement function = getElement(procedure);
return !_compiler.closedWorld.getCannotThrow(function);
return !_closedWorld.getCannotThrow(function);
}
TypeMask returnTypeOf(ir.Member node) {
@ -136,7 +137,7 @@ class KernelAstAdapter {
}
SideEffects getSideEffects(ir.Node node) {
return _compiler.closedWorld.getSideEffectsOfElement(getElement(node));
return _closedWorld.getSideEffectsOfElement(getElement(node));
}
CallStructure getCallStructure(ir.Arguments arguments) {
@ -214,7 +215,7 @@ class KernelAstAdapter {
}
TypeMask typeOfSet(ir.PropertySet setter) {
return _compiler.closedWorld.commonMasks.dynamicType;
return _closedWorld.commonMasks.dynamicType;
}
TypeMask typeOfSend(ir.Expression send) {
@ -226,10 +227,10 @@ class KernelAstAdapter {
ast.Node node = getNodeOrNull(listLiteral);
if (node == null) {
assertNodeIsSynthetic(listLiteral);
return _compiler.closedWorld.commonMasks.growableListType;
return _closedWorld.commonMasks.growableListType;
}
return _resultOf(owner).typeOfNewList(getNode(listLiteral)) ??
_compiler.closedWorld.commonMasks.dynamicType;
_closedWorld.commonMasks.dynamicType;
}
TypeMask typeOfIterator(ir.ForInStatement forInStatement) {
@ -246,24 +247,24 @@ class KernelAstAdapter {
bool isJsIndexableIterator(ir.ForInStatement forInStatement) {
TypeMask mask = typeOfIterator(forInStatement);
ClosedWorld closedWorld = _compiler.closedWorld;
return mask != null &&
mask.satisfies(_backend.helpers.jsIndexableClass, closedWorld) &&
mask.satisfies(_backend.helpers.jsIndexableClass, _closedWorld) &&
// String is indexable but not iterable.
!mask.satisfies(_backend.helpers.jsStringClass, closedWorld);
!mask.satisfies(_backend.helpers.jsStringClass, _closedWorld);
}
bool isFixedLength(TypeMask mask) {
ClosedWorld closedWorld = _compiler.closedWorld;
JavaScriptBackend backend = _compiler.backend;
if (mask.isContainer && (mask as ContainerTypeMask).length != null) {
// A container on which we have inferred the length.
return true;
}
// TODO(sra): Recognize any combination of fixed length indexables.
if (mask.containsOnly(backend.helpers.jsFixedArrayClass) ||
mask.containsOnly(backend.helpers.jsUnmodifiableArrayClass) ||
mask.containsOnlyString(closedWorld) ||
if (mask.containsOnly(
_closedWorld.backendClasses.fixedListImplementation) ||
mask.containsOnly(
_closedWorld.backendClasses.constListImplementation) ||
mask.containsOnlyString(_closedWorld) ||
backend.isTypedArray(mask)) {
return true;
}

View file

@ -38,7 +38,7 @@ class KernelStringBuilder extends ir.Visitor {
// conversions.
// 2. The value can be primitive, because the library stringifier has
// fast-path code for most primitives.
if (expression.canBePrimitive(compiler)) {
if (expression.canBePrimitive(builder.closedWorld)) {
append(stringify(expression));
return;
}
@ -62,14 +62,14 @@ class KernelStringBuilder extends ir.Visitor {
HInstruction concat(HInstruction left, HInstruction right) {
HInstruction instruction =
new HStringConcat(left, right, builder.backend.stringType);
new HStringConcat(left, right, builder.commonMasks.stringType);
builder.add(instruction);
return instruction;
}
HInstruction stringify(HInstruction expression) {
HInstruction instruction =
new HStringify(expression, builder.backend.stringType);
new HStringify(expression, builder.commonMasks.stringType);
builder.add(instruction);
return instruction;
}

View file

@ -70,6 +70,10 @@ class LocalsHandler {
? null
: instanceType;
ClosedWorld get closedWorld => builder.closedWorld;
CommonMasks get commonMasks => closedWorld.commonMasks;
/// Substituted type variables occurring in [type] into the context of
/// [contextClass].
DartType substInContext(DartType type) {
@ -111,9 +115,8 @@ class LocalsHandler {
HInstruction createBox() {
// TODO(floitsch): Clean up this hack. Should we create a box-object by
// just creating an empty object literal?
JavaScriptBackend backend = _compiler.backend;
HInstruction box = new HForeignCode(
js.js.parseForeignJS('{}'), backend.nonNullType, <HInstruction>[],
js.js.parseForeignJS('{}'), commonMasks.nonNullType, <HInstruction>[],
nativeBehavior: native.NativeBehavior.PURE_ALLOCATION);
builder.add(box);
return box;
@ -131,8 +134,7 @@ class LocalsHandler {
if (element != null && element.isGenerativeConstructorBody) {
// The box is passed as a parameter to a generative
// constructor body.
JavaScriptBackend backend = _compiler.backend;
box = builder.addParameter(scopeData.boxElement, backend.nonNullType);
box = builder.addParameter(scopeData.boxElement, commonMasks.nonNullType);
} else {
box = createBox();
}
@ -222,7 +224,7 @@ class LocalsHandler {
if (closureData.isClosure) {
// Inside closure redirect references to itself to [:this:].
HThis thisInstruction =
new HThis(closureData.thisLocal, backend.nonNullType);
new HThis(closureData.thisLocal, commonMasks.nonNullType);
builder.graph.thisInstruction = thisInstruction;
builder.graph.entry.addAtEntry(thisInstruction);
updateLocal(closureData.closureElement, thisInstruction);
@ -267,7 +269,6 @@ class LocalsHandler {
new SyntheticLocal('receiver', executableContext);
// Unlike `this`, receiver is nullable since direct calls to generative
// constructor call the constructor with `null`.
ClosedWorld closedWorld = _compiler.closedWorld;
HParameterValue value =
new HParameterValue(parameter, new TypeMask.exact(cls, closedWorld));
builder.graph.explicitReceiverParameter = value;
@ -325,7 +326,7 @@ class LocalsHandler {
ClosureFieldElement redirect = redirectionMapping[local];
HInstruction receiver = readLocal(closureData.closureElement);
TypeMask type = local is BoxLocal
? (_compiler.backend as JavaScriptBackend).nonNullType
? commonMasks.nonNullType
: getTypeOfCapturedVariable(redirect);
HInstruction fieldGet = new HFieldGet(redirect, receiver, type);
builder.add(fieldGet);
@ -346,10 +347,7 @@ class LocalsHandler {
assert(isUsedInTryOrGenerator(local));
HLocalValue localValue = getLocal(local);
HInstruction instruction = new HLocalGet(
local,
localValue,
(_compiler.backend as JavaScriptBackend).dynamicType,
sourceInformation);
local, localValue, commonMasks.dynamicType, sourceInformation);
builder.add(instruction);
return instruction;
}
@ -377,8 +375,7 @@ class LocalsHandler {
}
return activationVariables.putIfAbsent(local, () {
JavaScriptBackend backend = _compiler.backend;
HLocalValue localValue = new HLocalValue(local, backend.nonNullType)
HLocalValue localValue = new HLocalValue(local, commonMasks.nonNullType)
..sourceInformation = sourceInformation;
builder.graph.entry.addAtExit(localValue);
return localValue;
@ -489,7 +486,7 @@ class LocalsHandler {
// We know 'this' cannot be modified.
if (local != closureData.thisLocal) {
HPhi phi =
new HPhi.singleInput(local, instruction, backend.dynamicType);
new HPhi.singleInput(local, instruction, commonMasks.dynamicType);
loopEntry.addPhi(phi);
directLocals[local] = phi;
} else {
@ -546,7 +543,6 @@ class LocalsHandler {
// variable cannot be alive outside the block. Note: this is only
// true for nodes where we do joins.
Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>();
JavaScriptBackend backend = _compiler.backend;
otherLocals.directLocals.forEach((Local local, HInstruction instruction) {
// We know 'this' cannot be modified.
if (local == closureData.thisLocal) {
@ -558,8 +554,8 @@ class LocalsHandler {
if (identical(instruction, mine)) {
joinedLocals[local] = instruction;
} else {
HInstruction phi = new HPhi.manyInputs(
local, <HInstruction>[mine, instruction], backend.dynamicType);
HInstruction phi = new HPhi.manyInputs(local,
<HInstruction>[mine, instruction], commonMasks.dynamicType);
joinBlock.addPhi(phi);
joinedLocals[local] = phi;
}
@ -579,10 +575,9 @@ class LocalsHandler {
if (localsHandlers.length == 1) return localsHandlers[0];
Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>();
HInstruction thisValue = null;
JavaScriptBackend backend = _compiler.backend;
directLocals.forEach((Local local, HInstruction instruction) {
if (local != closureData.thisLocal) {
HPhi phi = new HPhi.noInputs(local, backend.dynamicType);
HPhi phi = new HPhi.noInputs(local, commonMasks.dynamicType);
joinedLocals[local] = phi;
joinBlock.addPhi(phi);
} else {
@ -625,17 +620,14 @@ class LocalsHandler {
if (result == null) {
ThisLocal local = closureData.thisLocal;
ClassElement cls = local.enclosingClass;
ClosedWorld closedWorld = _compiler.closedWorld;
if (closedWorld.isUsedAsMixin(cls)) {
// If the enclosing class is used as a mixin, [:this:] can be
// 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.declaration, _compiler.closedWorld);
result = new TypeMask.nonNullSubtype(cls.declaration, closedWorld);
} else {
result = new TypeMask.nonNullSubclass(
cls.declaration, _compiler.closedWorld);
result = new TypeMask.nonNullSubclass(cls.declaration, closedWorld);
}
cachedTypeOfThis = result;
}

View file

@ -4,6 +4,7 @@
import '../closure.dart';
import '../common.dart';
import '../common/backend_api.dart' show BackendClasses;
import '../compiler.dart' show Compiler;
import '../constants/constant_system.dart';
import '../constants/values.dart';
@ -949,203 +950,168 @@ abstract class HInstruction implements Spannable {
typeMask.satisfies(cls, closedWorld);
}
bool canBePrimitive(Compiler compiler) {
return canBePrimitiveNumber(compiler) ||
canBePrimitiveArray(compiler) ||
canBePrimitiveBoolean(compiler) ||
canBePrimitiveString(compiler) ||
bool canBePrimitive(ClosedWorld closedWorld) {
return canBePrimitiveNumber(closedWorld) ||
canBePrimitiveArray(closedWorld) ||
canBePrimitiveBoolean(closedWorld) ||
canBePrimitiveString(closedWorld) ||
isNull();
}
bool canBePrimitiveNumber(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
JavaScriptBackend backend = compiler.backend;
BackendHelpers helpers = backend.helpers;
bool canBePrimitiveNumber(ClosedWorld closedWorld) {
BackendClasses backendClasses = closedWorld.backendClasses;
// TODO(sra): It should be possible to test only jsDoubleClass and
// jsUInt31Class, since all others are superclasses of these two.
return containsType(instructionType, helpers.jsNumberClass, closedWorld) ||
containsType(instructionType, helpers.jsIntClass, closedWorld) ||
return containsType(
instructionType, backendClasses.numImplementation, closedWorld) ||
containsType(
instructionType, helpers.jsPositiveIntClass, closedWorld) ||
containsType(instructionType, helpers.jsUInt32Class, closedWorld) ||
containsType(instructionType, helpers.jsUInt31Class, closedWorld) ||
containsType(instructionType, helpers.jsDoubleClass, closedWorld);
instructionType, backendClasses.intImplementation, closedWorld) ||
containsType(instructionType, backendClasses.positiveIntImplementation,
closedWorld) ||
containsType(instructionType, backendClasses.uint32Implementation,
closedWorld) ||
containsType(instructionType, backendClasses.uint31Implementation,
closedWorld) ||
containsType(
instructionType, backendClasses.doubleImplementation, closedWorld);
}
bool canBePrimitiveBoolean(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
JavaScriptBackend backend = compiler.backend;
BackendHelpers helpers = backend.helpers;
return containsType(instructionType, helpers.jsBoolClass, closedWorld);
bool canBePrimitiveBoolean(ClosedWorld closedWorld) {
return containsType(instructionType,
closedWorld.backendClasses.boolImplementation, closedWorld);
}
bool canBePrimitiveArray(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
JavaScriptBackend backend = compiler.backend;
BackendHelpers helpers = backend.helpers;
return containsType(instructionType, helpers.jsArrayClass, closedWorld) ||
containsType(instructionType, helpers.jsFixedArrayClass, closedWorld) ||
containsType(
instructionType, helpers.jsExtendableArrayClass, closedWorld) ||
containsType(
instructionType, helpers.jsUnmodifiableArrayClass, closedWorld);
bool canBePrimitiveArray(ClosedWorld closedWorld) {
BackendClasses backendClasses = closedWorld.backendClasses;
return containsType(
instructionType, backendClasses.listImplementation, closedWorld) ||
containsType(instructionType, backendClasses.fixedListImplementation,
closedWorld) ||
containsType(instructionType, backendClasses.growableListImplementation,
closedWorld) ||
containsType(instructionType, backendClasses.constListImplementation,
closedWorld);
}
bool isIndexablePrimitive(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
JavaScriptBackend backend = compiler.backend;
BackendHelpers helpers = backend.helpers;
bool isIndexablePrimitive(ClosedWorld closedWorld) {
return instructionType.containsOnlyString(closedWorld) ||
isInstanceOf(instructionType, helpers.jsIndexableClass, closedWorld);
isInstanceOf(instructionType,
closedWorld.backendClasses.indexableImplementation, closedWorld);
}
bool isFixedArray(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
JavaScriptBackend backend = compiler.backend;
BackendHelpers helpers = backend.helpers;
bool isFixedArray(ClosedWorld closedWorld) {
BackendClasses backendClasses = closedWorld.backendClasses;
// TODO(sra): Recognize the union of these types as well.
return containsOnlyType(
instructionType, helpers.jsFixedArrayClass, closedWorld) ||
containsOnlyType(
instructionType, helpers.jsUnmodifiableArrayClass, closedWorld);
return containsOnlyType(instructionType,
backendClasses.fixedListImplementation, closedWorld) ||
containsOnlyType(instructionType,
backendClasses.constListImplementation, closedWorld);
}
bool isExtendableArray(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
JavaScriptBackend backend = compiler.backend;
BackendHelpers helpers = backend.helpers;
return containsOnlyType(
instructionType, helpers.jsExtendableArrayClass, closedWorld);
bool isExtendableArray(ClosedWorld closedWorld) {
return containsOnlyType(instructionType,
closedWorld.backendClasses.growableListImplementation, closedWorld);
}
bool isMutableArray(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
JavaScriptBackend backend = compiler.backend;
BackendHelpers helpers = backend.helpers;
return isInstanceOf(
instructionType, helpers.jsMutableArrayClass, closedWorld);
bool isMutableArray(ClosedWorld closedWorld) {
return isInstanceOf(instructionType,
closedWorld.backendClasses.mutableListImplementation, closedWorld);
}
bool isReadableArray(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
JavaScriptBackend backend = compiler.backend;
BackendHelpers helpers = backend.helpers;
return isInstanceOf(instructionType, helpers.jsArrayClass, closedWorld);
bool isReadableArray(ClosedWorld closedWorld) {
return isInstanceOf(instructionType,
closedWorld.backendClasses.listImplementation, closedWorld);
}
bool isMutableIndexable(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
JavaScriptBackend backend = compiler.backend;
BackendHelpers helpers = backend.helpers;
return isInstanceOf(
instructionType, helpers.jsMutableIndexableClass, closedWorld);
bool isMutableIndexable(ClosedWorld closedWorld) {
return isInstanceOf(instructionType,
closedWorld.backendClasses.mutableIndexableImplementation, closedWorld);
}
bool isArray(Compiler compiler) => isReadableArray(compiler);
bool isArray(ClosedWorld closedWorld) => isReadableArray(closedWorld);
bool canBePrimitiveString(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
JavaScriptBackend backend = compiler.backend;
BackendHelpers helpers = backend.helpers;
return containsType(instructionType, helpers.jsStringClass, closedWorld);
bool canBePrimitiveString(ClosedWorld closedWorld) {
return containsType(instructionType,
closedWorld.backendClasses.stringImplementation, closedWorld);
}
bool isInteger(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
bool isInteger(ClosedWorld closedWorld) {
return instructionType.containsOnlyInt(closedWorld) &&
!instructionType.isNullable;
}
bool isUInt32(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
JavaScriptBackend backend = compiler.backend;
BackendHelpers helpers = backend.helpers;
bool isUInt32(ClosedWorld closedWorld) {
return !instructionType.isNullable &&
isInstanceOf(instructionType, helpers.jsUInt32Class, closedWorld);
isInstanceOf(instructionType,
closedWorld.backendClasses.uint32Implementation, closedWorld);
}
bool isUInt31(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
JavaScriptBackend backend = compiler.backend;
BackendHelpers helpers = backend.helpers;
bool isUInt31(ClosedWorld closedWorld) {
return !instructionType.isNullable &&
isInstanceOf(instructionType, helpers.jsUInt31Class, closedWorld);
isInstanceOf(instructionType,
closedWorld.backendClasses.uint31Implementation, closedWorld);
}
bool isPositiveInteger(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
JavaScriptBackend backend = compiler.backend;
BackendHelpers helpers = backend.helpers;
bool isPositiveInteger(ClosedWorld closedWorld) {
return !instructionType.isNullable &&
isInstanceOf(instructionType, helpers.jsPositiveIntClass, closedWorld);
isInstanceOf(instructionType,
closedWorld.backendClasses.positiveIntImplementation, closedWorld);
}
bool isPositiveIntegerOrNull(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
JavaScriptBackend backend = compiler.backend;
BackendHelpers helpers = backend.helpers;
return isInstanceOf(
instructionType, helpers.jsPositiveIntClass, closedWorld);
bool isPositiveIntegerOrNull(ClosedWorld closedWorld) {
return isInstanceOf(instructionType,
closedWorld.backendClasses.positiveIntImplementation, closedWorld);
}
bool isIntegerOrNull(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
bool isIntegerOrNull(ClosedWorld closedWorld) {
return instructionType.containsOnlyInt(closedWorld);
}
bool isNumber(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
bool isNumber(ClosedWorld closedWorld) {
return instructionType.containsOnlyNum(closedWorld) &&
!instructionType.isNullable;
}
bool isNumberOrNull(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
bool isNumberOrNull(ClosedWorld closedWorld) {
return instructionType.containsOnlyNum(closedWorld);
}
bool isDouble(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
bool isDouble(ClosedWorld closedWorld) {
return instructionType.containsOnlyDouble(closedWorld) &&
!instructionType.isNullable;
}
bool isDoubleOrNull(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
bool isDoubleOrNull(ClosedWorld closedWorld) {
return instructionType.containsOnlyDouble(closedWorld);
}
bool isBoolean(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
bool isBoolean(ClosedWorld closedWorld) {
return instructionType.containsOnlyBool(closedWorld) &&
!instructionType.isNullable;
}
bool isBooleanOrNull(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
bool isBooleanOrNull(ClosedWorld closedWorld) {
return instructionType.containsOnlyBool(closedWorld);
}
bool isString(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
bool isString(ClosedWorld closedWorld) {
return instructionType.containsOnlyString(closedWorld) &&
!instructionType.isNullable;
}
bool isStringOrNull(Compiler compiler) {
ClosedWorld closedWorld = compiler.closedWorld;
bool isStringOrNull(ClosedWorld closedWorld) {
return instructionType.containsOnlyString(closedWorld);
}
bool isPrimitive(Compiler compiler) {
return (isPrimitiveOrNull(compiler) && !instructionType.isNullable) ||
bool isPrimitive(ClosedWorld closedWorld) {
return (isPrimitiveOrNull(closedWorld) && !instructionType.isNullable) ||
isNull();
}
bool isPrimitiveOrNull(Compiler compiler) {
return isIndexablePrimitive(compiler) ||
isNumberOrNull(compiler) ||
isBooleanOrNull(compiler) ||
bool isPrimitiveOrNull(ClosedWorld closedWorld) {
return isIndexablePrimitive(closedWorld) ||
isNumberOrNull(closedWorld) ||
isBooleanOrNull(closedWorld) ||
isNull();
}
@ -1364,7 +1330,7 @@ abstract class HInstruction implements Spannable {
return false;
}
HInstruction convertType(Compiler compiler, DartType type, int kind) {
HInstruction convertType(ClosedWorld closedWorld, DartType type, int kind) {
if (type == null) return this;
type = type.unaliased;
// Only the builder knows how to create [HTypeConversion]
@ -1374,19 +1340,20 @@ abstract class HInstruction implements Spannable {
assert(type.treatAsRaw || type.isFunctionType);
if (type.isDynamic) return this;
if (type.isObject) return this;
JavaScriptBackend backend = compiler.backend;
if (type.isVoid || type.isFunctionType || type.isMalformed) {
return new HTypeConversion(type, kind, backend.dynamicType, this);
return new HTypeConversion(
type, kind, closedWorld.commonMasks.dynamicType, this);
}
assert(type.isInterfaceType);
if (kind == HTypeConversion.BOOLEAN_CONVERSION_CHECK) {
// Boolean conversion checks work on non-nullable booleans.
return new HTypeConversion(type, kind, backend.boolType, this);
return new HTypeConversion(
type, kind, closedWorld.commonMasks.boolType, this);
} else if (kind == HTypeConversion.CHECKED_MODE_CHECK && !type.treatAsRaw) {
throw 'creating compound check to $type (this = ${this})';
} else {
Entity cls = type.element;
TypeMask subtype = new TypeMask.subtype(cls, compiler.closedWorld);
TypeMask subtype = new TypeMask.subtype(cls, closedWorld);
return new HTypeConversion(type, kind, subtype, this);
}
}
@ -1412,8 +1379,8 @@ class HRef extends HInstruction {
HInstruction get value => inputs[0];
@override
HInstruction convertType(Compiler compiler, DartType type, int kind) {
HInstruction converted = value.convertType(compiler, type, kind);
HInstruction convertType(ClosedWorld closedWorld, DartType type, int kind) {
HInstruction converted = value.convertType(closedWorld, type, kind);
if (converted == value) return this;
HTypeConversion conversion = converted;
conversion.inputs[0] = this;
@ -2862,7 +2829,7 @@ class HTypeConversion extends HCheck {
HInstruction get checkedInput =>
usesMethodOnType ? inputs[1] : super.checkedInput;
HInstruction convertType(Compiler compiler, DartType type, int kind) {
HInstruction convertType(ClosedWorld closedWorld, DartType type, int kind) {
if (typeExpression == type) {
// Don't omit a boolean conversion (which doesn't allow `null`) unless
// this type conversion is already a boolean conversion.
@ -2870,7 +2837,7 @@ class HTypeConversion extends HCheck {
return this;
}
}
return super.convertType(compiler, type, kind);
return super.convertType(closedWorld, type, kind);
}
bool get isCheckedModeCheck {

View file

@ -40,6 +40,7 @@ class SsaOptimizerTask extends CompilerTask {
super(backend.compiler.measurer);
String get name => 'SSA optimizer';
Compiler get compiler => backend.compiler;
ClosedWorld get closedWorld => compiler.closedWorld;
Map<HInstruction, Range> ranges = <HInstruction, Range>{};
void optimize(CodegenWorkItem work, HGraph graph) {
@ -59,16 +60,18 @@ class SsaOptimizerTask extends CompilerTask {
// Run trivial instruction simplification first to optimize
// some patterns useful for type conversion.
new SsaInstructionSimplifier(constantSystem, backend, this, registry),
new SsaTypeConversionInserter(compiler),
new SsaTypeConversionInserter(closedWorld),
new SsaRedundantPhiEliminator(),
new SsaDeadPhiEliminator(),
new SsaTypePropagator(compiler),
// After type propagation, more instructions can be
// simplified.
new SsaInstructionSimplifier(constantSystem, backend, this, registry),
new SsaCheckInserter(trustPrimitives, backend, boundsChecked),
new SsaCheckInserter(
trustPrimitives, backend, closedWorld, boundsChecked),
new SsaInstructionSimplifier(constantSystem, backend, this, registry),
new SsaCheckInserter(trustPrimitives, backend, boundsChecked),
new SsaCheckInserter(
trustPrimitives, backend, closedWorld, boundsChecked),
new SsaTypePropagator(compiler),
// Run a dead code eliminator before LICM because dead
// interceptors are often in the way of LICM'able instructions.
@ -86,7 +89,8 @@ class SsaOptimizerTask extends CompilerTask {
// Previous optimizations may have generated new
// opportunities for instruction simplification.
new SsaInstructionSimplifier(constantSystem, backend, this, registry),
new SsaCheckInserter(trustPrimitives, backend, boundsChecked),
new SsaCheckInserter(
trustPrimitives, backend, closedWorld, boundsChecked),
];
phases.forEach(runPhase);
@ -105,7 +109,8 @@ class SsaOptimizerTask extends CompilerTask {
new SsaCodeMotion(),
new SsaValueRangeAnalyzer(compiler, constantSystem, this),
new SsaInstructionSimplifier(constantSystem, backend, this, registry),
new SsaCheckInserter(trustPrimitives, backend, boundsChecked),
new SsaCheckInserter(
trustPrimitives, backend, closedWorld, boundsChecked),
new SsaSimplifyInterceptors(compiler, constantSystem, work.element),
new SsaDeadCodeEliminator(compiler, this),
];
@ -167,6 +172,8 @@ class SsaInstructionSimplifier extends HBaseVisitor
CoreClasses get coreClasses => compiler.coreClasses;
ClosedWorld get closedWorld => compiler.closedWorld;
BackendHelpers get helpers => backend.helpers;
void visitGraph(HGraph visitee) {
@ -187,12 +194,12 @@ class SsaInstructionSimplifier extends HBaseVisitor
// might be that an operation thought to return double, can be
// simplified to an int. For example:
// `2.5 * 10`.
if (!(replacement.isNumberOrNull(compiler) &&
instruction.isNumberOrNull(compiler))) {
if (!(replacement.isNumberOrNull(closedWorld) &&
instruction.isNumberOrNull(closedWorld))) {
// If we can replace [instruction] with [replacement], then
// [replacement]'s type can be narrowed.
TypeMask newType = replacement.instructionType
.intersection(instruction.instructionType, compiler.closedWorld);
.intersection(instruction.instructionType, closedWorld);
replacement.instructionType = newType;
}
@ -275,7 +282,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
List<HInstruction> inputs = node.inputs;
assert(inputs.length == 1);
HInstruction input = inputs[0];
if (input.isBoolean(compiler)) return input;
if (input.isBoolean(closedWorld)) return input;
// If the code is unreachable, remove the HBoolify. This can happen when
// there is a throw expression in a short-circuit conditional. Removing the
@ -285,7 +292,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
// All values that cannot be 'true' are boolified to false.
TypeMask mask = input.instructionType;
if (!mask.contains(helpers.jsBoolClass, compiler.closedWorld)) {
if (!mask.contains(helpers.jsBoolClass, closedWorld)) {
return graph.addConstantBool(false, compiler);
}
return node;
@ -322,7 +329,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
HInstruction tryOptimizeLengthInterceptedGetter(HInvokeDynamic node) {
HInstruction actualReceiver = node.inputs[1];
if (actualReceiver.isIndexablePrimitive(compiler)) {
if (actualReceiver.isIndexablePrimitive(closedWorld)) {
if (actualReceiver.isConstantString()) {
HConstant constantInput = actualReceiver;
StringConstantValue constant = constantInput.constant;
@ -335,15 +342,14 @@ class SsaInstructionSimplifier extends HBaseVisitor
MemberElement element = helpers.jsIndexableLength;
bool isFixed = isFixedLength(actualReceiver.instructionType, compiler);
TypeMask actualType = node.instructionType;
ClosedWorld closedWorld = compiler.closedWorld;
TypeMask resultType = backend.positiveIntType;
TypeMask resultType = closedWorld.commonMasks.positiveIntType;
// If we already have computed a more specific type, keep that type.
if (HInstruction.isInstanceOf(
actualType, helpers.jsUInt31Class, closedWorld)) {
resultType = backend.uint31Type;
resultType = closedWorld.commonMasks.uint31Type;
} else if (HInstruction.isInstanceOf(
actualType, helpers.jsUInt32Class, closedWorld)) {
resultType = backend.uint32Type;
resultType = closedWorld.commonMasks.uint32Type;
}
HFieldGet result = new HFieldGet(element, actualReceiver, resultType,
isAssignable: !isFixed);
@ -368,23 +374,21 @@ class SsaInstructionSimplifier extends HBaseVisitor
// Try converting the instruction to a builtin instruction.
HInstruction instruction =
node.specializer.tryConvertToBuiltin(node, compiler);
node.specializer.tryConvertToBuiltin(node, compiler, closedWorld);
if (instruction != null) return instruction;
Selector selector = node.selector;
TypeMask mask = node.mask;
HInstruction input = node.inputs[1];
ClosedWorld world = compiler.closedWorld;
bool applies(Element element) {
return selector.applies(element) &&
(mask == null || mask.canHit(element, selector, world));
(mask == null || mask.canHit(element, selector, closedWorld));
}
if (selector.isCall || selector.isOperator) {
MethodElement target;
if (input.isExtendableArray(compiler)) {
if (input.isExtendableArray(closedWorld)) {
if (applies(helpers.jsArrayRemoveLast)) {
target = helpers.jsArrayRemoveLast;
} else if (applies(helpers.jsArrayAdd)) {
@ -394,10 +398,10 @@ class SsaInstructionSimplifier extends HBaseVisitor
target = helpers.jsArrayAdd;
}
}
} else if (input.isStringOrNull(compiler)) {
} else if (input.isStringOrNull(closedWorld)) {
if (applies(helpers.jsStringSplit)) {
HInstruction argument = node.inputs[2];
if (argument.isString(compiler)) {
if (argument.isString(closedWorld)) {
target = helpers.jsStringSplit;
}
} else if (applies(helpers.jsStringOperatorAdd)) {
@ -405,7 +409,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
// make sure the receiver and the argument are not null.
// TODO(sra): Do this via [node.specializer].
HInstruction argument = node.inputs[2];
if (argument.isString(compiler) && !input.canBeNull()) {
if (argument.isString(closedWorld) && !input.canBeNull()) {
return new HStringConcat(input, argument, node.instructionType);
}
} else if (applies(helpers.jsStringToString) && !input.canBeNull()) {
@ -559,7 +563,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
HInstruction visitBoundsCheck(HBoundsCheck node) {
HInstruction index = node.index;
if (index.isInteger(compiler)) return node;
if (index.isInteger(closedWorld)) return node;
if (index.isConstant()) {
HConstant constantInstruction = index;
assert(!constantInstruction.constant.isInt);
@ -587,7 +591,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
HInstruction right = node.right;
// We can only perform this rewriting on Integer, as it is not
// valid for -0.0.
if (left.isInteger(compiler) && right.isInteger(compiler)) {
if (left.isInteger(closedWorld) && right.isInteger(closedWorld)) {
if (left is HConstant && left.constant.isZero) return right;
if (right is HConstant && right.constant.isZero) return left;
}
@ -597,7 +601,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
HInstruction visitMultiply(HMultiply node) {
HInstruction left = node.left;
HInstruction right = node.right;
if (left.isNumber(compiler) && right.isNumber(compiler)) {
if (left.isNumber(closedWorld) && right.isNumber(closedWorld)) {
if (left is HConstant && left.constant.isOne) return right;
if (right is HConstant && right.constant.isOne) return left;
}
@ -643,8 +647,9 @@ class SsaInstructionSimplifier extends HBaseVisitor
// Intersection of int and double return conflicting, so
// we don't optimize on numbers to preserve the runtime semantics.
if (!(left.isNumberOrNull(compiler) && right.isNumberOrNull(compiler))) {
if (leftType.isDisjoint(rightType, compiler.closedWorld)) {
if (!(left.isNumberOrNull(closedWorld) &&
right.isNumberOrNull(closedWorld))) {
if (leftType.isDisjoint(rightType, closedWorld)) {
return makeFalse();
}
}
@ -657,15 +662,15 @@ class SsaInstructionSimplifier extends HBaseVisitor
if (constant.constant.isTrue) {
return input;
} else {
return new HNot(input, backend.boolType);
return new HNot(input, closedWorld.commonMasks.boolType);
}
}
if (left.isConstantBoolean() && right.isBoolean(compiler)) {
if (left.isConstantBoolean() && right.isBoolean(closedWorld)) {
return compareConstant(left, right);
}
if (right.isConstantBoolean() && left.isBoolean(compiler)) {
if (right.isConstantBoolean() && left.isBoolean(closedWorld)) {
return compareConstant(right, left);
}
@ -674,8 +679,8 @@ class SsaInstructionSimplifier extends HBaseVisitor
// dart2js runtime has not always been consistent with the Dart
// specification (section 16.0.1), which makes distinctions on NaNs and
// -0.0 that are hard to implement efficiently.
if (left.isIntegerOrNull(compiler)) return makeTrue();
if (!left.canBePrimitiveNumber(compiler)) return makeTrue();
if (left.isIntegerOrNull(closedWorld)) return makeTrue();
if (!left.canBePrimitiveNumber(closedWorld)) return makeTrue();
}
return null;
@ -735,9 +740,8 @@ class SsaInstructionSimplifier extends HBaseVisitor
return graph.addConstantBool(true, compiler);
}
ClosedWorld closedWorld = compiler.closedWorld;
HInstruction expression = node.expression;
if (expression.isInteger(compiler)) {
if (expression.isInteger(closedWorld)) {
if (element == coreClasses.intClass ||
element == coreClasses.numClass ||
Elements.isNumberOrStringSupertype(element, compiler)) {
@ -749,7 +753,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
} else {
return graph.addConstantBool(false, compiler);
}
} else if (expression.isDouble(compiler)) {
} else if (expression.isDouble(closedWorld)) {
if (element == coreClasses.doubleClass ||
element == coreClasses.numClass ||
Elements.isNumberOrStringSupertype(element, compiler)) {
@ -762,14 +766,14 @@ class SsaInstructionSimplifier extends HBaseVisitor
} else {
return graph.addConstantBool(false, compiler);
}
} else if (expression.isNumber(compiler)) {
} else if (expression.isNumber(closedWorld)) {
if (element == coreClasses.numClass) {
return graph.addConstantBool(true, compiler);
} else {
// We cannot just return false, because the expression may be of
// type int or double.
}
} else if (expression.canBePrimitiveNumber(compiler) &&
} else if (expression.canBePrimitiveNumber(closedWorld) &&
element == coreClasses.intClass) {
// We let the JS semantics decide for that check.
return node;
@ -785,7 +789,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
: new TypeMask.nonNullSubtype(element, closedWorld);
if (expressionMask.union(typeMask, closedWorld) == typeMask) {
return graph.addConstantBool(true, compiler);
} else if (expressionMask.isDisjoint(typeMask, compiler.closedWorld)) {
} else if (expressionMask.isDisjoint(typeMask, closedWorld)) {
return graph.addConstantBool(false, compiler);
}
}
@ -830,7 +834,6 @@ class SsaInstructionSimplifier extends HBaseVisitor
}
HInstruction removeIfCheckAlwaysSucceeds(HCheck node, TypeMask checkedType) {
ClosedWorld closedWorld = compiler.closedWorld;
if (checkedType.containsAll(closedWorld)) return node;
HInstruction input = node.checkedInput;
TypeMask inputType = input.instructionType;
@ -854,7 +857,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
// should not be necessary but it currently makes it easier for
// other optimizations to reason about a fixed length constructor
// that we know takes an int.
if (receiver.inputs[0].isInteger(compiler)) {
if (receiver.inputs[0].isInteger(closedWorld)) {
return receiver.inputs[0];
}
} else if (receiver.isConstantList() || receiver.isConstantString()) {
@ -919,8 +922,8 @@ class SsaInstructionSimplifier extends HBaseVisitor
if (field != null) return directFieldGet(receiver, field);
if (node.element == null) {
MemberElement element = compiler.closedWorld
.locateSingleElement(node.selector, receiver.instructionType);
MemberElement element = closedWorld.locateSingleElement(
node.selector, receiver.instructionType);
if (element != null && element.name == node.selector.name) {
node.element = element;
if (element.isFunction) {
@ -935,7 +938,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
}
HInstruction directFieldGet(HInstruction receiver, FieldElement field) {
bool isAssignable = !compiler.closedWorld.fieldNeverChanges(field);
bool isAssignable = !closedWorld.fieldNeverChanges(field);
TypeMask type;
if (backend.isNative(field.enclosingClass)) {
@ -972,8 +975,8 @@ class SsaInstructionSimplifier extends HBaseVisitor
// can skip the test an generate the HFieldSet.
return node;
}
HInstruction other =
value.convertType(compiler, type, HTypeConversion.CHECKED_MODE_CHECK);
HInstruction other = value.convertType(
closedWorld, type, HTypeConversion.CHECKED_MODE_CHECK);
if (other != value) {
node.block.addBefore(node, other);
value = other;
@ -997,17 +1000,17 @@ class SsaInstructionSimplifier extends HBaseVisitor
} else if (element == backend.helpers.checkInt) {
if (node.inputs.length == 1) {
HInstruction argument = node.inputs[0];
if (argument.isInteger(compiler)) return argument;
if (argument.isInteger(closedWorld)) return argument;
}
} else if (element == backend.helpers.checkNum) {
if (node.inputs.length == 1) {
HInstruction argument = node.inputs[0];
if (argument.isNumber(compiler)) return argument;
if (argument.isNumber(closedWorld)) return argument;
}
} else if (element == backend.helpers.checkString) {
if (node.inputs.length == 1) {
HInstruction argument = node.inputs[0];
if (argument.isString(compiler)) return argument;
if (argument.isString(closedWorld)) return argument;
}
}
return node;
@ -1057,12 +1060,13 @@ class SsaInstructionSimplifier extends HBaseVisitor
leftString.primitiveValue, rightString.primitiveValue)),
compiler);
if (prefix == null) return folded;
return new HStringConcat(prefix, folded, backend.stringType);
return new HStringConcat(
prefix, folded, closedWorld.commonMasks.stringType);
}
HInstruction visitStringify(HStringify node) {
HInstruction input = node.inputs[0];
if (input.isString(compiler)) return input;
if (input.isString(closedWorld)) return input;
HInstruction tryConstant() {
if (!input.isConstant()) return null;
@ -1086,12 +1090,11 @@ class SsaInstructionSimplifier extends HBaseVisitor
// it directly. Keep the stringifier for primitives (since they have fast
// path code in the stringifier) and for classes requiring interceptors
// (since SsaInstructionSimplifier runs after SsaSimplifyInterceptors).
if (input.canBePrimitive(compiler)) return null;
if (input.canBePrimitive(closedWorld)) return null;
if (input.canBeNull()) return null;
Selector selector = Selectors.toString_;
TypeMask toStringType = TypeMaskFactory.inferredTypeForSelector(
selector, input.instructionType, compiler);
ClosedWorld closedWorld = compiler.closedWorld;
if (!toStringType.containsOnlyString(closedWorld)) return null;
// All intercepted classes extend `Interceptor`, so if the receiver can't
// be a class extending `Interceptor` then it can be called directly.
@ -1116,7 +1119,6 @@ class SsaInstructionSimplifier extends HBaseVisitor
}
bool needsSubstitutionForTypeVariableAccess(ClassElement cls) {
ClosedWorld closedWorld = compiler.closedWorld;
if (closedWorld.isUsedAsMixin(cls)) return true;
return closedWorld.anyStrictSubclassOf(cls, (ClassElement subclass) {
@ -1169,7 +1171,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
}
if (source == null) return null;
return new HTypeInfoReadRaw(source, backend.dynamicType);
return new HTypeInfoReadRaw(source, closedWorld.commonMasks.dynamicType);
}
// TODO(sra): Consider fusing type expression trees with no type variables,
@ -1192,7 +1194,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
TypeInfoExpressionKind.COMPLETE,
typeArgument,
const <HInstruction>[],
backend.dynamicType);
closedWorld.commonMasks.dynamicType);
return replacement;
}
return node;
@ -1222,7 +1224,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
TypeInfoExpressionKind.COMPLETE,
type,
arguments,
backend.dynamicType);
closedWorld.commonMasks.dynamicType);
return replacement;
}
@ -1289,10 +1291,12 @@ class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase {
final Set<HInstruction> boundsChecked;
final bool trustPrimitives;
final JavaScriptBackend backend;
final ClosedWorld closedWorld;
final String name = "SsaCheckInserter";
HGraph graph;
SsaCheckInserter(this.trustPrimitives, this.backend, this.boundsChecked);
SsaCheckInserter(
this.trustPrimitives, this.backend, this.closedWorld, this.boundsChecked);
BackendHelpers get helpers => backend.helpers;
@ -1319,14 +1323,14 @@ class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase {
HBoundsCheck insertBoundsCheck(
HInstruction indexNode, HInstruction array, HInstruction indexArgument) {
Compiler compiler = backend.compiler;
HFieldGet length = new HFieldGet(
helpers.jsIndexableLength, array, backend.positiveIntType,
HFieldGet length = new HFieldGet(helpers.jsIndexableLength, array,
closedWorld.commonMasks.positiveIntType,
isAssignable: !isFixedLength(array.instructionType, compiler));
indexNode.block.addBefore(indexNode, length);
TypeMask type = indexArgument.isPositiveInteger(compiler)
TypeMask type = indexArgument.isPositiveInteger(closedWorld)
? indexArgument.instructionType
: backend.positiveIntType;
: closedWorld.commonMasks.positiveIntType;
HBoundsCheck check = new HBoundsCheck(indexArgument, length, array, type);
indexNode.block.addBefore(indexNode, check);
// If the index input to the bounds check was not known to be an integer
@ -1336,7 +1340,7 @@ class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase {
// the index eg. if it is a constant. The range information from the
// BoundsCheck instruction is attached to the input directly by
// visitBoundsCheck in the SsaValueRangeAnalyzer.
if (!indexArgument.isInteger(compiler)) {
if (!indexArgument.isInteger(closedWorld)) {
indexArgument.replaceAllUsersDominatedBy(indexNode, check);
}
boundsChecked.add(indexNode);
@ -1382,6 +1386,8 @@ class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase {
SsaDeadCodeEliminator(this.compiler, this.optimizer);
ClosedWorld get closedWorld => compiler.closedWorld;
HInstruction zapInstructionCache;
HInstruction get zapInstruction {
if (zapInstructionCache == null) {
@ -1512,7 +1518,7 @@ class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase {
}
void visitGraph(HGraph graph) {
analyzer = new SsaLiveBlockAnalyzer(graph, compiler, optimizer);
analyzer = new SsaLiveBlockAnalyzer(graph, closedWorld, optimizer);
analyzer.analyze();
visitPostDominatorTree(graph);
cleanPhis(graph);
@ -1600,9 +1606,9 @@ class SsaLiveBlockAnalyzer extends HBaseVisitor {
final Set<HBasicBlock> live = new Set<HBasicBlock>();
final List<HBasicBlock> worklist = <HBasicBlock>[];
final SsaOptimizerTask optimizer;
final Compiler compiler;
final ClosedWorld closedWorld;
SsaLiveBlockAnalyzer(this.graph, this.compiler, this.optimizer);
SsaLiveBlockAnalyzer(this.graph, this.closedWorld, this.optimizer);
Map<HInstruction, Range> get ranges => optimizer.ranges;
@ -1641,7 +1647,7 @@ class SsaLiveBlockAnalyzer extends HBaseVisitor {
}
void visitSwitch(HSwitch node) {
if (node.expression.isInteger(compiler)) {
if (node.expression.isInteger(closedWorld)) {
Range switchRange = ranges[node.expression];
if (switchRange != null &&
switchRange.lower is IntValue &&
@ -2095,9 +2101,9 @@ class SsaCodeMotion extends HBaseVisitor implements OptimizationPhase {
class SsaTypeConversionInserter extends HBaseVisitor
implements OptimizationPhase {
final String name = "SsaTypeconversionInserter";
final Compiler compiler;
final ClosedWorld closedWorld;
SsaTypeConversionInserter(this.compiler);
SsaTypeConversionInserter(this.closedWorld);
void visitGraph(HGraph graph) {
visitDominatorTree(graph);
@ -2135,8 +2141,7 @@ class SsaTypeConversionInserter extends HBaseVisitor
if (trueTargets.isEmpty && falseTargets.isEmpty) return;
TypeMask convertedType =
new TypeMask.nonNullSubtype(element, compiler.closedWorld);
TypeMask convertedType = new TypeMask.nonNullSubtype(element, closedWorld);
HInstruction input = instruction.expression;
for (HBasicBlock block in trueTargets) {

View file

@ -161,8 +161,7 @@ class SsaBranchBuilder {
boolifiedLeft = builder.popBoolified();
builder.stack.add(boolifiedLeft);
if (!isAnd) {
JavaScriptBackend backend = compiler.backend;
builder.push(new HNot(builder.pop(), backend.boolType));
builder.push(new HNot(builder.pop(), builder.commonMasks.boolType));
}
}
@ -173,9 +172,10 @@ class SsaBranchBuilder {
handleIf(visitCondition, visitThen, null);
HConstant notIsAnd = builder.graph.addConstantBool(!isAnd, compiler);
JavaScriptBackend backend = compiler.backend;
HPhi result = new HPhi.manyInputs(
null, <HInstruction>[boolifiedRight, notIsAnd], backend.dynamicType);
null,
<HInstruction>[boolifiedRight, notIsAnd],
builder.commonMasks.dynamicType);
builder.current.addPhi(result);
builder.stack.add(result);
}
@ -200,9 +200,8 @@ class SsaBranchBuilder {
if (isExpression) {
assert(thenValue != null && elseValue != null);
JavaScriptBackend backend = compiler.backend;
HPhi phi = new HPhi.manyInputs(
null, <HInstruction>[thenValue, elseValue], backend.dynamicType);
HPhi phi = new HPhi.manyInputs(null, <HInstruction>[thenValue, elseValue],
builder.commonMasks.dynamicType);
joinBranch.block.addPhi(phi);
builder.stack.add(phi);
}

View file

@ -10,6 +10,7 @@ import '../compiler.dart' show Compiler;
import '../diagnostics/invariant.dart' show DEBUG_MODE;
import '../js_backend/js_backend.dart';
import '../tracer.dart';
import '../world.dart' show ClosedWorld;
import 'nodes.dart';
/**
@ -117,6 +118,8 @@ class HInstructionStringifier implements HVisitor<String> {
HInstructionStringifier(this.currentBlock, this.compiler);
ClosedWorld get closedWorld => compiler.closedWorld;
visit(HInstruction node) => '${node.accept(this)} ${node.instructionType}';
String temporaryId(HInstruction instruction) {
@ -125,27 +128,27 @@ class HInstructionStringifier implements HVisitor<String> {
prefix = 'u';
} else if (instruction.isConflicting()) {
prefix = 'c';
} else if (instruction.isExtendableArray(compiler)) {
} else if (instruction.isExtendableArray(closedWorld)) {
prefix = 'e';
} else if (instruction.isFixedArray(compiler)) {
} else if (instruction.isFixedArray(closedWorld)) {
prefix = 'f';
} else if (instruction.isMutableArray(compiler)) {
} else if (instruction.isMutableArray(closedWorld)) {
prefix = 'm';
} else if (instruction.isReadableArray(compiler)) {
} else if (instruction.isReadableArray(closedWorld)) {
prefix = 'a';
} else if (instruction.isString(compiler)) {
} else if (instruction.isString(closedWorld)) {
prefix = 's';
} else if (instruction.isIndexablePrimitive(compiler)) {
} else if (instruction.isIndexablePrimitive(closedWorld)) {
prefix = 'r';
} else if (instruction.isBoolean(compiler)) {
} else if (instruction.isBoolean(closedWorld)) {
prefix = 'b';
} else if (instruction.isInteger(compiler)) {
} else if (instruction.isInteger(closedWorld)) {
prefix = 'i';
} else if (instruction.isDouble(compiler)) {
} else if (instruction.isDouble(closedWorld)) {
prefix = 'd';
} else if (instruction.isNumber(compiler)) {
} else if (instruction.isNumber(closedWorld)) {
prefix = 'n';
} else if (instruction.instructionType.containsAll(compiler.closedWorld)) {
} else if (instruction.instructionType.containsAll(closedWorld)) {
prefix = 'v';
} else {
prefix = 'U';

View file

@ -30,7 +30,7 @@ class TypeBuilder {
if (type.isObject) return original;
// The type element is either a class or the void element.
Element element = type.element;
TypeMask mask = new TypeMask.subtype(element, builder.compiler.closedWorld);
TypeMask mask = new TypeMask.subtype(element, builder.closedWorld);
return new HTypeKnown.pinned(mask, original);
}
@ -133,9 +133,9 @@ class TypeBuilder {
assert(member.isInstanceMember);
assert(variable is! MethodTypeVariableType);
HInstruction target = builder.localsHandler.readThis();
builder.push(
new HTypeInfoReadVariable(variable, target, builder.backend.dynamicType)
..sourceInformation = sourceInformation);
builder.push(new HTypeInfoReadVariable(
variable, target, builder.commonMasks.dynamicType)
..sourceInformation = sourceInformation);
return builder.pop();
}
@ -154,7 +154,7 @@ class TypeBuilder {
TypeInfoExpressionKind.INSTANCE,
interface.element.thisType,
inputs,
builder.backend.dynamicType);
builder.commonMasks.dynamicType);
return representation;
}
@ -195,7 +195,7 @@ class TypeBuilder {
TypeInfoExpressionKind.COMPLETE,
argument,
inputs,
builder.backend.dynamicType)..sourceInformation = sourceInformation;
builder.commonMasks.dynamicType)..sourceInformation = sourceInformation;
builder.add(result);
return result;
}
@ -246,7 +246,7 @@ class TypeBuilder {
} else if (type.isFunctionType) {
return builder.buildFunctionTypeConversion(original, type, kind);
} else {
return original.convertType(builder.compiler, type, kind);
return original.convertType(builder.closedWorld, type, kind);
}
}
}

View file

@ -109,18 +109,21 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
TypeMask visitBinaryArithmetic(HBinaryArithmetic instruction) {
HInstruction left = instruction.left;
HInstruction right = instruction.right;
if (left.isInteger(compiler) && right.isInteger(compiler)) {
return backend.intType;
if (left.isInteger(closedWorld) && right.isInteger(closedWorld)) {
return closedWorld.commonMasks.intType;
}
if (left.isDouble(compiler)) return backend.doubleType;
return backend.numType;
if (left.isDouble(closedWorld)) {
return closedWorld.commonMasks.doubleType;
}
return closedWorld.commonMasks.numType;
}
TypeMask checkPositiveInteger(HBinaryArithmetic instruction) {
HInstruction left = instruction.left;
HInstruction right = instruction.right;
if (left.isPositiveInteger(compiler) && right.isPositiveInteger(compiler)) {
return backend.positiveIntType;
if (left.isPositiveInteger(closedWorld) &&
right.isPositiveInteger(closedWorld)) {
return closedWorld.commonMasks.positiveIntType;
}
return visitBinaryArithmetic(instruction);
}
@ -147,7 +150,9 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
HInstruction operand = instruction.operand;
// We have integer subclasses that represent ranges, so widen any int
// subclass to full integer.
if (operand.isInteger(compiler)) return backend.intType;
if (operand.isInteger(closedWorld)) {
return closedWorld.commonMasks.intType;
}
return instruction.operand.instructionType;
}
@ -157,7 +162,7 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
}
TypeMask visitPhi(HPhi phi) {
TypeMask candidateType = backend.emptyType;
TypeMask candidateType = closedWorld.commonMasks.emptyType;
for (int i = 0, length = phi.inputs.length; i < length; i++) {
TypeMask inputType = phi.inputs[i].instructionType;
candidateType = candidateType.union(inputType, closedWorld);
@ -175,11 +180,11 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
// We only do an int check if the input is integer or null.
if (checkedType.containsOnlyNum(closedWorld) &&
!checkedType.containsOnlyDouble(closedWorld) &&
input.isIntegerOrNull(compiler)) {
instruction.checkedType = backend.intType;
input.isIntegerOrNull(closedWorld)) {
instruction.checkedType = closedWorld.commonMasks.intType;
} else if (checkedType.containsOnlyInt(closedWorld) &&
!input.isIntegerOrNull(compiler)) {
instruction.checkedType = backend.numType;
!input.isIntegerOrNull(closedWorld)) {
instruction.checkedType = closedWorld.commonMasks.numType;
}
}
@ -193,9 +198,9 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
if (inputType.containsOnlyInt(closedWorld) &&
checkedType.containsOnlyDouble(closedWorld)) {
if (inputType.isNullable && checkedType.isNullable) {
outputType = backend.doubleType.nullable();
outputType = closedWorld.commonMasks.doubleType.nullable();
} else {
outputType = backend.doubleType;
outputType = closedWorld.commonMasks.doubleType;
}
}
}
@ -248,7 +253,7 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
// If the instruction's type is integer or null, the codegen
// will emit a null check, which is enough to know if it will
// hit a noSuchMethod.
return instruction.isIntegerOrNull(compiler);
return instruction.isIntegerOrNull(closedWorld);
}
return true;
}
@ -259,8 +264,8 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
bool checkReceiver(HInvokeDynamic instruction) {
assert(instruction.isInterceptedCall);
HInstruction receiver = instruction.inputs[1];
if (receiver.isNumber(compiler)) return false;
if (receiver.isNumberOrNull(compiler)) {
if (receiver.isNumber(closedWorld)) return false;
if (receiver.isNumberOrNull(closedWorld)) {
convertInput(
instruction,
receiver,
@ -268,7 +273,7 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
HTypeConversion.RECEIVER_TYPE_CHECK);
return true;
} else if (instruction.element == null) {
Iterable<Element> targets = compiler.closedWorld.allFunctions
Iterable<Element> targets = closedWorld.allFunctions
.filter(instruction.selector, instruction.mask);
if (targets.length == 1) {
MemberElement target = targets.first;
@ -302,11 +307,11 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
HInstruction right = instruction.inputs[2];
Selector selector = instruction.selector;
if (selector.isOperator && left.isNumber(compiler)) {
if (right.isNumber(compiler)) return false;
TypeMask type = right.isIntegerOrNull(compiler)
if (selector.isOperator && left.isNumber(closedWorld)) {
if (right.isNumber(closedWorld)) return false;
TypeMask type = right.isIntegerOrNull(closedWorld)
? right.instructionType.nonNullable()
: backend.numType;
: closedWorld.commonMasks.numType;
// TODO(ngeoffray): Some number operations don't have a builtin
// variant and will do the check in their method anyway. We
// still add a check because it allows to GVN these operations,
@ -371,7 +376,7 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
if (!instruction.selector.isClosureCall) {
TypeMask newType;
TypeMask computeNewType() {
newType = compiler.closedWorld.allFunctions
newType = closedWorld.allFunctions
.receiverType(instruction.selector, instruction.mask);
newType = newType.intersection(receiverType, closedWorld);
return newType;
@ -406,6 +411,6 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
}
return instruction.specializer
.computeTypeFromInputTypes(instruction, compiler);
.computeTypeFromInputTypes(instruction, compiler, closedWorld);
}
}

View file

@ -7,6 +7,7 @@ import '../constant_system_dart.dart';
import '../constants/constant_system.dart';
import '../constants/values.dart';
import '../js_backend/js_backend.dart';
import '../world.dart' show ClosedWorld;
import 'nodes.dart';
import 'optimize.dart';
@ -611,6 +612,8 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
: info = new ValueRangeInfo(constantSystem),
this.constantSystem = constantSystem;
ClosedWorld get closedWorld => compiler.closedWorld;
void visitGraph(HGraph graph) {
this.graph = graph;
visitDominatorTree(graph);
@ -632,7 +635,7 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
void visitBasicBlock(HBasicBlock block) {
void visit(HInstruction instruction) {
Range range = instruction.accept(this);
if (instruction.isInteger(compiler)) {
if (instruction.isInteger(closedWorld)) {
assert(range != null);
ranges[instruction] = range;
}
@ -643,10 +646,10 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
}
Range visitInstruction(HInstruction instruction) {
if (instruction.isPositiveInteger(compiler)) {
if (instruction.isPositiveInteger(closedWorld)) {
return info.newNormalizedRange(
info.intZero, info.newPositiveValue(instruction));
} else if (instruction.isInteger(compiler)) {
} else if (instruction.isInteger(closedWorld)) {
InstructionValue value = info.newInstructionValue(instruction);
return info.newNormalizedRange(value, value);
} else {
@ -655,16 +658,17 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
}
Range visitPhi(HPhi phi) {
if (!phi.isInteger(compiler)) return info.newUnboundRange();
if (!phi.isInteger(closedWorld)) return info.newUnboundRange();
// Some phases may replace instructions that change the inputs of
// this phi. Only the [SsaTypesPropagation] phase will update the
// phi type. Play it safe by assuming the [SsaTypesPropagation]
// phase is not necessarily run before the [ValueRangeAnalyzer].
if (phi.inputs.any((i) => !i.isInteger(compiler))) {
if (phi.inputs.any((i) => !i.isInteger(closedWorld))) {
return info.newUnboundRange();
}
if (phi.block.isLoopHeader()) {
Range range = new LoopUpdateRecognizer(compiler, ranges, info).run(phi);
Range range =
new LoopUpdateRecognizer(closedWorld, ranges, info).run(phi);
if (range == null) return info.newUnboundRange();
return range;
}
@ -677,7 +681,7 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
}
Range visitConstant(HConstant hConstant) {
if (!hConstant.isInteger(compiler)) return info.newUnboundRange();
if (!hConstant.isInteger(closedWorld)) return info.newUnboundRange();
ConstantValue constant = hConstant.constant;
NumConstantValue constantNum;
if (constant is DeferredConstantValue) {
@ -694,8 +698,8 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
}
Range visitFieldGet(HFieldGet fieldGet) {
if (!fieldGet.isInteger(compiler)) return info.newUnboundRange();
if (!fieldGet.receiver.isIndexablePrimitive(compiler)) {
if (!fieldGet.isInteger(closedWorld)) return info.newUnboundRange();
if (!fieldGet.receiver.isIndexablePrimitive(closedWorld)) {
return visitInstruction(fieldGet);
}
JavaScriptBackend backend = compiler.backend;
@ -715,7 +719,7 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
Range lengthRange = ranges[check.length];
if (indexRange == null) {
indexRange = info.newUnboundRange();
assert(!check.index.isInteger(compiler));
assert(!check.index.isInteger(closedWorld));
}
if (lengthRange == null) {
// We might have lost the length range due to a type conversion that
@ -723,7 +727,7 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
// get to this point anyway, so no need to try and refine ranges.
return indexRange;
}
assert(check.length.isInteger(compiler));
assert(check.length.isInteger(closedWorld));
// Check if the index is strictly below the upper bound of the length
// range.
@ -776,8 +780,8 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
Range visitRelational(HRelational relational) {
HInstruction right = relational.right;
HInstruction left = relational.left;
if (!left.isInteger(compiler)) return info.newUnboundRange();
if (!right.isInteger(compiler)) return info.newUnboundRange();
if (!left.isInteger(closedWorld)) return info.newUnboundRange();
if (!right.isInteger(closedWorld)) return info.newUnboundRange();
BinaryOperation operation = relational.operation(constantSystem);
Range rightRange = ranges[relational.right];
Range leftRange = ranges[relational.left];
@ -812,7 +816,7 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
if (divisor != null) {
// For Integer values we can be precise in the upper bound,
// so special case those.
if (left.isInteger(compiler) && right.isInteger(compiler)) {
if (left.isInteger(closedWorld) && right.isInteger(closedWorld)) {
if (divisor.isPositive) {
return info.newNormalizedRange(
info.intZero, divisor.upper - info.intOne);
@ -820,7 +824,7 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
return info.newNormalizedRange(
info.intZero, info.newNegateValue(divisor.lower) - info.intOne);
}
} else if (left.isNumber(compiler) && right.isNumber(compiler)) {
} else if (left.isNumber(closedWorld) && right.isNumber(closedWorld)) {
if (divisor.isPositive) {
return info.newNormalizedRange(info.intZero, divisor.upper);
} else if (divisor.isNegative) {
@ -839,7 +843,7 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
}
Range handleBinaryOperation(HBinaryArithmetic instruction) {
if (!instruction.isInteger(compiler)) return info.newUnboundRange();
if (!instruction.isInteger(closedWorld)) return info.newUnboundRange();
return instruction
.operation(constantSystem)
.apply(ranges[instruction.left], ranges[instruction.right]);
@ -854,10 +858,10 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
}
Range visitBitAnd(HBitAnd node) {
if (!node.isInteger(compiler)) return info.newUnboundRange();
if (!node.isInteger(closedWorld)) return info.newUnboundRange();
HInstruction right = node.right;
HInstruction left = node.left;
if (left.isInteger(compiler) && right.isInteger(compiler)) {
if (left.isInteger(closedWorld) && right.isInteger(closedWorld)) {
return ranges[left] & ranges[right];
}
@ -871,9 +875,9 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
return info.newUnboundRange();
}
if (left.isInteger(compiler)) {
if (left.isInteger(closedWorld)) {
return tryComputeRange(left);
} else if (right.isInteger(compiler)) {
} else if (right.isInteger(closedWorld)) {
return tryComputeRange(right);
}
return info.newUnboundRange();
@ -888,9 +892,8 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
HInstruction createRangeConversion(
HInstruction cursor, HInstruction instruction) {
JavaScriptBackend backend = compiler.backend;
HRangeConversion newInstruction =
new HRangeConversion(instruction, backend.intType);
new HRangeConversion(instruction, closedWorld.commonMasks.intType);
conversions.add(newInstruction);
cursor.block.addBefore(cursor, newInstruction);
// Update the users of the instruction dominated by [cursor] to
@ -953,8 +956,8 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
if (condition is HIdentity) return info.newUnboundRange();
HInstruction right = condition.right;
HInstruction left = condition.left;
if (!left.isInteger(compiler)) return info.newUnboundRange();
if (!right.isInteger(compiler)) return info.newUnboundRange();
if (!left.isInteger(closedWorld)) return info.newUnboundRange();
if (!right.isInteger(closedWorld)) return info.newUnboundRange();
Range rightRange = ranges[right];
Range leftRange = ranges[left];
@ -1016,10 +1019,10 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
* Tries to find a range for the update instruction of a loop phi.
*/
class LoopUpdateRecognizer extends HBaseVisitor {
final Compiler compiler;
final ClosedWorld closedWorld;
final Map<HInstruction, Range> ranges;
final ValueRangeInfo info;
LoopUpdateRecognizer(this.compiler, this.ranges, this.info);
LoopUpdateRecognizer(this.closedWorld, this.ranges, this.info);
Range run(HPhi loopPhi) {
// Create a marker range for the loop phi, so that if the update
@ -1044,7 +1047,7 @@ class LoopUpdateRecognizer extends HBaseVisitor {
}
Range visit(HInstruction instruction) {
if (!instruction.isInteger(compiler)) return null;
if (!instruction.isInteger(closedWorld)) return null;
if (ranges[instruction] != null) return ranges[instruction];
return instruction.accept(this);
}

View file

@ -61,6 +61,12 @@ class CommonMasks {
TypeMask _syncStarIterableType;
TypeMask _asyncFutureType;
TypeMask _asyncStarStreamType;
TypeMask _indexablePrimitiveType;
TypeMask _readableArrayType;
TypeMask _mutableArrayType;
TypeMask _fixedArrayType;
TypeMask _extendableArrayType;
TypeMask _unmodifiableArrayType;
TypeMask get dynamicType => _dynamicType ??=
new TypeMask.subclass(closedWorld.coreClasses.objectClass, closedWorld);
@ -132,4 +138,29 @@ class CommonMasks {
// TODO(johnniwinther): Assert that the null type has been resolved.
TypeMask get nullType => _nullType ??= const TypeMask.empty();
TypeMask get emptyType => const TypeMask.nonNullEmpty();
TypeMask get indexablePrimitiveType =>
_indexablePrimitiveType ??= new TypeMask.nonNullSubtype(
backendClasses.indexableImplementation, closedWorld);
TypeMask get readableArrayType =>
_readableArrayType ??= new TypeMask.nonNullSubclass(
backendClasses.listImplementation, closedWorld);
TypeMask get mutableArrayType =>
_mutableArrayType ??= new TypeMask.nonNullSubclass(
backendClasses.mutableListImplementation, closedWorld);
TypeMask get fixedArrayType => _fixedArrayType ??= new TypeMask.nonNullExact(
backendClasses.fixedListImplementation, closedWorld);
TypeMask get extendableArrayType =>
_extendableArrayType ??= new TypeMask.nonNullExact(
backendClasses.growableListImplementation, closedWorld);
TypeMask get unmodifiableArrayType =>
_unmodifiableArrayType ??= new TypeMask.nonNullExact(
backendClasses.constListImplementation, closedWorld);
}