Make codegen and optimizations depend more directly on data objects.

This is a move towards passing all information through data objects
computed by previous phases rather than pulling it directly from
Backend or Compiler.

This is needed to support a shift from model K to model J between
resolution and codegen.

R=efortuna@google.com

Review-Url: https://codereview.chromium.org/2777163002 .
This commit is contained in:
Johnni Winther
2017-03-28 10:38:25 +02:00
parent a2286d6eb1
commit e7a72961c8
7 changed files with 564 additions and 346 deletions
+7 -6
View File
@@ -318,17 +318,18 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
}
void preGenerateMethod(HGraph graph) {
new SsaInstructionSelection(compiler, closedWorld).visitGraph(graph);
new SsaInstructionSelection(closedWorld, backend.interceptorData)
.visitGraph(graph);
new SsaTypeKnownRemover().visitGraph(graph);
new SsaTrustedCheckRemover(compiler).visitGraph(graph);
new SsaInstructionMerger(generateAtUseSite, compiler).visitGraph(graph);
new SsaTrustedCheckRemover(compiler.options).visitGraph(graph);
new SsaInstructionMerger(generateAtUseSite, backend).visitGraph(graph);
new SsaConditionMerger(generateAtUseSite, controlFlowOperators)
.visitGraph(graph);
SsaLiveIntervalBuilder intervalBuilder = new SsaLiveIntervalBuilder(
compiler, generateAtUseSite, controlFlowOperators);
SsaLiveIntervalBuilder intervalBuilder =
new SsaLiveIntervalBuilder(generateAtUseSite, controlFlowOperators);
intervalBuilder.visitGraph(graph);
SsaVariableAllocator allocator = new SsaVariableAllocator(
compiler,
backend.namer,
intervalBuilder.liveInstructions,
intervalBuilder.liveIntervals,
generateAtUseSite);
+20 -22
View File
@@ -2,10 +2,11 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import '../compiler.dart' show Compiler;
import '../constants/values.dart';
import '../elements/elements.dart';
import '../js_backend/js_backend.dart';
import '../js_backend/interceptor_data.dart';
import '../options.dart';
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
import '../world.dart' show ClosedWorld;
@@ -16,13 +17,11 @@ import 'nodes.dart';
* Caches codegen information on nodes.
*/
class SsaInstructionSelection extends HBaseVisitor {
final Compiler compiler;
final ClosedWorld closedWorld;
final ClosedWorld _closedWorld;
final InterceptorData _interceptorData;
HGraph graph;
SsaInstructionSelection(this.compiler, this.closedWorld);
JavaScriptBackend get backend => compiler.backend;
SsaInstructionSelection(this._closedWorld, this._interceptorData);
void visitGraph(HGraph graph) {
this.graph = graph;
@@ -68,8 +67,8 @@ class SsaInstructionSelection extends HBaseVisitor {
if (node.kind == HIs.RAW_CHECK) {
HInstruction interceptor = node.interceptor;
if (interceptor != null) {
return new HIsViaInterceptor(
node.typeExpression, interceptor, closedWorld.commonMasks.boolType);
return new HIsViaInterceptor(node.typeExpression, interceptor,
_closedWorld.commonMasks.boolType);
}
}
return node;
@@ -88,7 +87,7 @@ class SsaInstructionSelection extends HBaseVisitor {
if (leftType.isNullable && rightType.isNullable) {
if (left.isConstantNull() ||
right.isConstantNull() ||
(left.isPrimitive(closedWorld) && leftType == rightType)) {
(left.isPrimitive(_closedWorld) && leftType == rightType)) {
return '==';
}
return null;
@@ -105,7 +104,7 @@ class SsaInstructionSelection extends HBaseVisitor {
HInstruction visitInvokeSuper(HInvokeSuper node) {
if (node.isInterceptedCall) {
TypeMask mask = node.getDartReceiver(closedWorld).instructionType;
TypeMask mask = node.getDartReceiver(_closedWorld).instructionType;
tryReplaceInterceptorWithDummy(node, node.selector, mask);
}
return node;
@@ -142,12 +141,12 @@ class SsaInstructionSelection extends HBaseVisitor {
HInstruction receiverArgument = node.inputs[1];
if (interceptor.nonCheck() == receiverArgument.nonCheck()) {
if (backend.interceptorData.isInterceptedSelector(selector) &&
!backend.interceptorData.isInterceptedMixinSelector(selector, mask)) {
if (_interceptorData.isInterceptedSelector(selector) &&
!_interceptorData.isInterceptedMixinSelector(selector, mask)) {
ConstantValue constant = new SyntheticConstantValue(
SyntheticConstantKind.DUMMY_INTERCEPTOR,
receiverArgument.instructionType);
HConstant dummy = graph.addConstant(constant, closedWorld);
HConstant dummy = graph.addConstant(constant, _closedWorld);
receiverArgument.usedBy.remove(node);
node.inputs[1] = dummy;
dummy.usedBy.add(node);
@@ -244,7 +243,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(closedWorld)) return simpleBinary(assignOp);
if (op.isUInt31(_closedWorld)) return simpleBinary(assignOp);
return noMatchingRead();
}
@@ -298,11 +297,12 @@ class SsaTypeKnownRemover extends HBaseVisitor {
* mode.
*/
class SsaTrustedCheckRemover extends HBaseVisitor {
Compiler compiler;
SsaTrustedCheckRemover(this.compiler);
final CompilerOptions _options;
SsaTrustedCheckRemover(this._options);
void visitGraph(HGraph graph) {
if (!compiler.options.trustPrimitives) return;
if (!_options.trustPrimitives) return;
visitDominatorTree(graph);
}
@@ -334,7 +334,7 @@ class SsaTrustedCheckRemover extends HBaseVisitor {
* t2 = add(4, 3);
*/
class SsaInstructionMerger extends HBaseVisitor {
final Compiler compiler;
final JavaScriptBackend _backend;
/**
* List of [HInstruction] that the instruction merger expects in
* order when visiting the inputs of an instruction.
@@ -353,9 +353,7 @@ class SsaInstructionMerger extends HBaseVisitor {
generateAtUseSite.add(instruction);
}
SsaInstructionMerger(this.generateAtUseSite, this.compiler);
JavaScriptBackend get backend => compiler.backend;
SsaInstructionMerger(this.generateAtUseSite, this._backend);
void visitGraph(HGraph graph) {
visitDominatorTree(graph);
@@ -438,7 +436,7 @@ class SsaInstructionMerger extends HBaseVisitor {
// after first access if we use lazy initialization.
// In this case, we therefore don't allow the receiver (the first argument)
// to be generated at use site, and only analyze all other arguments.
if (!backend.canUseAliasedSuperMember(superMethod, selector)) {
if (!_backend.canUseAliasedSuperMember(superMethod, selector)) {
analyzeInputs(instruction, 1);
} else {
super.visitInvokeSuper(instruction);
@@ -3,11 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
import '../common/backend_api.dart' show BackendClasses;
import '../compiler.dart' show Compiler;
import '../constants/constant_system.dart';
import '../constants/values.dart';
import '../elements/entities.dart';
import '../js_backend/backend.dart';
import '../js_backend/backend_helpers.dart';
import '../js_backend/interceptor_data.dart';
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
import '../world.dart' show ClosedWorld;
@@ -38,13 +38,13 @@ class SsaSimplifyInterceptors extends HBaseVisitor
implements OptimizationPhase {
final String name = "SsaSimplifyInterceptors";
final ClosedWorld closedWorld;
final Compiler compiler;
final BackendHelpers helpers;
final InterceptorData interceptorData;
final ClassEntity enclosingClass;
HGraph graph;
SsaSimplifyInterceptors(this.compiler, this.closedWorld, this.enclosingClass);
JavaScriptBackend get backend => compiler.backend;
SsaSimplifyInterceptors(this.closedWorld, this.helpers, this.interceptorData,
this.enclosingClass);
BackendClasses get backendClasses => closedWorld.backendClasses;
@@ -108,8 +108,7 @@ class SsaSimplifyInterceptors extends HBaseVisitor
// All intercepted classes extend `Interceptor`, so if the receiver can't be
// a class extending `Interceptor` then it can be called directly.
return new TypeMask.nonNullSubclass(
backend.helpers.jsInterceptorClass, closedWorld)
return new TypeMask.nonNullSubclass(helpers.jsInterceptorClass, closedWorld)
.isDisjoint(receiver.instructionType, closedWorld);
}
@@ -224,8 +223,8 @@ class SsaSimplifyInterceptors extends HBaseVisitor
dominator.isCallOnInterceptor(closedWorld) &&
node == dominator.receiver &&
useCount(dominator, node) == 1) {
interceptedClasses = backend.interceptorData
.getInterceptedClassesOn(dominator.selector.name);
interceptedClasses =
interceptorData.getInterceptedClassesOn(dominator.selector.name);
// If we found that we need number, we must still go through all
// uses to check if they require int, or double.
@@ -235,8 +234,8 @@ class SsaSimplifyInterceptors extends HBaseVisitor
Set<ClassEntity> required;
for (HInstruction user in node.usedBy) {
if (user is! HInvoke) continue;
Set<ClassEntity> intercepted = backend.interceptorData
.getInterceptedClassesOn(user.selector.name);
Set<ClassEntity> intercepted =
interceptorData.getInterceptedClassesOn(user.selector.name);
if (intercepted.contains(backendClasses.intClass)) {
// TODO(johnniwinther): Use type argument when all uses of
// intercepted classes expect entities instead of elements.
@@ -250,7 +249,7 @@ class SsaSimplifyInterceptors extends HBaseVisitor
required.add(backendClasses.doubleClass);
}
}
// Don't modify the result of [backend.getInterceptedClassesOn].
// Don't modify the result of [interceptorData.getInterceptedClassesOn].
if (required != null) {
interceptedClasses = interceptedClasses.union(required);
}
@@ -264,18 +263,18 @@ class SsaSimplifyInterceptors extends HBaseVisitor
user.isCallOnInterceptor(closedWorld) &&
node == user.receiver &&
useCount(user, node) == 1) {
interceptedClasses.addAll(backend.interceptorData
.getInterceptedClassesOn(user.selector.name));
interceptedClasses.addAll(
interceptorData.getInterceptedClassesOn(user.selector.name));
} else if (user is HInvokeSuper &&
user.isCallOnInterceptor(closedWorld) &&
node == user.receiver &&
useCount(user, node) == 1) {
interceptedClasses.addAll(backend.interceptorData
.getInterceptedClassesOn(user.selector.name));
interceptedClasses.addAll(
interceptorData.getInterceptedClassesOn(user.selector.name));
} else {
// Use a most general interceptor for other instructions, example,
// is-checks and escaping interceptors.
interceptedClasses.addAll(backend.interceptorData.interceptedClasses);
interceptedClasses.addAll(interceptorData.interceptedClasses);
break;
}
}
@@ -352,8 +351,7 @@ class SsaSimplifyInterceptors extends HBaseVisitor
// See if we can rewrite the is-check to use 'instanceof', i.e. rewrite
// "getInterceptor(x).$isT" to "x instanceof T".
if (node == user.interceptor) {
if (backend.interceptorData
.mayGenerateInstanceofCheck(user.typeExpression)) {
if (interceptorData.mayGenerateInstanceofCheck(user.typeExpression)) {
HInstruction instanceofCheck = new HIs.instanceOf(
user.typeExpression, user.expression, user.instructionType);
instanceofCheck.sourceInformation = user.sourceInformation;
@@ -8,6 +8,8 @@ import '../constants/values.dart';
import '../elements/elements.dart' show Name;
import '../elements/entities.dart';
import '../js_backend/js_backend.dart';
import '../js_backend/backend_helpers.dart';
import '../options.dart';
import '../types/types.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
@@ -25,13 +27,21 @@ class InvokeDynamicSpecializer {
const InvokeDynamicSpecializer();
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
return TypeMaskFactory.inferredTypeForSelector(instruction.selector,
instruction.mask, compiler.globalInference.results);
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
return TypeMaskFactory.inferredTypeForSelector(
instruction.selector, instruction.mask, results);
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
return null;
}
@@ -42,11 +52,9 @@ class InvokeDynamicSpecializer {
}
Selector renameToOptimizedSelector(
String name, Selector selector, Compiler compiler) {
String name, Selector selector, BackendHelpers helpers) {
if (selector.name == name) return selector;
JavaScriptBackend backend = compiler.backend;
return new Selector.call(
new Name(name, backend.helpers.interceptorsLibrary),
return new Selector.call(new Name(name, helpers.interceptorsLibrary),
new CallStructure(selector.argumentCount));
}
@@ -108,10 +116,14 @@ class IndexAssignSpecializer extends InvokeDynamicSpecializer {
const IndexAssignSpecializer();
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
if (instruction.inputs[1].isMutableIndexable(closedWorld)) {
if (!instruction.inputs[2].isInteger(closedWorld) &&
compiler.options.enableTypeAssertions) {
options.enableTypeAssertions) {
// We want the right checked mode error.
return null;
}
@@ -126,17 +138,21 @@ class IndexSpecializer extends InvokeDynamicSpecializer {
const IndexSpecializer();
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
if (!instruction.inputs[1].isIndexablePrimitive(closedWorld)) return null;
if (!instruction.inputs[2].isInteger(closedWorld) &&
compiler.options.enableTypeAssertions) {
options.enableTypeAssertions) {
// We want the right checked mode error.
return null;
}
TypeMask receiverType =
instruction.getDartReceiver(closedWorld).instructionType;
TypeMask type = TypeMaskFactory.inferredTypeForSelector(
instruction.selector, receiverType, compiler.globalInference.results);
instruction.selector, receiverType, results);
return new HIndex(instruction.inputs[1], instruction.inputs[2],
instruction.selector, type);
}
@@ -150,21 +166,33 @@ class BitNotSpecializer extends InvokeDynamicSpecializer {
}
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
// All bitwise operations on primitive types either produce an
// integer or throw an error.
if (instruction.inputs[1].isPrimitiveOrNull(closedWorld)) {
return closedWorld.commonMasks.uint32Type;
}
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
return super.computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld);
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
HInstruction input = instruction.inputs[1];
if (input.isNumber(closedWorld)) {
return new HBitNot(input, instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
return new HBitNot(
input,
instruction.selector,
computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld));
}
return null;
}
@@ -178,14 +206,23 @@ class UnaryNegateSpecializer extends InvokeDynamicSpecializer {
}
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
TypeMask operandType = instruction.inputs[1].instructionType;
if (instruction.inputs[1].isNumberOrNull(closedWorld)) return operandType;
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
return super.computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld);
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
HInstruction input = instruction.inputs[1];
if (input.isNumber(closedWorld)) {
return new HNegate(input, instruction.selector, input.instructionType);
@@ -198,7 +235,11 @@ abstract class BinaryArithmeticSpecializer extends InvokeDynamicSpecializer {
const BinaryArithmeticSpecializer();
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
if (left.isIntegerOrNull(closedWorld) &&
@@ -212,7 +253,8 @@ abstract class BinaryArithmeticSpecializer extends InvokeDynamicSpecializer {
}
return closedWorld.commonMasks.numType;
}
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
return super.computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld);
}
bool isBuiltin(HInvokeDynamic instruction, ClosedWorld closedWorld) {
@@ -221,10 +263,14 @@ abstract class BinaryArithmeticSpecializer extends InvokeDynamicSpecializer {
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
if (isBuiltin(instruction, closedWorld)) {
HInstruction builtin =
newBuiltinVariant(instruction, compiler, closedWorld);
HInstruction builtin = newBuiltinVariant(
instruction, results, options, helpers, 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
@@ -249,21 +295,30 @@ abstract class BinaryArithmeticSpecializer extends InvokeDynamicSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld);
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld);
}
class AddSpecializer extends BinaryArithmeticSpecializer {
const AddSpecializer();
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
if (inputsAreUInt31(instruction, closedWorld)) {
return closedWorld.commonMasks.uint32Type;
}
if (inputsArePositiveIntegers(instruction, closedWorld)) {
return closedWorld.commonMasks.positiveIntType;
}
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
return super.computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld);
}
BinaryOperation operation(ConstantSystem constantSystem) {
@@ -271,12 +326,17 @@ class AddSpecializer extends BinaryArithmeticSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
return new HAdd(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld));
}
}
@@ -288,16 +348,25 @@ class DivideSpecializer extends BinaryArithmeticSpecializer {
}
TypeMask computeTypeFromInputTypes(
HInstruction instruction, Compiler compiler, ClosedWorld closedWorld) {
HInstruction instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
if (left.isNumberOrNull(closedWorld)) {
return closedWorld.commonMasks.doubleType;
}
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
return super.computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld);
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
return new HDivide(instruction.inputs[1], instruction.inputs[2],
instruction.selector, closedWorld.commonMasks.doubleType);
}
@@ -307,11 +376,16 @@ class ModuloSpecializer extends BinaryArithmeticSpecializer {
const ModuloSpecializer();
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
if (inputsArePositiveIntegers(instruction, closedWorld)) {
return closedWorld.commonMasks.positiveIntType;
}
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
return super.computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld);
}
BinaryOperation operation(ConstantSystem constantSystem) {
@@ -319,7 +393,11 @@ class ModuloSpecializer extends BinaryArithmeticSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
// Modulo cannot be mapped to the native operator (different semantics).
// We can use HRemainder if both inputs are non-negative and the receiver
@@ -366,7 +444,8 @@ class ModuloSpecializer extends BinaryArithmeticSpecializer {
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld));
}
// TODO(sra):
// a % N --> a & (N-1), N=2^k, where a>=0, does not have -0.0 problem.
@@ -385,11 +464,16 @@ class RemainderSpecializer extends BinaryArithmeticSpecializer {
const RemainderSpecializer();
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
if (inputsArePositiveIntegers(instruction, closedWorld)) {
return closedWorld.commonMasks.positiveIntType;
}
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
return super.computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld);
}
BinaryOperation operation(ConstantSystem constantSystem) {
@@ -397,12 +481,17 @@ class RemainderSpecializer extends BinaryArithmeticSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
return new HRemainder(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld));
}
}
@@ -414,20 +503,30 @@ class MultiplySpecializer extends BinaryArithmeticSpecializer {
}
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
if (inputsArePositiveIntegers(instruction, closedWorld)) {
return closedWorld.commonMasks.positiveIntType;
}
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
return super.computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld);
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
return new HMultiply(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld));
}
}
@@ -439,12 +538,17 @@ class SubtractSpecializer extends BinaryArithmeticSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
return new HSubtract(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld));
}
}
@@ -456,14 +560,19 @@ class TruncatingDivideSpecializer extends BinaryArithmeticSpecializer {
}
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
if (hasUint31Result(instruction, closedWorld)) {
return closedWorld.commonMasks.uint31Type;
}
if (inputsArePositiveIntegers(instruction, closedWorld)) {
return closedWorld.commonMasks.positiveIntType;
}
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
return super.computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld);
}
bool isNotZero(HInstruction instruction) {
@@ -497,17 +606,22 @@ class TruncatingDivideSpecializer extends BinaryArithmeticSpecializer {
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
HInstruction right = instruction.inputs[2];
if (isBuiltin(instruction, closedWorld)) {
if (right.isPositiveInteger(closedWorld) && isNotZero(right)) {
if (hasUint31Result(instruction, closedWorld)) {
return newBuiltinVariant(instruction, compiler, closedWorld);
return newBuiltinVariant(
instruction, results, options, helpers, closedWorld);
}
// We can call _tdivFast because the rhs is a 32bit integer
// and not 0, nor -1.
instruction.selector = renameToOptimizedSelector(
'_tdivFast', instruction.selector, compiler);
'_tdivFast', instruction.selector, helpers);
}
clearAllSideEffects(instruction);
}
@@ -515,12 +629,17 @@ class TruncatingDivideSpecializer extends BinaryArithmeticSpecializer {
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
return new HTruncatingDivide(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld));
}
}
@@ -528,14 +647,19 @@ abstract class BinaryBitOpSpecializer extends BinaryArithmeticSpecializer {
const BinaryBitOpSpecializer();
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
// All bitwise operations on primitive types either produce an
// integer or throw an error.
HInstruction left = instruction.inputs[1];
if (left.isPrimitiveOrNull(closedWorld)) {
return closedWorld.commonMasks.uint32Type;
}
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
return super.computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld);
}
bool argumentLessThan32(HInstruction instruction) {
@@ -573,12 +697,17 @@ class ShiftLeftSpecializer extends BinaryBitOpSpecializer {
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
if (left.isNumber(closedWorld)) {
if (argumentLessThan32(right)) {
return newBuiltinVariant(instruction, compiler, closedWorld);
return newBuiltinVariant(
instruction, results, options, helpers, closedWorld);
}
// Even if there is no builtin equivalent instruction, we know
// the instruction does not have any side effect, and that it
@@ -586,19 +715,24 @@ class ShiftLeftSpecializer extends BinaryBitOpSpecializer {
clearAllSideEffects(instruction);
if (isPositive(right, closedWorld)) {
instruction.selector = renameToOptimizedSelector(
'_shlPositive', instruction.selector, compiler);
'_shlPositive', instruction.selector, helpers);
}
}
return null;
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
return new HShiftLeft(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld));
}
}
@@ -606,19 +740,29 @@ class ShiftRightSpecializer extends BinaryBitOpSpecializer {
const ShiftRightSpecializer();
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
if (left.isUInt32(closedWorld)) return left.instructionType;
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
return super.computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld);
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
if (left.isNumber(closedWorld)) {
if (argumentLessThan32(right) && isPositive(left, closedWorld)) {
return newBuiltinVariant(instruction, compiler, closedWorld);
return newBuiltinVariant(
instruction, results, options, helpers, closedWorld);
}
// Even if there is no builtin equivalent instruction, we know
// the instruction does not have any side effect, and that it
@@ -626,25 +770,30 @@ class ShiftRightSpecializer extends BinaryBitOpSpecializer {
clearAllSideEffects(instruction);
if (isPositive(right, closedWorld) && isPositive(left, closedWorld)) {
instruction.selector = renameToOptimizedSelector(
'_shrBothPositive', instruction.selector, compiler);
'_shrBothPositive', instruction.selector, helpers);
} else if (isPositive(left, closedWorld) && right.isNumber(closedWorld)) {
instruction.selector = renameToOptimizedSelector(
'_shrReceiverPositive', instruction.selector, compiler);
'_shrReceiverPositive', instruction.selector, helpers);
} else if (isPositive(right, closedWorld)) {
instruction.selector = renameToOptimizedSelector(
'_shrOtherPositive', instruction.selector, compiler);
'_shrOtherPositive', instruction.selector, helpers);
}
}
return null;
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
return new HShiftRight(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld));
}
BinaryOperation operation(ConstantSystem constantSystem) {
@@ -660,22 +809,32 @@ class BitOrSpecializer extends BinaryBitOpSpecializer {
}
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
if (left.isUInt31(closedWorld) && right.isUInt31(closedWorld)) {
return closedWorld.commonMasks.uint31Type;
}
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
return super.computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld);
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
return new HBitOr(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld));
}
}
@@ -687,23 +846,33 @@ class BitAndSpecializer extends BinaryBitOpSpecializer {
}
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
if (left.isPrimitiveOrNull(closedWorld) &&
(left.isUInt31(closedWorld) || right.isUInt31(closedWorld))) {
return closedWorld.commonMasks.uint31Type;
}
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
return super.computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld);
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
return new HBitAnd(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld));
}
}
@@ -715,22 +884,32 @@ class BitXorSpecializer extends BinaryBitOpSpecializer {
}
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
if (left.isUInt31(closedWorld) && right.isUInt31(closedWorld)) {
return closedWorld.commonMasks.uint31Type;
}
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
return super.computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld);
}
HInstruction newBuiltinVariant(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
return new HBitXor(
instruction.inputs[1],
instruction.inputs[2],
instruction.selector,
computeTypeFromInputTypes(instruction, compiler, closedWorld));
computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld));
}
}
@@ -738,15 +917,24 @@ abstract class RelationalSpecializer extends InvokeDynamicSpecializer {
const RelationalSpecializer();
TypeMask computeTypeFromInputTypes(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
if (instruction.inputs[1].isPrimitiveOrNull(closedWorld)) {
return closedWorld.commonMasks.boolType;
}
return super.computeTypeFromInputTypes(instruction, compiler, closedWorld);
return super.computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld);
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
if (left.isNumber(closedWorld) && right.isNumber(closedWorld)) {
@@ -763,7 +951,11 @@ class EqualsSpecializer extends RelationalSpecializer {
const EqualsSpecializer();
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
TypeMask instructionType = left.instructionType;
@@ -857,7 +1049,11 @@ class CodeUnitAtSpecializer extends InvokeDynamicSpecializer {
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
// TODO(sra): Implement a builtin HCodeUnitAt instruction and the same index
// bounds checking optimizations as for HIndex.
HInstruction receiver = instruction.getDartReceiver(closedWorld);
@@ -868,7 +1064,7 @@ class CodeUnitAtSpecializer extends InvokeDynamicSpecializer {
clearAllSideEffects(instruction);
if (instruction.inputs.last.isPositiveInteger(closedWorld)) {
instruction.selector = renameToOptimizedSelector(
'_codeUnitAt', instruction.selector, compiler);
'_codeUnitAt', instruction.selector, helpers);
}
}
return null;
@@ -879,7 +1075,11 @@ class IdempotentStringOperationSpecializer extends InvokeDynamicSpecializer {
const IdempotentStringOperationSpecializer();
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
HInstruction receiver = instruction.getDartReceiver(closedWorld);
if (receiver.isStringOrNull(closedWorld)) {
// String.xxx does not have any side effect (other than throwing), and it
@@ -902,7 +1102,11 @@ class PatternMatchSpecializer extends InvokeDynamicSpecializer {
const PatternMatchSpecializer();
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
HInstruction receiver = instruction.getDartReceiver(closedWorld);
HInstruction pattern = instruction.inputs[2];
if (receiver.isStringOrNull(closedWorld) &&
@@ -923,7 +1127,11 @@ class RoundSpecializer extends InvokeDynamicSpecializer {
}
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction, Compiler compiler, ClosedWorld closedWorld) {
HInvokeDynamic instruction,
GlobalTypeInferenceResults results,
CompilerOptions options,
BackendHelpers helpers,
ClosedWorld closedWorld) {
HInstruction receiver = instruction.getDartReceiver(closedWorld);
if (receiver.isNumberOrNull(closedWorld)) {
// Even if there is no builtin equivalent instruction, we know the
+196 -180
View File
@@ -16,7 +16,10 @@ import '../elements/resolution_types.dart';
import '../js/js.dart' as js;
import '../js_backend/backend_helpers.dart' show BackendHelpers;
import '../js_backend/js_backend.dart';
import '../js_backend/interceptor_data.dart' show InterceptorData;
import '../js_backend/native_data.dart' show NativeData;
import '../native/native.dart' as native;
import '../options.dart';
import '../tree/dartstring.dart' as ast;
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
@@ -36,26 +39,34 @@ abstract class OptimizationPhase {
}
class SsaOptimizerTask extends CompilerTask {
final JavaScriptBackend backend;
final JavaScriptBackend _backend;
Map<HInstruction, Range> ranges = <HInstruction, Range>{};
SsaOptimizerTask(JavaScriptBackend backend)
: this.backend = backend,
super(backend.compiler.measurer);
SsaOptimizerTask(this._backend) : super(_backend.compiler.measurer);
String get name => 'SSA optimizer';
Compiler get compiler => backend.compiler;
Compiler get _compiler => _backend.compiler;
GlobalTypeInferenceResults get _results => _compiler.globalInference.results;
BackendHelpers get _helpers => _backend.helpers;
CompilerOptions get _options => _compiler.options;
RuntimeTypesSubstitutions get _rtiSubstitutions => _backend.rtiSubstitutions;
InterceptorData get _interceptorData => _backend.interceptorData;
void optimize(CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) {
void runPhase(OptimizationPhase phase) {
measureSubtask(phase.name, () => phase.visitGraph(graph));
backend.tracer.traceGraph(phase.name, graph);
_backend.tracer.traceGraph(phase.name, graph);
assert(graph.isValid());
}
bool trustPrimitives = compiler.options.trustPrimitives;
bool trustPrimitives = _options.trustPrimitives;
CodegenRegistry registry = work.registry;
Set<HInstruction> boundsChecked = new Set<HInstruction>();
SsaCodeMotion codeMotion;
@@ -64,51 +75,55 @@ class SsaOptimizerTask extends CompilerTask {
List<OptimizationPhase> phases = <OptimizationPhase>[
// Run trivial instruction simplification first to optimize
// some patterns useful for type conversion.
new SsaInstructionSimplifier(backend, closedWorld, this, registry),
new SsaInstructionSimplifier(_results, _options, _helpers,
_rtiSubstitutions, closedWorld, registry),
new SsaTypeConversionInserter(closedWorld),
new SsaRedundantPhiEliminator(),
new SsaDeadPhiEliminator(),
new SsaTypePropagator(compiler, closedWorld),
new SsaTypePropagator(_results, _options, _helpers, closedWorld),
// After type propagation, more instructions can be
// simplified.
new SsaInstructionSimplifier(backend, closedWorld, this, registry),
new SsaInstructionSimplifier(_results, _options, _helpers,
_rtiSubstitutions, closedWorld, registry),
new SsaCheckInserter(
trustPrimitives, backend, closedWorld, boundsChecked),
new SsaInstructionSimplifier(backend, closedWorld, this, registry),
trustPrimitives, _helpers, closedWorld, boundsChecked),
new SsaInstructionSimplifier(_results, _options, _helpers,
_rtiSubstitutions, closedWorld, registry),
new SsaCheckInserter(
trustPrimitives, backend, closedWorld, boundsChecked),
new SsaTypePropagator(compiler, closedWorld),
trustPrimitives, _helpers, closedWorld, boundsChecked),
new SsaTypePropagator(_results, _options, _helpers, closedWorld),
// Run a dead code eliminator before LICM because dead
// interceptors are often in the way of LICM'able instructions.
new SsaDeadCodeEliminator(closedWorld, this),
new SsaGlobalValueNumberer(),
// After GVN, some instructions might need their type to be
// updated because they now have different inputs.
new SsaTypePropagator(compiler, closedWorld),
new SsaTypePropagator(_results, _options, _helpers, closedWorld),
codeMotion = new SsaCodeMotion(),
loadElimination =
new SsaLoadElimination(backend, compiler, closedWorld),
new SsaLoadElimination(_helpers, _compiler, closedWorld),
new SsaRedundantPhiEliminator(),
new SsaDeadPhiEliminator(),
// After GVN and load elimination the same value may be used in code
// controlled by a test on the value, so redo 'conversion insertion' to
// learn from the refined type.
new SsaTypeConversionInserter(closedWorld),
new SsaTypePropagator(compiler, closedWorld),
new SsaValueRangeAnalyzer(backend.helpers, closedWorld, this),
new SsaTypePropagator(_results, _options, _helpers, closedWorld),
new SsaValueRangeAnalyzer(_helpers, closedWorld, this),
// Previous optimizations may have generated new
// opportunities for instruction simplification.
new SsaInstructionSimplifier(backend, closedWorld, this, registry),
new SsaInstructionSimplifier(_results, _options, _helpers,
_rtiSubstitutions, closedWorld, registry),
new SsaCheckInserter(
trustPrimitives, backend, closedWorld, boundsChecked),
trustPrimitives, _helpers, closedWorld, boundsChecked),
];
phases.forEach(runPhase);
// Simplifying interceptors is not strictly just an optimization, it is
// required for implementation correctness because the code generator
// assumes it is always performed.
runPhase(new SsaSimplifyInterceptors(
compiler, closedWorld, work.element.enclosingClass));
runPhase(new SsaSimplifyInterceptors(closedWorld, _helpers,
_interceptorData, work.element.enclosingClass));
SsaDeadCodeEliminator dce = new SsaDeadCodeEliminator(closedWorld, this);
runPhase(dce);
@@ -116,23 +131,25 @@ class SsaOptimizerTask extends CompilerTask {
dce.eliminatedSideEffects ||
loadElimination.newGvnCandidates) {
phases = <OptimizationPhase>[
new SsaTypePropagator(compiler, closedWorld),
new SsaTypePropagator(_results, _options, _helpers, closedWorld),
new SsaGlobalValueNumberer(),
new SsaCodeMotion(),
new SsaValueRangeAnalyzer(backend.helpers, closedWorld, this),
new SsaInstructionSimplifier(backend, closedWorld, this, registry),
new SsaValueRangeAnalyzer(_helpers, closedWorld, this),
new SsaInstructionSimplifier(_results, _options, _helpers,
_rtiSubstitutions, closedWorld, registry),
new SsaCheckInserter(
trustPrimitives, backend, closedWorld, boundsChecked),
new SsaSimplifyInterceptors(
compiler, closedWorld, work.element.enclosingClass),
trustPrimitives, _helpers, closedWorld, boundsChecked),
new SsaSimplifyInterceptors(closedWorld, _helpers, _interceptorData,
work.element.enclosingClass),
new SsaDeadCodeEliminator(closedWorld, this),
];
} else {
phases = <OptimizationPhase>[
new SsaTypePropagator(compiler, closedWorld),
new SsaTypePropagator(_results, _options, _helpers, closedWorld),
// Run the simplifier to remove unneeded type checks inserted by
// type propagation.
new SsaInstructionSimplifier(backend, closedWorld, this, registry),
new SsaInstructionSimplifier(_results, _options, _helpers,
_rtiSubstitutions, closedWorld, registry),
];
}
phases.forEach(runPhase);
@@ -171,27 +188,25 @@ class SsaInstructionSimplifier extends HBaseVisitor
static const MAX_SHARED_CONSTANT_FOLDED_STRING_LENGTH = 512;
final String name = "SsaInstructionSimplifier";
final JavaScriptBackend backend;
final ClosedWorld closedWorld;
final CodegenRegistry registry;
HGraph graph;
Compiler get compiler => backend.compiler;
final SsaOptimizerTask optimizer;
final GlobalTypeInferenceResults _globalInferenceResults;
final CompilerOptions _options;
final BackendHelpers _helpers;
final RuntimeTypesSubstitutions _rtiSubstitutions;
final ClosedWorld _closedWorld;
final CodegenRegistry _registry;
HGraph _graph;
SsaInstructionSimplifier(
this.backend, this.closedWorld, this.optimizer, this.registry);
SsaInstructionSimplifier(this._globalInferenceResults, this._options,
this._helpers, this._rtiSubstitutions, this._closedWorld, this._registry);
CommonElements get commonElements => closedWorld.commonElements;
CommonElements get commonElements => _closedWorld.commonElements;
BackendHelpers get helpers => backend.helpers;
ConstantSystem get constantSystem => _closedWorld.constantSystem;
ConstantSystem get constantSystem => closedWorld.constantSystem;
GlobalTypeInferenceResults get globalInferenceResults =>
compiler.globalInference.results;
NativeData get _nativeData => _closedWorld.nativeData;
void visitGraph(HGraph visitee) {
graph = visitee;
_graph = visitee;
visitDominatorTree(visitee);
}
@@ -208,12 +223,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(closedWorld) &&
instruction.isNumberOrNull(closedWorld))) {
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, closedWorld);
.intersection(instruction.instructionType, _closedWorld);
replacement.instructionType = newType;
}
@@ -260,7 +275,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
if (node.usedBy.isEmpty) return;
ConstantValue value = getConstantFromType(node);
if (value != null) {
HConstant constant = graph.addConstant(value, closedWorld);
HConstant constant = _graph.addConstant(value, _closedWorld);
for (HInstruction user in node.usedBy.toList()) {
user.changeUse(node, constant);
}
@@ -296,7 +311,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
List<HInstruction> inputs = node.inputs;
assert(inputs.length == 1);
HInstruction input = inputs[0];
if (input.isBoolean(closedWorld)) 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
@@ -306,8 +321,8 @@ class SsaInstructionSimplifier extends HBaseVisitor
// All values that cannot be 'true' are boolified to false.
TypeMask mask = input.instructionType;
if (!mask.contains(helpers.jsBoolClass, closedWorld)) {
return graph.addConstantBool(false, closedWorld);
if (!mask.contains(_helpers.jsBoolClass, _closedWorld)) {
return _graph.addConstantBool(false, _closedWorld);
}
return node;
}
@@ -319,7 +334,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
if (input is HConstant) {
HConstant constant = input;
bool isTrue = constant.constant.isTrue;
return graph.addConstantBool(!isTrue, closedWorld);
return _graph.addConstantBool(!isTrue, _closedWorld);
} else if (input is HNot) {
return input.inputs[0];
}
@@ -336,33 +351,34 @@ class SsaInstructionSimplifier extends HBaseVisitor
if (operand is HConstant) {
HConstant receiver = operand;
ConstantValue folded = operation.fold(receiver.constant);
if (folded != null) return graph.addConstant(folded, closedWorld);
if (folded != null) return _graph.addConstant(folded, _closedWorld);
}
return null;
}
HInstruction tryOptimizeLengthInterceptedGetter(HInvokeDynamic node) {
HInstruction actualReceiver = node.inputs[1];
if (actualReceiver.isIndexablePrimitive(closedWorld)) {
if (actualReceiver.isIndexablePrimitive(_closedWorld)) {
if (actualReceiver.isConstantString()) {
HConstant constantInput = actualReceiver;
StringConstantValue constant = constantInput.constant;
return graph.addConstantInt(constant.length, closedWorld);
return _graph.addConstantInt(constant.length, _closedWorld);
} else if (actualReceiver.isConstantList()) {
HConstant constantInput = actualReceiver;
ListConstantValue constant = constantInput.constant;
return graph.addConstantInt(constant.length, closedWorld);
return _graph.addConstantInt(constant.length, _closedWorld);
}
bool isFixed = isFixedLength(actualReceiver.instructionType, closedWorld);
bool isFixed =
isFixedLength(actualReceiver.instructionType, _closedWorld);
TypeMask actualType = node.instructionType;
TypeMask resultType = closedWorld.commonMasks.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 = closedWorld.commonMasks.uint31Type;
actualType, _helpers.jsUInt31Class, _closedWorld)) {
resultType = _closedWorld.commonMasks.uint31Type;
} else if (HInstruction.isInstanceOf(
actualType, helpers.jsUInt32Class, closedWorld)) {
resultType = closedWorld.commonMasks.uint32Type;
actualType, _helpers.jsUInt32Class, _closedWorld)) {
resultType = _closedWorld.commonMasks.uint32Type;
}
HGetLength result =
new HGetLength(actualReceiver, resultType, isAssignable: !isFixed);
@@ -370,7 +386,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
} else if (actualReceiver.isConstantMap()) {
HConstant constantInput = actualReceiver;
MapConstantValue constant = constantInput.constant;
return graph.addConstantInt(constant.length, closedWorld);
return _graph.addConstantInt(constant.length, _closedWorld);
}
return null;
}
@@ -386,8 +402,8 @@ class SsaInstructionSimplifier extends HBaseVisitor
}
// Try converting the instruction to a builtin instruction.
HInstruction instruction =
node.specializer.tryConvertToBuiltin(node, compiler, closedWorld);
HInstruction instruction = node.specializer.tryConvertToBuiltin(
node, _globalInferenceResults, _options, _helpers, _closedWorld);
if (instruction != null) return instruction;
Selector selector = node.selector;
@@ -396,36 +412,36 @@ class SsaInstructionSimplifier extends HBaseVisitor
bool applies(MemberEntity element) {
return selector.applies(element) &&
(mask == null || mask.canHit(element, selector, closedWorld));
(mask == null || mask.canHit(element, selector, _closedWorld));
}
if (selector.isCall || selector.isOperator) {
FunctionEntity target;
if (input.isExtendableArray(closedWorld)) {
if (applies(helpers.jsArrayRemoveLast)) {
target = helpers.jsArrayRemoveLast;
} else if (applies(helpers.jsArrayAdd)) {
if (input.isExtendableArray(_closedWorld)) {
if (applies(_helpers.jsArrayRemoveLast)) {
target = _helpers.jsArrayRemoveLast;
} else if (applies(_helpers.jsArrayAdd)) {
// The codegen special cases array calls, but does not
// inline argument type checks.
if (!compiler.options.enableTypeAssertions) {
target = helpers.jsArrayAdd;
if (!_options.enableTypeAssertions) {
target = _helpers.jsArrayAdd;
}
}
} else if (input.isStringOrNull(closedWorld)) {
if (applies(helpers.jsStringSplit)) {
} else if (input.isStringOrNull(_closedWorld)) {
if (applies(_helpers.jsStringSplit)) {
HInstruction argument = node.inputs[2];
if (argument.isString(closedWorld)) {
target = helpers.jsStringSplit;
if (argument.isString(_closedWorld)) {
target = _helpers.jsStringSplit;
}
} else if (applies(helpers.jsStringOperatorAdd)) {
} else if (applies(_helpers.jsStringOperatorAdd)) {
// `operator+` is turned into a JavaScript '+' so we need to
// 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(closedWorld) && !input.canBeNull()) {
if (argument.isString(_closedWorld) && !input.canBeNull()) {
return new HStringConcat(input, argument, node.instructionType);
}
} else if (applies(helpers.jsStringToString) && !input.canBeNull()) {
} else if (applies(_helpers.jsStringToString) && !input.canBeNull()) {
return input;
}
}
@@ -444,7 +460,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
return result;
}
} else if (selector.isGetter) {
if (selector.applies(helpers.jsIndexableLength)) {
if (selector.applies(_helpers.jsIndexableLength)) {
HInstruction optimized = tryOptimizeLengthInterceptedGetter(node);
if (optimized != null) return optimized;
}
@@ -460,9 +476,9 @@ class SsaInstructionSimplifier extends HBaseVisitor
if (folded != node) return folded;
}
TypeMask receiverType = node.getDartReceiver(closedWorld).instructionType;
TypeMask receiverType = node.getDartReceiver(_closedWorld).instructionType;
MemberEntity element =
closedWorld.locateSingleElement(node.selector, receiverType);
_closedWorld.locateSingleElement(node.selector, receiverType);
// TODO(ngeoffray): Also fold if it's a getter or variable.
if (element != null &&
element.isFunction
@@ -472,7 +488,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
node.selector.applies(element)) {
MethodElement method = element;
if (backend.nativeData.isNativeMember(method)) {
if (_nativeData.isNativeMember(method)) {
HInstruction folded = tryInlineNativeMethod(node, method);
if (folded != null) return folded;
} else {
@@ -498,11 +514,11 @@ class SsaInstructionSimplifier extends HBaseVisitor
element.isField &&
element.name == node.selector.name) {
FieldEntity field = element;
if (!backend.nativeData.isNativeMember(field) &&
!node.isCallOnInterceptor(closedWorld)) {
HInstruction receiver = node.getDartReceiver(closedWorld);
if (!_nativeData.isNativeMember(field) &&
!node.isCallOnInterceptor(_closedWorld)) {
HInstruction receiver = node.getDartReceiver(_closedWorld);
TypeMask type = TypeMaskFactory.inferredTypeForElement(
field as Entity, globalInferenceResults);
field as Entity, _globalInferenceResults);
HInstruction load = new HFieldGet(field, receiver, type);
node.block.addBefore(node, load);
Selector callSelector = new Selector.callClosureFrom(node.selector);
@@ -548,7 +564,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
List<HInstruction> inputs = node.inputs.sublist(1);
bool canInline = true;
if (compiler.options.enableTypeAssertions && inputs.length > 1) {
if (_options.enableTypeAssertions && inputs.length > 1) {
// TODO(sra): Check if [input] is guaranteed to pass the parameter
// type check. Consider using a strengthened type check to avoid
// passing `null` to primitive types since the native methods usually
@@ -574,9 +590,9 @@ class SsaInstructionSimplifier extends HBaseVisitor
// Strengthen instruction type from annotations to help optimize
// dependent instructions.
native.NativeBehavior nativeBehavior =
backend.nativeData.getNativeMethodBehavior(method);
_nativeData.getNativeMethodBehavior(method);
TypeMask returnType =
TypeMaskFactory.fromNativeBehavior(nativeBehavior, closedWorld);
TypeMaskFactory.fromNativeBehavior(nativeBehavior, _closedWorld);
HInvokeDynamicMethod result =
new HInvokeDynamicMethod(node.selector, node.mask, inputs, returnType);
result.element = method;
@@ -585,7 +601,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
HInstruction visitBoundsCheck(HBoundsCheck node) {
HInstruction index = node.index;
if (index.isInteger(closedWorld)) return node;
if (index.isInteger(_closedWorld)) return node;
if (index.isConstant()) {
HConstant constantInstruction = index;
assert(!constantInstruction.constant.isInt);
@@ -603,7 +619,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
HConstant op1 = left;
HConstant op2 = right;
ConstantValue folded = operation.fold(op1.constant, op2.constant);
if (folded != null) return graph.addConstant(folded, closedWorld);
if (folded != null) return _graph.addConstant(folded, _closedWorld);
}
return null;
}
@@ -613,7 +629,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(closedWorld) && right.isInteger(closedWorld)) {
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;
}
@@ -623,7 +639,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
HInstruction visitMultiply(HMultiply node) {
HInstruction left = node.left;
HInstruction right = node.right;
if (left.isNumber(closedWorld) && right.isNumber(closedWorld)) {
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;
}
@@ -664,14 +680,14 @@ class SsaInstructionSimplifier extends HBaseVisitor
TypeMask leftType = left.instructionType;
TypeMask rightType = right.instructionType;
HInstruction makeTrue() => graph.addConstantBool(true, closedWorld);
HInstruction makeFalse() => graph.addConstantBool(false, closedWorld);
HInstruction makeTrue() => _graph.addConstantBool(true, _closedWorld);
HInstruction makeFalse() => _graph.addConstantBool(false, _closedWorld);
// Intersection of int and double return conflicting, so
// we don't optimize on numbers to preserve the runtime semantics.
if (!(left.isNumberOrNull(closedWorld) &&
right.isNumberOrNull(closedWorld))) {
if (leftType.isDisjoint(rightType, closedWorld)) {
if (!(left.isNumberOrNull(_closedWorld) &&
right.isNumberOrNull(_closedWorld))) {
if (leftType.isDisjoint(rightType, _closedWorld)) {
return makeFalse();
}
}
@@ -684,15 +700,15 @@ class SsaInstructionSimplifier extends HBaseVisitor
if (constant.constant.isTrue) {
return input;
} else {
return new HNot(input, closedWorld.commonMasks.boolType);
return new HNot(input, _closedWorld.commonMasks.boolType);
}
}
if (left.isConstantBoolean() && right.isBoolean(closedWorld)) {
if (left.isConstantBoolean() && right.isBoolean(_closedWorld)) {
return compareConstant(left, right);
}
if (right.isConstantBoolean() && left.isBoolean(closedWorld)) {
if (right.isConstantBoolean() && left.isBoolean(_closedWorld)) {
return compareConstant(right, left);
}
@@ -701,8 +717,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(closedWorld)) return makeTrue();
if (!left.canBePrimitiveNumber(closedWorld)) return makeTrue();
if (left.isIntegerOrNull(_closedWorld)) return makeTrue();
if (!left.canBePrimitiveNumber(_closedWorld)) return makeTrue();
}
return null;
@@ -716,7 +732,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
void simplifyCondition(
HBasicBlock block, HInstruction condition, bool value) {
condition.dominatedUsers(block.first).forEach((user) {
HInstruction newCondition = graph.addConstantBool(value, closedWorld);
HInstruction newCondition = _graph.addConstantBool(value, _closedWorld);
user.changeUse(condition, newCondition);
});
}
@@ -758,44 +774,44 @@ class SsaInstructionSimplifier extends HBaseVisitor
}
if (type.isObject || type.treatAsDynamic) {
return graph.addConstantBool(true, closedWorld);
return _graph.addConstantBool(true, _closedWorld);
}
ResolutionInterfaceType interfaceType = type;
ClassEntity element = interfaceType.element;
HInstruction expression = node.expression;
if (expression.isInteger(closedWorld)) {
if (expression.isInteger(_closedWorld)) {
if (element == commonElements.intClass ||
element == commonElements.numClass ||
commonElements.isNumberOrStringSupertype(element)) {
return graph.addConstantBool(true, closedWorld);
return _graph.addConstantBool(true, _closedWorld);
} else if (element == commonElements.doubleClass) {
// We let the JS semantics decide for that check. Currently
// the code we emit will always return true.
return node;
} else {
return graph.addConstantBool(false, closedWorld);
return _graph.addConstantBool(false, _closedWorld);
}
} else if (expression.isDouble(closedWorld)) {
} else if (expression.isDouble(_closedWorld)) {
if (element == commonElements.doubleClass ||
element == commonElements.numClass ||
commonElements.isNumberOrStringSupertype(element)) {
return graph.addConstantBool(true, closedWorld);
return _graph.addConstantBool(true, _closedWorld);
} else if (element == commonElements.intClass) {
// We let the JS semantics decide for that check. Currently
// the code we emit will return true for a double that can be
// represented as a 31-bit integer and for -0.0.
return node;
} else {
return graph.addConstantBool(false, closedWorld);
return _graph.addConstantBool(false, _closedWorld);
}
} else if (expression.isNumber(closedWorld)) {
} else if (expression.isNumber(_closedWorld)) {
if (element == commonElements.numClass) {
return graph.addConstantBool(true, closedWorld);
return _graph.addConstantBool(true, _closedWorld);
} else {
// We cannot just return false, because the expression may be of
// type int or double.
}
} else if (expression.canBePrimitiveNumber(closedWorld) &&
} else if (expression.canBePrimitiveNumber(_closedWorld) &&
element == commonElements.intClass) {
// We let the JS semantics decide for that check.
return node;
@@ -805,14 +821,14 @@ class SsaInstructionSimplifier extends HBaseVisitor
// raw type.
} else if (!RuntimeTypesSubstitutions.hasTypeArguments(type)) {
TypeMask expressionMask = expression.instructionType;
assert(TypeMask.assertIsNormalized(expressionMask, closedWorld));
assert(TypeMask.assertIsNormalized(expressionMask, _closedWorld));
TypeMask typeMask = (element == commonElements.nullClass)
? new TypeMask.subtype(element, closedWorld)
: new TypeMask.nonNullSubtype(element, closedWorld);
if (expressionMask.union(typeMask, closedWorld) == typeMask) {
return graph.addConstantBool(true, closedWorld);
} else if (expressionMask.isDisjoint(typeMask, closedWorld)) {
return graph.addConstantBool(false, closedWorld);
? new TypeMask.subtype(element, _closedWorld)
: new TypeMask.nonNullSubtype(element, _closedWorld);
if (expressionMask.union(typeMask, _closedWorld) == typeMask) {
return _graph.addConstantBool(true, _closedWorld);
} else if (expressionMask.isDisjoint(typeMask, _closedWorld)) {
return _graph.addConstantBool(false, _closedWorld);
}
}
return node;
@@ -856,10 +872,10 @@ class SsaInstructionSimplifier extends HBaseVisitor
}
HInstruction removeIfCheckAlwaysSucceeds(HCheck node, TypeMask checkedType) {
if (checkedType.containsAll(closedWorld)) return node;
if (checkedType.containsAll(_closedWorld)) return node;
HInstruction input = node.checkedInput;
TypeMask inputType = input.instructionType;
return inputType.isInMask(checkedType, closedWorld) ? input : node;
return inputType.isInMask(checkedType, _closedWorld) ? input : node;
}
HInstruction removeCheck(HCheck node) => node.checkedInput;
@@ -867,7 +883,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
FieldEntity findConcreteFieldForDynamicAccess(
HInstruction receiver, Selector selector) {
TypeMask receiverType = receiver.instructionType;
return closedWorld.locateSingleField(selector, receiverType);
return _closedWorld.locateSingleField(selector, receiverType);
}
HInstruction visitFieldGet(HFieldGet node) {
@@ -883,7 +899,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
Map<FieldEntity, ConstantValue> fields = constructedConstant.fields;
ConstantValue value = fields[node.element];
if (value != null) {
return graph.addConstant(value, closedWorld);
return _graph.addConstant(value, _closedWorld);
}
}
}
@@ -893,20 +909,21 @@ class SsaInstructionSimplifier extends HBaseVisitor
HInstruction visitGetLength(HGetLength node) {
var receiver = node.receiver;
if (graph.allocatedFixedLists.contains(receiver)) {
if (_graph.allocatedFixedLists.contains(receiver)) {
// TODO(ngeoffray): checking if the second input is an integer
// 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(closedWorld)) {
if (receiver.inputs[0].isInteger(_closedWorld)) {
return receiver.inputs[0];
}
} else if (receiver.isConstantList() || receiver.isConstantString()) {
return graph.addConstantInt(receiver.constant.length, closedWorld);
return _graph.addConstantInt(receiver.constant.length, _closedWorld);
} else {
var type = receiver.instructionType;
if (type.isContainer && type.length != null) {
HInstruction constant = graph.addConstantInt(type.length, closedWorld);
HInstruction constant =
_graph.addConstantInt(type.length, _closedWorld);
if (type.isNullable) {
// If the container can be null, we update all uses of the length
// access to use the constant instead, but keep the length access in
@@ -920,7 +937,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
}
if (node.isAssignable &&
isFixedLength(receiver.instructionType, closedWorld)) {
isFixedLength(receiver.instructionType, _closedWorld)) {
// The input type has changed to fixed-length so change to an unassignable
// HGetLength to allow more GVN optimizations.
return new HGetLength(receiver, node.instructionType,
@@ -936,7 +953,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
instruction = node.index;
int index = instruction.constant.primitiveValue;
if (index >= 0 && index < entries.length) {
return graph.addConstant(entries[index], closedWorld);
return _graph.addConstant(entries[index], _closedWorld);
}
}
return node;
@@ -948,13 +965,13 @@ class SsaInstructionSimplifier extends HBaseVisitor
HInstruction folded = handleInterceptedCall(node);
if (folded != node) return folded;
}
HInstruction receiver = node.getDartReceiver(closedWorld);
HInstruction receiver = node.getDartReceiver(_closedWorld);
FieldEntity field =
findConcreteFieldForDynamicAccess(receiver, node.selector);
if (field != null) return directFieldGet(receiver, field);
if (node.element == null) {
MemberEntity element = closedWorld.locateSingleElement(
MemberEntity element = _closedWorld.locateSingleElement(
node.selector, receiver.instructionType);
if (element != null && element.name == node.selector.name) {
node.element = element;
@@ -970,15 +987,15 @@ class SsaInstructionSimplifier extends HBaseVisitor
}
HInstruction directFieldGet(HInstruction receiver, FieldEntity field) {
bool isAssignable = !closedWorld.fieldNeverChanges(field);
bool isAssignable = !_closedWorld.fieldNeverChanges(field);
TypeMask type;
if (backend.nativeData.isNativeClass(field.enclosingClass)) {
if (_nativeData.isNativeClass(field.enclosingClass)) {
type = TypeMaskFactory.fromNativeBehavior(
backend.nativeData.getNativeFieldLoadBehavior(field), closedWorld);
_nativeData.getNativeFieldLoadBehavior(field), _closedWorld);
} else {
type = TypeMaskFactory.inferredTypeForElement(
field as Entity, globalInferenceResults);
field as Entity, _globalInferenceResults);
}
return new HFieldGet(field, receiver, type, isAssignable: isAssignable);
@@ -990,14 +1007,14 @@ class SsaInstructionSimplifier extends HBaseVisitor
if (folded != node) return folded;
}
HInstruction receiver = node.getDartReceiver(closedWorld);
HInstruction receiver = node.getDartReceiver(_closedWorld);
FieldElement field =
findConcreteFieldForDynamicAccess(receiver, node.selector);
if (field == null || !field.isAssignable) return node;
// Use `node.inputs.last` in case the call follows the interceptor calling
// convention, but is not a call on an interceptor.
HInstruction value = node.inputs.last;
if (compiler.options.enableTypeAssertions) {
if (_options.enableTypeAssertions) {
ResolutionDartType type = field.type;
if (!type.treatAsRaw ||
type.isTypeVariable ||
@@ -1009,7 +1026,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
return node;
}
HInstruction other = value.convertType(
closedWorld, type, HTypeConversion.CHECKED_MODE_CHECK);
_closedWorld, type, HTypeConversion.CHECKED_MODE_CHECK);
if (other != value) {
node.block.addBefore(node, other);
value = other;
@@ -1022,13 +1039,13 @@ class SsaInstructionSimplifier extends HBaseVisitor
propagateConstantValueToUses(node);
MemberEntity element = node.element;
if (element == compiler.commonElements.identicalFunction) {
if (element == commonElements.identicalFunction) {
if (node.inputs.length == 2) {
return new HIdentity(node.inputs[0], node.inputs[1], null,
closedWorld.commonMasks.boolType)
_closedWorld.commonMasks.boolType)
..sourceInformation = node.sourceInformation;
}
} else if (element == backend.helpers.checkConcurrentModificationError) {
} else if (element == _helpers.checkConcurrentModificationError) {
if (node.inputs.length == 2) {
HInstruction firstArgument = node.inputs[0];
if (firstArgument is HConstant) {
@@ -1036,20 +1053,20 @@ class SsaInstructionSimplifier extends HBaseVisitor
if (constant.constant.isTrue) return constant;
}
}
} else if (element == backend.helpers.checkInt) {
} else if (element == _helpers.checkInt) {
if (node.inputs.length == 1) {
HInstruction argument = node.inputs[0];
if (argument.isInteger(closedWorld)) return argument;
if (argument.isInteger(_closedWorld)) return argument;
}
} else if (element == backend.helpers.checkNum) {
} else if (element == _helpers.checkNum) {
if (node.inputs.length == 1) {
HInstruction argument = node.inputs[0];
if (argument.isNumber(closedWorld)) return argument;
if (argument.isNumber(_closedWorld)) return argument;
}
} else if (element == backend.helpers.checkString) {
} else if (element == _helpers.checkString) {
if (node.inputs.length == 1) {
HInstruction argument = node.inputs[0];
if (argument.isString(closedWorld)) return argument;
if (argument.isString(_closedWorld)) return argument;
}
}
return node;
@@ -1094,18 +1111,18 @@ class SsaInstructionSimplifier extends HBaseVisitor
if (node.usedBy.length > 1) return node;
}
HInstruction folded = graph.addConstant(
HInstruction folded = _graph.addConstant(
constantSystem.createString(new ast.DartString.concat(
leftString.primitiveValue, rightString.primitiveValue)),
closedWorld);
_closedWorld);
if (prefix == null) return folded;
return new HStringConcat(
prefix, folded, closedWorld.commonMasks.stringType);
prefix, folded, _closedWorld.commonMasks.stringType);
}
HInstruction visitStringify(HStringify node) {
HInstruction input = node.inputs[0];
if (input.isString(closedWorld)) return input;
if (input.isString(_closedWorld)) return input;
HInstruction tryConstant() {
if (!input.isConstant()) return null;
@@ -1120,8 +1137,8 @@ class SsaInstructionSimplifier extends HBaseVisitor
if (!intConstant.isUInt32()) return null;
}
PrimitiveConstantValue primitive = constant.constant;
return graph.addConstant(
constantSystem.createString(primitive.toDartString()), closedWorld);
return _graph.addConstant(
constantSystem.createString(primitive.toDartString()), _closedWorld);
}
HInstruction tryToString() {
@@ -1129,16 +1146,17 @@ 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(closedWorld)) return null;
if (input.canBePrimitive(_closedWorld)) return null;
if (input.canBeNull()) return null;
Selector selector = Selectors.toString_;
TypeMask toStringType = TypeMaskFactory.inferredTypeForSelector(
selector, input.instructionType, globalInferenceResults);
if (!toStringType.containsOnlyString(closedWorld)) return null;
selector, input.instructionType, _globalInferenceResults);
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.
if (new TypeMask.nonNullSubclass(helpers.jsInterceptorClass, closedWorld)
.isDisjoint(input.instructionType, closedWorld)) {
if (new TypeMask.nonNullSubclass(
_helpers.jsInterceptorClass, _closedWorld)
.isDisjoint(input.instructionType, _closedWorld)) {
var inputs = <HInstruction>[input, input]; // [interceptor, receiver].
HInstruction result = new HInvokeDynamicMethod(
selector,
@@ -1158,10 +1176,10 @@ class SsaInstructionSimplifier extends HBaseVisitor
}
bool needsSubstitutionForTypeVariableAccess(ClassEntity cls) {
if (closedWorld.isUsedAsMixin(cls)) return true;
if (_closedWorld.isUsedAsMixin(cls)) return true;
return closedWorld.anyStrictSubclassOf(cls, (ClassEntity subclass) {
return !backend.rtiSubstitutions.isTrivialSubstitution(subclass, cls);
return _closedWorld.anyStrictSubclassOf(cls, (ClassEntity subclass) {
return !_rtiSubstitutions.isTrivialSubstitution(subclass, cls);
});
}
@@ -1210,7 +1228,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
}
if (source == null) return null;
return new HTypeInfoReadRaw(source, closedWorld.commonMasks.dynamicType);
return new HTypeInfoReadRaw(source, _closedWorld.commonMasks.dynamicType);
}
// TODO(sra): Consider fusing type expression trees with no type variables,
@@ -1233,7 +1251,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
TypeInfoExpressionKind.COMPLETE,
typeArgument,
const <HInstruction>[],
closedWorld.commonMasks.dynamicType);
_closedWorld.commonMasks.dynamicType);
return replacement;
}
return node;
@@ -1263,7 +1281,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
TypeInfoExpressionKind.COMPLETE,
type,
arguments,
closedWorld.commonMasks.dynamicType);
_closedWorld.commonMasks.dynamicType);
return replacement;
}
@@ -1296,7 +1314,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
// become dead. This breaks the algorithm for generating the per-type
// runtime type information, so we instantiate them here in case the
// HCreate becomes dead.
object.instantiatedTypes?.forEach(registry.registerInstantiation);
object.instantiatedTypes?.forEach(_registry.registerInstantiation);
}
if (object.hasRtiInput) {
@@ -1314,7 +1332,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
return finishSubstituted(
object.element,
// If there are type arguments, all type arguments are 'dynamic'.
(int i) => graph.addConstantNull(closedWorld));
(int i) => _graph.addConstantNull(_closedWorld));
}
}
@@ -1329,15 +1347,13 @@ class SsaInstructionSimplifier extends HBaseVisitor
class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase {
final Set<HInstruction> boundsChecked;
final bool trustPrimitives;
final JavaScriptBackend backend;
final BackendHelpers _helpers;
final ClosedWorld closedWorld;
final String name = "SsaCheckInserter";
HGraph graph;
SsaCheckInserter(
this.trustPrimitives, this.backend, this.closedWorld, this.boundsChecked);
BackendHelpers get helpers => backend.helpers;
SsaCheckInserter(this.trustPrimitives, this._helpers, this.closedWorld,
this.boundsChecked);
void visitGraph(HGraph graph) {
this.graph = graph;
@@ -1400,7 +1416,7 @@ class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase {
void visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
MemberEntity element = node.element;
if (node.isInterceptedCall) return;
if (element != helpers.jsArrayRemoveLast) return;
if (element != _helpers.jsArrayRemoveLast) return;
if (boundsChecked.contains(node)) return;
// `0` is the index we want to check, but we want to report `-1`, as if we
// executed `a[a.length-1]`
@@ -2258,7 +2274,7 @@ class SsaTypeConversionInserter extends HBaseVisitor
* location.
*/
class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase {
final JavaScriptBackend backend;
final BackendHelpers _helpers;
final Compiler compiler;
final ClosedWorld closedWorld;
final String name = "SsaLoadElimination";
@@ -2266,7 +2282,7 @@ class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase {
List<MemorySet> memories;
bool newGvnCandidates = false;
SsaLoadElimination(this.backend, this.compiler, this.closedWorld);
SsaLoadElimination(this._helpers, this.compiler, this.closedWorld);
void visitGraph(HGraph graph) {
memories = new List<MemorySet>(graph.blocks.length);
@@ -2335,8 +2351,8 @@ class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase {
}
void visitGetLength(HGetLength instruction) {
_visitFieldGet(backend.helpers.jsIndexableLength,
instruction.receiver.nonCheck(), instruction);
_visitFieldGet(_helpers.jsIndexableLength, instruction.receiver.nonCheck(),
instruction);
}
void _visitFieldGet(
@@ -2,9 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import '../compiler.dart' show Compiler;
import '../elements/entities.dart';
import '../js_backend/js_backend.dart';
import '../js_backend/backend_helpers.dart';
import '../options.dart';
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
import '../world.dart' show ClosedWorld;
@@ -17,12 +17,13 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
final Map<HInstruction, Function> pendingOptimizations =
new Map<HInstruction, Function>();
final Compiler compiler;
final GlobalTypeInferenceResults results;
final CompilerOptions options;
final BackendHelpers helpers;
final ClosedWorld closedWorld;
JavaScriptBackend get backend => compiler.backend;
String get name => 'type propagator';
SsaTypePropagator(this.compiler, this.closedWorld);
SsaTypePropagator(this.results, this.options, this.helpers, this.closedWorld);
TypeMask computeType(HInstruction instruction) {
return instruction.accept(this);
@@ -284,7 +285,7 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
TypeMask type = new TypeMask.nonNullSubclass(cls, closedWorld);
// TODO(ngeoffray): We currently only optimize on primitive
// types.
if (!type.satisfies(backend.helpers.jsIndexableClass, closedWorld) &&
if (!type.satisfies(helpers.jsIndexableClass, closedWorld) &&
!type.containsOnlyNum(closedWorld) &&
!type.containsOnlyBool(closedWorld)) {
return false;
@@ -304,7 +305,7 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
// Return true if the argument type check was added.
bool checkArgument(HInvokeDynamic instruction) {
// We want the right error in checked mode.
if (compiler.options.enableTypeAssertions) return false;
if (options.enableTypeAssertions) return false;
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
@@ -412,7 +413,7 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
}
}
return instruction.specializer
.computeTypeFromInputTypes(instruction, compiler, closedWorld);
return instruction.specializer.computeTypeFromInputTypes(
instruction, results, options, helpers, closedWorld);
}
}
@@ -187,7 +187,6 @@ class LiveEnvironment {
* instruction, and computes the liveIns of each basic block.
*/
class SsaLiveIntervalBuilder extends HBaseVisitor {
final Compiler compiler;
final Set<HInstruction> generateAtUseSite;
final Set<HInstruction> controlFlowOperators;
@@ -209,17 +208,15 @@ class SsaLiveIntervalBuilder extends HBaseVisitor {
*/
final Map<HInstruction, LiveInterval> liveIntervals;
SsaLiveIntervalBuilder(
this.compiler, this.generateAtUseSite, this.controlFlowOperators)
SsaLiveIntervalBuilder(this.generateAtUseSite, this.controlFlowOperators)
: liveInstructions = new Map<HBasicBlock, LiveEnvironment>(),
liveIntervals = new Map<HInstruction, LiveInterval>();
DiagnosticReporter get reporter => compiler.reporter;
void visitGraph(HGraph graph) {
visitPostDominatorTree(graph);
if (!liveInstructions[graph.entry].isEmpty) {
reporter.internalError(CURRENT_ELEMENT_SPANNABLE, 'LiveIntervalBuilder.');
throw new SpannableAssertionFailure(
CURRENT_ELEMENT_SPANNABLE, 'LiveIntervalBuilder.');
}
}
@@ -495,13 +492,13 @@ class VariableNames {
*/
class VariableNamer {
final VariableNames names;
final Compiler compiler;
final Namer _namer;
final Set<String> usedNames;
final List<String> freeTemporaryNames;
int temporaryIndex = 0;
static final RegExp regexp = new RegExp('t[0-9]+');
VariableNamer(LiveEnvironment environment, this.names, this.compiler)
VariableNamer(LiveEnvironment environment, this.names, this._namer)
: usedNames = new Set<String>(),
freeTemporaryNames = new List<String>() {
// [VariableNames.swapTemp] is used when there is a cycle in a copy handler.
@@ -521,10 +518,9 @@ class VariableNamer {
String allocateWithHint(String originalName) {
int i = 0;
JavaScriptBackend backend = compiler.backend;
String name = backend.namer.safeVariableName(originalName);
String name = _namer.safeVariableName(originalName);
while (usedNames.contains(name)) {
name = backend.namer.safeVariableName('$originalName${i++}');
name = _namer.safeVariableName('$originalName${i++}');
}
return name;
}
@@ -615,14 +611,14 @@ class VariableNamer {
* it adds a copy to the CopyHandler of the corresponding predecessor.
*/
class SsaVariableAllocator extends HBaseVisitor {
final Compiler compiler;
final Namer _namer;
final Map<HBasicBlock, LiveEnvironment> liveInstructions;
final Map<HInstruction, LiveInterval> liveIntervals;
final Set<HInstruction> generateAtUseSite;
final VariableNames names;
SsaVariableAllocator(this.compiler, this.liveInstructions, this.liveIntervals,
SsaVariableAllocator(this._namer, this.liveInstructions, this.liveIntervals,
this.generateAtUseSite)
: this.names = new VariableNames();
@@ -631,15 +627,15 @@ class SsaVariableAllocator extends HBaseVisitor {
}
void visitBasicBlock(HBasicBlock block) {
VariableNamer namer =
new VariableNamer(liveInstructions[block], names, compiler);
VariableNamer variableNamer =
new VariableNamer(liveInstructions[block], names, _namer);
block.forEachPhi((HPhi phi) {
handlePhi(phi, namer);
handlePhi(phi, variableNamer);
});
block.forEachInstruction((HInstruction instruction) {
handleInstruction(instruction, namer);
handleInstruction(instruction, variableNamer);
});
}