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:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user