mirror of
https://github.com/dart-lang/sdk
synced 2024-09-18 22:21:18 +00:00
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:
parent
756cfc963d
commit
415ba7948c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue