Search in sources :

Example 1 with OptimisationStrategy

use of com.redhat.ceylon.compiler.java.codegen.Operators.OptimisationStrategy in project ceylon-compiler by ceylon.

the class ExpressionTransformer method transform.

// Postfix operator
public JCExpression transform(Tree.PostfixOperatorExpression expr) {
    OperatorTranslation operator = Operators.getOperator(expr.getClass());
    if (operator == null) {
        return makeErroneous(expr, "compiler bug " + expr.getNodeType() + " is not yet supported");
    }
    OptimisationStrategy optimisationStrategy = operator.getUnOpOptimisationStrategy(expr, expr.getTerm(), this);
    boolean canOptimise = optimisationStrategy.useJavaOperator();
    // only fully optimise if we don't have to access the getter/setter
    if (canOptimise && CodegenUtil.isDirectAccessVariable(expr.getTerm())) {
        JCExpression term = transformExpression(expr.getTerm(), BoxingStrategy.UNBOXED, expr.getTypeModel(), EXPR_WIDEN_PRIM);
        return at(expr).Unary(operator.javacOperator, term);
    }
    Tree.Term term = unwrapExpressionUntilTerm(expr.getTerm());
    Interface compoundType = expr.getUnit().getOrdinalDeclaration();
    Type valueType = getSupertype(expr.getTerm(), compoundType);
    Type returnType = getMostPreciseType(term, getTypeArgument(valueType, 0));
    List<JCVariableDecl> decls = List.nil();
    List<JCStatement> stats = List.nil();
    JCExpression result = null;
    // we can optimise that case a bit sometimes
    boolean boxResult = !canOptimise;
    // (let $tmp = attr; attr = $tmp.getSuccessor(); $tmp;)
    if (term instanceof Tree.BaseMemberExpression || // special case for java statics Foo.attr where Foo does not need to be evaluated
    (term instanceof Tree.QualifiedMemberExpression && ((Tree.QualifiedMemberExpression) term).getStaticMethodReference())) {
        JCExpression getter;
        if (term instanceof Tree.BaseMemberExpression)
            getter = transform((Tree.BaseMemberExpression) term, null);
        else
            getter = transformMemberExpression((Tree.QualifiedMemberExpression) term, null, null);
        at(expr);
        // Type $tmp = attr
        JCExpression exprType = makeJavaType(returnType, boxResult ? JT_NO_PRIMITIVES : 0);
        Name varName = naming.tempName("op");
        // make sure we box the results if necessary
        getter = applyErasureAndBoxing(getter, term, boxResult ? BoxingStrategy.BOXED : BoxingStrategy.UNBOXED, returnType);
        JCVariableDecl tmpVar = make().VarDef(make().Modifiers(0), varName, exprType, getter);
        decls = decls.prepend(tmpVar);
        // attr = $tmp.getSuccessor()
        JCExpression successor;
        if (canOptimise) {
            // use +1/-1 if we can optimise a bit
            successor = make().Binary(operator == OperatorTranslation.UNARY_POSTFIX_INCREMENT ? JCTree.PLUS : JCTree.MINUS, make().Ident(varName), makeInteger(1));
            successor = unAutoPromote(successor, returnType);
        } else {
            successor = make().Apply(null, makeSelect(make().Ident(varName), operator.ceylonMethod), List.<JCExpression>nil());
            // make sure the result is boxed if necessary, the result of successor/predecessor is always boxed
            successor = boxUnboxIfNecessary(successor, true, term.getTypeModel(), CodegenUtil.getBoxingStrategy(term));
        }
        JCExpression assignment = transformAssignment(expr, term, successor);
        stats = stats.prepend(at(expr).Exec(assignment));
        // $tmp
        result = make().Ident(varName);
    } else if (term instanceof Tree.QualifiedMemberExpression) {
        // e.attr++
        // (let $tmpE = e, $tmpV = $tmpE.attr; $tmpE.attr = $tmpV.getSuccessor(); $tmpV;)
        Tree.QualifiedMemberExpression qualified = (Tree.QualifiedMemberExpression) term;
        boolean isSuper = isSuperOrSuperOf(qualified.getPrimary());
        boolean isPackage = isPackageQualified(qualified);
        // transform the primary, this will get us a boxed primary 
        JCExpression e = transformQualifiedMemberPrimary(qualified);
        at(expr);
        // Type $tmpE = e
        JCExpression exprType = makeJavaType(qualified.getTarget().getQualifyingType(), JT_NO_PRIMITIVES);
        Name varEName = naming.tempName("opE");
        JCVariableDecl tmpEVar = make().VarDef(make().Modifiers(0), varEName, exprType, e);
        // Type $tmpV = $tmpE.attr
        JCExpression attrType = makeJavaType(returnType, boxResult ? JT_NO_PRIMITIVES : 0);
        Name varVName = naming.tempName("opV");
        JCExpression getter;
        if (isSuper) {
            getter = transformMemberExpression(qualified, transformSuper(qualified), null);
        } else if (isPackage) {
            getter = transformMemberExpression(qualified, null, null);
        } else {
            getter = transformMemberExpression(qualified, make().Ident(varEName), null);
        }
        // make sure we box the results if necessary
        getter = applyErasureAndBoxing(getter, term, boxResult ? BoxingStrategy.BOXED : BoxingStrategy.UNBOXED, returnType);
        JCVariableDecl tmpVVar = make().VarDef(make().Modifiers(0), varVName, attrType, getter);
        decls = decls.prepend(tmpVVar);
        if (!isSuper && !isPackage) {
            // define all the variables
            decls = decls.prepend(tmpEVar);
        }
        // $tmpE.attr = $tmpV.getSuccessor()
        JCExpression successor;
        if (canOptimise) {
            // use +1/-1 if we can optimise a bit
            successor = make().Binary(operator == OperatorTranslation.UNARY_POSTFIX_INCREMENT ? JCTree.PLUS : JCTree.MINUS, make().Ident(varVName), makeInteger(1));
            successor = unAutoPromote(successor, returnType);
        } else {
            successor = make().Apply(null, makeSelect(make().Ident(varVName), operator.ceylonMethod), List.<JCExpression>nil());
            //  make sure the result is boxed if necessary, the result of successor/predecessor is always boxed
            successor = boxUnboxIfNecessary(successor, true, term.getTypeModel(), CodegenUtil.getBoxingStrategy(term));
        }
        JCExpression assignment = transformAssignment(expr, term, isSuper ? transformSuper(qualified) : make().Ident(varEName), successor);
        stats = stats.prepend(at(expr).Exec(assignment));
        // $tmpV
        result = make().Ident(varVName);
    } else {
        return makeErroneous(term, "compiler bug: " + term.getNodeType() + " is not supported yet");
    }
    return make().LetExpr(decls, stats, result);
}
Also used : Term(com.redhat.ceylon.compiler.typechecker.tree.Tree.Term) JCStatement(com.sun.tools.javac.tree.JCTree.JCStatement) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) AssignmentOperatorTranslation(com.redhat.ceylon.compiler.java.codegen.Operators.AssignmentOperatorTranslation) OperatorTranslation(com.redhat.ceylon.compiler.java.codegen.Operators.OperatorTranslation) SyntheticName(com.redhat.ceylon.compiler.java.codegen.Naming.SyntheticName) Name(com.sun.tools.javac.util.Name) Type(com.redhat.ceylon.model.typechecker.model.Type) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JCTree(com.sun.tools.javac.tree.JCTree) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) OptimisationStrategy(com.redhat.ceylon.compiler.java.codegen.Operators.OptimisationStrategy) Interface(com.redhat.ceylon.model.typechecker.model.Interface) ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface)

Example 2 with OptimisationStrategy

use of com.redhat.ceylon.compiler.java.codegen.Operators.OptimisationStrategy in project ceylon-compiler by ceylon.

the class ExpressionTransformer method transform.

// Prefix operator
public JCExpression transform(final Tree.PrefixOperatorExpression expr) {
    final OperatorTranslation operator = Operators.getOperator(expr.getClass());
    if (operator == null) {
        return makeErroneous(expr, "compiler bug: " + expr.getNodeType() + " is not supported yet");
    }
    OptimisationStrategy optimisationStrategy = operator.getUnOpOptimisationStrategy(expr, expr.getTerm(), this);
    final boolean canOptimise = optimisationStrategy.useJavaOperator();
    Tree.Term term = expr.getTerm();
    // only fully optimise if we don't have to access the getter/setter
    if (canOptimise && CodegenUtil.isDirectAccessVariable(term)) {
        JCExpression jcTerm = transformExpression(term, BoxingStrategy.UNBOXED, expr.getTypeModel(), EXPR_WIDEN_PRIM);
        return at(expr).Unary(operator.javacOperator, jcTerm);
    }
    Interface compoundType = expr.getUnit().getOrdinalDeclaration();
    Type valueType = getSupertype(term, compoundType);
    final Type returnType = getMostPreciseType(term, getTypeArgument(valueType, 0));
    // we work on boxed types unless we could have optimised
    return transformAssignAndReturnOperation(expr, term, !canOptimise, valueType, returnType, new AssignAndReturnOperationFactory() {

        @Override
        public JCExpression getNewValue(JCExpression previousValue) {
            // use +1/-1 if we can optimise a bit
            if (canOptimise) {
                JCExpression ret = make().Binary(operator == OperatorTranslation.UNARY_PREFIX_INCREMENT ? JCTree.PLUS : JCTree.MINUS, previousValue, makeInteger(1));
                ret = unAutoPromote(ret, returnType);
                return ret;
            }
            // make this call: previousValue.getSuccessor() or previousValue.getPredecessor()
            return make().Apply(null, makeSelect(previousValue, operator.ceylonMethod), List.<JCExpression>nil());
        }
    });
}
Also used : Type(com.redhat.ceylon.model.typechecker.model.Type) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) Term(com.redhat.ceylon.compiler.typechecker.tree.Tree.Term) JCTree(com.sun.tools.javac.tree.JCTree) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) OptimisationStrategy(com.redhat.ceylon.compiler.java.codegen.Operators.OptimisationStrategy) Interface(com.redhat.ceylon.model.typechecker.model.Interface) ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface) AssignmentOperatorTranslation(com.redhat.ceylon.compiler.java.codegen.Operators.AssignmentOperatorTranslation) OperatorTranslation(com.redhat.ceylon.compiler.java.codegen.Operators.OperatorTranslation)

Example 3 with OptimisationStrategy

use of com.redhat.ceylon.compiler.java.codegen.Operators.OptimisationStrategy in project ceylon-compiler by ceylon.

the class ExpressionTransformer method transform.

//
// Binary operators
public JCExpression transform(Tree.NotEqualOp op) {
    OperatorTranslation operator = Operators.OperatorTranslation.BINARY_EQUAL;
    OptimisationStrategy optimisationStrategy = operator.getBinOpOptimisationStrategy(op, op.getLeftTerm(), op.getRightTerm(), this);
    // we want it unboxed only if the operator is optimised
    // we don't care about the left erased type, since equals() is on Object
    JCExpression left = transformExpression(op.getLeftTerm(), optimisationStrategy.getBoxingStrategy(), null, EXPR_WIDEN_PRIM);
    // we don't care about the right erased type, since equals() is on Object
    JCExpression expr = transformOverridableBinaryOperator(op.getLeftTerm(), op.getRightTerm(), null, operator, optimisationStrategy, left, op.getTypeModel());
    return at(op).Unary(JCTree.NOT, expr);
}
Also used : JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) OptimisationStrategy(com.redhat.ceylon.compiler.java.codegen.Operators.OptimisationStrategy) AssignmentOperatorTranslation(com.redhat.ceylon.compiler.java.codegen.Operators.AssignmentOperatorTranslation) OperatorTranslation(com.redhat.ceylon.compiler.java.codegen.Operators.OperatorTranslation)

Example 4 with OptimisationStrategy

use of com.redhat.ceylon.compiler.java.codegen.Operators.OptimisationStrategy in project ceylon-compiler by ceylon.

the class ExpressionTransformer method transform.

public JCExpression transform(Tree.WithinOp op) {
    Tree.Term middleTerm = op.getTerm();
    Tree.Bound lowerBound = op.getLowerBound();
    OperatorTranslation lowerOp = Operators.getOperator(lowerBound instanceof Tree.OpenBound ? Tree.SmallerOp.class : Tree.SmallAsOp.class);
    Tree.Term lowerTerm = lowerBound.getTerm();
    Tree.Bound upperBound = op.getUpperBound();
    OperatorTranslation upperOp = Operators.getOperator(upperBound instanceof Tree.OpenBound ? Tree.SmallerOp.class : Tree.SmallAsOp.class);
    Tree.Term upperTerm = upperBound.getTerm();
    Type middleType = getComparableType(middleTerm);
    Type lowerType = getComparableType(lowerTerm);
    Type upperType = getComparableType(upperTerm);
    // If any of the terms is optimizable, then use optimized
    OptimisationStrategy opt;
    boolean optimizeLower = lowerOp.isTermOptimisable(lowerTerm, lowerType, this) == OptimisationStrategy.OPTIMISE || lowerOp.isTermOptimisable(middleTerm, middleType, this) == OptimisationStrategy.OPTIMISE;
    boolean optimizeUpper = upperOp.isTermOptimisable(middleTerm, middleType, this) == OptimisationStrategy.OPTIMISE || upperOp.isTermOptimisable(upperTerm, upperType, this) == OptimisationStrategy.OPTIMISE;
    if ((lowerType.isExactly(middleType) && middleType.isExactly(upperType) && (optimizeLower || // if all same type and any optimizable
    optimizeUpper)) || (// otherwise onle if all optimizable
    optimizeLower && optimizeUpper)) {
        opt = OptimisationStrategy.OPTIMISE;
    } else {
        opt = OptimisationStrategy.NONE;
    }
    SyntheticName middleName = naming.alias("middle");
    List<JCStatement> vars = List.<JCStatement>of(makeVar(middleName, makeJavaType(middleType, opt.getBoxingStrategy() == BoxingStrategy.UNBOXED ? 0 : JT_NO_PRIMITIVES), transformExpression(middleTerm, opt.getBoxingStrategy(), middleType)));
    JCExpression lower = transformBound(middleName, middleType, lowerType, lowerOp, opt, middleTerm, lowerBound, false);
    JCExpression upper = transformBound(middleName, middleType, upperType, upperOp, opt, middleTerm, upperBound, true);
    at(op);
    OperatorTranslation andOp = Operators.getOperator(Tree.AndOp.class);
    OptimisationStrategy optimisationStrategy = OptimisationStrategy.OPTIMISE;
    return make().LetExpr(vars, transformOverridableBinaryOperator(andOp, optimisationStrategy, lower, upper, null, null, op.getTypeModel()));
}
Also used : Term(com.redhat.ceylon.compiler.typechecker.tree.Tree.Term) SyntheticName(com.redhat.ceylon.compiler.java.codegen.Naming.SyntheticName) JCStatement(com.sun.tools.javac.tree.JCTree.JCStatement) AssignmentOperatorTranslation(com.redhat.ceylon.compiler.java.codegen.Operators.AssignmentOperatorTranslation) OperatorTranslation(com.redhat.ceylon.compiler.java.codegen.Operators.OperatorTranslation) Type(com.redhat.ceylon.model.typechecker.model.Type) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JCTree(com.sun.tools.javac.tree.JCTree) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) OptimisationStrategy(com.redhat.ceylon.compiler.java.codegen.Operators.OptimisationStrategy)

Example 5 with OptimisationStrategy

use of com.redhat.ceylon.compiler.java.codegen.Operators.OptimisationStrategy in project ceylon-compiler by ceylon.

the class ExpressionTransformer method checkForBitwiseOperators.

private JCExpression checkForBitwiseOperators(Tree.Term node, Tree.QualifiedMemberExpression qme, Tree.Term right) {
    // must be a call on Integer
    Tree.Term left = qme.getPrimary();
    if (left == null) {
        return null;
    }
    String signature;
    Type binaryType;
    if (isCeylonInteger(left.getTypeModel())) {
        // must be a supported method/attribute
        binaryType = typeFact().getIntegerType();
        String name = qme.getIdentifier().getText();
        signature = "ceylon.language.Integer." + name;
    } else if (isCeylonByte(left.getTypeModel())) {
        binaryType = typeFact().getByteType();
        String name = qme.getIdentifier().getText();
        signature = "ceylon.language.Byte." + name;
    } else {
        return null;
    }
    // see if we have an operator for it
    OperatorTranslation operator = Operators.getOperator(signature);
    if (operator != null) {
        JCExpression result;
        if (operator.getArity() == 2) {
            if (right == null)
                return null;
            OptimisationStrategy optimisationStrategy = operator.getBinOpOptimisationStrategy(node, left, right, this);
            // check that we can optimise it
            if (!optimisationStrategy.useJavaOperator())
                return null;
            JCExpression leftExpr = transformExpression(left, optimisationStrategy.getBoxingStrategy(), binaryType, EXPR_WIDEN_PRIM);
            JCExpression rightExpr = transformExpression(right, optimisationStrategy.getBoxingStrategy(), binaryType, EXPR_WIDEN_PRIM);
            if (operator.valueMask != 0) {
                leftExpr = make().Binary(JCTree.BITAND, leftExpr, makeInteger(operator.valueMask));
            }
            result = make().Binary(operator.javacOperator, leftExpr, rightExpr);
        } else {
            // must be unary
            if (right != null)
                return null;
            OptimisationStrategy optimisationStrategy = operator.getUnOpOptimisationStrategy(node, left, this);
            // check that we can optimise it
            if (!optimisationStrategy.useJavaOperator())
                return null;
            JCExpression leftExpr = transformExpression(left, optimisationStrategy.getBoxingStrategy(), binaryType, EXPR_WIDEN_PRIM);
            if (operator.valueMask != 0) {
                leftExpr = make().Binary(JCTree.BITAND, leftExpr, makeInteger(operator.valueMask));
            }
            result = make().Unary(operator.javacOperator, leftExpr);
        }
        if (isCeylonByte(binaryType)) {
            result = make().TypeCast(syms().byteType, result);
        }
        return result;
    }
    return null;
}
Also used : Type(com.redhat.ceylon.model.typechecker.model.Type) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) Term(com.redhat.ceylon.compiler.typechecker.tree.Tree.Term) JCTree(com.sun.tools.javac.tree.JCTree) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) OptimisationStrategy(com.redhat.ceylon.compiler.java.codegen.Operators.OptimisationStrategy) AssignmentOperatorTranslation(com.redhat.ceylon.compiler.java.codegen.Operators.AssignmentOperatorTranslation) OperatorTranslation(com.redhat.ceylon.compiler.java.codegen.Operators.OperatorTranslation)

Aggregations

OptimisationStrategy (com.redhat.ceylon.compiler.java.codegen.Operators.OptimisationStrategy)7 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)7 AssignmentOperatorTranslation (com.redhat.ceylon.compiler.java.codegen.Operators.AssignmentOperatorTranslation)6 OperatorTranslation (com.redhat.ceylon.compiler.java.codegen.Operators.OperatorTranslation)6 Tree (com.redhat.ceylon.compiler.typechecker.tree.Tree)4 Term (com.redhat.ceylon.compiler.typechecker.tree.Tree.Term)4 Type (com.redhat.ceylon.model.typechecker.model.Type)4 JCTree (com.sun.tools.javac.tree.JCTree)4 SyntheticName (com.redhat.ceylon.compiler.java.codegen.Naming.SyntheticName)2 ClassOrInterface (com.redhat.ceylon.model.typechecker.model.ClassOrInterface)2 Interface (com.redhat.ceylon.model.typechecker.model.Interface)2 JCStatement (com.sun.tools.javac.tree.JCTree.JCStatement)2 JCVariableDecl (com.sun.tools.javac.tree.JCTree.JCVariableDecl)1 Name (com.sun.tools.javac.util.Name)1