Index: pkg/compiler/lib/src/cps_ir/type_propagation.dart |
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
index d9e4d47c5de469edda65af9fb48d50645424679b..e5368785336f0b9d4f4bfec139a25e5630dff29f 100644 |
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
@@ -5,11 +5,12 @@ |
import 'optimizers.dart' show Pass, ParentVisitor; |
import '../constants/constant_system.dart'; |
+import '../constants/expressions.dart'; |
import '../resolution/operators.dart'; |
import '../constants/values.dart'; |
import '../dart_types.dart' as types; |
import '../dart2jslib.dart' as dart2js; |
-import '../tree/tree.dart' show DartString, ConsDartString, LiteralDartString; |
+import '../tree/tree.dart' show LiteralDartString; |
import 'cps_ir_nodes.dart'; |
import '../types/types.dart'; |
import '../types/constants.dart' show computeTypeMask; |
@@ -466,7 +467,9 @@ class TransformingVisitor extends RecursiveVisitor { |
/// Make a constant primitive for [constant] and set its entry in [values]. |
Constant makeConstantPrimitive(ConstantValue constant) { |
- Constant primitive = new Constant(constant); |
+ ConstantExpression constExp = |
+ const ConstantExpressionCreator().convert(constant); |
+ Constant primitive = new Constant(constExp, constant); |
values[primitive] = new AbstractValue.constantValue(constant, |
typeSystem.getTypeOf(constant)); |
return primitive; |
@@ -635,11 +638,6 @@ class TransformingVisitor extends RecursiveVisitor { |
return replaceWithBinary(operator, leftArg, rightArg); |
} |
} |
- else if (lattice.isDefinitelyString(left, allowNull: false) && |
- lattice.isDefinitelyString(right, allowNull: false)) { |
- return replaceWithBinary(BuiltinOperator.StringConcatenate, |
- leftArg, rightArg); |
- } |
} |
} |
// We should only get here if the node was not specialized. |
@@ -714,6 +712,12 @@ class TransformingVisitor extends RecursiveVisitor { |
super.visitInvokeMethod(node); |
} |
+ void visitConcatenateStrings(ConcatenateStrings node) { |
+ Continuation cont = node.continuation.definition; |
+ if (constifyExpression(node, cont)) return; |
+ super.visitConcatenateStrings(node); |
+ } |
+ |
void visitTypeCast(TypeCast node) { |
Continuation cont = node.continuation.definition; |
@@ -741,27 +745,6 @@ class TransformingVisitor extends RecursiveVisitor { |
super.visitTypeCast(node); |
} |
- void visitInvokeStatic(InvokeStatic node) { |
- // Specialize calls to static methods. |
- // TODO(asgerf): This is written to easily scale to more cases, |
- // either add more cases or clean up. |
- Continuation cont = node.continuation.definition; |
- Primitive arg(int n) => node.arguments[n].definition; |
- AbstractValue argType(int n) => getValue(arg(n)); |
- if (node.target.library.isInternalLibrary) { |
- switch(node.target.name) { |
- case InternalMethod.Stringify: |
- if (lattice.isDefinitelyString(argType(0))) { |
- InvokeContinuation invoke = |
- new InvokeContinuation(cont, <Primitive>[arg(0)]); |
- replaceSubtree(node, invoke); |
- visitInvokeContinuation(invoke); |
- } |
- break; |
- } |
- } |
- } |
- |
AbstractValue getValue(Primitive primitive) { |
AbstractValue value = values[primitive]; |
return value == null ? new AbstractValue.nothing() : value; |
@@ -780,64 +763,6 @@ class TransformingVisitor extends RecursiveVisitor { |
} |
} |
- void insertLetPrim(Expression node, Primitive prim) { |
- InteriorNode parent = node.parent; |
- LetPrim let = new LetPrim(prim); |
- parent.body = let; |
- let.body = node; |
- node.parent = let; |
- let.parent = parent; |
- } |
- |
- void visitApplyBuiltinOperator(ApplyBuiltinOperator node) { |
- DartString getString(AbstractValue value) { |
- StringConstantValue constant = value.constant; |
- return constant.primitiveValue; |
- } |
- switch (node.operator) { |
- case BuiltinOperator.StringConcatenate: |
- // Concatenate consecutive constants. |
- bool argumentsWereRemoved = false; |
- int i = 0; |
- while (i < node.arguments.length - 1) { |
- int startOfSequence = i; |
- AbstractValue firstValue = getValue(node.arguments[i++].definition); |
- if (!firstValue.isConstant) continue; |
- AbstractValue secondValue = getValue(node.arguments[i++].definition); |
- if (!secondValue.isConstant) continue; |
- |
- DartString string = |
- new ConsDartString(getString(firstValue), getString(secondValue)); |
- |
- // We found a sequence of at least two constants. |
- // Look for the end of the sequence. |
- while (i < node.arguments.length) { |
- AbstractValue value = getValue(node.arguments[i].definition); |
- if (!value.isConstant) break; |
- string = new ConsDartString(string, getString(value)); |
- ++i; |
- } |
- Constant prim = |
- makeConstantPrimitive(new StringConstantValue(string)); |
- insertLetPrim(node.parent, prim); |
- for (int k = startOfSequence; k < i; ++k) { |
- node.arguments[k].unlink(); |
- node.arguments[k] = null; // Remove the argument after the loop. |
- } |
- node.arguments[startOfSequence] = new Reference<Primitive>(prim); |
- argumentsWereRemoved = true; |
- } |
- if (argumentsWereRemoved) { |
- node.arguments.removeWhere((ref) => ref == null); |
- } |
- // TODO(asgerf): Rebalance nested StringConcats that arise from |
- // rewriting the + operator to StringConcat. |
- break; |
- |
- default: |
- } |
- } |
- |
Primitive visitTypeTest(TypeTest node) { |
Primitive prim = node.value.definition; |
AbstractValue value = getValue(prim); |
@@ -878,10 +803,6 @@ class TransformingVisitor extends RecursiveVisitor { |
} else { |
Primitive newPrim = visit(node.primitive); |
if (newPrim != null) { |
- if (!values.containsKey(newPrim)) { |
- // If the type was not set, default to the same type as before. |
- values[newPrim] = values[node.primitive]; |
- } |
newPrim.substituteFor(node.primitive); |
RemovalVisitor.remove(node.primitive); |
node.primitive = newPrim; |
@@ -1054,22 +975,10 @@ class TypePropagationVisitor implements Visitor { |
assert(cont.parameters.length == 1); |
Parameter returnValue = cont.parameters[0]; |
- |
- if (node.target.library.isInternalLibrary) { |
- switch (node.target.name) { |
- case InternalMethod.Stringify: |
- AbstractValue argValue = getValue(node.arguments[0].definition); |
- if (argValue.isNothing) return; // And come back later. |
- if (lattice.isDefinitelyString(argValue)) { |
- setValue(returnValue, argValue); |
- } else { |
- setValue(returnValue, nonConstant(typeSystem.stringType)); |
- } |
- return; |
- } |
- } |
- |
- TypeMask returnType = typeSystem.getReturnType(node.target); |
+ Entity target = node.target; |
+ TypeMask returnType = target is FieldElement |
+ ? typeSystem.dynamicType |
+ : typeSystem.getReturnType(node.target); |
setValue(returnValue, nonConstant(returnType)); |
} |
@@ -1143,34 +1052,8 @@ class TypePropagationVisitor implements Visitor { |
} |
void visitApplyBuiltinOperator(ApplyBuiltinOperator node) { |
- // Note that most built-in operators do not exist before the transformation |
- // pass after this analysis has finished. |
- switch (node.operator) { |
- case BuiltinOperator.StringConcatenate: |
- DartString stringValue = const LiteralDartString(''); |
- for (Reference<Primitive> arg in node.arguments) { |
- AbstractValue value = getValue(arg.definition); |
- if (value.isNothing) { |
- return; // And come back later |
- } else if (value.isConstant && |
- value.constant.isString && |
- stringValue != null) { |
- StringConstantValue constant = value.constant; |
- stringValue = |
- new ConsDartString(stringValue, constant.primitiveValue); |
- } else { |
- stringValue = null; |
- break; |
- } |
- } |
- if (stringValue == null) { |
- setValue(node, nonConstant(typeSystem.stringType)); |
- } else { |
- setValue(node, constantValue(new StringConstantValue(stringValue))); |
- } |
- break; |
- default: |
- } |
+ // Not actually reachable yet. |
+ // TODO(asgerf): Implement type propagation for builtin operators. |
setValue(node, nonConstant()); |
} |
@@ -1193,6 +1076,50 @@ class TypePropagationVisitor implements Visitor { |
setValue(returnValue, nonConstant(typeSystem.getReturnType(node.target))); |
} |
+ void visitConcatenateStrings(ConcatenateStrings node) { |
+ Continuation cont = node.continuation.definition; |
+ setReachable(cont); |
+ |
+ /// Sets the value of the target continuation parameter, and possibly |
+ /// try to replace the whole invocation with a constant. |
+ void setResult(AbstractValue updateValue, {bool canReplace: false}) { |
+ Parameter returnValue = cont.parameters[0]; |
+ setValue(returnValue, updateValue); |
+ if (canReplace && updateValue.isConstant) { |
+ replacements[node] = updateValue.constant; |
+ } else { |
+ // A previous iteration might have tried to replace this. |
+ replacements.remove(node); |
+ } |
+ } |
+ |
+ // TODO(jgruber): Currently we only optimize if all arguments are string |
+ // constants, but we could also handle cases such as "foo${42}". |
+ bool allStringConstants = node.arguments.every((Reference ref) { |
+ if (!(ref.definition is Constant)) { |
+ return false; |
+ } |
+ Constant constant = ref.definition; |
+ return constant != null && constant.value.isString; |
+ }); |
+ |
+ TypeMask type = typeSystem.stringType; |
+ assert(cont.parameters.length == 1); |
+ if (allStringConstants) { |
+ // All constant, we can concatenate ourselves. |
+ Iterable<String> allStrings = node.arguments.map((Reference ref) { |
+ Constant constant = ref.definition; |
+ StringConstantValue stringConstant = constant.value; |
+ return stringConstant.primitiveValue.slowToString(); |
+ }); |
+ LiteralDartString dartString = new LiteralDartString(allStrings.join()); |
+ ConstantValue constant = new StringConstantValue(dartString); |
+ setResult(constantValue(constant, type), canReplace: true); |
+ } else { |
+ setResult(nonConstant(type)); |
+ } |
+ } |
+ |
void visitThrow(Throw node) { |
} |
@@ -1523,7 +1450,76 @@ class AbstractValue { |
} |
} |
-/// Enum-like class with the names of internal methods we care about. |
-abstract class InternalMethod { |
- static const String Stringify = 'S'; |
-} |
+class ConstantExpressionCreator |
+ implements ConstantValueVisitor<ConstantExpression, dynamic> { |
+ |
+ const ConstantExpressionCreator(); |
+ |
+ ConstantExpression convert(ConstantValue value) => value.accept(this, null); |
+ |
+ @override |
+ ConstantExpression visitBool(BoolConstantValue constant, _) { |
+ return new BoolConstantExpression(constant.primitiveValue); |
+ } |
+ |
+ @override |
+ ConstantExpression visitConstructed(ConstructedConstantValue constant, arg) { |
+ throw new UnsupportedError("ConstantExpressionCreator.visitConstructed"); |
+ } |
+ |
+ @override |
+ ConstantExpression visitDeferred(DeferredConstantValue constant, arg) { |
+ throw new UnsupportedError("ConstantExpressionCreator.visitDeferred"); |
+ } |
+ |
+ @override |
+ ConstantExpression visitDouble(DoubleConstantValue constant, arg) { |
+ return new DoubleConstantExpression(constant.primitiveValue); |
+ } |
+ |
+ @override |
+ ConstantExpression visitSynthetic(SyntheticConstantValue constant, arg) { |
+ throw new UnsupportedError("ConstantExpressionCreator.visitSynthetic"); |
+ } |
+ |
+ @override |
+ ConstantExpression visitFunction(FunctionConstantValue constant, arg) { |
+ throw new UnsupportedError("ConstantExpressionCreator.visitFunction"); |
+ } |
+ |
+ @override |
+ ConstantExpression visitInt(IntConstantValue constant, arg) { |
+ return new IntConstantExpression(constant.primitiveValue); |
+ } |
+ |
+ @override |
+ ConstantExpression visitInterceptor(InterceptorConstantValue constant, arg) { |
+ throw new UnsupportedError("ConstantExpressionCreator.visitInterceptor"); |
+ } |
+ |
+ @override |
+ ConstantExpression visitList(ListConstantValue constant, arg) { |
+ throw new UnsupportedError("ConstantExpressionCreator.visitList"); |
+ } |
+ |
+ @override |
+ ConstantExpression visitMap(MapConstantValue constant, arg) { |
+ throw new UnsupportedError("ConstantExpressionCreator.visitMap"); |
+ } |
+ |
+ @override |
+ ConstantExpression visitNull(NullConstantValue constant, arg) { |
+ return new NullConstantExpression(); |
+ } |
+ |
+ @override |
+ ConstantExpression visitString(StringConstantValue constant, arg) { |
+ return new StringConstantExpression( |
+ constant.primitiveValue.slowToString()); |
+ } |
+ |
+ @override |
+ ConstantExpression visitType(TypeConstantValue constant, arg) { |
+ throw new UnsupportedError("ConstantExpressionCreator.visitType"); |
+ } |
+} |