Chromium Code Reviews| 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 7ae47a5c134e79a5ad369d2a07259bf3dd9c03d7..c4f557c6953335465dca51320101f809776d0cee 100644 |
| --- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
| +++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
| @@ -5,12 +5,11 @@ |
| 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 LiteralDartString; |
| +import '../tree/tree.dart' show DartString, ConsDartString, LiteralDartString; |
| import 'cps_ir_nodes.dart'; |
| import '../types/types.dart' show TypeMask, TypesTask; |
| import '../types/constants.dart' show computeTypeMask; |
| @@ -457,9 +456,7 @@ class TransformingVisitor extends RecursiveVisitor { |
| /// Make a constant primitive for [constant] and set its entry in [values]. |
| Constant makeConstantPrimitive(ConstantValue constant) { |
| - ConstantExpression constExp = |
| - const ConstantExpressionCreator().convert(constant); |
| - Constant primitive = new Constant(constExp, constant); |
| + Constant primitive = new Constant(constant); |
| values[primitive] = new AbstractValue.constantValue(constant, |
| typeSystem.getTypeOf(constant)); |
| return primitive; |
| @@ -628,6 +625,11 @@ class TransformingVisitor extends RecursiveVisitor { |
| return replaceWithBinary(operator, leftArg, rightArg); |
| } |
| } |
| + else if (lattice.isDefinitelyString(left, allowNull: false) && |
| + lattice.isDefinitelyString(right, allowNull: false)) { |
| + return replaceWithBinary(BuiltinOperator.StringConcat, |
| + leftArg, rightArg); |
| + } |
| } |
| } |
| // We should only get here if the node was not specialized. |
| @@ -645,12 +647,6 @@ 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; |
| @@ -678,6 +674,24 @@ class TransformingVisitor extends RecursiveVisitor { |
| super.visitTypeCast(node); |
| } |
| + void visitInvokeStatic(InvokeStatic node) { |
| + Continuation cont = node.continuation.definition; |
| + Primitive arg(int n) => node.arguments[n].definition; |
|
karlklose
2015/06/19 08:33:45
Could you inline the two helpers?
asgerf
2015/06/19 11:04:34
We're going to need them anyway.
Why I am doing t
|
| + AbstractValue argType(int n) => getValue(arg(n)); |
| + if (node.target.library.isInternalLibrary) { |
|
karlklose
2015/06/19 08:33:45
Change to one conditional?
if (node.target.libra
asgerf
2015/06/19 11:04:34
See previous reply.
|
| + switch(node.target.name) { |
| + case InternalMethod.Stringify: |
| + if (lattice.isDefinitelyString(argType(0))) { |
| + InvokeContinuation invoke = |
| + new InvokeContinuation(cont, <Primitive>[arg(0)]); |
|
Kevin Millikin (Google)
2015/06/19 11:36:13
I wonder if we can come up with a convenient and s
asgerf
2015/06/19 12:00:52
Yeah I don't like it either. I tried adding constr
|
| + replaceSubtree(node, invoke); |
| + visitInvokeContinuation(invoke); |
| + } |
| + break; |
| + } |
| + } |
| + } |
| + |
| AbstractValue getValue(Primitive primitive) { |
| AbstractValue value = values[primitive]; |
| return value == null ? new AbstractValue.nothing() : value; |
| @@ -696,6 +710,63 @@ 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) { |
| + switch (node.operator) { |
| + case BuiltinOperator.StringConcat: |
|
karlklose
2015/06/19 08:33:45
Use if instead?
asgerf
2015/06/19 11:04:34
Same as previous reply.
|
| + // 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 getString(AbstractValue value) { |
|
karlklose
2015/06/19 08:33:45
Consider moving this helper to the top of the meth
asgerf
2015/06/19 11:04:34
Done.
|
| + return (value.constant as StringConstantValue).primitiveValue; |
| + } |
| + 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); |
| @@ -732,6 +803,10 @@ 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; |
| @@ -904,10 +979,22 @@ class TypePropagationVisitor implements Visitor { |
| assert(cont.parameters.length == 1); |
| Parameter returnValue = cont.parameters[0]; |
| - Entity target = node.target; |
| - TypeMask returnType = target is FieldElement |
| - ? typeSystem.dynamicType |
| - : typeSystem.getReturnType(node.target); |
| + |
| + if (node.target.library.isInternalLibrary) { |
| + switch (node.target.name) { |
|
karlklose
2015/06/19 08:33:45
Use if?
asgerf
2015/06/19 11:04:34
See previous reply.
|
| + 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); |
| setValue(returnValue, nonConstant(returnType)); |
| } |
| @@ -981,8 +1068,34 @@ class TypePropagationVisitor implements Visitor { |
| } |
| void visitApplyBuiltinOperator(ApplyBuiltinOperator node) { |
| - // Not actually reachable yet. |
| - // TODO(asgerf): Implement type propagation for builtin operators. |
| + // Note that most built-in operators do not exist before the transformation |
| + // pass after this analysis has finished. |
| + switch (node.operator) { |
| + case BuiltinOperator.StringConcat: |
|
karlklose
2015/06/19 08:33:45
Use if?
asgerf
2015/06/19 11:04:34
Same.
|
| + 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: |
| + } |
| setValue(node, nonConstant()); |
| } |
| @@ -1005,50 +1118,6 @@ 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) { |
| } |
| @@ -1367,76 +1436,7 @@ class AbstractValue { |
| } |
| } |
| -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"); |
| - } |
| -} |
| +/// Enum-like class with the names of internal methods we care about. |
| +abstract class InternalMethod { |
| + static const String Stringify = 'S'; |
|
karlklose
2015/06/19 08:33:45
Make this a predicate to test on the element inste
asgerf
2015/06/19 11:04:34
Are you proposing this?
isStringify(FunctionEleme
|
| +} |