Index: dart/compiler/java/com/google/dart/compiler/backend/js/BasicOptimizationStrategy.java |
diff --git a/dart/compiler/java/com/google/dart/compiler/backend/js/BasicOptimizationStrategy.java b/dart/compiler/java/com/google/dart/compiler/backend/js/BasicOptimizationStrategy.java |
deleted file mode 100644 |
index 9c4d50e7478c306edc09322ff31d02b5d25e2949..0000000000000000000000000000000000000000 |
--- a/dart/compiler/java/com/google/dart/compiler/backend/js/BasicOptimizationStrategy.java |
+++ /dev/null |
@@ -1,466 +0,0 @@ |
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
-// 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. |
- |
-package com.google.dart.compiler.backend.js; |
- |
-import com.google.common.collect.Sets; |
-import com.google.dart.compiler.ast.DartArrayAccess; |
-import com.google.dart.compiler.ast.DartBinaryExpression; |
-import com.google.dart.compiler.ast.DartExpression; |
-import com.google.dart.compiler.ast.DartFunction; |
-import com.google.dart.compiler.ast.DartFunctionExpression; |
-import com.google.dart.compiler.ast.DartFunctionObjectInvocation; |
-import com.google.dart.compiler.ast.DartIdentifier; |
-import com.google.dart.compiler.ast.DartInitializer; |
-import com.google.dart.compiler.ast.DartMethodDefinition; |
-import com.google.dart.compiler.ast.DartMethodInvocation; |
-import com.google.dart.compiler.ast.DartNode; |
-import com.google.dart.compiler.ast.DartNullLiteral; |
-import com.google.dart.compiler.ast.DartParameter; |
-import com.google.dart.compiler.ast.DartPropertyAccess; |
-import com.google.dart.compiler.ast.DartReturnStatement; |
-import com.google.dart.compiler.ast.DartStatement; |
-import com.google.dart.compiler.ast.DartThisExpression; |
-import com.google.dart.compiler.ast.DartUnaryExpression; |
-import com.google.dart.compiler.ast.DartUnit; |
-import com.google.dart.compiler.ast.Modifiers; |
-import com.google.dart.compiler.backend.common.TypeHeuristic; |
-import com.google.dart.compiler.backend.common.TypeHeuristic.FieldKind; |
-import com.google.dart.compiler.backend.common.TypeHeuristicImplementation; |
-import com.google.dart.compiler.parser.Token; |
-import com.google.dart.compiler.resolver.ClassElement; |
-import com.google.dart.compiler.resolver.ConstructorElement; |
-import com.google.dart.compiler.resolver.CoreTypeProvider; |
-import com.google.dart.compiler.resolver.Element; |
-import com.google.dart.compiler.resolver.ElementKind; |
-import com.google.dart.compiler.resolver.FieldElement; |
-import com.google.dart.compiler.resolver.MethodElement; |
-import com.google.dart.compiler.type.Type; |
-import com.google.dart.compiler.type.TypeKind; |
- |
-import java.util.List; |
-import java.util.Set; |
- |
-class BasicOptimizationStrategy implements OptimizationStrategy { |
- |
- private final TypeHeuristic typeHeuristic; |
- private final CoreTypeProvider typeProvider; |
- private static final String NUMBER_IMPLEMENTATION = "NumberImplementation"; |
- private static final String STRING_IMPLEMENTATION = "StringImplementation"; |
- private static final String BOOL_IMPLEMENTATION = "BoolImplementation"; |
- |
- public BasicOptimizationStrategy(DartUnit unit, CoreTypeProvider typeProvider) { |
- this.typeHeuristic = new TypeHeuristicImplementation(unit, typeProvider); |
- this.typeProvider = typeProvider; |
- } |
- |
- @Override |
- public boolean canSkipOperatorShim(DartBinaryExpression x) { |
- // If both expressions are raw js number types, we can elide the operator shim. |
- Token operator = x.getOperator(); |
- switch (operator) { |
- case SHL: |
- case SAR: |
- case BIT_AND: |
- case BIT_OR: |
- case BIT_XOR: |
- case LT: |
- case GT: |
- case LTE: |
- case GTE: |
- case ADD: |
- case SUB: |
- case MUL: |
- case DIV: { |
- return (isNumericType(x.getArg1()) && isNumericType(x.getArg2())); |
- } |
- |
- case OR: |
- case AND: { |
- return ((isNumericType(x.getArg1()) && isNumericType(x.getArg2())) |
- || (isBooleanType(x.getArg1()) && isBooleanType(x.getArg2()))); |
- } |
- |
- case NE: |
- case EQ: { |
- DartExpression lhs = x.getArg1(); |
- DartExpression rhs = x.getArg2(); |
- return ((isNumericType(lhs) && (isNumericType(rhs) || isNullLiteral(rhs))) |
- || (isStringType(lhs) && (isStringType(rhs) || isNullLiteral(rhs))) |
- || (isBooleanType(lhs) && (isBooleanType(rhs) || isNullLiteral(rhs))) |
- || isNullLiteral(lhs) |
- || hasSingleImplementation(x)); |
- } |
- |
- case EQ_STRICT: |
- case NE_STRICT: { |
- return true; |
- } |
- } |
- |
- return false; |
- } |
- |
- @Override |
- public boolean canSkipOperatorShim(DartUnaryExpression x) { |
- Token op = x.getOperator(); |
- switch (op) { |
- case BIT_NOT: |
- case SUB: { |
- return (isNumericType(x.getArg()) && hasSingleImplementation(x)); |
- } |
- |
- case INC: |
- case DEC: { |
- assert !op.isUserDefinableOperator(); |
- return isNumericType(x.getArg()); |
- } |
- |
- case NOT: { |
- assert !op.isUserDefinableOperator(); |
- return isBooleanType(x.getArg()); |
- } |
- } |
- return false; |
- } |
- |
- @Override |
- public boolean canSkipArrayAccessShim(DartArrayAccess array, boolean isAssignee) { |
- Set<MethodElement> impls = typeHeuristic.getImplementationsOf(array); |
- if (impls != null && impls.size() == 1) { |
- MethodElement impl = impls.iterator().next(); |
- Element arrayElement = TypeHeuristicImplementation.maybeGetTargetElement(array); |
- if (isAssignee && (arrayElement == null || arrayElement.getModifiers().isFinal())) { |
- return false; |
- } |
- return impl.getEnclosingElement().equals(typeProvider.getObjectArrayType().getElement()); |
- } |
- return false; |
- } |
- |
- private boolean isStringType(DartExpression expr) { |
- return isSingleType(expr, STRING_IMPLEMENTATION); |
- } |
- |
- static boolean isStringType(Set<Type> types) { |
- return isSingleType(types, STRING_IMPLEMENTATION); |
- } |
- |
- private boolean isBooleanType(DartExpression expr) { |
- return isSingleType(expr, BOOL_IMPLEMENTATION); |
- } |
- |
- static boolean isBooleanType(Set<Type> types) { |
- return isSingleType(types, BOOL_IMPLEMENTATION); |
- } |
- |
- private boolean isNumericType(DartExpression expr) { |
- return isSingleType(typeHeuristic.getTypesOf(expr), NUMBER_IMPLEMENTATION); |
- } |
- |
- static boolean isNumericType(Set<Type> types) { |
- return isSingleType(types, NUMBER_IMPLEMENTATION); |
- } |
- |
- private boolean isSingleType(DartExpression expr, String className) { |
- Set<Type> types = typeHeuristic.getTypesOf(expr); |
- return isSingleType(types, className); |
- } |
- |
- private boolean hasSingleImplementation(DartBinaryExpression expr) { |
- Set<MethodElement> impl = typeHeuristic.getImplementationsOf(expr); |
- return ((impl != null) && (impl.size() == 1)); |
- } |
- |
- private boolean isNullLiteral(DartExpression expr) { |
- return expr instanceof DartNullLiteral; |
- } |
- |
- private static boolean isSingleType(Set<Type> types, String className) { |
- if (types.size() != 1) { |
- return false; |
- } |
- |
- Type type = types.iterator().next(); |
- if (type.getKind() == TypeKind.INTERFACE) { |
- return className.equals(type.getElement().getName()); |
- } |
- return false; |
- } |
- |
- /** |
- * Return {@link FieldElement} if the {@link DartIdentifier} is actually an access to the field |
- * and we can optimize away the call to the generated getter. |
- */ |
- @Override |
- public FieldElement findOptimizableFieldElementFor(DartExpression expr, FieldKind fieldKind) { |
- Set<DartNode> visited = Sets.newHashSet(); |
- FieldElement field = maybeGetInlineableField(expr, fieldKind, visited); |
- visited = null; |
- return field; |
- } |
- |
- private FieldElement maybeGetInlineableField(DartExpression expr, FieldKind fieldKind, |
- Set<DartNode> visited) { |
- // if the field is referenced in a function expression we cannot inline it. |
- if (expr.getParent() instanceof DartFunctionObjectInvocation) { |
- return null; |
- } |
- |
- Set<FieldElement> impls = typeHeuristic.getFieldImplementationsOf(expr, fieldKind); |
- if ((impls != null) && (impls.size() == 1)) { |
- FieldElement field = impls.iterator().next(); |
- |
- // Check if field is non-abstract and can be 'trivially' inlined. |
- if (isFieldInlinable(field, fieldKind)) { |
- return field; |
- } |
- |
- // Check if field is native and whitelisted. |
- if (isWhitelistedNativeField(field, fieldKind)) { |
- return field; |
- } |
- |
- // Check if field is abstract and has no side effect. |
- FieldElement backingField = maybeGetNonAbstractFieldGetter(field, fieldKind, visited); |
- if (backingField != null) { |
- return backingField; |
- } |
- } |
- return null; |
- } |
- |
- private FieldElement maybeGetNonAbstractFieldGetter(FieldElement field, FieldKind fieldKind, |
- Set<DartNode> visited) { |
- if (visited.contains(field.getNode())) { |
- // If field references itself, it will cause a cycle. in this case, we return null. |
- return null; |
- } |
- visited.add(field.getNode()); |
- if (field.getModifiers().isAbstractField()) { |
- if (fieldKind.equals(FieldKind.GETTER) && (field.getGetter() != null)) { |
- DartMethodDefinition getter = (DartMethodDefinition) field.getGetter().getNode(); |
- if (getter != null && getter.getFunction() != null) { |
- DartFunction fnGetter = getter.getFunction(); |
- if (fnGetter.getBody() != null && fnGetter.getBody().getStatements() != null |
- && fnGetter.getBody().getStatements().size() == 1) { |
- DartStatement stmt = fnGetter.getBody().getStatements().iterator().next(); |
- if (stmt instanceof DartReturnStatement) { |
- DartReturnStatement returnStmt = (DartReturnStatement) stmt; |
- DartExpression retExpr = returnStmt.getValue(); |
- if (retExpr instanceof DartIdentifier) { |
- return maybeGetInlineableField(retExpr, fieldKind, visited); |
- } else if (retExpr instanceof DartPropertyAccess) { |
- DartPropertyAccess propAccess = (DartPropertyAccess) retExpr; |
- if (propAccess.getQualifier() instanceof DartThisExpression) { |
- return maybeGetInlineableField(propAccess, fieldKind, visited); |
- } |
- } |
- } |
- } |
- } |
- } |
- } |
- return null; |
- } |
- |
- @Override |
- public Element findElementFor(DartMethodInvocation expr) { |
- Set<MethodElement> impls = typeHeuristic.getImplementationsOf(expr); |
- if ((impls != null) && (impls.size() == 1)) { |
- return impls.iterator().next(); |
- } |
- return (Element) expr.getTargetSymbol(); |
- } |
- |
- @Override |
- public boolean canSkipNormalization(DartBinaryExpression expr) { |
- Token operator = expr.getOperator(); |
- Set<Type> types = typeHeuristic.getTypesOf(expr.getArg1()); |
- switch (operator) { |
- case ASSIGN_ADD: { |
- if (!canInlineSideEffect(expr.getArg1())) { |
- return false; |
- } |
- return isNumericType(types) || isStringType(types); |
- } |
- case ASSIGN_SUB: |
- case ASSIGN_MUL: |
- case ASSIGN_DIV: |
- case ASSIGN_SAR: |
- case ASSIGN_SHL: |
- case ASSIGN_BIT_AND: |
- case ASSIGN_BIT_OR: |
- case ASSIGN_BIT_XOR: { |
- if (!canInlineSideEffect(expr.getArg1())) { |
- return false; |
- } |
- return isNumericType(types); |
- } |
- case AND: |
- case OR: { |
- return isNumericType(types) || isBooleanType(types); |
- } |
- case ASSIGN_TRUNC: |
- case ASSIGN_MOD: |
- // TRUNC and MOD cannot skip normalization as there is no 'native' javascript |
- // equivalent operator. |
- return false; |
- default: |
- throw new AssertionError("Internal Error: Unknown operator " + operator); |
- } |
- } |
- |
- @Override |
- public boolean canSkipNormalization(DartUnaryExpression expr) { |
- Token operator = expr.getOperator(); |
- Set<Type> types = typeHeuristic.getTypesOf(expr.getArg()); |
- switch (operator) { |
- case DEC: |
- case INC: { |
- // DEC, INC are not user definable. |
- if (!canInlineSideEffect(expr.getArg())) { |
- return false; |
- } |
- return isNumericType(types); |
- } |
- default: |
- throw new AssertionError("Internal Error: Unknown operator " + operator); |
- } |
- } |
- |
- @Override |
- public boolean isWhitelistedNativeField(FieldElement field, FieldKind fieldKind) { |
- // TODO (fabiomfv) : Given that we only whitelist two types and one field, hardcode the logic |
- // for now. If the number grows, consider moving to a map. |
- // Assumes the native field name is the same as the FieldElement name. |
- if (isNativeFieldWithAccessor(field, fieldKind)) { |
- Element fieldHolder = field.getEnclosingElement(); |
- if (fieldHolder.equals(typeProvider.getObjectArrayType().getElement()) |
- || fieldHolder.equals(typeProvider.getStringImplementationType().getElement())) { |
- return field.getName().equals("length"); |
- } |
- } |
- return false; |
- } |
- |
- private boolean canInlineSideEffect(DartExpression expr) { |
- if (expr instanceof DartArrayAccess) { |
- Set<MethodElement> impls = typeHeuristic.getImplementationsOf(expr); |
- if (impls != null) { |
- for (MethodElement impl : impls) { |
- if (ElementKind.of(impl.getEnclosingElement()).equals(ElementKind.CLASS)) { |
- ClassElement cls = (ClassElement) impl.getEnclosingElement(); |
- Element indexAssignOp = cls.lookupLocalElement("operator []="); |
- if (indexAssignOp != null && !cls.getType().equals(typeProvider.getObjectArrayType())) { |
- return false; |
- } |
- } |
- } |
- return true; |
- } |
- } else { |
- Element element = TypeHeuristicImplementation.maybeGetTargetElement(expr); |
- if ((element != null) && element.getModifiers().isFinal()) { |
- return false; |
- } |
- switch (ElementKind.of(element)) { |
- case FIELD: { |
- return isFieldInlinable((FieldElement) element); |
- } |
- case PARAMETER: |
- case VARIABLE: |
- return true; |
- } |
- } |
- return false; |
- } |
- |
- private boolean isFieldInlinable(FieldElement field) { |
- return !field.isStatic() && !field.isDynamic() && !field.getModifiers().isAbstractField(); |
- } |
- |
- private boolean isFieldInlinable(FieldElement field, FieldKind fieldKind) { |
- return isFieldInlinable(field) |
- && (fieldKind != FieldKind.SETTER || !field.getModifiers().isFinal()); |
- } |
- |
- private boolean isNativeFieldWithAccessor(FieldElement field, FieldKind fieldKind) { |
- if (fieldKind == FieldKind.GETTER && field.getGetter() != null) { |
- return field.getGetter().getModifiers().isNative(); |
- } else if (fieldKind == FieldKind.SETTER && field.getSetter() != null) { |
- return field.getSetter().getModifiers().isNative(); |
- } |
- return false; |
- } |
- |
- private boolean hasSingleImplementation(DartExpression expr) { |
- Set<MethodElement> impls = typeHeuristic.getImplementationsOf(expr); |
- return ((impls != null) && (impls.size() == 1)); |
- } |
- |
- @Override |
- public boolean canInlineInitializers(ConstructorElement constructorElement) { |
- // For now we only inline classes that don't have Only immediate subtypes of object that are |
- // not subclassed. |
- // We will refine this in the near future to include arbitrary class hierarchies. |
- ClassElement classElement = (ClassElement) constructorElement.getEnclosingElement(); |
- if (canEmitOptimizedClassConstructor(classElement)) { |
- Modifiers modifiers = constructorElement.getModifiers(); |
- if (modifiers.isRedirectedConstructor() || modifiers.isConstant()) { |
- return false; |
- } |
- return (classElement.isObjectChild() && (classElement.getSubtypes().size() == 1)); |
- } |
- return false; |
- } |
- |
- @Override |
- public boolean canEmitOptimizedClassConstructor(ClassElement classElement) { |
- // For now we only inline classes that don't have Only immediate subtypes of object that are |
- // not subclassed. |
- // We will refine this in the near future to include arbitrary class hierarchies. |
- if (classElement.getNativeName() != null) { |
- return false; |
- } |
- List<ConstructorElement> constructors = classElement.getConstructors(); |
- if (constructors.size() != 1) { |
- return false; |
- } |
- ConstructorElement constructor = constructors.iterator().next(); |
- Modifiers modifiers = constructor.getModifiers(); |
- if (modifiers.isStatic() || modifiers.isConstant() || modifiers.isNative()) { |
- return false; |
- } |
- DartMethodDefinition method = (DartMethodDefinition) constructor.getNode(); |
- for (DartParameter param : method.getFunction().getParams()) { |
- if (param.getModifiers().isNamed() || (param.getDefaultExpr() != null)) { |
- return false; |
- } |
- } |
- for (DartInitializer initializer : method.getInitializers()) { |
- // TODO (fabiomfv) : |
- // Function expressions in initializers are being revisited due to the possiblity of having |
- // closures on 'this' that is not fully created at the time of initialization. Keeping the |
- // simplest case for now. Will revisit this in the next round. |
- if (initializer.getValue() instanceof DartFunctionExpression) { |
- return false; |
- } |
- } |
- return true; |
- } |
- |
- @Override |
- public boolean canOptimizeFunctionExpressionBind(DartFunctionExpression expr) { |
- DartFunction fn = expr.getFunction(); |
- if (fn != null) { |
- for (DartParameter param : fn.getParams()) { |
- if (param.getModifiers().isNamed()) { |
- return false; |
- } |
- } |
- } |
- return true; |
- } |
-} |